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