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