Merge "transcoding: Do not throw exception in registerClient." into sc-dev
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 4ca3105..5b28e00 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -237,7 +237,8 @@
     public BiometricTestSession createTestSession(int sensorId) {
         try {
             return new BiometricTestSession(mContext, sensorId,
-                    mService.createTestSession(sensorId, mContext.getOpPackageName()));
+                    (context, sensorId1, callback) -> mService
+                            .createTestSession(sensorId1, callback, context.getOpPackageName()));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/biometrics/BiometricTestSession.java b/core/java/android/hardware/biometrics/BiometricTestSession.java
index 1c35608..ff1a17e 100644
--- a/core/java/android/hardware/biometrics/BiometricTestSession.java
+++ b/core/java/android/hardware/biometrics/BiometricTestSession.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.TEST_BIOMETRIC;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
 import android.content.Context;
@@ -27,6 +28,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Common set of interfaces to test biometric-related APIs, including {@link BiometricPrompt} and
  * {@link android.hardware.fingerprint.FingerprintManager}.
@@ -36,22 +40,58 @@
 public class BiometricTestSession implements AutoCloseable {
     private static final String TAG = "BiometricTestSession";
 
+    /**
+     * @hide
+     */
+    public interface TestSessionProvider {
+        @NonNull
+        ITestSession createTestSession(@NonNull Context context, int sensorId,
+                @NonNull ITestSessionCallback callback) throws RemoteException;
+    }
+
     private final Context mContext;
     private final int mSensorId;
     private final ITestSession mTestSession;
 
     // Keep track of users that were tested, which need to be cleaned up when finishing.
-    private final ArraySet<Integer> mTestedUsers;
+    @NonNull private final ArraySet<Integer> mTestedUsers;
+
+    // Track the users currently cleaning up, and provide a latch that gets notified when all
+    // users have finished cleaning up. This is an imperfect system, as there can technically be
+    // multiple cleanups per user. Theoretically we should track the cleanup's BaseClientMonitor's
+    // unique ID, but it's complicated to plumb it through. This should be fine for now.
+    @Nullable private CountDownLatch mCloseLatch;
+    @NonNull private final ArraySet<Integer> mUsersCleaningUp;
+
+    private final ITestSessionCallback mCallback = new ITestSessionCallback.Stub() {
+        @Override
+        public void onCleanupStarted(int userId) {
+            Log.d(TAG, "onCleanupStarted, sensor: " + mSensorId + ", userId: " + userId);
+        }
+
+        @Override
+        public void onCleanupFinished(int userId) {
+            Log.d(TAG, "onCleanupFinished, sensor: " + mSensorId
+                    + ", userId: " + userId
+                    + ", remaining users: " + mUsersCleaningUp.size());
+            mUsersCleaningUp.remove(userId);
+
+            if (mUsersCleaningUp.isEmpty() && mCloseLatch != null) {
+                mCloseLatch.countDown();
+            }
+        }
+    };
 
     /**
      * @hide
      */
     public BiometricTestSession(@NonNull Context context, int sensorId,
-            @NonNull ITestSession testSession) {
+            @NonNull TestSessionProvider testSessionProvider) throws RemoteException {
         mContext = context;
         mSensorId = sensorId;
-        mTestSession = testSession;
+        mTestSession = testSessionProvider.createTestSession(context, sensorId, mCallback);
         mTestedUsers = new ArraySet<>();
+        mUsersCleaningUp = new ArraySet<>();
         setTestHalEnabled(true);
     }
 
@@ -176,6 +216,11 @@
     @RequiresPermission(TEST_BIOMETRIC)
     public void cleanupInternalState(int userId) {
         try {
+            if (mUsersCleaningUp.contains(userId)) {
+                Log.w(TAG, "Cleanup already in progress for user: " + userId);
+            }
+
+            mUsersCleaningUp.add(userId);
             mTestSession.cleanupInternalState(userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -185,12 +230,24 @@
     @Override
     @RequiresPermission(TEST_BIOMETRIC)
     public void close() {
-        // Disable the test HAL first, so that enumerate is run on the real HAL, which should have
-        // no enrollments. Test-only framework enrollments will be deleted.
-        setTestHalEnabled(false);
+        // Cleanup can be performed using the test HAL, since it always responds to enumerate with
+        // zero enrollments.
+        if (!mTestedUsers.isEmpty()) {
+            mCloseLatch = new CountDownLatch(1);
+            for (int user : mTestedUsers) {
+                cleanupInternalState(user);
+            }
 
-        for (int user : mTestedUsers) {
-            cleanupInternalState(user);
+            try {
+                Log.d(TAG, "Awaiting latch...");
+                mCloseLatch.await(10, TimeUnit.SECONDS);
+                Log.d(TAG, "Finished awaiting");
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Latch interrupted", e);
+            }
         }
+
+        // Disable the test HAL after the sensor becomes idle.
+        setTestHalEnabled(false);
     }
 }
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 0dfd5db..d8c9dbc 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -20,6 +20,7 @@
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorPropertiesInternal;
 
@@ -32,7 +33,7 @@
  */
 interface IAuthService {
     // Creates a test session with the specified sensorId
-    ITestSession createTestSession(int sensorId, String opPackageName);
+    ITestSession createTestSession(int sensorId, ITestSessionCallback callback, String opPackageName);
 
     // Retrieve static sensor properties for all biometric sensors
     List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index c854ac98..7639c5d 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -20,6 +20,7 @@
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
@@ -32,7 +33,7 @@
 interface IBiometricAuthenticator {
 
     // Creates a test session
-    ITestSession createTestSession(String opPackageName);
+    ITestSession createTestSession(ITestSessionCallback callback, String opPackageName);
 
     // Retrieve static sensor properties
     SensorPropertiesInternal getSensorProperties(String opPackageName);
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index a14a910..2433186 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -21,6 +21,7 @@
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorPropertiesInternal;
 
@@ -30,7 +31,7 @@
  */
 interface IBiometricService {
     // Creates a test session with the specified sensorId
-    ITestSession createTestSession(int sensorId, String opPackageName);
+    ITestSession createTestSession(int sensorId, ITestSessionCallback callback, String opPackageName);
 
     // Retrieve static sensor properties for all biometric sensors
     List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
diff --git a/core/java/android/hardware/biometrics/ITestSession.aidl b/core/java/android/hardware/biometrics/ITestSession.aidl
index fa7a62c..f8395a1 100644
--- a/core/java/android/hardware/biometrics/ITestSession.aidl
+++ b/core/java/android/hardware/biometrics/ITestSession.aidl
@@ -18,7 +18,7 @@
 import android.hardware.biometrics.SensorPropertiesInternal;
 
 /**
- * A test service for FingerprintManager and BiometricPrompt.
+ * A test service for FingerprintManager and BiometricManager.
  * @hide
  */
 interface ITestSession {
diff --git a/core/java/android/hardware/biometrics/ITestSessionCallback.aidl b/core/java/android/hardware/biometrics/ITestSessionCallback.aidl
new file mode 100644
index 0000000..3d9517f
--- /dev/null
+++ b/core/java/android/hardware/biometrics/ITestSessionCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 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.hardware.biometrics;
+
+/**
+ * ITestSession callback for FingerprintManager and BiometricManager.
+ * @hide
+ */
+interface ITestSessionCallback {
+    void onCleanupStarted(int userId);
+    void onCleanupFinished(int userId);
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 886a8c1..a9bcdeff 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -574,12 +574,23 @@
                 mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver,
                         mContext.getOpPackageName());
             } catch (RemoteException e) {
-                Slog.w(TAG, "Remote exception in remove: ", e);
-                if (callback != null) {
-                    callback.onRemovalError(face, FACE_ERROR_HW_UNAVAILABLE,
-                            getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
-                                0 /* vendorCode */));
-                }
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Removes all face templates for the given user.
+     * @hide
+     */
+    @RequiresPermission(MANAGE_BIOMETRIC)
+    public void removeAll(int userId, @NonNull RemovalCallback callback) {
+        if (mService != null) {
+            try {
+                mRemovalCallback = callback;
+                mService.removeAll(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index a3e7e2d..6e7c701 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -19,6 +19,7 @@
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
 import android.hardware.face.FaceSensorPropertiesInternal;
@@ -32,7 +33,7 @@
 interface IFaceService {
 
     // Creates a test session with the specified sensorId
-    ITestSession createTestSession(int sensorId, String opPackageName);
+    ITestSession createTestSession(int sensorId, ITestSessionCallback callback, String opPackageName);
 
     // Requests a proto dump of the specified sensor
     byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer);
@@ -83,10 +84,13 @@
     // Cancel enrollment in progress
     void cancelEnrollment(IBinder token);
 
-    // Any errors resulting from this call will be returned to the listener
+    // Removes the specified face enrollment for the specified userId.
     void remove(IBinder token, int faceId, int userId, IFaceServiceReceiver receiver,
             String opPackageName);
 
+    // Removes all face enrollments for the specified userId.
+    void removeAll(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
+
     // Get the enrolled face for user.
     List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName);
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a614ebf..fc795d8 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -114,6 +114,21 @@
      */
     public static final int SENSOR_ID_ANY = -1;
 
+    private static class RemoveTracker {
+        static final int REMOVE_SINGLE = 1;
+        static final int REMOVE_ALL = 2;
+        @IntDef({REMOVE_SINGLE, REMOVE_ALL})
+        @interface RemoveRequest {}
+
+        final @RemoveRequest int mRemoveRequest;
+        @Nullable final Fingerprint mSingleFingerprint;
+
+        RemoveTracker(@RemoveRequest int request, @Nullable Fingerprint fingerprint) {
+            mRemoveRequest = request;
+            mSingleFingerprint = fingerprint;
+        }
+    }
+
     private IFingerprintService mService;
     private Context mContext;
     private IBinder mToken = new Binder();
@@ -123,10 +138,9 @@
     private RemovalCallback mRemovalCallback;
     private GenerateChallengeCallback mGenerateChallengeCallback;
     private CryptoObject mCryptoObject;
-    private Fingerprint mRemovalFingerprint;
+    @Nullable private RemoveTracker mRemoveTracker;
     private Handler mHandler;
 
-
     /**
      * Retrieves a list of properties for all fingerprint sensors on the device.
      * @hide
@@ -154,7 +168,8 @@
     public BiometricTestSession createTestSession(int sensorId) {
         try {
             return new BiometricTestSession(mContext, sensorId,
-                    mService.createTestSession(sensorId, mContext.getOpPackageName()));
+                    (context, sensorId1, callback) -> mService
+                            .createTestSession(sensorId1, callback, context.getOpPackageName()));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -735,15 +750,27 @@
     public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
         if (mService != null) try {
             mRemovalCallback = callback;
-            mRemovalFingerprint = fp;
+            mRemoveTracker = new RemoveTracker(RemoveTracker.REMOVE_SINGLE, fp);
             mService.remove(mToken, fp.getBiometricId(), userId, mServiceReceiver,
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Slog.w(TAG, "Remote exception in remove: ", e);
-            if (callback != null) {
-                callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(mContext, FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                            0 /* vendorCode */));
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes all face templates for the given user.
+     * @hide
+     */
+    @RequiresPermission(MANAGE_FINGERPRINT)
+    public void removeAll(int userId, @NonNull RemovalCallback callback) {
+        if (mService != null) {
+            try {
+                mRemovalCallback = callback;
+                mRemoveTracker = new RemoveTracker(RemoveTracker.REMOVE_ALL, null /* fp */);
+                mService.removeAll(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1044,16 +1071,29 @@
         if (mRemovalCallback == null) {
             return;
         }
-        if (fingerprint == null) {
-            Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
+
+        if (mRemoveTracker == null) {
+            Slog.w(TAG, "Removal tracker is null");
             return;
         }
 
-        int fingerId = fingerprint.getBiometricId();
-        int reqFingerId = mRemovalFingerprint.getBiometricId();
-        if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
-            Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
-            return;
+        if (mRemoveTracker.mRemoveRequest == RemoveTracker.REMOVE_SINGLE) {
+            if (fingerprint == null) {
+                Slog.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
+                return;
+            }
+
+            if (mRemoveTracker.mSingleFingerprint == null) {
+                Slog.e(TAG, "Missing fingerprint");
+                return;
+            }
+
+            final int fingerId = fingerprint.getBiometricId();
+            int reqFingerId = mRemoveTracker.mSingleFingerprint.getBiometricId();
+            if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
+                Slog.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+                return;
+            }
         }
 
         mRemovalCallback.onRemovalSucceeded(fingerprint, remaining);
@@ -1110,7 +1150,9 @@
             mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
                     getErrorString(mContext, errMsgId, vendorCode));
         } else if (mRemovalCallback != null) {
-            mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
+            final Fingerprint fp = mRemoveTracker != null
+                    ? mRemoveTracker.mSingleFingerprint : null;
+            mRemovalCallback.onRemovalError(fp, clientErrMsgId,
                     getErrorString(mContext, errMsgId, vendorCode));
         }
     }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 8888247..054c0d0 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -19,6 +19,7 @@
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -33,7 +34,7 @@
 interface IFingerprintService {
 
     // Creates a test session with the specified sensorId
-    ITestSession createTestSession(int sensorId, String opPackageName);
+    ITestSession createTestSession(int sensorId, ITestSessionCallback callback, String opPackageName);
 
     // Requests a proto dump of the specified sensor
     byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer);
@@ -87,6 +88,9 @@
     void remove(IBinder token, int fingerId, int userId, IFingerprintServiceReceiver receiver,
             String opPackageName);
 
+    // Removes all face enrollments for the specified userId.
+    void removeAll(IBinder token, int userId, IFingerprintServiceReceiver receiver, String opPackageName);
+
     // Rename the fingerprint specified by fingerId and userId to the given name
     void rename(int fingerId, int userId, String name);
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 33dedda..874add5 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -24,7 +24,6 @@
 import android.net.NetworkStats;
 import android.net.RouteInfo;
 import android.net.UidRange;
-import android.os.INetworkActivityListener;
 
 /**
  * @hide
@@ -294,25 +293,6 @@
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     boolean isBandwidthControlEnabled();
 
-    /**
-     * Sets idletimer for an interface.
-     *
-     * This either initializes a new idletimer or increases its
-     * reference-counting if an idletimer already exists for given
-     * {@code iface}.
-     *
-     * {@code type} is the type of the interface, such as TYPE_MOBILE.
-     *
-     * Every {@code addIdleTimer} should be paired with a
-     * {@link removeIdleTimer} to cleanup when the network disconnects.
-     */
-    void addIdleTimer(String iface, int timeout, int type);
-
-    /**
-     * Removes idletimer for an interface.
-     */
-    void removeIdleTimer(String iface);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
@@ -320,21 +300,6 @@
     void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
     void setFirewallChainEnabled(int chain, boolean enable);
 
-    /**
-     * Start listening for mobile activity state changes.
-     */
-    void registerNetworkActivityListener(INetworkActivityListener listener);
-
-    /**
-     * Stop listening for mobile activity state changes.
-     */
-    void unregisterNetworkActivityListener(INetworkActivityListener listener);
-
-    /**
-     * Check whether the mobile radio is currently active.
-     */
-    boolean isNetworkActive();
-
     void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
 
     /**
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index d7c8291..4ddae53 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -49,8 +49,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -835,7 +833,6 @@
 
     private final Context mContext;
 
-    private INetworkManagementService mNMService;
     private INetworkPolicyManager mNPManager;
     private final TetheringManager mTetheringManager;
 
@@ -2211,17 +2208,6 @@
         void onNetworkActive();
     }
 
-    private INetworkManagementService getNetworkManagementService() {
-        synchronized (this) {
-            if (mNMService != null) {
-                return mNMService;
-            }
-            IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-            mNMService = INetworkManagementService.Stub.asInterface(b);
-            return mNMService;
-        }
-    }
-
     private final ArrayMap<OnNetworkActiveListener, INetworkActivityListener>
             mNetworkActivityListeners = new ArrayMap<>();
 
@@ -2246,7 +2232,7 @@
         };
 
         try {
-            getNetworkManagementService().registerNetworkActivityListener(rl);
+            mService.registerNetworkActivityListener(rl);
             mNetworkActivityListeners.put(l, rl);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -2263,7 +2249,7 @@
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
         Preconditions.checkArgument(rl != null, "Listener was not registered.");
         try {
-            getNetworkManagementService().unregisterNetworkActivityListener(rl);
+            mService.registerNetworkActivityListener(rl);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2279,7 +2265,7 @@
      */
     public boolean isDefaultNetworkActive() {
         try {
-            return getNetworkManagementService().isNetworkActive();
+            return mService.isDefaultNetworkActive();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index 6391802..160338d 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -21,6 +21,7 @@
 import android.net.ConnectivityDiagnosticsManager;
 import android.net.IConnectivityDiagnosticsCallback;
 import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.INetworkActivityListener;
 import android.net.IQosCallback;
 import android.net.ISocketKeepaliveCallback;
 import android.net.LinkProperties;
@@ -36,7 +37,6 @@
 import android.net.QosSocketInfo;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
diff --git a/core/java/android/os/INetworkActivityListener.aidl b/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
similarity index 96%
rename from core/java/android/os/INetworkActivityListener.aidl
rename to packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
index 24e6e55..79687dd 100644
--- a/core/java/android/os/INetworkActivityListener.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
@@ -13,7 +13,7 @@
 ** limitations under the License.
 */
 
-package android.os;
+package android.net;
 
 /**
  * @hide
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 6e2398c..eb95d16 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -56,6 +56,7 @@
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.fingerprint.FingerprintManager;
 import android.media.AudioManager;
+import android.nfc.NfcAdapter;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
@@ -851,6 +852,17 @@
         assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
     }
 
+    @Test
+    public void testRequireUnlockForNfc_Broadcast() {
+        KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+        mKeyguardUpdateMonitor.registerCallback(callback);
+        Intent intent = new Intent(NfcAdapter.ACTION_REQUIRE_UNLOCK_FOR_NFC);
+        mKeyguardUpdateMonitor.mBroadcastAllReceiver.onReceive(getContext(), intent);
+        mTestableLooper.processAllMessages();
+
+        verify(callback, atLeastOnce()).onRequireUnlockForNfc();
+    }
+
     private void setKeyguardBouncerVisibility(boolean isVisible) {
         mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible);
         mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 0cae6742..ce14bca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -609,6 +609,16 @@
         assertThat(mTextView.getText()).isEqualTo(percentage);
     }
 
+    @Test
+    public void onRequireUnlockForNfc_showsRequireUnlockForNfcIndication() {
+        createController();
+        String message = mContext.getString(R.string.require_unlock_for_nfc);
+        mController.getKeyguardCallback().onRequireUnlockForNfc();
+        mController.setVisible(true);
+
+        assertThat(mTextView.getText()).isEqualTo(message);
+    }
+
     private void sendUpdateDisclosureBroadcast() {
         mBroadcastReceiver.onReceive(mContext, new Intent());
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5077cc6..f54551e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -90,6 +90,7 @@
 import android.net.IConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
+import android.net.INetworkActivityListener;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -147,13 +148,13 @@
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
+import android.os.BatteryStatsManager;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
@@ -163,6 +164,7 @@
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
@@ -172,6 +174,7 @@
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
@@ -559,6 +562,11 @@
     private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
 
     /**
+     * Used to indicate the system default network becomes active.
+     */
+    private static final int EVENT_REPORT_NETWORK_ACTIVITY = 49;
+
+    /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be shown.
      */
@@ -1192,7 +1200,7 @@
         mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
                 null /* broadcastPermission */, mHandler);
 
-        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
+        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
 
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
@@ -2404,7 +2412,7 @@
      */
     @Override
     public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
-        // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+        mNetworkActivityTracker.registerNetworkActivityListener(l);
     }
 
     /**
@@ -2412,7 +2420,7 @@
      */
     @Override
     public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
-        // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+        mNetworkActivityTracker.unregisterNetworkActivityListener(l);
     }
 
     /**
@@ -2420,8 +2428,7 @@
      */
     @Override
     public boolean isDefaultNetworkActive() {
-        // TODO: Replace isNetworkActive() in NMS.
-        return false;
+        return mNetworkActivityTracker.isDefaultNetworkActive();
     }
 
     /**
@@ -2686,6 +2693,12 @@
         pw.increaseIndent();
         mPermissionMonitor.dump(pw);
         pw.decreaseIndent();
+
+        pw.println();
+        pw.println("Legacy network activity:");
+        pw.increaseIndent();
+        mNetworkActivityTracker.dump(pw);
+        pw.decreaseIndent();
     }
 
     private void dumpNetworks(IndentingPrintWriter pw) {
@@ -4452,6 +4465,9 @@
                         loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
                     }
                     break;
+                case EVENT_REPORT_NETWORK_ACTIVITY:
+                    mNetworkActivityTracker.handleReportNetworkActivity();
+                    break;
             }
         }
     }
@@ -8639,13 +8655,35 @@
      * changes.
      */
     private static final class LegacyNetworkActivityTracker {
+        private static final int NO_UID = -1;
         private final Context mContext;
+        private final INetd mNetd;
         private final INetworkManagementService mNMS;
+        private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
+                new RemoteCallbackList<>();
+        // Indicate the current system default network activity is active or not.
+        @GuardedBy("mActiveIdleTimers")
+        private boolean mNetworkActive;
+        @GuardedBy("mActiveIdleTimers")
+        private final ArrayMap<String, IdleTimerParams> mActiveIdleTimers = new ArrayMap();
+        private final Handler mHandler;
 
-        LegacyNetworkActivityTracker(@NonNull Context context,
-                @NonNull INetworkManagementService nms) {
+        private class IdleTimerParams {
+            public final int timeout;
+            public final int transportType;
+
+            IdleTimerParams(int timeout, int transport) {
+                this.timeout = timeout;
+                this.transportType = transport;
+            }
+        }
+
+        LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
+                @NonNull INetworkManagementService nms, @NonNull INetd netd) {
             mContext = context;
             mNMS = nms;
+            mNetd = netd;
+            mHandler = handler;
             try {
                 mNMS.registerObserver(mDataActivityObserver);
             } catch (RemoteException e) {
@@ -8661,9 +8699,50 @@
                             long tsNanos, int uid) {
                         sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
                                 tsNanos);
+                        synchronized (mActiveIdleTimers) {
+                            mNetworkActive = active;
+                            // If there are no idle timers, it means that system is not monitoring
+                            // activity, so the system default network for those default network
+                            // unspecified apps is always considered active.
+                            //
+                            // TODO: If the mActiveIdleTimers is empty, netd will actually not send
+                            // any network activity change event. Whenever this event is received,
+                            // the mActiveIdleTimers should be always not empty. The legacy behavior
+                            // is no-op. Remove to refer to mNetworkActive only.
+                            if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
+                                mHandler.sendMessage(
+                                        mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
+                            }
+                        }
                     }
                 };
 
+        // The network activity should only be updated from ConnectivityService handler thread
+        // when mActiveIdleTimers lock is held.
+        @GuardedBy("mActiveIdleTimers")
+        private void reportNetworkActive() {
+            final int length = mNetworkActivityListeners.beginBroadcast();
+            if (DDBG) log("reportNetworkActive, notify " + length + " listeners");
+            try {
+                for (int i = 0; i < length; i++) {
+                    try {
+                        mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
+                    } catch (RemoteException | RuntimeException e) {
+                        loge("Fail to send network activie to listener " + e);
+                    }
+                }
+            } finally {
+                mNetworkActivityListeners.finishBroadcast();
+            }
+        }
+
+        @GuardedBy("mActiveIdleTimers")
+        public void handleReportNetworkActivity() {
+            synchronized (mActiveIdleTimers) {
+                reportNetworkActive();
+            }
+        }
+
         // This is deprecated and only to support legacy use cases.
         private int transportTypeToLegacyType(int type) {
             switch (type) {
@@ -8728,10 +8807,17 @@
                 return; // do not track any other networks
             }
 
+            updateRadioPowerState(true /* isActive */, type);
+
             if (timeout > 0 && iface != null) {
                 try {
-                    // TODO: Access INetd directly instead of NMS
-                    mNMS.addIdleTimer(iface, timeout, type);
+                    synchronized (mActiveIdleTimers) {
+                        // Networks start up.
+                        mNetworkActive = true;
+                        mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
+                        mNetd.idletimerAddInterface(iface, timeout, Integer.toString(type));
+                        reportNetworkActive();
+                    }
                 } catch (Exception e) {
                     // You shall not crash!
                     loge("Exception in setupDataActivityTracking " + e);
@@ -8746,16 +8832,28 @@
             final String iface = networkAgent.linkProperties.getInterfaceName();
             final NetworkCapabilities caps = networkAgent.networkCapabilities;
 
-            if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
-                    || caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
-                try {
-                    // the call fails silently if no idle timer setup for this interface
-                    // TODO: Access INetd directly instead of NMS
-                    mNMS.removeIdleTimer(iface);
-                } catch (Exception e) {
-                    // You shall not crash!
-                    loge("Exception in removeDataActivityTracking " + e);
+            if (iface == null) return;
+
+            final int type;
+            if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                type = NetworkCapabilities.TRANSPORT_CELLULAR;
+            } else if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                type = NetworkCapabilities.TRANSPORT_WIFI;
+            } else {
+                return; // do not track any other networks
+            }
+
+            try {
+                updateRadioPowerState(false /* isActive */, type);
+                synchronized (mActiveIdleTimers) {
+                    final IdleTimerParams params = mActiveIdleTimers.remove(iface);
+                    // The call fails silently if no idle timer setup for this interface
+                    mNetd.idletimerRemoveInterface(iface, params.timeout,
+                            Integer.toString(params.transportType));
                 }
+            } catch (Exception e) {
+                // You shall not crash!
+                loge("Exception in removeDataActivityTracking " + e);
             }
         }
 
@@ -8771,6 +8869,53 @@
                 removeDataActivityTracking(oldNetwork);
             }
         }
+
+        private void updateRadioPowerState(boolean isActive, int transportType) {
+            final BatteryStatsManager bs = mContext.getSystemService(BatteryStatsManager.class);
+            switch (transportType) {
+                case NetworkCapabilities.TRANSPORT_CELLULAR:
+                    bs.reportMobileRadioPowerState(isActive, NO_UID);
+                    break;
+                case NetworkCapabilities.TRANSPORT_WIFI:
+                    bs.reportWifiRadioPowerState(isActive, NO_UID);
+                    break;
+                default:
+                    logw("Untracked transport type:" + transportType);
+            }
+        }
+
+        public boolean isDefaultNetworkActive() {
+            synchronized (mActiveIdleTimers) {
+                // If there are no idle timers, it means that system is not monitoring activity,
+                // so the default network is always considered active.
+                //
+                // TODO : Distinguish between the cases where mActiveIdleTimers is empty because
+                // tracking is disabled (negative idle timer value configured), or no active default
+                // network. In the latter case, this reports active but it should report inactive.
+                return mNetworkActive || mActiveIdleTimers.isEmpty();
+            }
+        }
+
+        public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
+            mNetworkActivityListeners.register(l);
+        }
+
+        public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
+            mNetworkActivityListeners.unregister(l);
+        }
+
+        public void dump(IndentingPrintWriter pw) {
+            synchronized (mActiveIdleTimers) {
+                pw.print("mNetworkActive="); pw.println(mNetworkActive);
+                pw.println("Idle timers:");
+                for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
+                    pw.print("  "); pw.print(ent.getKey()); pw.println(":");
+                    final IdleTimerParams params = ent.getValue();
+                    pw.print("    timeout="); pw.print(params.timeout);
+                    pw.print(" type="); pw.println(params.transportType);
+                }
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d30a640..4405408 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -69,7 +69,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -80,7 +79,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.telephony.DataConnectionRealTimeInfo;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
@@ -229,32 +227,9 @@
     @GuardedBy("mQuotaLock")
     private volatile boolean mDataSaverMode;
 
-    private final Object mIdleTimerLock = new Object();
-    /** Set of interfaces with active idle timers. */
-    private static class IdleTimerParams {
-        public final int timeout;
-        public final int type;
-        public int networkCount;
-
-        IdleTimerParams(int timeout, int type) {
-            this.timeout = timeout;
-            this.type = type;
-            this.networkCount = 1;
-        }
-    }
-    private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
-
     private volatile boolean mFirewallEnabled;
     private volatile boolean mStrictEnabled;
 
-    private boolean mMobileActivityFromRadio = false;
-    private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-    private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-
-    private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
-            new RemoteCallbackList<>();
-    private boolean mNetworkActive;
-
     /**
      * Constructs a new NetworkManagementService instance
      *
@@ -397,55 +372,8 @@
      */
     private void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
             int uid) {
-        final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
-        int powerState = isActive
-                ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
-                : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-        if (isMobile) {
-            if (mLastPowerStateFromRadio != powerState) {
-                mLastPowerStateFromRadio = powerState;
-                try {
-                    // TODO: The interface changes that comes from netd are handled by BSS itself.
-                    // There are still events caused by setting or removing idle timer, so keep
-                    // reporting from here until setting idler timer moved to CS.
-                    getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
-        if (ConnectivityManager.isNetworkTypeWifi(type)) {
-            if (mLastPowerStateFromWifi != powerState) {
-                mLastPowerStateFromWifi = powerState;
-                try {
-                    // TODO: The interface changes that comes from netd are handled by BSS itself.
-                    // There are still events caused by setting or removing idle timer, so keep
-                    // reporting from here until setting idler timer moved to CS.
-                    getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
-        final boolean active = isActive;
         invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
-                type, active, tsNanos, uid));
-
-        boolean report = false;
-        synchronized (mIdleTimerLock) {
-            if (mActiveIdleTimers.isEmpty()) {
-                // If there are no idle timers, we are not monitoring activity, so we
-                // are always considered active.
-                isActive = true;
-            }
-            if (mNetworkActive != isActive) {
-                mNetworkActive = isActive;
-                report = isActive;
-            }
-        }
-        if (report) {
-            reportNetworkActive();
-        }
+                type, isActive, tsNanos, uid));
     }
 
     @Override
@@ -1122,60 +1050,6 @@
     }
 
     @Override
-    public void addIdleTimer(String iface, int timeout, final int type) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        if (DBG) Slog.d(TAG, "Adding idletimer");
-
-        synchronized (mIdleTimerLock) {
-            IdleTimerParams params = mActiveIdleTimers.get(iface);
-            if (params != null) {
-                // the interface already has idletimer, update network count
-                params.networkCount++;
-                return;
-            }
-
-            try {
-                mNetdService.idletimerAddInterface(iface, timeout, Integer.toString(type));
-            } catch (RemoteException | ServiceSpecificException e) {
-                throw new IllegalStateException(e);
-            }
-            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
-
-            // Networks start up.
-            if (ConnectivityManager.isNetworkTypeMobile(type)) {
-                mNetworkActive = false;
-            }
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(type, true,
-                    SystemClock.elapsedRealtimeNanos(), -1));
-        }
-    }
-
-    @Override
-    public void removeIdleTimer(String iface) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        if (DBG) Slog.d(TAG, "Removing idletimer");
-
-        synchronized (mIdleTimerLock) {
-            final IdleTimerParams params = mActiveIdleTimers.get(iface);
-            if (params == null || --(params.networkCount) > 0) {
-                return;
-            }
-
-            try {
-                mNetdService.idletimerRemoveInterface(iface,
-                        params.timeout, Integer.toString(params.type));
-            } catch (RemoteException | ServiceSpecificException e) {
-                throw new IllegalStateException(e);
-            }
-            mActiveIdleTimers.remove(iface);
-            mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type, false,
-                    SystemClock.elapsedRealtimeNanos(), -1));
-        }
-    }
-
-    @Override
     public void setInterfaceQuota(String iface, long quotaBytes) {
         NetworkStack.checkNetworkStackPermission(mContext);
 
@@ -1813,44 +1687,9 @@
     }
 
     @Override
-    public void registerNetworkActivityListener(INetworkActivityListener listener) {
-        mNetworkActivityListeners.register(listener);
-    }
-
-    @Override
-    public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
-        mNetworkActivityListeners.unregister(listener);
-    }
-
-    @Override
-    public boolean isNetworkActive() {
-        synchronized (mNetworkActivityListeners) {
-            return mNetworkActive || mActiveIdleTimers.isEmpty();
-        }
-    }
-
-    private void reportNetworkActive() {
-        final int length = mNetworkActivityListeners.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mNetworkActivityListeners.finishBroadcast();
-        }
-    }
-
-    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
-                pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
-        pw.print("mNetworkActive="); pw.println(mNetworkActive);
-
         synchronized (mQuotaLock) {
             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
@@ -1882,17 +1721,6 @@
                     mUidFirewallRestrictedRules);
         }
 
