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.NetworkTemplate.buildTemplateMobileAll;
     36 import static android.net.NetworkTemplate.buildTemplateWifi;
     37 import static android.net.TrafficStats.UID_REMOVED;
     38 import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
     39 import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
     40 import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
     41 import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
     42 import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
     43 import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
     44 import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
     45 import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
     46 import static android.telephony.PhoneStateListener.LISTEN_NONE;
     47 import static android.text.format.DateUtils.DAY_IN_MILLIS;
     48 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
     49 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
     50 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
     51 import static com.android.internal.util.Preconditions.checkNotNull;
     52 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
     53 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
     54 import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
     55 
     56 import android.app.AlarmManager;
     57 import android.app.IAlarmManager;
     58 import android.app.PendingIntent;
     59 import android.content.BroadcastReceiver;
     60 import android.content.ContentResolver;
     61 import android.content.Context;
     62 import android.content.Intent;
     63 import android.content.IntentFilter;
     64 import android.content.pm.ApplicationInfo;
     65 import android.content.pm.PackageManager;
     66 import android.content.pm.PackageManager.NameNotFoundException;
     67 import android.net.IConnectivityManager;
     68 import android.net.INetworkManagementEventObserver;
     69 import android.net.INetworkStatsService;
     70 import android.net.NetworkIdentity;
     71 import android.net.NetworkInfo;
     72 import android.net.NetworkState;
     73 import android.net.NetworkStats;
     74 import android.net.NetworkStats.NonMonotonicException;
     75 import android.net.NetworkStatsHistory;
     76 import android.net.NetworkTemplate;
     77 import android.os.Binder;
     78 import android.os.DropBoxManager;
     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 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         if (mLastPollUidSnapshot != null) {
   1064             mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
   1065             mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
   1066         }
   1067 
   1068         // clear kernel stats associated with UID
   1069         resetKernelUidStats(uid);
   1070 
   1071         // since this was radical rewrite, push to disk
   1072         writeUidStatsLocked();
   1073     }
   1074 
   1075     private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) {
   1076         return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats);
   1077     }
   1078 
   1079     private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) {
   1080         return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats);
   1081     }
   1082 
   1083     private NetworkStatsHistory findOrCreateNetworkStatsLocked(
   1084             NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
   1085         final NetworkStatsHistory existing = source.get(ident);
   1086 
   1087         // update when no existing, or when bucket duration changed
   1088         final long bucketDuration = mSettings.getNetworkBucketDuration();
   1089         NetworkStatsHistory updated = null;
   1090         if (existing == null) {
   1091             updated = new NetworkStatsHistory(bucketDuration, 10);
   1092         } else if (existing.getBucketDuration() != bucketDuration) {
   1093             updated = new NetworkStatsHistory(
   1094                     bucketDuration, estimateResizeBuckets(existing, bucketDuration));
   1095             updated.recordEntireHistory(existing);
   1096         }
   1097 
   1098         if (updated != null) {
   1099             source.put(ident, updated);
   1100             return updated;
   1101         } else {
   1102             return existing;
   1103         }
   1104     }
   1105 
   1106     private NetworkStatsHistory findOrCreateUidStatsLocked(
   1107             NetworkIdentitySet ident, int uid, int set, int tag) {
   1108         ensureUidStatsLoadedLocked();
   1109 
   1110         final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
   1111         final NetworkStatsHistory existing = mUidStats.get(key);
   1112 
   1113         // update when no existing, or when bucket duration changed
   1114         final long bucketDuration = mSettings.getUidBucketDuration();
   1115         NetworkStatsHistory updated = null;
   1116         if (existing == null) {
   1117             updated = new NetworkStatsHistory(bucketDuration, 10);
   1118         } else if (existing.getBucketDuration() != bucketDuration) {
   1119             updated = new NetworkStatsHistory(
   1120                     bucketDuration, estimateResizeBuckets(existing, bucketDuration));
   1121             updated.recordEntireHistory(existing);
   1122         }
   1123 
   1124         if (updated != null) {
   1125             mUidStats.put(key, updated);
   1126             return updated;
   1127         } else {
   1128             return existing;
   1129         }
   1130     }
   1131 
   1132     private void readNetworkDevStatsLocked() {
   1133         if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()");
   1134         readNetworkStats(mNetworkDevFile, mNetworkDevStats);
   1135     }
   1136 
   1137     private void readNetworkXtStatsLocked() {
   1138         if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()");
   1139         readNetworkStats(mNetworkXtFile, mNetworkXtStats);
   1140     }
   1141 
   1142     private static void readNetworkStats(
   1143             AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output) {
   1144         // clear any existing stats and read from disk
   1145         output.clear();
   1146 
   1147         DataInputStream in = null;
   1148         try {
   1149             in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
   1150 
   1151             // verify file magic header intact
   1152             final int magic = in.readInt();
   1153             if (magic != FILE_MAGIC) {
   1154                 throw new ProtocolException("unexpected magic: " + magic);
   1155             }
   1156 
   1157             final int version = in.readInt();
   1158             switch (version) {
   1159                 case VERSION_NETWORK_INIT: {
   1160                     // network := size *(NetworkIdentitySet NetworkStatsHistory)
   1161                     final int size = in.readInt();
   1162                     for (int i = 0; i < size; i++) {
   1163                         final NetworkIdentitySet ident = new NetworkIdentitySet(in);
   1164                         final NetworkStatsHistory history = new NetworkStatsHistory(in);
   1165                         output.put(ident, history);
   1166                     }
   1167                     break;
   1168                 }
   1169                 default: {
   1170                     throw new ProtocolException("unexpected version: " + version);
   1171                 }
   1172             }
   1173         } catch (FileNotFoundException e) {
   1174             // missing stats is okay, probably first boot
   1175         } catch (IOException e) {
   1176             Log.wtf(TAG, "problem reading network stats", e);
   1177         } finally {
   1178             IoUtils.closeQuietly(in);
   1179         }
   1180     }
   1181 
   1182     private void ensureUidStatsLoadedLocked() {
   1183         if (!mUidStatsLoaded) {
   1184             readUidStatsLocked();
   1185             mUidStatsLoaded = true;
   1186         }
   1187     }
   1188 
   1189     private void readUidStatsLocked() {
   1190         if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
   1191 
   1192         // clear any existing stats and read from disk
   1193         mUidStats.clear();
   1194 
   1195         DataInputStream in = null;
   1196         try {
   1197             in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
   1198 
   1199             // verify file magic header intact
   1200             final int magic = in.readInt();
   1201             if (magic != FILE_MAGIC) {
   1202                 throw new ProtocolException("unexpected magic: " + magic);
   1203             }
   1204 
   1205             final int version = in.readInt();
   1206             switch (version) {
   1207                 case VERSION_UID_INIT: {
   1208                     // uid := size *(UID NetworkStatsHistory)
   1209 
   1210                     // drop this data version, since we don't have a good
   1211                     // mapping into NetworkIdentitySet.
   1212                     break;
   1213                 }
   1214                 case VERSION_UID_WITH_IDENT: {
   1215                     // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
   1216 
   1217                     // drop this data version, since this version only existed
   1218                     // for a short time.
   1219                     break;
   1220                 }
   1221                 case VERSION_UID_WITH_TAG:
   1222                 case VERSION_UID_WITH_SET: {
   1223                     // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
   1224                     final int identSize = in.readInt();
   1225                     for (int i = 0; i < identSize; i++) {
   1226                         final NetworkIdentitySet ident = new NetworkIdentitySet(in);
   1227 
   1228                         final int size = in.readInt();
   1229                         for (int j = 0; j < size; j++) {
   1230                             final int uid = in.readInt();
   1231                             final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
   1232                                     : SET_DEFAULT;
   1233                             final int tag = in.readInt();
   1234 
   1235                             final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
   1236                             final NetworkStatsHistory history = new NetworkStatsHistory(in);
   1237                             mUidStats.put(key, history);
   1238                         }
   1239                     }
   1240                     break;
   1241                 }
   1242                 default: {
   1243                     throw new ProtocolException("unexpected version: " + version);
   1244                 }
   1245             }
   1246         } catch (FileNotFoundException e) {
   1247             // missing stats is okay, probably first boot
   1248         } catch (IOException e) {
   1249             Log.wtf(TAG, "problem reading uid stats", e);
   1250         } finally {
   1251             IoUtils.closeQuietly(in);
   1252         }
   1253     }
   1254 
   1255     private void writeNetworkDevStatsLocked() {
   1256         if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()");
   1257         writeNetworkStats(mNetworkDevStats, mNetworkDevFile);
   1258     }
   1259 
   1260     private void writeNetworkXtStatsLocked() {
   1261         if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()");
   1262         writeNetworkStats(mNetworkXtStats, mNetworkXtFile);
   1263     }
   1264 
   1265     private void writeNetworkStats(
   1266             HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile) {
   1267         // TODO: consider duplicating stats and releasing lock while writing
   1268 
   1269         // trim any history beyond max
   1270         if (mTime.hasCache()) {
   1271             final long systemCurrentTime = System.currentTimeMillis();
   1272             final long trustedCurrentTime = mTime.currentTimeMillis();
   1273 
   1274             final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime);
   1275             final long maxHistory = mSettings.getNetworkMaxHistory();
   1276 
   1277             for (NetworkStatsHistory history : input.values()) {
   1278                 final int beforeSize = history.size();
   1279                 history.removeBucketsBefore(currentTime - maxHistory);
   1280                 final int afterSize = history.size();
   1281 
   1282                 if (beforeSize > 24 && afterSize < beforeSize / 2) {
   1283                     // yikes, dropping more than half of significant history
   1284                     final StringBuilder builder = new StringBuilder();
   1285                     builder.append("yikes, dropping more than half of history").append('\n');
   1286                     builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n');
   1287                     builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n');
   1288                     builder.append("maxHistory=").append(maxHistory).append('\n');
   1289                     builder.append("beforeSize=").append(beforeSize).append('\n');
   1290                     builder.append("afterSize=").append(afterSize).append('\n');
   1291                     mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
   1292                 }
   1293             }
   1294         }
   1295 
   1296         FileOutputStream fos = null;
   1297         try {
   1298             fos = outputFile.startWrite();
   1299             final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
   1300 
   1301             out.writeInt(FILE_MAGIC);
   1302             out.writeInt(VERSION_NETWORK_INIT);
   1303 
   1304             out.writeInt(input.size());
   1305             for (NetworkIdentitySet ident : input.keySet()) {
   1306                 final NetworkStatsHistory history = input.get(ident);
   1307                 ident.writeToStream(out);
   1308                 history.writeToStream(out);
   1309             }
   1310 
   1311             out.flush();
   1312             outputFile.finishWrite(fos);
   1313         } catch (IOException e) {
   1314             Log.wtf(TAG, "problem writing stats", e);
   1315             if (fos != null) {
   1316                 outputFile.failWrite(fos);
   1317             }
   1318         }
   1319     }
   1320 
   1321     private void writeUidStatsLocked() {
   1322         if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
   1323 
   1324         if (!mUidStatsLoaded) {
   1325             Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
   1326             return;
   1327         }
   1328 
   1329         // TODO: consider duplicating stats and releasing lock while writing
   1330 
   1331         // trim any history beyond max
   1332         if (mTime.hasCache()) {
   1333             final long currentTime = Math.min(
   1334                     System.currentTimeMillis(), mTime.currentTimeMillis());
   1335             final long maxUidHistory = mSettings.getUidMaxHistory();
   1336             final long maxTagHistory = mSettings.getTagMaxHistory();
   1337             for (UidStatsKey key : mUidStats.keySet()) {
   1338                 final NetworkStatsHistory history = mUidStats.get(key);
   1339 
   1340                 // detailed tags are trimmed sooner than summary in TAG_NONE
   1341                 if (key.tag == TAG_NONE) {
   1342                     history.removeBucketsBefore(currentTime - maxUidHistory);
   1343                 } else {
   1344                     history.removeBucketsBefore(currentTime - maxTagHistory);
   1345                 }
   1346             }
   1347         }
   1348 
   1349         // build UidStatsKey lists grouped by ident
   1350         final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
   1351         for (UidStatsKey key : mUidStats.keySet()) {
   1352             ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
   1353             if (keys == null) {
   1354                 keys = Lists.newArrayList();
   1355                 keysByIdent.put(key.ident, keys);
   1356             }
   1357             keys.add(key);
   1358         }
   1359 
   1360         FileOutputStream fos = null;
   1361         try {
   1362             fos = mUidFile.startWrite();
   1363             final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
   1364 
   1365             out.writeInt(FILE_MAGIC);
   1366             out.writeInt(VERSION_UID_WITH_SET);
   1367 
   1368             out.writeInt(keysByIdent.size());
   1369             for (NetworkIdentitySet ident : keysByIdent.keySet()) {
   1370                 final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
   1371                 ident.writeToStream(out);
   1372 
   1373                 out.writeInt(keys.size());
   1374                 for (UidStatsKey key : keys) {
   1375                     final NetworkStatsHistory history = mUidStats.get(key);
   1376                     out.writeInt(key.uid);
   1377                     out.writeInt(key.set);
   1378                     out.writeInt(key.tag);
   1379                     history.writeToStream(out);
   1380                 }
   1381             }
   1382 
   1383             out.flush();
   1384             mUidFile.finishWrite(fos);
   1385         } catch (IOException e) {
   1386             Log.wtf(TAG, "problem writing stats", e);
   1387             if (fos != null) {
   1388                 mUidFile.failWrite(fos);
   1389             }
   1390         }
   1391     }
   1392 
   1393     @Override
   1394     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1395         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
   1396 
   1397         final HashSet<String> argSet = new HashSet<String>();
   1398         for (String arg : args) {
   1399             argSet.add(arg);
   1400         }
   1401 
   1402         final boolean fullHistory = argSet.contains("full");
   1403 
   1404         synchronized (mStatsLock) {
   1405             // TODO: remove this testing code, since it corrupts stats
   1406             if (argSet.contains("generate")) {
   1407                 generateRandomLocked(args);
   1408                 pw.println("Generated stub stats");
   1409                 return;
   1410             }
   1411 
   1412             if (argSet.contains("poll")) {
   1413                 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
   1414                 pw.println("Forced poll");
   1415                 return;
   1416             }
   1417 
   1418             pw.println("Active interfaces:");
   1419             for (String iface : mActiveIfaces.keySet()) {
   1420                 final NetworkIdentitySet ident = mActiveIfaces.get(iface);
   1421                 pw.print("  iface="); pw.print(iface);
   1422                 pw.print(" ident="); pw.println(ident.toString());
   1423             }
   1424 
   1425             pw.println("Known historical dev stats:");
   1426             for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) {
   1427                 final NetworkStatsHistory history = mNetworkDevStats.get(ident);
   1428                 pw.print("  ident="); pw.println(ident.toString());
   1429                 history.dump("  ", pw, fullHistory);
   1430             }
   1431 
   1432             pw.println("Known historical xt stats:");
   1433             for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) {
   1434                 final NetworkStatsHistory history = mNetworkXtStats.get(ident);
   1435                 pw.print("  ident="); pw.println(ident.toString());
   1436                 history.dump("  ", pw, fullHistory);
   1437             }
   1438 
   1439             if (argSet.contains("detail")) {
   1440                 // since explicitly requested with argument, we're okay to load
   1441                 // from disk if not already in memory.
   1442                 ensureUidStatsLoadedLocked();
   1443 
   1444                 final ArrayList<UidStatsKey> keys = Lists.newArrayList();
   1445                 keys.addAll(mUidStats.keySet());
   1446                 Collections.sort(keys);
   1447 
   1448                 pw.println("Detailed UID stats:");
   1449                 for (UidStatsKey key : keys) {
   1450                     pw.print("  ident="); pw.print(key.ident.toString());
   1451                     pw.print(" uid="); pw.print(key.uid);
   1452                     pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
   1453                     pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
   1454 
   1455                     final NetworkStatsHistory history = mUidStats.get(key);
   1456                     history.dump("    ", pw, fullHistory);
   1457                 }
   1458             }
   1459         }
   1460     }
   1461 
   1462     /**
   1463      * @deprecated only for temporary testing
   1464      */
   1465     @Deprecated
   1466     private void generateRandomLocked(String[] args) {
   1467         final long totalBytes = Long.parseLong(args[1]);
   1468         final long totalTime = Long.parseLong(args[2]);
   1469 
   1470         final PackageManager pm = mContext.getPackageManager();
   1471         final ArrayList<Integer> specialUidList = Lists.newArrayList();
   1472         for (int i = 3; i < args.length; i++) {
   1473             try {
   1474                 specialUidList.add(pm.getApplicationInfo(args[i], 0).uid);
   1475             } catch (NameNotFoundException e) {
   1476                 throw new RuntimeException(e);
   1477             }
   1478         }
   1479 
   1480         final HashSet<Integer> otherUidSet = Sets.newHashSet();
   1481         for (ApplicationInfo info : pm.getInstalledApplications(0)) {
   1482             if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName)
   1483                     == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) {
   1484                 otherUidSet.add(info.uid);
   1485             }
   1486         }
   1487 
   1488         final ArrayList<Integer> otherUidList = new ArrayList<Integer>(otherUidSet);
   1489 
   1490         final long end = System.currentTimeMillis();
   1491         final long start = end - totalTime;
   1492 
   1493         mNetworkDevStats.clear();
   1494         mNetworkXtStats.clear();
   1495         mUidStats.clear();
   1496 
   1497         final Random r = new Random();
   1498         for (NetworkIdentitySet ident : mActiveIfaces.values()) {
   1499             final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident);
   1500             final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident);
   1501 
   1502             final ArrayList<Integer> uidList = new ArrayList<Integer>();
   1503             uidList.addAll(specialUidList);
   1504 
   1505             if (uidList.size() == 0) {
   1506                 Collections.shuffle(otherUidList);
   1507                 uidList.addAll(otherUidList);
   1508             }
   1509 
   1510             boolean first = true;
   1511             long remainingBytes = totalBytes;
   1512             for (int uid : uidList) {
   1513                 final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked(
   1514                         ident, uid, SET_DEFAULT, TAG_NONE);
   1515                 final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked(
   1516                         ident, uid, SET_FOREGROUND, TAG_NONE);
   1517 
   1518                 final long uidBytes = totalBytes / uidList.size();
   1519 
   1520                 final float fractionDefault = r.nextFloat();
   1521                 final long defaultBytes = (long) (uidBytes * fractionDefault);
   1522                 final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault));
   1523 
   1524                 defaultHistory.generateRandom(start, end, defaultBytes);
   1525                 foregroundHistory.generateRandom(start, end, foregroundBytes);
   1526 
   1527                 if (first) {
   1528                     final long bumpTime = (start + end) / 2;
   1529                     defaultHistory.recordData(
   1530                             bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0);
   1531                     first = false;
   1532                 }
   1533 
   1534                 devHistory.recordEntireHistory(defaultHistory);
   1535                 devHistory.recordEntireHistory(foregroundHistory);
   1536                 xtHistory.recordEntireHistory(defaultHistory);
   1537                 xtHistory.recordEntireHistory(foregroundHistory);
   1538             }
   1539         }
   1540     }
   1541 
   1542     /**
   1543      * Return the delta between two {@link NetworkStats} snapshots, where {@code
   1544      * before} can be {@code null}.
   1545      */
   1546     private NetworkStats computeStatsDelta(
   1547             NetworkStats before, NetworkStats current, boolean collectStale, String type) {
   1548         if (before != null) {
   1549             try {
   1550                 return current.subtract(before, false);
   1551             } catch (NonMonotonicException e) {
   1552                 Log.w(TAG, "found non-monotonic values; saving to dropbox");
   1553 
   1554                 // record error for debugging
   1555                 final StringBuilder builder = new StringBuilder();
   1556                 builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex
   1557                         + "] - right[" + e.rightIndex + "]\n");
   1558                 builder.append("left=").append(e.left).append('\n');
   1559                 builder.append("right=").append(e.right).append('\n');
   1560                 mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
   1561 
   1562                 try {
   1563                     // return clamped delta to help recover
   1564                     return current.subtract(before, true);
   1565                 } catch (NonMonotonicException e1) {
   1566                     Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
   1567                     return new NetworkStats(0L, 10);
   1568                 }
   1569             }
   1570         } else if (collectStale) {
   1571             // caller is okay collecting stale stats for first call.
   1572             return current;
   1573         } else {
   1574             // this is first snapshot; to prevent from double-counting we only
   1575             // observe traffic occuring between known snapshots.
   1576             return new NetworkStats(0L, 10);
   1577         }
   1578     }
   1579 
   1580     /**
   1581      * Return snapshot of current tethering statistics. Will return empty
   1582      * {@link NetworkStats} if any problems are encountered.
   1583      */
   1584     private NetworkStats getNetworkStatsTethering() throws RemoteException {
   1585         try {
   1586             final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
   1587             return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
   1588         } catch (IllegalStateException e) {
   1589             Log.wtf(TAG, "problem reading network stats", e);
   1590             return new NetworkStats(0L, 10);
   1591         }
   1592     }
   1593 
   1594     private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
   1595         return uidSnapshot.groupedByIface();
   1596     }
   1597 
   1598     private int estimateNetworkBuckets() {
   1599         return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
   1600     }
   1601 
   1602     private int estimateUidBuckets() {
   1603         return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
   1604     }
   1605 
   1606     private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
   1607         return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
   1608     }
   1609 
   1610     /**
   1611      * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
   1612      * in the given {@link NetworkIdentitySet}.
   1613      */
   1614     private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
   1615         for (NetworkIdentity ident : identSet) {
   1616             if (template.matches(ident)) {
   1617                 return true;
   1618             }
   1619         }
   1620         return false;
   1621     }
   1622 
   1623     private Handler.Callback mHandlerCallback = new Handler.Callback() {
   1624         /** {@inheritDoc} */
   1625         public boolean handleMessage(Message msg) {
   1626             switch (msg.what) {
   1627                 case MSG_PERFORM_POLL: {
   1628                     final int flags = msg.arg1;
   1629                     performPoll(flags);
   1630                     return true;
   1631                 }
   1632                 case MSG_UPDATE_IFACES: {
   1633                     updateIfaces();
   1634                     return true;
   1635                 }
   1636                 default: {
   1637                     return false;
   1638                 }
   1639             }
   1640         }
   1641     };
   1642 
   1643     private static String getActiveSubscriberId(Context context) {
   1644         final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
   1645                 Context.TELEPHONY_SERVICE);
   1646         return telephony.getSubscriberId();
   1647     }
   1648 
   1649     /**
   1650      * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
   1651      */
   1652     private static class UidStatsKey implements Comparable<UidStatsKey> {
   1653         public final NetworkIdentitySet ident;
   1654         public final int uid;
   1655         public final int set;
   1656         public final int tag;
   1657 
   1658         public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
   1659             this.ident = ident;
   1660             this.uid = uid;
   1661             this.set = set;
   1662             this.tag = tag;
   1663         }
   1664 
   1665         @Override
   1666         public int hashCode() {
   1667             return Objects.hashCode(ident, uid, set, tag);
   1668         }
   1669 
   1670         @Override
   1671         public boolean equals(Object obj) {
   1672             if (obj instanceof UidStatsKey) {
   1673                 final UidStatsKey key = (UidStatsKey) obj;
   1674                 return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
   1675                         && tag == key.tag;
   1676             }
   1677             return false;
   1678         }
   1679 
   1680         /** {@inheritDoc} */
   1681         public int compareTo(UidStatsKey another) {
   1682             return Integer.compare(uid, another.uid);
   1683         }
   1684     }
   1685 
   1686     /**
   1687      * Default external settings that read from {@link Settings.Secure}.
   1688      */
   1689     private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
   1690         private final ContentResolver mResolver;
   1691 
   1692         public DefaultNetworkStatsSettings(Context context) {
   1693             mResolver = checkNotNull(context.getContentResolver());
   1694             // TODO: adjust these timings for production builds
   1695         }
   1696 
   1697         private long getSecureLong(String name, long def) {
   1698             return Settings.Secure.getLong(mResolver, name, def);
   1699         }
   1700         private boolean getSecureBoolean(String name, boolean def) {
   1701             final int defInt = def ? 1 : 0;
   1702             return Settings.Secure.getInt(mResolver, name, defInt) != 0;
   1703         }
   1704 
   1705         public long getPollInterval() {
   1706             return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
   1707         }
   1708         public long getPersistThreshold() {
   1709             return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
   1710         }
   1711         public long getNetworkBucketDuration() {
   1712             return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
   1713         }
   1714         public long getNetworkMaxHistory() {
   1715             return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
   1716         }
   1717         public long getUidBucketDuration() {
   1718             return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
   1719         }
   1720         public long getUidMaxHistory() {
   1721             return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
   1722         }
   1723         public long getTagMaxHistory() {
   1724             return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
   1725         }
   1726         public long getTimeCacheMaxAge() {
   1727             return DAY_IN_MILLIS;
   1728         }
   1729     }
   1730 }
   1731