1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.net; 18 19 import static android.Manifest.permission.NETWORK_SETTINGS; 20 import static android.Manifest.permission.NETWORK_STATS_PROVIDER; 21 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; 22 import static android.Manifest.permission.UPDATE_DEVICE_STATS; 23 import static android.app.usage.NetworkStatsManager.PREFIX_DEV; 24 import static android.content.Intent.ACTION_SHUTDOWN; 25 import static android.content.Intent.ACTION_UID_REMOVED; 26 import static android.content.Intent.ACTION_USER_REMOVED; 27 import static android.content.Intent.EXTRA_UID; 28 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 29 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 30 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; 31 import static android.net.NetworkStats.DEFAULT_NETWORK_NO; 32 import static android.net.NetworkStats.IFACE_ALL; 33 import static android.net.NetworkStats.IFACE_VT; 34 import static android.net.NetworkStats.INTERFACES_ALL; 35 import static android.net.NetworkStats.METERED_ALL; 36 import static android.net.NetworkStats.METERED_NO; 37 import static android.net.NetworkStats.METERED_YES; 38 import static android.net.NetworkStats.ROAMING_ALL; 39 import static android.net.NetworkStats.ROAMING_NO; 40 import static android.net.NetworkStats.SET_ALL; 41 import static android.net.NetworkStats.SET_DEFAULT; 42 import static android.net.NetworkStats.SET_FOREGROUND; 43 import static android.net.NetworkStats.STATS_PER_IFACE; 44 import static android.net.NetworkStats.STATS_PER_UID; 45 import static android.net.NetworkStats.TAG_ALL; 46 import static android.net.NetworkStats.TAG_NONE; 47 import static android.net.NetworkStats.UID_ALL; 48 import static android.net.NetworkStatsHistory.FIELD_ALL; 49 import static android.net.NetworkTemplate.MATCH_MOBILE; 50 import static android.net.NetworkTemplate.MATCH_TEST; 51 import static android.net.NetworkTemplate.MATCH_WIFI; 52 import static android.net.TrafficStats.KB_IN_BYTES; 53 import static android.net.TrafficStats.MB_IN_BYTES; 54 import static android.net.TrafficStats.TYPE_RX_BYTES; 55 import static android.net.TrafficStats.TYPE_RX_PACKETS; 56 import static android.net.TrafficStats.TYPE_TX_BYTES; 57 import static android.net.TrafficStats.TYPE_TX_PACKETS; 58 import static android.net.TrafficStats.UID_TETHERING; 59 import static android.net.TrafficStats.UNSUPPORTED; 60 import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE; 61 import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; 62 import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; 63 import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT; 64 import static android.os.Trace.TRACE_TAG_NETWORK; 65 import static android.provider.DeviceConfig.NAMESPACE_TETHERING; 66 import static android.system.OsConstants.ENOENT; 67 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 68 import static android.text.format.DateUtils.DAY_IN_MILLIS; 69 import static android.text.format.DateUtils.HOUR_IN_MILLIS; 70 import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 71 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 72 73 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; 74 import static com.android.net.module.util.DeviceConfigUtils.getDeviceConfigPropertyInt; 75 import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; 76 import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; 77 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_PERIODIC; 78 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_DUMPSYS; 79 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_FORCE_UPDATE; 80 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_GLOBAL_ALERT; 81 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_NETWORK_STATUS_CHANGED; 82 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_OPEN_SESSION; 83 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED; 84 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REG_CALLBACK; 85 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REMOVE_UIDS; 86 import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_UPSTREAM_CHANGED; 87 import static com.android.server.net.NetworkStatsEventLogger.PollEvent; 88 89 import android.annotation.NonNull; 90 import android.annotation.Nullable; 91 import android.annotation.TargetApi; 92 import android.app.AlarmManager; 93 import android.app.BroadcastOptions; 94 import android.app.PendingIntent; 95 import android.app.compat.CompatChanges; 96 import android.app.usage.NetworkStatsManager; 97 import android.content.ApexEnvironment; 98 import android.content.BroadcastReceiver; 99 import android.content.ContentResolver; 100 import android.content.Context; 101 import android.content.Intent; 102 import android.content.IntentFilter; 103 import android.content.pm.ApplicationInfo; 104 import android.content.pm.PackageManager; 105 import android.content.res.Resources; 106 import android.database.ContentObserver; 107 import android.net.DataUsageRequest; 108 import android.net.INetd; 109 import android.net.INetworkStatsService; 110 import android.net.INetworkStatsSession; 111 import android.net.Network; 112 import android.net.NetworkCapabilities; 113 import android.net.NetworkIdentity; 114 import android.net.NetworkIdentitySet; 115 import android.net.NetworkPolicyManager; 116 import android.net.NetworkSpecifier; 117 import android.net.NetworkStack; 118 import android.net.NetworkStateSnapshot; 119 import android.net.NetworkStats; 120 import android.net.NetworkStats.NonMonotonicObserver; 121 import android.net.NetworkStatsAccess; 122 import android.net.NetworkStatsCollection; 123 import android.net.NetworkStatsHistory; 124 import android.net.NetworkTemplate; 125 import android.net.TelephonyNetworkSpecifier; 126 import android.net.TetherStatsParcel; 127 import android.net.TetheringManager; 128 import android.net.TrafficStats; 129 import android.net.TransportInfo; 130 import android.net.UnderlyingNetworkInfo; 131 import android.net.Uri; 132 import android.net.netstats.IUsageCallback; 133 import android.net.netstats.NetworkStatsDataMigrationUtils; 134 import android.net.netstats.provider.INetworkStatsProvider; 135 import android.net.netstats.provider.INetworkStatsProviderCallback; 136 import android.net.netstats.provider.NetworkStatsProvider; 137 import android.net.wifi.WifiInfo; 138 import android.os.Binder; 139 import android.os.Build; 140 import android.os.Bundle; 141 import android.os.DropBoxManager; 142 import android.os.Environment; 143 import android.os.Handler; 144 import android.os.HandlerThread; 145 import android.os.IBinder; 146 import android.os.Looper; 147 import android.os.Message; 148 import android.os.PowerManager; 149 import android.os.RemoteException; 150 import android.os.ServiceSpecificException; 151 import android.os.SystemClock; 152 import android.os.Trace; 153 import android.os.UserHandle; 154 import android.provider.DeviceConfig; 155 import android.provider.Settings; 156 import android.provider.Settings.Global; 157 import android.service.NetworkInterfaceProto; 158 import android.service.NetworkStatsServiceDumpProto; 159 import android.system.ErrnoException; 160 import android.telephony.PhoneStateListener; 161 import android.telephony.SubscriptionPlan; 162 import android.text.TextUtils; 163 import android.text.format.DateUtils; 164 import android.util.ArrayMap; 165 import android.util.ArraySet; 166 import android.util.EventLog; 167 import android.util.IndentingPrintWriter; 168 import android.util.Log; 169 import android.util.SparseIntArray; 170 import android.util.proto.ProtoOutputStream; 171 172 import com.android.connectivity.resources.R; 173 import com.android.internal.annotations.GuardedBy; 174 import com.android.internal.annotations.VisibleForTesting; 175 import com.android.internal.util.FileRotator; 176 import com.android.modules.utils.build.SdkLevel; 177 import com.android.net.module.util.BaseNetdUnsolicitedEventListener; 178 import com.android.net.module.util.BestClock; 179 import com.android.net.module.util.BinderUtils; 180 import com.android.net.module.util.BpfDump; 181 import com.android.net.module.util.BpfMap; 182 import com.android.net.module.util.CollectionUtils; 183 import com.android.net.module.util.DeviceConfigUtils; 184 import com.android.net.module.util.IBpfMap; 185 import com.android.net.module.util.LocationPermissionChecker; 186 import com.android.net.module.util.NetworkStatsUtils; 187 import com.android.net.module.util.PermissionUtils; 188 import com.android.net.module.util.SharedLog; 189 import com.android.net.module.util.Struct; 190 import com.android.net.module.util.Struct.S32; 191 import com.android.net.module.util.Struct.U8; 192 import com.android.net.module.util.bpf.CookieTagMapKey; 193 import com.android.net.module.util.bpf.CookieTagMapValue; 194 import com.android.networkstack.apishim.BroadcastOptionsShimImpl; 195 import com.android.networkstack.apishim.ConstantsShim; 196 import com.android.networkstack.apishim.common.UnsupportedApiLevelException; 197 import com.android.server.BpfNetMaps; 198 import com.android.server.connectivity.ConnectivityResources; 199 200 import java.io.File; 201 import java.io.FileDescriptor; 202 import java.io.FileOutputStream; 203 import java.io.IOException; 204 import java.io.PrintWriter; 205 import java.nio.file.Path; 206 import java.time.Clock; 207 import java.time.Instant; 208 import java.time.ZoneOffset; 209 import java.util.ArrayList; 210 import java.util.Arrays; 211 import java.util.Collections; 212 import java.util.HashMap; 213 import java.util.HashSet; 214 import java.util.List; 215 import java.util.Map; 216 import java.util.Objects; 217 import java.util.Set; 218 import java.util.concurrent.CopyOnWriteArrayList; 219 import java.util.concurrent.Executor; 220 import java.util.concurrent.Semaphore; 221 import java.util.concurrent.TimeUnit; 222 223 /** 224 * Collect and persist detailed network statistics, and provide this data to 225 * other system services. 226 */ 227 @TargetApi(Build.VERSION_CODES.TIRAMISU) 228 public class NetworkStatsService extends INetworkStatsService.Stub { 229 static { 230 System.loadLibrary("service-connectivity"); 231 } 232 233 static final String TAG = "NetworkStats"; 234 static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); 235 static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); 236 237 // Perform polling and persist all (FLAG_PERSIST_ALL). 238 private static final int MSG_PERFORM_POLL = 1; 239 // Perform polling, persist network, and register the global alert again. 240 private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; 241 private static final int MSG_NOTIFY_NETWORK_STATUS = 3; 242 // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent 243 // deadlock. 244 private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; 245 246 /** Flags to control detail level of poll event. */ 247 private static final int FLAG_PERSIST_NETWORK = 0x1; 248 private static final int FLAG_PERSIST_UID = 0x2; 249 private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; 250 private static final int FLAG_PERSIST_FORCE = 0x100; 251 252 /** 253 * When global alert quota is high, wait for this delay before processing each polling, 254 * and do not schedule further polls once there is already one queued. 255 * This avoids firing the global alert too often on devices with high transfer speeds and 256 * high quota. 257 */ 258 private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000; 259 260 private static final String TAG_NETSTATS_ERROR = "netstats_error"; 261 262 /** 263 * EventLog tags used when logging into the event log. Note the values must be sync with 264 * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct 265 * name translation. 266 */ 267 private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100; 268 private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101; 269 270 // TODO: Replace the hardcoded string and move it into ConnectivitySettingsManager. 271 private static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = 272 "netstats_combine_subtype_enabled"; 273 274 private static final String UID_COUNTERSET_MAP_PATH = 275 "/sys/fs/bpf/netd_shared/map_netd_uid_counterset_map"; 276 private static final String COOKIE_TAG_MAP_PATH = 277 "/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map"; 278 private static final String APP_UID_STATS_MAP_PATH = 279 "/sys/fs/bpf/netd_shared/map_netd_app_uid_stats_map"; 280 private static final String STATS_MAP_A_PATH = 281 "/sys/fs/bpf/netd_shared/map_netd_stats_map_A"; 282 private static final String STATS_MAP_B_PATH = 283 "/sys/fs/bpf/netd_shared/map_netd_stats_map_B"; 284 private static final String IFACE_STATS_MAP_PATH = 285 "/sys/fs/bpf/netd_shared/map_netd_iface_stats_map"; 286 287 /** 288 * DeviceConfig flag used to indicate whether the files should be stored in the apex data 289 * directory. 290 */ 291 static final String NETSTATS_STORE_FILES_IN_APEXDATA = "netstats_store_files_in_apexdata"; 292 /** 293 * DeviceConfig flag is used to indicate whether the legacy files need to be imported, and 294 * retry count before giving up. Only valid when {@link #NETSTATS_STORE_FILES_IN_APEXDATA} 295 * set to true. Note that the value gets rollback when the mainline module gets rollback. 296 */ 297 static final String NETSTATS_IMPORT_LEGACY_TARGET_ATTEMPTS = 298 "netstats_import_legacy_target_attempts"; 299 static final int DEFAULT_NETSTATS_IMPORT_LEGACY_TARGET_ATTEMPTS = 1; 300 static final String NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME = "import.attempts"; 301 static final String NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME = "import.successes"; 302 static final String NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME = "import.fallbacks"; 303 static final String CONFIG_ENABLE_NETWORK_STATS_EVENT_LOGGER = 304 "enable_network_stats_event_logger"; 305 306 static final String NETSTATS_FASTDATAINPUT_TARGET_ATTEMPTS = 307 "netstats_fastdatainput_target_attempts"; 308 static final String NETSTATS_FASTDATAINPUT_SUCCESSES_COUNTER_NAME = "fastdatainput.successes"; 309 static final String NETSTATS_FASTDATAINPUT_FALLBACKS_COUNTER_NAME = "fastdatainput.fallbacks"; 310 311 static final String TRAFFIC_STATS_CACHE_EXPIRY_DURATION_NAME = 312 "trafficstats_cache_expiry_duration_ms"; 313 static final String TRAFFIC_STATS_CACHE_MAX_ENTRIES_NAME = "trafficstats_cache_max_entries"; 314 static final int DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS = 1000; 315 static final int DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES = 400; 316 317 private final Context mContext; 318 private final NetworkStatsFactory mStatsFactory; 319 private final AlarmManager mAlarmManager; 320 private final Clock mClock; 321 private final NetworkStatsSettings mSettings; 322 private final NetworkStatsObservers mStatsObservers; 323 324 private final File mStatsDir; 325 326 private final PowerManager.WakeLock mWakeLock; 327 328 private final ContentObserver mContentObserver; 329 private final ContentResolver mContentResolver; 330 331 protected INetd mNetd; 332 private final AlertObserver mAlertObserver = new AlertObserver(); 333 334 // Persistent counters that backed by AtomicFile which stored in the data directory as a file, 335 // to track attempts/successes/fallbacks count across reboot. Note that these counter values 336 // will be rollback as the module rollbacks. 337 private PersistentInt mImportLegacyAttemptsCounter = null; 338 private PersistentInt mImportLegacySuccessesCounter = null; 339 private PersistentInt mImportLegacyFallbacksCounter = null; 340 private PersistentInt mFastDataInputSuccessesCounter = null; 341 private PersistentInt mFastDataInputFallbacksCounter = null; 342 343 @VisibleForTesting 344 public static final String ACTION_NETWORK_STATS_POLL = 345 "com.android.server.action.NETWORK_STATS_POLL"; 346 public static final String ACTION_NETWORK_STATS_UPDATED = 347 "com.android.server.action.NETWORK_STATS_UPDATED"; 348 349 private PendingIntent mPollIntent; 350 351 /** 352 * Settings that can be changed externally. 353 */ 354 public interface NetworkStatsSettings { getPollInterval()355 long getPollInterval(); getPollDelay()356 long getPollDelay(); getSampleEnabled()357 boolean getSampleEnabled(); getAugmentEnabled()358 boolean getAugmentEnabled(); 359 /** 360 * When enabled, all mobile data is reported under {@link NetworkTemplate#NETWORK_TYPE_ALL}. 361 * When disabled, mobile data is broken down by a granular ratType representative of the 362 * actual ratType. See {@link android.app.usage.NetworkStatsManager#getCollapsedRatType}. 363 * Enabling this decreases the level of detail but saves performance, disk space and 364 * amount of data logged. 365 */ getCombineSubtypeEnabled()366 boolean getCombineSubtypeEnabled(); 367 368 class Config { 369 public final long bucketDuration; 370 public final long rotateAgeMillis; 371 public final long deleteAgeMillis; 372 Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis)373 public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) { 374 this.bucketDuration = bucketDuration; 375 this.rotateAgeMillis = rotateAgeMillis; 376 this.deleteAgeMillis = deleteAgeMillis; 377 } 378 } 379 getXtConfig()380 Config getXtConfig(); getUidConfig()381 Config getUidConfig(); getUidTagConfig()382 Config getUidTagConfig(); 383 getGlobalAlertBytes(long def)384 long getGlobalAlertBytes(long def); getXtPersistBytes(long def)385 long getXtPersistBytes(long def); getUidPersistBytes(long def)386 long getUidPersistBytes(long def); getUidTagPersistBytes(long def)387 long getUidTagPersistBytes(long def); 388 } 389 390 private final Object mStatsLock = new Object(); 391 392 /** Set of currently active ifaces. */ 393 @GuardedBy("mStatsLock") 394 private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>(); 395 396 /** Set of currently active ifaces for UID stats. */ 397 @GuardedBy("mStatsLock") 398 private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>(); 399 400 /** Current default active iface. */ 401 @GuardedBy("mStatsLock") 402 private String mActiveIface; 403 404 /** Set of all ifaces currently associated with mobile networks. */ 405 private volatile String[] mMobileIfaces = new String[0]; 406 407 /* A set of all interfaces that have ever been associated with mobile networks since boot. */ 408 @GuardedBy("mStatsLock") 409 private final Set<String> mAllMobileIfacesSinceBoot = new ArraySet<>(); 410 411 /* A set of all interfaces that have ever been associated with wifi networks since boot. */ 412 @GuardedBy("mStatsLock") 413 private final Set<String> mAllWifiIfacesSinceBoot = new ArraySet<>(); 414 415 /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ 416 @GuardedBy("mStatsLock") 417 private Network[] mDefaultNetworks = new Network[0]; 418 419 /** Last states of all networks sent from ConnectivityService. */ 420 @GuardedBy("mStatsLock") 421 @Nullable 422 private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null; 423 424 private final DropBoxNonMonotonicObserver mNonMonotonicObserver = 425 new DropBoxNonMonotonicObserver(); 426 427 private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; 428 private final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList = 429 new CopyOnWriteArrayList<>(); 430 /** Semaphore used to wait for stats provider to respond to request stats update. */ 431 private final Semaphore mStatsProviderSem = new Semaphore(0, true); 432 433 @GuardedBy("mStatsLock") 434 private NetworkStatsRecorder mXtRecorder; 435 @GuardedBy("mStatsLock") 436 private NetworkStatsRecorder mUidRecorder; 437 @GuardedBy("mStatsLock") 438 private NetworkStatsRecorder mUidTagRecorder; 439 440 /** Cached {@link #mXtRecorder} stats. */ 441 @GuardedBy("mStatsLock") 442 private NetworkStatsCollection mXtStatsCached; 443 444 /** 445 * Current counter sets for each UID. 446 * TODO: maybe remove mActiveUidCounterSet and read UidCouneterSet value from mUidCounterSetMap 447 * directly ? But if mActiveUidCounterSet would be accessed very frequently, maybe keep 448 * mActiveUidCounterSet to avoid accessing kernel too frequently. 449 */ 450 private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); 451 private final IBpfMap<S32, U8> mUidCounterSetMap; 452 private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap; 453 private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapA; 454 private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapB; 455 private final IBpfMap<UidStatsMapKey, StatsMapValue> mAppUidStatsMap; 456 private final IBpfMap<S32, StatsMapValue> mIfaceStatsMap; 457 458 /** Data layer operation counters for splicing into other structures. */ 459 private NetworkStats mUidOperations = new NetworkStats(0L, 10); 460 461 @NonNull 462 private final Handler mHandler; 463 464 private volatile boolean mSystemReady; 465 private long mPersistThreshold = 2 * MB_IN_BYTES; 466 private long mGlobalAlertBytes; 467 468 private static final long POLL_RATE_LIMIT_MS = 15_000; 469 470 private long mLastStatsSessionPoll; 471 472 private final TrafficStatsRateLimitCache mTrafficStatsTotalCache; 473 private final TrafficStatsRateLimitCache mTrafficStatsIfaceCache; 474 private final TrafficStatsRateLimitCache mTrafficStatsUidCache; 475 static final String TRAFFICSTATS_RATE_LIMIT_CACHE_ENABLED_FLAG = 476 "trafficstats_rate_limit_cache_enabled_flag"; 477 private final boolean mAlwaysUseTrafficStatsRateLimitCache; 478 private final int mTrafficStatsRateLimitCacheExpiryDuration; 479 private final int mTrafficStatsRateLimitCacheMaxEntries; 480 481 private final Object mOpenSessionCallsLock = new Object(); 482 483 /** 484 * Map from key {@code OpenSessionKey} to count of opened sessions. This is for recording 485 * the caller of open session and it is only for debugging. 486 */ 487 // TODO: Move to NetworkStatsEventLogger to centralize event logging. 488 @GuardedBy("mOpenSessionCallsLock") 489 private final HashMap<OpenSessionKey, Integer> mOpenSessionCallsPerCaller = new HashMap<>(); 490 491 private final static int DUMP_STATS_SESSION_COUNT = 20; 492 493 @NonNull 494 private final Dependencies mDeps; 495 496 @NonNull 497 private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; 498 499 @NonNull 500 private final LocationPermissionChecker mLocationPermissionChecker; 501 502 @NonNull 503 private final BpfInterfaceMapHelper mInterfaceMapHelper; 504 505 @Nullable 506 private final SkDestroyListener mSkDestroyListener; 507 508 private static final int MAX_SOCKET_DESTROY_LISTENER_LOGS = 20; 509 getDefaultClock()510 private static @NonNull Clock getDefaultClock() { 511 return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(), 512 Clock.systemUTC()); 513 } 514 515 /** 516 * This class is a key that used in {@code mOpenSessionCallsPerCaller} to identify the count of 517 * the caller. 518 */ 519 private static class OpenSessionKey { 520 public final int uid; 521 @Nullable 522 public final String packageName; 523 OpenSessionKey(int uid, @Nullable String packageName)524 OpenSessionKey(int uid, @Nullable String packageName) { 525 this.uid = uid; 526 this.packageName = packageName; 527 } 528 529 @Override toString()530 public String toString() { 531 final StringBuilder sb = new StringBuilder(); 532 sb.append("{"); 533 sb.append("uid=").append(uid).append(","); 534 sb.append("package=").append(packageName); 535 sb.append("}"); 536 return sb.toString(); 537 } 538 539 @Override equals(@onNull Object o)540 public boolean equals(@NonNull Object o) { 541 if (this == o) return true; 542 if (o.getClass() != getClass()) return false; 543 544 final OpenSessionKey key = (OpenSessionKey) o; 545 return this.uid == key.uid && TextUtils.equals(this.packageName, key.packageName); 546 } 547 548 @Override hashCode()549 public int hashCode() { 550 return Objects.hash(uid, packageName); 551 } 552 } 553 554 private final class NetworkStatsHandler extends Handler { NetworkStatsHandler(@onNull Looper looper)555 NetworkStatsHandler(@NonNull Looper looper) { 556 super(looper); 557 } 558 559 @Override handleMessage(Message msg)560 public void handleMessage(Message msg) { 561 switch (msg.what) { 562 case MSG_PERFORM_POLL: { 563 performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent((int) msg.obj)); 564 break; 565 } 566 case MSG_NOTIFY_NETWORK_STATUS: { 567 synchronized (mStatsLock) { 568 // If no cached states, ignore. 569 if (mLastNetworkStateSnapshots == null) break; 570 handleNotifyNetworkStatus(mDefaultNetworks, mLastNetworkStateSnapshots, 571 mActiveIface, maybeCreatePollEvent((int) msg.obj)); 572 } 573 break; 574 } 575 case MSG_PERFORM_POLL_REGISTER_ALERT: { 576 performPoll(FLAG_PERSIST_NETWORK, 577 maybeCreatePollEvent(POLL_REASON_GLOBAL_ALERT)); 578 registerGlobalAlert(); 579 break; 580 } 581 case MSG_BROADCAST_NETWORK_STATS_UPDATED: { 582 final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); 583 updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 584 Bundle opts = null; 585 if (SdkLevel.isAtLeastU()) { 586 try { 587 // This allows us to discard older broadcasts still waiting to 588 // be delivered. 589 opts = BroadcastOptionsShimImpl.newInstance( 590 BroadcastOptions.makeBasic()) 591 .setDeliveryGroupPolicy( 592 ConstantsShim.DELIVERY_GROUP_POLICY_MOST_RECENT) 593 .setDeferralPolicy( 594 ConstantsShim.DEFERRAL_POLICY_UNTIL_ACTIVE) 595 .toBundle(); 596 } catch (UnsupportedApiLevelException e) { 597 Log.wtf(TAG, "Using unsupported API" + e); 598 } 599 } 600 mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, 601 READ_NETWORK_USAGE_HISTORY, opts); 602 break; 603 } 604 } 605 } 606 } 607 608 /** Creates a new NetworkStatsService */ create(Context context)609 public static NetworkStatsService create(Context context) { 610 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 611 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 612 PowerManager.WakeLock wakeLock = 613 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 614 final INetd netd = INetd.Stub.asInterface( 615 (IBinder) context.getSystemService(Context.NETD_SERVICE)); 616 final NetworkStatsService service = new NetworkStatsService(context, 617 INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), 618 alarmManager, wakeLock, getDefaultClock(), 619 new DefaultNetworkStatsSettings(), new NetworkStatsFactory(context), 620 new NetworkStatsObservers(), new Dependencies()); 621 622 return service; 623 } 624 625 // This must not be called outside of tests, even within the same package, as this constructor 626 // does not register the local service. Use the create() helper above. 627 @VisibleForTesting NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings, NetworkStatsFactory factory, NetworkStatsObservers statsObservers, @NonNull Dependencies deps)628 NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager, 629 PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings, 630 NetworkStatsFactory factory, NetworkStatsObservers statsObservers, 631 @NonNull Dependencies deps) { 632 mContext = Objects.requireNonNull(context, "missing Context"); 633 mNetd = Objects.requireNonNull(netd, "missing Netd"); 634 mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); 635 mClock = Objects.requireNonNull(clock, "missing Clock"); 636 mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); 637 mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); 638 mStatsFactory = Objects.requireNonNull(factory, "missing factory"); 639 mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); 640 mDeps = Objects.requireNonNull(deps, "missing Dependencies"); 641 mStatsDir = mDeps.getOrCreateStatsDir(); 642 if (!mStatsDir.exists()) { 643 throw new IllegalStateException("Persist data directory does not exist: " + mStatsDir); 644 } 645 646 final HandlerThread handlerThread = mDeps.makeHandlerThread(); 647 handlerThread.start(); 648 mHandler = new NetworkStatsHandler(handlerThread.getLooper()); 649 mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, 650 (command) -> mHandler.post(command) , this); 651 mContentResolver = mContext.getContentResolver(); 652 mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, 653 mNetworkStatsSubscriptionsMonitor); 654 mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); 655 mInterfaceMapHelper = mDeps.makeBpfInterfaceMapHelper(); 656 mUidCounterSetMap = mDeps.getUidCounterSetMap(); 657 mCookieTagMap = mDeps.getCookieTagMap(); 658 mStatsMapA = mDeps.getStatsMapA(); 659 mStatsMapB = mDeps.getStatsMapB(); 660 mAppUidStatsMap = mDeps.getAppUidStatsMap(); 661 mIfaceStatsMap = mDeps.getIfaceStatsMap(); 662 // To prevent any possible races, the flag is not allowed to change until rebooting. 663 mSupportEventLogger = mDeps.supportEventLogger(mContext); 664 if (mSupportEventLogger) { 665 mEventLogger = new NetworkStatsEventLogger(); 666 } else { 667 mEventLogger = null; 668 } 669 670 mAlwaysUseTrafficStatsRateLimitCache = 671 mDeps.alwaysUseTrafficStatsRateLimitCache(mContext); 672 mTrafficStatsRateLimitCacheExpiryDuration = 673 mDeps.getTrafficStatsRateLimitCacheExpiryDuration(); 674 mTrafficStatsRateLimitCacheMaxEntries = 675 mDeps.getTrafficStatsRateLimitCacheMaxEntries(); 676 mTrafficStatsTotalCache = new TrafficStatsRateLimitCache(mClock, 677 mTrafficStatsRateLimitCacheExpiryDuration, mTrafficStatsRateLimitCacheMaxEntries); 678 mTrafficStatsIfaceCache = new TrafficStatsRateLimitCache(mClock, 679 mTrafficStatsRateLimitCacheExpiryDuration, mTrafficStatsRateLimitCacheMaxEntries); 680 mTrafficStatsUidCache = new TrafficStatsRateLimitCache(mClock, 681 mTrafficStatsRateLimitCacheExpiryDuration, mTrafficStatsRateLimitCacheMaxEntries); 682 683 // TODO: Remove bpfNetMaps creation and always start SkDestroyListener 684 // Following code is for the experiment to verify the SkDestroyListener refactoring. Based 685 // on the experiment flag, BpfNetMaps starts C SkDestroyListener (existing code) or 686 // NetworkStatsService starts Java SkDestroyListener (new code). 687 final BpfNetMaps bpfNetMaps = mDeps.makeBpfNetMaps(mContext); 688 mSkDestroyListener = mDeps.makeSkDestroyListener(mCookieTagMap, mHandler); 689 mHandler.post(mSkDestroyListener::start); 690 } 691 692 /** 693 * Dependencies of NetworkStatsService, for injection in tests. 694 */ 695 // TODO: Move more stuff into dependencies object. 696 @VisibleForTesting 697 public static class Dependencies { 698 /** 699 * Get legacy platform stats directory. 700 */ 701 @NonNull getLegacyStatsDir()702 public File getLegacyStatsDir() { 703 final File systemDataDir = new File(Environment.getDataDirectory(), "system"); 704 return new File(systemDataDir, "netstats"); 705 } 706 707 /** 708 * Get or create the directory that stores the persisted data usage. 709 */ 710 @NonNull getOrCreateStatsDir()711 public File getOrCreateStatsDir() { 712 final boolean storeInApexDataDir = getStoreFilesInApexData(); 713 714 final File statsDataDir; 715 if (storeInApexDataDir) { 716 final File apexDataDir = ApexEnvironment 717 .getApexEnvironment(DeviceConfigUtils.TETHERING_MODULE_NAME) 718 .getDeviceProtectedDataDir(); 719 statsDataDir = new File(apexDataDir, "netstats"); 720 721 } else { 722 statsDataDir = getLegacyStatsDir(); 723 } 724 725 if (statsDataDir.exists() || statsDataDir.mkdirs()) { 726 return statsDataDir; 727 } 728 throw new IllegalStateException("Cannot write into stats data directory: " 729 + statsDataDir); 730 } 731 732 /** 733 * Get the count of import legacy target attempts. 734 */ getImportLegacyTargetAttempts()735 public int getImportLegacyTargetAttempts() { 736 return getDeviceConfigPropertyInt( 737 DeviceConfig.NAMESPACE_TETHERING, 738 NETSTATS_IMPORT_LEGACY_TARGET_ATTEMPTS, 739 DEFAULT_NETSTATS_IMPORT_LEGACY_TARGET_ATTEMPTS); 740 } 741 742 /** 743 * Get the count of using FastDataInput target attempts. 744 */ getUseFastDataInputTargetAttempts()745 public int getUseFastDataInputTargetAttempts() { 746 return getDeviceConfigPropertyInt( 747 DeviceConfig.NAMESPACE_TETHERING, 748 NETSTATS_FASTDATAINPUT_TARGET_ATTEMPTS, 0); 749 } 750 751 /** 752 * Compare two {@link NetworkStatsCollection} instances and returning a human-readable 753 * string description of difference for debugging purpose. 754 */ compareStats(@onNull NetworkStatsCollection a, @NonNull NetworkStatsCollection b, boolean allowKeyChange)755 public String compareStats(@NonNull NetworkStatsCollection a, 756 @NonNull NetworkStatsCollection b, boolean allowKeyChange) { 757 return NetworkStatsCollection.compareStats(a, b, allowKeyChange); 758 } 759 760 /** 761 * Create a persistent counter for given directory and name. 762 */ createPersistentCounter(@onNull Path dir, @NonNull String name)763 public PersistentInt createPersistentCounter(@NonNull Path dir, @NonNull String name) 764 throws IOException { 765 // TODO: Modify PersistentInt to call setStartTime every time a write is made. 766 // Create and pass a real logger here. 767 final String path = dir.resolve(name).toString(); 768 return new PersistentInt(path, null /* logger */); 769 } 770 771 /** 772 * Get the flag of storing files in the apex data directory. 773 * @return whether to store files in the apex data directory. 774 */ getStoreFilesInApexData()775 public boolean getStoreFilesInApexData() { 776 return DeviceConfigUtils.getDeviceConfigPropertyBoolean( 777 DeviceConfig.NAMESPACE_TETHERING, 778 NETSTATS_STORE_FILES_IN_APEXDATA, true); 779 } 780 781 /** 782 * Read legacy persisted network stats from disk. 783 */ 784 @NonNull readPlatformCollection( @onNull String prefix, long bucketDuration)785 public NetworkStatsCollection readPlatformCollection( 786 @NonNull String prefix, long bucketDuration) throws IOException { 787 return NetworkStatsDataMigrationUtils.readPlatformCollection(prefix, bucketDuration); 788 } 789 790 /** 791 * Create a HandlerThread to use in NetworkStatsService. 792 */ 793 @NonNull makeHandlerThread()794 public HandlerThread makeHandlerThread() { 795 return new HandlerThread(TAG); 796 } 797 798 /** 799 * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change 800 * event in NetworkStatsService. 801 */ 802 @NonNull makeSubscriptionsMonitor(@onNull Context context, @NonNull Executor executor, @NonNull NetworkStatsService service)803 public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, 804 @NonNull Executor executor, @NonNull NetworkStatsService service) { 805 // TODO: Update RatType passively in NSS, instead of querying into the monitor 806 // when notifyNetworkStatus. 807 return new NetworkStatsSubscriptionsMonitor(context, executor, 808 (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); 809 } 810 811 /** 812 * Create a ContentObserver instance which is used to observe settings changes, 813 * and dispatch onChange events on handler thread. 814 */ makeContentObserver(@onNull Handler handler, @NonNull NetworkStatsSettings settings, @NonNull NetworkStatsSubscriptionsMonitor monitor)815 public @NonNull ContentObserver makeContentObserver(@NonNull Handler handler, 816 @NonNull NetworkStatsSettings settings, 817 @NonNull NetworkStatsSubscriptionsMonitor monitor) { 818 return new ContentObserver(handler) { 819 @Override 820 public void onChange(boolean selfChange, @NonNull Uri uri) { 821 if (!settings.getCombineSubtypeEnabled()) { 822 monitor.start(); 823 } else { 824 monitor.stop(); 825 } 826 } 827 }; 828 } 829 830 /** 831 * @see LocationPermissionChecker 832 */ 833 public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { 834 return new LocationPermissionChecker(context); 835 } 836 837 /** Create BpfInterfaceMapHelper to update bpf interface map. */ 838 @NonNull 839 public BpfInterfaceMapHelper makeBpfInterfaceMapHelper() { 840 return new BpfInterfaceMapHelper(); 841 } 842 843 /** Get counter sets map for each UID. */ 844 public IBpfMap<S32, U8> getUidCounterSetMap() { 845 try { 846 return new BpfMap<>(UID_COUNTERSET_MAP_PATH, S32.class, U8.class); 847 } catch (ErrnoException e) { 848 Log.wtf(TAG, "Cannot open uid counter set map: " + e); 849 return null; 850 } 851 } 852 853 /** Gets the cookie tag map */ 854 public IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() { 855 try { 856 return new BpfMap<>(COOKIE_TAG_MAP_PATH, 857 CookieTagMapKey.class, CookieTagMapValue.class); 858 } catch (ErrnoException e) { 859 Log.wtf(TAG, "Cannot open cookie tag map: " + e); 860 return null; 861 } 862 } 863 864 /** Gets stats map A */ 865 public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapA() { 866 try { 867 return new BpfMap<>(STATS_MAP_A_PATH, StatsMapKey.class, StatsMapValue.class); 868 } catch (ErrnoException e) { 869 Log.wtf(TAG, "Cannot open stats map A: " + e); 870 return null; 871 } 872 } 873 874 /** Gets stats map B */ 875 public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapB() { 876 try { 877 return new BpfMap<>(STATS_MAP_B_PATH, StatsMapKey.class, StatsMapValue.class); 878 } catch (ErrnoException e) { 879 Log.wtf(TAG, "Cannot open stats map B: " + e); 880 return null; 881 } 882 } 883 884 /** Gets the uid stats map */ 885 public IBpfMap<UidStatsMapKey, StatsMapValue> getAppUidStatsMap() { 886 try { 887 return new BpfMap<>(APP_UID_STATS_MAP_PATH, 888 UidStatsMapKey.class, StatsMapValue.class); 889 } catch (ErrnoException e) { 890 Log.wtf(TAG, "Cannot open app uid stats map: " + e); 891 return null; 892 } 893 } 894 895 /** Gets interface stats map */ 896 public IBpfMap<S32, StatsMapValue> getIfaceStatsMap() { 897 try { 898 return new BpfMap<>(IFACE_STATS_MAP_PATH, S32.class, StatsMapValue.class); 899 } catch (ErrnoException e) { 900 throw new IllegalStateException("Failed to open interface stats map", e); 901 } 902 } 903 904 /** Gets whether the build is userdebug. */ 905 public boolean isDebuggable() { 906 return Build.isDebuggable(); 907 } 908 909 /** Create a new BpfNetMaps. */ 910 public BpfNetMaps makeBpfNetMaps(Context ctx) { 911 return new BpfNetMaps(ctx); 912 } 913 914 /** Create a new SkDestroyListener. */ 915 public SkDestroyListener makeSkDestroyListener( 916 IBpfMap<CookieTagMapKey, CookieTagMapValue> cookieTagMap, Handler handler) { 917 return new SkDestroyListener( 918 cookieTagMap, handler, new SharedLog(MAX_SOCKET_DESTROY_LISTENER_LOGS, TAG)); 919 } 920 921 /** 922 * Get whether event logger feature is supported. 923 */ 924 public boolean supportEventLogger(Context ctx) { 925 return DeviceConfigUtils.isTetheringFeatureNotChickenedOut( 926 ctx, CONFIG_ENABLE_NETWORK_STATS_EVENT_LOGGER); 927 } 928 929 /** 930 * Get whether TrafficStats rate-limit cache is always applied. 931 * 932 * This method should only be called once in the constructor, 933 * to ensure that the code does not need to deal with flag values changing at runtime. 934 */ 935 public boolean alwaysUseTrafficStatsRateLimitCache(@NonNull Context ctx) { 936 return SdkLevel.isAtLeastV() && DeviceConfigUtils.isTetheringFeatureNotChickenedOut( 937 ctx, TRAFFICSTATS_RATE_LIMIT_CACHE_ENABLED_FLAG); 938 } 939 940 /** 941 * Get TrafficStats rate-limit cache expiry. 942 * 943 * This method should only be called once in the constructor, 944 * to ensure that the code does not need to deal with flag values changing at runtime. 945 */ 946 public int getTrafficStatsRateLimitCacheExpiryDuration() { 947 return getDeviceConfigPropertyInt( 948 NAMESPACE_TETHERING, TRAFFIC_STATS_CACHE_EXPIRY_DURATION_NAME, 949 DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS); 950 } 951 952 /** 953 * Get TrafficStats rate-limit cache max entries. 954 * 955 * This method should only be called once in the constructor, 956 * to ensure that the code does not need to deal with flag values changing at runtime. 957 */ 958 public int getTrafficStatsRateLimitCacheMaxEntries() { 959 return getDeviceConfigPropertyInt( 960 NAMESPACE_TETHERING, TRAFFIC_STATS_CACHE_MAX_ENTRIES_NAME, 961 DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES); 962 } 963 964 /** 965 * Wrapper method for {@link CompatChanges#isChangeEnabled(long, int)} 966 */ 967 public boolean isChangeEnabled(final long changeId, final int uid) { 968 return CompatChanges.isChangeEnabled(changeId, uid); 969 } 970 971 /** 972 * Retrieves native network total statistics. 973 * 974 * @return A NetworkStats.Entry containing the native statistics, or 975 * null if an error occurs. 976 */ 977 @Nullable 978 public NetworkStats.Entry nativeGetTotalStat() { 979 return NetworkStatsService.nativeGetTotalStat(); 980 } 981 982 /** 983 * Retrieves native network interface statistics for the specified interface. 984 * 985 * @param iface The name of the network interface to query. 986 * @return A NetworkStats.Entry containing the native statistics for the interface, or 987 * null if an error occurs. 988 */ 989 @Nullable 990 public NetworkStats.Entry nativeGetIfaceStat(String iface) { 991 return NetworkStatsService.nativeGetIfaceStat(iface); 992 } 993 994 /** 995 * Retrieves native network uid statistics for the specified uid. 996 * 997 * @param uid The uid of the application to query. 998 * @return A NetworkStats.Entry containing the native statistics for the uid, or 999 * null if an error occurs. 1000 */ 1001 @Nullable 1002 public NetworkStats.Entry nativeGetUidStat(int uid) { 1003 return NetworkStatsService.nativeGetUidStat(uid); 1004 } 1005 } 1006 1007 /** 1008 * Observer that watches for {@link INetdUnsolicitedEventListener} alerts. 1009 */ 1010 @VisibleForTesting 1011 public class AlertObserver extends BaseNetdUnsolicitedEventListener { 1012 @Override 1013 public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { 1014 PermissionUtils.enforceNetworkStackPermission(mContext); 1015 1016 if (LIMIT_GLOBAL_ALERT.equals(alertName)) { 1017 // kick off background poll to collect network stats unless there is already 1018 // such a call pending; UID stats are handled during normal polling interval. 1019 if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { 1020 mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, 1021 mSettings.getPollDelay()); 1022 } 1023 } 1024 } 1025 } 1026 1027 public void systemReady() { 1028 synchronized (mStatsLock) { 1029 mSystemReady = true; 1030 1031 makeRecordersLocked(); 1032 1033 updatePersistThresholdsLocked(); 1034 1035 // upgrade any legacy stats 1036 maybeUpgradeLegacyStatsLocked(); 1037 1038 // read historical network stats from disk, since policy service 1039 // might need them right away. 1040 mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked(); 1041 1042 // bootstrap initial stats to prevent double-counting later 1043 bootstrapStatsLocked(); 1044 } 1045 1046 // watch for tethering changes 1047 final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); 1048 tetheringManager.registerTetheringEventCallback( 1049 (command) -> mHandler.post(command), mTetherListener); 1050 1051 // listen for periodic polling events 1052 final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); 1053 mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); 1054 1055 // listen for uid removal to clean stats 1056 final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); 1057 mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); 1058 1059 // listen for user changes to clean stats 1060 final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED); 1061 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); 1062 1063 // persist stats during clean shutdown 1064 final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN); 1065 mContext.registerReceiver(mShutdownReceiver, shutdownFilter); 1066 1067 try { 1068 mNetd.registerUnsolicitedEventListener(mAlertObserver); 1069 } catch (RemoteException | ServiceSpecificException e) { 1070 Log.wtf(TAG, "Error registering event listener :", e); 1071 } 1072 1073 // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. 1074 final PendingIntent pollIntent = 1075 PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 1076 PendingIntent.FLAG_IMMUTABLE); 1077 1078 final long currentRealtime = SystemClock.elapsedRealtime(); 1079 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, 1080 mSettings.getPollInterval(), pollIntent); 1081 1082 mContentResolver.registerContentObserver(Settings.Global 1083 .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED), 1084 false /* notifyForDescendants */, mContentObserver); 1085 1086 // Post a runnable on handler thread to call onChange(). It's for getting current value of 1087 // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes. 1088 mHandler.post(() -> mContentObserver.onChange(false, Settings.Global 1089 .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED))); 1090 1091 registerGlobalAlert(); 1092 } 1093 1094 private NetworkStatsRecorder buildRecorder( 1095 String prefix, NetworkStatsSettings.Config config, boolean includeTags, 1096 File baseDir, boolean wipeOnError, boolean useFastDataInput) { 1097 final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( 1098 Context.DROPBOX_SERVICE); 1099 return new NetworkStatsRecorder(new FileRotator( 1100 baseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), 1101 mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags, 1102 wipeOnError, useFastDataInput, baseDir); 1103 } 1104 1105 @GuardedBy("mStatsLock") 1106 private void makeRecordersLocked() { 1107 boolean useFastDataInput = true; 1108 try { 1109 mFastDataInputSuccessesCounter = mDeps.createPersistentCounter(mStatsDir.toPath(), 1110 NETSTATS_FASTDATAINPUT_SUCCESSES_COUNTER_NAME); 1111 mFastDataInputFallbacksCounter = mDeps.createPersistentCounter(mStatsDir.toPath(), 1112 NETSTATS_FASTDATAINPUT_FALLBACKS_COUNTER_NAME); 1113 } catch (IOException e) { 1114 Log.wtf(TAG, "Failed to create persistent counters, skip.", e); 1115 useFastDataInput = false; 1116 } 1117 1118 final int targetAttempts = mDeps.getUseFastDataInputTargetAttempts(); 1119 int successes = 0; 1120 int fallbacks = 0; 1121 try { 1122 successes = mFastDataInputSuccessesCounter.get(); 1123 // Fallbacks counter would be set to non-zero value to indicate the reading was 1124 // not successful. 1125 fallbacks = mFastDataInputFallbacksCounter.get(); 1126 } catch (IOException e) { 1127 Log.wtf(TAG, "Failed to read counters, skip.", e); 1128 useFastDataInput = false; 1129 } 1130 1131 final boolean doComparison; 1132 if (useFastDataInput) { 1133 // Use FastDataInput if it needs to be evaluated or at least one success. 1134 doComparison = targetAttempts > successes + fallbacks; 1135 // Set target attempt to -1 as the kill switch to disable the feature. 1136 useFastDataInput = targetAttempts >= 0 && (doComparison || successes > 0); 1137 } else { 1138 // useFastDataInput is false due to previous failures. 1139 doComparison = false; 1140 } 1141 1142 // create data recorders along with historical rotators. 1143 // Don't wipe on error if comparison is needed. 1144 mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, mStatsDir, 1145 !doComparison /* wipeOnError */, useFastDataInput); 1146 mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, mStatsDir, 1147 !doComparison /* wipeOnError */, useFastDataInput); 1148 mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true, 1149 mStatsDir, !doComparison /* wipeOnError */, useFastDataInput); 1150 1151 if (!doComparison) return; 1152 1153 final MigrationInfo[] migrations = new MigrationInfo[]{ 1154 new MigrationInfo(mXtRecorder), 1155 new MigrationInfo(mUidRecorder), 1156 new MigrationInfo(mUidTagRecorder) 1157 }; 1158 // Set wipeOnError flag false so the recorder won't damage persistent data if reads 1159 // failed and calling deleteAll. 1160 final NetworkStatsRecorder[] legacyRecorders = new NetworkStatsRecorder[]{ 1161 buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, mStatsDir, 1162 false /* wipeOnError */, false /* useFastDataInput */), 1163 buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, mStatsDir, 1164 false /* wipeOnError */, false /* useFastDataInput */), 1165 buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true, mStatsDir, 1166 false /* wipeOnError */, false /* useFastDataInput */)}; 1167 boolean success = true; 1168 for (int i = 0; i < migrations.length; i++) { 1169 try { 1170 migrations[i].collection = migrations[i].recorder.getOrLoadCompleteLocked(); 1171 } catch (Throwable t) { 1172 Log.wtf(TAG, "Failed to load collection, skip.", t); 1173 success = false; 1174 break; 1175 } 1176 if (!compareImportedToLegacyStats(migrations[i], legacyRecorders[i], 1177 false /* allowKeyChange */)) { 1178 success = false; 1179 break; 1180 } 1181 } 1182 1183 try { 1184 if (success) { 1185 mFastDataInputSuccessesCounter.set(successes + 1); 1186 } else { 1187 // Fallback. 1188 mXtRecorder = legacyRecorders[0]; 1189 mUidRecorder = legacyRecorders[1]; 1190 mUidTagRecorder = legacyRecorders[2]; 1191 mFastDataInputFallbacksCounter.set(fallbacks + 1); 1192 } 1193 } catch (IOException e) { 1194 Log.wtf(TAG, "Failed to update counters. success = " + success, e); 1195 } 1196 } 1197 1198 @GuardedBy("mStatsLock") 1199 private void shutdownLocked() { 1200 final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); 1201 try { 1202 tetheringManager.unregisterTetheringEventCallback(mTetherListener); 1203 } catch (IllegalStateException e) { 1204 Log.i(TAG, "shutdownLocked: error when unregister tethering, ignored. e=" + e); 1205 } 1206 mContext.unregisterReceiver(mPollReceiver); 1207 mContext.unregisterReceiver(mRemovedReceiver); 1208 mContext.unregisterReceiver(mUserReceiver); 1209 mContext.unregisterReceiver(mShutdownReceiver); 1210 1211 if (!mSettings.getCombineSubtypeEnabled()) { 1212 mNetworkStatsSubscriptionsMonitor.stop(); 1213 } 1214 1215 mContentResolver.unregisterContentObserver(mContentObserver); 1216 1217 final long currentTime = mClock.millis(); 1218 1219 // persist any pending stats 1220 mXtRecorder.forcePersistLocked(currentTime); 1221 mUidRecorder.forcePersistLocked(currentTime); 1222 mUidTagRecorder.forcePersistLocked(currentTime); 1223 1224 mSystemReady = false; 1225 } 1226 1227 private static class MigrationInfo { 1228 public final NetworkStatsRecorder recorder; 1229 public NetworkStatsCollection collection; 1230 public boolean imported; 1231 MigrationInfo(@NonNull final NetworkStatsRecorder recorder) { 1232 this.recorder = recorder; 1233 collection = null; 1234 imported = false; 1235 } 1236 } 1237 1238 @GuardedBy("mStatsLock") 1239 private void maybeUpgradeLegacyStatsLocked() { 1240 final boolean storeFilesInApexData = mDeps.getStoreFilesInApexData(); 1241 if (!storeFilesInApexData) { 1242 return; 1243 } 1244 try { 1245 mImportLegacyAttemptsCounter = mDeps.createPersistentCounter(mStatsDir.toPath(), 1246 NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME); 1247 mImportLegacySuccessesCounter = mDeps.createPersistentCounter(mStatsDir.toPath(), 1248 NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME); 1249 mImportLegacyFallbacksCounter = mDeps.createPersistentCounter(mStatsDir.toPath(), 1250 NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME); 1251 } catch (IOException e) { 1252 Log.wtf(TAG, "Failed to create persistent counters, skip.", e); 1253 return; 1254 } 1255 1256 final int targetAttempts = mDeps.getImportLegacyTargetAttempts(); 1257 final int attempts; 1258 final int fallbacks; 1259 final boolean runComparison; 1260 try { 1261 attempts = mImportLegacyAttemptsCounter.get(); 1262 // Fallbacks counter would be set to non-zero value to indicate the migration was 1263 // not successful. 1264 fallbacks = mImportLegacyFallbacksCounter.get(); 1265 runComparison = shouldRunComparison(); 1266 } catch (IOException e) { 1267 Log.wtf(TAG, "Failed to read counters, skip.", e); 1268 return; 1269 } 1270 1271 // If the target number of attempts are reached, don't import any data. 1272 // However, if comparison is requested, still read the legacy data and compare 1273 // it to the importer output. This allows OEMs to debug issues with the 1274 // importer code and to collect signals from the field. 1275 final boolean dryRunImportOnly = 1276 fallbacks != 0 && runComparison && (attempts >= targetAttempts); 1277 // Return if target attempts are reached and there is no need to dry run. 1278 if (attempts >= targetAttempts && !dryRunImportOnly) return; 1279 1280 if (dryRunImportOnly) { 1281 Log.i(TAG, "Starting import : only perform read"); 1282 } else { 1283 Log.i(TAG, "Starting import : attempts " + attempts + "/" + targetAttempts); 1284 } 1285 1286 // Still create a legacy dev recorder locally but the service doesn't really use it. 1287 // This is for backward compatibility where the OEMs might call readPlatformCollection to 1288 // perform proprietary operations and relying on the side-effects to complete the follow-up 1289 // import process. 1290 final NetworkStatsSettings.Config devConfig = 1291 new NetworkStatsSettings.Config(HOUR_IN_MILLIS, 1292 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); 1293 final NetworkStatsRecorder devRecorder = buildRecorder(PREFIX_DEV, devConfig, 1294 false, mStatsDir, true /* wipeOnError */, false /* useFastDataInput */); 1295 final MigrationInfo[] migrations = new MigrationInfo[]{ 1296 new MigrationInfo(devRecorder), new MigrationInfo(mXtRecorder), 1297 new MigrationInfo(mUidRecorder), new MigrationInfo(mUidTagRecorder) 1298 }; 1299 1300 // Legacy directories will be created by recorders if they do not exist 1301 final NetworkStatsRecorder[] legacyRecorders; 1302 if (runComparison) { 1303 final File legacyBaseDir = mDeps.getLegacyStatsDir(); 1304 // Set wipeOnError flag false so the recorder won't damage persistent data if reads 1305 // failed and calling deleteAll. 1306 // Set DEV legacy recorder as null since the DEV recorder has been removed. 1307 // Thus it doesn't need to build DEV legacy recorder for comparing with imported data. 1308 legacyRecorders = new NetworkStatsRecorder[]{ 1309 null /* dev Recorder */, 1310 buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, legacyBaseDir, 1311 false /* wipeOnError */, false /* useFastDataInput */), 1312 buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, legacyBaseDir, 1313 false /* wipeOnError */, false /* useFastDataInput */), 1314 buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true, legacyBaseDir, 1315 false /* wipeOnError */, false /* useFastDataInput */)}; 1316 } else { 1317 legacyRecorders = null; 1318 } 1319 1320 long migrationEndTime = Long.MIN_VALUE; 1321 try { 1322 // First, read all legacy collections. This is OEM code and it can throw. Don't 1323 // commit any data to disk until all are read. 1324 for (int i = 0; i < migrations.length; i++) { 1325 final MigrationInfo migration = migrations[i]; 1326 // Read the collection from platform code, and set fallbacks counter if throws 1327 // for better debugging. 1328 try { 1329 migration.collection = readPlatformCollectionForRecorder(migration.recorder); 1330 } catch (Throwable e) { 1331 if (dryRunImportOnly) { 1332 Log.wtf(TAG, "Platform data read failed. ", e); 1333 return; 1334 } else { 1335 // Data is not imported successfully, set fallbacks counter to non-zero 1336 // value to trigger dry run every later boot when the runComparison is 1337 // true, in order to make it easier to debug issues. 1338 tryIncrementLegacyFallbacksCounter(); 1339 // Re-throw for error handling. This will increase attempts counter. 1340 throw e; 1341 } 1342 } 1343 1344 if (runComparison) { 1345 final boolean success = 1346 compareImportedToLegacyStats(migration, legacyRecorders[i], 1347 true /* allowKeyChange */); 1348 if (!success && !dryRunImportOnly) { 1349 tryIncrementLegacyFallbacksCounter(); 1350 } 1351 } 1352 } 1353 1354 // For cases where the fallbacks are not zero but target attempts counts reached, 1355 // only perform reads above and return here. 1356 if (dryRunImportOnly) return; 1357 1358 // Find the latest end time. 1359 for (final MigrationInfo migration : migrations) { 1360 if (PREFIX_DEV.equals(migration.recorder.getCookie())) continue; 1361 final long migrationEnd = migration.collection.getEndMillis(); 1362 if (migrationEnd > migrationEndTime) migrationEndTime = migrationEnd; 1363 } 1364 1365 // Reading all collections from legacy data has succeeded. At this point it is 1366 // safe to start overwriting the files on disk. The next step is to remove all 1367 // data in the new location that overlaps with imported data. This ensures that 1368 // any data in the new location that was created by a previous failed import is 1369 // ignored. After that, write the imported data into the recorder. The code 1370 // below can still possibly throw (disk error or OutOfMemory for example), but 1371 // does not depend on code from non-mainline code. 1372 Log.i(TAG, "Rewriting data with imported collections with cutoff " 1373 + Instant.ofEpochMilli(migrationEndTime)); 1374 for (final MigrationInfo migration : migrations) { 1375 migration.imported = true; 1376 migration.recorder.removeDataBefore(migrationEndTime); 1377 if (migration.collection.isEmpty() 1378 || PREFIX_DEV.equals(migration.recorder.getCookie())) continue; 1379 migration.recorder.importCollectionLocked(migration.collection); 1380 } 1381 1382 // Success normally or uses fallback method. 1383 } catch (Throwable e) { 1384 // The code above calls OEM code that may behave differently across devices. 1385 // It can throw any exception including RuntimeExceptions and 1386 // OutOfMemoryErrors. Try to recover anyway. 1387 Log.wtf(TAG, "Platform data import failed. Remaining tries " 1388 + (targetAttempts - attempts), e); 1389 1390 // Failed this time around : try again next time unless we're out of tries. 1391 try { 1392 mImportLegacyAttemptsCounter.set(attempts + 1); 1393 } catch (IOException ex) { 1394 Log.wtf(TAG, "Failed to update attempts counter.", ex); 1395 } 1396 1397 // Try to remove any data from the failed import. 1398 if (migrationEndTime > Long.MIN_VALUE) { 1399 try { 1400 for (final MigrationInfo migration : migrations) { 1401 if (PREFIX_DEV.equals(migration.recorder.getCookie())) continue; 1402 if (migration.imported) { 1403 migration.recorder.removeDataBefore(migrationEndTime); 1404 } 1405 } 1406 } catch (Throwable f) { 1407 // If rollback still throws, there isn't much left to do. Try nuking 1408 // all data, since that's the last stop. If nuking still throws, the 1409 // framework will reboot, and if there are remaining tries, the migration 1410 // process will retry, which is fine because it's idempotent. 1411 for (final MigrationInfo migration : migrations) { 1412 if (PREFIX_DEV.equals(migration.recorder.getCookie())) continue; 1413 migration.recorder.recoverAndDeleteData(); 1414 } 1415 } 1416 } 1417 1418 return; 1419 } 1420 1421 // Success ! No need to import again next time. 1422 try { 1423 mImportLegacyAttemptsCounter.set(targetAttempts); 1424 Log.i(TAG, "Successfully imported platform collections"); 1425 // The successes counter is only for debugging. Hence, the synchronization 1426 // between successes counter and attempts counter are not very critical. 1427 final int successCount = mImportLegacySuccessesCounter.get(); 1428 mImportLegacySuccessesCounter.set(successCount + 1); 1429 } catch (IOException e) { 1430 Log.wtf(TAG, "Succeed but failed to update counters.", e); 1431 } 1432 } 1433 1434 void tryIncrementLegacyFallbacksCounter() { 1435 try { 1436 final int fallbacks = mImportLegacyFallbacksCounter.get(); 1437 mImportLegacyFallbacksCounter.set(fallbacks + 1); 1438 } catch (IOException e) { 1439 Log.wtf(TAG, "Failed to update fallback counter.", e); 1440 } 1441 } 1442 1443 @VisibleForTesting 1444 boolean shouldRunComparison() { 1445 final ConnectivityResources resources = new ConnectivityResources(mContext); 1446 // 0 if id not found. 1447 Boolean overlayValue = null; 1448 try { 1449 switch (resources.get().getInteger(R.integer.config_netstats_validate_import)) { 1450 case 1: 1451 overlayValue = Boolean.TRUE; 1452 break; 1453 case 0: 1454 overlayValue = Boolean.FALSE; 1455 break; 1456 } 1457 } catch (Resources.NotFoundException e) { 1458 // Overlay value is not defined. 1459 } 1460 return overlayValue != null ? overlayValue : mDeps.isDebuggable(); 1461 } 1462 1463 /** 1464 * Compare imported data with the data returned by legacy recorders. 1465 * 1466 * @return true if the data matches or if {@code legacyRecorder} is null, false if the data 1467 * does not match or throw with exceptions. 1468 */ 1469 private boolean compareImportedToLegacyStats(@NonNull MigrationInfo migration, 1470 @Nullable NetworkStatsRecorder legacyRecorder, boolean allowKeyChange) { 1471 final NetworkStatsCollection legacyStats; 1472 // Skip the recorder that doesn't need to be compared. 1473 if (legacyRecorder == null) return true; 1474 try { 1475 legacyStats = legacyRecorder.getOrLoadCompleteLocked(); 1476 } catch (Throwable e) { 1477 Log.wtf(TAG, "Failed to read stats with legacy method for recorder " 1478 + legacyRecorder.getCookie(), e); 1479 // Cannot read data from legacy method, skip comparison. 1480 return false; 1481 } 1482 1483 // The result of comparison is only for logging. 1484 try { 1485 final String error = mDeps.compareStats(migration.collection, legacyStats, 1486 allowKeyChange); 1487 if (error != null) { 1488 Log.wtf(TAG, "Unexpected comparison result for recorder " 1489 + legacyRecorder.getCookie() + ": " + error); 1490 return false; 1491 } 1492 } catch (Throwable e) { 1493 Log.wtf(TAG, "Failed to compare migrated stats with legacy stats for recorder " 1494 + legacyRecorder.getCookie(), e); 1495 return false; 1496 } 1497 return true; 1498 } 1499 1500 @GuardedBy("mStatsLock") 1501 @NonNull 1502 private NetworkStatsCollection readPlatformCollectionForRecorder( 1503 @NonNull final NetworkStatsRecorder rec) throws IOException { 1504 final String prefix = rec.getCookie(); 1505 Log.i(TAG, "Importing platform collection for prefix " + prefix); 1506 final NetworkStatsCollection collection = Objects.requireNonNull( 1507 mDeps.readPlatformCollection(prefix, rec.getBucketDuration()), 1508 "Imported platform collection for prefix " + prefix + " must not be null"); 1509 1510 final long bootTimestamp = System.currentTimeMillis() - SystemClock.elapsedRealtime(); 1511 if (!collection.isEmpty() && bootTimestamp < collection.getStartMillis()) { 1512 throw new IllegalArgumentException("Platform collection for prefix " + prefix 1513 + " contains data that could not possibly come from the previous boot " 1514 + "(start timestamp = " + Instant.ofEpochMilli(collection.getStartMillis()) 1515 + ", last booted at " + Instant.ofEpochMilli(bootTimestamp)); 1516 } 1517 1518 Log.i(TAG, "Successfully read platform collection spanning from " 1519 // Instant uses ISO-8601 for toString() 1520 + Instant.ofEpochMilli(collection.getStartMillis()).toString() + " to " 1521 + Instant.ofEpochMilli(collection.getEndMillis()).toString()); 1522 return collection; 1523 } 1524 1525 /** 1526 * Register for a global alert that is delivered through {@link AlertObserver} 1527 * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has 1528 * been transferred. 1529 */ 1530 private void registerGlobalAlert() { 1531 try { 1532 mNetd.bandwidthSetGlobalAlert(mGlobalAlertBytes); 1533 } catch (IllegalStateException e) { 1534 Log.w(TAG, "problem registering for global alert: " + e); 1535 } catch (RemoteException | ServiceSpecificException e) { 1536 // ignored; service lives in system_server 1537 } 1538 invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); 1539 } 1540 1541 @Override 1542 public INetworkStatsSession openSession() { 1543 return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null); 1544 } 1545 1546 @Override 1547 public INetworkStatsSession openSessionForUsageStats( 1548 int flags, @NonNull String callingPackage) { 1549 Objects.requireNonNull(callingPackage); 1550 PermissionUtils.enforcePackageNameMatchesUid( 1551 mContext, Binder.getCallingUid(), callingPackage); 1552 return openSessionInternal(flags, callingPackage); 1553 } 1554 1555 private boolean isRateLimitedForPoll(@NonNull OpenSessionKey key) { 1556 final long lastCallTime; 1557 final long now = SystemClock.elapsedRealtime(); 1558 1559 synchronized (mOpenSessionCallsLock) { 1560 Integer callsPerCaller = mOpenSessionCallsPerCaller.get(key); 1561 if (callsPerCaller == null) { 1562 mOpenSessionCallsPerCaller.put((key), 1); 1563 } else { 1564 mOpenSessionCallsPerCaller.put(key, Integer.sum(callsPerCaller, 1)); 1565 } 1566 1567 if (key.uid == android.os.Process.SYSTEM_UID) { 1568 return false; 1569 } 1570 1571 // To avoid a non-system user to be rate-limited after system users open sessions, 1572 // so update mLastStatsSessionPoll after checked if the uid is SYSTEM_UID. 1573 lastCallTime = mLastStatsSessionPoll; 1574 mLastStatsSessionPoll = now; 1575 } 1576 1577 return now - lastCallTime < POLL_RATE_LIMIT_MS; 1578 } 1579 1580 private int restrictFlagsForCaller(int flags, @Nullable String callingPackage) { 1581 // All non-privileged callers are not allowed to turn off POLL_ON_OPEN. 1582 final boolean isPrivileged = PermissionUtils.hasAnyPermissionOf(mContext, 1583 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, 1584 android.Manifest.permission.NETWORK_STACK); 1585 if (!isPrivileged) { 1586 flags |= NetworkStatsManager.FLAG_POLL_ON_OPEN; 1587 } 1588 // Non-system uids are rate limited for POLL_ON_OPEN. 1589 final int callingUid = Binder.getCallingUid(); 1590 final OpenSessionKey key = new OpenSessionKey(callingUid, callingPackage); 1591 flags = isRateLimitedForPoll(key) 1592 ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) 1593 : flags; 1594 return flags; 1595 } 1596 1597 private INetworkStatsSession openSessionInternal( 1598 final int flags, @Nullable final String callingPackage) { 1599 final int restrictedFlags = restrictFlagsForCaller(flags, callingPackage); 1600 if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN 1601 | NetworkStatsManager.FLAG_POLL_FORCE)) != 0) { 1602 final long ident = Binder.clearCallingIdentity(); 1603 try { 1604 performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_OPEN_SESSION)); 1605 } finally { 1606 Binder.restoreCallingIdentity(ident); 1607 } 1608 } 1609 1610 // return an IBinder which holds strong references to any loaded stats 1611 // for its lifetime; when caller closes only weak references remain. 1612 1613 return new INetworkStatsSession.Stub() { 1614 private final int mCallingUid = Binder.getCallingUid(); 1615 @Nullable 1616 private final String mCallingPackage = callingPackage; 1617 private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel( 1618 callingPackage); 1619 1620 private NetworkStatsCollection mUidComplete; 1621 private NetworkStatsCollection mUidTagComplete; 1622 1623 private NetworkStatsCollection getUidComplete() { 1624 synchronized (mStatsLock) { 1625 if (mUidComplete == null) { 1626 mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); 1627 } 1628 return mUidComplete; 1629 } 1630 } 1631 1632 private NetworkStatsCollection getUidTagComplete() { 1633 synchronized (mStatsLock) { 1634 if (mUidTagComplete == null) { 1635 mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); 1636 } 1637 return mUidTagComplete; 1638 } 1639 } 1640 1641 @Override 1642 public int[] getRelevantUids() { 1643 return getUidComplete().getRelevantUids(mAccessLevel); 1644 } 1645 1646 @Override 1647 public NetworkStats getDeviceSummaryForNetwork( 1648 NetworkTemplate template, long start, long end) { 1649 enforceTemplatePermissions(template, callingPackage); 1650 return internalGetSummaryForNetwork(template, restrictedFlags, start, end, 1651 mAccessLevel, mCallingUid); 1652 } 1653 1654 @Override 1655 public NetworkStats getSummaryForNetwork( 1656 NetworkTemplate template, long start, long end) { 1657 enforceTemplatePermissions(template, callingPackage); 1658 return internalGetSummaryForNetwork(template, restrictedFlags, start, end, 1659 mAccessLevel, mCallingUid); 1660 } 1661 1662 // TODO: Remove this after all callers are removed. 1663 @Override 1664 public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { 1665 enforceTemplatePermissions(template, callingPackage); 1666 return internalGetHistoryForNetwork(template, restrictedFlags, fields, 1667 mAccessLevel, mCallingUid, Long.MIN_VALUE, Long.MAX_VALUE); 1668 } 1669 1670 @Override 1671 public NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template, 1672 int fields, long start, long end) { 1673 enforceTemplatePermissions(template, callingPackage); 1674 // TODO(b/200768422): Redact returned history if the template is location 1675 // sensitive but the caller is not privileged. 1676 return internalGetHistoryForNetwork(template, restrictedFlags, fields, 1677 mAccessLevel, mCallingUid, start, end); 1678 } 1679 1680 @Override 1681 public NetworkStats getSummaryForAllUid( 1682 NetworkTemplate template, long start, long end, boolean includeTags) { 1683 enforceTemplatePermissions(template, callingPackage); 1684 try { 1685 final NetworkStats stats = getUidComplete() 1686 .getSummary(template, start, end, mAccessLevel, mCallingUid); 1687 if (includeTags) { 1688 final NetworkStats tagStats = getUidTagComplete() 1689 .getSummary(template, start, end, mAccessLevel, mCallingUid); 1690 stats.combineAllValues(tagStats); 1691 } 1692 return stats; 1693 } catch (NullPointerException e) { 1694 throw e; 1695 } 1696 } 1697 1698 @Override 1699 public NetworkStats getTaggedSummaryForAllUid( 1700 NetworkTemplate template, long start, long end) { 1701 enforceTemplatePermissions(template, callingPackage); 1702 try { 1703 final NetworkStats tagStats = getUidTagComplete() 1704 .getSummary(template, start, end, mAccessLevel, mCallingUid); 1705 return tagStats; 1706 } catch (NullPointerException e) { 1707 throw e; 1708 } 1709 } 1710 1711 @Override 1712 public NetworkStatsHistory getHistoryForUid( 1713 NetworkTemplate template, int uid, int set, int tag, int fields) { 1714 enforceTemplatePermissions(template, callingPackage); 1715 // NOTE: We don't augment UID-level statistics 1716 if (tag == TAG_NONE) { 1717 return getUidComplete().getHistory(template, null, uid, set, tag, fields, 1718 Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); 1719 } else { 1720 return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, 1721 Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); 1722 } 1723 } 1724 1725 @Override 1726 public NetworkStatsHistory getHistoryIntervalForUid( 1727 NetworkTemplate template, int uid, int set, int tag, int fields, 1728 long start, long end) { 1729 enforceTemplatePermissions(template, callingPackage); 1730 // TODO(b/200768422): Redact returned history if the template is location 1731 // sensitive but the caller is not privileged. 1732 // NOTE: We don't augment UID-level statistics 1733 if (tag == TAG_NONE) { 1734 return getUidComplete().getHistory(template, null, uid, set, tag, fields, 1735 start, end, mAccessLevel, mCallingUid); 1736 } else if (uid == Binder.getCallingUid()) { 1737 return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, 1738 start, end, mAccessLevel, mCallingUid); 1739 } else { 1740 throw new SecurityException("Calling package " + mCallingPackage 1741 + " cannot access tag information from a different uid"); 1742 } 1743 } 1744 1745 @Override 1746 public void close() { 1747 mUidComplete = null; 1748 mUidTagComplete = null; 1749 } 1750 }; 1751 } 1752 1753 private void enforceTemplatePermissions(@NonNull NetworkTemplate template, 1754 @Nullable String callingPackage) { 1755 // For a template with wifi network keys, it is possible for a malicious 1756 // client to track the user locations via querying data usage. Thus, enforce 1757 // fine location permission check. 1758 // For a template with MATCH_TEST, since the wifi network key is just a placeholder 1759 // to identify a specific test network, it is not related to track user location. 1760 if (!template.getWifiNetworkKeys().isEmpty() && template.getMatchRule() != MATCH_TEST) { 1761 final boolean canAccessFineLocation = mLocationPermissionChecker 1762 .checkCallersLocationPermission(callingPackage, 1763 null /* featureId */, 1764 Binder.getCallingUid(), 1765 false /* coarseForTargetSdkLessThanQ */, 1766 null /* message */); 1767 if (!canAccessFineLocation) { 1768 throw new SecurityException("Access fine location is required when querying" 1769 + " with wifi network keys, make sure the app has the necessary" 1770 + "permissions and the location toggle is on."); 1771 } 1772 } 1773 } 1774 1775 private @NetworkStatsAccess.Level int checkAccessLevel(@Nullable String callingPackage) { 1776 return NetworkStatsAccess.checkAccessLevel( 1777 mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage); 1778 } 1779 1780 /** 1781 * Find the most relevant {@link SubscriptionPlan} for the given 1782 * {@link NetworkTemplate} and flags. This is typically used to augment 1783 * local measurement results to match a known anchor from the carrier. 1784 */ 1785 private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) { 1786 SubscriptionPlan plan = null; 1787 if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 1788 && mSettings.getAugmentEnabled()) { 1789 if (LOGD) Log.d(TAG, "Resolving plan for " + template); 1790 final long token = Binder.clearCallingIdentity(); 1791 try { 1792 plan = mContext.getSystemService(NetworkPolicyManager.class) 1793 .getSubscriptionPlan(template); 1794 } finally { 1795 Binder.restoreCallingIdentity(token); 1796 } 1797 if (LOGD) Log.d(TAG, "Resolved to plan " + plan); 1798 } 1799 return plan; 1800 } 1801 1802 /** 1803 * Return network summary, splicing between DEV and XT stats when 1804 * appropriate. 1805 */ 1806 private NetworkStats internalGetSummaryForNetwork(NetworkTemplate template, int flags, 1807 long start, long end, @NetworkStatsAccess.Level int accessLevel, int callingUid) { 1808 // We've been using pure XT stats long enough that we no longer need to 1809 // splice DEV and XT together. 1810 final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL, 1811 accessLevel, callingUid, Long.MIN_VALUE, Long.MAX_VALUE); 1812 1813 final long now = mClock.millis(); 1814 final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); 1815 1816 final NetworkStats stats = new NetworkStats(end - start, 1); 1817 stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, 1818 METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, 1819 entry.txBytes, entry.txPackets, entry.operations)); 1820 return stats; 1821 } 1822 1823 /** 1824 * Return network history, splicing between DEV and XT stats when 1825 * appropriate. 1826 */ 1827 private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, 1828 int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid, 1829 long start, long end) { 1830 // We've been using pure XT stats long enough that we no longer need to 1831 // splice DEV and XT together. 1832 final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags); 1833 synchronized (mStatsLock) { 1834 return mXtStatsCached.getHistory(template, augmentPlan, 1835 UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid); 1836 } 1837 } 1838 1839 private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { 1840 assertSystemReady(); 1841 1842 return internalGetSummaryForNetwork(template, 1843 NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end, 1844 NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes(); 1845 } 1846 1847 private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { 1848 assertSystemReady(); 1849 1850 final NetworkStatsCollection uidComplete; 1851 synchronized (mStatsLock) { 1852 uidComplete = mUidRecorder.getOrLoadCompleteLocked(); 1853 } 1854 return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE, 1855 android.os.Process.SYSTEM_UID); 1856 } 1857 1858 @Override 1859 public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { 1860 if (Binder.getCallingUid() != uid) { 1861 Log.w(TAG, "Snapshots only available for calling UID"); 1862 return new NetworkStats(SystemClock.elapsedRealtime(), 0); 1863 } 1864 1865 // TODO: switch to data layer stats once kernel exports 1866 // for now, read network layer stats and flatten across all ifaces. 1867 // This function is used to query NeworkStats for calle's uid. The only caller method 1868 // TrafficStats#getDataLayerSnapshotForUid alrady claim no special permission to query 1869 // its own NetworkStats. 1870 final long ident = Binder.clearCallingIdentity(); 1871 final NetworkStats networkLayer; 1872 try { 1873 networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL); 1874 } finally { 1875 Binder.restoreCallingIdentity(ident); 1876 } 1877 1878 // splice in operation counts 1879 networkLayer.spliceOperationsFrom(mUidOperations); 1880 1881 final NetworkStats dataLayer = new NetworkStats( 1882 networkLayer.getElapsedRealtime(), networkLayer.size()); 1883 1884 NetworkStats.Entry entry = null; 1885 for (int i = 0; i < networkLayer.size(); i++) { 1886 entry = networkLayer.getValues(i, entry); 1887 entry.iface = IFACE_ALL; 1888 dataLayer.combineValues(entry); 1889 } 1890 1891 return dataLayer; 1892 } 1893 1894 private String[] getAllIfacesSinceBoot(int transport) { 1895 synchronized (mStatsLock) { 1896 final Set<String> ifaceSet; 1897 if (transport == TRANSPORT_WIFI) { 1898 ifaceSet = mAllWifiIfacesSinceBoot; 1899 } else if (transport == TRANSPORT_CELLULAR) { 1900 // Since satellite networks appear under type mobile, this includes both cellular 1901 // and satellite active interfaces 1902 ifaceSet = mAllMobileIfacesSinceBoot; 1903 } else { 1904 throw new IllegalArgumentException("Invalid transport " + transport); 1905 } 1906 1907 return ifaceSet.toArray(new String[0]); 1908 } 1909 } 1910 1911 @Override 1912 public NetworkStats getUidStatsForTransport(int transport) { 1913 PermissionUtils.enforceNetworkStackPermission(mContext); 1914 try { 1915 final String[] ifaceArray = getAllIfacesSinceBoot(transport); 1916 final NetworkStats stats = getNetworkStatsUidDetail(ifaceArray); 1917 // Clear the interfaces of the stats before returning, so callers won't get this 1918 // information. This is because no caller needs this information for now, and it 1919 // makes it easier to change the implementation later by using the histories in the 1920 // recorder. 1921 return stats.withoutInterfaces(); 1922 } catch (RemoteException e) { 1923 Log.wtf(TAG, "Error compiling UID stats", e); 1924 return new NetworkStats(0L, 0); 1925 } 1926 } 1927 1928 @Override 1929 public String[] getMobileIfaces() { 1930 return mMobileIfaces.clone(); 1931 } 1932 1933 @Override 1934 public void incrementOperationCount(int uid, int tag, int operationCount) { 1935 if (Binder.getCallingUid() != uid) { 1936 mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); 1937 } 1938 1939 if (operationCount < 0) { 1940 throw new IllegalArgumentException("operation count can only be incremented"); 1941 } 1942 if (tag == TAG_NONE) { 1943 throw new IllegalArgumentException("operation count must have specific tag"); 1944 } 1945 1946 synchronized (mStatsLock) { 1947 final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT); 1948 mUidOperations.combineValues( 1949 mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount); 1950 mUidOperations.combineValues( 1951 mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount); 1952 } 1953 } 1954 1955 private void setKernelCounterSet(int uid, int set) { 1956 if (mUidCounterSetMap == null) { 1957 Log.wtf(TAG, "Fail to set UidCounterSet: Null bpf map"); 1958 return; 1959 } 1960 1961 if (set == SET_DEFAULT) { 1962 try { 1963 mUidCounterSetMap.deleteEntry(new S32(uid)); 1964 } catch (ErrnoException e) { 1965 Log.w(TAG, "UidCounterSetMap.deleteEntry(" + uid + ") failed with errno: " + e); 1966 } 1967 return; 1968 } 1969 1970 try { 1971 mUidCounterSetMap.updateEntry(new S32(uid), new U8((short) set)); 1972 } catch (ErrnoException e) { 1973 Log.w(TAG, "UidCounterSetMap.updateEntry(" + uid + ", " + set 1974 + ") failed with errno: " + e); 1975 } 1976 } 1977 1978 @VisibleForTesting 1979 public void noteUidForeground(int uid, boolean uidForeground) { 1980 PermissionUtils.enforceNetworkStackPermission(mContext); 1981 synchronized (mStatsLock) { 1982 final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; 1983 final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT); 1984 if (oldSet != set) { 1985 mActiveUidCounterSet.put(uid, set); 1986 setKernelCounterSet(uid, set); 1987 } 1988 } 1989 } 1990 1991 /** 1992 * Notify {@code NetworkStatsService} about network status changed. 1993 */ 1994 public void notifyNetworkStatus( 1995 @NonNull Network[] defaultNetworks, 1996 @NonNull NetworkStateSnapshot[] networkStates, 1997 @Nullable String activeIface, 1998 @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { 1999 PermissionUtils.enforceNetworkStackPermission(mContext); 2000 2001 final long token = Binder.clearCallingIdentity(); 2002 try { 2003 handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface, 2004 maybeCreatePollEvent(POLL_REASON_NETWORK_STATUS_CHANGED)); 2005 } finally { 2006 Binder.restoreCallingIdentity(token); 2007 } 2008 2009 // Update the VPN underlying interfaces only after the poll is made and tun data has been 2010 // migrated. Otherwise the migration would use the new interfaces instead of the ones that 2011 // were current when the polled data was transferred. 2012 mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos); 2013 } 2014 2015 @Override 2016 public void forceUpdate() { 2017 PermissionUtils.enforceNetworkStackPermission(mContext); 2018 2019 final long token = Binder.clearCallingIdentity(); 2020 try { 2021 // TODO: Log callstack for system server callers. 2022 performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_FORCE_UPDATE)); 2023 } finally { 2024 Binder.restoreCallingIdentity(token); 2025 } 2026 } 2027 2028 /** Advise persistence threshold; may be overridden internally. */ 2029 public void advisePersistThreshold(long thresholdBytes) { 2030 PermissionUtils.enforceNetworkStackPermission(mContext); 2031 // clamp threshold into safe range 2032 mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes, 2033 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); 2034 if (LOGV) { 2035 Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " 2036 + mPersistThreshold); 2037 } 2038 2039 final long oldGlobalAlertBytes = mGlobalAlertBytes; 2040 2041 // update and persist if beyond new thresholds 2042 final long currentTime = mClock.millis(); 2043 synchronized (mStatsLock) { 2044 if (!mSystemReady) return; 2045 2046 updatePersistThresholdsLocked(); 2047 2048 mXtRecorder.maybePersistLocked(currentTime); 2049 mUidRecorder.maybePersistLocked(currentTime); 2050 mUidTagRecorder.maybePersistLocked(currentTime); 2051 } 2052 2053 if (oldGlobalAlertBytes != mGlobalAlertBytes) { 2054 registerGlobalAlert(); 2055 } 2056 } 2057 2058 @Override 2059 public DataUsageRequest registerUsageCallback(@NonNull String callingPackage, 2060 @NonNull DataUsageRequest request, @NonNull IUsageCallback callback) { 2061 Objects.requireNonNull(callingPackage, "calling package is null"); 2062 Objects.requireNonNull(request, "DataUsageRequest is null"); 2063 Objects.requireNonNull(request.template, "NetworkTemplate is null"); 2064 Objects.requireNonNull(callback, "callback is null"); 2065 2066 final int callingPid = Binder.getCallingPid(); 2067 final int callingUid = Binder.getCallingUid(); 2068 PermissionUtils.enforcePackageNameMatchesUid(mContext, callingUid, callingPackage); 2069 @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage); 2070 DataUsageRequest normalizedRequest; 2071 final long token = Binder.clearCallingIdentity(); 2072 try { 2073 normalizedRequest = mStatsObservers.register(mContext, 2074 request, callback, callingPid, callingUid, callingPackage, accessLevel); 2075 } finally { 2076 Binder.restoreCallingIdentity(token); 2077 } 2078 2079 // Create baseline stats 2080 mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, 2081 POLL_REASON_REG_CALLBACK)); 2082 2083 return normalizedRequest; 2084 } 2085 2086 @Override 2087 public void unregisterUsageRequest(DataUsageRequest request) { 2088 Objects.requireNonNull(request, "DataUsageRequest is null"); 2089 2090 int callingUid = Binder.getCallingUid(); 2091 final long token = Binder.clearCallingIdentity(); 2092 try { 2093 mStatsObservers.unregister(request, callingUid); 2094 } finally { 2095 Binder.restoreCallingIdentity(token); 2096 } 2097 } 2098 2099 @Override 2100 public long getUidStats(int uid, int type) { 2101 final int callingUid = Binder.getCallingUid(); 2102 if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { 2103 return UNSUPPORTED; 2104 } 2105 if (!isEntryValueTypeValid(type)) return UNSUPPORTED; 2106 2107 if (mAlwaysUseTrafficStatsRateLimitCache 2108 || mDeps.isChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, callingUid)) { 2109 final NetworkStats.Entry entry = mTrafficStatsUidCache.getOrCompute(IFACE_ALL, uid, 2110 () -> mDeps.nativeGetUidStat(uid)); 2111 return getEntryValueForType(entry, type); 2112 } 2113 2114 return getEntryValueForType(mDeps.nativeGetUidStat(uid), type); 2115 } 2116 2117 @Nullable 2118 private NetworkStats.Entry getIfaceStatsInternal(@NonNull String iface) { 2119 final NetworkStats.Entry entry = mDeps.nativeGetIfaceStat(iface); 2120 if (entry == null) { 2121 return null; 2122 } 2123 // When tethering offload is in use, nativeIfaceStats does not contain usage from 2124 // offload, add it back here. Note that the included statistics might be stale 2125 // since polling newest stats from hardware might impact system health and not 2126 // suitable for TrafficStats API use cases. 2127 entry.add(getProviderIfaceStats(iface)); 2128 return entry; 2129 } 2130 2131 @Override 2132 public long getIfaceStats(@NonNull String iface, int type) { 2133 Objects.requireNonNull(iface); 2134 if (!isEntryValueTypeValid(type)) return UNSUPPORTED; 2135 2136 if (mAlwaysUseTrafficStatsRateLimitCache 2137 || mDeps.isChangeEnabled( 2138 ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, Binder.getCallingUid())) { 2139 final NetworkStats.Entry entry = mTrafficStatsIfaceCache.getOrCompute(iface, UID_ALL, 2140 () -> getIfaceStatsInternal(iface)); 2141 return getEntryValueForType(entry, type); 2142 } 2143 2144 return getEntryValueForType(getIfaceStatsInternal(iface), type); 2145 } 2146 2147 private long getEntryValueForType(@Nullable NetworkStats.Entry entry, int type) { 2148 if (entry == null) return UNSUPPORTED; 2149 if (!isEntryValueTypeValid(type)) return UNSUPPORTED; 2150 switch (type) { 2151 case TYPE_RX_BYTES: 2152 return entry.rxBytes; 2153 case TYPE_RX_PACKETS: 2154 return entry.rxPackets; 2155 case TYPE_TX_BYTES: 2156 return entry.txBytes; 2157 case TYPE_TX_PACKETS: 2158 return entry.txPackets; 2159 default: 2160 throw new IllegalStateException("Bug: Invalid type: " 2161 + type + " should not reach here."); 2162 } 2163 } 2164 2165 private boolean isEntryValueTypeValid(int type) { 2166 switch (type) { 2167 case TYPE_RX_BYTES: 2168 case TYPE_RX_PACKETS: 2169 case TYPE_TX_BYTES: 2170 case TYPE_TX_PACKETS: 2171 return true; 2172 default : 2173 return false; 2174 } 2175 } 2176 2177 @Nullable 2178 private NetworkStats.Entry getTotalStatsInternal() { 2179 final NetworkStats.Entry entry = mDeps.nativeGetTotalStat(); 2180 if (entry == null) { 2181 return null; 2182 } 2183 entry.add(getProviderIfaceStats(IFACE_ALL)); 2184 return entry; 2185 } 2186 2187 @Override 2188 public long getTotalStats(int type) { 2189 if (!isEntryValueTypeValid(type)) return UNSUPPORTED; 2190 if (mAlwaysUseTrafficStatsRateLimitCache 2191 || mDeps.isChangeEnabled( 2192 ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, Binder.getCallingUid())) { 2193 final NetworkStats.Entry entry = mTrafficStatsTotalCache.getOrCompute( 2194 IFACE_ALL, UID_ALL, () -> getTotalStatsInternal()); 2195 return getEntryValueForType(entry, type); 2196 } 2197 2198 return getEntryValueForType(getTotalStatsInternal(), type); 2199 } 2200 2201 @Override 2202 public void clearTrafficStatsRateLimitCaches() { 2203 PermissionUtils.enforceNetworkStackPermissionOr(mContext, NETWORK_SETTINGS); 2204 mTrafficStatsUidCache.clear(); 2205 mTrafficStatsIfaceCache.clear(); 2206 mTrafficStatsTotalCache.clear(); 2207 } 2208 2209 private NetworkStats.Entry getProviderIfaceStats(@Nullable String iface) { 2210 final NetworkStats providerSnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); 2211 final HashSet<String> limitIfaces; 2212 if (iface == IFACE_ALL) { 2213 limitIfaces = null; 2214 } else { 2215 limitIfaces = new HashSet<>(); 2216 limitIfaces.add(iface); 2217 } 2218 return providerSnapshot.getTotal(null, limitIfaces); 2219 } 2220 2221 /** 2222 * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to 2223 * reflect current {@link #mPersistThreshold} value. Always defers to 2224 * {@link Global} values when defined. 2225 */ 2226 @GuardedBy("mStatsLock") 2227 private void updatePersistThresholdsLocked() { 2228 mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); 2229 mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold)); 2230 mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold)); 2231 mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); 2232 } 2233 2234 /** 2235 * Listener that watches for {@link TetheringManager} to claim interface pairs. 2236 */ 2237 private final TetheringManager.TetheringEventCallback mTetherListener = 2238 new TetheringManager.TetheringEventCallback() { 2239 @Override 2240 public void onUpstreamChanged(@Nullable Network network) { 2241 performPoll(FLAG_PERSIST_NETWORK, 2242 maybeCreatePollEvent(POLL_REASON_UPSTREAM_CHANGED)); 2243 } 2244 }; 2245 2246 private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { 2247 @Override 2248 public void onReceive(Context context, Intent intent) { 2249 // on background handler thread, and verified UPDATE_DEVICE_STATS 2250 // permission above. 2251 performPoll(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_PERIODIC)); 2252 2253 // verify that we're watching global alert 2254 registerGlobalAlert(); 2255 } 2256 }; 2257 2258 private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() { 2259 @Override 2260 public void onReceive(Context context, Intent intent) { 2261 // on background handler thread, and UID_REMOVED is protected 2262 // broadcast. 2263 2264 final int uid = intent.getIntExtra(EXTRA_UID, -1); 2265 if (uid == -1) return; 2266 2267 synchronized (mStatsLock) { 2268 mWakeLock.acquire(); 2269 try { 2270 removeUidsLocked(uid); 2271 } finally { 2272 mWakeLock.release(); 2273 } 2274 } 2275 } 2276 }; 2277 2278 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 2279 @Override 2280 public void onReceive(Context context, Intent intent) { 2281 // On background handler thread, and USER_REMOVED is protected 2282 // broadcast. 2283 2284 final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); 2285 if (userHandle == null) return; 2286 2287 synchronized (mStatsLock) { 2288 mWakeLock.acquire(); 2289 try { 2290 removeUserLocked(userHandle); 2291 } finally { 2292 mWakeLock.release(); 2293 } 2294 } 2295 } 2296 }; 2297 2298 private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { 2299 @Override 2300 public void onReceive(Context context, Intent intent) { 2301 // SHUTDOWN is protected broadcast. 2302 synchronized (mStatsLock) { 2303 shutdownLocked(); 2304 } 2305 } 2306 }; 2307 2308 /** 2309 * Handle collapsed RAT type changed event. 2310 */ 2311 @VisibleForTesting 2312 public void handleOnCollapsedRatTypeChanged() { 2313 // Protect service from frequently updating. Remove pending messages if any. 2314 mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS); 2315 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS, 2316 POLL_REASON_RAT_CHANGED), mSettings.getPollDelay()); 2317 } 2318 2319 private void handleNotifyNetworkStatus( 2320 Network[] defaultNetworks, 2321 NetworkStateSnapshot[] snapshots, 2322 String activeIface, 2323 @Nullable PollEvent event) { 2324 synchronized (mStatsLock) { 2325 mWakeLock.acquire(); 2326 try { 2327 mActiveIface = activeIface; 2328 handleNotifyNetworkStatusLocked(defaultNetworks, snapshots, event); 2329 } finally { 2330 mWakeLock.release(); 2331 } 2332 } 2333 } 2334 2335 /** 2336 * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to 2337 * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, 2338 * they are combined under a single {@link NetworkIdentitySet}. 2339 */ 2340 @GuardedBy("mStatsLock") 2341 private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, 2342 @NonNull NetworkStateSnapshot[] snapshots, @Nullable PollEvent event) { 2343 if (!mSystemReady) return; 2344 if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()"); 2345 2346 // take one last stats snapshot before updating iface mapping. this 2347 // isn't perfect, since the kernel may already be counting traffic from 2348 // the updated network. 2349 2350 // poll, but only persist network stats to keep codepath fast. UID stats 2351 // will be persisted during next alarm poll event. 2352 performPollLocked(FLAG_PERSIST_NETWORK, event); 2353 2354 // Rebuild active interfaces based on connected networks 2355 mActiveIfaces.clear(); 2356 mActiveUidIfaces.clear(); 2357 // Update the list of default networks. 2358 mDefaultNetworks = defaultNetworks; 2359 2360 mLastNetworkStateSnapshots = snapshots; 2361 2362 final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); 2363 final ArraySet<String> mobileIfaces = new ArraySet<>(); 2364 for (NetworkStateSnapshot snapshot : snapshots) { 2365 final int displayTransport = 2366 getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); 2367 // Consider satellite transport to support satellite stats appear as type_mobile 2368 final boolean isMobile = NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport 2369 || NetworkCapabilities.TRANSPORT_SATELLITE == displayTransport; 2370 final boolean isWifi = (NetworkCapabilities.TRANSPORT_WIFI == displayTransport); 2371 final boolean isDefault = CollectionUtils.contains( 2372 mDefaultNetworks, snapshot.getNetwork()); 2373 final int ratType = combineSubtypeEnabled ? NetworkTemplate.NETWORK_TYPE_ALL 2374 : getRatTypeForStateSnapshot(snapshot); 2375 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, 2376 isDefault, ratType); 2377 2378 // If WifiInfo contains a null network key then this identity should not be added into 2379 // the network identity set. See b/266598304. 2380 final TransportInfo transportInfo = snapshot.getNetworkCapabilities() 2381 .getTransportInfo(); 2382 if (transportInfo instanceof WifiInfo) { 2383 final WifiInfo info = (WifiInfo) transportInfo; 2384 if (info.getNetworkKey() == null) continue; 2385 } 2386 // Traffic occurring on the base interface is always counted for 2387 // both total usage and UID details. 2388 final String baseIface = snapshot.getLinkProperties().getInterfaceName(); 2389 if (baseIface != null) { 2390 nativeRegisterIface(baseIface); 2391 findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); 2392 findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); 2393 2394 // Build a separate virtual interface for VT (Video Telephony) data usage. 2395 // Only do this when IMS is not metered, but VT is metered. 2396 // If IMS is metered, then the IMS network usage has already included VT usage. 2397 // VT is considered always metered in framework's layer. If VT is not metered 2398 // per carrier's policy, modem will report 0 usage for VT calls. 2399 if (snapshot.getNetworkCapabilities().hasCapability( 2400 NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { 2401 2402 // Copy the identify from IMS one but mark it as metered. 2403 NetworkIdentity vtIdent = new NetworkIdentity.Builder() 2404 .setType(ident.getType()) 2405 .setRatType(ident.getRatType()) 2406 .setSubscriberId(ident.getSubscriberId()) 2407 .setWifiNetworkKey(ident.getWifiNetworkKey()) 2408 .setRoaming(ident.isRoaming()).setMetered(true) 2409 .setDefaultNetwork(true) 2410 .setOemManaged(ident.getOemManaged()) 2411 .setSubId(ident.getSubId()).build(); 2412 final String ifaceVt = IFACE_VT + getSubIdForCellularOrSatellite(snapshot); 2413 findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); 2414 findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); 2415 } 2416 2417 if (isMobile) { 2418 mobileIfaces.add(baseIface); 2419 // If the interface name was present in the wifi set, the interface won't 2420 // be removed from it to prevent stats from getting rollback. 2421 mAllMobileIfacesSinceBoot.add(baseIface); 2422 } 2423 if (isWifi) { 2424 mAllWifiIfacesSinceBoot.add(baseIface); 2425 } 2426 } 2427 2428 // Traffic occurring on stacked interfaces is usually clatd. 2429 // 2430 // UID stats are always counted on the stacked interface and never on the base 2431 // interface, because the packets on the base interface do not actually match 2432 // application sockets (they're not IPv4) and thus the app uid is not known. 2433 // For receive this is obvious: packets must be translated from IPv6 to IPv4 2434 // before the application socket can be found. 2435 // For transmit: either they go through the clat daemon which by virtue of going 2436 // through userspace strips the original socket association during the IPv4 to 2437 // IPv6 translation process, or they are offloaded by eBPF, which doesn't: 2438 // However, on an ebpf device the accounting is done in cgroup ebpf hooks, 2439 // which don't trigger again post ebpf translation. 2440 // (as such stats accounted to the clat uid are ignored) 2441 // 2442 // Interface stats are more complicated. 2443 // 2444 // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus 2445 // *all* statistics are collected by iptables on the stacked v4-* interface. 2446 // 2447 // Additionally for ingress all packets bound for the clat IPv6 address are dropped 2448 // in ip6tables raw prerouting and thus even non-offloaded packets are only 2449 // accounted for on the stacked interface. 2450 // 2451 // For egress, packets subject to eBPF offload never appear on the base interface 2452 // and only appear on the stacked interface. Thus to ensure packets increment 2453 // interface stats, we must collate data from stacked interfaces. For xt_qtaguid 2454 // (or non eBPF offloaded) TX they would appear on both, however egress interface 2455 // accounting is explicitly bypassed for traffic from the clat uid. 2456 // 2457 // TODO: This code might be combined to above code. 2458 for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) { 2459 // baseIface has been handled, so ignore it. 2460 if (TextUtils.equals(baseIface, iface)) continue; 2461 if (iface != null) { 2462 nativeRegisterIface(iface); 2463 findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident); 2464 findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident); 2465 if (isMobile) { 2466 mobileIfaces.add(iface); 2467 mAllMobileIfacesSinceBoot.add(iface); 2468 } 2469 if (isWifi) { 2470 mAllWifiIfacesSinceBoot.add(iface); 2471 } 2472 2473 mStatsFactory.noteStackedIface(iface, baseIface); 2474 } 2475 } 2476 } 2477 2478 mMobileIfaces = mobileIfaces.toArray(new String[0]); 2479 } 2480 2481 private static int getSubIdForCellularOrSatellite(@NonNull NetworkStateSnapshot state) { 2482 if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) 2483 // Both cellular and satellite are 2 different network transport at Mobile using 2484 // same telephony network specifier. So adding satellite transport to consider 2485 // for, when satellite network is active at mobile. 2486 && !state.getNetworkCapabilities().hasTransport( 2487 NetworkCapabilities.TRANSPORT_SATELLITE)) { 2488 throw new IllegalArgumentException( 2489 "Mobile state need capability TRANSPORT_CELLULAR or TRANSPORT_SATELLITE"); 2490 } 2491 2492 final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier(); 2493 if (spec instanceof TelephonyNetworkSpecifier) { 2494 return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); 2495 } else { 2496 Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); 2497 return INVALID_SUBSCRIPTION_ID; 2498 } 2499 } 2500 2501 /** 2502 * For networks with {@code TRANSPORT_CELLULAR} Or {@code TRANSPORT_SATELLITE}, get ratType 2503 * that was obtained through {@link PhoneStateListener}. Otherwise, return 0 given that other 2504 * networks with different transport types do not actually fill this value. 2505 */ 2506 private int getRatTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { 2507 if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) 2508 && !state.getNetworkCapabilities() 2509 .hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)) { 2510 return 0; 2511 } 2512 2513 return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId()); 2514 } 2515 2516 private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet( 2517 ArrayMap<K, NetworkIdentitySet> map, K key) { 2518 NetworkIdentitySet ident = map.get(key); 2519 if (ident == null) { 2520 ident = new NetworkIdentitySet(); 2521 map.put(key, ident); 2522 } 2523 return ident; 2524 } 2525 2526 @GuardedBy("mStatsLock") 2527 private void recordSnapshotLocked(long currentTime) throws RemoteException { 2528 // snapshot and record current counters; read UID stats first to 2529 // avoid over counting xt stats. 2530 Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid"); 2531 final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); 2532 Trace.traceEnd(TRACE_TAG_NETWORK); 2533 Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); 2534 final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); 2535 Trace.traceEnd(TRACE_TAG_NETWORK); 2536 2537 // Snapshot for xt stats from all custom stats providers. Counts per-interface data 2538 // from stats providers that isn't already counted by XT stats. 2539 Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); 2540 final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); 2541 Trace.traceEnd(TRACE_TAG_NETWORK); 2542 xtSnapshot.combineAllValues(providersnapshot); 2543 2544 // For xt, we pass a null VPN array because usage is aggregated by UID, so VPN traffic 2545 // can't be reattributed to responsible apps. 2546 Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); 2547 mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); 2548 Trace.traceEnd(TRACE_TAG_NETWORK); 2549 2550 // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. 2551 Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); 2552 mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); 2553 Trace.traceEnd(TRACE_TAG_NETWORK); 2554 Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); 2555 mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); 2556 Trace.traceEnd(TRACE_TAG_NETWORK); 2557 2558 // We need to make copies of member fields that are sent to the observer to avoid 2559 // a race condition between the service handler thread and the observer's 2560 mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), 2561 new ArrayMap<>(mActiveUidIfaces), currentTime); 2562 } 2563 2564 /** 2565 * Bootstrap initial stats snapshot, usually during {@link #systemReady()} 2566 * so we have baseline values without double-counting. 2567 */ 2568 @GuardedBy("mStatsLock") 2569 private void bootstrapStatsLocked() { 2570 final long currentTime = mClock.millis(); 2571 2572 try { 2573 recordSnapshotLocked(currentTime); 2574 } catch (IllegalStateException e) { 2575 Log.w(TAG, "problem reading network stats: " + e); 2576 } catch (RemoteException e) { 2577 // ignored; service lives in system_server 2578 } 2579 } 2580 2581 private void performPoll(int flags, @Nullable PollEvent event) { 2582 synchronized (mStatsLock) { 2583 mWakeLock.acquire(); 2584 2585 try { 2586 performPollLocked(flags, event); 2587 } finally { 2588 mWakeLock.release(); 2589 } 2590 } 2591 } 2592 2593 /** 2594 * Periodic poll operation, reading current statistics and recording into 2595 * {@link NetworkStatsHistory}. 2596 */ 2597 @GuardedBy("mStatsLock") 2598 private void performPollLocked(int flags, @Nullable PollEvent event) { 2599 if (!mSystemReady) return; 2600 if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); 2601 Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked"); 2602 2603 if (mSupportEventLogger) { 2604 mEventLogger.logPollEvent(flags, event); 2605 } 2606 2607 final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; 2608 final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; 2609 final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; 2610 2611 performPollFromProvidersLocked(); 2612 2613 // TODO: consider marking "untrusted" times in historical stats 2614 final long currentTime = mClock.millis(); 2615 2616 try { 2617 recordSnapshotLocked(currentTime); 2618 } catch (IllegalStateException e) { 2619 Log.wtf(TAG, "problem reading network stats", e); 2620 return; 2621 } catch (RemoteException e) { 2622 // ignored; service lives in system_server 2623 return; 2624 } 2625 2626 // persist any pending data depending on requested flags 2627 Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]"); 2628 if (persistForce) { 2629 mXtRecorder.forcePersistLocked(currentTime); 2630 mUidRecorder.forcePersistLocked(currentTime); 2631 mUidTagRecorder.forcePersistLocked(currentTime); 2632 } else { 2633 if (persistNetwork) { 2634 mXtRecorder.maybePersistLocked(currentTime); 2635 } 2636 if (persistUid) { 2637 mUidRecorder.maybePersistLocked(currentTime); 2638 mUidTagRecorder.maybePersistLocked(currentTime); 2639 } 2640 } 2641 Trace.traceEnd(TRACE_TAG_NETWORK); 2642 2643 if (mSettings.getSampleEnabled()) { 2644 // sample stats after each full poll 2645 performSampleLocked(); 2646 } 2647 2648 // finally, dispatch updated event to any listeners 2649 mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED)); 2650 2651 Trace.traceEnd(TRACE_TAG_NETWORK); 2652 } 2653 2654 @GuardedBy("mStatsLock") 2655 private void performPollFromProvidersLocked() { 2656 // Request asynchronous stats update from all providers for next poll. And wait a bit of 2657 // time to allow providers report-in given that normally binder call should be fast. Note 2658 // that size of list might be changed because addition/removing at the same time. For 2659 // addition, the stats of the missed provider can only be collected in next poll; 2660 // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS 2661 // once that happened. 2662 // TODO: request with a valid token. 2663 Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); 2664 final int registeredCallbackCount = mStatsProviderCbList.size(); 2665 mStatsProviderSem.drainPermits(); 2666 invokeForAllStatsProviderCallbacks( 2667 (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); 2668 try { 2669 mStatsProviderSem.tryAcquire(registeredCallbackCount, 2670 MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); 2671 } catch (InterruptedException e) { 2672 // Strictly speaking it's possible a provider happened to deliver between the timeout 2673 // and the log, and that doesn't matter too much as this is just a debug log. 2674 Log.d(TAG, "requestStatsUpdate - providers responded " 2675 + mStatsProviderSem.availablePermits() 2676 + "/" + registeredCallbackCount + " : " + e); 2677 } 2678 Trace.traceEnd(TRACE_TAG_NETWORK); 2679 } 2680 2681 /** 2682 * Sample recent statistics summary into {@link EventLog}. 2683 */ 2684 @GuardedBy("mStatsLock") 2685 private void performSampleLocked() { 2686 // TODO: migrate trustedtime fixes to separate binary log events 2687 final long currentTime = mClock.millis(); 2688 2689 NetworkTemplate template; 2690 NetworkStats.Entry xtTotal; 2691 NetworkStats.Entry uidTotal; 2692 2693 // collect mobile sample 2694 template = new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build(); 2695 xtTotal = mXtRecorder.getTotalSinceBootLocked(template); 2696 uidTotal = mUidRecorder.getTotalSinceBootLocked(template); 2697 2698 if (SdkLevel.isAtLeastU()) { 2699 EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, 2700 xtTotal.rxBytes, xtTotal.txBytes, xtTotal.rxPackets, xtTotal.txPackets, 2701 uidTotal.rxBytes, uidTotal.txBytes, uidTotal.rxPackets, uidTotal.txPackets, 2702 currentTime); 2703 } else { 2704 // To keep the format of event log, here replaces the value of DevRecorder with the 2705 // value of XtRecorder because they have the same content in old design. 2706 EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, 2707 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, 2708 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, 2709 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, 2710 currentTime); 2711 } 2712 2713 // collect wifi sample 2714 template = new NetworkTemplate.Builder(MATCH_WIFI).build(); 2715 xtTotal = mXtRecorder.getTotalSinceBootLocked(template); 2716 uidTotal = mUidRecorder.getTotalSinceBootLocked(template); 2717 2718 if (SdkLevel.isAtLeastU()) { 2719 EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, 2720 xtTotal.rxBytes, xtTotal.txBytes, xtTotal.rxPackets, xtTotal.txPackets, 2721 uidTotal.rxBytes, uidTotal.txBytes, uidTotal.rxPackets, uidTotal.txPackets, 2722 currentTime); 2723 } else { 2724 // To keep the format of event log, here replaces the value of DevRecorder with the 2725 // value of XtRecorder because they have the same content in old design. 2726 EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, 2727 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, 2728 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, 2729 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, 2730 currentTime); 2731 2732 } 2733 } 2734 2735 // deleteKernelTagData can ignore ENOENT; otherwise we should log an error 2736 private void logErrorIfNotErrNoent(final ErrnoException e, final String msg) { 2737 if (e.errno != ENOENT) Log.e(TAG, msg, e); 2738 } 2739 2740 private <K extends StatsMapKey, V extends StatsMapValue> void deleteStatsMapTagData( 2741 IBpfMap<K, V> statsMap, int uid) { 2742 try { 2743 statsMap.forEach((key, value) -> { 2744 if (key.uid == uid) { 2745 try { 2746 statsMap.deleteEntry(key); 2747 } catch (ErrnoException e) { 2748 logErrorIfNotErrNoent(e, "Failed to delete data(uid = " + key.uid + ")"); 2749 } 2750 } 2751 }); 2752 } catch (ErrnoException e) { 2753 Log.e(TAG, "FAILED to delete tag data from stats map", e); 2754 } 2755 } 2756 2757 /** 2758 * Deletes uid tag data from CookieTagMap, StatsMapA, StatsMapB, and UidStatsMap 2759 * @param uid 2760 */ 2761 private void deleteKernelTagData(int uid) { 2762 try { 2763 mCookieTagMap.forEach((key, value) -> { 2764 // If SkDestroyListener deletes the socket tag while this code is running, 2765 // forEach will either restart iteration from the beginning or return null, 2766 // depending on when the deletion happens. 2767 // If it returns null, continue iteration to delete the data and in fact it would 2768 // just iterate from first key because BpfMap#getNextKey would return first key 2769 // if the current key is not exist. 2770 if (value != null && value.uid == uid) { 2771 try { 2772 mCookieTagMap.deleteEntry(key); 2773 } catch (ErrnoException e) { 2774 logErrorIfNotErrNoent(e, "Failed to delete data(cookie = " + key + ")"); 2775 } 2776 } 2777 }); 2778 } catch (ErrnoException e) { 2779 Log.e(TAG, "Failed to delete tag data from cookie tag map", e); 2780 } 2781 2782 deleteStatsMapTagData(mStatsMapA, uid); 2783 deleteStatsMapTagData(mStatsMapB, uid); 2784 2785 try { 2786 mUidCounterSetMap.deleteEntry(new S32(uid)); 2787 } catch (ErrnoException e) { 2788 logErrorIfNotErrNoent(e, "Failed to delete tag data from uid counter set map"); 2789 } 2790 2791 try { 2792 mAppUidStatsMap.deleteEntry(new UidStatsMapKey(uid)); 2793 } catch (ErrnoException e) { 2794 logErrorIfNotErrNoent(e, "Failed to delete tag data from app uid stats map"); 2795 } 2796 } 2797 2798 /** 2799 * Clean up {@link #mUidRecorder} after UID is removed. 2800 */ 2801 @GuardedBy("mStatsLock") 2802 private void removeUidsLocked(int... uids) { 2803 if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); 2804 2805 // Perform one last poll before removing 2806 performPollLocked(FLAG_PERSIST_ALL, maybeCreatePollEvent(POLL_REASON_REMOVE_UIDS)); 2807 2808 mUidRecorder.removeUidsLocked(uids); 2809 mUidTagRecorder.removeUidsLocked(uids); 2810 2811 mStatsFactory.removeUidsLocked(uids); 2812 // Clear kernel stats associated with UID 2813 for (int uid : uids) { 2814 deleteKernelTagData(uid); 2815 } 2816 // TODO: Remove the UID's entries from mOpenSessionCallsPerCaller. 2817 } 2818 2819 /** 2820 * Clean up {@link #mUidRecorder} after user is removed. 2821 */ 2822 @GuardedBy("mStatsLock") 2823 private void removeUserLocked(@NonNull UserHandle userHandle) { 2824 if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle); 2825 2826 // Build list of UIDs that we should clean up 2827 final ArrayList<Integer> uids = new ArrayList<>(); 2828 final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications( 2829 PackageManager.MATCH_ANY_USER 2830 | PackageManager.MATCH_DISABLED_COMPONENTS); 2831 for (ApplicationInfo app : apps) { 2832 final int uid = userHandle.getUid(app.uid); 2833 uids.add(uid); 2834 } 2835 2836 removeUidsLocked(CollectionUtils.toIntArray(uids)); 2837 } 2838 2839 /** 2840 * Set the warning and limit to all registered custom network stats providers. 2841 * Note that invocation of any interface will be sent to all providers. 2842 */ 2843 public void setStatsProviderWarningAndLimitAsync( 2844 @NonNull String iface, long warning, long limit) { 2845 PermissionUtils.enforceNetworkStackPermission(mContext); 2846 if (LOGV) { 2847 Log.v(TAG, "setStatsProviderWarningAndLimitAsync(" 2848 + iface + "," + warning + "," + limit + ")"); 2849 } 2850 invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, 2851 warning, limit)); 2852 } 2853 2854 @Override 2855 protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { 2856 if (!PermissionUtils.hasDumpPermission(mContext, TAG, rawWriter)) return; 2857 2858 long duration = DateUtils.DAY_IN_MILLIS; 2859 final HashSet<String> argSet = new HashSet<String>(); 2860 for (String arg : args) { 2861 argSet.add(arg); 2862 2863 if (arg.startsWith("--duration=")) { 2864 try { 2865 duration = Long.parseLong(arg.substring(11)); 2866 } catch (NumberFormatException ignored) { 2867 } 2868 } 2869 } 2870 2871 // usage: dumpsys netstats --full --uid --tag --poll --checkin 2872 final boolean poll = argSet.contains("--poll") || argSet.contains("poll"); 2873 final boolean checkin = argSet.contains("--checkin"); 2874 final boolean bpfRawMap = argSet.contains("--bpfRawMap"); 2875 final boolean fullHistory = argSet.contains("--full") || argSet.contains("full"); 2876 final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail"); 2877 final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail"); 2878 2879 final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); 2880 2881 synchronized (mStatsLock) { 2882 if (args.length > 0 && "--proto".equals(args[0])) { 2883 // In this case ignore all other arguments. 2884 dumpProtoLocked(fd); 2885 return; 2886 } 2887 2888 if (poll) { 2889 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE, 2890 maybeCreatePollEvent(POLL_REASON_DUMPSYS)); 2891 pw.println("Forced poll"); 2892 return; 2893 } 2894 2895 if (checkin) { 2896 final long end = System.currentTimeMillis(); 2897 final long start = end - duration; 2898 2899 pw.print("v1,"); 2900 pw.print(start / SECOND_IN_MILLIS); pw.print(','); 2901 pw.print(end / SECOND_IN_MILLIS); pw.println(); 2902 2903 pw.println("xt"); 2904 mXtRecorder.dumpCheckin(rawWriter, start, end); 2905 2906 if (includeUid) { 2907 pw.println("uid"); 2908 mUidRecorder.dumpCheckin(rawWriter, start, end); 2909 } 2910 if (includeTag) { 2911 pw.println("tag"); 2912 mUidTagRecorder.dumpCheckin(rawWriter, start, end); 2913 } 2914 return; 2915 } 2916 2917 if (bpfRawMap) { 2918 dumpRawMapLocked(pw, args); 2919 return; 2920 } 2921 2922 pw.println("Directory:"); 2923 pw.increaseIndent(); 2924 pw.println(mStatsDir); 2925 pw.decreaseIndent(); 2926 2927 pw.println("Configs:"); 2928 pw.increaseIndent(); 2929 pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); 2930 pw.println(); 2931 pw.print(NETSTATS_STORE_FILES_IN_APEXDATA, mDeps.getStoreFilesInApexData()); 2932 pw.println(); 2933 pw.print(NETSTATS_IMPORT_LEGACY_TARGET_ATTEMPTS, mDeps.getImportLegacyTargetAttempts()); 2934 pw.println(); 2935 if (mDeps.getStoreFilesInApexData()) { 2936 try { 2937 pw.print("platform legacy stats import attempts count", 2938 mImportLegacyAttemptsCounter.get()); 2939 pw.println(); 2940 pw.print("platform legacy stats import successes count", 2941 mImportLegacySuccessesCounter.get()); 2942 pw.println(); 2943 pw.print("platform legacy stats import fallbacks count", 2944 mImportLegacyFallbacksCounter.get()); 2945 pw.println(); 2946 } catch (IOException e) { 2947 pw.println("(failed to dump platform legacy stats import counters)"); 2948 } 2949 } 2950 pw.println(CONFIG_ENABLE_NETWORK_STATS_EVENT_LOGGER + ": " + mSupportEventLogger); 2951 pw.print(NETSTATS_FASTDATAINPUT_TARGET_ATTEMPTS, 2952 mDeps.getUseFastDataInputTargetAttempts()); 2953 pw.println(); 2954 try { 2955 pw.print("FastDataInput successes", mFastDataInputSuccessesCounter.get()); 2956 pw.println(); 2957 pw.print("FastDataInput fallbacks", mFastDataInputFallbacksCounter.get()); 2958 pw.println(); 2959 } catch (IOException e) { 2960 pw.println("(failed to dump FastDataInput counters)"); 2961 } 2962 pw.print("trafficstats.cache.alwaysuse", mAlwaysUseTrafficStatsRateLimitCache); 2963 pw.println(); 2964 pw.print(TRAFFIC_STATS_CACHE_EXPIRY_DURATION_NAME, 2965 mTrafficStatsRateLimitCacheExpiryDuration); 2966 pw.println(); 2967 pw.print(TRAFFIC_STATS_CACHE_MAX_ENTRIES_NAME, mTrafficStatsRateLimitCacheMaxEntries); 2968 pw.println(); 2969 2970 pw.decreaseIndent(); 2971 2972 pw.println("Active interfaces:"); 2973 pw.increaseIndent(); 2974 for (int i = 0; i < mActiveIfaces.size(); i++) { 2975 pw.print("iface", mActiveIfaces.keyAt(i)); 2976 pw.print("ident", mActiveIfaces.valueAt(i)); 2977 pw.println(); 2978 } 2979 pw.decreaseIndent(); 2980 2981 pw.println("Active UID interfaces:"); 2982 pw.increaseIndent(); 2983 for (int i = 0; i < mActiveUidIfaces.size(); i++) { 2984 pw.print("iface", mActiveUidIfaces.keyAt(i)); 2985 pw.print("ident", mActiveUidIfaces.valueAt(i)); 2986 pw.println(); 2987 } 2988 pw.decreaseIndent(); 2989 2990 pw.println("All wifi interfaces:"); 2991 pw.increaseIndent(); 2992 for (String iface : mAllWifiIfacesSinceBoot) { 2993 pw.print(iface + " "); 2994 } 2995 pw.println(); 2996 pw.decreaseIndent(); 2997 2998 pw.println("All mobile interfaces:"); 2999 pw.increaseIndent(); 3000 for (String iface : mAllMobileIfacesSinceBoot) { 3001 pw.print(iface + " "); 3002 } 3003 pw.println(); 3004 pw.decreaseIndent(); 3005 3006 // Get the top openSession callers 3007 final HashMap calls; 3008 synchronized (mOpenSessionCallsLock) { 3009 calls = new HashMap<>(mOpenSessionCallsPerCaller); 3010 } 3011 final List<Map.Entry<OpenSessionKey, Integer>> list = new ArrayList<>(calls.entrySet()); 3012 Collections.sort(list, 3013 (left, right) -> Integer.compare(left.getValue(), right.getValue())); 3014 final int num = list.size(); 3015 final int end = Math.max(0, num - DUMP_STATS_SESSION_COUNT); 3016 pw.println("Top openSession callers:"); 3017 pw.increaseIndent(); 3018 for (int j = num - 1; j >= end; j--) { 3019 final Map.Entry<OpenSessionKey, Integer> entry = list.get(j); 3020 pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); 3021 3022 } 3023 pw.decreaseIndent(); 3024 pw.println(); 3025 3026 if (mSupportEventLogger) { 3027 mEventLogger.dump(pw); 3028 } 3029 3030 pw.println("Stats Providers:"); 3031 pw.increaseIndent(); 3032 invokeForAllStatsProviderCallbacks((cb) -> { 3033 pw.println(cb.mTag + " Xt:"); 3034 pw.increaseIndent(); 3035 pw.print(cb.getCachedStats(STATS_PER_IFACE).toString()); 3036 pw.decreaseIndent(); 3037 if (includeUid) { 3038 pw.println(cb.mTag + " Uid:"); 3039 pw.increaseIndent(); 3040 pw.print(cb.getCachedStats(STATS_PER_UID).toString()); 3041 pw.decreaseIndent(); 3042 } 3043 }); 3044 pw.decreaseIndent(); 3045 pw.println(); 3046 3047 pw.println("Stats Observers:"); 3048 pw.increaseIndent(); 3049 mStatsObservers.dump(pw); 3050 pw.decreaseIndent(); 3051 pw.println(); 3052 3053 pw.println("Dev stats:"); 3054 pw.increaseIndent(); 3055 pw.println("Pending bytes: "); 3056 if (fullHistory) { 3057 pw.println("Complete history:"); 3058 } else { 3059 pw.println("History since boot:"); 3060 } 3061 pw.decreaseIndent(); 3062 3063 pw.println("Xt stats:"); 3064 pw.increaseIndent(); 3065 mXtRecorder.dumpLocked(pw, fullHistory); 3066 pw.decreaseIndent(); 3067 3068 if (includeUid) { 3069 pw.println("UID stats:"); 3070 pw.increaseIndent(); 3071 mUidRecorder.dumpLocked(pw, fullHistory); 3072 pw.decreaseIndent(); 3073 } 3074 3075 if (includeTag) { 3076 pw.println("UID tag stats:"); 3077 pw.increaseIndent(); 3078 mUidTagRecorder.dumpLocked(pw, fullHistory); 3079 pw.decreaseIndent(); 3080 } 3081 3082 pw.println(); 3083 pw.println("InterfaceMapHelper:"); 3084 pw.increaseIndent(); 3085 mInterfaceMapHelper.dump(pw); 3086 pw.decreaseIndent(); 3087 3088 pw.println(); 3089 pw.println("BPF map status:"); 3090 pw.increaseIndent(); 3091 dumpMapStatus(pw); 3092 pw.decreaseIndent(); 3093 pw.println(); 3094 3095 // Following BPF map content dump contains uid and tag regardless of the flags because 3096 // following dumps are moved from TrafficController and bug report already contains this 3097 // information. 3098 pw.println("BPF map content:"); 3099 pw.increaseIndent(); 3100 dumpCookieTagMapLocked(pw); 3101 dumpUidCounterSetMapLocked(pw); 3102 dumpAppUidStatsMapLocked(pw); 3103 dumpStatsMapLocked(mStatsMapA, pw, "mStatsMapA"); 3104 dumpStatsMapLocked(mStatsMapB, pw, "mStatsMapB"); 3105 dumpIfaceStatsMapLocked(pw); 3106 pw.decreaseIndent(); 3107 3108 pw.println(); 3109 pw.println("SkDestroyListener logs:"); 3110 pw.increaseIndent(); 3111 mSkDestroyListener.dump(pw); 3112 pw.decreaseIndent(); 3113 } 3114 } 3115 3116 @GuardedBy("mStatsLock") 3117 private void dumpProtoLocked(FileDescriptor fd) { 3118 final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); 3119 3120 // TODO Right now it writes all history. Should it limit to the "since-boot" log? 3121 3122 dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, 3123 mActiveIfaces); 3124 dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, 3125 mActiveUidIfaces); 3126 mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); 3127 mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); 3128 mUidTagRecorder.dumpDebugLocked(proto, 3129 NetworkStatsServiceDumpProto.UID_TAG_STATS); 3130 3131 proto.flush(); 3132 } 3133 3134 private <K extends Struct, V extends Struct> void dumpRawMap(IBpfMap<K, V> map, 3135 IndentingPrintWriter pw) throws ErrnoException { 3136 if (map == null) { 3137 pw.println("Map is null"); 3138 return; 3139 } 3140 if (map.isEmpty()) { 3141 pw.println(""); 3142 return; 3143 } 3144 // If there is a concurrent entry deletion, value could be null. http://b/220084230. 3145 // Also, map.forEach could restart iteration from the beginning and dump could contain 3146 // duplicated entries. User of this dump needs to take care of the duplicated entries. 3147 map.forEach((k, v) -> { 3148 if (v != null) { 3149 pw.println(BpfDump.toBase64EncodedString(k, v)); 3150 } 3151 }); 3152 } 3153 3154 @GuardedBy("mStatsLock") 3155 private void dumpRawMapLocked(final IndentingPrintWriter pw, final String[] args) { 3156 if (CollectionUtils.contains(args, "--cookieTagMap")) { 3157 try { 3158 dumpRawMap(mCookieTagMap, pw); 3159 } catch (ErrnoException e) { 3160 pw.println("Error dumping cookieTag map: " + e); 3161 } 3162 return; 3163 } 3164 } 3165 3166 private static void dumpInterfaces(ProtoOutputStream proto, long tag, 3167 ArrayMap<String, NetworkIdentitySet> ifaces) { 3168 for (int i = 0; i < ifaces.size(); i++) { 3169 final long start = proto.start(tag); 3170 3171 proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); 3172 ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); 3173 3174 proto.end(start); 3175 } 3176 } 3177 3178 private void dumpMapStatus(final IndentingPrintWriter pw) { 3179 BpfDump.dumpMapStatus(mCookieTagMap, pw, "mCookieTagMap", COOKIE_TAG_MAP_PATH); 3180 BpfDump.dumpMapStatus(mUidCounterSetMap, pw, "mUidCounterSetMap", UID_COUNTERSET_MAP_PATH); 3181 BpfDump.dumpMapStatus(mAppUidStatsMap, pw, "mAppUidStatsMap", APP_UID_STATS_MAP_PATH); 3182 BpfDump.dumpMapStatus(mStatsMapA, pw, "mStatsMapA", STATS_MAP_A_PATH); 3183 BpfDump.dumpMapStatus(mStatsMapB, pw, "mStatsMapB", STATS_MAP_B_PATH); 3184 // mIfaceStatsMap is always not null but dump status to be consistent with other maps. 3185 BpfDump.dumpMapStatus(mIfaceStatsMap, pw, "mIfaceStatsMap", IFACE_STATS_MAP_PATH); 3186 } 3187 3188 @GuardedBy("mStatsLock") 3189 private void dumpCookieTagMapLocked(final IndentingPrintWriter pw) { 3190 if (mCookieTagMap == null) { 3191 return; 3192 } 3193 BpfDump.dumpMap(mCookieTagMap, pw, "mCookieTagMap", 3194 (key, value) -> "cookie=" + key.socketCookie 3195 + " tag=0x" + Long.toHexString(value.tag) 3196 + " uid=" + value.uid); 3197 } 3198 3199 @GuardedBy("mStatsLock") 3200 private void dumpUidCounterSetMapLocked(final IndentingPrintWriter pw) { 3201 if (mUidCounterSetMap == null) { 3202 return; 3203 } 3204 BpfDump.dumpMap(mUidCounterSetMap, pw, "mUidCounterSetMap", 3205 (uid, set) -> "uid=" + uid.val + " set=" + set.val); 3206 } 3207 3208 @GuardedBy("mStatsLock") 3209 private void dumpAppUidStatsMapLocked(final IndentingPrintWriter pw) { 3210 if (mAppUidStatsMap == null) { 3211 return; 3212 } 3213 BpfDump.dumpMap(mAppUidStatsMap, pw, "mAppUidStatsMap", 3214 "uid rxBytes rxPackets txBytes txPackets", 3215 (key, value) -> key.uid + " " 3216 + value.rxBytes + " " 3217 + value.rxPackets + " " 3218 + value.txBytes + " " 3219 + value.txPackets); 3220 } 3221 3222 @GuardedBy("mStatsLock") 3223 private void dumpStatsMapLocked(final IBpfMap<StatsMapKey, StatsMapValue> statsMap, 3224 final IndentingPrintWriter pw, final String mapName) { 3225 if (statsMap == null) { 3226 return; 3227 } 3228 3229 BpfDump.dumpMap(statsMap, pw, mapName, 3230 "ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets", 3231 (key, value) -> { 3232 final String ifName = mInterfaceMapHelper.getIfNameByIndex(key.ifaceIndex); 3233 return key.ifaceIndex + " " 3234 + (ifName != null ? ifName : "unknown") + " " 3235 + "0x" + Long.toHexString(key.tag) + " " 3236 + key.uid + " " 3237 + key.counterSet + " " 3238 + value.rxBytes + " " 3239 + value.rxPackets + " " 3240 + value.txBytes + " " 3241 + value.txPackets; 3242 }); 3243 } 3244 3245 @GuardedBy("mStatsLock") 3246 private void dumpIfaceStatsMapLocked(final IndentingPrintWriter pw) { 3247 BpfDump.dumpMap(mIfaceStatsMap, pw, "mIfaceStatsMap", 3248 "ifaceIndex ifaceName rxBytes rxPackets txBytes txPackets", 3249 (key, value) -> { 3250 final String ifName = mInterfaceMapHelper.getIfNameByIndex(key.val); 3251 return key.val + " " 3252 + (ifName != null ? ifName : "unknown") + " " 3253 + value.rxBytes + " " 3254 + value.rxPackets + " " 3255 + value.txBytes + " " 3256 + value.txPackets; 3257 }); 3258 } 3259 3260 private NetworkStats readNetworkStatsSummaryXt() { 3261 try { 3262 return mStatsFactory.readNetworkStatsSummaryXt(); 3263 } catch (IOException e) { 3264 throw new IllegalStateException(e); 3265 } 3266 } 3267 3268 private NetworkStats readNetworkStatsUidDetail(int uid, String[] ifaces, int tag) { 3269 try { 3270 return mStatsFactory.readNetworkStatsDetail(uid, ifaces, tag); 3271 } catch (IOException e) { 3272 throw new IllegalStateException(e); 3273 } 3274 } 3275 3276 /** 3277 * Return snapshot of current UID statistics, including any 3278 * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} 3279 * values. 3280 * 3281 * @param ifaces A list of interfaces the stats should be restricted to, or 3282 * {@link NetworkStats#INTERFACES_ALL}. 3283 */ 3284 private NetworkStats getNetworkStatsUidDetail(String[] ifaces) 3285 throws RemoteException { 3286 final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL, ifaces, TAG_ALL); 3287 3288 // fold tethering stats and operations into uid snapshot 3289 final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); 3290 tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); 3291 mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); 3292 uidSnapshot.combineAllValues(tetherSnapshot); 3293 3294 // get a stale copy of uid stats snapshot provided by providers. 3295 final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); 3296 providerStats.filter(UID_ALL, ifaces, TAG_ALL); 3297 mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); 3298 uidSnapshot.combineAllValues(providerStats); 3299 3300 uidSnapshot.combineAllValues(mUidOperations); 3301 uidSnapshot.filter(UID_ALL, ifaces, TAG_ALL); 3302 3303 return uidSnapshot; 3304 } 3305 3306 /** 3307 * Return snapshot of current non-offloaded tethering statistics. Will return empty 3308 * {@link NetworkStats} if any problems are encountered, or queried by {@code STATS_PER_IFACE} 3309 * since it is already included by {@link #nativeGetIfaceStat}. 3310 * See {@code OffloadTetheringStatsProvider} for offloaded tethering stats. 3311 */ 3312 // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded 3313 // tethering stats. 3314 private @NonNull NetworkStats getNetworkStatsTethering(int how) throws RemoteException { 3315 // We only need to return per-UID stats. Per-device stats are already counted by 3316 // interface counters. 3317 if (how != STATS_PER_UID) { 3318 return new NetworkStats(SystemClock.elapsedRealtime(), 0); 3319 } 3320 3321 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); 3322 try { 3323 final TetherStatsParcel[] tetherStatsParcels = mNetd.tetherGetStats(); 3324 for (TetherStatsParcel tetherStats : tetherStatsParcels) { 3325 try { 3326 stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING, 3327 SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3328 tetherStats.rxBytes, tetherStats.rxPackets, 3329 tetherStats.txBytes, tetherStats.txPackets, 0L)); 3330 } catch (ArrayIndexOutOfBoundsException e) { 3331 throw new IllegalStateException("invalid tethering stats " + e); 3332 } 3333 } 3334 } catch (IllegalStateException | ServiceSpecificException e) { 3335 Log.wtf(TAG, "problem reading network stats", e); 3336 } 3337 return stats; 3338 } 3339 3340 /** 3341 * Registers a custom provider of {@link android.net.NetworkStats} to combine the network 3342 * statistics that cannot be seen by the kernel to system. To unregister, invoke the 3343 * {@code unregister()} of the returned callback. 3344 * 3345 * @param tag a human readable identifier of the custom network stats provider. 3346 * @param provider the {@link INetworkStatsProvider} binder corresponding to the 3347 * {@link NetworkStatsProvider} to be registered. 3348 * 3349 * @return a {@link INetworkStatsProviderCallback} binder 3350 * interface, which can be used to report events to the system. 3351 */ 3352 public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( 3353 @NonNull String tag, @NonNull INetworkStatsProvider provider) { 3354 PermissionUtils.enforceAnyPermissionOf(mContext, NETWORK_STATS_PROVIDER, 3355 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); 3356 Objects.requireNonNull(provider, "provider is null"); 3357 Objects.requireNonNull(tag, "tag is null"); 3358 final NetworkPolicyManager netPolicyManager = mContext 3359 .getSystemService(NetworkPolicyManager.class); 3360 try { 3361 NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( 3362 tag, provider, mStatsProviderSem, mAlertObserver, 3363 mStatsProviderCbList, netPolicyManager); 3364 mStatsProviderCbList.add(callback); 3365 Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" 3366 + getCallingUid() + "/" + getCallingPid()); 3367 return callback; 3368 } catch (RemoteException e) { 3369 Log.e(TAG, "registerNetworkStatsProvider failed", e); 3370 } 3371 return null; 3372 } 3373 3374 // Collect stats from local cache of providers. 3375 private @NonNull NetworkStats getNetworkStatsFromProviders(int how) { 3376 final NetworkStats ret = new NetworkStats(0L, 0); 3377 invokeForAllStatsProviderCallbacks((cb) -> ret.combineAllValues(cb.getCachedStats(how))); 3378 return ret; 3379 } 3380 3381 @FunctionalInterface 3382 private interface ThrowingConsumer<S, T extends Throwable> { 3383 void accept(S s) throws T; 3384 } 3385 3386 private void invokeForAllStatsProviderCallbacks( 3387 @NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) { 3388 for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { 3389 try { 3390 task.accept(cb); 3391 } catch (RemoteException e) { 3392 Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); 3393 } 3394 } 3395 } 3396 3397 private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub 3398 implements IBinder.DeathRecipient { 3399 @NonNull final String mTag; 3400 3401 @NonNull final INetworkStatsProvider mProvider; 3402 @NonNull private final Semaphore mSemaphore; 3403 @NonNull final AlertObserver mAlertObserver; 3404 @NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList; 3405 @NonNull final NetworkPolicyManager mNetworkPolicyManager; 3406 3407 @NonNull private final Object mProviderStatsLock = new Object(); 3408 3409 @GuardedBy("mProviderStatsLock") 3410 // Track STATS_PER_IFACE and STATS_PER_UID separately. 3411 private final NetworkStats mIfaceStats = new NetworkStats(0L, 0); 3412 @GuardedBy("mProviderStatsLock") 3413 private final NetworkStats mUidStats = new NetworkStats(0L, 0); 3414 3415 NetworkStatsProviderCallbackImpl( 3416 @NonNull String tag, @NonNull INetworkStatsProvider provider, 3417 @NonNull Semaphore semaphore, 3418 @NonNull AlertObserver alertObserver, 3419 @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList, 3420 @NonNull NetworkPolicyManager networkPolicyManager) 3421 throws RemoteException { 3422 mTag = tag; 3423 mProvider = provider; 3424 mProvider.asBinder().linkToDeath(this, 0); 3425 mSemaphore = semaphore; 3426 mAlertObserver = alertObserver; 3427 mStatsProviderCbList = cbList; 3428 mNetworkPolicyManager = networkPolicyManager; 3429 } 3430 3431 @NonNull 3432 public NetworkStats getCachedStats(int how) { 3433 synchronized (mProviderStatsLock) { 3434 NetworkStats stats; 3435 switch (how) { 3436 case STATS_PER_IFACE: 3437 stats = mIfaceStats; 3438 break; 3439 case STATS_PER_UID: 3440 stats = mUidStats; 3441 break; 3442 default: 3443 throw new IllegalArgumentException("Invalid type: " + how); 3444 } 3445 // Callers might be able to mutate the returned object. Return a defensive copy 3446 // instead of local reference. 3447 return stats.clone(); 3448 } 3449 } 3450 3451 @Override 3452 public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats, 3453 @Nullable NetworkStats uidStats) { 3454 // TODO: 1. Use token to map ifaces to correct NetworkIdentity. 3455 // 2. Store the difference and store it directly to the recorder. 3456 synchronized (mProviderStatsLock) { 3457 if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats); 3458 if (uidStats != null) mUidStats.combineAllValues(uidStats); 3459 } 3460 mSemaphore.release(); 3461 } 3462 3463 @Override 3464 public void notifyAlertReached() throws RemoteException { 3465 // This binder object can only have been obtained by a process that holds 3466 // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required. 3467 BinderUtils.withCleanCallingIdentity(() -> 3468 mAlertObserver.onQuotaLimitReached(LIMIT_GLOBAL_ALERT, null /* unused */)); 3469 } 3470 3471 @Override 3472 public void notifyWarningReached() { 3473 Log.d(TAG, mTag + ": notifyWarningReached"); 3474 BinderUtils.withCleanCallingIdentity(() -> 3475 mNetworkPolicyManager.notifyStatsProviderWarningReached()); 3476 } 3477 3478 @Override 3479 public void notifyLimitReached() { 3480 Log.d(TAG, mTag + ": notifyLimitReached"); 3481 BinderUtils.withCleanCallingIdentity(() -> 3482 mNetworkPolicyManager.notifyStatsProviderLimitReached()); 3483 } 3484 3485 @Override 3486 public void binderDied() { 3487 Log.d(TAG, mTag + ": binderDied"); 3488 mStatsProviderCbList.remove(this); 3489 } 3490 3491 @Override 3492 public void unregister() { 3493 Log.d(TAG, mTag + ": unregister"); 3494 mStatsProviderCbList.remove(this); 3495 } 3496 3497 } 3498 3499 private void assertSystemReady() { 3500 if (!mSystemReady) { 3501 throw new IllegalStateException("System not ready"); 3502 } 3503 } 3504 3505 private final boolean mSupportEventLogger; 3506 @GuardedBy("mStatsLock") 3507 @Nullable 3508 private final NetworkStatsEventLogger mEventLogger; 3509 3510 /** 3511 * Create a PollEvent instance if the feature is enabled. 3512 */ 3513 @Nullable 3514 public PollEvent maybeCreatePollEvent(@NetworkStatsEventLogger.PollReason int reason) { 3515 if (mSupportEventLogger) { 3516 return new PollEvent(reason); 3517 } 3518 return null; 3519 } 3520 3521 private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> { 3522 @Override 3523 public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, 3524 int rightIndex, String cookie) { 3525 Log.w(TAG, "Found non-monotonic values; saving to dropbox"); 3526 3527 // record error for debugging 3528 final StringBuilder builder = new StringBuilder(); 3529 builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex 3530 + "] - right[" + rightIndex + "]\n"); 3531 builder.append("left=").append(left).append('\n'); 3532 builder.append("right=").append(right).append('\n'); 3533 3534 mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, 3535 builder.toString()); 3536 } 3537 3538 @Override 3539 public void foundNonMonotonic( 3540 NetworkStats stats, int statsIndex, String cookie) { 3541 Log.w(TAG, "Found non-monotonic values; saving to dropbox"); 3542 3543 final StringBuilder builder = new StringBuilder(); 3544 builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n"); 3545 builder.append("stats=").append(stats).append('\n'); 3546 3547 mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, 3548 builder.toString()); 3549 } 3550 } 3551 3552 /** 3553 * Default external settings that read from 3554 * {@link android.provider.Settings.Global}. 3555 */ 3556 @VisibleForTesting(visibility = PRIVATE) 3557 static class DefaultNetworkStatsSettings implements NetworkStatsSettings { 3558 DefaultNetworkStatsSettings() {} 3559 3560 @Override 3561 public long getPollInterval() { 3562 return 30 * MINUTE_IN_MILLIS; 3563 } 3564 @Override 3565 public long getPollDelay() { 3566 return DEFAULT_PERFORM_POLL_DELAY_MS; 3567 } 3568 @Override 3569 public long getGlobalAlertBytes(long def) { 3570 return def; 3571 } 3572 @Override 3573 public boolean getSampleEnabled() { 3574 return true; 3575 } 3576 @Override 3577 public boolean getAugmentEnabled() { 3578 return true; 3579 } 3580 @Override 3581 public boolean getCombineSubtypeEnabled() { 3582 return false; 3583 } 3584 @Override 3585 public Config getXtConfig() { 3586 return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); 3587 } 3588 @Override 3589 public Config getUidConfig() { 3590 return new Config(2 * HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); 3591 } 3592 @Override 3593 public Config getUidTagConfig() { 3594 return new Config(2 * HOUR_IN_MILLIS, 5 * DAY_IN_MILLIS, 15 * DAY_IN_MILLIS); 3595 } 3596 @Override 3597 public long getXtPersistBytes(long def) { 3598 return def; 3599 } 3600 @Override 3601 public long getUidPersistBytes(long def) { 3602 return def; 3603 } 3604 @Override 3605 public long getUidTagPersistBytes(long def) { 3606 return def; 3607 } 3608 } 3609 3610 // TODO: Read stats by using BpfNetMapsReader. 3611 private static native void nativeRegisterIface(String iface); 3612 @Nullable 3613 private static native NetworkStats.Entry nativeGetTotalStat(); 3614 @Nullable 3615 private static native NetworkStats.Entry nativeGetIfaceStat(String iface); 3616 @Nullable 3617 private static native NetworkStats.Entry nativeGetUidStat(int uid); 3618 3619 /** Initializes and registers the Perfetto Network Trace data source */ 3620 public static native void nativeInitNetworkTracing(); 3621 } 3622