NetworkStatsService.java revision 92d141fbc2f6bfc85dca1056e40512cba6d1dddb
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
17package com.android.server.net;
18
19import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
21import static android.Manifest.permission.DUMP;
22import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
23import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
24import static android.content.Intent.ACTION_SHUTDOWN;
25import static android.content.Intent.ACTION_UID_REMOVED;
26import static android.content.Intent.ACTION_USER_REMOVED;
27import static android.content.Intent.EXTRA_UID;
28import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
29import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
30import static android.net.ConnectivityManager.isNetworkTypeMobile;
31import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
32import static android.net.NetworkStats.IFACE_ALL;
33import static android.net.NetworkStats.SET_ALL;
34import static android.net.NetworkStats.SET_DEFAULT;
35import static android.net.NetworkStats.SET_FOREGROUND;
36import static android.net.NetworkStats.TAG_NONE;
37import static android.net.NetworkStats.UID_ALL;
38import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
39import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
40import static android.net.TrafficStats.KB_IN_BYTES;
41import static android.net.TrafficStats.MB_IN_BYTES;
42import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION;
43import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE;
44import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES;
45import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE;
46import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES;
47import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL;
48import static android.provider.Settings.Global.NETSTATS_REPORT_XT_OVER_DEV;
49import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED;
50import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE;
51import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
52import static android.provider.Settings.Global.NETSTATS_UID_DELETE_AGE;
53import static android.provider.Settings.Global.NETSTATS_UID_PERSIST_BYTES;
54import static android.provider.Settings.Global.NETSTATS_UID_ROTATE_AGE;
55import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION;
56import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
57import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
58import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
59import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
60import static android.telephony.PhoneStateListener.LISTEN_NONE;
61import static android.text.format.DateUtils.DAY_IN_MILLIS;
62import static android.text.format.DateUtils.HOUR_IN_MILLIS;
63import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
64import static android.text.format.DateUtils.SECOND_IN_MILLIS;
65import static com.android.internal.util.Preconditions.checkNotNull;
66import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
67import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
68import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
69
70import android.app.AlarmManager;
71import android.app.IAlarmManager;
72import android.app.PendingIntent;
73import android.content.BroadcastReceiver;
74import android.content.ContentResolver;
75import android.content.Context;
76import android.content.Intent;
77import android.content.IntentFilter;
78import android.content.pm.ApplicationInfo;
79import android.content.pm.PackageManager;
80import android.net.IConnectivityManager;
81import android.net.INetworkManagementEventObserver;
82import android.net.INetworkStatsService;
83import android.net.INetworkStatsSession;
84import android.net.LinkProperties;
85import android.net.NetworkIdentity;
86import android.net.NetworkInfo;
87import android.net.NetworkState;
88import android.net.NetworkStats;
89import android.net.NetworkStats.NonMonotonicObserver;
90import android.net.NetworkStatsHistory;
91import android.net.NetworkTemplate;
92import android.net.TrafficStats;
93import android.os.Binder;
94import android.os.DropBoxManager;
95import android.os.Environment;
96import android.os.Handler;
97import android.os.HandlerThread;
98import android.os.INetworkManagementService;
99import android.os.Message;
100import android.os.PowerManager;
101import android.os.RemoteException;
102import android.os.SystemClock;
103import android.os.UserHandle;
104import android.provider.Settings;
105import android.provider.Settings.Global;
106import android.telephony.PhoneStateListener;
107import android.telephony.TelephonyManager;
108import android.util.ArrayMap;
109import android.util.ArraySet;
110import android.util.EventLog;
111import android.util.Log;
112import android.util.MathUtils;
113import android.util.NtpTrustedTime;
114import android.util.Slog;
115import android.util.SparseIntArray;
116import android.util.TrustedTime;
117
118import com.android.internal.annotations.VisibleForTesting;
119import com.android.internal.util.ArrayUtils;
120import com.android.internal.util.FileRotator;
121import com.android.internal.util.IndentingPrintWriter;
122import com.android.server.EventLogTags;
123import com.android.server.connectivity.Tethering;
124
125import java.io.File;
126import java.io.FileDescriptor;
127import java.io.IOException;
128import java.io.PrintWriter;
129import java.util.Arrays;
130import java.util.HashSet;
131import java.util.List;
132
133/**
134 * Collect and persist detailed network statistics, and provide this data to
135 * other system services.
136 */
137public class NetworkStatsService extends INetworkStatsService.Stub {
138    private static final String TAG = "NetworkStats";
139    private static final boolean LOGV = false;
140
141    private static final int MSG_PERFORM_POLL = 1;
142    private static final int MSG_UPDATE_IFACES = 2;
143    private static final int MSG_REGISTER_GLOBAL_ALERT = 3;
144
145    /** Flags to control detail level of poll event. */
146    private static final int FLAG_PERSIST_NETWORK = 0x1;
147    private static final int FLAG_PERSIST_UID = 0x2;
148    private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
149    private static final int FLAG_PERSIST_FORCE = 0x100;
150
151    private static final String TAG_NETSTATS_ERROR = "netstats_error";
152
153    private final Context mContext;
154    private final INetworkManagementService mNetworkManager;
155    private final AlarmManager mAlarmManager;
156    private final TrustedTime mTime;
157    private final TelephonyManager mTeleManager;
158    private final NetworkStatsSettings mSettings;
159
160    private final File mSystemDir;
161    private final File mBaseDir;
162
163    private final PowerManager.WakeLock mWakeLock;
164
165    private IConnectivityManager mConnManager;
166
167    @VisibleForTesting
168    public static final String ACTION_NETWORK_STATS_POLL =
169            "com.android.server.action.NETWORK_STATS_POLL";
170    public static final String ACTION_NETWORK_STATS_UPDATED =
171            "com.android.server.action.NETWORK_STATS_UPDATED";
172
173    private PendingIntent mPollIntent;
174
175    private static final String PREFIX_DEV = "dev";
176    private static final String PREFIX_XT = "xt";
177    private static final String PREFIX_UID = "uid";
178    private static final String PREFIX_UID_TAG = "uid_tag";
179
180    /**
181     * Settings that can be changed externally.
182     */
183    public interface NetworkStatsSettings {
184        public long getPollInterval();
185        public long getTimeCacheMaxAge();
186        public boolean getSampleEnabled();
187        public boolean getReportXtOverDev();
188
189        public static class Config {
190            public final long bucketDuration;
191            public final long rotateAgeMillis;
192            public final long deleteAgeMillis;
193
194            public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) {
195                this.bucketDuration = bucketDuration;
196                this.rotateAgeMillis = rotateAgeMillis;
197                this.deleteAgeMillis = deleteAgeMillis;
198            }
199        }
200
201        public Config getDevConfig();
202        public Config getXtConfig();
203        public Config getUidConfig();
204        public Config getUidTagConfig();
205
206        public long getGlobalAlertBytes(long def);
207        public long getDevPersistBytes(long def);
208        public long getXtPersistBytes(long def);
209        public long getUidPersistBytes(long def);
210        public long getUidTagPersistBytes(long def);
211    }
212
213    private final Object mStatsLock = new Object();
214
215    /** Set of currently active ifaces. */
216    private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>();
217    /** Set of currently active ifaces for UID stats. */
218    private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>();
219    /** Current default active iface. */
220    private String mActiveIface;
221    /** Set of any ifaces associated with mobile networks since boot. */
222    private String[] mMobileIfaces = new String[0];
223
224    private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
225            new DropBoxNonMonotonicObserver();
226
227    private NetworkStatsRecorder mDevRecorder;
228    private NetworkStatsRecorder mXtRecorder;
229    private NetworkStatsRecorder mUidRecorder;
230    private NetworkStatsRecorder mUidTagRecorder;
231
232    /** Cached {@link #mDevRecorder} stats. */
233    private NetworkStatsCollection mDevStatsCached;
234    /** Cached {@link #mXtRecorder} stats. */
235    private NetworkStatsCollection mXtStatsCached;
236
237    /** Current counter sets for each UID. */
238    private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
239
240    /** Data layer operation counters for splicing into other structures. */
241    private NetworkStats mUidOperations = new NetworkStats(0L, 10);
242
243    private final Handler mHandler;
244
245    private boolean mSystemReady;
246    private long mPersistThreshold = 2 * MB_IN_BYTES;
247    private long mGlobalAlertBytes;
248
249    public NetworkStatsService(
250            Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
251        this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
252                getDefaultSystemDir(), new DefaultNetworkStatsSettings(context));
253    }
254
255    private static File getDefaultSystemDir() {
256        return new File(Environment.getDataDirectory(), "system");
257    }
258
259    public NetworkStatsService(Context context, INetworkManagementService networkManager,
260            IAlarmManager alarmManager, TrustedTime time, File systemDir,
261            NetworkStatsSettings settings) {
262        mContext = checkNotNull(context, "missing Context");
263        mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
264        mTime = checkNotNull(time, "missing TrustedTime");
265        mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
266        mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
267        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
268
269        final PowerManager powerManager = (PowerManager) context.getSystemService(
270                Context.POWER_SERVICE);
271        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
272
273        HandlerThread thread = new HandlerThread(TAG);
274        thread.start();
275        mHandler = new Handler(thread.getLooper(), mHandlerCallback);
276
277        mSystemDir = checkNotNull(systemDir);
278        mBaseDir = new File(systemDir, "netstats");
279        mBaseDir.mkdirs();
280    }
281
282    public void bindConnectivityManager(IConnectivityManager connManager) {
283        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
284    }
285
286    public void systemReady() {
287        mSystemReady = true;
288
289        if (!isBandwidthControlEnabled()) {
290            Slog.w(TAG, "bandwidth controls disabled, unable to track stats");
291            return;
292        }
293
294        // create data recorders along with historical rotators
295        mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
296        mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false);
297        mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
298        mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
299
300        updatePersistThresholds();
301
302        synchronized (mStatsLock) {
303            // upgrade any legacy stats, migrating them to rotated files
304            maybeUpgradeLegacyStatsLocked();
305
306            // read historical network stats from disk, since policy service
307            // might need them right away.
308            mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked();
309            mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked();
310
311            // bootstrap initial stats to prevent double-counting later
312            bootstrapStatsLocked();
313        }
314
315        // watch for network interfaces to be claimed
316        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
317        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
318
319        // watch for tethering changes
320        final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
321        mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler);
322
323        // listen for periodic polling events
324        final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
325        mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
326
327        // listen for uid removal to clean stats
328        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
329        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
330
331        // listen for user changes to clean stats
332        final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED);
333        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
334
335        // persist stats during clean shutdown
336        final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
337        mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
338
339        try {
340            mNetworkManager.registerObserver(mAlertObserver);
341        } catch (RemoteException e) {
342            // ignored; service lives in system_server
343        }
344
345        // watch for networkType changes that aren't broadcast through
346        // CONNECTIVITY_ACTION_IMMEDIATE above.
347        if (!COMBINE_SUBTYPE_ENABLED) {
348            mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE);
349        }
350
351        registerPollAlarmLocked();
352        registerGlobalAlert();
353    }
354
355    private NetworkStatsRecorder buildRecorder(
356            String prefix, NetworkStatsSettings.Config config, boolean includeTags) {
357        final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
358                Context.DROPBOX_SERVICE);
359        return new NetworkStatsRecorder(new FileRotator(
360                mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
361                mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags);
362    }
363
364    private void shutdownLocked() {
365        mContext.unregisterReceiver(mConnReceiver);
366        mContext.unregisterReceiver(mTetherReceiver);
367        mContext.unregisterReceiver(mPollReceiver);
368        mContext.unregisterReceiver(mRemovedReceiver);
369        mContext.unregisterReceiver(mShutdownReceiver);
370
371        if (!COMBINE_SUBTYPE_ENABLED) {
372            mTeleManager.listen(mPhoneListener, LISTEN_NONE);
373        }
374
375        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
376                : System.currentTimeMillis();
377
378        // persist any pending stats
379        mDevRecorder.forcePersistLocked(currentTime);
380        mXtRecorder.forcePersistLocked(currentTime);
381        mUidRecorder.forcePersistLocked(currentTime);
382        mUidTagRecorder.forcePersistLocked(currentTime);
383
384        mDevRecorder = null;
385        mXtRecorder = null;
386        mUidRecorder = null;
387        mUidTagRecorder = null;
388
389        mDevStatsCached = null;
390        mXtStatsCached = null;
391
392        mSystemReady = false;
393    }
394
395    private void maybeUpgradeLegacyStatsLocked() {
396        File file;
397        try {
398            file = new File(mSystemDir, "netstats.bin");
399            if (file.exists()) {
400                mDevRecorder.importLegacyNetworkLocked(file);
401                file.delete();
402            }
403
404            file = new File(mSystemDir, "netstats_xt.bin");
405            if (file.exists()) {
406                file.delete();
407            }
408
409            file = new File(mSystemDir, "netstats_uid.bin");
410            if (file.exists()) {
411                mUidRecorder.importLegacyUidLocked(file);
412                mUidTagRecorder.importLegacyUidLocked(file);
413                file.delete();
414            }
415        } catch (IOException e) {
416            Log.wtf(TAG, "problem during legacy upgrade", e);
417        } catch (OutOfMemoryError e) {
418            Log.wtf(TAG, "problem during legacy upgrade", e);
419        }
420    }
421
422    /**
423     * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
424     * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
425     */
426    private void registerPollAlarmLocked() {
427        if (mPollIntent != null) {
428            mAlarmManager.cancel(mPollIntent);
429        }
430
431        mPollIntent = PendingIntent.getBroadcast(
432                mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
433
434        final long currentRealtime = SystemClock.elapsedRealtime();
435        mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
436                mSettings.getPollInterval(), mPollIntent);
437    }
438
439    /**
440     * Register for a global alert that is delivered through
441     * {@link INetworkManagementEventObserver} once a threshold amount of data
442     * has been transferred.
443     */
444    private void registerGlobalAlert() {
445        try {
446            mNetworkManager.setGlobalAlert(mGlobalAlertBytes);
447        } catch (IllegalStateException e) {
448            Slog.w(TAG, "problem registering for global alert: " + e);
449        } catch (RemoteException e) {
450            // ignored; service lives in system_server
451        }
452    }
453
454    @Override
455    public INetworkStatsSession openSession() {
456        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
457        assertBandwidthControlEnabled();
458
459        // return an IBinder which holds strong references to any loaded stats
460        // for its lifetime; when caller closes only weak references remain.
461
462        return new INetworkStatsSession.Stub() {
463            private NetworkStatsCollection mUidComplete;
464            private NetworkStatsCollection mUidTagComplete;
465
466            private NetworkStatsCollection getUidComplete() {
467                synchronized (mStatsLock) {
468                    if (mUidComplete == null) {
469                        mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
470                    }
471                    return mUidComplete;
472                }
473            }
474
475            private NetworkStatsCollection getUidTagComplete() {
476                synchronized (mStatsLock) {
477                    if (mUidTagComplete == null) {
478                        mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
479                    }
480                    return mUidTagComplete;
481                }
482            }
483
484            @Override
485            public NetworkStats getSummaryForNetwork(
486                    NetworkTemplate template, long start, long end) {
487                return internalGetSummaryForNetwork(template, start, end);
488            }
489
490            @Override
491            public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
492                return internalGetHistoryForNetwork(template, fields);
493            }
494
495            @Override
496            public NetworkStats getSummaryForAllUid(
497                    NetworkTemplate template, long start, long end, boolean includeTags) {
498                final NetworkStats stats = getUidComplete().getSummary(template, start, end);
499                if (includeTags) {
500                    final NetworkStats tagStats = getUidTagComplete()
501                            .getSummary(template, start, end);
502                    stats.combineAllValues(tagStats);
503                }
504                return stats;
505            }
506
507            @Override
508            public NetworkStatsHistory getHistoryForUid(
509                    NetworkTemplate template, int uid, int set, int tag, int fields) {
510                if (tag == TAG_NONE) {
511                    return getUidComplete().getHistory(template, uid, set, tag, fields);
512                } else {
513                    return getUidTagComplete().getHistory(template, uid, set, tag, fields);
514                }
515            }
516
517            @Override
518            public void close() {
519                mUidComplete = null;
520                mUidTagComplete = null;
521            }
522        };
523    }
524
525    /**
526     * Return network summary, splicing between {@link #mDevStatsCached}
527     * and {@link #mXtStatsCached} when appropriate.
528     */
529    private NetworkStats internalGetSummaryForNetwork(
530            NetworkTemplate template, long start, long end) {
531        if (!mSettings.getReportXtOverDev()) {
532            // shortcut when XT reporting disabled
533            return mDevStatsCached.getSummary(template, start, end);
534        }
535
536        // splice stats between DEV and XT, switching over from DEV to XT at
537        // first atomic bucket.
538        final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
539        final NetworkStats dev = mDevStatsCached.getSummary(
540                template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket));
541        final NetworkStats xt = mXtStatsCached.getSummary(
542                template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket));
543
544        xt.combineAllValues(dev);
545        return xt;
546    }
547
548    /**
549     * Return network history, splicing between {@link #mDevStatsCached}
550     * and {@link #mXtStatsCached} when appropriate.
551     */
552    private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) {
553        if (!mSettings.getReportXtOverDev()) {
554            // shortcut when XT reporting disabled
555            return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
556        }
557
558        // splice stats between DEV and XT, switching over from DEV to XT at
559        // first atomic bucket.
560        final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
561        final NetworkStatsHistory dev = mDevStatsCached.getHistory(
562                template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket);
563        final NetworkStatsHistory xt = mXtStatsCached.getHistory(
564                template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE);
565
566        xt.recordEntireHistory(dev);
567        return xt;
568    }
569
570    @Override
571    public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
572        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
573        assertBandwidthControlEnabled();
574        return internalGetSummaryForNetwork(template, start, end).getTotalBytes();
575    }
576
577    @Override
578    public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
579        if (Binder.getCallingUid() != uid) {
580            mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
581        }
582        assertBandwidthControlEnabled();
583
584        // TODO: switch to data layer stats once kernel exports
585        // for now, read network layer stats and flatten across all ifaces
586        final long token = Binder.clearCallingIdentity();
587        final NetworkStats networkLayer;
588        try {
589            networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
590        } finally {
591            Binder.restoreCallingIdentity(token);
592        }
593
594        // splice in operation counts
595        networkLayer.spliceOperationsFrom(mUidOperations);
596
597        final NetworkStats dataLayer = new NetworkStats(
598                networkLayer.getElapsedRealtime(), networkLayer.size());
599
600        NetworkStats.Entry entry = null;
601        for (int i = 0; i < networkLayer.size(); i++) {
602            entry = networkLayer.getValues(i, entry);
603            entry.iface = IFACE_ALL;
604            dataLayer.combineValues(entry);
605        }
606
607        return dataLayer;
608    }
609
610    @Override
611    public String[] getMobileIfaces() {
612        return mMobileIfaces;
613    }
614
615    @Override
616    public void incrementOperationCount(int uid, int tag, int operationCount) {
617        if (Binder.getCallingUid() != uid) {
618            mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
619        }
620
621        if (operationCount < 0) {
622            throw new IllegalArgumentException("operation count can only be incremented");
623        }
624        if (tag == TAG_NONE) {
625            throw new IllegalArgumentException("operation count must have specific tag");
626        }
627
628        synchronized (mStatsLock) {
629            final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
630            mUidOperations.combineValues(
631                    mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
632            mUidOperations.combineValues(
633                    mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
634        }
635    }
636
637    @Override
638    public void setUidForeground(int uid, boolean uidForeground) {
639        mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
640
641        synchronized (mStatsLock) {
642            final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
643            final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
644            if (oldSet != set) {
645                mActiveUidCounterSet.put(uid, set);
646                setKernelCounterSet(uid, set);
647            }
648        }
649    }
650
651    @Override
652    public void forceUpdate() {
653        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
654        assertBandwidthControlEnabled();
655
656        final long token = Binder.clearCallingIdentity();
657        try {
658            performPoll(FLAG_PERSIST_ALL);
659        } finally {
660            Binder.restoreCallingIdentity(token);
661        }
662    }
663
664    @Override
665    public void advisePersistThreshold(long thresholdBytes) {
666        mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
667        assertBandwidthControlEnabled();
668
669        // clamp threshold into safe range
670        mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
671        if (LOGV) {
672            Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
673                    + mPersistThreshold);
674        }
675
676        // update and persist if beyond new thresholds
677        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
678                : System.currentTimeMillis();
679        synchronized (mStatsLock) {
680            if (!mSystemReady) return;
681
682            updatePersistThresholds();
683
684            mDevRecorder.maybePersistLocked(currentTime);
685            mXtRecorder.maybePersistLocked(currentTime);
686            mUidRecorder.maybePersistLocked(currentTime);
687            mUidTagRecorder.maybePersistLocked(currentTime);
688        }
689
690        // re-arm global alert
691        registerGlobalAlert();
692    }
693
694    /**
695     * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
696     * reflect current {@link #mPersistThreshold} value. Always defers to
697     * {@link Global} values when defined.
698     */
699    private void updatePersistThresholds() {
700        mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold));
701        mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold));
702        mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold));
703        mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold));
704        mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold);
705    }
706
707    /**
708     * Receiver that watches for {@link IConnectivityManager} to claim network
709     * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
710     * with mobile interfaces.
711     */
712    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
713        @Override
714        public void onReceive(Context context, Intent intent) {
715            // on background handler thread, and verified CONNECTIVITY_INTERNAL
716            // permission above.
717            updateIfaces();
718        }
719    };
720
721    /**
722     * Receiver that watches for {@link Tethering} to claim interface pairs.
723     */
724    private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
725        @Override
726        public void onReceive(Context context, Intent intent) {
727            // on background handler thread, and verified CONNECTIVITY_INTERNAL
728            // permission above.
729            performPoll(FLAG_PERSIST_NETWORK);
730        }
731    };
732
733    private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
734        @Override
735        public void onReceive(Context context, Intent intent) {
736            // on background handler thread, and verified UPDATE_DEVICE_STATS
737            // permission above.
738            performPoll(FLAG_PERSIST_ALL);
739
740            // verify that we're watching global alert
741            registerGlobalAlert();
742        }
743    };
744
745    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
746        @Override
747        public void onReceive(Context context, Intent intent) {
748            // on background handler thread, and UID_REMOVED is protected
749            // broadcast.
750
751            final int uid = intent.getIntExtra(EXTRA_UID, -1);
752            if (uid == -1) return;
753
754            synchronized (mStatsLock) {
755                mWakeLock.acquire();
756                try {
757                    removeUidsLocked(uid);
758                } finally {
759                    mWakeLock.release();
760                }
761            }
762        }
763    };
764
765    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
766        @Override
767        public void onReceive(Context context, Intent intent) {
768            // On background handler thread, and USER_REMOVED is protected
769            // broadcast.
770
771            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
772            if (userId == -1) return;
773
774            synchronized (mStatsLock) {
775                mWakeLock.acquire();
776                try {
777                    removeUserLocked(userId);
778                } finally {
779                    mWakeLock.release();
780                }
781            }
782        }
783    };
784
785    private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
786        @Override
787        public void onReceive(Context context, Intent intent) {
788            // SHUTDOWN is protected broadcast.
789            synchronized (mStatsLock) {
790                shutdownLocked();
791            }
792        }
793    };
794
795    /**
796     * Observer that watches for {@link INetworkManagementService} alerts.
797     */
798    private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() {
799        @Override
800        public void limitReached(String limitName, String iface) {
801            // only someone like NMS should be calling us
802            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
803
804            if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
805                // kick off background poll to collect network stats; UID stats
806                // are handled during normal polling interval.
807                final int flags = FLAG_PERSIST_NETWORK;
808                mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
809
810                // re-arm global alert for next update
811                mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget();
812            }
813        }
814    };
815
816    private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN;
817    private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
818
819    /**
820     * Receiver that watches for {@link TelephonyManager} changes, such as
821     * transitioning between network types.
822     */
823    private PhoneStateListener mPhoneListener = new PhoneStateListener() {
824        @Override
825        public void onDataConnectionStateChanged(int state, int networkType) {
826            final boolean stateChanged = state != mLastPhoneState;
827            final boolean networkTypeChanged = networkType != mLastPhoneNetworkType;
828
829            if (networkTypeChanged && !stateChanged) {
830                // networkType changed without a state change, which means we
831                // need to roll our own update. delay long enough for
832                // ConnectivityManager to process.
833                // TODO: add direct event to ConnectivityService instead of
834                // relying on this delay.
835                if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()");
836                mHandler.sendMessageDelayed(
837                        mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);
838            }
839
840            mLastPhoneState = state;
841            mLastPhoneNetworkType = networkType;
842        }
843    };
844
845    private void updateIfaces() {
846        synchronized (mStatsLock) {
847            mWakeLock.acquire();
848            try {
849                updateIfacesLocked();
850            } finally {
851                mWakeLock.release();
852            }
853        }
854    }
855
856    /**
857     * Inspect all current {@link NetworkState} to derive mapping from {@code
858     * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
859     * are active on a single {@code iface}, they are combined under a single
860     * {@link NetworkIdentitySet}.
861     */
862    private void updateIfacesLocked() {
863        if (!mSystemReady) return;
864        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
865
866        // take one last stats snapshot before updating iface mapping. this
867        // isn't perfect, since the kernel may already be counting traffic from
868        // the updated network.
869
870        // poll, but only persist network stats to keep codepath fast. UID stats
871        // will be persisted during next alarm poll event.
872        performPollLocked(FLAG_PERSIST_NETWORK);
873
874        final NetworkState[] states;
875        final LinkProperties activeLink;
876        try {
877            states = mConnManager.getAllNetworkState();
878            activeLink = mConnManager.getActiveLinkProperties();
879        } catch (RemoteException e) {
880            // ignored; service lives in system_server
881            return;
882        }
883
884        mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null;
885
886        // Rebuild active interfaces based on connected networks
887        mActiveIfaces.clear();
888        mActiveUidIfaces.clear();
889
890        final ArraySet<String> mobileIfaces = new ArraySet<>();
891        for (NetworkState state : states) {
892            if (state.networkInfo.isConnected()) {
893                final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
894                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
895
896                // Traffic occurring on the base interface is always counted for
897                // both total usage and UID details.
898                final String baseIface = state.linkProperties.getInterfaceName();
899                if (baseIface != null) {
900                    findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
901                    findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
902                    if (isMobile) {
903                        mobileIfaces.add(baseIface);
904                    }
905                }
906
907                // Traffic occurring on stacked interfaces is usually clatd,
908                // which is already accounted against its final egress interface
909                // by the kernel. Thus, we only need to collect stacked
910                // interface stats at the UID level.
911                final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
912                for (LinkProperties stackedLink : stackedLinks) {
913                    final String stackedIface = stackedLink.getInterfaceName();
914                    if (stackedIface != null) {
915                        findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
916                        if (isMobile) {
917                            mobileIfaces.add(stackedIface);
918                        }
919                    }
920                }
921            }
922        }
923
924        mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
925    }
926
927    private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet(
928            ArrayMap<K, NetworkIdentitySet> map, K key) {
929        NetworkIdentitySet ident = map.get(key);
930        if (ident == null) {
931            ident = new NetworkIdentitySet();
932            map.put(key, ident);
933        }
934        return ident;
935    }
936
937    /**
938     * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
939     * so we have baseline values without double-counting.
940     */
941    private void bootstrapStatsLocked() {
942        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
943                : System.currentTimeMillis();
944
945        try {
946            // snapshot and record current counters; read UID stats first to
947            // avoid overcounting dev stats.
948            final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
949            final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
950            final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
951
952            mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
953            mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
954            mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
955            mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
956
957        } catch (IllegalStateException e) {
958            Slog.w(TAG, "problem reading network stats: " + e);
959        } catch (RemoteException e) {
960            // ignored; service lives in system_server
961        }
962    }
963
964    private void performPoll(int flags) {
965        // try refreshing time source when stale
966        if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
967            mTime.forceRefresh();
968        }
969
970        synchronized (mStatsLock) {
971            mWakeLock.acquire();
972
973            try {
974                performPollLocked(flags);
975            } finally {
976                mWakeLock.release();
977            }
978        }
979    }
980
981    /**
982     * Periodic poll operation, reading current statistics and recording into
983     * {@link NetworkStatsHistory}.
984     */
985    private void performPollLocked(int flags) {
986        if (!mSystemReady) return;
987        if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
988
989        final long startRealtime = SystemClock.elapsedRealtime();
990
991        final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
992        final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
993        final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
994
995        // TODO: consider marking "untrusted" times in historical stats
996        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
997                : System.currentTimeMillis();
998
999        try {
1000            // snapshot and record current counters; read UID stats first to
1001            // avoid overcounting dev stats.
1002            final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
1003            final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
1004            final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
1005
1006            mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
1007            mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
1008            mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
1009            mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
1010
1011        } catch (IllegalStateException e) {
1012            Log.wtf(TAG, "problem reading network stats", e);
1013            return;
1014        } catch (RemoteException e) {
1015            // ignored; service lives in system_server
1016            return;
1017        }
1018
1019        // persist any pending data depending on requested flags
1020        if (persistForce) {
1021            mDevRecorder.forcePersistLocked(currentTime);
1022            mXtRecorder.forcePersistLocked(currentTime);
1023            mUidRecorder.forcePersistLocked(currentTime);
1024            mUidTagRecorder.forcePersistLocked(currentTime);
1025        } else {
1026            if (persistNetwork) {
1027                mDevRecorder.maybePersistLocked(currentTime);
1028                mXtRecorder.maybePersistLocked(currentTime);
1029            }
1030            if (persistUid) {
1031                mUidRecorder.maybePersistLocked(currentTime);
1032                mUidTagRecorder.maybePersistLocked(currentTime);
1033            }
1034        }
1035
1036        if (LOGV) {
1037            final long duration = SystemClock.elapsedRealtime() - startRealtime;
1038            Slog.v(TAG, "performPollLocked() took " + duration + "ms");
1039        }
1040
1041        if (mSettings.getSampleEnabled()) {
1042            // sample stats after each full poll
1043            performSampleLocked();
1044        }
1045
1046        // finally, dispatch updated event to any listeners
1047        final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
1048        updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
1049        mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
1050                READ_NETWORK_USAGE_HISTORY);
1051    }
1052
1053    /**
1054     * Sample recent statistics summary into {@link EventLog}.
1055     */
1056    private void performSampleLocked() {
1057        // TODO: migrate trustedtime fixes to separate binary log events
1058        final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
1059
1060        NetworkTemplate template;
1061        NetworkStats.Entry devTotal;
1062        NetworkStats.Entry xtTotal;
1063        NetworkStats.Entry uidTotal;
1064
1065        // collect mobile sample
1066        template = buildTemplateMobileWildcard();
1067        devTotal = mDevRecorder.getTotalSinceBootLocked(template);
1068        xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
1069        uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
1070
1071        EventLogTags.writeNetstatsMobileSample(
1072                devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1073                xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1074                uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
1075                trustedTime);
1076
1077        // collect wifi sample
1078        template = buildTemplateWifiWildcard();
1079        devTotal = mDevRecorder.getTotalSinceBootLocked(template);
1080        xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
1081        uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
1082
1083        EventLogTags.writeNetstatsWifiSample(
1084                devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1085                xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1086                uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
1087                trustedTime);
1088    }
1089
1090    /**
1091     * Clean up {@link #mUidRecorder} after UID is removed.
1092     */
1093    private void removeUidsLocked(int... uids) {
1094        if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
1095
1096        // Perform one last poll before removing
1097        performPollLocked(FLAG_PERSIST_ALL);
1098
1099        mUidRecorder.removeUidsLocked(uids);
1100        mUidTagRecorder.removeUidsLocked(uids);
1101
1102        // Clear kernel stats associated with UID
1103        for (int uid : uids) {
1104            resetKernelUidStats(uid);
1105        }
1106    }
1107
1108    /**
1109     * Clean up {@link #mUidRecorder} after user is removed.
1110     */
1111    private void removeUserLocked(int userId) {
1112        if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
1113
1114        // Build list of UIDs that we should clean up
1115        int[] uids = new int[0];
1116        final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
1117                PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
1118        for (ApplicationInfo app : apps) {
1119            final int uid = UserHandle.getUid(userId, app.uid);
1120            uids = ArrayUtils.appendInt(uids, uid);
1121        }
1122
1123        removeUidsLocked(uids);
1124    }
1125
1126    @Override
1127    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1128        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1129
1130        final HashSet<String> argSet = new HashSet<String>();
1131        for (String arg : args) {
1132            argSet.add(arg);
1133        }
1134
1135        // usage: dumpsys netstats --full --uid --tag --poll --checkin
1136        final boolean poll = argSet.contains("--poll") || argSet.contains("poll");
1137        final boolean checkin = argSet.contains("--checkin");
1138        final boolean fullHistory = argSet.contains("--full") || argSet.contains("full");
1139        final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail");
1140        final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail");
1141
1142        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
1143
1144        synchronized (mStatsLock) {
1145            if (poll) {
1146                performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
1147                pw.println("Forced poll");
1148                return;
1149            }
1150
1151            if (checkin) {
1152                // list current stats files to verify rotation
1153                pw.println("Current files:");
1154                pw.increaseIndent();
1155                for (String file : mBaseDir.list()) {
1156                    pw.println(file);
1157                }
1158                pw.decreaseIndent();
1159                return;
1160            }
1161
1162            pw.println("Active interfaces:");
1163            pw.increaseIndent();
1164            for (int i = 0; i < mActiveIfaces.size(); i++) {
1165                pw.printPair("iface", mActiveIfaces.keyAt(i));
1166                pw.printPair("ident", mActiveIfaces.valueAt(i));
1167                pw.println();
1168            }
1169            pw.decreaseIndent();
1170
1171            pw.println("Active UID interfaces:");
1172            pw.increaseIndent();
1173            for (int i = 0; i < mActiveUidIfaces.size(); i++) {
1174                pw.printPair("iface", mActiveUidIfaces.keyAt(i));
1175                pw.printPair("ident", mActiveUidIfaces.valueAt(i));
1176                pw.println();
1177            }
1178            pw.decreaseIndent();
1179
1180            pw.println("Dev stats:");
1181            pw.increaseIndent();
1182            mDevRecorder.dumpLocked(pw, fullHistory);
1183            pw.decreaseIndent();
1184
1185            pw.println("Xt stats:");
1186            pw.increaseIndent();
1187            mXtRecorder.dumpLocked(pw, fullHistory);
1188            pw.decreaseIndent();
1189
1190            if (includeUid) {
1191                pw.println("UID stats:");
1192                pw.increaseIndent();
1193                mUidRecorder.dumpLocked(pw, fullHistory);
1194                pw.decreaseIndent();
1195            }
1196
1197            if (includeTag) {
1198                pw.println("UID tag stats:");
1199                pw.increaseIndent();
1200                mUidTagRecorder.dumpLocked(pw, fullHistory);
1201                pw.decreaseIndent();
1202            }
1203        }
1204    }
1205
1206    /**
1207     * Return snapshot of current UID statistics, including any
1208     * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
1209     */
1210    private NetworkStats getNetworkStatsUidDetail() throws RemoteException {
1211        final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
1212
1213        // fold tethering stats and operations into uid snapshot
1214        final NetworkStats tetherSnapshot = getNetworkStatsTethering();
1215        uidSnapshot.combineAllValues(tetherSnapshot);
1216        uidSnapshot.combineAllValues(mUidOperations);
1217
1218        return uidSnapshot;
1219    }
1220
1221    /**
1222     * Return snapshot of current tethering statistics. Will return empty
1223     * {@link NetworkStats} if any problems are encountered.
1224     */
1225    private NetworkStats getNetworkStatsTethering() throws RemoteException {
1226        try {
1227            return mNetworkManager.getNetworkStatsTethering();
1228        } catch (IllegalStateException e) {
1229            Log.wtf(TAG, "problem reading network stats", e);
1230            return new NetworkStats(0L, 10);
1231        }
1232    }
1233
1234    private Handler.Callback mHandlerCallback = new Handler.Callback() {
1235        @Override
1236        public boolean handleMessage(Message msg) {
1237            switch (msg.what) {
1238                case MSG_PERFORM_POLL: {
1239                    final int flags = msg.arg1;
1240                    performPoll(flags);
1241                    return true;
1242                }
1243                case MSG_UPDATE_IFACES: {
1244                    updateIfaces();
1245                    return true;
1246                }
1247                case MSG_REGISTER_GLOBAL_ALERT: {
1248                    registerGlobalAlert();
1249                    return true;
1250                }
1251                default: {
1252                    return false;
1253                }
1254            }
1255        }
1256    };
1257
1258    private void assertBandwidthControlEnabled() {
1259        if (!isBandwidthControlEnabled()) {
1260            throw new IllegalStateException("Bandwidth module disabled");
1261        }
1262    }
1263
1264    private boolean isBandwidthControlEnabled() {
1265        final long token = Binder.clearCallingIdentity();
1266        try {
1267            return mNetworkManager.isBandwidthControlEnabled();
1268        } catch (RemoteException e) {
1269            // ignored; service lives in system_server
1270            return false;
1271        } finally {
1272            Binder.restoreCallingIdentity(token);
1273        }
1274    }
1275
1276    private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
1277        @Override
1278        public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
1279                int rightIndex, String cookie) {
1280            Log.w(TAG, "found non-monotonic values; saving to dropbox");
1281
1282            // record error for debugging
1283            final StringBuilder builder = new StringBuilder();
1284            builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex
1285                    + "] - right[" + rightIndex + "]\n");
1286            builder.append("left=").append(left).append('\n');
1287            builder.append("right=").append(right).append('\n');
1288
1289            final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
1290                    Context.DROPBOX_SERVICE);
1291            dropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
1292        }
1293    }
1294
1295    /**
1296     * Default external settings that read from
1297     * {@link android.provider.Settings.Global}.
1298     */
1299    private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
1300        private final ContentResolver mResolver;
1301
1302        public DefaultNetworkStatsSettings(Context context) {
1303            mResolver = checkNotNull(context.getContentResolver());
1304            // TODO: adjust these timings for production builds
1305        }
1306
1307        private long getGlobalLong(String name, long def) {
1308            return Settings.Global.getLong(mResolver, name, def);
1309        }
1310        private boolean getGlobalBoolean(String name, boolean def) {
1311            final int defInt = def ? 1 : 0;
1312            return Settings.Global.getInt(mResolver, name, defInt) != 0;
1313        }
1314
1315        @Override
1316        public long getPollInterval() {
1317            return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
1318        }
1319        @Override
1320        public long getTimeCacheMaxAge() {
1321            return getGlobalLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
1322        }
1323        @Override
1324        public long getGlobalAlertBytes(long def) {
1325            return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def);
1326        }
1327        @Override
1328        public boolean getSampleEnabled() {
1329            return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true);
1330        }
1331        @Override
1332        public boolean getReportXtOverDev() {
1333            return getGlobalBoolean(NETSTATS_REPORT_XT_OVER_DEV, true);
1334        }
1335        @Override
1336        public Config getDevConfig() {
1337            return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
1338                    getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
1339                    getGlobalLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS));
1340        }
1341        @Override
1342        public Config getXtConfig() {
1343            return getDevConfig();
1344        }
1345        @Override
1346        public Config getUidConfig() {
1347            return new Config(getGlobalLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
1348                    getGlobalLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS),
1349                    getGlobalLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS));
1350        }
1351        @Override
1352        public Config getUidTagConfig() {
1353            return new Config(getGlobalLong(NETSTATS_UID_TAG_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
1354                    getGlobalLong(NETSTATS_UID_TAG_ROTATE_AGE, 5 * DAY_IN_MILLIS),
1355                    getGlobalLong(NETSTATS_UID_TAG_DELETE_AGE, 15 * DAY_IN_MILLIS));
1356        }
1357        @Override
1358        public long getDevPersistBytes(long def) {
1359            return getGlobalLong(NETSTATS_DEV_PERSIST_BYTES, def);
1360        }
1361        @Override
1362        public long getXtPersistBytes(long def) {
1363            return getDevPersistBytes(def);
1364        }
1365        @Override
1366        public long getUidPersistBytes(long def) {
1367            return getGlobalLong(NETSTATS_UID_PERSIST_BYTES, def);
1368        }
1369        @Override
1370        public long getUidTagPersistBytes(long def) {
1371            return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def);
1372        }
1373    }
1374}
1375