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