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