blob: 2357637b7270ffb2d3b8b043dce047ea2b2c8ed4 [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
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +090040import com.android.internal.annotations.VisibleForTesting;
41
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000042/**
43 * Provides access to network usage history and statistics. Usage data is collected in
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010044 * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000045 * <p />
46 * 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 -080047 * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain
48 * data about themselves. See the below note for special cases in which apps can obtain data about
49 * other applications.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000050 * <h3>
51 * Summary queries
52 * </h3>
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010053 * {@link #querySummaryForDevice} <p />
54 * {@link #querySummaryForUser} <p />
55 * {@link #querySummary} <p />
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000056 * These queries aggregate network usage across the whole interval. Therefore there will be only one
Stephen Chen25147872016-10-21 12:44:26 -070057 * bucket for a particular key, state, metered and roaming combination. In case of the user-wide
58 * and device-wide summaries a single bucket containing the totalised network usage is returned.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000059 * <h3>
60 * History queries
61 * </h3>
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +010062 * {@link #queryDetailsForUid} <p />
63 * {@link #queryDetails} <p />
Stephen Chen25147872016-10-21 12:44:26 -070064 * These queries do not aggregate over time but do aggregate over state, metered and roaming.
Lorenzo Colitti35c13e52018-01-19 01:12:58 +090065 * Therefore there can be multiple buckets for a particular key. However, all Buckets will have
66 * {@code state} {@link NetworkStats.Bucket#STATE_ALL},
67 * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
68 * {@code metered } {@link NetworkStats.Bucket#METERED_ALL},
69 * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000070 * <p />
Zoltan Szatmary-Ban3a8b3432016-01-21 10:44:37 +000071 * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
72 * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS},
73 * which is a system-level permission and will not be granted to third-party apps. However,
74 * declaring the permission implies intention to use the API and the user of the device can grant
75 * permission through the Settings application.
76 * <p />
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000077 * Profile owner apps are automatically granted permission to query data on the profile they manage
Jeff Davidson1efb1332015-12-09 18:04:50 -080078 * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
79 * privileged apps likewise get access to usage data for all users on the device.
80 * <p />
81 * In addition to tethering usage, usage by removed users and apps, and usage by the system
82 * is also included in the results for callers with one of these higher levels of access.
83 * <p />
Jeff Sharkeyf4de2942017-08-29 15:32:13 -060084 * <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 -080085 * the above permission, even to access an app's own data usage, and carrier-privileged apps were
86 * not included.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000087 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060088@SystemService(Context.NETWORK_STATS_SERVICE)
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000089public class NetworkStatsManager {
Antonio Cansadocd42acd2016-02-17 13:03:38 -080090 private static final String TAG = "NetworkStatsManager";
91 private static final boolean DBG = false;
92
93 /** @hide */
94 public static final int CALLBACK_LIMIT_REACHED = 0;
95 /** @hide */
96 public static final int CALLBACK_RELEASED = 1;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +000097
98 private final Context mContext;
Antonio Cansadocd42acd2016-02-17 13:03:38 -080099 private final INetworkStatsService mService;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000100
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600101 /** @hide */
102 public static final int FLAG_POLL_ON_OPEN = 1 << 0;
103 /** @hide */
104 public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 1;
105
106 private int mFlags;
107
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000108 /**
109 * {@hide}
110 */
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600111 public NetworkStatsManager(Context context) throws ServiceNotFoundException {
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900112 this(context, INetworkStatsService.Stub.asInterface(
113 ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)));
114 }
115
116 /** @hide */
117 @VisibleForTesting
118 public NetworkStatsManager(Context context, INetworkStatsService service) {
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000119 mContext = context;
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900120 mService = service;
Jeff Sharkeyf4de2942017-08-29 15:32:13 -0600121 setPollOnOpen(true);
122 }
123
124 /** @hide */
125 public void setPollOnOpen(boolean pollOnOpen) {
126 if (pollOnOpen) {
127 mFlags |= FLAG_POLL_ON_OPEN;
128 } else {
129 mFlags &= ~FLAG_POLL_ON_OPEN;
130 }
131 }
132
133 /** @hide */
134 public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) {
135 if (augmentWithSubscriptionPlan) {
136 mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
137 } else {
138 mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
139 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000140 }
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800141
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900142 /** @hide */
143 public Bucket querySummaryForDevice(NetworkTemplate template,
144 long startTime, long endTime) throws SecurityException, RemoteException {
145 Bucket bucket = null;
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900146 NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
147 mService);
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900148 bucket = stats.getDeviceSummaryForNetwork();
149
150 stats.close();
151 return bucket;
152 }
153
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000154 /**
155 * Query network usage statistics summaries. Result is summarised data usage for the whole
Stephen Chen25147872016-10-21 12:44:26 -0700156 * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
157 * roaming. This means the bucket's start and end timestamp are going to be the same as the
158 * 'startTime' and 'endTime' parameters. State is going to be
159 * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900160 * tag {@link NetworkStats.Bucket#TAG_NONE},
161 * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
162 * metered {@link NetworkStats.Bucket#METERED_ALL},
Antonio Cansado46c753672015-12-10 15:57:56 -0800163 * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000164 *
165 * @param networkType As defined in {@link ConnectivityManager}, e.g.
166 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
167 * etc.
168 * @param subscriberId If applicable, the subscriber id of the network interface.
169 * @param startTime Start of period. Defined in terms of "Unix time", see
170 * {@link java.lang.System#currentTimeMillis}.
171 * @param endTime End of period. Defined in terms of "Unix time", see
172 * {@link java.lang.System#currentTimeMillis}.
173 * @return Bucket object or null if permissions are insufficient or error happened during
174 * statistics collection.
175 */
176 public Bucket querySummaryForDevice(int networkType, String subscriberId,
177 long startTime, long endTime) throws SecurityException, RemoteException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700178 NetworkTemplate template;
179 try {
180 template = createTemplate(networkType, subscriberId);
181 } catch (IllegalArgumentException e) {
182 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000183 return null;
184 }
185
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900186 return querySummaryForDevice(template, startTime, endTime);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000187 }
188
189 /**
190 * Query network usage statistics summaries. Result is summarised data usage for all uids
191 * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100192 * 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 -0700193 * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL},
194 * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE},
195 * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming
196 * {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000197 *
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 * @param startTime Start of period. Defined in terms of "Unix time", see
203 * {@link java.lang.System#currentTimeMillis}.
204 * @param endTime End of period. Defined in terms of "Unix time", see
205 * {@link java.lang.System#currentTimeMillis}.
206 * @return Bucket object or null if permissions are insufficient or error happened during
207 * statistics collection.
208 */
209 public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
Antonio Cansado6965c182016-03-30 11:37:18 -0700210 long endTime) throws SecurityException, RemoteException {
211 NetworkTemplate template;
212 try {
213 template = createTemplate(networkType, subscriberId);
214 } catch (IllegalArgumentException e) {
215 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000216 return null;
217 }
218
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100219 NetworkStats stats;
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900220 stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
Antonio Cansado6965c182016-03-30 11:37:18 -0700221 stats.startSummaryEnumeration();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000222
223 stats.close();
224 return stats.getSummaryAggregate();
225 }
226
227 /**
228 * Query network usage statistics summaries. Result filtered to include only uids belonging to
229 * calling user. Result is aggregated over time, hence all buckets will have the same start and
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900230 * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This
231 * means buckets' start and end timestamps are going to be the same as the 'startTime' and
232 * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to
233 * be the same.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000234 *
235 * @param networkType As defined in {@link ConnectivityManager}, e.g.
236 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
237 * etc.
238 * @param subscriberId If applicable, the subscriber id of the network interface.
239 * @param startTime Start of period. Defined in terms of "Unix time", see
240 * {@link java.lang.System#currentTimeMillis}.
241 * @param endTime End of period. Defined in terms of "Unix time", see
242 * {@link java.lang.System#currentTimeMillis}.
243 * @return Statistics object or null if permissions are insufficient or error happened during
244 * statistics collection.
245 */
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100246 public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
Antonio Cansado6965c182016-03-30 11:37:18 -0700247 long endTime) throws SecurityException, RemoteException {
248 NetworkTemplate template;
249 try {
250 template = createTemplate(networkType, subscriberId);
251 } catch (IllegalArgumentException e) {
252 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000253 return null;
254 }
255
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100256 NetworkStats result;
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900257 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
Antonio Cansado6965c182016-03-30 11:37:18 -0700258 result.startSummaryEnumeration();
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000259
260 return result;
261 }
262
263 /**
Antonio Cansado46c753672015-12-10 15:57:56 -0800264 * Query network usage statistics details for a given uid.
265 *
266 * #see queryDetailsForUidTag(int, String, long, long, int, int)
267 */
268 public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
269 long startTime, long endTime, int uid) throws SecurityException, RemoteException {
270 return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid,
Antonio Cansado6965c182016-03-30 11:37:18 -0700271 NetworkStats.Bucket.TAG_NONE);
Antonio Cansado46c753672015-12-10 15:57:56 -0800272 }
273
274 /**
275 * Query network usage statistics details for a given uid and tag. Only usable for uids
276 * belonging to calling user. Result is aggregated over state but not aggregated over time.
277 * This means buckets' start and end timestamps are going to be between 'startTime' and
278 * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900279 * same as the 'uid' parameter and tag the same as 'tag' parameter.
280 * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
281 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
282 * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100283 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
284 * interpolate across partial buckets. Since bucket length is in the order of hours, this
285 * method cannot be used to measure data usage on a fine grained time scale.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000286 *
287 * @param networkType As defined in {@link ConnectivityManager}, e.g.
288 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
289 * etc.
290 * @param subscriberId If applicable, the subscriber id of the network interface.
291 * @param startTime Start of period. Defined in terms of "Unix time", see
292 * {@link java.lang.System#currentTimeMillis}.
293 * @param endTime End of period. Defined in terms of "Unix time", see
294 * {@link java.lang.System#currentTimeMillis}.
295 * @param uid UID of app
Antonio Cansado6965c182016-03-30 11:37:18 -0700296 * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags.
Antonio Cansado904237f2016-05-25 09:57:21 -0700297 * @return Statistics object or null if an error happened during statistics collection.
298 * @throws SecurityException if permissions are insufficient to read network statistics.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000299 */
Antonio Cansado46c753672015-12-10 15:57:56 -0800300 public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
Antonio Cansado904237f2016-05-25 09:57:21 -0700301 long startTime, long endTime, int uid, int tag) throws SecurityException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700302 NetworkTemplate template;
Antonio Cansado904237f2016-05-25 09:57:21 -0700303 template = createTemplate(networkType, subscriberId);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000304
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100305 NetworkStats result;
Antonio Cansado6965c182016-03-30 11:37:18 -0700306 try {
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900307 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
Antonio Cansado6965c182016-03-30 11:37:18 -0700308 result.startHistoryEnumeration(uid, tag);
309 } catch (RemoteException e) {
310 Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
311 return null;
312 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000313
314 return result;
315 }
316
317 /**
318 * Query network usage statistics details. Result filtered to include only uids belonging to
Stephen Chen25147872016-10-21 12:44:26 -0700319 * calling user. Result is aggregated over state but not aggregated over time, uid, tag,
320 * metered, nor roaming. This means buckets' start and end timestamps are going to be between
321 * 'startTime' and 'endTime' parameters. State is going to be
322 * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary,
Lorenzo Colitti35c13e52018-01-19 01:12:58 +0900323 * tag {@link NetworkStats.Bucket#TAG_NONE},
324 * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
325 * metered is going to be {@link NetworkStats.Bucket#METERED_ALL},
326 * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
Zoltan Szatmary-Ban72027d22015-06-16 15:49:16 +0100327 * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
328 * interpolate across partial buckets. Since bucket length is in the order of hours, this
329 * method cannot be used to measure data usage on a fine grained time scale.
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000330 *
331 * @param networkType As defined in {@link ConnectivityManager}, e.g.
332 * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
333 * etc.
334 * @param subscriberId If applicable, the subscriber id of the network interface.
335 * @param startTime Start of period. Defined in terms of "Unix time", see
336 * {@link java.lang.System#currentTimeMillis}.
337 * @param endTime End of period. Defined in terms of "Unix time", see
338 * {@link java.lang.System#currentTimeMillis}.
339 * @return Statistics object or null if permissions are insufficient or error happened during
340 * statistics collection.
341 */
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100342 public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000343 long endTime) throws SecurityException, RemoteException {
Antonio Cansado6965c182016-03-30 11:37:18 -0700344 NetworkTemplate template;
345 try {
346 template = createTemplate(networkType, subscriberId);
347 } catch (IllegalArgumentException e) {
348 if (DBG) Log.e(TAG, "Cannot create template", e);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000349 return null;
350 }
Antonio Cansado6965c182016-03-30 11:37:18 -0700351
Zoltan Szatmary-Ban381483b2015-05-13 17:53:17 +0100352 NetworkStats result;
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900353 result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000354 result.startUserUidEnumeration();
355 return result;
356 }
357
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900358 /** @hide */
359 public void registerUsageCallback(NetworkTemplate template, int networkType,
360 long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
361 checkNotNull(callback, "UsageCallback cannot be null");
362
363 final Looper looper;
364 if (handler == null) {
365 looper = Looper.myLooper();
366 } else {
367 looper = handler.getLooper();
368 }
369
370 DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
371 template, thresholdBytes);
372 try {
373 CallbackHandler callbackHandler = new CallbackHandler(looper, networkType,
374 template.getSubscriberId(), callback);
375 callback.request = mService.registerUsageCallback(
376 mContext.getOpPackageName(), request, new Messenger(callbackHandler),
377 new Binder());
378 if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
379
380 if (callback.request == null) {
381 Log.e(TAG, "Request from callback is null; should not happen");
382 }
383 } catch (RemoteException e) {
384 if (DBG) Log.d(TAG, "Remote exception when registering callback");
385 throw e.rethrowFromSystemServer();
386 }
387 }
388
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800389 /**
Antonio Cansado6965c182016-03-30 11:37:18 -0700390 * Registers to receive notifications about data usage on specified networks.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800391 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700392 * #see registerUsageCallback(int, String[], long, UsageCallback, Handler)
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800393 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700394 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
395 UsageCallback callback) {
Antonio Cansadof7048372016-06-20 15:03:03 -0700396 registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
397 null /* handler */);
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800398 }
399
400 /**
Antonio Cansado6965c182016-03-30 11:37:18 -0700401 * Registers to receive notifications about data usage on specified networks.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800402 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700403 * <p>The callbacks will continue to be called as long as the process is live or
404 * {@link #unregisterUsageCallback} is called.
405 *
406 * @param networkType Type of network to monitor. Either
407 {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
408 * @param subscriberId If applicable, the subscriber id of the network interface.
409 * @param thresholdBytes Threshold in bytes to be notified on.
410 * @param callback The {@link UsageCallback} that the system will call when data usage
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800411 * has exceeded the specified threshold.
412 * @param handler to dispatch callback events through, otherwise if {@code null} it uses
413 * the calling thread.
414 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700415 public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
416 UsageCallback callback, @Nullable Handler handler) {
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900417 NetworkTemplate template = createTemplate(networkType, subscriberId);
Antonio Cansado6965c182016-03-30 11:37:18 -0700418 if (DBG) {
419 Log.d(TAG, "registerUsageCallback called with: {"
420 + " networkType=" + networkType
421 + " subscriberId=" + subscriberId
422 + " thresholdBytes=" + thresholdBytes
423 + " }");
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800424 }
Lorenzo Colittie0f69092018-01-22 21:00:49 +0900425 registerUsageCallback(template, networkType, thresholdBytes, callback, handler);
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800426 }
427
428 /**
429 * Unregisters callbacks on data usage.
430 *
Antonio Cansado6965c182016-03-30 11:37:18 -0700431 * @param callback The {@link UsageCallback} used when registering.
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800432 */
Antonio Cansado6965c182016-03-30 11:37:18 -0700433 public void unregisterUsageCallback(UsageCallback callback) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800434 if (callback == null || callback.request == null
435 || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
Antonio Cansado6965c182016-03-30 11:37:18 -0700436 throw new IllegalArgumentException("Invalid UsageCallback");
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800437 }
438 try {
Antonio Cansado6965c182016-03-30 11:37:18 -0700439 mService.unregisterUsageRequest(callback.request);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800440 } catch (RemoteException e) {
441 if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
Antonio Cansado6965c182016-03-30 11:37:18 -0700442 throw e.rethrowFromSystemServer();
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800443 }
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800444 }
445
Antonio Cansado6965c182016-03-30 11:37:18 -0700446 /**
447 * Base class for usage callbacks. Should be extended by applications wanting notifications.
448 */
449 public static abstract class UsageCallback {
450
451 /**
452 * Called when data usage has reached the given threshold.
453 */
454 public abstract void onThresholdReached(int networkType, String subscriberId);
455
456 /**
457 * @hide used for internal bookkeeping
458 */
Antonio Cansadoba8288d2015-12-02 08:42:54 -0800459 private DataUsageRequest request;
460 }
461
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000462 private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900463 final NetworkTemplate template;
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000464 switch (networkType) {
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900465 case ConnectivityManager.TYPE_MOBILE:
466 template = subscriberId == null
467 ? NetworkTemplate.buildTemplateMobileWildcard()
468 : NetworkTemplate.buildTemplateMobileAll(subscriberId);
469 break;
470 case ConnectivityManager.TYPE_WIFI:
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000471 template = NetworkTemplate.buildTemplateWifiWildcard();
Remi NGUYEN VAN786b7ad2018-03-05 18:14:56 +0900472 break;
473 default:
Antonio Cansado6965c182016-03-30 11:37:18 -0700474 throw new IllegalArgumentException("Cannot create template for network type "
475 + networkType + ", subscriberId '"
476 + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000477 }
478 return template;
479 }
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800480
481 private static class CallbackHandler extends Handler {
Antonio Cansado6965c182016-03-30 11:37:18 -0700482 private final int mNetworkType;
483 private final String mSubscriberId;
484 private UsageCallback mCallback;
485
486 CallbackHandler(Looper looper, int networkType, String subscriberId,
487 UsageCallback callback) {
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800488 super(looper);
Antonio Cansado6965c182016-03-30 11:37:18 -0700489 mNetworkType = networkType;
490 mSubscriberId = subscriberId;
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800491 mCallback = callback;
492 }
493
494 @Override
495 public void handleMessage(Message message) {
496 DataUsageRequest request =
497 (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
498
499 switch (message.what) {
500 case CALLBACK_LIMIT_REACHED: {
501 if (mCallback != null) {
Antonio Cansado6965c182016-03-30 11:37:18 -0700502 mCallback.onThresholdReached(mNetworkType, mSubscriberId);
Antonio Cansadocd42acd2016-02-17 13:03:38 -0800503 } else {
504 Log.e(TAG, "limit reached with released callback for " + request);
505 }
506 break;
507 }
508 case CALLBACK_RELEASED: {
509 if (DBG) Log.d(TAG, "callback released for " + request);
510 mCallback = null;
511 break;
512 }
513 }
514 }
515
516 private static Object getObject(Message msg, String key) {
517 return msg.getData().getParcelable(key);
518 }
519 }
Zoltan Szatmary-Ban9c5dfa52015-02-23 17:20:20 +0000520}