Merge "[MS67.1] Expose registerUsageCallback with template" am: a88cab0f1f am: 3d505ef365
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1956051 Change-Id: Iaadb1473872bcefa2f99d76a79000559cbfd82a0
This commit is contained in:
@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
@@ -39,14 +40,11 @@ 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.provider.INetworkStatsProviderCallback;
|
||||
import android.net.netstats.provider.NetworkStatsProvider;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -57,6 +55,7 @@ import com.android.net.module.util.NetworkIdentityUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Provides access to network usage history and statistics. Usage data is collected in
|
||||
@@ -723,26 +722,35 @@ public class NetworkStatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void registerUsageCallback(NetworkTemplate template, int networkType,
|
||||
long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
|
||||
/**
|
||||
* Registers to receive notifications about data usage on specified networks.
|
||||
*
|
||||
* <p>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.
|
||||
* @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)
|
||||
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 Looper looper;
|
||||
if (handler == null) {
|
||||
looper = Looper.myLooper();
|
||||
} else {
|
||||
looper = handler.getLooper();
|
||||
}
|
||||
|
||||
DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
|
||||
final DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
|
||||
template, thresholdBytes);
|
||||
try {
|
||||
CallbackHandler callbackHandler = new CallbackHandler(looper, networkType,
|
||||
template.getSubscriberId(), callback);
|
||||
final UsageCallbackWrapper callbackWrapper =
|
||||
new UsageCallbackWrapper(executor, callback);
|
||||
callback.request = mService.registerUsageCallback(
|
||||
mContext.getOpPackageName(), request, new Messenger(callbackHandler),
|
||||
new Binder());
|
||||
mContext.getOpPackageName(), request, callbackWrapper);
|
||||
if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request);
|
||||
|
||||
if (callback.request == null) {
|
||||
@@ -800,7 +808,10 @@ public class NetworkStatsManager {
|
||||
+ " thresholdBytes=" + thresholdBytes
|
||||
+ " }");
|
||||
}
|
||||
registerUsageCallback(template, networkType, thresholdBytes, callback, handler);
|
||||
|
||||
final Executor executor = handler == null ? r -> r.run() : r -> handler.post(r);
|
||||
|
||||
registerUsageCallback(template, thresholdBytes, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -825,6 +836,26 @@ public class NetworkStatsManager {
|
||||
* 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.
|
||||
@@ -835,6 +866,25 @@ public class NetworkStatsManager {
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -953,43 +1003,32 @@ public class NetworkStatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static class CallbackHandler extends Handler {
|
||||
private final int mNetworkType;
|
||||
private final String mSubscriberId;
|
||||
private UsageCallback mCallback;
|
||||
private static class UsageCallbackWrapper extends IUsageCallback.Stub {
|
||||
// Null if unregistered.
|
||||
private volatile UsageCallback mCallback;
|
||||
|
||||
CallbackHandler(Looper looper, int networkType, String subscriberId,
|
||||
UsageCallback callback) {
|
||||
super(looper);
|
||||
mNetworkType = networkType;
|
||||
mSubscriberId = subscriberId;
|
||||
private final Executor mExecutor;
|
||||
|
||||
UsageCallbackWrapper(@NonNull Executor executor, @NonNull UsageCallback callback) {
|
||||
mCallback = callback;
|
||||
mExecutor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
DataUsageRequest request =
|
||||
(DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
|
||||
|
||||
switch (message.what) {
|
||||
case CALLBACK_LIMIT_REACHED: {
|
||||
if (mCallback != null) {
|
||||
mCallback.onThresholdReached(mNetworkType, mSubscriberId);
|
||||
public void onThresholdReached(DataUsageRequest request) {
|
||||
// Copy it to a local variable in case mCallback changed inside the if condition.
|
||||
final UsageCallback callback = mCallback;
|
||||
if (callback != null) {
|
||||
mExecutor.execute(() -> callback.onThresholdReached(request.template));
|
||||
} else {
|
||||
Log.e(TAG, "limit reached with released callback for " + request);
|
||||
Log.e(TAG, "onThresholdReached with released callback for " + request);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CALLBACK_RELEASED: {
|
||||
|
||||
@Override
|
||||
public void onCallbackReleased(DataUsageRequest request) {
|
||||
if (DBG) Log.d(TAG, "callback released for " + request);
|
||||
mCallback = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Object getObject(Message msg, String key) {
|
||||
return msg.getData().getParcelable(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.net.NetworkStats;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.net.UnderlyingNetworkInfo;
|
||||
import android.net.netstats.IUsageCallback;
|
||||
import android.net.netstats.provider.INetworkStatsProvider;
|
||||
import android.net.netstats.provider.INetworkStatsProviderCallback;
|
||||
import android.os.IBinder;
|
||||
@@ -71,7 +72,7 @@ interface INetworkStatsService {
|
||||
|
||||
/** Registers a callback on data usage. */
|
||||
DataUsageRequest registerUsageCallback(String callingPackage,
|
||||
in DataUsageRequest request, in Messenger messenger, in IBinder binder);
|
||||
in DataUsageRequest request, in IUsageCallback callback);
|
||||
|
||||
/** Unregisters a callback on data usage. */
|
||||
void unregisterUsageRequest(in DataUsageRequest request);
|
||||
|
||||
29
framework-t/src/android/net/netstats/IUsageCallback.aidl
Normal file
29
framework-t/src/android/net/netstats/IUsageCallback.aidl
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.net.netstats;
|
||||
|
||||
import android.net.DataUsageRequest;
|
||||
|
||||
/**
|
||||
* Interface for NetworkStatsService to notify events to the callers of registerUsageCallback.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IUsageCallback {
|
||||
void onThresholdReached(in DataUsageRequest request);
|
||||
void onCallbackReleased(in DataUsageRequest request);
|
||||
}
|
||||
@@ -26,13 +26,12 @@ import android.net.NetworkStatsAccess;
|
||||
import android.net.NetworkStatsCollection;
|
||||
import android.net.NetworkStatsHistory;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.os.Bundle;
|
||||
import android.net.netstats.IUsageCallback;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
@@ -75,10 +74,10 @@ class NetworkStatsObservers {
|
||||
*
|
||||
* @return the normalized request wrapped within {@link RequestInfo}.
|
||||
*/
|
||||
public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger,
|
||||
IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
|
||||
public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback,
|
||||
int callingUid, @NetworkStatsAccess.Level int accessLevel) {
|
||||
DataUsageRequest request = buildRequest(inputRequest);
|
||||
RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
|
||||
RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid,
|
||||
accessLevel);
|
||||
|
||||
if (LOGV) Log.v(TAG, "Registering observer for " + request);
|
||||
@@ -206,11 +205,10 @@ class NetworkStatsObservers {
|
||||
request.template, thresholdInBytes);
|
||||
}
|
||||
|
||||
private RequestInfo buildRequestInfo(DataUsageRequest request,
|
||||
Messenger messenger, IBinder binder, int callingUid,
|
||||
@NetworkStatsAccess.Level int accessLevel) {
|
||||
private RequestInfo buildRequestInfo(DataUsageRequest request, IUsageCallback callback,
|
||||
int callingUid, @NetworkStatsAccess.Level int accessLevel) {
|
||||
if (accessLevel <= NetworkStatsAccess.Level.USER) {
|
||||
return new UserUsageRequestInfo(this, request, messenger, binder, callingUid,
|
||||
return new UserUsageRequestInfo(this, request, callback, callingUid,
|
||||
accessLevel);
|
||||
} else {
|
||||
// Safety check in case a new access level is added and we forgot to update this
|
||||
@@ -218,7 +216,7 @@ class NetworkStatsObservers {
|
||||
throw new IllegalArgumentException(
|
||||
"accessLevel " + accessLevel + " is less than DEVICESUMMARY.");
|
||||
}
|
||||
return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid,
|
||||
return new NetworkUsageRequestInfo(this, request, callback, callingUid,
|
||||
accessLevel);
|
||||
}
|
||||
}
|
||||
@@ -230,25 +228,23 @@ class NetworkStatsObservers {
|
||||
private abstract static class RequestInfo implements IBinder.DeathRecipient {
|
||||
private final NetworkStatsObservers mStatsObserver;
|
||||
protected final DataUsageRequest mRequest;
|
||||
private final Messenger mMessenger;
|
||||
private final IBinder mBinder;
|
||||
private final IUsageCallback mCallback;
|
||||
protected final int mCallingUid;
|
||||
protected final @NetworkStatsAccess.Level int mAccessLevel;
|
||||
protected NetworkStatsRecorder mRecorder;
|
||||
protected NetworkStatsCollection mCollection;
|
||||
|
||||
RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
|
||||
Messenger messenger, IBinder binder, int callingUid,
|
||||
IUsageCallback callback, int callingUid,
|
||||
@NetworkStatsAccess.Level int accessLevel) {
|
||||
mStatsObserver = statsObserver;
|
||||
mRequest = request;
|
||||
mMessenger = messenger;
|
||||
mBinder = binder;
|
||||
mCallback = callback;
|
||||
mCallingUid = callingUid;
|
||||
mAccessLevel = accessLevel;
|
||||
|
||||
try {
|
||||
mBinder.linkToDeath(this, 0);
|
||||
mCallback.asBinder().linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
binderDied();
|
||||
}
|
||||
@@ -257,7 +253,7 @@ class NetworkStatsObservers {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
if (LOGV) {
|
||||
Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mBinder + ")");
|
||||
Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mCallback + ")");
|
||||
}
|
||||
mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
|
||||
callCallback(NetworkStatsManager.CALLBACK_RELEASED);
|
||||
@@ -270,9 +266,7 @@ class NetworkStatsObservers {
|
||||
}
|
||||
|
||||
private void unlinkDeathRecipient() {
|
||||
if (mBinder != null) {
|
||||
mBinder.unlinkToDeath(this, 0);
|
||||
}
|
||||
mCallback.asBinder().unlinkToDeath(this, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,17 +288,19 @@ class NetworkStatsObservers {
|
||||
}
|
||||
|
||||
private void callCallback(int callbackType) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(DataUsageRequest.PARCELABLE_KEY, mRequest);
|
||||
Message msg = Message.obtain();
|
||||
msg.what = callbackType;
|
||||
msg.setData(bundle);
|
||||
try {
|
||||
if (LOGV) {
|
||||
Log.v(TAG, "sending notification " + callbackTypeToName(callbackType)
|
||||
+ " for " + mRequest);
|
||||
}
|
||||
mMessenger.send(msg);
|
||||
switch (callbackType) {
|
||||
case NetworkStatsManager.CALLBACK_LIMIT_REACHED:
|
||||
mCallback.onThresholdReached(mRequest);
|
||||
break;
|
||||
case NetworkStatsManager.CALLBACK_RELEASED:
|
||||
mCallback.onCallbackReleased(mRequest);
|
||||
break;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// May occur naturally in the race of binder death.
|
||||
Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
|
||||
@@ -334,9 +330,9 @@ class NetworkStatsObservers {
|
||||
|
||||
private static class NetworkUsageRequestInfo extends RequestInfo {
|
||||
NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
|
||||
Messenger messenger, IBinder binder, int callingUid,
|
||||
IUsageCallback callback, int callingUid,
|
||||
@NetworkStatsAccess.Level int accessLevel) {
|
||||
super(statsObserver, request, messenger, binder, callingUid, accessLevel);
|
||||
super(statsObserver, request, callback, callingUid, accessLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -376,9 +372,9 @@ class NetworkStatsObservers {
|
||||
|
||||
private static class UserUsageRequestInfo extends RequestInfo {
|
||||
UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
|
||||
Messenger messenger, IBinder binder, int callingUid,
|
||||
IUsageCallback callback, int callingUid,
|
||||
@NetworkStatsAccess.Level int accessLevel) {
|
||||
super(statsObserver, request, messenger, binder, callingUid, accessLevel);
|
||||
super(statsObserver, request, callback, callingUid, accessLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -99,6 +99,7 @@ import android.net.TetheringManager;
|
||||
import android.net.TrafficStats;
|
||||
import android.net.UnderlyingNetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.net.netstats.IUsageCallback;
|
||||
import android.net.netstats.provider.INetworkStatsProvider;
|
||||
import android.net.netstats.provider.INetworkStatsProviderCallback;
|
||||
import android.net.netstats.provider.NetworkStatsProvider;
|
||||
@@ -110,7 +111,6 @@ import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceSpecificException;
|
||||
@@ -1148,21 +1148,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUsageRequest registerUsageCallback(String callingPackage,
|
||||
DataUsageRequest request, Messenger messenger, IBinder binder) {
|
||||
public DataUsageRequest registerUsageCallback(@NonNull String callingPackage,
|
||||
@NonNull DataUsageRequest request, @NonNull IUsageCallback callback) {
|
||||
Objects.requireNonNull(callingPackage, "calling package is null");
|
||||
Objects.requireNonNull(request, "DataUsageRequest is null");
|
||||
Objects.requireNonNull(request.template, "NetworkTemplate is null");
|
||||
Objects.requireNonNull(messenger, "messenger is null");
|
||||
Objects.requireNonNull(binder, "binder is null");
|
||||
Objects.requireNonNull(callback, "callback is null");
|
||||
|
||||
int callingUid = Binder.getCallingUid();
|
||||
@NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
|
||||
DataUsageRequest normalizedRequest;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
normalizedRequest = mStatsObservers.register(request, messenger, binder,
|
||||
callingUid, accessLevel);
|
||||
normalizedRequest = mStatsObservers.register(
|
||||
request, callback, callingUid, accessLevel);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user