-        synchronized (mIdleTimerLock) {
-            pw.println("Idle timers:");
-            for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
-                pw.print("  "); pw.print(ent.getKey()); pw.println(":");
-                IdleTimerParams params = ent.getValue();
-                pw.print("    timeout="); pw.print(params.timeout);
-                pw.print(" type="); pw.print(params.type);
-                pw.print(" networkCount="); pw.println(params.networkCount);
-            }
-        }
-
         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
         pw.print("Netd service status: " );
         if (mNetdService == null) {
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index b15a886..e19745e 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -40,6 +40,7 @@
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.face.IFaceService;
@@ -144,13 +145,14 @@
 
     private final class AuthServiceImpl extends IAuthService.Stub {
         @Override
-        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName)
-                throws RemoteException {
+        public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+                @NonNull String opPackageName) throws RemoteException {
             Utils.checkPermission(getContext(), TEST_BIOMETRIC);
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                return mInjector.getBiometricService().createTestSession(sensorId, opPackageName);
+                return mInjector.getBiometricService()
+                        .createTestSession(sensorId, callback, opPackageName);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 614c5f1..00a4e43 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -44,6 +44,7 @@
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.PromptInfo;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.fingerprint.FingerprintManager;
@@ -570,13 +571,13 @@
      */
     private final class BiometricServiceWrapper extends IBiometricService.Stub {
         @Override // Binder call
-        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName)
-                throws RemoteException {
+        public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+                @NonNull String opPackageName) throws RemoteException {
             checkInternalPermission();
 
             for (BiometricSensor sensor : mSensors) {
                 if (sensor.id == sensorId) {
-                    return sensor.impl.createTestSession(opPackageName);
+                    return sensor.impl.createTestSession(callback, opPackageName);
                 }
             }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index 57efd22..8197edc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -37,18 +37,16 @@
 
     private static final String TAG = "Biometrics/RemovalClient";
 
-    protected final int mBiometricId;
     private final BiometricUtils<S> mBiometricUtils;
     private final Map<Integer, Long> mAuthenticatorIds;
 
     public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
-            int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils<S> utils,
-            int sensorId, @NonNull Map<Integer, Long> authenticatorIds, int statsModality) {
+            int userId, @NonNull String owner, @NonNull BiometricUtils<S> utils, int sensorId,
+            @NonNull Map<Integer, Long> authenticatorIds, int statsModality) {
         super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
                 statsModality, BiometricsProtoEnums.ACTION_REMOVE,
                 BiometricsProtoEnums.CLIENT_UNKNOWN);
-        mBiometricId = biometricId;
         mBiometricUtils = utils;
         mAuthenticatorIds = authenticatorIds;
     }
@@ -68,6 +66,7 @@
 
     @Override
     public void onRemoved(@Nullable BiometricAuthenticator.Identifier identifier, int remaining) {
+        Slog.d(TAG, "onRemoved: " + identifier.getBiometricId() + " remaining: " + remaining);
         if (identifier != null) {
             mBiometricUtils.removeBiometricForUser(getContext(), getTargetUserId(),
                     identifier.getBiometricId());
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index f37cf18..06b049b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -21,6 +21,7 @@
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.face.IFaceService;
 import android.os.IBinder;
@@ -41,8 +42,9 @@
     }
 
     @Override
-    public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException {
-        return mFaceService.createTestSession(mSensorId, opPackageName);
+    public ITestSession createTestSession(@NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) throws RemoteException {
+        return mFaceService.createTestSession(mSensorId, callback, opPackageName);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 8253927..6dbd590 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -31,6 +31,7 @@
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.IFace;
 import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.Face;
@@ -133,7 +134,8 @@
      */
     private final class FaceServiceWrapper extends IFaceService.Stub {
         @Override
-        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
+        public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+                @NonNull String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -143,7 +145,7 @@
                 return null;
             }
 
-            return provider.createTestSession(sensorId, opPackageName);
+            return provider.createTestSession(sensorId, callback, opPackageName);
         }
 
         @Override
@@ -386,7 +388,22 @@
                     opPackageName);
         }
 
-        @Override
+        @Override // Binder call
+        public void removeAll(final IBinder token, final int userId,
+                final IFaceServiceReceiver receiver, final String opPackageName) {
+            Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for removeAll");
+                return;
+            }
+
+            provider.second.scheduleRemoveAll(provider.first, token, userId, receiver,
+                    opPackageName);
+        }
+
+        @Override // Binder call
         public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
                 final String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index cc24b89..88edfbf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.face.Face;
 import android.hardware.face.FaceManager;
 import android.hardware.face.FaceSensorPropertiesInternal;
