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