blob: 5576e86edd8a35bbd2ca4550567feedc91ce12ec [file] [log] [blame]
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +00001/**
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy
6 * of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17package android.app.usage;
18
Antonio Cansadoba8288d2015-12-02 08:42:54 -080019import static com.android.internal.util.Preconditions.checkNotNull;
20
21import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060022import android.annotation.SystemService;
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010023import android.app.usage.NetworkStats.Bucket;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000024import android.content.Context;
25import android.net.ConnectivityManager;
Antonio Cansadoba8288d2015-12-02 08:42:54 -080026import android.net.DataUsageRequest;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060027import android.net.INetworkStatsService;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000028import android.net.NetworkIdentity;
29import android.net.NetworkTemplate;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080030import android.os.Binder;
Antonio Cansadoba8288d2015-12-02 08:42:54 -080031import android.os.Handler;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080032import android.os.Looper;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060033import android.os.Message;
34import android.os.Messenger;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000035import android.os.RemoteException;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080036import android.os.ServiceManager;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060037import android.os.ServiceManager.ServiceNotFoundException;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000038import android.util.Log;
39
40/**
41 * Provides access to network usage history and statistics. Usage data is collected in
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010042 * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000043 * <p />
44 * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
Jeff Davidson1efb1332015-12-09 18:04:50 -080045 * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain
46 * data about themselves. See the below note for special cases in which apps can obtain data about
47 * other applications.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000048 * <h3>
49 * Summary queries
50 * </h3>
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010051 * {@link #querySummaryForDevice} <p />
52 * {@link #querySummaryForUser} <p />
53 * {@link #querySummary} <p />
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000054 * These queries aggregate network usage across the whole interval. Therefore there will be only one
Stephen Chen25147872016-10-21 12:44:26 -070055 * bucket for a particular key, state, metered and roaming combination. In case of the user-wide
56 * and device-wide summaries a single bucket containing the totalised network usage is returned.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000057 * <h3>
58 * History queries
59 * </h3>
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010060 * {@link #queryDetailsForUid} <p />
61 * {@link #queryDetails} <p />
Stephen Chen25147872016-10-21 12:44:26 -070062 * These queries do not aggregate over time but do aggregate over state, metered and roaming.
Lorenzo Colitti35c13e52018-01-19 01:12:58 +090063 * Therefore there can be multiple buckets for a particular key. However, all Buckets will have
64 * {@code state} {@link NetworkStats.Bucket#STATE_ALL},
65 * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
66 * {@code metered } {@link NetworkStats.Bucket#METERED_ALL},
67 * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000068 * <p />
Zoltan Szatmary-Ban3a8b3432016-01-21 10:44:37 +000069 * <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 />
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000075 * Profile owner apps are automatically granted permission to query data on the profile they manage
Jeff Davidson1efb1332015-12-09 18:04:50 -080076 * (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 />
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060082 * <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required
Jeff Davidson1efb1332015-12-09 18:04:50 -080083 * the above permission, even to access an app's own data usage, and carrier-privileged apps were
84 * not included.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000085 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060086@SystemService(Context.NETWORK_STATS_SERVICE)
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000087public class NetworkStatsManager {
Antonio Cansadocd42acd2016-02-17 13:03:38 -080088 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;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000095
96 private final Context mContext;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080097 private final INetworkStatsService mService;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000098
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060099 /** @hide */
100 public static final int FLAG_POLL_ON_OPEN = 1 << 0;
101 /** @hide */
102 public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 1;
103
104 private int mFlags;
105
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000106 /**
107 * {@hide}
108 */
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600109 public NetworkStatsManager(Context context) throws ServiceNotFoundException {
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000110 mContext = context;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800111 mService = INetworkStatsService.Stub.asInterface(
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600112 ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE));
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600113 setPollOnOpen(true);
114 }
115
116 /** @hide */
117 public void setPollOnOpen(boolean pollOnOpen) {
118 if (pollOnOpen) {
119 mFlags |= FLAG_POLL_ON_OPEN;
120 } else {
121 mFlags &= ~FLAG_POLL_ON_OPEN;
122 }
123 }
124
125 /** @hide */
126 public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) {
127 if (augmentWithSubscriptionPlan) {
128 mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
129 } else {
130 mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
131 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000132 }
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800133
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900134 /** @hide */
135 public Bucket querySummaryForDevice(NetworkTemplate template,
136 long startTime, long endTime) throws SecurityException, RemoteException {
137 Bucket bucket = null;
138 NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
139 bucket = stats.getDeviceSummaryForNetwork();
140
141 stats.close();
142 return bucket;
143 }
144
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000145 /**
146 * Query network usage statistics summaries. Result is summarised data usage for the whole
Stephen Chen25147872016-10-21 12:44:26 -0700147 * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
148 * roaming. This means the bucket's start and end timestamp are going to be the same as the
149 * 'startTime' and 'endTime' parameters. State is going to be
150 * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900151 * tag {@link NetworkStats.Bucket#TAG_NONE},
152 * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
153 * metered {@link NetworkStats.Bucket#METERED_ALL},
Antonio Cansado46c753672015-12-10 15:57:56 -0800154 * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000155 *
156 * @param networkType As defined in {@link ConnectivityManager}, e.g.
157 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
158 * etc.
159 * @param subscriberId If applicable, the subscriber id of the network interface.
160 * @param startTime Start of period. Defined in terms of "Unix time", see
161 * {@link java.lang.System#currentTimeMillis}.
162 * @param endTime End of period. Defined in terms of "Unix time", see
163 * {@link java.lang.System#currentTimeMillis}.
164 * @return Bucket object or null if permissions are insufficient or error happened during
165 * statistics collection.
166 */
167 public Bucket querySummaryForDevice(int networkType, String subscriberId,
168 long startTime, long endTime) throws SecurityException, RemoteException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700169 NetworkTemplate template;
170 try {
171 template = createTemplate(networkType, subscriberId);
172 } catch (IllegalArgumentException e) {
173 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000174 return null;
175 }
176
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900177 return querySummaryForDevice(template, startTime, endTime);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000178 }
179
180 /**
181 * Query network usage statistics summaries. Result is summarised data usage for all uids
182 * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100183 * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
Stephen Chen25147872016-10-21 12:44:26 -0700184 * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
185 * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
186 * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
187 * {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000188 *
189 * @param networkType As defined in {@link ConnectivityManager}, e.g.
190 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
191 * etc.
192 * @param subscriberId If applicable, the subscriber id of the network interface.
193 * @param startTime Start of period. Defined in terms of "Unix time", see
194 * {@link java.lang.System#currentTimeMillis}.
195 * @param endTime End of period. Defined in terms of "Unix time", see
196 * {@link java.lang.System#currentTimeMillis}.
197 * @return Bucket object or null if permissions are insufficient or error happened during
198 * statistics collection.
199 */
200 public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
Antonio Cansado6965c182016-03-30 11:37:18 -0700201 long endTime) throws SecurityException, RemoteException {
202 NetworkTemplate template;
203 try {
204 template = createTemplate(networkType, subscriberId);
205 } catch (IllegalArgumentException e) {
206 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000207 return null;
208 }
209
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100210 NetworkStats stats;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600211 stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
Antonio Cansado6965c182016-03-30 11:37:18 -0700212 stats.startSummaryEnumeration();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000213
214 stats.close();
215 return stats.getSummaryAggregate();
216 }
217
218 /**
219 * Query network usage statistics summaries. Result filtered to include only uids belonging to
220 * calling user. Result is aggregated over time, hence all buckets will have the same start and
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900221 * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This
222 * means buckets' start and end timestamps are going to be the same as the 'startTime' and
223 * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to
224 * be the same.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000225 *
226 * @param networkType As defined in {@link ConnectivityManager}, e.g.
227 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
228 * etc.
229 * @param subscriberId If applicable, the subscriber id of the network interface.
230 * @param startTime Start of period. Defined in terms of "Unix time", see
231 * {@link java.lang.System#currentTimeMillis}.
232 * @param endTime End of period. Defined in terms of "Unix time", see
233 * {@link java.lang.System#currentTimeMillis}.
234 * @return Statistics object or null if permissions are insufficient or error happened during
235 * statistics collection.
236 */
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100237 public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
Antonio Cansado6965c182016-03-30 11:37:18 -0700238 long endTime) throws SecurityException, RemoteException {
239 NetworkTemplate template;
240 try {
241 template = createTemplate(networkType, subscriberId);
242 } catch (IllegalArgumentException e) {
243 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000244 return null;
245 }
246
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100247 NetworkStats result;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600248 result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
Antonio Cansado6965c182016-03-30 11:37:18 -0700249 result.startSummaryEnumeration();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000250
251 return result;
252 }
253
254 /**
Antonio Cansado46c753672015-12-10 15:57:56 -0800255 * Query network usage statistics details for a given uid.
256 *
257 * #see queryDetailsForUidTag(int, String, long, long, int, int)
258 */
259 public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
260 long startTime, long endTime, int uid) throws SecurityException, RemoteException {
261 return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid,
Antonio Cansado6965c182016-03-30 11:37:18 -0700262 NetworkStats.Bucket.TAG_NONE);
Antonio Cansado46c753672015-12-10 15:57:56 -0800263 }
264
265 /**
266 * Query network usage statistics details for a given uid and tag. Only usable for uids
267 * belonging to calling user. Result is aggregated over state but not aggregated over time.
268 * This means buckets' start and end timestamps are going to be between 'startTime' and
269 * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900270 * same as the 'uid' parameter and tag the same as 'tag' parameter.
271 * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
272 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
273 * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100274 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
275 * interpolate across partial buckets. Since bucket length is in the order of hours, this
276 * method cannot be used to measure data usage on a fine grained time scale.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000277 *
278 * @param networkType As defined in {@link ConnectivityManager}, e.g.
279 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
280 * etc.
281 * @param subscriberId If applicable, the subscriber id of the network interface.
282 * @param startTime Start of period. Defined in terms of "Unix time", see
283 * {@link java.lang.System#currentTimeMillis}.
284 * @param endTime End of period. Defined in terms of "Unix time", see
285 * {@link java.lang.System#currentTimeMillis}.
286 * @param uid UID of app
Antonio Cansado6965c182016-03-30 11:37:18 -0700287 * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags.
Antonio Cansado904237f2016-05-25 09:57:21 -0700288 * @return Statistics object or null if an error happened during statistics collection.
289 * @throws SecurityException if permissions are insufficient to read network statistics.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000290 */
Antonio Cansado46c753672015-12-10 15:57:56 -0800291 public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
Antonio Cansado904237f2016-05-25 09:57:21 -0700292 long startTime, long endTime, int uid, int tag) throws SecurityException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700293 NetworkTemplate template;
Antonio Cansado904237f2016-05-25 09:57:21 -0700294 template = createTemplate(networkType, subscriberId);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000295
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100296 NetworkStats result;
Antonio Cansado6965c182016-03-30 11:37:18 -0700297 try {
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600298 result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
Antonio Cansado6965c182016-03-30 11:37:18 -0700299 result.startHistoryEnumeration(uid, tag);
300 } catch (RemoteException e) {
301 Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
302 return null;
303 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000304
305 return result;
306 }
307
308 /**
309 * Query network usage statistics details. Result filtered to include only uids belonging to
Stephen Chen25147872016-10-21 12:44:26 -0700310 * calling user. Result is aggregated over state but not aggregated over time, uid, tag,
311 * metered, nor roaming. This means buckets' start and end timestamps are going to be between
312 * 'startTime' and 'endTime' parameters. State is going to be
313 * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900314 * tag {@link NetworkStats.Bucket#TAG_NONE},
315 * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
316 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL},
317 * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100318 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
319 * interpolate across partial buckets. Since bucket length is in the order of hours, this
320 * method cannot be used to measure data usage on a fine grained time scale.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000321 *
322 * @param networkType As defined in {@link ConnectivityManager}, e.g.
323 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
324 * etc.
325 * @param subscriberId If applicable, the subscriber id of the network interface.
326 * @param startTime Start of period. Defined in terms of "Unix time", see
327 * {@link java.lang.System#currentTimeMillis}.
328 * @param endTime End of period. Defined in terms of "Unix time", see
329 * {@link java.lang.System#currentTimeMillis}.
330 * @return Statistics object or null if permissions are insufficient or error happened during
331 * statistics collection.
332 */
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100333 public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000334 long endTime) throws SecurityException, RemoteException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700335 NetworkTemplate template;
336 try {
337 template = createTemplate(networkType, subscriberId);
338 } catch (IllegalArgumentException e) {
339 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000340 return null;
341 }
Antonio Cansado6965c182016-03-30 11:37:18 -0700342
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100343 NetworkStats result;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600344 result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000345 result.startUserUidEnumeration();
346 return result;
347 }
348
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900349 /** @hide */
350 public void registerUsageCallback(NetworkTemplate template, int networkType,
351 long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
352 checkNotNull(callback, "UsageCallback cannot be null");
353
354 final Looper looper;
355 if (handler == null) {
356 looper = Looper.myLooper();
357 } else {
358 looper = handler.getLooper();
359 }
360
361 DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
362 template, thresholdBytes);
363 try {
364 CallbackHandler callbackHandler = new CallbackHandler(looper, networkType,
365 template.getSubscriberId(), callback);
366 callback.request = mService.registerUsageCallback(
367 mContext.getOpPackageName(), request, new Messenger(callbackHandler),
368 new Binder());
369 if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
370
371 if (callback.request == null) {
372 Log.e(TAG, "Request from callback is null; should not happen");
373 }
374 } catch (RemoteException e) {
375 if (DBG) Log.d(TAG, "Remote exception when registering callback");
376 throw e.rethrowFromSystemServer();
377 }
378 }
379
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800380 /**
Antonio Cansado6965c182016-03-30 11:37:18 -0700381 * Registers to receive notifications about data usage on specified networks.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800382 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700383 * #see registerUsageCallback(int, String[], long, UsageCallback, Handler)
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800384 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700385 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
386 UsageCallback callback) {
Antonio Cansadof7048372016-06-20 15:03:03 -0700387 registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
388 null /* handler */);
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800389 }
390
391 /**
Antonio Cansado6965c182016-03-30 11:37:18 -0700392 * Registers to receive notifications about data usage on specified networks.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800393 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700394 * <p>The callbacks will continue to be called as long as the process is live or
395 * {@link #unregisterUsageCallback} is called.
396 *
397 * @param networkType Type of network to monitor. Either
398 {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
399 * @param subscriberId If applicable, the subscriber id of the network interface.
400 * @param thresholdBytes Threshold in bytes to be notified on.
401 * @param callback The {@link UsageCallback} that the system will call when data usage
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800402 * has exceeded the specified threshold.
403 * @param handler to dispatch callback events through, otherwise if {@code null} it uses
404 * the calling thread.
405 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700406 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
407 UsageCallback callback, @Nullable Handler handler) {
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900408 NetworkTemplate template = createTemplate(networkType, subscriberId);
Antonio Cansado6965c182016-03-30 11:37:18 -0700409 if (DBG) {
410 Log.d(TAG, "registerUsageCallback called with: {"
411 + " networkType=" + networkType
412 + " subscriberId=" + subscriberId
413 + " thresholdBytes=" + thresholdBytes
414 + " }");
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800415 }
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900416 registerUsageCallback(template, networkType, thresholdBytes, callback, handler);
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800417 }
418
419 /**
420 * Unregisters callbacks on data usage.
421 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700422 * @param callback The {@link UsageCallback} used when registering.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800423 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700424 public void unregisterUsageCallback(UsageCallback callback) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800425 if (callback == null || callback.request == null
426 || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
Antonio Cansado6965c182016-03-30 11:37:18 -0700427 throw new IllegalArgumentException("Invalid UsageCallback");
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800428 }
429 try {
Antonio Cansado6965c182016-03-30 11:37:18 -0700430 mService.unregisterUsageRequest(callback.request);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800431 } catch (RemoteException e) {
432 if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
Antonio Cansado6965c182016-03-30 11:37:18 -0700433 throw e.rethrowFromSystemServer();
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800434 }
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800435 }
436
Antonio Cansado6965c182016-03-30 11:37:18 -0700437 /**
438 * Base class for usage callbacks. Should be extended by applications wanting notifications.
439 */
440 public static abstract class UsageCallback {
441
442 /**
443 * Called when data usage has reached the given threshold.
444 */
445 public abstract void onThresholdReached(int networkType, String subscriberId);
446
447 /**
448 * @hide used for internal bookkeeping
449 */
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800450 private DataUsageRequest request;
451 }
452
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000453 private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
454 NetworkTemplate template = null;
455 switch (networkType) {
456 case ConnectivityManager.TYPE_MOBILE: {
457 template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
458 } break;
459 case ConnectivityManager.TYPE_WIFI: {
460 template = NetworkTemplate.buildTemplateWifiWildcard();
461 } break;
462 default: {
Antonio Cansado6965c182016-03-30 11:37:18 -0700463 throw new IllegalArgumentException("Cannot create template for network type "
464 + networkType + ", subscriberId '"
465 + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000466 }
467 }
468 return template;
469 }
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800470
471 private static class CallbackHandler extends Handler {
Antonio Cansado6965c182016-03-30 11:37:18 -0700472 private final int mNetworkType;
473 private final String mSubscriberId;
474 private UsageCallback mCallback;
475
476 CallbackHandler(Looper looper, int networkType, String subscriberId,
477 UsageCallback callback) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800478 super(looper);
Antonio Cansado6965c182016-03-30 11:37:18 -0700479 mNetworkType = networkType;
480 mSubscriberId = subscriberId;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800481 mCallback = callback;
482 }
483
484 @Override
485 public void handleMessage(Message message) {
486 DataUsageRequest request =
487 (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
488
489 switch (message.what) {
490 case CALLBACK_LIMIT_REACHED: {
491 if (mCallback != null) {
Antonio Cansado6965c182016-03-30 11:37:18 -0700492 mCallback.onThresholdReached(mNetworkType, mSubscriberId);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800493 } else {
494 Log.e(TAG, "limit reached with released callback for " + request);
495 }
496 break;
497 }
498 case CALLBACK_RELEASED: {
499 if (DBG) Log.d(TAG, "callback released for " + request);
500 mCallback = null;
501 break;
502 }
503 }
504 }
505
506 private static Object getObject(Message msg, String key) {
507 return msg.getData().getParcelable(key);
508 }
509 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000510}