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 17 package android.app.usage; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.annotation.Nullable; 22 import android.annotation.SystemService; 23 import android.annotation.TestApi; 24 import android.app.usage.NetworkStats.Bucket; 25 import android.content.Context; 26 import android.net.ConnectivityManager; 27 import android.net.DataUsageRequest; 28 import android.net.INetworkStatsService; 29 import android.net.NetworkIdentity; 30 import android.net.NetworkTemplate; 31 import android.os.Binder; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.Messenger; 36 import android.os.RemoteException; 37 import android.os.ServiceManager; 38 import android.os.ServiceManager.ServiceNotFoundException; 39 import android.util.DataUnit; 40 import android.util.Log; 41 42 import com.android.internal.annotations.VisibleForTesting; 43 44 /** 45 * Provides access to network usage history and statistics. Usage data is collected in 46 * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. 47 * <p /> 48 * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and 49 * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain 50 * data about themselves. See the below note for special cases in which apps can obtain data about 51 * other applications. 52 * <h3> 53 * Summary queries 54 * </h3> 55 * {@link #querySummaryForDevice} <p /> 56 * {@link #querySummaryForUser} <p /> 57 * {@link #querySummary} <p /> 58 * These queries aggregate network usage across the whole interval. Therefore there will be only one 59 * bucket for a particular key, state, metered and roaming combination. In case of the user-wide 60 * and device-wide summaries a single bucket containing the totalised network usage is returned. 61 * <h3> 62 * History queries 63 * </h3> 64 * {@link #queryDetailsForUid} <p /> 65 * {@link #queryDetails} <p /> 66 * These queries do not aggregate over time but do aggregate over state, metered and roaming. 67 * Therefore there can be multiple buckets for a particular key. However, all Buckets will have 68 * {@code state} {@link NetworkStats.Bucket#STATE_ALL}, 69 * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 70 * {@code metered } {@link NetworkStats.Bucket#METERED_ALL}, 71 * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}. 72 * <p /> 73 * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the 74 * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, 75 * which is a system-level permission and will not be granted to third-party apps. However, 76 * declaring the permission implies intention to use the API and the user of the device can grant 77 * permission through the Settings application. 78 * <p /> 79 * Profile owner apps are automatically granted permission to query data on the profile they manage 80 * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier- 81 * privileged apps likewise get access to usage data for all users on the device. 82 * <p /> 83 * In addition to tethering usage, usage by removed users and apps, and usage by the system 84 * is also included in the results for callers with one of these higher levels of access. 85 * <p /> 86 * <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required 87 * the above permission, even to access an app's own data usage, and carrier-privileged apps were 88 * not included. 89 */ 90 @SystemService(Context.NETWORK_STATS_SERVICE) 91 public class NetworkStatsManager { 92 private static final String TAG = "NetworkStatsManager"; 93 private static final boolean DBG = false; 94 95 /** @hide */ 96 public static final int CALLBACK_LIMIT_REACHED = 0; 97 /** @hide */ 98 public static final int CALLBACK_RELEASED = 1; 99 100 /** 101 * Minimum data usage threshold for registering usage callbacks. 102 * 103 * Requests registered with a threshold lower than this will only be triggered once this minimum 104 * is reached. 105 * @hide 106 */ 107 public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2); 108 109 private final Context mContext; 110 private final INetworkStatsService mService; 111 112 /** @hide */ 113 public static final int FLAG_POLL_ON_OPEN = 1 << 0; 114 /** @hide */ 115 public static final int FLAG_POLL_FORCE = 1 << 1; 116 /** @hide */ 117 public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2; 118 119 private int mFlags; 120 121 /** 122 * {@hide} 123 */ 124 public NetworkStatsManager(Context context) throws ServiceNotFoundException { 125 this(context, INetworkStatsService.Stub.asInterface( 126 ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); 127 } 128 129 /** @hide */ 130 @VisibleForTesting 131 public NetworkStatsManager(Context context, INetworkStatsService service) { 132 mContext = context; 133 mService = service; 134 setPollOnOpen(true); 135 } 136 137 /** @hide */ 138 public void setPollOnOpen(boolean pollOnOpen) { 139 if (pollOnOpen) { 140 mFlags |= FLAG_POLL_ON_OPEN; 141 } else { 142 mFlags &= ~FLAG_POLL_ON_OPEN; 143 } 144 } 145 146 /** @hide */ 147 @TestApi 148 public void setPollForce(boolean pollForce) { 149 if (pollForce) { 150 mFlags |= FLAG_POLL_FORCE; 151 } else { 152 mFlags &= ~FLAG_POLL_FORCE; 153 } 154 } 155 156 /** @hide */ 157 public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) { 158 if (augmentWithSubscriptionPlan) { 159 mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; 160 } else { 161 mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; 162 } 163 } 164 165 /** @hide */ 166 public Bucket querySummaryForDevice(NetworkTemplate template, 167 long startTime, long endTime) throws SecurityException, RemoteException { 168 Bucket bucket = null; 169 NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, 170 mService); 171 bucket = stats.getDeviceSummaryForNetwork(); 172 173 stats.close(); 174 return bucket; 175 } 176 177 /** 178 * Query network usage statistics summaries. Result is summarised data usage for the whole 179 * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and 180 * roaming. This means the bucket's start and end timestamp are going to be the same as the 181 * 'startTime' and 'endTime' parameters. State is going to be 182 * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, 183 * tag {@link NetworkStats.Bucket#TAG_NONE}, 184 * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 185 * metered {@link NetworkStats.Bucket#METERED_ALL}, 186 * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. 187 * 188 * @param networkType As defined in {@link ConnectivityManager}, e.g. 189 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 190 * etc. 191 * @param subscriberId If applicable, the subscriber id of the network interface. 192 * @param startTime Start of period. Defined in terms of "Unix time", see 193 * {@link java.lang.System#currentTimeMillis}. 194 * @param endTime End of period. Defined in terms of "Unix time", see 195 * {@link java.lang.System#currentTimeMillis}. 196 * @return Bucket object or null if permissions are insufficient or error happened during 197 * statistics collection. 198 */ 199 public Bucket querySummaryForDevice(int networkType, String subscriberId, 200 long startTime, long endTime) throws SecurityException, RemoteException { 201 NetworkTemplate template; 202 try { 203 template = createTemplate(networkType, subscriberId); 204 } catch (IllegalArgumentException e) { 205 if (DBG) Log.e(TAG, "Cannot create template", e); 206 return null; 207 } 208 209 return querySummaryForDevice(template, startTime, endTime); 210 } 211 212 /** 213 * Query network usage statistics summaries. Result is summarised data usage for all uids 214 * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. 215 * This means the bucket's start and end timestamp are going to be the same as the 'startTime' 216 * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, 217 * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, 218 * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming 219 * {@link NetworkStats.Bucket#ROAMING_ALL}. 220 * 221 * @param networkType As defined in {@link ConnectivityManager}, e.g. 222 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 223 * etc. 224 * @param subscriberId If applicable, the subscriber id of the network interface. 225 * @param startTime Start of period. Defined in terms of "Unix time", see 226 * {@link java.lang.System#currentTimeMillis}. 227 * @param endTime End of period. Defined in terms of "Unix time", see 228 * {@link java.lang.System#currentTimeMillis}. 229 * @return Bucket object or null if permissions are insufficient or error happened during 230 * statistics collection. 231 */ 232 public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, 233 long endTime) throws SecurityException, RemoteException { 234 NetworkTemplate template; 235 try { 236 template = createTemplate(networkType, subscriberId); 237 } catch (IllegalArgumentException e) { 238 if (DBG) Log.e(TAG, "Cannot create template", e); 239 return null; 240 } 241 242 NetworkStats stats; 243 stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 244 stats.startSummaryEnumeration(); 245 246 stats.close(); 247 return stats.getSummaryAggregate(); 248 } 249 250 /** 251 * Query network usage statistics summaries. Result filtered to include only uids belonging to 252 * calling user. Result is aggregated over time, hence all buckets will have the same start and 253 * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This 254 * means buckets' start and end timestamps are going to be the same as the 'startTime' and 255 * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to 256 * be the same. 257 * 258 * @param networkType As defined in {@link ConnectivityManager}, e.g. 259 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 260 * etc. 261 * @param subscriberId If applicable, the subscriber id of the network interface. 262 * @param startTime Start of period. Defined in terms of "Unix time", see 263 * {@link java.lang.System#currentTimeMillis}. 264 * @param endTime End of period. Defined in terms of "Unix time", see 265 * {@link java.lang.System#currentTimeMillis}. 266 * @return Statistics object or null if permissions are insufficient or error happened during 267 * statistics collection. 268 */ 269 public NetworkStats querySummary(int networkType, String subscriberId, long startTime, 270 long endTime) throws SecurityException, RemoteException { 271 NetworkTemplate template; 272 try { 273 template = createTemplate(networkType, subscriberId); 274 } catch (IllegalArgumentException e) { 275 if (DBG) Log.e(TAG, "Cannot create template", e); 276 return null; 277 } 278 279 NetworkStats result; 280 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 281 result.startSummaryEnumeration(); 282 283 return result; 284 } 285 286 /** 287 * Query network usage statistics details for a given uid. 288 * 289 * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) 290 */ 291 public NetworkStats queryDetailsForUid(int networkType, String subscriberId, 292 long startTime, long endTime, int uid) throws SecurityException { 293 return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, 294 NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); 295 } 296 297 /** 298 * Query network usage statistics details for a given uid and tag. 299 * 300 * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) 301 */ 302 public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, 303 long startTime, long endTime, int uid, int tag) throws SecurityException { 304 return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, 305 tag, NetworkStats.Bucket.STATE_ALL); 306 } 307 308 /** 309 * Query network usage statistics details for a given uid, tag, and state. Only usable for uids 310 * belonging to calling user. Result is not aggregated over time. This means buckets' start and 311 * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going 312 * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state 313 * the same as the 'state' parameter. 314 * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 315 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and 316 * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. 317 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't 318 * interpolate across partial buckets. Since bucket length is in the order of hours, this 319 * method cannot be used to measure data usage on a fine grained time scale. 320 * 321 * @param networkType As defined in {@link ConnectivityManager}, e.g. 322 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 323 * etc. 324 * @param subscriberId If applicable, the subscriber id of the network interface. 325 * @param startTime Start of period. Defined in terms of "Unix time", see 326 * {@link java.lang.System#currentTimeMillis}. 327 * @param endTime End of period. Defined in terms of "Unix time", see 328 * {@link java.lang.System#currentTimeMillis}. 329 * @param uid UID of app 330 * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags. 331 * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate 332 * traffic from all states. 333 * @return Statistics object or null if an error happened during statistics collection. 334 * @throws SecurityException if permissions are insufficient to read network statistics. 335 */ 336 public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId, 337 long startTime, long endTime, int uid, int tag, int state) throws SecurityException { 338 NetworkTemplate template; 339 template = createTemplate(networkType, subscriberId); 340 341 NetworkStats result; 342 try { 343 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 344 result.startHistoryEnumeration(uid, tag, state); 345 } catch (RemoteException e) { 346 Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag 347 + " state=" + state, e); 348 return null; 349 } 350 351 return result; 352 } 353 354 /** 355 * Query network usage statistics details. Result filtered to include only uids belonging to 356 * calling user. Result is aggregated over state but not aggregated over time, uid, tag, 357 * metered, nor roaming. This means buckets' start and end timestamps are going to be between 358 * 'startTime' and 'endTime' parameters. State is going to be 359 * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, 360 * tag {@link NetworkStats.Bucket#TAG_NONE}, 361 * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, 362 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, 363 * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. 364 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't 365 * interpolate across partial buckets. Since bucket length is in the order of hours, this 366 * method cannot be used to measure data usage on a fine grained time scale. 367 * 368 * @param networkType As defined in {@link ConnectivityManager}, e.g. 369 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} 370 * etc. 371 * @param subscriberId If applicable, the subscriber id of the network interface. 372 * @param startTime Start of period. Defined in terms of "Unix time", see 373 * {@link java.lang.System#currentTimeMillis}. 374 * @param endTime End of period. Defined in terms of "Unix time", see 375 * {@link java.lang.System#currentTimeMillis}. 376 * @return Statistics object or null if permissions are insufficient or error happened during 377 * statistics collection. 378 */ 379 public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, 380 long endTime) throws SecurityException, RemoteException { 381 NetworkTemplate template; 382 try { 383 template = createTemplate(networkType, subscriberId); 384 } catch (IllegalArgumentException e) { 385 if (DBG) Log.e(TAG, "Cannot create template", e); 386 return null; 387 } 388 389 NetworkStats result; 390 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); 391 result.startUserUidEnumeration(); 392 return result; 393 } 394 395 /** @hide */ 396 public void registerUsageCallback(NetworkTemplate template, int networkType, 397 long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { 398 checkNotNull(callback, "UsageCallback cannot be null"); 399 400 final Looper looper; 401 if (handler == null) { 402 looper = Looper.myLooper(); 403 } else { 404 looper = handler.getLooper(); 405 } 406 407 DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, 408 template, thresholdBytes); 409 try { 410 CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, 411 template.getSubscriberId(), callback); 412 callback.request = mService.registerUsageCallback( 413 mContext.getOpPackageName(), request, new Messenger(callbackHandler), 414 new Binder()); 415 if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); 416 417 if (callback.request == null) { 418 Log.e(TAG, "Request from callback is null; should not happen"); 419 } 420 } catch (RemoteException e) { 421 if (DBG) Log.d(TAG, "Remote exception when registering callback"); 422 throw e.rethrowFromSystemServer(); 423 } 424 } 425 426 /** 427 * Registers to receive notifications about data usage on specified networks. 428 * 429 * #see registerUsageCallback(int, String[], long, UsageCallback, Handler) 430 */ 431 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, 432 UsageCallback callback) { 433 registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, 434 null /* handler */); 435 } 436 437 /** 438 * Registers to receive notifications about data usage on specified networks. 439 * 440 * <p>The callbacks will continue to be called as long as the process is live or 441 * {@link #unregisterUsageCallback} is called. 442 * 443 * @param networkType Type of network to monitor. Either 444 {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. 445 * @param subscriberId If applicable, the subscriber id of the network interface. 446 * @param thresholdBytes Threshold in bytes to be notified on. 447 * @param callback The {@link UsageCallback} that the system will call when data usage 448 * has exceeded the specified threshold. 449 * @param handler to dispatch callback events through, otherwise if {@code null} it uses 450 * the calling thread. 451 */ 452 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, 453 UsageCallback callback, @Nullable Handler handler) { 454 NetworkTemplate template = createTemplate(networkType, subscriberId); 455 if (DBG) { 456 Log.d(TAG, "registerUsageCallback called with: {" 457 + " networkType=" + networkType 458 + " subscriberId=" + subscriberId 459 + " thresholdBytes=" + thresholdBytes 460 + " }"); 461 } 462 registerUsageCallback(template, networkType, thresholdBytes, callback, handler); 463 } 464 465 /** 466 * Unregisters callbacks on data usage. 467 * 468 * @param callback The {@link UsageCallback} used when registering. 469 */ 470 public void unregisterUsageCallback(UsageCallback callback) { 471 if (callback == null || callback.request == null 472 || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { 473 throw new IllegalArgumentException("Invalid UsageCallback"); 474 } 475 try { 476 mService.unregisterUsageRequest(callback.request); 477 } catch (RemoteException e) { 478 if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); 479 throw e.rethrowFromSystemServer(); 480 } 481 } 482 483 /** 484 * Base class for usage callbacks. Should be extended by applications wanting notifications. 485 */ 486 public static abstract class UsageCallback { 487 488 /** 489 * Called when data usage has reached the given threshold. 490 */ 491 public abstract void onThresholdReached(int networkType, String subscriberId); 492 493 /** 494 * @hide used for internal bookkeeping 495 */ 496 private DataUsageRequest request; 497 } 498 499 private static NetworkTemplate createTemplate(int networkType, String subscriberId) { 500 final NetworkTemplate template; 501 switch (networkType) { 502 case ConnectivityManager.TYPE_MOBILE: 503 template = subscriberId == null 504 ? NetworkTemplate.buildTemplateMobileWildcard() 505 : NetworkTemplate.buildTemplateMobileAll(subscriberId); 506 break; 507 case ConnectivityManager.TYPE_WIFI: 508 template = NetworkTemplate.buildTemplateWifiWildcard(); 509 break; 510 default: 511 throw new IllegalArgumentException("Cannot create template for network type " 512 + networkType + ", subscriberId '" 513 + NetworkIdentity.scrubSubscriberId(subscriberId) + "'."); 514 } 515 return template; 516 } 517 518 private static class CallbackHandler extends Handler { 519 private final int mNetworkType; 520 private final String mSubscriberId; 521 private UsageCallback mCallback; 522 523 CallbackHandler(Looper looper, int networkType, String subscriberId, 524 UsageCallback callback) { 525 super(looper); 526 mNetworkType = networkType; 527 mSubscriberId = subscriberId; 528 mCallback = callback; 529 } 530 531 @Override 532 public void handleMessage(Message message) { 533 DataUsageRequest request = 534 (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY); 535 536 switch (message.what) { 537 case CALLBACK_LIMIT_REACHED: { 538 if (mCallback != null) { 539 mCallback.onThresholdReached(mNetworkType, mSubscriberId); 540 } else { 541 Log.e(TAG, "limit reached with released callback for " + request); 542 } 543 break; 544 } 545 case CALLBACK_RELEASED: { 546 if (DBG) Log.d(TAG, "callback released for " + request); 547 mCallback = null; 548 break; 549 } 550 } 551 } 552 553 private static Object getObject(Message msg, String key) { 554 return msg.getData().getParcelable(key); 555 } 556 } 557 } 558