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