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