NetworkStatsService.java revision c506ff615080082515b1f634ad49b19fd2111669
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.NetworkStats.IFACE_ALL;
30import static android.net.NetworkStats.SET_ALL;
31import static android.net.NetworkStats.SET_DEFAULT;
32import static android.net.NetworkStats.SET_FOREGROUND;
33import static android.net.NetworkStats.TAG_NONE;
34import static android.net.NetworkStats.UID_ALL;
35import static android.net.NetworkTemplate.buildTemplateMobileAll;
36import static android.net.NetworkTemplate.buildTemplateWifi;
37import static android.net.TrafficStats.UID_REMOVED;
38import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
39import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
40import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
41import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
42import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
43import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
44import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
45import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
46import static android.telephony.PhoneStateListener.LISTEN_NONE;
47import static android.text.format.DateUtils.DAY_IN_MILLIS;
48import static android.text.format.DateUtils.HOUR_IN_MILLIS;
49import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
50import static android.text.format.DateUtils.SECOND_IN_MILLIS;
51import static com.android.internal.util.Preconditions.checkNotNull;
52import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
53import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
54import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
55
56import android.app.AlarmManager;
57import android.app.IAlarmManager;
58import android.app.PendingIntent;
59import android.content.BroadcastReceiver;
60import android.content.ContentResolver;
61import android.content.Context;
62import android.content.Intent;
63import android.content.IntentFilter;
64import android.content.pm.ApplicationInfo;
65import android.content.pm.PackageManager;
66import android.content.pm.PackageManager.NameNotFoundException;
67import android.net.IConnectivityManager;
68import android.net.INetworkManagementEventObserver;
69import android.net.INetworkStatsService;
70import android.net.NetworkIdentity;
71import android.net.NetworkInfo;
72import android.net.NetworkState;
73import android.net.NetworkStats;
74import android.net.NetworkStats.NonMonotonicException;
75import android.net.NetworkStatsHistory;
76import android.net.NetworkTemplate;
77import android.os.Binder;
78import android.os.DropBoxManager;
79import android.os.Environment;
80import android.os.Handler;
81import android.os.HandlerThread;
82import android.os.INetworkManagementService;
83import android.os.Message;
84import android.os.PowerManager;
85import android.os.RemoteException;
86import android.os.SystemClock;
87import android.provider.Settings;
88import android.telephony.PhoneStateListener;
89import android.telephony.TelephonyManager;
90import android.util.EventLog;
91import android.util.Log;
92import android.util.NtpTrustedTime;
93import android.util.Slog;
94import android.util.SparseIntArray;
95import android.util.TrustedTime;
96
97import com.android.internal.os.AtomicFile;
98import com.android.internal.util.Objects;
99import com.android.server.EventLogTags;
100import com.android.server.connectivity.Tethering;
101import com.google.android.collect.Lists;
102import com.google.android.collect.Maps;
103import com.google.android.collect.Sets;
104
105import java.io.BufferedInputStream;
106import java.io.BufferedOutputStream;
107import java.io.DataInputStream;
108import java.io.DataOutputStream;
109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileNotFoundException;
112import java.io.FileOutputStream;
113import java.io.IOException;
114import java.io.PrintWriter;
115import java.net.ProtocolException;
116import java.util.ArrayList;
117import java.util.Collections;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Random;
121
122import libcore.io.IoUtils;
123
124/**
125 * Collect and persist detailed network statistics, and provide this data to
126 * other system services.
127 */
128public class NetworkStatsService extends INetworkStatsService.Stub {
129    private static final String TAG = "NetworkStats";
130    private static final boolean LOGD = false;
131    private static final boolean LOGV = false;
132
133    /** File header magic number: "ANET" */
134    private static final int FILE_MAGIC = 0x414E4554;
135    private static final int VERSION_NETWORK_INIT = 1;
136    private static final int VERSION_UID_INIT = 1;
137    private static final int VERSION_UID_WITH_IDENT = 2;
138    private static final int VERSION_UID_WITH_TAG = 3;
139    private static final int VERSION_UID_WITH_SET = 4;
140
141    private static final int MSG_PERFORM_POLL = 1;
142    private static final int MSG_UPDATE_IFACES = 2;
143
144    /** Flags to control detail level of poll event. */
145    private static final int FLAG_PERSIST_NETWORK = 0x1;
146    private static final int FLAG_PERSIST_UID = 0x2;
147    private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
148    private static final int FLAG_PERSIST_FORCE = 0x100;
149
150    /** Sample recent usage after each poll event. */
151    private static final boolean ENABLE_SAMPLE_AFTER_POLL = true;
152
153    private static final String TAG_NETSTATS_ERROR = "netstats_error";
154
155    private final Context mContext;
156    private final INetworkManagementService mNetworkManager;
157    private final IAlarmManager mAlarmManager;
158    private final TrustedTime mTime;
159    private final TelephonyManager mTeleManager;
160    private final NetworkStatsSettings mSettings;
161
162    private final PowerManager.WakeLock mWakeLock;
163
164    private IConnectivityManager mConnManager;
165    private DropBoxManager mDropBox;
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    // TODO: trim empty history objects entirely
176
177    private static final long KB_IN_BYTES = 1024;
178    private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
179    private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
180
181    /**
182     * Settings that can be changed externally.
183     */
184    public interface NetworkStatsSettings {
185        public long getPollInterval();
186        public long getPersistThreshold();
187        public long getNetworkBucketDuration();
188        public long getNetworkMaxHistory();
189        public long getUidBucketDuration();
190        public long getUidMaxHistory();
191        public long getTagMaxHistory();
192        public long getTimeCacheMaxAge();
193    }
194
195    private final Object mStatsLock = new Object();
196
197    /** Set of currently active ifaces. */
198    private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
199    /** Set of historical {@code dev} stats for known networks. */
200    private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkDevStats = Maps.newHashMap();
201    /** Set of historical {@code xtables} stats for known networks. */
202    private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkXtStats = Maps.newHashMap();
203    /** Set of historical {@code xtables} stats for known UIDs. */
204    private HashMap<UidStatsKey, NetworkStatsHistory> mUidStats = Maps.newHashMap();
205
206    /** Flag if {@link #mNetworkDevStats} have been loaded from disk. */
207    private boolean mNetworkStatsLoaded = false;
208    /** Flag if {@link #mUidStats} have been loaded from disk. */
209    private boolean mUidStatsLoaded = false;
210
211    private NetworkStats mLastPollNetworkDevSnapshot;
212    private NetworkStats mLastPollNetworkXtSnapshot;
213    private NetworkStats mLastPollUidSnapshot;
214    private NetworkStats mLastPollOperationsSnapshot;
215
216    private NetworkStats mLastPersistNetworkDevSnapshot;
217    private NetworkStats mLastPersistNetworkXtSnapshot;
218    private NetworkStats mLastPersistUidSnapshot;
219
220    /** Current counter sets for each UID. */
221    private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
222
223    /** Data layer operation counters for splicing into other structures. */
224    private NetworkStats mOperations = new NetworkStats(0L, 10);
225
226    private final HandlerThread mHandlerThread;
227    private final Handler mHandler;
228
229    private final AtomicFile mNetworkDevFile;
230    private final AtomicFile mNetworkXtFile;
231    private final AtomicFile mUidFile;
232
233    public NetworkStatsService(
234            Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
235        this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
236                getSystemDir(), new DefaultNetworkStatsSettings(context));
237    }
238
239    private static File getSystemDir() {
240        return new File(Environment.getDataDirectory(), "system");
241    }
242
243    public NetworkStatsService(Context context, INetworkManagementService networkManager,
244            IAlarmManager alarmManager, TrustedTime time, File systemDir,
245            NetworkStatsSettings settings) {
246        mContext = checkNotNull(context, "missing Context");
247        mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
248        mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
249        mTime = checkNotNull(time, "missing TrustedTime");
250        mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
251        mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
252
253        final PowerManager powerManager = (PowerManager) context.getSystemService(
254                Context.POWER_SERVICE);
255        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
256
257        mHandlerThread = new HandlerThread(TAG);
258        mHandlerThread.start();
259        mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
260
261        mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin"));
262        mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin"));
263        mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
264    }
265
266    public void bindConnectivityManager(IConnectivityManager connManager) {
267        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
268    }
269
270    public void systemReady() {
271        synchronized (mStatsLock) {
272            // read historical network stats from disk, since policy service
273            // might need them right away. we delay loading detailed UID stats
274            // until actually needed.
275            readNetworkDevStatsLocked();
276            readNetworkXtStatsLocked();
277            mNetworkStatsLoaded = true;
278        }
279
280        // bootstrap initial stats to prevent double-counting later
281        bootstrapStats();
282
283        // watch for network interfaces to be claimed
284        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
285        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
286
287        // watch for tethering changes
288        final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
289        mContext.registerReceiver(mTetherReceiver, tetherFilter, CONNECTIVITY_INTERNAL, mHandler);
290
291        // listen for periodic polling events
292        final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
293        mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
294
295        // listen for uid removal to clean stats
296        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
297        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
298
299        // persist stats during clean shutdown
300        final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
301        mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
302
303        try {
304            mNetworkManager.registerObserver(mAlertObserver);
305        } catch (RemoteException e) {
306            // ignored; service lives in system_server
307        }
308
309        // watch for networkType changes that aren't broadcast through
310        // CONNECTIVITY_ACTION_IMMEDIATE above.
311        mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE);
312
313        registerPollAlarmLocked();
314        registerGlobalAlert();
315
316        mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
317    }
318
319    private void shutdownLocked() {
320        mContext.unregisterReceiver(mConnReceiver);
321        mContext.unregisterReceiver(mTetherReceiver);
322        mContext.unregisterReceiver(mPollReceiver);
323        mContext.unregisterReceiver(mRemovedReceiver);
324        mContext.unregisterReceiver(mShutdownReceiver);
325
326        mTeleManager.listen(mPhoneListener, LISTEN_NONE);
327
328        if (mNetworkStatsLoaded) {
329            writeNetworkDevStatsLocked();
330            writeNetworkXtStatsLocked();
331        }
332        if (mUidStatsLoaded) {
333            writeUidStatsLocked();
334        }
335        mNetworkDevStats.clear();
336        mNetworkXtStats.clear();
337        mUidStats.clear();
338        mNetworkStatsLoaded = false;
339        mUidStatsLoaded = false;
340    }
341
342    /**
343     * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
344     * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
345     */
346    private void registerPollAlarmLocked() {
347        try {
348            if (mPollIntent != null) {
349                mAlarmManager.remove(mPollIntent);
350            }
351
352            mPollIntent = PendingIntent.getBroadcast(
353                    mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
354
355            final long currentRealtime = SystemClock.elapsedRealtime();
356            mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
357                    mSettings.getPollInterval(), mPollIntent);
358        } catch (RemoteException e) {
359            // ignored; service lives in system_server
360        }
361    }
362
363    /**
364     * Register for a global alert that is delivered through
365     * {@link INetworkManagementEventObserver} once a threshold amount of data
366     * has been transferred.
367     */
368    private void registerGlobalAlert() {
369        try {
370            final long alertBytes = mSettings.getPersistThreshold();
371            mNetworkManager.setGlobalAlert(alertBytes);
372        } catch (IllegalStateException e) {
373            Slog.w(TAG, "problem registering for global alert: " + e);
374        } catch (RemoteException e) {
375            // ignored; service lives in system_server
376        }
377    }
378
379    @Override
380    public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
381        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
382        return getHistoryForNetworkDev(template, fields);
383    }
384
385    private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) {
386        return getHistoryForNetwork(template, fields, mNetworkDevStats);
387    }
388
389    private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) {
390        return getHistoryForNetwork(template, fields, mNetworkXtStats);
391    }
392
393    private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields,
394            HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
395        synchronized (mStatsLock) {
396            // combine all interfaces that match template
397            final NetworkStatsHistory combined = new NetworkStatsHistory(
398                    mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
399            for (NetworkIdentitySet ident : source.keySet()) {
400                if (templateMatches(template, ident)) {
401                    final NetworkStatsHistory history = source.get(ident);
402                    if (history != null) {
403                        combined.recordEntireHistory(history);
404                    }
405                }
406            }
407            return combined;
408        }
409    }
410
411    @Override
412    public NetworkStatsHistory getHistoryForUid(
413            NetworkTemplate template, int uid, int set, int tag, int fields) {
414        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
415
416        synchronized (mStatsLock) {
417            ensureUidStatsLoadedLocked();
418
419            // combine all interfaces that match template
420            final NetworkStatsHistory combined = new NetworkStatsHistory(
421                    mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
422            for (UidStatsKey key : mUidStats.keySet()) {
423                final boolean setMatches = set == SET_ALL || key.set == set;
424                if (templateMatches(template, key.ident) && key.uid == uid && setMatches
425                        && key.tag == tag) {
426                    final NetworkStatsHistory history = mUidStats.get(key);
427                    combined.recordEntireHistory(history);
428                }
429            }
430
431            return combined;
432        }
433    }
434
435    @Override
436    public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
437        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
438        return getSummaryForNetworkDev(template, start, end);
439    }
440
441    private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) {
442        return getSummaryForNetwork(template, start, end, mNetworkDevStats);
443    }
444
445    private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) {
446        return getSummaryForNetwork(template, start, end, mNetworkXtStats);
447    }
448
449    private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end,
450            HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
451        synchronized (mStatsLock) {
452            // use system clock to be externally consistent
453            final long now = System.currentTimeMillis();
454
455            final NetworkStats stats = new NetworkStats(end - start, 1);
456            final NetworkStats.Entry entry = new NetworkStats.Entry();
457            NetworkStatsHistory.Entry historyEntry = null;
458
459            // combine total from all interfaces that match template
460            for (NetworkIdentitySet ident : source.keySet()) {
461                if (templateMatches(template, ident)) {
462                    final NetworkStatsHistory history = source.get(ident);
463                    historyEntry = history.getValues(start, end, now, historyEntry);
464
465                    entry.iface = IFACE_ALL;
466                    entry.uid = UID_ALL;
467                    entry.tag = TAG_NONE;
468                    entry.rxBytes = historyEntry.rxBytes;
469                    entry.rxPackets = historyEntry.rxPackets;
470                    entry.txBytes = historyEntry.txBytes;
471                    entry.txPackets = historyEntry.txPackets;
472
473                    stats.combineValues(entry);
474                }
475            }
476
477            return stats;
478        }
479    }
480
481    private long getHistoryStartLocked(
482            NetworkTemplate template, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
483        long start = Long.MAX_VALUE;
484        for (NetworkIdentitySet ident : source.keySet()) {
485            if (templateMatches(template, ident)) {
486                final NetworkStatsHistory history = source.get(ident);
487                start = Math.min(start, history.getStart());
488            }
489        }
490        return start;
491    }
492
493    @Override
494    public NetworkStats getSummaryForAllUid(
495            NetworkTemplate template, long start, long end, boolean includeTags) {
496        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
497
498        synchronized (mStatsLock) {
499            ensureUidStatsLoadedLocked();
500
501            // use system clock to be externally consistent
502            final long now = System.currentTimeMillis();
503
504            final NetworkStats stats = new NetworkStats(end - start, 24);
505            final NetworkStats.Entry entry = new NetworkStats.Entry();
506            NetworkStatsHistory.Entry historyEntry = null;
507
508            for (UidStatsKey key : mUidStats.keySet()) {
509                if (templateMatches(template, key.ident)) {
510                    // always include summary under TAG_NONE, and include
511                    // other tags when requested.
512                    if (key.tag == TAG_NONE || includeTags) {
513                        final NetworkStatsHistory history = mUidStats.get(key);
514                        historyEntry = history.getValues(start, end, now, historyEntry);
515
516                        entry.iface = IFACE_ALL;
517                        entry.uid = key.uid;
518                        entry.set = key.set;
519                        entry.tag = key.tag;
520                        entry.rxBytes = historyEntry.rxBytes;
521                        entry.rxPackets = historyEntry.rxPackets;
522                        entry.txBytes = historyEntry.txBytes;
523                        entry.txPackets = historyEntry.txPackets;
524                        entry.operations = historyEntry.operations;
525
526                        if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
527                                || entry.txPackets > 0 || entry.operations > 0) {
528                            stats.combineValues(entry);
529                        }
530                    }
531                }
532            }
533
534            return stats;
535        }
536    }
537
538    @Override
539    public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException {
540        if (Binder.getCallingUid() != uid) {
541            mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
542        }
543
544        // TODO: switch to data layer stats once kernel exports
545        // for now, read network layer stats and flatten across all ifaces
546        final NetworkStats networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
547        final NetworkStats dataLayer = new NetworkStats(
548                networkLayer.getElapsedRealtime(), networkLayer.size());
549
550        NetworkStats.Entry entry = null;
551        for (int i = 0; i < networkLayer.size(); i++) {
552            entry = networkLayer.getValues(i, entry);
553            entry.iface = IFACE_ALL;
554            dataLayer.combineValues(entry);
555        }
556
557        // splice in operation counts
558        dataLayer.spliceOperationsFrom(mOperations);
559        return dataLayer;
560    }
561
562    @Override
563    public void incrementOperationCount(int uid, int tag, int operationCount) {
564        if (Binder.getCallingUid() != uid) {
565            mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
566        }
567
568        if (operationCount < 0) {
569            throw new IllegalArgumentException("operation count can only be incremented");
570        }
571        if (tag == TAG_NONE) {
572            throw new IllegalArgumentException("operation count must have specific tag");
573        }
574
575        synchronized (mStatsLock) {
576            final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
577            mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
578            mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
579        }
580    }
581
582    @Override
583    public void setUidForeground(int uid, boolean uidForeground) {
584        mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
585
586        synchronized (mStatsLock) {
587            final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
588            final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
589            if (oldSet != set) {
590                mActiveUidCounterSet.put(uid, set);
591                setKernelCounterSet(uid, set);
592            }
593        }
594    }
595
596    @Override
597    public void forceUpdate() {
598        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
599        performPoll(FLAG_PERSIST_ALL);
600    }
601
602    /**
603     * Receiver that watches for {@link IConnectivityManager} to claim network
604     * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
605     * with mobile interfaces.
606     */
607    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
608        @Override
609        public void onReceive(Context context, Intent intent) {
610            // on background handler thread, and verified CONNECTIVITY_INTERNAL
611            // permission above.
612            updateIfaces();
613        }
614    };
615
616    /**
617     * Receiver that watches for {@link Tethering} to claim interface pairs.
618     */
619    private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
620        @Override
621        public void onReceive(Context context, Intent intent) {
622            // on background handler thread, and verified CONNECTIVITY_INTERNAL
623            // permission above.
624            performPoll(FLAG_PERSIST_NETWORK);
625        }
626    };
627
628    private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
629        @Override
630        public void onReceive(Context context, Intent intent) {
631            // on background handler thread, and verified UPDATE_DEVICE_STATS
632            // permission above.
633            performPoll(FLAG_PERSIST_ALL);
634
635            // verify that we're watching global alert
636            registerGlobalAlert();
637        }
638    };
639
640    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
641        @Override
642        public void onReceive(Context context, Intent intent) {
643            // on background handler thread, and UID_REMOVED is protected
644            // broadcast.
645            final int uid = intent.getIntExtra(EXTRA_UID, 0);
646            synchronized (mStatsLock) {
647                mWakeLock.acquire();
648                try {
649                    removeUidLocked(uid);
650                } finally {
651                    mWakeLock.release();
652                }
653            }
654        }
655    };
656
657    private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
658        @Override
659        public void onReceive(Context context, Intent intent) {
660            // SHUTDOWN is protected broadcast.
661            synchronized (mStatsLock) {
662                shutdownLocked();
663            }
664        }
665    };
666
667    /**
668     * Observer that watches for {@link INetworkManagementService} alerts.
669     */
670    private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
671        @Override
672        public void limitReached(String limitName, String iface) {
673            // only someone like NMS should be calling us
674            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
675
676            if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
677                // kick off background poll to collect network stats; UID stats
678                // are handled during normal polling interval.
679                final int flags = FLAG_PERSIST_NETWORK;
680                mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
681
682                // re-arm global alert for next update
683                registerGlobalAlert();
684            }
685        }
686    };
687
688    private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN;
689    private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
690
691    /**
692     * Receiver that watches for {@link TelephonyManager} changes, such as
693     * transitioning between network types.
694     */
695    private PhoneStateListener mPhoneListener = new PhoneStateListener() {
696        @Override
697        public void onDataConnectionStateChanged(int state, int networkType) {
698            final boolean stateChanged = state != mLastPhoneState;
699            final boolean networkTypeChanged = networkType != mLastPhoneNetworkType;
700
701            if (networkTypeChanged && !stateChanged) {
702                // networkType changed without a state change, which means we
703                // need to roll our own update. delay long enough for
704                // ConnectivityManager to process.
705                // TODO: add direct event to ConnectivityService instead of
706                // relying on this delay.
707                if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()");
708                mHandler.sendMessageDelayed(
709                        mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);
710            }
711
712            mLastPhoneState = state;
713            mLastPhoneNetworkType = networkType;
714        }
715    };
716
717    private void updateIfaces() {
718        synchronized (mStatsLock) {
719            mWakeLock.acquire();
720            try {
721                updateIfacesLocked();
722            } finally {
723                mWakeLock.release();
724            }
725        }
726    }
727
728    /**
729     * Inspect all current {@link NetworkState} to derive mapping from {@code
730     * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
731     * are active on a single {@code iface}, they are combined under a single
732     * {@link NetworkIdentitySet}.
733     */
734    private void updateIfacesLocked() {
735        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
736
737        // take one last stats snapshot before updating iface mapping. this
738        // isn't perfect, since the kernel may already be counting traffic from
739        // the updated network.
740
741        // poll, but only persist network stats to keep codepath fast. UID stats
742        // will be persisted during next alarm poll event.
743        performPollLocked(FLAG_PERSIST_NETWORK);
744
745        final NetworkState[] states;
746        try {
747            states = mConnManager.getAllNetworkState();
748        } catch (RemoteException e) {
749            // ignored; service lives in system_server
750            return;
751        }
752
753        // rebuild active interfaces based on connected networks
754        mActiveIfaces.clear();
755
756        for (NetworkState state : states) {
757            if (state.networkInfo.isConnected()) {
758                // collect networks under their parent interfaces
759                final String iface = state.linkProperties.getInterfaceName();
760
761                NetworkIdentitySet ident = mActiveIfaces.get(iface);
762                if (ident == null) {
763                    ident = new NetworkIdentitySet();
764                    mActiveIfaces.put(iface, ident);
765                }
766
767                ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
768            }
769        }
770    }
771
772    /**
773     * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
774     * so we have baseline values without double-counting.
775     */
776    private void bootstrapStats() {
777        try {
778            mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
779            mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
780            mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
781            mLastPollOperationsSnapshot = new NetworkStats(0L, 0);
782        } catch (IllegalStateException e) {
783            Slog.w(TAG, "problem reading network stats: " + e);
784        } catch (RemoteException e) {
785            // ignored; service lives in system_server
786        }
787    }
788
789    private void performPoll(int flags) {
790        synchronized (mStatsLock) {
791            mWakeLock.acquire();
792
793            // try refreshing time source when stale
794            if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
795                mTime.forceRefresh();
796            }
797
798            try {
799                performPollLocked(flags);
800            } finally {
801                mWakeLock.release();
802            }
803        }
804    }
805
806    /**
807     * Periodic poll operation, reading current statistics and recording into
808     * {@link NetworkStatsHistory}.
809     */
810    private void performPollLocked(int flags) {
811        if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
812        final long startRealtime = SystemClock.elapsedRealtime();
813
814        final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
815        final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
816        final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
817
818        // TODO: consider marking "untrusted" times in historical stats
819        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
820                : System.currentTimeMillis();
821        final long threshold = mSettings.getPersistThreshold();
822
823        final NetworkStats uidSnapshot;
824        final NetworkStats networkXtSnapshot;
825        final NetworkStats networkDevSnapshot;
826        try {
827            // collect any tethering stats
828            final NetworkStats tetherSnapshot = getNetworkStatsTethering();
829
830            // record uid stats, folding in tethering stats
831            uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
832            uidSnapshot.combineAllValues(tetherSnapshot);
833            performUidPollLocked(uidSnapshot, currentTime);
834
835            // record dev network stats
836            networkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
837            performNetworkDevPollLocked(networkDevSnapshot, currentTime);
838
839            // record xt network stats
840            networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot);
841            performNetworkXtPollLocked(networkXtSnapshot, currentTime);
842
843        } catch (IllegalStateException e) {
844            Log.wtf(TAG, "problem reading network stats", e);
845            return;
846        } catch (RemoteException e) {
847            // ignored; service lives in system_server
848            return;
849        }
850
851        // persist when enough network data has occurred
852        final long persistNetworkDevDelta = computeStatsDelta(
853                mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes();
854        final long persistNetworkXtDelta = computeStatsDelta(
855                mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes();
856        final boolean networkOverThreshold = persistNetworkDevDelta > threshold
857                || persistNetworkXtDelta > threshold;
858        if (persistForce || (persistNetwork && networkOverThreshold)) {
859            writeNetworkDevStatsLocked();
860            writeNetworkXtStatsLocked();
861            mLastPersistNetworkDevSnapshot = networkDevSnapshot;
862            mLastPersistNetworkXtSnapshot = networkXtSnapshot;
863        }
864
865        // persist when enough uid data has occurred
866        final long persistUidDelta = computeStatsDelta(
867                mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes();
868        if (persistForce || (persistUid && persistUidDelta > threshold)) {
869            writeUidStatsLocked();
870            mLastPersistUidSnapshot = uidSnapshot;
871        }
872
873        if (LOGV) {
874            final long duration = SystemClock.elapsedRealtime() - startRealtime;
875            Slog.v(TAG, "performPollLocked() took " + duration + "ms");
876        }
877
878        if (ENABLE_SAMPLE_AFTER_POLL) {
879            // sample stats after each full poll
880            performSample();
881        }
882
883        // finally, dispatch updated event to any listeners
884        final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
885        updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
886        mContext.sendBroadcast(updatedIntent, READ_NETWORK_USAGE_HISTORY);
887    }
888
889    /**
890     * Update {@link #mNetworkDevStats} historical usage.
891     */
892    private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) {
893        final HashSet<String> unknownIface = Sets.newHashSet();
894
895        final NetworkStats delta = computeStatsDelta(
896                mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev");
897        final long timeStart = currentTime - delta.getElapsedRealtime();
898
899        NetworkStats.Entry entry = null;
900        for (int i = 0; i < delta.size(); i++) {
901            entry = delta.getValues(i, entry);
902            final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
903            if (ident == null) {
904                unknownIface.add(entry.iface);
905                continue;
906            }
907
908            final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident);
909            history.recordData(timeStart, currentTime, entry);
910        }
911
912        mLastPollNetworkDevSnapshot = networkDevSnapshot;
913
914        if (LOGD && unknownIface.size() > 0) {
915            Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats");
916        }
917    }
918
919    /**
920     * Update {@link #mNetworkXtStats} historical usage.
921     */
922    private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) {
923        final HashSet<String> unknownIface = Sets.newHashSet();
924
925        final NetworkStats delta = computeStatsDelta(
926                mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt");
927        final long timeStart = currentTime - delta.getElapsedRealtime();
928
929        NetworkStats.Entry entry = null;
930        for (int i = 0; i < delta.size(); i++) {
931            entry = delta.getValues(i, entry);
932            final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
933            if (ident == null) {
934                unknownIface.add(entry.iface);
935                continue;
936            }
937
938            final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident);
939            history.recordData(timeStart, currentTime, entry);
940        }
941
942        mLastPollNetworkXtSnapshot = networkXtSnapshot;
943
944        if (LOGD && unknownIface.size() > 0) {
945            Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats");
946        }
947    }
948
949    /**
950     * Update {@link #mUidStats} historical usage.
951     */
952    private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
953        ensureUidStatsLoadedLocked();
954
955        final NetworkStats delta = computeStatsDelta(
956                mLastPollUidSnapshot, uidSnapshot, false, "uid");
957        final NetworkStats operationsDelta = computeStatsDelta(
958                mLastPollOperationsSnapshot, mOperations, false, "uidop");
959        final long timeStart = currentTime - delta.getElapsedRealtime();
960
961        NetworkStats.Entry entry = null;
962        NetworkStats.Entry operationsEntry = null;
963        for (int i = 0; i < delta.size(); i++) {
964            entry = delta.getValues(i, entry);
965            final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
966            if (ident == null) {
967                if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
968                        || entry.txPackets > 0) {
969                    Log.w(TAG, "dropping UID delta from unknown iface: " + entry);
970                }
971                continue;
972            }
973
974            // splice in operation counts since last poll
975            final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag);
976            if (j != -1) {
977                operationsEntry = operationsDelta.getValues(j, operationsEntry);
978                entry.operations = operationsEntry.operations;
979            }
980
981            final NetworkStatsHistory history = findOrCreateUidStatsLocked(
982                    ident, entry.uid, entry.set, entry.tag);
983            history.recordData(timeStart, currentTime, entry);
984        }
985
986        mLastPollUidSnapshot = uidSnapshot;
987        mLastPollOperationsSnapshot = mOperations.clone();
988    }
989
990    /**
991     * Sample recent statistics summary into {@link EventLog}.
992     */
993    private void performSample() {
994        final long largestBucketSize = Math.max(
995                mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
996
997        // take sample as atomic buckets
998        final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
999        final long end = now - (now % largestBucketSize) + largestBucketSize;
1000        final long start = end - largestBucketSize;
1001
1002        final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
1003        long devHistoryStart = Long.MAX_VALUE;
1004
1005        NetworkTemplate template = null;
1006        NetworkStats.Entry devTotal = null;
1007        NetworkStats.Entry xtTotal = null;
1008        NetworkStats.Entry uidTotal = null;
1009
1010        // collect mobile sample
1011        template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
1012        devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
1013        devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
1014        xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
1015        uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
1016
1017        EventLogTags.writeNetstatsMobileSample(
1018                devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1019                xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1020                uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
1021                trustedTime, devHistoryStart);
1022
1023        // collect wifi sample
1024        template = buildTemplateWifi();
1025        devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
1026        devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
1027        xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
1028        uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
1029        EventLogTags.writeNetstatsWifiSample(
1030                devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
1031                xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
1032                uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
1033                trustedTime, devHistoryStart);
1034    }
1035
1036    /**
1037     * Clean up {@link #mUidStats} after UID is removed.
1038     */
1039    private void removeUidLocked(int uid) {
1040        ensureUidStatsLoadedLocked();
1041
1042        // perform one last poll before removing
1043        performPollLocked(FLAG_PERSIST_ALL);
1044
1045        final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList();
1046        knownKeys.addAll(mUidStats.keySet());
1047
1048        // migrate all UID stats into special "removed" bucket
1049        for (UidStatsKey key : knownKeys) {
1050            if (key.uid == uid) {
1051                // only migrate combined TAG_NONE history
1052                if (key.tag == TAG_NONE) {
1053                    final NetworkStatsHistory uidHistory = mUidStats.get(key);
1054                    final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
1055                            key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
1056                    removedHistory.recordEntireHistory(uidHistory);
1057                }
1058                mUidStats.remove(key);
1059            }
1060        }
1061
1062        // clear UID from current stats snapshot
1063        mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
1064        mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
1065
1066        // clear kernel stats associated with UID
1067        resetKernelUidStats(uid);
1068
1069        // since this was radical rewrite, push to disk
1070        writeUidStatsLocked();
1071    }
1072
1073    private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) {
1074        return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats);
1075    }
1076
1077    private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) {
1078        return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats);
1079    }
1080
1081    private NetworkStatsHistory findOrCreateNetworkStatsLocked(
1082            NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
1083        final NetworkStatsHistory existing = source.get(ident);
1084
1085        // update when no existing, or when bucket duration changed
1086        final long bucketDuration = mSettings.getNetworkBucketDuration();
1087        NetworkStatsHistory updated = null;
1088        if (existing == null) {
1089            updated = new NetworkStatsHistory(bucketDuration, 10);
1090        } else if (existing.getBucketDuration() != bucketDuration) {
1091            updated = new NetworkStatsHistory(
1092                    bucketDuration, estimateResizeBuckets(existing, bucketDuration));
1093            updated.recordEntireHistory(existing);
1094        }
1095
1096        if (updated != null) {
1097            source.put(ident, updated);
1098            return updated;
1099        } else {
1100            return existing;
1101        }
1102    }
1103
1104    private NetworkStatsHistory findOrCreateUidStatsLocked(
1105            NetworkIdentitySet ident, int uid, int set, int tag) {
1106        ensureUidStatsLoadedLocked();
1107
1108        final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
1109        final NetworkStatsHistory existing = mUidStats.get(key);
1110
1111        // update when no existing, or when bucket duration changed
1112        final long bucketDuration = mSettings.getUidBucketDuration();
1113        NetworkStatsHistory updated = null;
1114        if (existing == null) {
1115            updated = new NetworkStatsHistory(bucketDuration, 10);
1116        } else if (existing.getBucketDuration() != bucketDuration) {
1117            updated = new NetworkStatsHistory(
1118                    bucketDuration, estimateResizeBuckets(existing, bucketDuration));
1119            updated.recordEntireHistory(existing);
1120        }
1121
1122        if (updated != null) {
1123            mUidStats.put(key, updated);
1124            return updated;
1125        } else {
1126            return existing;
1127        }
1128    }
1129
1130    private void readNetworkDevStatsLocked() {
1131        if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()");
1132        readNetworkStats(mNetworkDevFile, mNetworkDevStats);
1133    }
1134
1135    private void readNetworkXtStatsLocked() {
1136        if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()");
1137        readNetworkStats(mNetworkXtFile, mNetworkXtStats);
1138    }
1139
1140    private static void readNetworkStats(
1141            AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output) {
1142        // clear any existing stats and read from disk
1143        output.clear();
1144
1145        DataInputStream in = null;
1146        try {
1147            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
1148
1149            // verify file magic header intact
1150            final int magic = in.readInt();
1151            if (magic != FILE_MAGIC) {
1152                throw new ProtocolException("unexpected magic: " + magic);
1153            }
1154
1155            final int version = in.readInt();
1156            switch (version) {
1157                case VERSION_NETWORK_INIT: {
1158                    // network := size *(NetworkIdentitySet NetworkStatsHistory)
1159                    final int size = in.readInt();
1160                    for (int i = 0; i < size; i++) {
1161                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
1162                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
1163                        output.put(ident, history);
1164                    }
1165                    break;
1166                }
1167                default: {
1168                    throw new ProtocolException("unexpected version: " + version);
1169                }
1170            }
1171        } catch (FileNotFoundException e) {
1172            // missing stats is okay, probably first boot
1173        } catch (IOException e) {
1174            Log.wtf(TAG, "problem reading network stats", e);
1175        } finally {
1176            IoUtils.closeQuietly(in);
1177        }
1178    }
1179
1180    private void ensureUidStatsLoadedLocked() {
1181        if (!mUidStatsLoaded) {
1182            readUidStatsLocked();
1183            mUidStatsLoaded = true;
1184        }
1185    }
1186
1187    private void readUidStatsLocked() {
1188        if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
1189
1190        // clear any existing stats and read from disk
1191        mUidStats.clear();
1192
1193        DataInputStream in = null;
1194        try {
1195            in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
1196
1197            // verify file magic header intact
1198            final int magic = in.readInt();
1199            if (magic != FILE_MAGIC) {
1200                throw new ProtocolException("unexpected magic: " + magic);
1201            }
1202
1203            final int version = in.readInt();
1204            switch (version) {
1205                case VERSION_UID_INIT: {
1206                    // uid := size *(UID NetworkStatsHistory)
1207
1208                    // drop this data version, since we don't have a good
1209                    // mapping into NetworkIdentitySet.
1210                    break;
1211                }
1212                case VERSION_UID_WITH_IDENT: {
1213                    // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
1214
1215                    // drop this data version, since this version only existed
1216                    // for a short time.
1217                    break;
1218                }
1219                case VERSION_UID_WITH_TAG:
1220                case VERSION_UID_WITH_SET: {
1221                    // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
1222                    final int identSize = in.readInt();
1223                    for (int i = 0; i < identSize; i++) {
1224                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
1225
1226                        final int size = in.readInt();
1227                        for (int j = 0; j < size; j++) {
1228                            final int uid = in.readInt();
1229                            final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
1230                                    : SET_DEFAULT;
1231                            final int tag = in.readInt();
1232
1233                            final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
1234                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
1235                            mUidStats.put(key, history);
1236                        }
1237                    }
1238                    break;
1239                }
1240                default: {
1241                    throw new ProtocolException("unexpected version: " + version);
1242                }
1243            }
1244        } catch (FileNotFoundException e) {
1245            // missing stats is okay, probably first boot
1246        } catch (IOException e) {
1247            Log.wtf(TAG, "problem reading uid stats", e);
1248        } finally {
1249            IoUtils.closeQuietly(in);
1250        }
1251    }
1252
1253    private void writeNetworkDevStatsLocked() {
1254        if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()");
1255        writeNetworkStats(mNetworkDevStats, mNetworkDevFile);
1256    }
1257
1258    private void writeNetworkXtStatsLocked() {
1259        if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()");
1260        writeNetworkStats(mNetworkXtStats, mNetworkXtFile);
1261    }
1262
1263    private void writeNetworkStats(
1264            HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile) {
1265        // TODO: consider duplicating stats and releasing lock while writing
1266
1267        // trim any history beyond max
1268        if (mTime.hasCache()) {
1269            final long systemCurrentTime = System.currentTimeMillis();
1270            final long trustedCurrentTime = mTime.currentTimeMillis();
1271
1272            final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime);
1273            final long maxHistory = mSettings.getNetworkMaxHistory();
1274
1275            for (NetworkStatsHistory history : input.values()) {
1276                final int beforeSize = history.size();
1277                history.removeBucketsBefore(currentTime - maxHistory);
1278                final int afterSize = history.size();
1279
1280                if (beforeSize > 24 && afterSize < beforeSize / 2) {
1281                    // yikes, dropping more than half of significant history
1282                    final StringBuilder builder = new StringBuilder();
1283                    builder.append("yikes, dropping more than half of history").append('\n');
1284                    builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n');
1285                    builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n');
1286                    builder.append("maxHistory=").append(maxHistory).append('\n');
1287                    builder.append("beforeSize=").append(beforeSize).append('\n');
1288                    builder.append("afterSize=").append(afterSize).append('\n');
1289                    mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
1290                }
1291            }
1292        }
1293
1294        FileOutputStream fos = null;
1295        try {
1296            fos = outputFile.startWrite();
1297            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
1298
1299            out.writeInt(FILE_MAGIC);
1300            out.writeInt(VERSION_NETWORK_INIT);
1301
1302            out.writeInt(input.size());
1303            for (NetworkIdentitySet ident : input.keySet()) {
1304                final NetworkStatsHistory history = input.get(ident);
1305                ident.writeToStream(out);
1306                history.writeToStream(out);
1307            }
1308
1309            out.flush();
1310            outputFile.finishWrite(fos);
1311        } catch (IOException e) {
1312            Log.wtf(TAG, "problem writing stats", e);
1313            if (fos != null) {
1314                outputFile.failWrite(fos);
1315            }
1316        }
1317    }
1318
1319    private void writeUidStatsLocked() {
1320        if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
1321
1322        if (!mUidStatsLoaded) {
1323            Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
1324            return;
1325        }
1326
1327        // TODO: consider duplicating stats and releasing lock while writing
1328
1329        // trim any history beyond max
1330        if (mTime.hasCache()) {
1331            final long currentTime = Math.min(
1332                    System.currentTimeMillis(), mTime.currentTimeMillis());
1333            final long maxUidHistory = mSettings.getUidMaxHistory();
1334            final long maxTagHistory = mSettings.getTagMaxHistory();
1335            for (UidStatsKey key : mUidStats.keySet()) {
1336                final NetworkStatsHistory history = mUidStats.get(key);
1337
1338                // detailed tags are trimmed sooner than summary in TAG_NONE
1339                if (key.tag == TAG_NONE) {
1340                    history.removeBucketsBefore(currentTime - maxUidHistory);
1341                } else {
1342                    history.removeBucketsBefore(currentTime - maxTagHistory);
1343                }
1344            }
1345        }
1346
1347        // build UidStatsKey lists grouped by ident
1348        final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
1349        for (UidStatsKey key : mUidStats.keySet()) {
1350            ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
1351            if (keys == null) {
1352                keys = Lists.newArrayList();
1353                keysByIdent.put(key.ident, keys);
1354            }
1355            keys.add(key);
1356        }
1357
1358        FileOutputStream fos = null;
1359        try {
1360            fos = mUidFile.startWrite();
1361            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
1362
1363            out.writeInt(FILE_MAGIC);
1364            out.writeInt(VERSION_UID_WITH_SET);
1365
1366            out.writeInt(keysByIdent.size());
1367            for (NetworkIdentitySet ident : keysByIdent.keySet()) {
1368                final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
1369                ident.writeToStream(out);
1370
1371                out.writeInt(keys.size());
1372                for (UidStatsKey key : keys) {
1373                    final NetworkStatsHistory history = mUidStats.get(key);
1374                    out.writeInt(key.uid);
1375                    out.writeInt(key.set);
1376                    out.writeInt(key.tag);
1377                    history.writeToStream(out);
1378                }
1379            }
1380
1381            out.flush();
1382            mUidFile.finishWrite(fos);
1383        } catch (IOException e) {
1384            Log.wtf(TAG, "problem writing stats", e);
1385            if (fos != null) {
1386                mUidFile.failWrite(fos);
1387            }
1388        }
1389    }
1390
1391    @Override
1392    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1393        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1394
1395        final HashSet<String> argSet = new HashSet<String>();
1396        for (String arg : args) {
1397            argSet.add(arg);
1398        }
1399
1400        final boolean fullHistory = argSet.contains("full");
1401
1402        synchronized (mStatsLock) {
1403            // TODO: remove this testing code, since it corrupts stats
1404            if (argSet.contains("generate")) {
1405                generateRandomLocked(args);
1406                pw.println("Generated stub stats");
1407                return;
1408            }
1409
1410            if (argSet.contains("poll")) {
1411                performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
1412                pw.println("Forced poll");
1413                return;
1414            }
1415
1416            pw.println("Active interfaces:");
1417            for (String iface : mActiveIfaces.keySet()) {
1418                final NetworkIdentitySet ident = mActiveIfaces.get(iface);
1419                pw.print("  iface="); pw.print(iface);
1420                pw.print(" ident="); pw.println(ident.toString());
1421            }
1422
1423            pw.println("Known historical dev stats:");
1424            for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) {
1425                final NetworkStatsHistory history = mNetworkDevStats.get(ident);
1426                pw.print("  ident="); pw.println(ident.toString());
1427                history.dump("  ", pw, fullHistory);
1428            }
1429
1430            pw.println("Known historical xt stats:");
1431            for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) {
1432                final NetworkStatsHistory history = mNetworkXtStats.get(ident);
1433                pw.print("  ident="); pw.println(ident.toString());
1434                history.dump("  ", pw, fullHistory);
1435            }
1436
1437            if (argSet.contains("detail")) {
1438                // since explicitly requested with argument, we're okay to load
1439                // from disk if not already in memory.
1440                ensureUidStatsLoadedLocked();
1441
1442                final ArrayList<UidStatsKey> keys = Lists.newArrayList();
1443                keys.addAll(mUidStats.keySet());
1444                Collections.sort(keys);
1445
1446                pw.println("Detailed UID stats:");
1447                for (UidStatsKey key : keys) {
1448                    pw.print("  ident="); pw.print(key.ident.toString());
1449                    pw.print(" uid="); pw.print(key.uid);
1450                    pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
1451                    pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
1452
1453                    final NetworkStatsHistory history = mUidStats.get(key);
1454                    history.dump("    ", pw, fullHistory);
1455                }
1456            }
1457        }
1458    }
1459
1460    /**
1461     * @deprecated only for temporary testing
1462     */
1463    @Deprecated
1464    private void generateRandomLocked(String[] args) {
1465        final long totalBytes = Long.parseLong(args[1]);
1466        final long totalTime = Long.parseLong(args[2]);
1467
1468        final PackageManager pm = mContext.getPackageManager();
1469        final ArrayList<Integer> specialUidList = Lists.newArrayList();
1470        for (int i = 3; i < args.length; i++) {
1471            try {
1472                specialUidList.add(pm.getApplicationInfo(args[i], 0).uid);
1473            } catch (NameNotFoundException e) {
1474                throw new RuntimeException(e);
1475            }
1476        }
1477
1478        final HashSet<Integer> otherUidSet = Sets.newHashSet();
1479        for (ApplicationInfo info : pm.getInstalledApplications(0)) {
1480            if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName)
1481                    == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) {
1482                otherUidSet.add(info.uid);
1483            }
1484        }
1485
1486        final ArrayList<Integer> otherUidList = new ArrayList<Integer>(otherUidSet);
1487
1488        final long end = System.currentTimeMillis();
1489        final long start = end - totalTime;
1490
1491        mNetworkDevStats.clear();
1492        mNetworkXtStats.clear();
1493        mUidStats.clear();
1494
1495        final Random r = new Random();
1496        for (NetworkIdentitySet ident : mActiveIfaces.values()) {
1497            final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident);
1498            final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident);
1499
1500            final ArrayList<Integer> uidList = new ArrayList<Integer>();
1501            uidList.addAll(specialUidList);
1502
1503            if (uidList.size() == 0) {
1504                Collections.shuffle(otherUidList);
1505                uidList.addAll(otherUidList);
1506            }
1507
1508            boolean first = true;
1509            long remainingBytes = totalBytes;
1510            for (int uid : uidList) {
1511                final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked(
1512                        ident, uid, SET_DEFAULT, TAG_NONE);
1513                final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked(
1514                        ident, uid, SET_FOREGROUND, TAG_NONE);
1515
1516                final long uidBytes = totalBytes / uidList.size();
1517
1518                final float fractionDefault = r.nextFloat();
1519                final long defaultBytes = (long) (uidBytes * fractionDefault);
1520                final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault));
1521
1522                defaultHistory.generateRandom(start, end, defaultBytes);
1523                foregroundHistory.generateRandom(start, end, foregroundBytes);
1524
1525                if (first) {
1526                    final long bumpTime = (start + end) / 2;
1527                    defaultHistory.recordData(
1528                            bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0);
1529                    first = false;
1530                }
1531
1532                devHistory.recordEntireHistory(defaultHistory);
1533                devHistory.recordEntireHistory(foregroundHistory);
1534                xtHistory.recordEntireHistory(defaultHistory);
1535                xtHistory.recordEntireHistory(foregroundHistory);
1536            }
1537        }
1538    }
1539
1540    /**
1541     * Return the delta between two {@link NetworkStats} snapshots, where {@code
1542     * before} can be {@code null}.
1543     */
1544    private NetworkStats computeStatsDelta(
1545            NetworkStats before, NetworkStats current, boolean collectStale, String type) {
1546        if (before != null) {
1547            try {
1548                return current.subtract(before, false);
1549            } catch (NonMonotonicException e) {
1550                Log.w(TAG, "found non-monotonic values; saving to dropbox");
1551
1552                // record error for debugging
1553                final StringBuilder builder = new StringBuilder();
1554                builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex
1555                        + "] - right[" + e.rightIndex + "]\n");
1556                builder.append("left=").append(e.left).append('\n');
1557                builder.append("right=").append(e.right).append('\n');
1558                mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
1559
1560                try {
1561                    // return clamped delta to help recover
1562                    return current.subtract(before, true);
1563                } catch (NonMonotonicException e1) {
1564                    Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
1565                    return new NetworkStats(0L, 10);
1566                }
1567            }
1568        } else if (collectStale) {
1569            // caller is okay collecting stale stats for first call.
1570            return current;
1571        } else {
1572            // this is first snapshot; to prevent from double-counting we only
1573            // observe traffic occuring between known snapshots.
1574            return new NetworkStats(0L, 10);
1575        }
1576    }
1577
1578    /**
1579     * Return snapshot of current tethering statistics. Will return empty
1580     * {@link NetworkStats} if any problems are encountered.
1581     */
1582    private NetworkStats getNetworkStatsTethering() throws RemoteException {
1583        try {
1584            final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
1585            return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
1586        } catch (IllegalStateException e) {
1587            Log.wtf(TAG, "problem reading network stats", e);
1588            return new NetworkStats(0L, 10);
1589        }
1590    }
1591
1592    private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
1593        return uidSnapshot.groupedByIface();
1594    }
1595
1596    private int estimateNetworkBuckets() {
1597        return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
1598    }
1599
1600    private int estimateUidBuckets() {
1601        return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
1602    }
1603
1604    private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
1605        return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
1606    }
1607
1608    /**
1609     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
1610     * in the given {@link NetworkIdentitySet}.
1611     */
1612    private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
1613        for (NetworkIdentity ident : identSet) {
1614            if (template.matches(ident)) {
1615                return true;
1616            }
1617        }
1618        return false;
1619    }
1620
1621    private Handler.Callback mHandlerCallback = new Handler.Callback() {
1622        /** {@inheritDoc} */
1623        public boolean handleMessage(Message msg) {
1624            switch (msg.what) {
1625                case MSG_PERFORM_POLL: {
1626                    final int flags = msg.arg1;
1627                    performPoll(flags);
1628                    return true;
1629                }
1630                case MSG_UPDATE_IFACES: {
1631                    updateIfaces();
1632                    return true;
1633                }
1634                default: {
1635                    return false;
1636                }
1637            }
1638        }
1639    };
1640
1641    private static String getActiveSubscriberId(Context context) {
1642        final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
1643                Context.TELEPHONY_SERVICE);
1644        return telephony.getSubscriberId();
1645    }
1646
1647    /**
1648     * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
1649     */
1650    private static class UidStatsKey implements Comparable<UidStatsKey> {
1651        public final NetworkIdentitySet ident;
1652        public final int uid;
1653        public final int set;
1654        public final int tag;
1655
1656        public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
1657            this.ident = ident;
1658            this.uid = uid;
1659            this.set = set;
1660            this.tag = tag;
1661        }
1662
1663        @Override
1664        public int hashCode() {
1665            return Objects.hashCode(ident, uid, set, tag);
1666        }
1667
1668        @Override
1669        public boolean equals(Object obj) {
1670            if (obj instanceof UidStatsKey) {
1671                final UidStatsKey key = (UidStatsKey) obj;
1672                return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
1673                        && tag == key.tag;
1674            }
1675            return false;
1676        }
1677
1678        /** {@inheritDoc} */
1679        public int compareTo(UidStatsKey another) {
1680            return Integer.compare(uid, another.uid);
1681        }
1682    }
1683
1684    /**
1685     * Default external settings that read from {@link Settings.Secure}.
1686     */
1687    private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
1688        private final ContentResolver mResolver;
1689
1690        public DefaultNetworkStatsSettings(Context context) {
1691            mResolver = checkNotNull(context.getContentResolver());
1692            // TODO: adjust these timings for production builds
1693        }
1694
1695        private long getSecureLong(String name, long def) {
1696            return Settings.Secure.getLong(mResolver, name, def);
1697        }
1698        private boolean getSecureBoolean(String name, boolean def) {
1699            final int defInt = def ? 1 : 0;
1700            return Settings.Secure.getInt(mResolver, name, defInt) != 0;
1701        }
1702
1703        public long getPollInterval() {
1704            return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
1705        }
1706        public long getPersistThreshold() {
1707            return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
1708        }
1709        public long getNetworkBucketDuration() {
1710            return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
1711        }
1712        public long getNetworkMaxHistory() {
1713            return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
1714        }
1715        public long getUidBucketDuration() {
1716            return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
1717        }
1718        public long getUidMaxHistory() {
1719            return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
1720        }
1721        public long getTagMaxHistory() {
1722            return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
1723        }
1724        public long getTimeCacheMaxAge() {
1725            return DAY_IN_MILLIS;
1726        }
1727    }
1728}
1729