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