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