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