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