NetworkStats.java revision 786b7ad2604709b63dac4675a0477b58c7532068
1/** 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17package android.app.usage; 18 19import android.annotation.IntDef; 20import android.content.Context; 21import android.net.INetworkStatsService; 22import android.net.INetworkStatsSession; 23import android.net.NetworkStatsHistory; 24import android.net.NetworkTemplate; 25import android.net.TrafficStats; 26import android.os.RemoteException; 27import android.util.IntArray; 28import android.util.Log; 29 30import dalvik.system.CloseGuard; 31 32import java.lang.annotation.Retention; 33import java.lang.annotation.RetentionPolicy; 34 35/** 36 * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects 37 * are returned as results to various queries in {@link NetworkStatsManager}. 38 */ 39public final class NetworkStats implements AutoCloseable { 40 private final static String TAG = "NetworkStats"; 41 42 private final CloseGuard mCloseGuard = CloseGuard.get(); 43 44 /** 45 * Start timestamp of stats collected 46 */ 47 private final long mStartTimeStamp; 48 49 /** 50 * End timestamp of stats collected 51 */ 52 private final long mEndTimeStamp; 53 54 /** 55 * Non-null array indicates the query enumerates over uids. 56 */ 57 private int[] mUids; 58 59 /** 60 * Index of the current uid in mUids when doing uid enumeration or a single uid value, 61 * depending on query type. 62 */ 63 private int mUidOrUidIndex; 64 65 /** 66 * Tag id in case if was specified in the query. 67 */ 68 private int mTag = android.net.NetworkStats.TAG_NONE; 69 70 /** 71 * The session while the query requires it, null if all the stats have been collected or close() 72 * has been called. 73 */ 74 private INetworkStatsSession mSession; 75 private NetworkTemplate mTemplate; 76 77 /** 78 * Results of a summary query. 79 */ 80 private android.net.NetworkStats mSummary = null; 81 82 /** 83 * Results of detail queries. 84 */ 85 private NetworkStatsHistory mHistory = null; 86 87 /** 88 * Where we are in enumerating over the current result. 89 */ 90 private int mEnumerationIndex = 0; 91 92 /** 93 * Recycling entry objects to prevent heap fragmentation. 94 */ 95 private android.net.NetworkStats.Entry mRecycledSummaryEntry = null; 96 private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; 97 98 /** @hide */ 99 NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp, 100 long endTimestamp, INetworkStatsService statsService) 101 throws RemoteException, SecurityException { 102 // Open network stats session 103 mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName()); 104 mCloseGuard.open("close"); 105 mTemplate = template; 106 mStartTimeStamp = startTimestamp; 107 mEndTimeStamp = endTimestamp; 108 } 109 110 @Override 111 protected void finalize() throws Throwable { 112 try { 113 if (mCloseGuard != null) { 114 mCloseGuard.warnIfOpen(); 115 } 116 close(); 117 } finally { 118 super.finalize(); 119 } 120 } 121 122 // -------------------------BEGINNING OF PUBLIC API----------------------------------- 123 124 /** 125 * Buckets are the smallest elements of a query result. As some dimensions of a result may be 126 * aggregated (e.g. time or state) some values may be equal across all buckets. 127 */ 128 public static class Bucket { 129 /** @hide */ 130 @IntDef(prefix = { "STATE_" }, value = { 131 STATE_ALL, 132 STATE_DEFAULT, 133 STATE_FOREGROUND 134 }) 135 @Retention(RetentionPolicy.SOURCE) 136 public @interface State {} 137 138 /** 139 * Combined usage across all states. 140 */ 141 public static final int STATE_ALL = -1; 142 143 /** 144 * Usage not accounted for in any other state. 145 */ 146 public static final int STATE_DEFAULT = 0x1; 147 148 /** 149 * Foreground usage. 150 */ 151 public static final int STATE_FOREGROUND = 0x2; 152 153 /** 154 * Special UID value for aggregate/unspecified. 155 */ 156 public static final int UID_ALL = android.net.NetworkStats.UID_ALL; 157 158 /** 159 * Special UID value for removed apps. 160 */ 161 public static final int UID_REMOVED = TrafficStats.UID_REMOVED; 162 163 /** 164 * Special UID value for data usage by tethering. 165 */ 166 public static final int UID_TETHERING = TrafficStats.UID_TETHERING; 167 168 /** @hide */ 169 @IntDef(prefix = { "METERED_" }, value = { 170 METERED_ALL, 171 METERED_NO, 172 METERED_YES 173 }) 174 @Retention(RetentionPolicy.SOURCE) 175 public @interface Metered {} 176 177 /** 178 * Combined usage across all metered states. Covers metered and unmetered usage. 179 */ 180 public static final int METERED_ALL = -1; 181 182 /** 183 * Usage that occurs on an unmetered network. 184 */ 185 public static final int METERED_NO = 0x1; 186 187 /** 188 * Usage that occurs on a metered network. 189 * 190 * <p>A network is classified as metered when the user is sensitive to heavy data usage on 191 * that connection. 192 */ 193 public static final int METERED_YES = 0x2; 194 195 /** @hide */ 196 @IntDef(prefix = { "ROAMING_" }, value = { 197 ROAMING_ALL, 198 ROAMING_NO, 199 ROAMING_YES 200 }) 201 @Retention(RetentionPolicy.SOURCE) 202 public @interface Roaming {} 203 204 /** 205 * Combined usage across all roaming states. Covers both roaming and non-roaming usage. 206 */ 207 public static final int ROAMING_ALL = -1; 208 209 /** 210 * Usage that occurs on a home, non-roaming network. 211 * 212 * <p>Any cellular usage in this bucket was incurred while the device was connected to a 213 * tower owned or operated by the user's wireless carrier, or a tower that the user's 214 * wireless carrier has indicated should be treated as a home network regardless. 215 * 216 * <p>This is also the default value for network types that do not support roaming. 217 */ 218 public static final int ROAMING_NO = 0x1; 219 220 /** 221 * Usage that occurs on a roaming network. 222 * 223 * <p>Any cellular usage in this bucket as incurred while the device was roaming on another 224 * carrier's network, for which additional charges may apply. 225 */ 226 public static final int ROAMING_YES = 0x2; 227 228 /** @hide */ 229 @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { 230 DEFAULT_NETWORK_ALL, 231 DEFAULT_NETWORK_NO, 232 DEFAULT_NETWORK_YES 233 }) 234 @Retention(RetentionPolicy.SOURCE) 235 public @interface DefaultNetwork {} 236 237 /** 238 * Combined usage for this network regardless of whether it was the active default network. 239 */ 240 public static final int DEFAULT_NETWORK_ALL = -1; 241 242 /** 243 * Usage that occurs while this network is not the active default network. 244 */ 245 public static final int DEFAULT_NETWORK_NO = 0x1; 246 247 /** 248 * Usage that occurs while this network is the active default network. 249 */ 250 public static final int DEFAULT_NETWORK_YES = 0x2; 251 252 /** 253 * Special TAG value for total data across all tags 254 */ 255 public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE; 256 257 private int mUid; 258 private int mTag; 259 private int mState; 260 private int mDefaultNetwork; 261 private int mMetered; 262 private int mRoaming; 263 private long mBeginTimeStamp; 264 private long mEndTimeStamp; 265 private long mRxBytes; 266 private long mRxPackets; 267 private long mTxBytes; 268 private long mTxPackets; 269 270 private static @State int convertState(int networkStatsSet) { 271 switch (networkStatsSet) { 272 case android.net.NetworkStats.SET_ALL : return STATE_ALL; 273 case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT; 274 case android.net.NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; 275 } 276 return 0; 277 } 278 279 private static int convertUid(int uid) { 280 switch (uid) { 281 case TrafficStats.UID_REMOVED: return UID_REMOVED; 282 case TrafficStats.UID_TETHERING: return UID_TETHERING; 283 } 284 return uid; 285 } 286 287 private static int convertTag(int tag) { 288 switch (tag) { 289 case android.net.NetworkStats.TAG_NONE: return TAG_NONE; 290 } 291 return tag; 292 } 293 294 private static @Metered int convertMetered(int metered) { 295 switch (metered) { 296 case android.net.NetworkStats.METERED_ALL : return METERED_ALL; 297 case android.net.NetworkStats.METERED_NO: return METERED_NO; 298 case android.net.NetworkStats.METERED_YES: return METERED_YES; 299 } 300 return 0; 301 } 302 303 private static @Roaming int convertRoaming(int roaming) { 304 switch (roaming) { 305 case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; 306 case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO; 307 case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES; 308 } 309 return 0; 310 } 311 312 private static @DefaultNetwork int convertDefaultNetwork(int defaultNetwork) { 313 switch (defaultNetwork) { 314 case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL; 315 case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO; 316 case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES; 317 } 318 return 0; 319 } 320 321 public Bucket() { 322 } 323 324 /** 325 * Key of the bucket. Usually an app uid or one of the following special values:<p /> 326 * <ul> 327 * <li>{@link #UID_REMOVED}</li> 328 * <li>{@link #UID_TETHERING}</li> 329 * <li>{@link android.os.Process#SYSTEM_UID}</li> 330 * </ul> 331 * @return Bucket key. 332 */ 333 public int getUid() { 334 return mUid; 335 } 336 337 /** 338 * Tag of the bucket.<p /> 339 * @return Bucket tag. 340 */ 341 public int getTag() { 342 return mTag; 343 } 344 345 /** 346 * Usage state. One of the following values:<p/> 347 * <ul> 348 * <li>{@link #STATE_ALL}</li> 349 * <li>{@link #STATE_DEFAULT}</li> 350 * <li>{@link #STATE_FOREGROUND}</li> 351 * </ul> 352 * @return Usage state. 353 */ 354 public @State int getState() { 355 return mState; 356 } 357 358 /** 359 * Metered state. One of the following values:<p/> 360 * <ul> 361 * <li>{@link #METERED_ALL}</li> 362 * <li>{@link #METERED_NO}</li> 363 * <li>{@link #METERED_YES}</li> 364 * </ul> 365 * <p>A network is classified as metered when the user is sensitive to heavy data usage on 366 * that connection. Apps may warn before using these networks for large downloads. The 367 * metered state can be set by the user within data usage network restrictions. 368 */ 369 public @Metered int getMetered() { 370 return mMetered; 371 } 372 373 /** 374 * Roaming state. One of the following values:<p/> 375 * <ul> 376 * <li>{@link #ROAMING_ALL}</li> 377 * <li>{@link #ROAMING_NO}</li> 378 * <li>{@link #ROAMING_YES}</li> 379 * </ul> 380 */ 381 public @Roaming int getRoaming() { 382 return mRoaming; 383 } 384 385 /** 386 * Default network state. One of the following values:<p/> 387 * <ul> 388 * <li>{@link #DEFAULT_NETWORK_ALL}</li> 389 * <li>{@link #DEFAULT_NETWORK_NO}</li> 390 * <li>{@link #DEFAULT_NETWORK_YES}</li> 391 * </ul> 392 * <p>Indicates whether the network usage occurred on the system default network for this 393 * type of traffic, or whether the application chose to send this traffic on a network that 394 * was not the one selected by the system. 395 */ 396 public @DefaultNetwork int getDefaultNetwork() { 397 return mDefaultNetwork; 398 } 399 400 /** 401 * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see 402 * {@link java.lang.System#currentTimeMillis}. 403 * @return Start of interval. 404 */ 405 public long getStartTimeStamp() { 406 return mBeginTimeStamp; 407 } 408 409 /** 410 * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see 411 * {@link java.lang.System#currentTimeMillis}. 412 * @return End of interval. 413 */ 414 public long getEndTimeStamp() { 415 return mEndTimeStamp; 416 } 417 418 /** 419 * Number of bytes received during the bucket's time interval. Statistics are measured at 420 * the network layer, so they include both TCP and UDP usage. 421 * @return Number of bytes. 422 */ 423 public long getRxBytes() { 424 return mRxBytes; 425 } 426 427 /** 428 * Number of bytes transmitted during the bucket's time interval. Statistics are measured at 429 * the network layer, so they include both TCP and UDP usage. 430 * @return Number of bytes. 431 */ 432 public long getTxBytes() { 433 return mTxBytes; 434 } 435 436 /** 437 * Number of packets received during the bucket's time interval. Statistics are measured at 438 * the network layer, so they include both TCP and UDP usage. 439 * @return Number of packets. 440 */ 441 public long getRxPackets() { 442 return mRxPackets; 443 } 444 445 /** 446 * Number of packets transmitted during the bucket's time interval. Statistics are measured 447 * at the network layer, so they include both TCP and UDP usage. 448 * @return Number of packets. 449 */ 450 public long getTxPackets() { 451 return mTxPackets; 452 } 453 } 454 455 /** 456 * Fills the recycled bucket with data of the next bin in the enumeration. 457 * @param bucketOut Bucket to be filled with data. 458 * @return true if successfully filled the bucket, false otherwise. 459 */ 460 public boolean getNextBucket(Bucket bucketOut) { 461 if (mSummary != null) { 462 return getNextSummaryBucket(bucketOut); 463 } else { 464 return getNextHistoryBucket(bucketOut); 465 } 466 } 467 468 /** 469 * Check if it is possible to ask for a next bucket in the enumeration. 470 * @return true if there is at least one more bucket. 471 */ 472 public boolean hasNextBucket() { 473 if (mSummary != null) { 474 return mEnumerationIndex < mSummary.size(); 475 } else if (mHistory != null) { 476 return mEnumerationIndex < mHistory.size() 477 || hasNextUid(); 478 } 479 return false; 480 } 481 482 /** 483 * Closes the enumeration. Call this method before this object gets out of scope. 484 */ 485 @Override 486 public void close() { 487 if (mSession != null) { 488 try { 489 mSession.close(); 490 } catch (RemoteException e) { 491 Log.w(TAG, e); 492 // Otherwise, meh 493 } 494 } 495 mSession = null; 496 if (mCloseGuard != null) { 497 mCloseGuard.close(); 498 } 499 } 500 501 // -------------------------END OF PUBLIC API----------------------------------- 502 503 /** 504 * Collects device summary results into a Bucket. 505 * @throws RemoteException 506 */ 507 Bucket getDeviceSummaryForNetwork() throws RemoteException { 508 mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, mStartTimeStamp, mEndTimeStamp); 509 510 // Setting enumeration index beyond end to avoid accidental enumeration over data that does 511 // not belong to the calling user. 512 mEnumerationIndex = mSummary.size(); 513 514 return getSummaryAggregate(); 515 } 516 517 /** 518 * Collects summary results and sets summary enumeration mode. 519 * @throws RemoteException 520 */ 521 void startSummaryEnumeration() throws RemoteException { 522 mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, 523 false /* includeTags */); 524 mEnumerationIndex = 0; 525 } 526 527 /** 528 * Collects history results for uid and resets history enumeration index. 529 */ 530 void startHistoryEnumeration(int uid) { 531 startHistoryEnumeration(uid, android.net.NetworkStats.TAG_NONE); 532 } 533 534 /** 535 * Collects history results for uid and resets history enumeration index. 536 */ 537 void startHistoryEnumeration(int uid, int tag) { 538 mHistory = null; 539 try { 540 mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, 541 android.net.NetworkStats.SET_ALL, tag, 542 NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); 543 setSingleUidTag(uid, tag); 544 } catch (RemoteException e) { 545 Log.w(TAG, e); 546 // Leaving mHistory null 547 } 548 mEnumerationIndex = 0; 549 } 550 551 /** 552 * Starts uid enumeration for current user. 553 * @throws RemoteException 554 */ 555 void startUserUidEnumeration() throws RemoteException { 556 // TODO: getRelevantUids should be sensitive to time interval. When that's done, 557 // the filtering logic below can be removed. 558 int[] uids = mSession.getRelevantUids(); 559 // Filtering of uids with empty history. 560 IntArray filteredUids = new IntArray(uids.length); 561 for (int uid : uids) { 562 try { 563 NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid, 564 android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, 565 NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); 566 if (history != null && history.size() > 0) { 567 filteredUids.add(uid); 568 } 569 } catch (RemoteException e) { 570 Log.w(TAG, "Error while getting history of uid " + uid, e); 571 } 572 } 573 mUids = filteredUids.toArray(); 574 mUidOrUidIndex = -1; 575 stepHistory(); 576 } 577 578 /** 579 * Steps to next uid in enumeration and collects history for that. 580 */ 581 private void stepHistory(){ 582 if (hasNextUid()) { 583 stepUid(); 584 mHistory = null; 585 try { 586 mHistory = mSession.getHistoryIntervalForUid(mTemplate, getUid(), 587 android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, 588 NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); 589 } catch (RemoteException e) { 590 Log.w(TAG, e); 591 // Leaving mHistory null 592 } 593 mEnumerationIndex = 0; 594 } 595 } 596 597 private void fillBucketFromSummaryEntry(Bucket bucketOut) { 598 bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); 599 bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); 600 bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); 601 bucketOut.mDefaultNetwork = Bucket.convertDefaultNetwork( 602 mRecycledSummaryEntry.defaultNetwork); 603 bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); 604 bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); 605 bucketOut.mBeginTimeStamp = mStartTimeStamp; 606 bucketOut.mEndTimeStamp = mEndTimeStamp; 607 bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; 608 bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets; 609 bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes; 610 bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets; 611 } 612 613 /** 614 * Getting the next item in summary enumeration. 615 * @param bucketOut Next item will be set here. 616 * @return true if a next item could be set. 617 */ 618 private boolean getNextSummaryBucket(Bucket bucketOut) { 619 if (bucketOut != null && mEnumerationIndex < mSummary.size()) { 620 mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry); 621 fillBucketFromSummaryEntry(bucketOut); 622 return true; 623 } 624 return false; 625 } 626 627 Bucket getSummaryAggregate() { 628 if (mSummary == null) { 629 return null; 630 } 631 Bucket bucket = new Bucket(); 632 if (mRecycledSummaryEntry == null) { 633 mRecycledSummaryEntry = new android.net.NetworkStats.Entry(); 634 } 635 mSummary.getTotal(mRecycledSummaryEntry); 636 fillBucketFromSummaryEntry(bucket); 637 return bucket; 638 } 639 /** 640 * Getting the next item in a history enumeration. 641 * @param bucketOut Next item will be set here. 642 * @return true if a next item could be set. 643 */ 644 private boolean getNextHistoryBucket(Bucket bucketOut) { 645 if (bucketOut != null && mHistory != null) { 646 if (mEnumerationIndex < mHistory.size()) { 647 mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++, 648 mRecycledHistoryEntry); 649 bucketOut.mUid = Bucket.convertUid(getUid()); 650 bucketOut.mTag = Bucket.convertTag(mTag); 651 bucketOut.mState = Bucket.STATE_ALL; 652 bucketOut.mDefaultNetwork = Bucket.DEFAULT_NETWORK_ALL; 653 bucketOut.mMetered = Bucket.METERED_ALL; 654 bucketOut.mRoaming = Bucket.ROAMING_ALL; 655 bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; 656 bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + 657 mRecycledHistoryEntry.bucketDuration; 658 bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes; 659 bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets; 660 bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes; 661 bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets; 662 return true; 663 } else if (hasNextUid()) { 664 stepHistory(); 665 return getNextHistoryBucket(bucketOut); 666 } 667 } 668 return false; 669 } 670 671 // ------------------ UID LOGIC------------------------ 672 673 private boolean isUidEnumeration() { 674 return mUids != null; 675 } 676 677 private boolean hasNextUid() { 678 return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length; 679 } 680 681 private int getUid() { 682 // Check if uid enumeration. 683 if (isUidEnumeration()) { 684 if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) { 685 throw new IndexOutOfBoundsException( 686 "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length); 687 } 688 return mUids[mUidOrUidIndex]; 689 } 690 // Single uid mode. 691 return mUidOrUidIndex; 692 } 693 694 private void setSingleUidTag(int uid, int tag) { 695 mUidOrUidIndex = uid; 696 mTag = tag; 697 } 698 699 private void stepUid() { 700 if (mUids != null) { 701 ++mUidOrUidIndex; 702 } 703 } 704} 705