@@ -28,6 +29,7 @@
 import android.os.NativeHandle;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.LockoutTracker;
 
@@ -109,6 +111,9 @@
     void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
             @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName);
 
+    void scheduleRemoveAll(int sensorId, @NonNull IBinder token, int userId,
+            @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName);
+
     void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken);
 
     void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
@@ -120,7 +125,8 @@
 
     void startPreparedClient(int sensorId, int cookie);
 
-    void scheduleInternalCleanup(int sensorId, int userId);
+    void scheduleInternalCleanup(int sensorId, int userId,
+            @Nullable BaseClientMonitor.Callback callback);
 
     void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
             boolean clearSchedulerBuffer);
@@ -130,7 +136,8 @@
     void dumpInternal(int sensorId, @NonNull PrintWriter pw);
 
     @NonNull
-    ITestSession createTestSession(int sensorId, @NonNull String opPackageName);
+    ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName);
 
     void dumpHal(int sensorId, @NonNull FileDescriptor fd, @NonNull String[] args);
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index 897ebd7..a5e6ddb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.AuthenticationFrame;
 import android.hardware.biometrics.face.BaseFrame;
 import android.hardware.face.Face;
@@ -28,10 +29,12 @@
 import android.hardware.face.FaceEnrollFrame;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
