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