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