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