/** * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package android.app.usage; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkTemplate.MATCH_MOBILE; import static android.net.NetworkTemplate.MATCH_WIFI; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.WorkerThread; import android.app.usage.NetworkStats.Bucket; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.Network; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; import android.net.UnderlyingNetworkInfo; import android.net.netstats.IUsageCallback; import android.net.netstats.NetworkStatsDataMigrationUtils; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Build; import android.os.Handler; import android.os.RemoteException; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetworkIdentityUtils; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; /** * Provides access to network usage history and statistics. Usage data is collected in * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. *
* Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain * data about themselves. See the below note for special cases in which apps can obtain data about * other applications. *Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @return Bucket object or null if permissions are insufficient or error happened during * statistics collection. */ @WorkerThread public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { template = createTemplate(networkType, subscriberId); } catch (IllegalArgumentException e) { if (DBG) Log.e(TAG, "Cannot create template", e); return null; } return querySummaryForDevice(template, startTime, endTime); } /** * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming * {@link NetworkStats.Bucket#ROAMING_ALL}. * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @return Bucket object or null if permissions are insufficient or error happened during * statistics collection. */ @WorkerThread public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { template = createTemplate(networkType, subscriberId); } catch (IllegalArgumentException e) { if (DBG) Log.e(TAG, "Cannot create template", e); return null; } NetworkStats stats; stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); stats.startSummaryEnumeration(); stats.close(); return stats.getSummaryAggregate(); } /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This * means buckets' start and end timestamps are going to be the same as the 'startTime' and * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to * be the same. * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ @WorkerThread public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { template = createTemplate(networkType, subscriberId); } catch (IllegalArgumentException e) { if (DBG) Log.e(TAG, "Cannot create template", e); return null; } return querySummary(template, startTime, endTime); } /** * Query network usage statistics summaries. * * The results will only include traffic made by UIDs belonging to the calling user profile. * The results are aggregated over time, so that all buckets will have the same start and * end timestamps as the passed arguments. Not aggregated over state, uid, default network, * metered, or roaming. * This may take a long time, and apps should avoid calling this on their main thread. * * @param template Template used to match networks. See {@link NetworkTemplate}. * @param startTime Start of period, in milliseconds since the Unix epoch, see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period, in milliseconds since the Unix epoch, see * {@link java.lang.System#currentTimeMillis}. * @return Statistics which is described above. * @hide */ @NonNull @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime, long endTime) throws SecurityException { Objects.requireNonNull(template); try { NetworkStats result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startSummaryEnumeration(); return result; } catch (RemoteException e) { e.rethrowFromSystemServer(); } return null; // To make the compiler happy. } /** * Query tagged network usage statistics summaries. * * The results will only include tagged traffic made by UIDs belonging to the calling user * profile. The results are aggregated over time, so that all buckets will have the same * start and end timestamps as the passed arguments. Not aggregated over state, uid, * default network, metered, or roaming. * This may take a long time, and apps should avoid calling this on their main thread. * * @param template Template used to match networks. See {@link NetworkTemplate}. * @param startTime Start of period, in milliseconds since the Unix epoch, see * {@link System#currentTimeMillis}. * @param endTime End of period, in milliseconds since the Unix epoch, see * {@link System#currentTimeMillis}. * @return Statistics which is described above. * @hide */ @NonNull @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime, long endTime) throws SecurityException { Objects.requireNonNull(template); try { NetworkStats result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startTaggedSummaryEnumeration(); return result; } catch (RemoteException e) { e.rethrowFromSystemServer(); } return null; // To make the compiler happy. } /** * Query usage statistics details for networks matching a given {@link NetworkTemplate}. * * Result is not aggregated over time. This means buckets' start and * end timestamps will be between 'startTime' and 'endTime' parameters. *
Only includes buckets whose entire time period is included between * startTime and endTime. Doesn't interpolate or return partial buckets. * Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. * This may take a long time, and apps should avoid calling this on their main thread. * * @param template Template used to match networks. See {@link NetworkTemplate}. * @param startTime Start of period, in milliseconds since the Unix epoch, see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period, in milliseconds since the Unix epoch, see * {@link java.lang.System#currentTimeMillis}. * @return Statistics which is described above. * @hide */ @NonNull @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template, long startTime, long endTime) { Objects.requireNonNull(template); try { final NetworkStats result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startHistoryDeviceEnumeration(); return result; } catch (RemoteException e) { e.rethrowFromSystemServer(); } return null; // To make the compiler happy. } /** * Query network usage statistics details for a given uid. * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app * @return Statistics which is described above. * @throws SecurityException if permissions are insufficient to read network statistics. * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ @NonNull @WorkerThread public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId, long startTime, long endTime, int uid) throws SecurityException { return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); } /** @hide */ @NonNull public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template, long startTime, long endTime, int uid) throws SecurityException { return queryDetailsForUidTagState(template, startTime, endTime, uid, NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); } /** * Query network usage statistics details for a given uid and tag. * * This may take a long time, and apps should avoid calling this on their main thread. * Only usable for uids belonging to calling user. Result is not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag * the same as the 'tag' parameter, and the state the same as the 'state' parameter. * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *
Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data * across all the tags. * @return Statistics which is described above. * @throws SecurityException if permissions are insufficient to read network statistics. */ @NonNull @WorkerThread public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId, long startTime, long endTime, int uid, int tag) throws SecurityException { return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, tag, NetworkStats.Bucket.STATE_ALL); } /** * Query network usage statistics details for a given uid, tag, and state. * * Only usable for uids belonging to calling user. Result is not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag * the same as the 'tag' parameter, and the state the same as the 'state' parameter. * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *
Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data * across all the tags. * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate * traffic from all states. * @return Statistics which is described above. * @throws SecurityException if permissions are insufficient to read network statistics. */ @NonNull @WorkerThread public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId, long startTime, long endTime, int uid, int tag, int state) throws SecurityException { NetworkTemplate template; template = createTemplate(networkType, subscriberId); return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state); } /** * Query network usage statistics details for a given template, uid, tag, and state. * * Only usable for uids belonging to calling user. Result is not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag * the same as the 'tag' parameter, and the state the same as the 'state' parameter. * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *
Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. * This may take a long time, and apps should avoid calling this on their main thread. * * @param template Template used to match networks. See {@link NetworkTemplate}. * @param startTime Start of period, in milliseconds since the Unix epoch, see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period, in milliseconds since the Unix epoch, see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data * across all the tags. * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate * traffic from all states. * @return Statistics which is described above. * @hide */ @NonNull @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template, long startTime, long endTime, int uid, int tag, int state) throws SecurityException { Objects.requireNonNull(template); try { final NetworkStats result = new NetworkStats( mContext, template, mFlags, startTime, endTime, mService); result.startHistoryUidEnumeration(uid, tag, state); return result; } catch (RemoteException e) { Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag + " state=" + state, e); e.rethrowFromSystemServer(); } return null; // To make the compiler happy. } /** * Query network usage statistics details. Result filtered to include only uids belonging to * calling user. Result is aggregated over state but not aggregated over time, uid, tag, * metered, nor roaming. This means buckets' start and end timestamps are going to be between * 'startTime' and 'endTime' parameters. State is going to be * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, * tag {@link NetworkStats.Bucket#TAG_NONE}, * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *
Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ @WorkerThread public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { template = createTemplate(networkType, subscriberId); } catch (IllegalArgumentException e) { if (DBG) Log.e(TAG, "Cannot create template", e); return null; } NetworkStats result; result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startUserUidEnumeration(); return result; } /** * Query realtime mobile network usage statistics. * * Return a snapshot of current UID network statistics for both cellular and satellite (which * also uses same mobile radio as cellular) when called. The snapshot will include any * tethering traffic, video calling data usage and count of * network operations set by {@link TrafficStats#incrementOperationCount} * made over a mobile radio. * The snapshot will not include any statistics that cannot be seen by * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getMobileUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when get Mobile uid stats"); throw e.rethrowFromSystemServer(); } } /** * Query realtime Wi-Fi network usage statistics. * * Return a snapshot of current UID network statistics, as it applies * to the Wi-Fi radios of the device. The snapshot will include any * tethering traffic, video calling data usage and count of * network operations set by {@link TrafficStats#incrementOperationCount} * made over a Wi-Fi radio. * The snapshot will not include any statistics that cannot be seen by * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. * * @hide */ @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getWifiUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_WIFI); } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when get WiFi uid stats"); throw e.rethrowFromSystemServer(); } } /** * Registers to receive notifications about data usage on specified networks. * *
The callbacks will continue to be called as long as the process is alive or * {@link #unregisterUsageCallback} is called. * * @param template Template used to match networks. See {@link NetworkTemplate}. * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB * will be clamped for callers except callers with the NETWORK_STACK * permission. * @param executor The executor on which callback will be invoked. The provided {@link Executor} * must run callback sequentially, otherwise the order of callbacks cannot be * guaranteed. * @param callback The {@link UsageCallback} that the system will call when data usage * has exceeded the specified threshold. * @hide */ @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}, conditional = true) public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { Objects.requireNonNull(template, "NetworkTemplate cannot be null"); Objects.requireNonNull(callback, "UsageCallback cannot be null"); Objects.requireNonNull(executor, "Executor cannot be null"); final DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, template, thresholdBytes); try { final UsageCallbackWrapper callbackWrapper = new UsageCallbackWrapper(executor, callback); callback.request = mService.registerUsageCallback( mContext.getOpPackageName(), request, callbackWrapper); if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); if (callback.request == null) { Log.e(TAG, "Request from callback is null; should not happen"); } } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when registering callback"); throw e.rethrowFromSystemServer(); } } /** * Registers to receive notifications about data usage on specified networks. * *
The callbacks will continue to be called as long as the process is live or * {@link #unregisterUsageCallback} is called. * * @param networkType Type of network to monitor. Either {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when registering for the mobile network type to receive * notifications for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a * {@code subscriberId} with wifi network type to receive usage for * wifi networks which is under the given subscription if applicable. * Otherwise, pass {@code null} when querying all wifi networks. * @param thresholdBytes Threshold in bytes to be notified on. * @param callback The {@link UsageCallback} that the system will call when data usage * has exceeded the specified threshold. */ public void registerUsageCallback(int networkType, @Nullable String subscriberId, long thresholdBytes, @NonNull UsageCallback callback) { registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, null /* handler */); } /** * Registers to receive notifications about data usage on specified networks. * *
The callbacks will continue to be called as long as the process is live or * {@link #unregisterUsageCallback} is called. * * @param networkType Type of network to monitor. Either {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. * @param subscriberId If applicable, the subscriber id of the network interface. *
Starting with API level 29, the {@code subscriberId} is guarded by * additional restrictions. Calling apps that do not meet the new * requirements to access the {@code subscriberId} can provide a {@code * null} value when registering for the mobile network type to receive * notifications for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. *
Starting with API level 31, calling apps can provide a
* {@code subscriberId} with wifi network type to receive usage for
* wifi networks which is under the given subscription if applicable.
* Otherwise, pass {@code null} when querying all wifi networks.
* @param thresholdBytes Threshold in bytes to be notified on.
* @param callback The {@link UsageCallback} that the system will call when data usage
* has exceeded the specified threshold.
* @param handler to dispatch callback events through, otherwise if {@code null} it uses
* the calling thread.
*/
public void registerUsageCallback(int networkType, @Nullable String subscriberId,
long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) {
NetworkTemplate template = createTemplate(networkType, subscriberId);
if (DBG) {
Log.d(TAG, "registerUsageCallback called with: {"
+ " networkType=" + networkType
+ " subscriberId=" + subscriberId
+ " thresholdBytes=" + thresholdBytes
+ " }");
}
final Executor executor = handler == null ? r -> r.run() : r -> handler.post(r);
registerUsageCallback(template, thresholdBytes, executor, callback);
}
/**
* Unregisters callbacks on data usage.
*
* @param callback The {@link UsageCallback} used when registering.
*/
public void unregisterUsageCallback(@NonNull UsageCallback callback) {
if (callback == null || callback.request == null
|| callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
throw new IllegalArgumentException("Invalid UsageCallback");
}
try {
mService.unregisterUsageRequest(callback.request);
} catch (RemoteException e) {
if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
throw e.rethrowFromSystemServer();
}
}
/**
* Base class for usage callbacks. Should be extended by applications wanting notifications.
*/
public static abstract class UsageCallback {
/**
* Called when data usage has reached the given threshold.
*
* Called by {@code NetworkStatsService} when the registered threshold is reached.
* If a caller implements {@link #onThresholdReached(NetworkTemplate)}, the system
* will not call {@link #onThresholdReached(int, String)}.
*
* @param template The {@link NetworkTemplate} that associated with this callback.
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
public void onThresholdReached(@NonNull NetworkTemplate template) {
// Backward compatibility for those who didn't override this function.
final int networkType = networkTypeForTemplate(template);
if (networkType != ConnectivityManager.TYPE_NONE) {
final String subscriberId = template.getSubscriberIds().isEmpty() ? null
: template.getSubscriberIds().iterator().next();
onThresholdReached(networkType, subscriberId);
}
}
/**
* Called when data usage has reached the given threshold.
*/
public abstract void onThresholdReached(int networkType, @Nullable String subscriberId);
/**
* @hide used for internal bookkeeping
*/
private DataUsageRequest request;
/**
* Get network type from a template if feasible.
*
* @param template the target {@link NetworkTemplate}.
* @return legacy network type, only supports for the types which is already supported in
* {@link #registerUsageCallback(int, String, long, UsageCallback, Handler)}.
* {@link ConnectivityManager#TYPE_NONE} for other types.
*/
private static int networkTypeForTemplate(@NonNull NetworkTemplate template) {
switch (template.getMatchRule()) {
case NetworkTemplate.MATCH_MOBILE:
return ConnectivityManager.TYPE_MOBILE;
case NetworkTemplate.MATCH_WIFI:
return ConnectivityManager.TYPE_WIFI;
default:
return ConnectivityManager.TYPE_NONE;
}
}
}
/**
* Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics
* to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}.
* Note that no de-duplication of statistics between providers is performed, so each provider
* must only report network traffic that is not being reported by any other provider. Also note
* that the provider cannot be re-registered after unregistering.
*
* @param tag a human readable identifier of the custom network stats provider. This is only
* used for debugging.
* @param provider the subclass of {@link NetworkStatsProvider} that needs to be
* registered to the system.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
public void registerNetworkStatsProvider(
@NonNull String tag,
@NonNull NetworkStatsProvider provider) {
try {
if (provider.getProviderCallbackBinder() != null) {
throw new IllegalArgumentException("provider is already registered");
}
final INetworkStatsProviderCallback cbBinder =
mService.registerNetworkStatsProvider(tag, provider.getProviderBinder());
provider.setProviderCallbackBinder(cbBinder);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
* Unregisters an instance of {@link NetworkStatsProvider}.
*
* @param provider the subclass of {@link NetworkStatsProvider} that needs to be
* unregistered to the system.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
try {
provider.getProviderCallbackBinderOrThrow().unregister();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) {
final NetworkTemplate template;
switch (networkType) {
case ConnectivityManager.TYPE_MOBILE:
template = subscriberId == null
? new NetworkTemplate.Builder(MATCH_MOBILE)
.setMeteredness(METERED_YES).build()
: new NetworkTemplate.Builder(MATCH_MOBILE)
.setMeteredness(METERED_YES)
.setSubscriberIds(Set.of(subscriberId)).build();
break;
case ConnectivityManager.TYPE_WIFI:
template = TextUtils.isEmpty(subscriberId)
? new NetworkTemplate.Builder(MATCH_WIFI).build()
: new NetworkTemplate.Builder(MATCH_WIFI)
.setSubscriberIds(Set.of(subscriberId)).build();
break;
default:
throw new IllegalArgumentException("Cannot create template for network type "
+ networkType + ", subscriberId '"
+ NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'.");
}
return template;
}
/**
* Notify {@code NetworkStatsService} about network status changed.
*
* Notifies NetworkStatsService of network state changes for data usage accounting purposes.
*
* To avoid races that attribute data usage to wrong network, such as new network with
* the same interface after SIM hot-swap, this function will not return until
* {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
* all data sources.
*
* @param defaultNetworks the list of all networks that could be used by network traffic that
* does not explicitly select a network.
* @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for
* each network that is currently connected.
* @param activeIface the active (i.e., connected) default network interface for the calling
* uid. Used to determine on which network future calls to
* {@link android.net.TrafficStats#incrementOperationCount} applies to.
* @param underlyingNetworkInfos the list of underlying network information for all
* currently-connected VPNs.
*
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
public void notifyNetworkStatus(
@NonNull List