Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d5840d7 authored by junyulai's avatar junyulai
Browse files

[MS67.1] Expose registerUsageCallback with template

Test: atest FrameworksNetTests
Bug: 204830222
Change-Id: I643e2d96144210852fc8916ec9c483f2b207a48b
parent a7d85f00
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -61,12 +61,17 @@ package android.app.usage {
    method @NonNull @WorkerThread public android.app.usage.NetworkStats querySummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException;
    method @NonNull @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(@NonNull android.net.NetworkTemplate, long, long);
    method @NonNull @WorkerThread public android.app.usage.NetworkStats queryTaggedSummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException;
    method public void registerUsageCallback(@NonNull android.net.NetworkTemplate, long, @NonNull java.util.concurrent.Executor, @NonNull android.app.usage.NetworkStatsManager.UsageCallback);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setDefaultGlobalAlert(long);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setPollOnOpen(boolean);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setStatsProviderWarningAndLimitAsync(@NonNull String, long, long);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setUidForeground(int, boolean);
  }

  public abstract static class NetworkStatsManager.UsageCallback {
    method public void onThresholdReached(@NonNull android.net.NetworkTemplate);
  }

}

package android.bluetooth {
+92 −53
Original line number Diff line number Diff line
@@ -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);
        }
    }

+2 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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 −30
Original line number Diff line number Diff line
@@ -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
Loading