+import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.biometrics.HardwareAuthTokenUtils;
 import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.face.FaceUtils;
 
 import java.util.HashSet;
@@ -49,6 +52,7 @@
 
     @NonNull private final Context mContext;
     private final int mSensorId;
+    @NonNull private final ITestSessionCallback mCallback;
     @NonNull private final FaceProvider mProvider;
     @NonNull private final Sensor mSensor;
     @NonNull private final Set<Integer> mEnrollmentIds;
@@ -132,9 +136,11 @@
     };
 
     BiometricTestSessionImpl(@NonNull Context context, int sensorId,
+            @NonNull ITestSessionCallback callback,
             @NonNull FaceProvider provider, @NonNull Sensor sensor) {
         mContext = context;
         mSensorId = sensorId;
+        mCallback = callback;
         mProvider = provider;
         mSensor = sensor;
         mEnrollmentIds = new HashSet<>();
@@ -224,6 +230,25 @@
     public void cleanupInternalState(int userId)  {
         Utils.checkPermission(mContext, TEST_BIOMETRIC);
 
-        mProvider.scheduleInternalCleanup(mSensorId, userId);
+        mProvider.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+            @Override
+            public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+                try {
+                    mCallback.onCleanupStarted(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+
+            @Override
+            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+                    boolean success) {
+                try {
+                    mCallback.onCleanupFinished(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+        });
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
index 9680e4e..c6696aed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
@@ -61,7 +61,7 @@
         // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
         // is all done internally.
         return new FaceRemovalClient(context, lazyDaemon, token,
-                null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
-                sensorId, authenticatorIds);
+                null /* ClientMonitorCallbackConverter */, new int[] {biometricId}, userId, owner,
+                utils, sensorId, authenticatorIds);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 1b6b9d7..1d8f210 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -25,6 +25,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.IFace;
 import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.Face;
@@ -177,7 +178,8 @@
         for (int i = 0; i < mSensors.size(); i++) {
             final int sensorId = mSensors.keyAt(i);
             scheduleLoadAuthenticatorIds(sensorId);
-            scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser());
+            scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
+                    null /* callback */);
         }
 
         return mDaemon;
@@ -468,6 +470,25 @@
     @Override
     public void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
             @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+        scheduleRemoveSpecifiedIds(sensorId, token, new int[] {faceId}, userId, receiver,
+                opPackageName);
+    }
+
+    @Override
+    public void scheduleRemoveAll(int sensorId, @NonNull IBinder token, int userId,
+            @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+        final List<Face> faces = FaceUtils.getInstance(sensorId)
+                .getBiometricsForUser(mContext, userId);
+        final int[] faceIds = new int[faces.size()];
+        for (int i = 0; i < faces.size(); i++) {
+            faceIds[i] = faces.get(i).getBiometricId();
+        }
+
+        scheduleRemoveSpecifiedIds(sensorId, token, faceIds, userId, receiver, opPackageName);
+    }
+
+    private void scheduleRemoveSpecifiedIds(int sensorId, @NonNull IBinder token, int[] faceIds,
+            int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
         mHandler.post(() -> {
             final IFace daemon = getHalInstance();
             if (daemon == null) {
@@ -485,7 +506,7 @@
 
                 final FaceRemovalClient client = new FaceRemovalClient(mContext,
                         mSensors.get(sensorId).getLazySession(), token,
-                        new ClientMonitorCallbackConverter(receiver), faceId, userId,
+                        new ClientMonitorCallbackConverter(receiver), faceIds, userId,
                         opPackageName, FaceUtils.getInstance(sensorId), sensorId,
                         mSensors.get(sensorId).getAuthenticatorIds());
 
@@ -543,7 +564,8 @@
     }
 
     @Override
-    public void scheduleInternalCleanup(int sensorId, int userId) {
+    public void scheduleInternalCleanup(int sensorId, int userId,
+            @Nullable BaseClientMonitor.Callback callback) {
         mHandler.post(() -> {
             final IFace daemon = getHalInstance();
             if (daemon == null) {
@@ -564,7 +586,7 @@
                                 FaceUtils.getInstance(sensorId),
                                 mSensors.get(sensorId).getAuthenticatorIds());
 
-                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
             } catch (RemoteException e) {
                 Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
             }
@@ -627,8 +649,9 @@
 
     @NonNull
     @Override
-    public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
-        return mSensors.get(sensorId).createTestSession();
+    public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) {
+        return mSensors.get(sensorId).createTestSession(callback);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
index 1cb5031..48796c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
@@ -38,19 +38,22 @@
 class FaceRemovalClient extends RemovalClient<Face, ISession> {
     private static final String TAG = "FaceRemovalClient";
 
+    final int[] mBiometricIds;
+
     FaceRemovalClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
-            int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils<Face> utils,
-            int sensorId, @NonNull Map<Integer, Long> authenticatorIds) {
-        super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+            int[] biometricIds, int userId, @NonNull String owner,
+            @NonNull BiometricUtils<Face> utils, int sensorId,
+            @NonNull Map<Integer, Long> authenticatorIds) {
+        super(context, lazyDaemon, token, listener, userId, owner, utils, sensorId,
                 authenticatorIds, BiometricsProtoEnums.MODALITY_FACE);
+        mBiometricIds = biometricIds;
     }
 
     @Override
     protected void startHalOperation() {
         try {
-            final int[] ids = new int[]{mBiometricId};
-            getFreshDaemon().removeEnrollments(mSequentialId, ids);
+            getFreshDaemon().removeEnrollments(mSequentialId, mBiometricIds);
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception when requesting remove", e);
             mCallback.onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 4925ce0..3434acb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -22,6 +22,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.AuthenticationFrame;
 import android.hardware.biometrics.face.EnrollmentFrame;
 import android.hardware.biometrics.face.Error;
@@ -459,8 +460,9 @@
         }
     }
 
-    @NonNull ITestSession createTestSession() {
-        return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, mProvider, this);
+    @NonNull ITestSession createTestSession(@NonNull ITestSessionCallback callback) {
+        return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
+                mProvider, this);
     }
 
     void createNewSession(@NonNull IFace daemon, int sensorId, int userId)
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index d519d60..e8668ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -21,14 +21,17 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.face.Face;
 import android.hardware.face.FaceAuthenticationFrame;
 import android.hardware.face.FaceEnrollFrame;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
+import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.face.FaceUtils;
 
 import java.util.ArrayList;
@@ -43,6 +46,7 @@
 
     @NonNull private final Context mContext;
     private final int mSensorId;
+    @NonNull private final ITestSessionCallback mCallback;
     @NonNull private final Face10 mFace10;
     @NonNull private final Face10.HalResultController mHalResultController;
     @NonNull private final Set<Integer> mEnrollmentIds;
@@ -120,10 +124,12 @@
         }
     };
 
-    BiometricTestSessionImpl(@NonNull Context context, int sensorId, @NonNull Face10 face10,
+    BiometricTestSessionImpl(@NonNull Context context, int sensorId,
+            @NonNull ITestSessionCallback callback, @NonNull Face10 face10,
             @NonNull Face10.HalResultController halResultController) {
         mContext = context;
         mSensorId = sensorId;
+        mCallback = callback;
         mFace10 = face10;
         mHalResultController = halResultController;
         mEnrollmentIds = new HashSet<>();
@@ -201,6 +207,25 @@
     public void cleanupInternalState(int userId) {
         Utils.checkPermission(mContext, TEST_BIOMETRIC);
 
-        mFace10.scheduleInternalCleanup(mSensorId, userId);
+        mFace10.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+            @Override
+            public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+                try {
+                    mCallback.onCleanupStarted(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+
+            @Override
+            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+                    boolean success) {
+                try {
+                    mCallback.onCleanupFinished(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+        });
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index e46661a..ee8823e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -29,6 +29,7 @@
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
 import android.hardware.face.Face;
@@ -123,7 +124,7 @@
     private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
         @Override
         public void onUserSwitching(int newUserId) {
-            scheduleInternalCleanup(newUserId);
+            scheduleInternalCleanup(newUserId, null /* callback */);
             scheduleGetFeature(mSensorId, new Binder(), newUserId,
                     BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION,
                     null, mContext.getOpPackageName());
@@ -437,7 +438,7 @@
         Slog.d(TAG, "Face HAL ready, HAL ID: " + halId);
         if (halId != 0) {
             scheduleLoadAuthenticatorIds();
-            scheduleInternalCleanup(ActivityManager.getCurrentUser());
+            scheduleInternalCleanup(ActivityManager.getCurrentUser(), null /* callback */);
             scheduleGetFeature(mSensorId, new Binder(),
                     ActivityManager.getCurrentUser(),
                     BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, null,
@@ -671,6 +672,20 @@
         });
     }
 
+    @Override
+    public void scheduleRemoveAll(int sensorId, @NonNull IBinder token, int userId,
+            @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+        mHandler.post(() -> {
+            scheduleUpdateActiveUserWithoutHandler(userId);
+
+            // For IBiometricsFace@1.0, remove(0) means remove all enrollments
+            final FaceRemovalClient client = new FaceRemovalClient(mContext, mLazyDaemon, token,
+                    new ClientMonitorCallbackConverter(receiver), 0 /* faceId */, userId,
+                    opPackageName,
+                    FaceUtils.getLegacyInstance(mSensorId), mSensorId, mAuthenticatorIds);
+            mScheduler.scheduleClientMonitor(client);
+        });
+    }
 
     @Override
     public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) {
@@ -742,7 +757,8 @@
         });
     }
 
-    private void scheduleInternalCleanup(int userId) {
+    private void scheduleInternalCleanup(int userId,
+            @Nullable BaseClientMonitor.Callback callback) {
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
@@ -750,13 +766,14 @@
             final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext,
                     mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, enrolledList,
                     FaceUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
-            mScheduler.scheduleClientMonitor(client);
+            mScheduler.scheduleClientMonitor(client, callback);
         });
     }
 
     @Override
-    public void scheduleInternalCleanup(int sensorId, int userId) {
-        scheduleInternalCleanup(userId);
+    public void scheduleInternalCleanup(int sensorId, int userId,
+            @Nullable BaseClientMonitor.Callback callback) {
+        scheduleInternalCleanup(userId, callback);
     }
 
     @Override
@@ -930,7 +947,9 @@
 
     @NonNull
     @Override
-    public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
-        return new BiometricTestSessionImpl(mContext, mSensorId, this, mHalResultController);
+    public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) {
+        return new BiometricTestSessionImpl(mContext, mSensorId, callback, this,
+                mHalResultController);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java
index d63791c..3ae2011 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java
@@ -38,12 +38,15 @@
 class FaceRemovalClient extends RemovalClient<Face, IBiometricsFace> {
     private static final String TAG = "FaceRemovalClient";
 
+    private final int mBiometricId;
+
     FaceRemovalClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
             int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils<Face> utils,
             int sensorId, @NonNull Map<Integer, Long> authenticatorIds) {
-        super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+        super(context, lazyDaemon, token, listener, userId, owner, utils, sensorId,
                 authenticatorIds, BiometricsProtoEnums.MODALITY_FACE);
+        mBiometricId = biometricId;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 34a9099..32e9409 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -21,6 +21,7 @@
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.fingerprint.IFingerprintService;
 import android.os.IBinder;
@@ -42,8 +43,9 @@
     }
 
     @Override
-    public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException {
-        return mFingerprintService.createTestSession(mSensorId, opPackageName);
+    public ITestSession createTestSession(@NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) throws RemoteException {
+        return mFingerprintService.createTestSession(mSensorId, callback, opPackageName);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index b0e42cd..396dd5f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -43,6 +43,7 @@
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.SensorProps;
 import android.hardware.fingerprint.Fingerprint;
@@ -109,7 +110,8 @@
      */
     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
         @Override
-        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
+        public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+                @NonNull String opPackageName) {
             Utils.checkPermission(getContext(), TEST_BIOMETRIC);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -119,7 +121,7 @@
                 return null;
             }
 
-            return provider.createTestSession(sensorId, opPackageName);
+            return provider.createTestSession(sensorId, callback, opPackageName);
         }
 
         @Override
@@ -499,7 +501,21 @@
                     opPackageName);
         }
 
-        @Override
+        @Override // Binder call
+        public void removeAll(final IBinder token, final int userId,
+                final IFingerprintServiceReceiver receiver, final String opPackageName) {
+            Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
+
+            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for removeAll");
+                return;
+            }
+            provider.second.scheduleRemoveAll(provider.first, token, receiver, userId,
+                    opPackageName);
+        }
+
+        @Override // Binder call
         public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
                 final String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index f672ae5..dfec2e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -28,6 +29,7 @@
 import android.os.IBinder;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.LockoutTracker;
 
@@ -98,7 +100,12 @@
             @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
             @NonNull String opPackageName);
 
-    void scheduleInternalCleanup(int sensorId, int userId);
+    void scheduleRemoveAll(int sensorId, @NonNull IBinder token,
+            @NonNull IFingerprintServiceReceiver receiver, int userId,
+            @NonNull String opPackageName);
+
+    void scheduleInternalCleanup(int sensorId, int userId,
+            @Nullable BaseClientMonitor.Callback callback);
 
     boolean isHardwareDetected(int sensorId);
 
@@ -133,5 +140,6 @@
     void dumpInternal(int sensorId, @NonNull PrintWriter pw);
 
     @NonNull
-    ITestSession createTestSession(int sensorId, @NonNull String opPackageName);
+    ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName);
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index ea9c709..20b3254 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -21,14 +21,17 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.Binder;
+import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.biometrics.HardwareAuthTokenUtils;
 import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
 
 import java.util.HashSet;
