• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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