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