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