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