• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.net;
18 
19 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
21 import static android.Manifest.permission.DUMP;
22 import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
23 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
24 import static android.content.Intent.ACTION_SHUTDOWN;
25 import static android.content.Intent.ACTION_UID_REMOVED;
26 import static android.content.Intent.EXTRA_UID;
27 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
28 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
29 import static android.net.NetworkStats.IFACE_ALL;
30 import static android.net.NetworkStats.SET_ALL;
31 import static android.net.NetworkStats.SET_DEFAULT;
32 import static android.net.NetworkStats.SET_FOREGROUND;
33 import static android.net.NetworkStats.TAG_NONE;
34 import static android.net.NetworkStats.UID_ALL;
35 import static android.net.NetworkStatsHistory.randomLong;
36 import static android.net.NetworkTemplate.buildTemplateMobileAll;
37 import static android.net.NetworkTemplate.buildTemplateWifi;
38 import static android.net.TrafficStats.UID_REMOVED;
39 import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
40 import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
41 import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
42 import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
43 import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
44 import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
45 import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
46 import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
47 import static android.telephony.PhoneStateListener.LISTEN_NONE;
48 import static android.text.format.DateUtils.DAY_IN_MILLIS;
49 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
50 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
51 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
52 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
53 import static com.android.internal.util.Preconditions.checkNotNull;
54 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
55 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
56 import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
57 
58 import android.app.AlarmManager;
59 import android.app.IAlarmManager;
60 import android.app.PendingIntent;
61 import android.content.BroadcastReceiver;
62 import android.content.ContentResolver;
63 import android.content.Context;
64 import android.content.Intent;
65 import android.content.IntentFilter;
66 import android.content.pm.ApplicationInfo;
67 import android.content.pm.PackageManager;
68 import android.content.pm.PackageManager.NameNotFoundException;
69 import android.net.IConnectivityManager;
70 import android.net.INetworkManagementEventObserver;
71 import android.net.INetworkStatsService;
72 import android.net.NetworkIdentity;
73 import android.net.NetworkInfo;
74 import android.net.NetworkState;
75 import android.net.NetworkStats;
76 import android.net.NetworkStatsHistory;
77 import android.net.NetworkTemplate;
78 import android.os.Binder;
79 import android.os.Environment;
80 import android.os.Handler;
81 import android.os.HandlerThread;
82 import android.os.INetworkManagementService;
83 import android.os.Message;
84 import android.os.PowerManager;
85 import android.os.RemoteException;
86 import android.os.SystemClock;
87 import android.provider.Settings;
88 import android.telephony.PhoneStateListener;
89 import android.telephony.TelephonyManager;
90 import android.util.EventLog;
91 import android.util.Log;
92 import android.util.NtpTrustedTime;
93 import android.util.Slog;
94 import android.util.SparseIntArray;
95 import android.util.TrustedTime;
96 
97 import com.android.internal.os.AtomicFile;
98 import com.android.internal.util.Objects;
99 import com.android.server.EventLogTags;
100 import com.android.server.connectivity.Tethering;
101 import com.google.android.collect.Lists;
102 import com.google.android.collect.Maps;
103 import com.google.android.collect.Sets;
104 
105 import java.io.BufferedInputStream;
106 import java.io.BufferedOutputStream;
107 import java.io.DataInputStream;
108 import java.io.DataOutputStream;
109 import java.io.File;
110 import java.io.FileDescriptor;
111 import java.io.FileNotFoundException;
112 import java.io.FileOutputStream;
113 import java.io.IOException;
114 import java.io.PrintWriter;
115 import java.net.ProtocolException;
116 import java.util.ArrayList;
117 import java.util.Collections;
118 import java.util.HashMap;
119 import java.util.HashSet;
120 import java.util.Random;
121 
122 import libcore.io.IoUtils;
123 
124 /**
125  * Collect and persist detailed network statistics, and provide this data to
126  * other system services.
127  */
128 public class NetworkStatsService extends INetworkStatsService.Stub {
129     private static final String TAG = "NetworkStats";
130     private static final boolean LOGD = false;
131     private static final boolean LOGV = false;
132 
133     /** File header magic number: "ANET" */
134     private static final int FILE_MAGIC = 0x414E4554;
135     private static final int VERSION_NETWORK_INIT = 1;
136     private static final int VERSION_UID_INIT = 1;
137     private static final int VERSION_UID_WITH_IDENT = 2;
138     private static final int VERSION_UID_WITH_TAG = 3;
139     private static final int VERSION_UID_WITH_SET = 4;
140 
141     private static final int MSG_PERFORM_POLL = 1;
142     private static final int MSG_UPDATE_IFACES = 2;
143 
144     /** Flags to control detail level of poll event. */
145     private static final int FLAG_PERSIST_NETWORK = 0x1;
146     private static final int FLAG_PERSIST_UID = 0x2;
147     private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
148     private static final int FLAG_PERSIST_FORCE = 0x100;
149 
150     /** Sample recent usage after each poll event. */
151     private static final boolean ENABLE_SAMPLE_AFTER_POLL = true;
152 
153     private final Context mContext;
154     private final INetworkManagementService mNetworkManager;
155     private final IAlarmManager mAlarmManager;
156     private final TrustedTime mTime;
157     private final TelephonyManager mTeleManager;
158     private final NetworkStatsSettings mSettings;
159 
160     private final PowerManager.WakeLock mWakeLock;
161 
162     private IConnectivityManager mConnManager;
163 
164     // @VisibleForTesting
165     public static final String ACTION_NETWORK_STATS_POLL =
166             "com.android.server.action.NETWORK_STATS_POLL";
167     public static final String ACTION_NETWORK_STATS_UPDATED =
168             "com.android.server.action.NETWORK_STATS_UPDATED";
169 
170     private PendingIntent mPollIntent;
171 
172     // TODO: trim empty history objects entirely
173 
174     private static final long KB_IN_BYTES = 1024;
175     private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
176     private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
177 
178     /**
179      * Settings that can be changed externally.
180      */
181     public interface NetworkStatsSettings {
getPollInterval()182         public long getPollInterval();
getPersistThreshold()183         public long getPersistThreshold();
getNetworkBucketDuration()184         public long getNetworkBucketDuration();
getNetworkMaxHistory()185         public long getNetworkMaxHistory();
getUidBucketDuration()186         public long getUidBucketDuration();
getUidMaxHistory()187         public long getUidMaxHistory();
getTagMaxHistory()188         public long getTagMaxHistory();
getTimeCacheMaxAge()189         public long getTimeCacheMaxAge();
190     }
191 
192     private final Object mStatsLock = new Object();
193 
194     /** Set of currently active ifaces. */
195     private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
196     /** Set of historical {@code dev} stats for known networks. */
197     private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkDevStats = Maps.newHashMap();
198     /** Set of historical {@code xtables} stats for known networks. */
199     private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkXtStats = Maps.newHashMap();
200     /** Set of historical {@code xtables} stats for known UIDs. */
201     private HashMap<UidStatsKey, NetworkStatsHistory> mUidStats = Maps.newHashMap();
202 
203     /** Flag if {@link #mUidStats} have been loaded from disk. */
204     private boolean mUidStatsLoaded = false;
205 
206     private NetworkStats mLastPollNetworkDevSnapshot;
207     private NetworkStats mLastPollNetworkXtSnapshot;
208     private NetworkStats mLastPollUidSnapshot;
209     private NetworkStats mLastPollOperationsSnapshot;
210 
211     private NetworkStats mLastPersistNetworkDevSnapshot;
212     private NetworkStats mLastPersistNetworkXtSnapshot;
213     private NetworkStats mLastPersistUidSnapshot;
214 
215     /** Current counter sets for each UID. */
216     private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
217 
218     /** Data layer operation counters for splicing into other structures. */
219     private NetworkStats mOperations = new NetworkStats(0L, 10);
220 
221     private final HandlerThread mHandlerThread;
222     private final Handler mHandler;
223 
224     private final AtomicFile mNetworkDevFile;
225     private final AtomicFile mNetworkXtFile;
226     private final AtomicFile mUidFile;
227 
NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager)228     public NetworkStatsService(
229             Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
230         this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
231                 getSystemDir(), new DefaultNetworkStatsSettings(context));
232     }
233 
getSystemDir()234     private static File getSystemDir() {
235         return new File(Environment.getDataDirectory(), "system");
236     }
237 
NetworkStatsService(Context context, INetworkManagementService networkManager, IAlarmManager alarmManager, TrustedTime time, File systemDir, NetworkStatsSettings settings)238     public NetworkStatsService(Context context, INetworkManagementService networkManager,
239             IAlarmManager alarmManager, TrustedTime time, File systemDir,
240             NetworkStatsSettings settings) {
241         mContext = checkNotNull(context, "missing Context");
242         mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
243         mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
244         mTime = checkNotNull(time, "missing TrustedTime");
245         mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
246         mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
247 
248         final PowerManager powerManager = (PowerManager) context.getSystemService(
249                 Context.POWER_SERVICE);
250         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
251 
252         mHandlerThread = new HandlerThread(TAG);
253         mHandlerThread.start();
254         mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
255 
256         mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin"));
257         mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin"));
258         mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
259     }
260 
bindConnectivityManager(IConnectivityManager connManager)261     public void bindConnectivityManager(IConnectivityManager connManager) {
262         mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
263     }
264 
systemReady()265     public void systemReady() {
266         synchronized (mStatsLock) {
267             // read historical network stats from disk, since policy service
268             // might need them right away. we delay loading detailed UID stats
269             // until actually needed.
270             readNetworkDevStatsLocked();
271             readNetworkXtStatsLocked();
272         }
273 
274         // watch for network interfaces to be claimed
275         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
276         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
277 
278         // watch for tethering changes
279         final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
280         mContext.registerReceiver(mTetherReceiver, tetherFilter, CONNECTIVITY_INTERNAL, mHandler);
281 
282         // listen for periodic polling events
283         final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
284         mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
285 
286         // listen for uid removal to clean stats
287         final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
288         mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
289 
290         // persist stats during clean shutdown
291         final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
292         mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
293 
294         try {
295             mNetworkManager.registerObserver(mAlertObserver);
296         } catch (RemoteException e) {
297             // ignored; service lives in system_server
298         }
299 
300         // watch for networkType changes that aren't broadcast through
301         // CONNECTIVITY_ACTION_IMMEDIATE above.
302         mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE);
303 
304         registerPollAlarmLocked();
305         registerGlobalAlert();
306 
307         // bootstrap initial stats to prevent double-counting later
308         bootstrapStats();
309     }
310 
shutdownLocked()311     private void shutdownLocked() {
312         mContext.unregisterReceiver(mConnReceiver);
313         mContext.unregisterReceiver(mTetherReceiver);
314         mContext.unregisterReceiver(mPollReceiver);
315         mContext.unregisterReceiver(mRemovedReceiver);
316         mContext.unregisterReceiver(mShutdownReceiver);
317 
318         mTeleManager.listen(mPhoneListener, LISTEN_NONE);
319 
320         writeNetworkDevStatsLocked();
321         writeNetworkXtStatsLocked();
322         if (mUidStatsLoaded) {
323             writeUidStatsLocked();
324         }
325         mNetworkDevStats.clear();
326         mNetworkXtStats.clear();
327         mUidStats.clear();
328         mUidStatsLoaded = false;
329     }
330 
331     /**
332      * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
333      * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
334      */
registerPollAlarmLocked()335     private void registerPollAlarmLocked() {
336         try {
337             if (mPollIntent != null) {
338                 mAlarmManager.remove(mPollIntent);
339             }
340 
341             mPollIntent = PendingIntent.getBroadcast(
342                     mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
343 
344             final long currentRealtime = SystemClock.elapsedRealtime();
345             mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
346                     mSettings.getPollInterval(), mPollIntent);
347         } catch (RemoteException e) {
348             // ignored; service lives in system_server
349         }
350     }
351 
352     /**
353      * Register for a global alert that is delivered through
354      * {@link INetworkManagementEventObserver} once a threshold amount of data
355      * has been transferred.
356      */
registerGlobalAlert()357     private void registerGlobalAlert() {
358         try {
359             final long alertBytes = mSettings.getPersistThreshold();
360             mNetworkManager.setGlobalAlert(alertBytes);
361         } catch (IllegalStateException e) {
362             Slog.w(TAG, "problem registering for global alert: " + e);
363         } catch (RemoteException e) {
364             // ignored; service lives in system_server
365         }
366     }
367 
368     @Override
getHistoryForNetwork(NetworkTemplate template, int fields)369     public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
370         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
371         return getHistoryForNetworkDev(template, fields);
372     }
373 
getHistoryForNetworkDev(NetworkTemplate template, int fields)374     private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) {
375         return getHistoryForNetwork(template, fields, mNetworkDevStats);
376     }
377 
getHistoryForNetworkXt(NetworkTemplate template, int fields)378     private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) {
379         return getHistoryForNetwork(template, fields, mNetworkXtStats);
380     }
381 
getHistoryForNetwork(NetworkTemplate template, int fields, HashMap<NetworkIdentitySet, NetworkStatsHistory> source)382     private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields,
383             HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
384         synchronized (mStatsLock) {
385             // combine all interfaces that match template
386             final NetworkStatsHistory combined = new NetworkStatsHistory(
387                     mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
388             for (NetworkIdentitySet ident : source.keySet()) {
389                 if (templateMatches(template, ident)) {
390                     final NetworkStatsHistory history = source.get(ident);
391                     if (history != null) {
392                         combined.recordEntireHistory(history);
393                     }
394                 }
395             }
396             return combined;
397         }
398     }
399 
400     @Override
getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields)401     public NetworkStatsHistory getHistoryForUid(
402             NetworkTemplate template, int uid, int set, int tag, int fields) {
403         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
404 
405         synchronized (mStatsLock) {
406             ensureUidStatsLoadedLocked();
407 
408             // combine all interfaces that match template
409             final NetworkStatsHistory combined = new NetworkStatsHistory(
410                     mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
411             for (UidStatsKey key : mUidStats.keySet()) {
412                 final boolean setMatches = set == SET_ALL || key.set == set;
413                 if (templateMatches(template, key.ident) && key.uid == uid && setMatches
414                         && key.tag == tag) {
415                     final NetworkStatsHistory history = mUidStats.get(key);
416                     combined.recordEntireHistory(history);
417                 }
418             }
419 
420             return combined;
421         }
422     }
423 
424     @Override
getSummaryForNetwork(NetworkTemplate template, long start, long end)425     public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
426         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
427         return getSummaryForNetworkDev(template, start, end);
428     }
429 
getSummaryForNetworkDev(NetworkTemplate template, long start, long end)430     private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) {
431         return getSummaryForNetwork(template, start, end, mNetworkDevStats);
432     }
433 
getSummaryForNetworkXt(NetworkTemplate template, long start, long end)434     private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) {
435         return getSummaryForNetwork(template, start, end, mNetworkXtStats);
436     }
437 
getSummaryForNetwork(NetworkTemplate template, long start, long end, HashMap<NetworkIdentitySet, NetworkStatsHistory> source)438     private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end,
439             HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
440         synchronized (mStatsLock) {
441             // use system clock to be externally consistent
442             final long now = System.currentTimeMillis();
443 
444             final NetworkStats stats = new NetworkStats(end - start, 1);
445             final NetworkStats.Entry entry = new NetworkStats.Entry();
446             NetworkStatsHistory.Entry historyEntry = null;
447 
448             // combine total from all interfaces that match template
449             for (NetworkIdentitySet ident : source.keySet()) {
450                 if (templateMatches(template, ident)) {
451                     final NetworkStatsHistory history = source.get(ident);
452                     historyEntry = history.getValues(start, end, now, historyEntry);
453 
454                     entry.iface = IFACE_ALL;
455                     entry.uid = UID_ALL;
456                     entry.tag = TAG_NONE;
457                     entry.rxBytes = historyEntry.rxBytes;
458                     entry.rxPackets = historyEntry.rxPackets;
459                     entry.txBytes = historyEntry.txBytes;
460                     entry.txPackets = historyEntry.txPackets;
461 
462                     stats.combineValues(entry);
463                 }
464             }
465 
466             return stats;
467         }
468     }
469 
470     @Override
getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags)471     public NetworkStats getSummaryForAllUid(
472             NetworkTemplate template, long start, long end, boolean includeTags) {
473         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
474 
475         synchronized (mStatsLock) {
476             ensureUidStatsLoadedLocked();
477 
478             // use system clock to be externally consistent
479             final long now = System.currentTimeMillis();
480 
481             final NetworkStats stats = new NetworkStats(end - start, 24);
482             final NetworkStats.Entry entry = new NetworkStats.Entry();
483             NetworkStatsHistory.Entry historyEntry = null;
484 
485             for (UidStatsKey key : mUidStats.keySet()) {
486                 if (templateMatches(template, key.ident)) {
487                     // always include summary under TAG_NONE, and include
488                     // other tags when requested.
489                     if (key.tag == TAG_NONE || includeTags) {
490                         final NetworkStatsHistory history = mUidStats.get(key);
491                         historyEntry = history.getValues(start, end, now, historyEntry);
492 
493                         entry.iface = IFACE_ALL;
494                         entry.uid = key.uid;
495                         entry.set = key.set;
496                         entry.tag = key.tag;
497                         entry.rxBytes = historyEntry.rxBytes;
498                         entry.rxPackets = historyEntry.rxPackets;
499                         entry.txBytes = historyEntry.txBytes;
500                         entry.txPackets = historyEntry.txPackets;
501                         entry.operations = historyEntry.operations;
502 
503                         if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
504                                 || entry.txPackets > 0 || entry.operations > 0) {
505                             stats.combineValues(entry);
506                         }
507                     }
508                 }
509             }
510 
511             return stats;
512         }
513     }
514 
515     @Override
getDataLayerSnapshotForUid(int uid)516     public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
517         if (Binder.getCallingUid() != uid) {
518             mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
519         }
520 
521         // TODO: switch to data layer stats once kernel exports
522         // for now, read network layer stats and flatten across all ifaces
523         final NetworkStats networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
524         final NetworkStats dataLayer = new NetworkStats(
525                 networkLayer.getElapsedRealtime(), networkLayer.size());
526 
527         NetworkStats.Entry entry = null;
528         for (int i = 0; i < networkLayer.size(); i++) {
529             entry = networkLayer.getValues(i, entry);
530             entry.iface = IFACE_ALL;
531             dataLayer.combineValues(entry);
532         }
533 
534         // splice in operation counts
535         dataLayer.spliceOperationsFrom(mOperations);
536         return dataLayer;
537     }
538 
539     @Override
incrementOperationCount(int uid, int tag, int operationCount)540     public void incrementOperationCount(int uid, int tag, int operationCount) {
541         if (Binder.getCallingUid() != uid) {
542             mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
543         }
544 
545         if (operationCount < 0) {
546             throw new IllegalArgumentException("operation count can only be incremented");
547         }
548         if (tag == TAG_NONE) {
549             throw new IllegalArgumentException("operation count must have specific tag");
550         }
551 
552         synchronized (mStatsLock) {
553             final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
554             mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
555             mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
556         }
557     }
558 
559     @Override
setUidForeground(int uid, boolean uidForeground)560     public void setUidForeground(int uid, boolean uidForeground) {
561         mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
562 
563         synchronized (mStatsLock) {
564             final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
565             final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
566             if (oldSet != set) {
567                 mActiveUidCounterSet.put(uid, set);
568                 setKernelCounterSet(uid, set);
569             }
570         }
571     }
572 
573     @Override
forceUpdate()574     public void forceUpdate() {
575         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
576         performPoll(FLAG_PERSIST_ALL);
577     }
578 
579     /**
580      * Receiver that watches for {@link IConnectivityManager} to claim network
581      * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
582      * with mobile interfaces.
583      */
584     private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
585         @Override
586         public void onReceive(Context context, Intent intent) {
587             // on background handler thread, and verified CONNECTIVITY_INTERNAL
588             // permission above.
589             updateIfaces();
590         }
591     };
592 
593     /**
594      * Receiver that watches for {@link Tethering} to claim interface pairs.
595      */
596     private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
597         @Override
598         public void onReceive(Context context, Intent intent) {
599             // on background handler thread, and verified CONNECTIVITY_INTERNAL
600             // permission above.
601             performPoll(FLAG_PERSIST_NETWORK);
602         }
603     };
604 
605     private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
606         @Override
607         public void onReceive(Context context, Intent intent) {
608             // on background handler thread, and verified UPDATE_DEVICE_STATS
609             // permission above.
610             performPoll(FLAG_PERSIST_ALL);
611 
612             // verify that we're watching global alert
613             registerGlobalAlert();
614         }
615     };
616 
617     private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
618         @Override
619         public void onReceive(Context context, Intent intent) {
620             // on background handler thread, and UID_REMOVED is protected
621             // broadcast.
622             final int uid = intent.getIntExtra(EXTRA_UID, 0);
623             synchronized (mStatsLock) {
624                 // TODO: perform one last stats poll for UID
625                 mWakeLock.acquire();
626                 try {
627                     removeUidLocked(uid);
628                 } finally {
629                     mWakeLock.release();
630                 }
631             }
632         }
633     };
634 
635     private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
636         @Override
637         public void onReceive(Context context, Intent intent) {
638             // SHUTDOWN is protected broadcast.
639             synchronized (mStatsLock) {
640                 shutdownLocked();
641             }
642         }
643     };
644 
645     /**
646      * Observer that watches for {@link INetworkManagementService} alerts.
647      */
648     private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
649         @Override
650         public void limitReached(String limitName, String iface) {
651             // only someone like NMS should be calling us
652             mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
653 
654             if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
655                 // kick off background poll to collect network stats; UID stats
656                 // are handled during normal polling interval.
657                 final int flags = FLAG_PERSIST_NETWORK;
658                 mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
659 
660                 // re-arm global alert for next update
661                 registerGlobalAlert();
662             }
663         }
664     };
665 
666     private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN;
667     private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
668 
669     /**
670      * Receiver that watches for {@link TelephonyManager} changes, such as
671      * transitioning between network types.
672      */
673     private PhoneStateListener mPhoneListener = new PhoneStateListener() {
674         @Override
675         public void onDataConnectionStateChanged(int state, int networkType) {
676             final boolean stateChanged = state != mLastPhoneState;
677             final boolean networkTypeChanged = networkType != mLastPhoneNetworkType;
678 
679             if (networkTypeChanged && !stateChanged) {
680                 // networkType changed without a state change, which means we
681                 // need to roll our own update. delay long enough for
682                 // ConnectivityManager to process.
683                 // TODO: add direct event to ConnectivityService instead of
684                 // relying on this delay.
685                 if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()");
686                 mHandler.sendMessageDelayed(
687                         mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);
688             }
689 
690             mLastPhoneState = state;
691             mLastPhoneNetworkType = networkType;
692         }
693     };
694 
updateIfaces()695     private void updateIfaces() {
696         synchronized (mStatsLock) {
697             mWakeLock.acquire();
698             try {
699                 updateIfacesLocked();
700             } finally {
701                 mWakeLock.release();
702             }
703         }
704     }
705 
706     /**
707      * Inspect all current {@link NetworkState} to derive mapping from {@code
708      * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
709      * are active on a single {@code iface}, they are combined under a single
710      * {@link NetworkIdentitySet}.
711      */
updateIfacesLocked()712     private void updateIfacesLocked() {
713         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
714 
715         // take one last stats snapshot before updating iface mapping. this
716         // isn't perfect, since the kernel may already be counting traffic from
717         // the updated network.
718 
719         // poll, but only persist network stats to keep codepath fast. UID stats
720         // will be persisted during next alarm poll event.
721         performPollLocked(FLAG_PERSIST_NETWORK);
722 
723         final NetworkState[] states;
724         try {
725             states = mConnManager.getAllNetworkState();
726         } catch (RemoteException e) {
727             // ignored; service lives in system_server
728             return;
729         }
730 
731         // rebuild active interfaces based on connected networks
732         mActiveIfaces.clear();
733 
734         for (NetworkState state : states) {
735             if (state.networkInfo.isConnected()) {
736                 // collect networks under their parent interfaces
737                 final String iface = state.linkProperties.getInterfaceName();
738 
739                 NetworkIdentitySet ident = mActiveIfaces.get(iface);
740                 if (ident == null) {
741                     ident = new NetworkIdentitySet();
742                     mActiveIfaces.put(iface, ident);
743                 }
744 
745                 ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
746             }
747         }
748     }
749 
750     /**
751      * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
752      * so we have baseline values without double-counting.
753      */
bootstrapStats()754     private void bootstrapStats() {
755         try {
756             mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
757             mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
758             mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
759             mLastPollOperationsSnapshot = new NetworkStats(0L, 0);
760         } catch (IllegalStateException e) {
761             Slog.w(TAG, "problem reading network stats: " + e);
762         } catch (RemoteException e) {
763             // ignored; service lives in system_server
764         }
765     }
766 
performPoll(int flags)767     private void performPoll(int flags) {
768         synchronized (mStatsLock) {
769             mWakeLock.acquire();
770             try {
771                 performPollLocked(flags);
772             } finally {
773                 mWakeLock.release();
774             }
775         }
776     }
777 
778     /**
779      * Periodic poll operation, reading current statistics and recording into
780      * {@link NetworkStatsHistory}.
781      */
performPollLocked(int flags)782     private void performPollLocked(int flags) {
783         if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
784         final long startRealtime = SystemClock.elapsedRealtime();
785 
786         final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
787         final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
788         final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
789 
790         // try refreshing time source when stale
791         if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
792             mTime.forceRefresh();
793         }
794 
795         // TODO: consider marking "untrusted" times in historical stats
796         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
797                 : System.currentTimeMillis();
798         final long threshold = mSettings.getPersistThreshold();
799 
800         final NetworkStats uidSnapshot;
801         final NetworkStats networkXtSnapshot;
802         final NetworkStats networkDevSnapshot;
803         try {
804             // collect any tethering stats
805             final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
806             final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
807                     tetheredIfacePairs);
808 
809             // record uid stats, folding in tethering stats
810             uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
811             uidSnapshot.combineAllValues(tetherSnapshot);
812             performUidPollLocked(uidSnapshot, currentTime);
813 
814             // record dev network stats
815             networkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
816             performNetworkDevPollLocked(networkDevSnapshot, currentTime);
817 
818             // record xt network stats
819             networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot);
820             performNetworkXtPollLocked(networkXtSnapshot, currentTime);
821 
822         } catch (IllegalStateException e) {
823             Log.wtf(TAG, "problem reading network stats", e);
824             return;
825         } catch (RemoteException e) {
826             // ignored; service lives in system_server
827             return;
828         }
829 
830         // persist when enough network data has occurred
831         final long persistNetworkDevDelta = computeStatsDelta(
832                 mLastPersistNetworkDevSnapshot, networkDevSnapshot, true).getTotalBytes();
833         final long persistNetworkXtDelta = computeStatsDelta(
834                 mLastPersistNetworkXtSnapshot, networkXtSnapshot, true).getTotalBytes();
835         final boolean networkOverThreshold = persistNetworkDevDelta > threshold
836                 || persistNetworkXtDelta > threshold;
837         if (persistForce || (persistNetwork && networkOverThreshold)) {
838             writeNetworkDevStatsLocked();
839             writeNetworkXtStatsLocked();
840             mLastPersistNetworkDevSnapshot = networkDevSnapshot;
841             mLastPersistNetworkXtSnapshot = networkXtSnapshot;
842         }
843 
844         // persist when enough uid data has occurred
845         final long persistUidDelta = computeStatsDelta(mLastPersistUidSnapshot, uidSnapshot, true)
846                 .getTotalBytes();
847         if (persistForce || (persistUid && persistUidDelta > threshold)) {
848             writeUidStatsLocked();
849             mLastPersistUidSnapshot = uidSnapshot;
850         }
851 
852         if (LOGV) {
853             final long duration = SystemClock.elapsedRealtime() - startRealtime;
854             Slog.v(TAG, "performPollLocked() took " + duration + "ms");
855         }
856 
857         if (ENABLE_SAMPLE_AFTER_POLL) {
858             // sample stats after each full poll
859             performSample();
860         }
861 
862         // finally, dispatch updated event to any listeners
863         final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
864         updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
865         mContext.sendBroadcast(updatedIntent, READ_NETWORK_USAGE_HISTORY);
866     }
867 
868     /**
869      * Update {@link #mNetworkDevStats} historical usage.
870      */
performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime)871     private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) {
872         final HashSet<String> unknownIface = Sets.newHashSet();
873 
874         final NetworkStats delta = computeStatsDelta(
875                 mLastPollNetworkDevSnapshot, networkDevSnapshot, false);
876         final long timeStart = currentTime - delta.getElapsedRealtime();
877 
878         NetworkStats.Entry entry = null;
879         for (int i = 0; i < delta.size(); i++) {
880             entry = delta.getValues(i, entry);
881             final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
882             if (ident == null) {
883                 unknownIface.add(entry.iface);
884                 continue;
885             }
886 
887             final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident);
888             history.recordData(timeStart, currentTime, entry);
889         }
890 
891         mLastPollNetworkDevSnapshot = networkDevSnapshot;
892 
893         if (LOGD && unknownIface.size() > 0) {
894             Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats");
895         }
896     }
897 
898     /**
899      * Update {@link #mNetworkXtStats} historical usage.
900      */
performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime)901     private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) {
902         final HashSet<String> unknownIface = Sets.newHashSet();
903 
904         final NetworkStats delta = computeStatsDelta(
905                 mLastPollNetworkXtSnapshot, networkXtSnapshot, false);
906         final long timeStart = currentTime - delta.getElapsedRealtime();
907 
908         NetworkStats.Entry entry = null;
909         for (int i = 0; i < delta.size(); i++) {
910             entry = delta.getValues(i, entry);
911             final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
912             if (ident == null) {
913                 unknownIface.add(entry.iface);
914                 continue;
915             }
916 
917             final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident);
918             history.recordData(timeStart, currentTime, entry);
919         }
920 
921         mLastPollNetworkXtSnapshot = networkXtSnapshot;
922 
923         if (LOGD && unknownIface.size() > 0) {
924             Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats");
925         }
926     }
927 
928     /**
929      * Update {@link #mUidStats} historical usage.
930      */
performUidPollLocked(NetworkStats uidSnapshot, long currentTime)931     private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
932         ensureUidStatsLoadedLocked();
933 
934         final NetworkStats delta = computeStatsDelta(mLastPollUidSnapshot, uidSnapshot, false);
935         final NetworkStats operationsDelta = computeStatsDelta(
936                 mLastPollOperationsSnapshot, mOperations, false);
937         final long timeStart = currentTime - delta.getElapsedRealtime();
938 
939         NetworkStats.Entry entry = null;
940         NetworkStats.Entry operationsEntry = null;
941         for (int i = 0; i < delta.size(); i++) {
942             entry = delta.getValues(i, entry);
943             final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
944             if (ident == null) {
945                 if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
946                         || entry.txPackets > 0) {
947                     Log.w(TAG, "dropping UID delta from unknown iface: " + entry);
948                 }
949                 continue;
950             }
951 
952             // splice in operation counts since last poll
953             final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag);
954             if (j != -1) {
955                 operationsEntry = operationsDelta.getValues(j, operationsEntry);
956                 entry.operations = operationsEntry.operations;
957             }
958 
959             final NetworkStatsHistory history = findOrCreateUidStatsLocked(
960                     ident, entry.uid, entry.set, entry.tag);
961             history.recordData(timeStart, currentTime, entry);
962         }
963 
964         mLastPollUidSnapshot = uidSnapshot;
965         mLastPollOperationsSnapshot = mOperations;
966         mOperations = new NetworkStats(0L, 10);
967     }
968 
969     /**
970      * Sample recent statistics summary into {@link EventLog}.
971      */
performSample()972     private void performSample() {
973         final long largestBucketSize = Math.max(
974                 mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
975 
976         // take sample as atomic buckets
977         final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
978         final long end = now - (now % largestBucketSize) + largestBucketSize;
979         final long start = end - largestBucketSize;
980 
981         final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
982 
983         NetworkTemplate template = null;
984         NetworkStats.Entry devTotal = null;
985         NetworkStats.Entry xtTotal = null;
986         NetworkStats.Entry uidTotal = null;
987 
988         // collect mobile sample
989         template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
990         devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
991         xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
992         uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
993         EventLogTags.writeNetstatsMobileSample(
994                 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
995                 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
996                 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
997                 trustedTime);
998 
999         // collect wifi sample
1000         template = buildTemplateWifi();
1001         devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
1002         xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
1003         uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
1004         EventLogTags.writeNetstatsWifiSample(
1005                 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1006                 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1007                 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
1008                 trustedTime);
1009     }
1010 
1011     /**
1012      * Clean up {@link #mUidStats} after UID is removed.
1013      */
removeUidLocked(int uid)1014     private void removeUidLocked(int uid) {
1015         ensureUidStatsLoadedLocked();
1016 
1017         final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList();
1018         knownKeys.addAll(mUidStats.keySet());
1019 
1020         // migrate all UID stats into special "removed" bucket
1021         for (UidStatsKey key : knownKeys) {
1022             if (key.uid == uid) {
1023                 // only migrate combined TAG_NONE history
1024                 if (key.tag == TAG_NONE) {
1025                     final NetworkStatsHistory uidHistory = mUidStats.get(key);
1026                     final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
1027                             key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
1028                     removedHistory.recordEntireHistory(uidHistory);
1029                 }
1030                 mUidStats.remove(key);
1031             }
1032         }
1033 
1034         // clear kernel stats associated with UID
1035         resetKernelUidStats(uid);
1036 
1037         // since this was radical rewrite, push to disk
1038         writeUidStatsLocked();
1039     }
1040 
findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident)1041     private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) {
1042         return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats);
1043     }
1044 
findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident)1045     private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) {
1046         return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats);
1047     }
1048 
findOrCreateNetworkStatsLocked( NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source)1049     private NetworkStatsHistory findOrCreateNetworkStatsLocked(
1050             NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
1051         final NetworkStatsHistory existing = source.get(ident);
1052 
1053         // update when no existing, or when bucket duration changed
1054         final long bucketDuration = mSettings.getNetworkBucketDuration();
1055         NetworkStatsHistory updated = null;
1056         if (existing == null) {
1057             updated = new NetworkStatsHistory(bucketDuration, 10);
1058         } else if (existing.getBucketDuration() != bucketDuration) {
1059             updated = new NetworkStatsHistory(
1060                     bucketDuration, estimateResizeBuckets(existing, bucketDuration));
1061             updated.recordEntireHistory(existing);
1062         }
1063 
1064         if (updated != null) {
1065             source.put(ident, updated);
1066             return updated;
1067         } else {
1068             return existing;
1069         }
1070     }
1071 
findOrCreateUidStatsLocked( NetworkIdentitySet ident, int uid, int set, int tag)1072     private NetworkStatsHistory findOrCreateUidStatsLocked(
1073             NetworkIdentitySet ident, int uid, int set, int tag) {
1074         ensureUidStatsLoadedLocked();
1075 
1076         final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
1077         final NetworkStatsHistory existing = mUidStats.get(key);
1078 
1079         // update when no existing, or when bucket duration changed
1080         final long bucketDuration = mSettings.getUidBucketDuration();
1081         NetworkStatsHistory updated = null;
1082         if (existing == null) {
1083             updated = new NetworkStatsHistory(bucketDuration, 10);
1084         } else if (existing.getBucketDuration() != bucketDuration) {
1085             updated = new NetworkStatsHistory(
1086                     bucketDuration, estimateResizeBuckets(existing, bucketDuration));
1087             updated.recordEntireHistory(existing);
1088         }
1089 
1090         if (updated != null) {
1091             mUidStats.put(key, updated);
1092             return updated;
1093         } else {
1094             return existing;
1095         }
1096     }
1097 
readNetworkDevStatsLocked()1098     private void readNetworkDevStatsLocked() {
1099         if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()");
1100         readNetworkStats(mNetworkDevFile, mNetworkDevStats);
1101     }
1102 
readNetworkXtStatsLocked()1103     private void readNetworkXtStatsLocked() {
1104         if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()");
1105         readNetworkStats(mNetworkXtFile, mNetworkXtStats);
1106     }
1107 
readNetworkStats( AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output)1108     private static void readNetworkStats(
1109             AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output) {
1110         // clear any existing stats and read from disk
1111         output.clear();
1112 
1113         DataInputStream in = null;
1114         try {
1115             in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
1116 
1117             // verify file magic header intact
1118             final int magic = in.readInt();
1119             if (magic != FILE_MAGIC) {
1120                 throw new ProtocolException("unexpected magic: " + magic);
1121             }
1122 
1123             final int version = in.readInt();
1124             switch (version) {
1125                 case VERSION_NETWORK_INIT: {
1126                     // network := size *(NetworkIdentitySet NetworkStatsHistory)
1127                     final int size = in.readInt();
1128                     for (int i = 0; i < size; i++) {
1129                         final NetworkIdentitySet ident = new NetworkIdentitySet(in);
1130                         final NetworkStatsHistory history = new NetworkStatsHistory(in);
1131                         output.put(ident, history);
1132                     }
1133                     break;
1134                 }
1135                 default: {
1136                     throw new ProtocolException("unexpected version: " + version);
1137                 }
1138             }
1139         } catch (FileNotFoundException e) {
1140             // missing stats is okay, probably first boot
1141         } catch (IOException e) {
1142             Log.wtf(TAG, "problem reading network stats", e);
1143         } finally {
1144             IoUtils.closeQuietly(in);
1145         }
1146     }
1147 
ensureUidStatsLoadedLocked()1148     private void ensureUidStatsLoadedLocked() {
1149         if (!mUidStatsLoaded) {
1150             readUidStatsLocked();
1151             mUidStatsLoaded = true;
1152         }
1153     }
1154 
readUidStatsLocked()1155     private void readUidStatsLocked() {
1156         if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
1157 
1158         // clear any existing stats and read from disk
1159         mUidStats.clear();
1160 
1161         DataInputStream in = null;
1162         try {
1163             in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
1164 
1165             // verify file magic header intact
1166             final int magic = in.readInt();
1167             if (magic != FILE_MAGIC) {
1168                 throw new ProtocolException("unexpected magic: " + magic);
1169             }
1170 
1171             final int version = in.readInt();
1172             switch (version) {
1173                 case VERSION_UID_INIT: {
1174                     // uid := size *(UID NetworkStatsHistory)
1175 
1176                     // drop this data version, since we don't have a good
1177                     // mapping into NetworkIdentitySet.
1178                     break;
1179                 }
1180                 case VERSION_UID_WITH_IDENT: {
1181                     // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
1182 
1183                     // drop this data version, since this version only existed
1184                     // for a short time.
1185                     break;
1186                 }
1187                 case VERSION_UID_WITH_TAG:
1188                 case VERSION_UID_WITH_SET: {
1189                     // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
1190                     final int identSize = in.readInt();
1191                     for (int i = 0; i < identSize; i++) {
1192                         final NetworkIdentitySet ident = new NetworkIdentitySet(in);
1193 
1194                         final int size = in.readInt();
1195                         for (int j = 0; j < size; j++) {
1196                             final int uid = in.readInt();
1197                             final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
1198                                     : SET_DEFAULT;
1199                             final int tag = in.readInt();
1200 
1201                             final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
1202                             final NetworkStatsHistory history = new NetworkStatsHistory(in);
1203                             mUidStats.put(key, history);
1204                         }
1205                     }
1206                     break;
1207                 }
1208                 default: {
1209                     throw new ProtocolException("unexpected version: " + version);
1210                 }
1211             }
1212         } catch (FileNotFoundException e) {
1213             // missing stats is okay, probably first boot
1214         } catch (IOException e) {
1215             Log.wtf(TAG, "problem reading uid stats", e);
1216         } finally {
1217             IoUtils.closeQuietly(in);
1218         }
1219     }
1220 
writeNetworkDevStatsLocked()1221     private void writeNetworkDevStatsLocked() {
1222         if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()");
1223         writeNetworkStats(mNetworkDevStats, mNetworkDevFile);
1224     }
1225 
writeNetworkXtStatsLocked()1226     private void writeNetworkXtStatsLocked() {
1227         if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()");
1228         writeNetworkStats(mNetworkXtStats, mNetworkXtFile);
1229     }
1230 
writeNetworkStats( HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile)1231     private void writeNetworkStats(
1232             HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile) {
1233         // TODO: consider duplicating stats and releasing lock while writing
1234 
1235         // trim any history beyond max
1236         if (mTime.hasCache()) {
1237             final long currentTime = mTime.currentTimeMillis();
1238             final long maxHistory = mSettings.getNetworkMaxHistory();
1239             for (NetworkStatsHistory history : input.values()) {
1240                 history.removeBucketsBefore(currentTime - maxHistory);
1241             }
1242         }
1243 
1244         FileOutputStream fos = null;
1245         try {
1246             fos = outputFile.startWrite();
1247             final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
1248 
1249             out.writeInt(FILE_MAGIC);
1250             out.writeInt(VERSION_NETWORK_INIT);
1251 
1252             out.writeInt(input.size());
1253             for (NetworkIdentitySet ident : input.keySet()) {
1254                 final NetworkStatsHistory history = input.get(ident);
1255                 ident.writeToStream(out);
1256                 history.writeToStream(out);
1257             }
1258 
1259             out.flush();
1260             outputFile.finishWrite(fos);
1261         } catch (IOException e) {
1262             Log.wtf(TAG, "problem writing stats", e);
1263             if (fos != null) {
1264                 outputFile.failWrite(fos);
1265             }
1266         }
1267     }
1268 
writeUidStatsLocked()1269     private void writeUidStatsLocked() {
1270         if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
1271 
1272         if (!mUidStatsLoaded) {
1273             Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
1274             return;
1275         }
1276 
1277         // TODO: consider duplicating stats and releasing lock while writing
1278 
1279         // trim any history beyond max
1280         if (mTime.hasCache()) {
1281             final long currentTime = mTime.currentTimeMillis();
1282             final long maxUidHistory = mSettings.getUidMaxHistory();
1283             final long maxTagHistory = mSettings.getTagMaxHistory();
1284             for (UidStatsKey key : mUidStats.keySet()) {
1285                 final NetworkStatsHistory history = mUidStats.get(key);
1286 
1287                 // detailed tags are trimmed sooner than summary in TAG_NONE
1288                 if (key.tag == TAG_NONE) {
1289                     history.removeBucketsBefore(currentTime - maxUidHistory);
1290                 } else {
1291                     history.removeBucketsBefore(currentTime - maxTagHistory);
1292                 }
1293             }
1294         }
1295 
1296         // build UidStatsKey lists grouped by ident
1297         final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
1298         for (UidStatsKey key : mUidStats.keySet()) {
1299             ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
1300             if (keys == null) {
1301                 keys = Lists.newArrayList();
1302                 keysByIdent.put(key.ident, keys);
1303             }
1304             keys.add(key);
1305         }
1306 
1307         FileOutputStream fos = null;
1308         try {
1309             fos = mUidFile.startWrite();
1310             final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
1311 
1312             out.writeInt(FILE_MAGIC);
1313             out.writeInt(VERSION_UID_WITH_SET);
1314 
1315             out.writeInt(keysByIdent.size());
1316             for (NetworkIdentitySet ident : keysByIdent.keySet()) {
1317                 final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
1318                 ident.writeToStream(out);
1319 
1320                 out.writeInt(keys.size());
1321                 for (UidStatsKey key : keys) {
1322                     final NetworkStatsHistory history = mUidStats.get(key);
1323                     out.writeInt(key.uid);
1324                     out.writeInt(key.set);
1325                     out.writeInt(key.tag);
1326                     history.writeToStream(out);
1327                 }
1328             }
1329 
1330             out.flush();
1331             mUidFile.finishWrite(fos);
1332         } catch (IOException e) {
1333             Log.wtf(TAG, "problem writing stats", e);
1334             if (fos != null) {
1335                 mUidFile.failWrite(fos);
1336             }
1337         }
1338     }
1339 
1340     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1341     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1342         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1343 
1344         final HashSet<String> argSet = new HashSet<String>();
1345         for (String arg : args) {
1346             argSet.add(arg);
1347         }
1348 
1349         final boolean fullHistory = argSet.contains("full");
1350 
1351         synchronized (mStatsLock) {
1352             // TODO: remove this testing code, since it corrupts stats
1353             if (argSet.contains("generate")) {
1354                 generateRandomLocked(args);
1355                 pw.println("Generated stub stats");
1356                 return;
1357             }
1358 
1359             if (argSet.contains("poll")) {
1360                 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
1361                 pw.println("Forced poll");
1362                 return;
1363             }
1364 
1365             pw.println("Active interfaces:");
1366             for (String iface : mActiveIfaces.keySet()) {
1367                 final NetworkIdentitySet ident = mActiveIfaces.get(iface);
1368                 pw.print("  iface="); pw.print(iface);
1369                 pw.print(" ident="); pw.println(ident.toString());
1370             }
1371 
1372             pw.println("Known historical dev stats:");
1373             for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) {
1374                 final NetworkStatsHistory history = mNetworkDevStats.get(ident);
1375                 pw.print("  ident="); pw.println(ident.toString());
1376                 history.dump("  ", pw, fullHistory);
1377             }
1378 
1379             pw.println("Known historical xt stats:");
1380             for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) {
1381                 final NetworkStatsHistory history = mNetworkXtStats.get(ident);
1382                 pw.print("  ident="); pw.println(ident.toString());
1383                 history.dump("  ", pw, fullHistory);
1384             }
1385 
1386             if (argSet.contains("detail")) {
1387                 // since explicitly requested with argument, we're okay to load
1388                 // from disk if not already in memory.
1389                 ensureUidStatsLoadedLocked();
1390 
1391                 final ArrayList<UidStatsKey> keys = Lists.newArrayList();
1392                 keys.addAll(mUidStats.keySet());
1393                 Collections.sort(keys);
1394 
1395                 pw.println("Detailed UID stats:");
1396                 for (UidStatsKey key : keys) {
1397                     pw.print("  ident="); pw.print(key.ident.toString());
1398                     pw.print(" uid="); pw.print(key.uid);
1399                     pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
1400                     pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
1401 
1402                     final NetworkStatsHistory history = mUidStats.get(key);
1403                     history.dump("    ", pw, fullHistory);
1404                 }
1405             }
1406         }
1407     }
1408 
1409     /**
1410      * @deprecated only for temporary testing
1411      */
1412     @Deprecated
generateRandomLocked(String[] args)1413     private void generateRandomLocked(String[] args) {
1414         final long totalBytes = Long.parseLong(args[1]);
1415         final long totalTime = Long.parseLong(args[2]);
1416 
1417         final PackageManager pm = mContext.getPackageManager();
1418         final ArrayList<Integer> specialUidList = Lists.newArrayList();
1419         for (int i = 3; i < args.length; i++) {
1420             try {
1421                 specialUidList.add(pm.getApplicationInfo(args[i], 0).uid);
1422             } catch (NameNotFoundException e) {
1423                 throw new RuntimeException(e);
1424             }
1425         }
1426 
1427         final HashSet<Integer> otherUidSet = Sets.newHashSet();
1428         for (ApplicationInfo info : pm.getInstalledApplications(0)) {
1429             if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName)
1430                     == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) {
1431                 otherUidSet.add(info.uid);
1432             }
1433         }
1434 
1435         final ArrayList<Integer> otherUidList = new ArrayList<Integer>(otherUidSet);
1436 
1437         final long end = System.currentTimeMillis();
1438         final long start = end - totalTime;
1439 
1440         mNetworkDevStats.clear();
1441         mNetworkXtStats.clear();
1442         mUidStats.clear();
1443 
1444         final Random r = new Random();
1445         for (NetworkIdentitySet ident : mActiveIfaces.values()) {
1446             final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident);
1447             final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident);
1448 
1449             final ArrayList<Integer> uidList = new ArrayList<Integer>();
1450             uidList.addAll(specialUidList);
1451 
1452             if (uidList.size() == 0) {
1453                 Collections.shuffle(otherUidList);
1454                 uidList.addAll(otherUidList);
1455             }
1456 
1457             boolean first = true;
1458             long remainingBytes = totalBytes;
1459             for (int uid : uidList) {
1460                 final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked(
1461                         ident, uid, SET_DEFAULT, TAG_NONE);
1462                 final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked(
1463                         ident, uid, SET_FOREGROUND, TAG_NONE);
1464 
1465                 final long uidBytes = totalBytes / uidList.size();
1466 
1467                 final float fractionDefault = r.nextFloat();
1468                 final long defaultBytes = (long) (uidBytes * fractionDefault);
1469                 final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault));
1470 
1471                 defaultHistory.generateRandom(start, end, defaultBytes);
1472                 foregroundHistory.generateRandom(start, end, foregroundBytes);
1473 
1474                 if (first) {
1475                     final long bumpTime = (start + end) / 2;
1476                     defaultHistory.recordData(
1477                             bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0);
1478                     first = false;
1479                 }
1480 
1481                 devHistory.recordEntireHistory(defaultHistory);
1482                 devHistory.recordEntireHistory(foregroundHistory);
1483                 xtHistory.recordEntireHistory(defaultHistory);
1484                 xtHistory.recordEntireHistory(foregroundHistory);
1485             }
1486         }
1487     }
1488 
1489     /**
1490      * Return the delta between two {@link NetworkStats} snapshots, where {@code
1491      * before} can be {@code null}.
1492      */
computeStatsDelta( NetworkStats before, NetworkStats current, boolean collectStale)1493     private static NetworkStats computeStatsDelta(
1494             NetworkStats before, NetworkStats current, boolean collectStale) {
1495         if (before != null) {
1496             return current.subtractClamped(before);
1497         } else if (collectStale) {
1498             // caller is okay collecting stale stats for first call.
1499             return current;
1500         } else {
1501             // this is first snapshot; to prevent from double-counting we only
1502             // observe traffic occuring between known snapshots.
1503             return new NetworkStats(0L, 10);
1504         }
1505     }
1506 
computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot)1507     private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
1508         return uidSnapshot.groupedByIface();
1509     }
1510 
estimateNetworkBuckets()1511     private int estimateNetworkBuckets() {
1512         return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
1513     }
1514 
estimateUidBuckets()1515     private int estimateUidBuckets() {
1516         return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
1517     }
1518 
estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration)1519     private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
1520         return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
1521     }
1522 
1523     /**
1524      * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
1525      * in the given {@link NetworkIdentitySet}.
1526      */
templateMatches(NetworkTemplate template, NetworkIdentitySet identSet)1527     private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
1528         for (NetworkIdentity ident : identSet) {
1529             if (template.matches(ident)) {
1530                 return true;
1531             }
1532         }
1533         return false;
1534     }
1535 
1536     private Handler.Callback mHandlerCallback = new Handler.Callback() {
1537         /** {@inheritDoc} */
1538         public boolean handleMessage(Message msg) {
1539             switch (msg.what) {
1540                 case MSG_PERFORM_POLL: {
1541                     final int flags = msg.arg1;
1542                     performPoll(flags);
1543                     return true;
1544                 }
1545                 case MSG_UPDATE_IFACES: {
1546                     updateIfaces();
1547                     return true;
1548                 }
1549                 default: {
1550                     return false;
1551                 }
1552             }
1553         }
1554     };
1555 
getActiveSubscriberId(Context context)1556     private static String getActiveSubscriberId(Context context) {
1557         final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
1558                 Context.TELEPHONY_SERVICE);
1559         return telephony.getSubscriberId();
1560     }
1561 
1562     /**
1563      * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
1564      */
1565     private static class UidStatsKey implements Comparable<UidStatsKey> {
1566         public final NetworkIdentitySet ident;
1567         public final int uid;
1568         public final int set;
1569         public final int tag;
1570 
UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag)1571         public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
1572             this.ident = ident;
1573             this.uid = uid;
1574             this.set = set;
1575             this.tag = tag;
1576         }
1577 
1578         @Override
hashCode()1579         public int hashCode() {
1580             return Objects.hashCode(ident, uid, set, tag);
1581         }
1582 
1583         @Override
equals(Object obj)1584         public boolean equals(Object obj) {
1585             if (obj instanceof UidStatsKey) {
1586                 final UidStatsKey key = (UidStatsKey) obj;
1587                 return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
1588                         && tag == key.tag;
1589             }
1590             return false;
1591         }
1592 
1593         /** {@inheritDoc} */
compareTo(UidStatsKey another)1594         public int compareTo(UidStatsKey another) {
1595             return Integer.compare(uid, another.uid);
1596         }
1597     }
1598 
1599     /**
1600      * Default external settings that read from {@link Settings.Secure}.
1601      */
1602     private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
1603         private final ContentResolver mResolver;
1604 
DefaultNetworkStatsSettings(Context context)1605         public DefaultNetworkStatsSettings(Context context) {
1606             mResolver = checkNotNull(context.getContentResolver());
1607             // TODO: adjust these timings for production builds
1608         }
1609 
getSecureLong(String name, long def)1610         private long getSecureLong(String name, long def) {
1611             return Settings.Secure.getLong(mResolver, name, def);
1612         }
getSecureBoolean(String name, boolean def)1613         private boolean getSecureBoolean(String name, boolean def) {
1614             final int defInt = def ? 1 : 0;
1615             return Settings.Secure.getInt(mResolver, name, defInt) != 0;
1616         }
1617 
getPollInterval()1618         public long getPollInterval() {
1619             return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
1620         }
getPersistThreshold()1621         public long getPersistThreshold() {
1622             return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
1623         }
getNetworkBucketDuration()1624         public long getNetworkBucketDuration() {
1625             return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
1626         }
getNetworkMaxHistory()1627         public long getNetworkMaxHistory() {
1628             return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
1629         }
getUidBucketDuration()1630         public long getUidBucketDuration() {
1631             return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
1632         }
getUidMaxHistory()1633         public long getUidMaxHistory() {
1634             return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
1635         }
getTagMaxHistory()1636         public long getTagMaxHistory() {
1637             return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
1638         }
getTimeCacheMaxAge()1639         public long getTimeCacheMaxAge() {
1640             return DAY_IN_MILLIS;
1641         }
1642     }
1643 }
1644