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