@@ -46,6 +49,7 @@
 
     @NonNull private final Context mContext;
     private final int mSensorId;
+    @NonNull private final ITestSessionCallback mCallback;
     @NonNull private final FingerprintProvider mProvider;
     @NonNull private final Sensor mSensor;
     @NonNull private final Set<Integer> mEnrollmentIds;
@@ -110,9 +114,11 @@
     };
 
     BiometricTestSessionImpl(@NonNull Context context, int sensorId,
-            @NonNull FingerprintProvider provider, @NonNull Sensor sensor) {
+            @NonNull ITestSessionCallback callback, @NonNull FingerprintProvider provider,
+            @NonNull Sensor sensor) {
         mContext = context;
         mSensorId = sensorId;
+        mCallback = callback;
         mProvider = provider;
         mSensor = sensor;
         mEnrollmentIds = new HashSet<>();
@@ -192,6 +198,25 @@
     public void cleanupInternalState(int userId)  {
         Utils.checkPermission(mContext, TEST_BIOMETRIC);
 
-        mProvider.scheduleInternalCleanup(mSensorId, userId);
+        mProvider.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+            @Override
+            public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+                try {
+                    mCallback.onCleanupStarted(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+
+            @Override
+            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+                    boolean success) {
+                try {
+                    mCallback.onCleanupFinished(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+        });
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java
index 2a0e984..0de3f4f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintInternalCleanupClient.java
@@ -60,7 +60,7 @@
             String owner, BiometricUtils<Fingerprint> utils, int sensorId,
             Map<Integer, Long> authenticatorIds) {
         return new FingerprintRemovalClient(context, lazyDaemon, token,
-                null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
-                sensorId, authenticatorIds);
+                null /* ClientMonitorCallbackConverter */, new int[] {biometricId}, userId, owner,
+                utils, sensorId, authenticatorIds);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 0bd2f24..598cc89 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -25,6 +25,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.SensorProps;
 import android.hardware.fingerprint.Fingerprint;
@@ -185,7 +186,8 @@
         for (int i = 0; i < mSensors.size(); i++) {
             final int sensorId = mSensors.keyAt(i);
             scheduleLoadAuthenticatorIds(sensorId);
-            scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser());
+            scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
+                    null /* callback */);
         }
 
         return mDaemon;
@@ -490,6 +492,27 @@
     public void scheduleRemove(int sensorId, @NonNull IBinder token,
             @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
             @NonNull String opPackageName) {
+        scheduleRemoveSpecifiedIds(sensorId, token, new int[] {fingerId}, userId, receiver,
+                opPackageName);
+    }
+
+    @Override
+    public void scheduleRemoveAll(int sensorId, @NonNull IBinder token,
+            @NonNull IFingerprintServiceReceiver receiver, int userId,
+            @NonNull String opPackageName) {
+        final List<Fingerprint> fingers = FingerprintUtils.getInstance(sensorId)
+                .getBiometricsForUser(mContext, userId);
+        final int[] fingerIds = new int[fingers.size()];
+        for (int i = 0; i < fingers.size(); i++) {
+            fingerIds[i] = fingers.get(i).getBiometricId();
+        }
+
+        scheduleRemoveSpecifiedIds(sensorId, token, fingerIds, userId, receiver, opPackageName);
+    }
+
+    private void scheduleRemoveSpecifiedIds(int sensorId, @NonNull IBinder token,
+            int[] fingerprintIds, int userId, @NonNull IFingerprintServiceReceiver receiver,
+            @NonNull String opPackageName) {
         mHandler.post(() -> {
             final IFingerprint daemon = getHalInstance();
             if (daemon == null) {
@@ -507,7 +530,7 @@
 
                 final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
                         mSensors.get(sensorId).getLazySession(), token,
-                        new ClientMonitorCallbackConverter(receiver), fingerId, userId,
+                        new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId,
                         opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
                         mSensors.get(sensorId).getAuthenticatorIds());
                 mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
@@ -518,7 +541,8 @@
     }
 
     @Override
-    public void scheduleInternalCleanup(int sensorId, int userId) {
+    public void scheduleInternalCleanup(int sensorId, int userId,
+            @Nullable BaseClientMonitor.Callback callback) {
         mHandler.post(() -> {
             final IFingerprint daemon = getHalInstance();
             if (daemon == null) {
@@ -538,7 +562,7 @@
                                 mContext.getOpPackageName(), sensorId, enrolledList,
                                 FingerprintUtils.getInstance(sensorId),
                                 mSensors.get(sensorId).getAuthenticatorIds());
-                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
             } catch (RemoteException e) {
                 Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
             }
@@ -683,8 +707,9 @@
 
     @NonNull
     @Override
-    public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
-        return mSensors.get(sensorId).createTestSession();
+    public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) {
+        return mSensors.get(sensorId).createTestSession(callback);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
index 4a99a7b..c622208 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
@@ -39,20 +39,22 @@
 class FingerprintRemovalClient extends RemovalClient<Fingerprint, ISession> {
     private static final String TAG = "FingerprintRemovalClient";
 
+    private final int[] mBiometricIds;
+
     FingerprintRemovalClient(@NonNull Context context,
             @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
-            @Nullable ClientMonitorCallbackConverter listener, int biometricId, int userId,
+            @Nullable ClientMonitorCallbackConverter listener, int[] biometricIds, int userId,
             @NonNull String owner, @NonNull BiometricUtils<Fingerprint> utils, int sensorId,
             @NonNull Map<Integer, Long> authenticatorIds) {
-        super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+        super(context, lazyDaemon, token, listener, userId, owner, utils, sensorId,
                 authenticatorIds, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+        mBiometricIds = biometricIds;
     }
 
     @Override
     protected void startHalOperation() {
         try {
-            final int[] ids = new int[] {mBiometricId};
-            getFreshDaemon().removeEnrollments(mSequentialId, ids);
+            getFreshDaemon().removeEnrollments(mSequentialId, mBiometricIds);
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception when requesting remove", e);
             mCallback.onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index c83c0fb..a98e7db 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -22,6 +22,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.fingerprint.Error;
 import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.ISession;
@@ -439,8 +440,9 @@
         }
     }
 
-    @NonNull ITestSession createTestSession() {
-        return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, mProvider, this);
+    @NonNull ITestSession createTestSession(@NonNull ITestSessionCallback callback) {
+        return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
+                mProvider, this);
     }
 
     void createNewSession(@NonNull IFingerprint daemon, int sensorId, int userId)
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 312ee0a..766a882 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -21,13 +21,16 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.Binder;
+import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
 
 import java.util.ArrayList;
@@ -47,6 +50,7 @@
 
     @NonNull private final Context mContext;
     private final int mSensorId;
+    @NonNull private final ITestSessionCallback mCallback;
     @NonNull private final Fingerprint21 mFingerprint21;
     @NonNull private final Fingerprint21.HalResultController mHalResultController;
     @NonNull private final Set<Integer> mEnrollmentIds;
@@ -111,10 +115,12 @@
     };
 
     BiometricTestSessionImpl(@NonNull Context context, int sensorId,
+            @NonNull ITestSessionCallback callback,
             @NonNull Fingerprint21 fingerprint21,
             @NonNull Fingerprint21.HalResultController halResultController) {
         mContext = context;
         mSensorId = sensorId;
+        mCallback = callback;
         mFingerprint21 = fingerprint21;
         mHalResultController = halResultController;
         mEnrollmentIds = new HashSet<>();
@@ -191,6 +197,25 @@
     public void cleanupInternalState(int userId)  {
         Utils.checkPermission(mContext, TEST_BIOMETRIC);
 
-        mFingerprint21.scheduleInternalCleanup(mSensorId, userId);
+        mFingerprint21.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
+            @Override
+            public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+                try {
+                    mCallback.onCleanupStarted(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+
+            @Override
+            public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+                    boolean success) {
+                try {
+                    mCallback.onCleanupFinished(clientMonitor.getTargetUserId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception", e);
+                }
+            }
+        });
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 554e3d4..6e22a79 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -30,6 +30,7 @@
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback;
 import android.hardware.fingerprint.Fingerprint;
@@ -158,7 +159,7 @@
     private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
         @Override
         public void onUserSwitching(int newUserId) {
-            scheduleInternalCleanup(newUserId);
+            scheduleInternalCleanup(newUserId, null /* callback */);
         }
     };
 
@@ -437,7 +438,7 @@
         Slog.d(TAG, "Fingerprint HAL ready, HAL ID: " + halId);
         if (halId != 0) {
             scheduleLoadAuthenticatorIds();
-            scheduleInternalCleanup(ActivityManager.getCurrentUser());
+            scheduleInternalCleanup(ActivityManager.getCurrentUser(), null /* callback */);
         } else {
             Slog.e(TAG, "Unable to set callback");
             mDaemon = null;
@@ -644,7 +645,25 @@
         });
     }
 
-    private void scheduleInternalCleanup(int userId) {
+    @Override
+    public void scheduleRemoveAll(int sensorId, @NonNull IBinder token,
+            @NonNull IFingerprintServiceReceiver receiver, int userId,
+            @NonNull String opPackageName) {
+        mHandler.post(() -> {
+            scheduleUpdateActiveUserWithoutHandler(userId);
+
+            // For IBiometricsFingerprint@2.1, remove(0) means remove all enrollments
+            final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
+                    mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver),
+                    0 /* fingerprintId */, userId, opPackageName,
+                    FingerprintUtils.getLegacyInstance(mSensorId),
+                    mSensorProperties.sensorId, mAuthenticatorIds);
+            mScheduler.scheduleClientMonitor(client);
+        });
+    }
+
+    private void scheduleInternalCleanup(int userId,
+            @Nullable BaseClientMonitor.Callback callback) {
         mHandler.post(() -> {
             scheduleUpdateActiveUserWithoutHandler(userId);
 
@@ -654,13 +673,14 @@
                     mContext, mLazyDaemon, userId, mContext.getOpPackageName(),
                     mSensorProperties.sensorId, enrolledList,
                     FingerprintUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
-            mScheduler.scheduleClientMonitor(client);
+            mScheduler.scheduleClientMonitor(client, callback);
         });
     }
 
     @Override
-    public void scheduleInternalCleanup(int sensorId, int userId) {
-        scheduleInternalCleanup(userId);
+    public void scheduleInternalCleanup(int sensorId, int userId,
+            @Nullable BaseClientMonitor.Callback callback) {
+        scheduleInternalCleanup(userId, callback);
     }
 
     @Override
@@ -840,8 +860,9 @@
 
     @NonNull
     @Override
-    public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
-        return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, this,
+    public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) {
+        return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback, this,
                 mHalResultController);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRemovalClient.java
index f6a22f5..2f360f3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRemovalClient.java
@@ -39,13 +39,16 @@
 class FingerprintRemovalClient extends RemovalClient<Fingerprint, IBiometricsFingerprint> {
     private static final String TAG = "FingerprintRemovalClient";
 
+    private final int mBiometricId;
+
     FingerprintRemovalClient(@NonNull Context context,
             @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
             @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
             @NonNull String owner, @NonNull BiometricUtils<Fingerprint> utils, int sensorId,
             @NonNull Map<Integer, Long> authenticatorIds) {
-        super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+        super(context, lazyDaemon, token, listener, userId, owner, utils, sensorId,
                 authenticatorIds, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+        mBiometricId = biometricId;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 8e84613..f44e069 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -21,6 +21,7 @@
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IInvalidationCallback;
 import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.ITestSessionCallback;
 import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.iris.IIrisService;
 import android.os.IBinder;
@@ -39,7 +40,8 @@
     }
 
     @Override
-    public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException {
+    public ITestSession createTestSession(@NonNull ITestSessionCallback callback,
+            @NonNull String opPackageName) throws RemoteException {
         return null;
     }
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 685e9e6..8da2d67 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2902,11 +2902,8 @@
         FingerprintManager mFingerprintManager = mInjector.getFingerprintManager();
         if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
             if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
-                CountDownLatch latch = new CountDownLatch(1);
-                // For the purposes of M and N, groupId is the same as userId.
-                Fingerprint finger = new Fingerprint(null, userId, 0, 0);
-                mFingerprintManager.remove(finger, userId,
-                        fingerprintManagerRemovalCallback(latch));
+                final CountDownLatch latch = new CountDownLatch(1);
+                mFingerprintManager.removeAll(userId, fingerprintManagerRemovalCallback(latch));
                 try {
                     latch.await(10000, TimeUnit.MILLISECONDS);
                 } catch (InterruptedException e) {
@@ -2920,9 +2917,8 @@
         FaceManager mFaceManager = mInjector.getFaceManager();
         if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
             if (mFaceManager.hasEnrolledTemplates(userId)) {
-                CountDownLatch latch = new CountDownLatch(1);
-                Face face = new Face(null, 0, 0);
-                mFaceManager.remove(face, userId, faceManagerRemovalCallback(latch));
+                final CountDownLatch latch = new CountDownLatch(1);
+                mFaceManager.removeAll(userId, faceManagerRemovalCallback(latch));
                 try {
                     latch.await(10000, TimeUnit.MILLISECONDS);
                 } catch (InterruptedException e) {
@@ -2936,10 +2932,8 @@
             CountDownLatch latch) {
         return new FingerprintManager.RemovalCallback() {
             @Override
-            public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence err) {
-                Slog.e(TAG, String.format(
-                        "Can't remove fingerprint %d in group %d. Reason: %s",
-                        fp.getBiometricId(), fp.getGroupId(), err));
+            public void onRemovalError(@Nullable Fingerprint fp, int errMsgId, CharSequence err) {
+                Slog.e(TAG, "Unable to remove fingerprint, error: " + err);
                 latch.countDown();
             }
 
@@ -2955,9 +2949,8 @@
     private FaceManager.RemovalCallback faceManagerRemovalCallback(CountDownLatch latch) {
         return new FaceManager.RemovalCallback() {
             @Override
-            public void onRemovalError(Face face, int errMsgId, CharSequence err) {
-                Slog.e(TAG, String.format("Can't remove face %d. Reason: %s",
-                        face.getBiometricId(), err));
+            public void onRemovalError(@Nullable Face face, int errMsgId, CharSequence err) {
+                Slog.e(TAG, "Unable to remove face, error: " + err);
                 latch.countDown();
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 1f66c7c..67d6929 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -339,11 +339,11 @@
         mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID);
 
         // Verify fingerprint is removed
-        verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any());
-        verify(mFaceManager).remove(any(), eq(PRIMARY_USER_ID), any());
+        verify(mFingerprintManager).removeAll(eq(PRIMARY_USER_ID), any());
+        verify(mFaceManager).removeAll(eq(PRIMARY_USER_ID), any());
 
-        verify(mFingerprintManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any());
-        verify(mFaceManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any());
+        verify(mFingerprintManager).removeAll(eq(MANAGED_PROFILE_USER_ID), any());
+        verify(mFaceManager).removeAll(eq(MANAGED_PROFILE_USER_ID), any());
     }
 
     @Test
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f687e4b..7669883 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -430,25 +430,17 @@
                 // Eventually it will be an error to not specify this.
                 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
                         curInteractorInfo.getServiceInfo().name), userHandle);
-                if (curInteractorInfo.getRecognitionService() != null) {
-                    setCurRecognizer(
-                            new ComponentName(curInteractorInfo.getServiceInfo().packageName,
-                                    curInteractorInfo.getRecognitionService()), userHandle);
-                    return;
-                }
+            } else {
+                // No voice interactor, so clear the setting.
+                setCurInteractor(null, userHandle);
             }
 
-            // No voice interactor, we'll just set up a simple recognizer.
-            initSimpleRecognizer(curInteractorInfo, userHandle);
+            initRecognizer(userHandle);
         }
 
-        public void initSimpleRecognizer(VoiceInteractionServiceInfo curInteractorInfo,
-                int userHandle) {
+        public void initRecognizer(int userHandle) {
             ComponentName curRecognizer = findAvailRecognizer(null, userHandle);
             if (curRecognizer != null) {
-                if (curInteractorInfo == null) {
-                    setCurInteractor(null, userHandle);
-                }
                 setCurRecognizer(curRecognizer, userHandle);
             }
         }
@@ -1772,7 +1764,9 @@
                     synchronized (VoiceInteractionManagerServiceStub.this) {
                         Slog.i(TAG, "Force stopping current voice recognizer: "
                                 + getCurRecognizer(userHandle));
-                        initSimpleRecognizer(null, userHandle);
+                        // TODO: Figure out why the interactor was being cleared and document it.
+                        setCurInteractor(null, userHandle);
+                        initRecognizer(userHandle);
                     }
                 }
                 return hitInt || hitRec;
@@ -1793,6 +1787,9 @@
                 if (isPackageAppearing(pkgName) != PACKAGE_UNCHANGED) {
                     return;
                 }
+                if (getCurRecognizer(mCurUser) == null) {
+                    initRecognizer(mCurUser);
+                }
                 final String curInteractorStr = Settings.Secure.getStringForUser(
                         mContext.getContentResolver(),
                         Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
@@ -1807,12 +1804,6 @@
                                 availInteractorInfo.getServiceInfo().packageName,
                                 availInteractorInfo.getServiceInfo().name);
                         setCurInteractor(availInteractor, mCurUser);
-                        if (getCurRecognizer(mCurUser) == null &&
-                                availInteractorInfo.getRecognitionService() != null) {
-                            setCurRecognizer(new ComponentName(
-                                    availInteractorInfo.getServiceInfo().packageName,
-                                    availInteractorInfo.getRecognitionService()), mCurUser);
-                        }
                     }
                 } else {
                     if (didSomePackagesChange()) {
@@ -1843,10 +1834,7 @@
                     if (curRecognizer == null) {
                         // Could a new recognizer appear when we don't have one pre-installed?
                         if (anyPackagesAppearing()) {
-                            curRecognizer = findAvailRecognizer(null, userHandle);
-                            if (curRecognizer != null) {
-                                setCurRecognizer(curRecognizer, userHandle);
-                            }
+                            initRecognizer(userHandle);
                         }
                         return;
                     }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 495311c..ad2b3a1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -8222,8 +8222,8 @@
         reset(mNetworkManagementService);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
-                eq(NetworkCapabilities.TRANSPORT_CELLULAR));
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         final LinkProperties wifiLp = new LinkProperties();
@@ -8231,25 +8231,27 @@
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
 
         // Network switch
-        reset(mNetworkManagementService);
         mWiFiNetworkAgent.connect(true);
         networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
         networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
-                eq(NetworkCapabilities.TRANSPORT_WIFI));
-        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(MOBILE_IFNAME));
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         // Disconnect wifi and switch back to cell
-        reset(mNetworkManagementService);
+        reset(mMockNetd);
         mWiFiNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         assertNoCallbacks(networkCallback);
-        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
-        verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
-                eq(NetworkCapabilities.TRANSPORT_CELLULAR));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         // reconnect wifi
+        reset(mMockNetd);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         wifiLp.setInterfaceName(WIFI_IFNAME);
         mWiFiNetworkAgent.sendLinkProperties(wifiLp);
@@ -8257,9 +8259,12 @@
         networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
         networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
 
         // Disconnect cell
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         mCellNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -8267,17 +8272,18 @@
         // sent as network being switched. Ensure rule removal for cell will not be triggered
         // unexpectedly before network being removed.
         waitForIdle();
-        verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
+        verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_CELLULAR)));
         verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
         verify(mMockDnsResolver, times(1))
                 .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
         ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
-        reset(mNetworkManagementService);
         mWiFiNetworkAgent.disconnect();
         b.expectBroadcast();
-        verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
+        verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
+                eq(Integer.toString(TRANSPORT_WIFI)));
 
         // Clean up
         mCm.unregisterNetworkCallback(networkCallback);