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