Merge "Remove current.txt files"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f7bbcbb..dbb3ecd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -10581,6 +10581,32 @@
 
     // A random number used as the dimension field to pull multiple atoms.
     optional int32 dimension = 25;
+
+    // Signal strength at the end of the call. This value is applicable to both cellular and WiFi.
+    optional android.telephony.SignalStrengthEnum signal_strength_at_end = 26;
+
+    // Band at the end of the call. Value 0 is used if the band is unknown.
+    // See GeranBands, UtranBands and EutranBands in IRadio interface, depending on the RAT at
+    // the end of the call.
+    optional int32 band_at_end = 27;
+
+    // Time spent setting up the call in milliseconds.
+    // The time is measured from dial to ringing for outgoing calls, and from answer to connected
+    // for incoming calls.
+    optional int32 setup_duration_millis = 28;
+
+    // Main codec quality. The codec quality was equal to or greater than this value for at least
+    // 70% of the call.
+    optional android.telephony.CodecQuality main_codec_quality = 29;
+
+    // Whether video was enabled at any point during the call.
+    optional bool video_enabled = 30;
+
+    // Radio access technology (RAT) used when call is connected.
+    optional android.telephony.NetworkTypeEnum rat_at_connected = 31;
+
+    // Whether the call was a conference call (applicable only for calls over IMS).
+    optional bool is_multiparty = 32;
 }
 
 /**
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1c72d02..f19b704 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -698,6 +698,7 @@
   public class BiometricManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
+    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public String getUiPackage();
   }
 
   public class BiometricTestSession implements java.lang.AutoCloseable {
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 25c749b..987d790 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -208,7 +208,17 @@
     @NonNull
     @RequiresPermission(TEST_BIOMETRIC)
     public List<SensorProperties> getSensorProperties() {
-        return new ArrayList<>(); // TODO(169459906)
+        try {
+            final List<SensorPropertiesInternal> internalProperties =
+                    mService.getSensorProperties(mContext.getOpPackageName());
+            final List<SensorProperties> properties = new ArrayList<>();
+            for (SensorPropertiesInternal internalProp : internalProperties) {
+                properties.add(SensorProperties.from(internalProp));
+            }
+            return properties;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -219,7 +229,27 @@
     @NonNull
     @RequiresPermission(TEST_BIOMETRIC)
     public BiometricTestSession createTestSession(int sensorId) {
-        return null; // TODO(169459906)
+        try {
+            return new BiometricTestSession(mContext,
+                    mService.createTestSession(sensorId, mContext.getOpPackageName()));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieves the package where BiometricPrompt's UI is implemented.
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    @RequiresPermission(TEST_BIOMETRIC)
+    public String getUiPackage() {
+        try {
+            return mService.getUiPackage();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index dd6aa73..8e7f5ce 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -18,7 +18,9 @@
 
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorPropertiesInternal;
 
 /**
  * Communication channel from BiometricPrompt and BiometricManager to AuthService. The
@@ -28,6 +30,15 @@
  * @hide
  */
 interface IAuthService {
+    // Creates a test session with the specified sensorId
+    ITestSession createTestSession(int sensorId, String opPackageName);
+
+    // Retrieve static sensor properties for all biometric sensors
+    List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
+
+    // Retrieve the package where BIometricOrompt's UI is implemented
+    String getUiPackage();
+
     // Requests authentication. The service choose the appropriate biometric to use, and show
     // the corresponding BiometricDialog.
     void authenticate(IBinder token, long sessionId, int userId,
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index 5e6fe68..cb43943 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -18,6 +18,8 @@
 
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
 
@@ -28,6 +30,15 @@
  */
 interface IBiometricAuthenticator {
 
+    // Creates a test session
+    ITestSession createTestSession(String opPackageName);
+
+    // Retrieve static sensor properties
+    SensorPropertiesInternal getSensorProperties(String opPackageName);
+
+    // Requests a proto dump of the service. See biometrics.proto
+    byte[] dumpSensorServiceStateProto();
+
     // This method prepares the service to start authenticating, but doesn't start authentication.
     // This is protected by the MANAGE_BIOMETRIC signature permission. This method should only be
     // called from BiometricService. The additional uid, pid, userId arguments should be determined
@@ -35,14 +46,13 @@
     // startPreparedClient().
     void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie, int callingUid, int callingPid, int callingUserId);
+            int cookie);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int cookie);
 
     // Cancels authentication.
-    void cancelAuthenticationFromService(IBinder token, String opPackageName,
-            int callingUid, int callingPid, int callingUserId);
+    void cancelAuthenticationFromService(IBinder token, String opPackageName);
 
     // Determine if HAL is loaded and ready
     boolean isHardwareDetected(String opPackageName);
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 005ed32..6f7bcb6 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -19,22 +19,28 @@
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorPropertiesInternal;
 
 /**
  * Communication channel from AuthService to BiometricService.
  * @hide
  */
 interface IBiometricService {
+    // Creates a test session with the specified sensorId
+    ITestSession createTestSession(int sensorId, String opPackageName);
+
+    // Retrieve static sensor properties for all biometric sensors
+    List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
+
     // Requests authentication. The service choose the appropriate biometric to use, and show
     // the corresponding BiometricDialog.
     void authenticate(IBinder token, long operationId, int userId,
-            IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo,
-            int callingUid, int callingPid, int callingUserId);
+            IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
 
     // Cancel authentication for the given session.
-    void cancelAuthentication(IBinder token, String opPackageName, int callingUid, int callingPid,
-            int callingUserId);
+    void cancelAuthentication(IBinder token, String opPackageName);
 
     // Checks if biometrics can be used.
     int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);
diff --git a/core/java/android/hardware/biometrics/SensorProperties.java b/core/java/android/hardware/biometrics/SensorProperties.java
index 5b1b5e6..360f138 100644
--- a/core/java/android/hardware/biometrics/SensorProperties.java
+++ b/core/java/android/hardware/biometrics/SensorProperties.java
@@ -81,4 +81,12 @@
     public int getSensorStrength() {
         return mSensorStrength;
     }
+
+    /**
+     * Constructs a {@link SensorProperties} from the internal parcelable representation.
+     * @hide
+     */
+    public static SensorProperties from(SensorPropertiesInternal internalProp) {
+        return new SensorProperties(internalProp.sensorId, internalProp.sensorStrength);
+    }
 }
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 27cdda7..c5c51e4 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -17,6 +17,7 @@
 
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.face.IFaceServiceReceiver;
 import android.hardware.face.Face;
 import android.hardware.face.FaceSensorPropertiesInternal;
@@ -28,9 +29,19 @@
  * @hide
  */
 interface IFaceService {
+
+    // Creates a test session with the specified sensorId
+    ITestSession createTestSession(int sensorId, String opPackageName);
+
+    // Requests a proto dump of the service to the specified fd
+    byte[] dumpSensorServiceStateProto();
+
     // Retrieve static sensor properties for all face sensors
     List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
 
+    // Retrieve static sensor properties for the specified sensor
+    FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
+
     // Authenticate the given sessionId with a face
     void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
             String opPackageName);
@@ -46,7 +57,7 @@
     // startPreparedClient().
     void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie, int callingUid, int callingPid, int callingUserId);
+            int cookie);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int sensorId, int cookie);
@@ -58,8 +69,7 @@
     void cancelFaceDetect(IBinder token, String opPackageName);
 
     // Same as above, with extra arguments.
-    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName,
-            int callingUid, int callingPid, int callingUserId);
+    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
 
     // Start face enrollment
     void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 2128d67..9248b08 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -34,9 +34,15 @@
     // Creates a test session with the specified sensorId
     ITestSession createTestSession(int sensorId, String opPackageName);
 
+    // Requests a proto dump of the service to the specified fd
+    byte[] dumpSensorServiceStateProto();
+
     // Retrieve static sensor properties for all fingerprint sensors
     List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
 
+    // Retrieve static sensor properties for the specified sensor
+    FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
+
     // Authenticate the given sessionId with a fingerprint. This is protected by
     // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
     // through FingerprintManager now.
@@ -54,8 +60,7 @@
     // by BiometricService. To start authentication after the clients are ready, use
     // startPreparedClient().
     void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
-            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
-            int callingUid, int callingPid, int callingUserId);
+            IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie);
 
     // Starts authentication with the previously prepared client.
     void startPreparedClient(int sensorId, int cookie);
@@ -68,8 +73,7 @@
 
     // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
     // an additional uid, pid, userid.
-    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName,
-            int callingUid, int callingPid, int callingUserId);
+    void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
 
     // Start fingerprint enrollment
     void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
diff --git a/core/proto/android/server/biometrics.proto b/core/proto/android/server/biometrics.proto
new file mode 100644
index 0000000..632c1e5
--- /dev/null
+++ b/core/proto/android/server/biometrics.proto
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package com.android.server.biometrics;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "BiometricsProto";
+
+// Overall state of BiometricService (and not <Biometric>Service), including any
+// <Biomteric>Service(s), for example FingerprintService or FaceService.
+message BiometricServiceStateProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    enum AuthSessionState {
+        /**
+         * Authentication either just called and we have not transitioned to the CALLED state, or
+         * authentication terminated (success or error).
+         */
+        STATE_AUTH_IDLE = 0;
+
+        /**
+         * Authentication was called and we are waiting for the <Biometric>Services to return their
+         * cookies before starting the hardware and showing the BiometricPrompt.
+         */
+        STATE_AUTH_CALLED = 1;
+
+        /**
+         * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
+         */
+        STATE_AUTH_STARTED = 2;
+
+        /**
+         * Same as {@link #STATE_AUTH_STARTED}, except the BiometricPrompt UI is done animating in.
+         */
+        STATE_AUTH_STARTED_UI_SHOWING = 3;
+
+        /**
+         * Authentication is paused, waiting for the user to press "try again" button. Only
+         * passive modalities such as Face or Iris should have this state. Note that for passive
+         * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
+         * fingerprint.
+         */
+        STATE_AUTH_PAUSED = 4;
+
+        /**
+         * Paused, but "try again" was pressed. Sensors have new cookies and we're now waiting for
+         * all cookies to be returned.
+         */
+        STATE_AUTH_PAUSED_RESUMING = 5;
+
+        /**
+         * Authentication is successful, but we're waiting for the user to press "confirm" button.
+         */
+        STATE_AUTH_PENDING_CONFIRM = 6;
+
+        /**
+         * Biometric authenticated, waiting for SysUI to finish animation
+         */
+        STATE_AUTHENTICATED_PENDING_SYSUI = 7;
+
+        /**
+         * Biometric error, waiting for SysUI to finish animation
+         */
+        STATE_ERROR_PENDING_SYSUI = 8;
+
+        /**
+         * Device credential in AuthController is showing
+         */
+        STATE_SHOWING_DEVICE_CREDENTIAL = 9;
+
+        /**
+         * The client binder died, and sensors were authenticating at the time. Cancel has been
+         * requested and we're waiting for the HAL(s) to send ERROR_CANCELED.
+         */
+        STATE_CLIENT_DIED_CANCELLING = 10;
+    }
+
+    repeated SensorServiceStateProto sensor_service_states = 1;
+
+    optional AuthSessionState auth_session_state = 2;
+}
+
+// Overall state for an instance of a <Biometric>Service, for example FingerprintService or
+// FaceService. Note that a single service may provide multiple sensors.
+message SensorServiceStateProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    repeated SensorStateProto sensor_states = 1;
+}
+
+// State of a single sensor.
+message SensorStateProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Unique sensorId
+    optional int32 sensor_id = 1;
+
+    // State of the sensor's scheduler. True if currently handling an operation, false if idle.
+    optional bool is_busy = 2;
+
+    // User states for this sensor.
+    repeated UserStateProto user_states = 3;
+}
+
+// State of a specific user for a specific sensor.
+message UserStateProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Android user ID
+    optional int32 user_id = 1;
+
+    // Number of fingerprints enrolled
+    optional int32 num_enrolled = 2;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/fingerprint.proto b/core/proto/android/server/fingerprint.proto
index a49a1ad..e6b2df5 100644
--- a/core/proto/android/server/fingerprint.proto
+++ b/core/proto/android/server/fingerprint.proto
@@ -65,37 +65,4 @@
 
     // Total number of permanent lockouts.
     optional int32 permanent_lockout = 5;
-}
-
-// Internal FingerprintService states. The above messages (FingerprintServiceDumpProto, etc)
-// are used for legacy metrics and should not be modified.
-message FingerprintServiceStateProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    repeated SensorStateProto sensor_states = 1;
-}
-
-// State of a single sensor.
-message SensorStateProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Unique sensorId
-    optional int32 sensor_id = 1;
-
-    // State of the sensor's scheduler. True if currently handling an operation, false if idle.
-    optional bool is_busy = 2;
-
-    // User states for this sensor.
-    repeated UserStateProto user_states = 3;
-}
-
-// State of a specific user for a specific sensor.
-message UserStateProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    // Android user ID
-    optional int32 user_id = 1;
-
-    // Number of fingerprints enrolled
-    optional int32 num_enrolled = 2;
 }
\ No newline at end of file
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 2546b51..b435fe7 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -99,7 +99,7 @@
     ROAMING_TYPE_ROAMING_INTERNATIONAL = 3;
 }
 
-// Signal strength levels, primarily used by android/telephony/SignalStrength.java.
+// Signal strength levels, as defined in android/telephony/SignalStrength.java.
 enum SignalStrengthEnum {
     SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
     SIGNAL_STRENGTH_POOR = 1;
@@ -267,4 +267,22 @@
     RECOVERY_ACTION_CLEANUP = 1;
     RECOVERY_ACTION_REREGISTER = 2;
     RECOVERY_ACTION_RADIO_RESTART = 3;
-}
\ No newline at end of file
+}
+
+// Codec quality
+enum CodecQuality {
+    /** Codec quality: unknown */
+    CODEC_QUALITY_UNKNOWN = 0;
+
+    /** Codec quality: narrowband */
+    CODEC_QUALITY_NARROWBAND = 1;
+
+    /** Codec quality: wideband */
+    CODEC_QUALITY_WIDEBAND = 2;
+
+    /** Codec quality: super-wideband */
+    CODEC_QUALITY_SUPER_WIDEBAND = 3;
+
+    /** Codec quality: fullband */
+    CODEC_QUALITY_FULLBAND = 4;
+}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c83594a..eda1c7a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4267,6 +4267,7 @@
     <!-- Which binder services to include in incident reports containing restricted images. -->
     <string-array name="config_restrictedImagesServices" translatable="false"/>
 
+    <string name="config_biometric_prompt_ui_package">com.android.systemui</string>
     <!-- List of biometric sensors on the device, in decreasing strength. Consumed by AuthService
          when registering authenticators with BiometricService. Format must be ID:Modality:Strength,
          where: IDs are unique per device, Modality as defined in BiometricAuthenticator.java,
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index acfafa4..966cb37 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2517,6 +2517,7 @@
   <java-symbol type="string" name="face_authenticated_confirmation_required" />
   <java-symbol type="string" name="face_error_security_update_required" />
 
+  <java-symbol type="string" name="config_biometric_prompt_ui_package" />
   <java-symbol type="array" name="config_biometric_sensors" />
   <java-symbol type="bool" name="allow_test_udfps" />
 
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index eeec1bb..cf8bfbc 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -20,6 +20,7 @@
 // TODO(b/141025588): Create separate internal and external permissions for AuthService.
 // TODO(b/141025588): Get rid of the USE_FINGERPRINT permission.
 
+import static android.Manifest.permission.TEST_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC;
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.Manifest.permission.USE_FINGERPRINT;
@@ -28,6 +29,7 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 
+import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -36,7 +38,9 @@
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.face.IFaceService;
 import android.hardware.fingerprint.IFingerprintService;
 import android.hardware.iris.IIrisService;
@@ -54,6 +58,8 @@
 import com.android.server.biometrics.sensors.fingerprint.FingerprintAuthenticator;
 import com.android.server.biometrics.sensors.iris.IrisAuthenticator;
 
+import java.util.List;
+
 /**
  * System service that provides an interface for authenticating with biometrics and
  * PIN/pattern/password to BiometricPrompt and lock screen.
@@ -137,6 +143,42 @@
 
     private final class AuthServiceImpl extends IAuthService.Stub {
         @Override
+        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName)
+                throws RemoteException {
+            Utils.checkPermission(getContext(), TEST_BIOMETRIC);
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return mInjector.getBiometricService().createTestSession(sensorId, opPackageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<SensorPropertiesInternal> getSensorProperties(String opPackageName)
+                throws RemoteException {
+            Utils.checkPermission(getContext(), TEST_BIOMETRIC);
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                // Get the result from BiometricService, since it is the source of truth for all
+                // biometric sensors.
+                return mInjector.getBiometricService().getSensorProperties(opPackageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public String getUiPackage() {
+            Utils.checkPermission(getContext(), TEST_BIOMETRIC);
+
+            return getContext().getResources()
+                    .getString(R.string.config_biometric_prompt_ui_package);
+        }
+
+        @Override
         public void authenticate(IBinder token, long sessionId, int userId,
                 IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo)
                 throws RemoteException {
@@ -176,8 +218,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 mBiometricService.authenticate(
-                        token, sessionId, userId, receiver, opPackageName, promptInfo, callingUid,
-                        callingPid, callingUserId);
+                        token, sessionId, userId, receiver, opPackageName, promptInfo);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -193,13 +234,9 @@
                 return;
             }
 
-            final int callingUid = Binder.getCallingUid();
-            final int callingPid = Binder.getCallingPid();
-            final int callingUserId = UserHandle.getCallingUserId();
             final long identity = Binder.clearCallingIdentity();
             try {
-                mBiometricService.cancelAuthentication(token, opPackageName, callingUid,
-                        callingPid, callingUserId);
+                mBiometricService.cancelAuthentication(token, opPackageName);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 637a896..efc025d 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -20,6 +20,8 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
 
+import static com.android.server.biometrics.BiometricServiceStateProto.*;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -48,7 +50,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 
@@ -61,60 +62,11 @@
     private static final String TAG = "BiometricService/AuthSession";
     private static final boolean DEBUG = false;
 
-    /**
-     * Authentication either just called and we have not transitioned to the CALLED state, or
-     * authentication terminated (success or error).
-     */
-    static final int STATE_AUTH_IDLE = 0;
-    /**
-     * Authentication was called and we are waiting for the <Biometric>Services to return their
-     * cookies before starting the hardware and showing the BiometricPrompt.
-     */
-    static final int STATE_AUTH_CALLED = 1;
-    /**
-     * Authentication started, BiometricPrompt is showing and the hardware is authenticating. At
-     * this point, the BiometricPrompt UI has been requested, but is not necessarily done animating
-     * in yet.
-     */
-    static final int STATE_AUTH_STARTED = 2;
-    /**
-     * Same as {@link #STATE_AUTH_STARTED}, except the BiometricPrompt UI is done animating in.
-     */
-    static final int STATE_AUTH_STARTED_UI_SHOWING = 3;
-    /**
-     * Authentication is paused, waiting for the user to press "try again" button. Only
-     * passive modalities such as Face or Iris should have this state. Note that for passive
-     * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
-     * fingerprint.
-     */
-    static final int STATE_AUTH_PAUSED = 4;
-    /**
-     * Paused, but "try again" was pressed. Sensors have new cookies and we're now waiting for all
-     * cookies to be returned.
-     */
-    static final int STATE_AUTH_PAUSED_RESUMING = 5;
-    /**
-     * Authentication is successful, but we're waiting for the user to press "confirm" button.
-     */
-    static final int STATE_AUTH_PENDING_CONFIRM = 6;
-    /**
-     * Biometric authenticated, waiting for SysUI to finish animation
-     */
-    static final int STATE_AUTHENTICATED_PENDING_SYSUI = 7;
-    /**
-     * Biometric error, waiting for SysUI to finish animation
-     */
-    static final int STATE_ERROR_PENDING_SYSUI = 8;
-    /**
-     * Device credential in AuthController is showing
-     */
-    static final int STATE_SHOWING_DEVICE_CREDENTIAL = 9;
-    /**
-     * The client binder died, and sensors were authenticating at the time. Cancel has been
-     * requested and we're waiting for the HAL(s) to send ERROR_CANCELED.
-     */
-    static final int STATE_CLIENT_DIED_CANCELLING = 10;
 
+
+    /*
+     * Defined in biometrics.proto
+     */
     @IntDef({
             STATE_AUTH_IDLE,
             STATE_AUTH_CALLED,
@@ -157,9 +109,6 @@
     // Original receiver from BiometricPrompt.
     private final IBiometricServiceReceiver mClientReceiver;
     private final String mOpPackageName;
-    private final int mCallingUid;
-    private final int mCallingPid;
-    private final int mCallingUserId;
     private final boolean mDebugEnabled;
     private final List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
 
@@ -191,9 +140,6 @@
             @NonNull IBiometricServiceReceiver clientReceiver,
             @NonNull String opPackageName,
             @NonNull PromptInfo promptInfo,
-            int callingUid,
-            int callingPid,
-            int callingUserId,
             boolean debugEnabled,
             @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
         mContext = context;
@@ -210,9 +156,6 @@
         mClientReceiver = clientReceiver;
         mOpPackageName = opPackageName;
         mPromptInfo = promptInfo;
-        mCallingUid = callingUid;
-        mCallingPid = callingPid;
-        mCallingUserId = callingUserId;
         mDebugEnabled = debugEnabled;
         mFingerprintSensorProperties = fingerprintSensorProperties;
 
@@ -254,8 +197,7 @@
             final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
             final boolean requireConfirmation = isConfirmationRequired(sensor);
             sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
-                    mUserId, mSensorReceiver, mOpPackageName, cookie, mCallingUid, mCallingPid,
-                    mCallingUserId);
+                    mUserId, mSensorReceiver, mOpPackageName, cookie);
         }
     }
 
@@ -264,7 +206,7 @@
             // Only device credential should be shown. In this case, we don't need to wait,
             // since LockSettingsService/Gatekeeper is always ready to check for credential.
             // SystemUI invokes that path.
-            mState = AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL;
+            mState = STATE_SHOWING_DEVICE_CREDENTIAL;
 
             mStatusBarService.showAuthenticationDialog(
                     mPromptInfo,
@@ -278,7 +220,7 @@
         } else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
             // Some combination of biometric or biometric|credential is requested
             setSensorsToStateWaitingForCookie();
-            mState = AuthSession.STATE_AUTH_CALLED;
+            mState = STATE_AUTH_CALLED;
         } else {
             // No authenticators requested. This should never happen - an exception should have
             // been thrown earlier in the pipeline.
@@ -386,8 +328,7 @@
         // sending the final error callback to the application.
         for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
             try {
-                sensor.goToStateCancelling(mToken, mOpPackageName, mCallingUid, mCallingPid,
-                        mCallingUserId);
+                sensor.goToStateCancelling(mToken, mOpPackageName);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Unable to cancel authentication");
             }
@@ -429,7 +370,7 @@
                     authenticators = Utils.removeBiometricBits(authenticators);
                     mPromptInfo.setAuthenticators(authenticators);
 
-                    mState = AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL;
+                    mState = STATE_SHOWING_DEVICE_CREDENTIAL;
 
                     mStatusBarService.showAuthenticationDialog(
                             mPromptInfo,
@@ -453,7 +394,7 @@
                         || error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
                 if (isAllowDeviceCredential() && errorLockout) {
                     // SystemUI handles transition from biometric to device credential.
-                    mState = AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL;
+                    mState = STATE_SHOWING_DEVICE_CREDENTIAL;
                     mStatusBarService.onBiometricError(modality, error, vendorCode);
                 } else if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
                     mStatusBarService.hideAuthenticationDialog();
@@ -463,7 +404,7 @@
                     mClientReceiver.onError(modality, error, vendorCode);
                     return true;
                 } else {
-                    mState = AuthSession.STATE_ERROR_PENDING_SYSUI;
+                    mState = STATE_ERROR_PENDING_SYSUI;
                     mStatusBarService.onBiometricError(modality, error, vendorCode);
                 }
                 break;
@@ -582,7 +523,7 @@
             if (hasPausableBiometric()) {
                 // Pause authentication. onBiometricAuthenticated(false) causes the
                 // dialog to show a "try again" button for passive modalities.
-                mState = AuthSession.STATE_AUTH_PAUSED;
+                mState = STATE_AUTH_PAUSED;
             }
 
             mClientReceiver.onAuthenticationFailed();
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 09d0583..17ec112 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -16,6 +16,8 @@
 
 package com.android.server.biometrics;
 
+import static android.hardware.biometrics.BiometricManager.Authenticators;
+
 import android.annotation.IntDef;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricManager;
@@ -61,11 +63,11 @@
     @interface SensorState {}
 
     public final int id;
-    public final int oemStrength; // strength as configured by the OEM
+    public final @Authenticators.Types int oemStrength; // strength as configured by the OEM
     public final int modality;
     public final IBiometricAuthenticator impl;
 
-    private int mUpdatedStrength; // strength updated by BiometricStrengthController
+    private @Authenticators.Types int mUpdatedStrength; // updated by BiometricStrengthController
     private @SensorState int mSensorState;
     private @BiometricConstants.Errors int mError;
 
@@ -82,7 +84,7 @@
      */
     abstract boolean confirmationSupported();
 
-    BiometricSensor(int id, int modality, int strength,
+    BiometricSensor(int id, int modality, @Authenticators.Types int strength,
             IBiometricAuthenticator impl) {
         this.id = id;
         this.modality = modality;
@@ -101,12 +103,11 @@
 
     void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
             int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-            int cookie, int callingUid, int callingPid, int callingUserId)
+            int cookie)
             throws RemoteException {
         mCookie = cookie;
         impl.prepareForAuthentication(requireConfirmation, token,
-                sessionId, userId, sensorReceiver, opPackageName, mCookie,
-                callingUid, callingPid, callingUserId);
+                sessionId, userId, sensorReceiver, opPackageName, mCookie);
         mSensorState = STATE_WAITING_FOR_COOKIE;
     }
 
@@ -122,10 +123,8 @@
         mSensorState = STATE_AUTHENTICATING;
     }
 
-    void goToStateCancelling(IBinder token, String opPackageName, int callingUid,
-            int callingPid, int callingUserId) throws RemoteException {
-        impl.cancelAuthenticationFromService(token, opPackageName, callingUid, callingPid,
-                callingUserId);
+    void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException {
+        impl.cancelAuthenticationFromService(token, opPackageName);
         mSensorState = STATE_CANCELING;
     }
 
@@ -143,7 +142,7 @@
      * strength.
      * @return a bitfield, see {@link BiometricManager.Authenticators}
      */
-    int getCurrentStrength() {
+    @Authenticators.Types int getCurrentStrength() {
         return oemStrength | mUpdatedStrength;
     }
 
@@ -160,7 +159,7 @@
      * is checked.
      * @param newStrength
      */
-    void updateStrength(int newStrength) {
+    void updateStrength(@Authenticators.Types int newStrength) {
         String log = "updateStrength: Before(" + toString() + ")";
         mUpdatedStrength = newStrength;
         log += " After(" + toString() + ")";
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 196582a..a471664 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -19,6 +19,9 @@
 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
@@ -38,7 +41,9 @@
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.net.Uri;
@@ -56,6 +61,7 @@
 import android.text.TextUtils;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -185,10 +191,7 @@
                             args.argi1 /* userid */,
                             (IBiometricServiceReceiver) args.arg3 /* receiver */,
                             (String) args.arg4 /* opPackageName */,
-                            (PromptInfo) args.arg5 /* promptInfo */,
-                            args.argi2 /* callingUid */,
-                            args.argi3 /* callingPid */,
-                            args.argi4 /* callingUserId */);
+                            (PromptInfo) args.arg5 /* promptInfo */);
                     args.recycle();
                     break;
                 }
@@ -476,6 +479,34 @@
      */
     private final class BiometricServiceWrapper extends IBiometricService.Stub {
         @Override // Binder call
+        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName)
+                throws RemoteException {
+            checkInternalPermission();
+
+            for (BiometricSensor sensor : mSensors) {
+                if (sensor.id == sensorId) {
+                    return sensor.impl.createTestSession(opPackageName);
+                }
+            }
+
+            Slog.e(TAG, "Unknown sensor for createTestSession: " + sensorId);
+            return null;
+        }
+
+        @Override // Binder call
+        public List<SensorPropertiesInternal> getSensorProperties(String opPackageName)
+                throws RemoteException {
+            checkInternalPermission();
+
+            final List<SensorPropertiesInternal> sensors = new ArrayList<>();
+            for (BiometricSensor sensor : mSensors) {
+                sensors.add(sensor.impl.getSensorProperties(opPackageName));
+            }
+
+            return sensors;
+        }
+
+        @Override // Binder call
         public void onReadyForAuthentication(int cookie) {
             checkInternalPermission();
 
@@ -486,8 +517,7 @@
 
         @Override // Binder call
         public void authenticate(IBinder token, long operationId, int userId,
-                IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo,
-                int callingUid, int callingPid, int callingUserId) {
+                IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
             checkInternalPermission();
 
             if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
@@ -516,16 +546,12 @@
             args.arg3 = receiver;
             args.arg4 = opPackageName;
             args.arg5 = promptInfo;
-            args.argi2 = callingUid;
-            args.argi3 = callingPid;
-            args.argi4 = callingUserId;
 
             mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
         }
 
         @Override // Binder call
-        public void cancelAuthentication(IBinder token, String opPackageName,
-                int callingUid, int callingPid, int callingUserId) {
+        public void cancelAuthentication(IBinder token, String opPackageName) {
             checkInternalPermission();
 
             mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget();
@@ -577,7 +603,7 @@
         }
 
         @Override
-        public void registerAuthenticator(int id, int modality, int strength,
+        public void registerAuthenticator(int id, int modality, @Authenticators.Types int strength,
                 IBiometricAuthenticator authenticator) {
             checkInternalPermission();
 
@@ -677,14 +703,28 @@
         }
 
         @Override
-        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
                 return;
             }
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                dumpInternal(pw);
+                if (args.length > 0 && "--proto".equals(args[0])) {
+                    final ProtoOutputStream proto = new ProtoOutputStream(fd);
+                    proto.write(BiometricServiceStateProto.AUTH_SESSION_STATE,
+                            mCurrentAuthSession != null ? mCurrentAuthSession.getState()
+                                    : STATE_AUTH_IDLE);
+                    for (BiometricSensor sensor : mSensors) {
+                        byte[] serviceState = sensor.impl.dumpSensorServiceStateProto();
+                        proto.write(BiometricServiceStateProto.SENSOR_SERVICE_STATES, serviceState);
+                    }
+                    proto.flush();
+                } else {
+                    dumpInternal(pw);
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -992,8 +1032,7 @@
     }
 
     private void handleAuthenticate(IBinder token, long operationId, int userId,
-            IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo,
-            int callingUid, int callingPid, int callingUserId) {
+            IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
 
         mHandler.post(() -> {
             try {
@@ -1017,7 +1056,7 @@
                     }
 
                     authenticateInternal(token, operationId, userId, receiver, opPackageName,
-                            promptInfo, callingUid, callingPid, callingUserId, preAuthInfo);
+                            promptInfo, preAuthInfo);
                 } else {
                     receiver.onError(preAuthStatus.first /* modality */,
                             preAuthStatus.second /* errorCode */,
@@ -1040,7 +1079,7 @@
      */
     private void authenticateInternal(IBinder token, long operationId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo,
-            int callingUid, int callingPid, int callingUserId, PreAuthInfo preAuthInfo) {
+            PreAuthInfo preAuthInfo) {
         Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo);
 
         // No need to dismiss dialog / send error yet if we're continuing authentication, e.g.
@@ -1057,8 +1096,7 @@
         final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId);
         mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver,
                 mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId,
-                mBiometricSensorReceiver, receiver, opPackageName, promptInfo, callingUid,
-                callingPid, callingUserId, debugEnabled,
+                mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled,
                 mInjector.getFingerprintSensorProperties(getContext()));
         try {
             mCurrentAuthSession.goToInitialState();
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 b3e6cad..62c9295 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
@@ -16,8 +16,11 @@
 
 package com.android.server.biometrics.sensors.face;
 
+import android.annotation.NonNull;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.face.IFaceService;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -32,20 +35,34 @@
     private final IFaceService mFaceService;
     private final int mSensorId;
 
-    public FaceAuthenticator(IFaceService faceService, int sensorId)
-            throws RemoteException {
+    public FaceAuthenticator(IFaceService faceService, int sensorId) throws RemoteException {
         mFaceService = faceService;
         mSensorId = sensorId;
     }
 
     @Override
+    public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException {
+        return mFaceService.createTestSession(mSensorId, opPackageName);
+    }
+
+    @Override
+    public SensorPropertiesInternal getSensorProperties(@NonNull String opPackageName)
+            throws RemoteException {
+        return mFaceService.getSensorProperties(mSensorId, opPackageName);
+    }
+
+    @Override
+    public byte[] dumpSensorServiceStateProto() throws RemoteException {
+        return mFaceService.dumpSensorServiceStateProto();
+    }
+
+    @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
+            String opPackageName, int cookie)
             throws RemoteException {
         mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
-                userId, sensorReceiver, opPackageName, cookie, callingUid, callingPid,
-                callingUserId);
+                userId, sensorReceiver, opPackageName, cookie);
     }
 
     @Override
@@ -54,10 +71,9 @@
     }
 
     @Override
-    public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
-            int callingPid, int callingUserId) throws RemoteException {
-        mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, callingUid,
-                callingPid, callingUserId);
+    public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+            throws RemoteException {
+        mFaceService.cancelAuthenticationFromService(mSensorId, token, 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 1e0764a..4906aac 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
@@ -29,6 +29,7 @@
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.face.IFace;
 import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.Face;
@@ -38,8 +39,8 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.NativeHandle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -140,6 +141,34 @@
      * Receives the incoming binder calls from FaceManager.
      */
     private final class FaceServiceWrapper extends IFaceService.Stub {
+        @Override
+        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
+            Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
+                return null;
+            }
+
+            return provider.createTestSession(sensorId, opPackageName);
+        }
+
+        @Override
+        public byte[] dumpSensorServiceStateProto() {
+            Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+            final ProtoOutputStream proto = new ProtoOutputStream();
+            for (ServiceProvider provider : mServiceProviders) {
+                for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
+                    provider.dumpProtoState(props.sensorId, proto);
+                }
+            }
+            proto.flush();
+            return proto.getBytes();
+        }
+
         @Override // Binder call
         public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(
                 String opPackageName) {
@@ -154,6 +183,21 @@
         }
 
         @Override // Binder call
+        public FaceSensorPropertiesInternal getSensorProperties(int sensorId,
+                @NonNull String opPackageName) {
+            Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+                        + ", caller: " + opPackageName);
+                return null;
+            }
+
+            return provider.getSensorProperties(sensorId);
+        }
+
+        @Override // Binder call
         public void generateChallenge(IBinder token, int sensorId, int userId,
                 IFaceServiceReceiver receiver, String opPackageName) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
@@ -270,8 +314,7 @@
         @Override // Binder call
         public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
                 IBinder token, long operationId, int userId,
-                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
-                int callingUid, int callingPid, int callingUserId) {
+                IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -326,7 +369,7 @@
 
         @Override // Binder call
         public void cancelAuthenticationFromService(int sensorId, final IBinder token,
-                final String opPackageName, int callingUid, int callingPid, int callingUserId) {
+                final String opPackageName) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
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 e3fb750..d1578fa 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
@@ -18,7 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.IBinder;
@@ -61,6 +63,9 @@
     List<FaceSensorPropertiesInternal> getSensorProperties();
 
     @NonNull
+    FaceSensorPropertiesInternal getSensorProperties(int sensorId);
+
+    @NonNull
     List<Face> getEnrolledFaces(int sensorId, int userId);
 
     @LockoutTracker.LockoutMode
@@ -110,4 +115,7 @@
     void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
 
     void dumpInternal(int sensorId, @NonNull PrintWriter pw);
+
+    @NonNull
+    ITestSession createTestSession(int sensorId, @NonNull String opPackageName);
 }
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 590579a..01c16fd 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
@@ -24,6 +24,7 @@
 import android.app.TaskStackListener;
 import android.content.Context;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.face.IFace;
 import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.Face;
@@ -254,6 +255,12 @@
 
     @NonNull
     @Override
+    public FaceSensorPropertiesInternal getSensorProperties(int sensorId) {
+        return mSensors.get(sensorId).getSensorProperties();
+    }
+
+    @NonNull
+    @Override
     public List<Face> getEnrolledFaces(int sensorId, int userId) {
         return FaceUtils.getInstance(sensorId).getBiometricsForUser(mContext, userId);
     }
@@ -566,6 +573,12 @@
         mUsageStats.print(pw);
     }
 
+    @NonNull
+    @Override
+    public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
+        return null; // TODO
+    }
+
     @Override
     public void binderDied() {
         Slog.e(getTag(), "HAL died");
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
new file mode 100644
index 0000000..4c983fb
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -0,0 +1,193 @@
+/*
+ * 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 com.android.server.biometrics.sensors.face.hidl;
+
+import static android.Manifest.permission.TEST_BIOMETRIC;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.ITestSession;
+import android.hardware.face.Face;
+import android.hardware.face.IFaceServiceReceiver;
+import android.os.Binder;
+import android.util.Slog;
+
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+public class BiometricTestSessionImpl extends ITestSession.Stub {
+    private static final String TAG = "BiometricTestSessionImpl";
+
+    @NonNull private final Context mContext;
+    private final int mSensorId;
+    @NonNull private final Face10 mFace10;
+    @NonNull private final Face10.HalResultController mHalResultController;
+    @NonNull private final Set<Integer> mEnrollmentIds;
+    @NonNull private final Random mRandom;
+
+    private final IFaceServiceReceiver mReceiver = new IFaceServiceReceiver.Stub() {
+        @Override
+        public void onEnrollResult(Face face, int remaining) {
+
+        }
+
+        @Override
+        public void onAcquired(int acquiredInfo, int vendorCode) {
+
+        }
+
+        @Override
+        public void onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric) {
+
+        }
+
+        @Override
+        public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
+
+        }
+
+        @Override
+        public void onAuthenticationFailed() {
+
+        }
+
+        @Override
+        public void onError(int error, int vendorCode) {
+
+        }
+
+        @Override
+        public void onRemoved(Face face, int remaining) {
+
+        }
+
+        @Override
+        public void onFeatureSet(boolean success, int feature) {
+
+        }
+
+        @Override
+        public void onFeatureGet(boolean success, int feature, boolean value) {
+
+        }
+
+        @Override
+        public void onChallengeGenerated(int sensorId, long challenge) {
+
+        }
+
+        @Override
+        public void onChallengeInterrupted(int sensorId) {
+
+        }
+
+        @Override
+        public void onChallengeInterruptFinished(int sensorId) {
+
+        }
+    };
+
+    BiometricTestSessionImpl(@NonNull Context context, int sensorId, @NonNull Face10 face10,
+            @NonNull Face10.HalResultController halResultController) {
+        mContext = context;
+        mSensorId = sensorId;
+        mFace10 = face10;
+        mHalResultController = halResultController;
+        mEnrollmentIds = new HashSet<>();
+        mRandom = new Random();
+    }
+
+    @Override
+    public void setTestHalEnabled(boolean enabled) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        mFace10.setTestHalEnabled(enabled);
+    }
+
+    @Override
+    public void startEnroll(int userId) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        mFace10.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
+                mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
+                null /* surfaceHandle */);
+    }
+
+    @Override
+    public void finishEnroll(int userId) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        int nextRandomId = mRandom.nextInt();
+        while (mEnrollmentIds.contains(nextRandomId)) {
+            nextRandomId = mRandom.nextInt();
+        }
+
+        mEnrollmentIds.add(nextRandomId);
+        mHalResultController.onEnrollResult(0 /* deviceId */,
+                nextRandomId /* faceId */, userId, 0);
+    }
+
+    @Override
+    public void acceptAuthentication(int userId) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        // Fake authentication with any of the existing fingers
+        List<Face> faces = FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+        if (faces.isEmpty()) {
+            Slog.w(TAG, "No faces, returning");
+            return;
+        }
+        final int fid = faces.get(0).getBiometricId();
+        final ArrayList<Byte> hat = new ArrayList<>(Collections.nCopies(69, (byte) 0));
+        mHalResultController.onAuthenticated(0 /* deviceId */, fid, userId, hat);
+    }
+
+    @Override
+    public void rejectAuthentication(int userId) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        mHalResultController.onAuthenticated(0 /* deviceId */, 0 /* faceId */, userId, null);
+    }
+
+    @Override
+    public void notifyAcquired(int userId, int acquireInfo) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        mHalResultController.onAcquired(0 /* deviceId */, userId, acquireInfo, 0 /* vendorCode */);
+    }
+
+    @Override
+    public void notifyError(int userId, int errorCode) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        mHalResultController.onError(0 /* deviceId */, userId, errorCode, 0 /* vendorCode */);
+    }
+
+    @Override
+    public void cleanupInternalState(int userId) {
+        Utils.checkPermission(mContext, TEST_BIOMETRIC);
+
+        mFace10.scheduleInternalCleanup(mSensorId, userId);
+    }
+}
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 7b70bd8a..27ca33d 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
@@ -28,6 +28,7 @@
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.ITestSession;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
 import android.hardware.face.Face;
@@ -51,6 +52,9 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.SensorServiceStateProto;
+import com.android.server.biometrics.SensorStateProto;
+import com.android.server.biometrics.UserStateProto;
 import com.android.server.biometrics.Utils;
 import com.android.server.biometrics.sensors.AcquisitionClient;
 import com.android.server.biometrics.sensors.AuthenticationConsumer;
@@ -67,6 +71,7 @@
 import com.android.server.biometrics.sensors.face.LockoutHalImpl;
 import com.android.server.biometrics.sensors.face.ServiceProvider;
 import com.android.server.biometrics.sensors.face.UsageStats;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -93,6 +98,8 @@
     static final String NOTIFICATION_TAG = "FaceService";
     static final int NOTIFICATION_ID = 1;
 
+    private boolean mTestHalEnabled;
+
     @NonNull private final FaceSensorPropertiesInternal mSensorProperties;
     @NonNull private final Context mContext;
     @NonNull private final BiometricScheduler mScheduler;
@@ -104,6 +111,7 @@
     @NonNull private final NotificationManager mNotificationManager;
     @NonNull private final Map<Integer, Long> mAuthenticatorIds;
     @Nullable private IBiometricsFace mDaemon;
+    @NonNull private final HalResultController mHalResultController;
     // If a challenge is generated, keep track of its owner. Since IBiometricsFace@1.0 only
     // supports a single in-flight challenge, we must notify the interrupted owner that its
     // challenge is no longer valid. The interrupted owner will be notified when the interrupter
@@ -122,174 +130,207 @@
         }
     };
 
-    private final IBiometricsFaceClientCallback mDaemonCallback =
-            new IBiometricsFaceClientCallback.Stub() {
-                @Override
-                public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
-                    mHandler.post(() -> {
-                        final CharSequence name = FaceUtils.getInstance()
-                                .getUniqueName(mContext, userId);
-                        final Face face = new Face(name, faceId, deviceId);
+    public static class HalResultController extends IBiometricsFaceClientCallback.Stub {
+        /**
+         * Interface to sends results to the HalResultController's owner.
+         */
+        public interface Callback {
+            /**
+             * Invoked when the HAL sends ERROR_HW_UNAVAILABLE.
+             */
+            void onHardwareUnavailable();
+        }
 
-                        final ClientMonitor<?> client = mScheduler.getCurrentClient();
-                        if (!(client instanceof FaceEnrollClient)) {
-                            Slog.e(TAG, "onEnrollResult for non-enroll client: "
-                                    + Utils.getClientName(client));
-                            return;
-                        }
+        private final int mSensorId;
+        @NonNull private final Context mContext;
+        @NonNull private final Handler mHandler;
+        @NonNull private final BiometricScheduler mScheduler;
+        @Nullable private Callback mCallback;
+        @NonNull private final LockoutHalImpl mLockoutTracker;
+        @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
 
-                        final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
-                        enrollClient.onEnrollResult(face, remaining);
-                    });
+        HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
+                @NonNull BiometricScheduler scheduler, @NonNull LockoutHalImpl lockoutTracker,
+                @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+            mSensorId = sensorId;
+            mContext = context;
+            mHandler = handler;
+            mScheduler = scheduler;
+            mLockoutTracker = lockoutTracker;
+            mLockoutResetDispatcher = lockoutResetDispatcher;
+        }
+
+        public void setCallback(@Nullable Callback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
+            mHandler.post(() -> {
+                final CharSequence name = FaceUtils.getInstance()
+                        .getUniqueName(mContext, userId);
+                final Face face = new Face(name, faceId, deviceId);
+
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof FaceEnrollClient)) {
+                    Slog.e(TAG, "onEnrollResult for non-enroll client: "
+                            + Utils.getClientName(client));
+                    return;
                 }
 
-                @Override
-                public void onAuthenticated(long deviceId, int faceId, int userId,
-                        ArrayList<Byte> token) {
-                    mHandler.post(() -> {
-                        final ClientMonitor<?> client = mScheduler.getCurrentClient();
-                        if (!(client instanceof AuthenticationConsumer)) {
-                            Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
-                                    + Utils.getClientName(client));
-                            return;
-                        }
+                final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
+                enrollClient.onEnrollResult(face, remaining);
+            });
+        }
 
-                        final AuthenticationConsumer authenticationConsumer =
-                                (AuthenticationConsumer) client;
-                        final boolean authenticated = faceId != 0;
-                        final Face face = new Face("", faceId, deviceId);
-                        authenticationConsumer.onAuthenticated(face, authenticated, token);
-                    });
+        @Override
+        public void onAuthenticated(long deviceId, int faceId, int userId,
+                ArrayList<Byte> token) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof AuthenticationConsumer)) {
+                    Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
+                            + Utils.getClientName(client));
+                    return;
                 }
 
-                @Override
-                public void onAcquired(long deviceId, int userId, int acquiredInfo,
-                        int vendorCode) {
-                    mHandler.post(() -> {
-                        final ClientMonitor<?> client = mScheduler.getCurrentClient();
-                        if (!(client instanceof AcquisitionClient)) {
-                            Slog.e(TAG, "onAcquired for non-acquire client: "
-                                    + Utils.getClientName(client));
-                            return;
-                        }
+                final AuthenticationConsumer authenticationConsumer =
+                        (AuthenticationConsumer) client;
+                final boolean authenticated = faceId != 0;
+                final Face face = new Face("", faceId, deviceId);
+                authenticationConsumer.onAuthenticated(face, authenticated, token);
+            });
+        }
 
-                        final AcquisitionClient<?> acquisitionClient =
-                                (AcquisitionClient<?>) client;
-                        acquisitionClient.onAcquired(acquiredInfo, vendorCode);
-                    });
+        @Override
+        public void onAcquired(long deviceId, int userId, int acquiredInfo,
+                int vendorCode) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof AcquisitionClient)) {
+                    Slog.e(TAG, "onAcquired for non-acquire client: "
+                            + Utils.getClientName(client));
+                    return;
                 }
 
-                @Override
-                public void onError(long deviceId, int userId, int error, int vendorCode) {
-                    mHandler.post(() -> {
-                        final ClientMonitor<?> client = mScheduler.getCurrentClient();
-                        Slog.d(TAG, "handleError"
-                                + ", client: " + (client != null ? client.getOwnerString() : null)
-                                + ", error: " + error
-                                + ", vendorCode: " + vendorCode);
-                        if (!(client instanceof Interruptable)) {
-                            Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(
-                                    client));
-                            return;
-                        }
+                final AcquisitionClient<?> acquisitionClient =
+                        (AcquisitionClient<?>) client;
+                acquisitionClient.onAcquired(acquiredInfo, vendorCode);
+            });
+        }
 
-                        final Interruptable interruptable = (Interruptable) client;
-                        interruptable.onError(error, vendorCode);
-
-                        if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
-                            Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE");
-                            mDaemon = null;
-                            mCurrentUserId = UserHandle.USER_NULL;
-                        }
-                    });
+        @Override
+        public void onError(long deviceId, int userId, int error, int vendorCode) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                Slog.d(TAG, "handleError"
+                        + ", client: " + (client != null ? client.getOwnerString() : null)
+                        + ", error: " + error
+                        + ", vendorCode: " + vendorCode);
+                if (!(client instanceof Interruptable)) {
+                    Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(
+                            client));
+                    return;
                 }
 
-                @Override
-                public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) {
-                    mHandler.post(() -> {
-                        final ClientMonitor<?> client = mScheduler.getCurrentClient();
-                        if (!(client instanceof RemovalConsumer)) {
-                            Slog.e(TAG, "onRemoved for non-removal consumer: "
-                                    + Utils.getClientName(client));
-                            return;
-                        }
+                final Interruptable interruptable = (Interruptable) client;
+                interruptable.onError(error, vendorCode);
 
-                        final RemovalConsumer removalConsumer = (RemovalConsumer) client;
+                if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
+                    Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE");
+                    if (mCallback != null) {
+                        mCallback.onHardwareUnavailable();
+                    }
+                }
+            });
+        }
 
-                        if (!removed.isEmpty()) {
-                            // Convert to old fingerprint-like behavior, where remove() receives
-                            // one removal
-                            // at a time. This way, remove can share some more common code.
-                            for (int i = 0; i < removed.size(); i++) {
-                                final int id = removed.get(i);
-                                final Face face = new Face("", id, deviceId);
-                                final int remaining = removed.size() - i - 1;
-                                Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining);
-                                removalConsumer.onRemoved(face, remaining);
-                            }
-                        } else {
-                            removalConsumer.onRemoved(null, 0 /* remaining */);
-                        }
-
-                        Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                                Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
-                    });
+        @Override
+        public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof RemovalConsumer)) {
+                    Slog.e(TAG, "onRemoved for non-removal consumer: "
+                            + Utils.getClientName(client));
+                    return;
                 }
 
-                @Override
-                public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) {
-                    mHandler.post(() -> {
-                        final ClientMonitor<?> client = mScheduler.getCurrentClient();
-                        if (!(client instanceof EnumerateConsumer)) {
-                            Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
-                                    + Utils.getClientName(client));
-                            return;
-                        }
+                final RemovalConsumer removalConsumer = (RemovalConsumer) client;
 
-                        final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client;
-
-                        if (!faceIds.isEmpty()) {
-                            // Convert to old fingerprint-like behavior, where enumerate()
-                            // receives one
-                            // template at a time. This way, enumerate can share some more common
-                            // code.
-                            for (int i = 0; i < faceIds.size(); i++) {
-                                final Face face = new Face("", faceIds.get(i), deviceId);
-                                enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1);
-                            }
-                        } else {
-                            // For face, the HIDL contract is to receive an empty list when there
-                            // are no
-                            // templates enrolled. Send a null identifier since we don't consume
-                            // them
-                            // anywhere, and send remaining == 0 so this code can be shared with
-                            // Fingerprint@2.1
-                            enumerateConsumer.onEnumerationResult(null /* identifier */, 0);
-                        }
-                    });
+                if (!removed.isEmpty()) {
+                    // Convert to old fingerprint-like behavior, where remove() receives
+                    // one removal
+                    // at a time. This way, remove can share some more common code.
+                    for (int i = 0; i < removed.size(); i++) {
+                        final int id = removed.get(i);
+                        final Face face = new Face("", id, deviceId);
+                        final int remaining = removed.size() - i - 1;
+                        Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining);
+                        removalConsumer.onRemoved(face, remaining);
+                    }
+                } else {
+                    removalConsumer.onRemoved(null, 0 /* remaining */);
                 }
 
-                @Override
-                public void onLockoutChanged(long duration) {
-                    mHandler.post(() -> {
-                        Slog.d(TAG, "onLockoutChanged: " + duration);
-                        final @LockoutTracker.LockoutMode int lockoutMode;
-                        if (duration == 0) {
-                            lockoutMode = LockoutTracker.LOCKOUT_NONE;
-                        } else if (duration == -1 || duration == Long.MAX_VALUE) {
-                            lockoutMode = LockoutTracker.LOCKOUT_PERMANENT;
-                        } else {
-                            lockoutMode = LockoutTracker.LOCKOUT_TIMED;
-                        }
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
+            });
+        }
 
-                        mLockoutTracker.setCurrentUserLockoutMode(lockoutMode);
-
-                        if (duration == 0) {
-                            mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId);
-                        }
-                    });
+        @Override
+        public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof EnumerateConsumer)) {
+                    Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
+                            + Utils.getClientName(client));
+                    return;
                 }
-            };
+
+                final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client;
+
+                if (!faceIds.isEmpty()) {
+                    // Convert to old fingerprint-like behavior, where enumerate()
+                    // receives one
+                    // template at a time. This way, enumerate can share some more common
+                    // code.
+                    for (int i = 0; i < faceIds.size(); i++) {
+                        final Face face = new Face("", faceIds.get(i), deviceId);
+                        enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1);
+                    }
+                } else {
+                    // For face, the HIDL contract is to receive an empty list when there
+                    // are no
+                    // templates enrolled. Send a null identifier since we don't consume
+                    // them
+                    // anywhere, and send remaining == 0 so this code can be shared with
+                    // Fingerprint@2.1
+                    enumerateConsumer.onEnumerationResult(null /* identifier */, 0);
+                }
+            });
+        }
+
+        @Override
+        public void onLockoutChanged(long duration) {
+            mHandler.post(() -> {
+                Slog.d(TAG, "onLockoutChanged: " + duration);
+                final @LockoutTracker.LockoutMode int lockoutMode;
+                if (duration == 0) {
+                    lockoutMode = LockoutTracker.LOCKOUT_NONE;
+                } else if (duration == -1 || duration == Long.MAX_VALUE) {
+                    lockoutMode = LockoutTracker.LOCKOUT_PERMANENT;
+                } else {
+                    lockoutMode = LockoutTracker.LOCKOUT_TIMED;
+                }
+
+                mLockoutTracker.setCurrentUserLockoutMode(lockoutMode);
+
+                if (duration == 0) {
+                    mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId);
+                }
+            });
+        }
+    }
 
     @VisibleForTesting
     public Face10(@NonNull Context context, int sensorId,
@@ -309,6 +350,12 @@
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
         mLockoutTracker = new LockoutHalImpl();
         mLockoutResetDispatcher = lockoutResetDispatcher;
+        mHalResultController = new HalResultController(sensorId, context, mHandler, mScheduler,
+                mLockoutTracker, lockoutResetDispatcher);
+        mHalResultController.setCallback(() -> {
+            mDaemon = null;
+            mCurrentUserId = UserHandle.USER_NULL;
+        });
 
         try {
             ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
@@ -351,6 +398,12 @@
     }
 
     private synchronized IBiometricsFace getDaemon() {
+        if (mTestHalEnabled) {
+            final TestHal testHal = new TestHal();
+            testHal.setCallback(mHalResultController);
+            return testHal;
+        }
+
         if (mDaemon != null) {
             return mDaemon;
         }
@@ -378,7 +431,7 @@
         // successfully set.
         long halId = 0;
         try {
-            halId = mDaemon.setCallback(mDaemonCallback).value;
+            halId = mDaemon.setCallback(mHalResultController).value;
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to set callback for face HAL", e);
             mDaemon = null;
@@ -413,6 +466,12 @@
         return properties;
     }
 
+    @NonNull
+    @Override
+    public FaceSensorPropertiesInternal getSensorProperties(int sensorId) {
+        return mSensorProperties;
+    }
+
     @Override
     @NonNull
     public List<Face> getEnrolledFaces(int sensorId, int userId) {
@@ -712,6 +771,22 @@
 
     @Override
     public void dumpProtoState(int sensorId, ProtoOutputStream proto) {
+        final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
+
+        proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
+        proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
+
+        for (UserInfo user : UserManager.get(mContext).getUsers()) {
+            final int userId = user.getUserHandle().getIdentifier();
+
+            final long userToken = proto.start(SensorStateProto.USER_STATES);
+            proto.write(UserStateProto.USER_ID, userId);
+            proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getInstance()
+                    .getBiometricsForUser(mContext, userId).size());
+            proto.end(userToken);
+        }
+
+        proto.end(sensorToken);
     }
 
     @Override
@@ -844,4 +919,14 @@
             }
         }
     }
+
+    void setTestHalEnabled(boolean enabled) {
+        mTestHalEnabled = enabled;
+    }
+
+    @NonNull
+    @Override
+    public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
+        return new BiometricTestSessionImpl(mContext, mSensorId, this, mHalResultController);
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java
new file mode 100644
index 0000000..bab1114d
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/TestHal.java
@@ -0,0 +1,132 @@
+/*
+ * 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 com.android.server.biometrics.sensors.face.hidl;
+
+import android.annotation.Nullable;
+import android.hardware.biometrics.face.V1_0.FaceError;
+import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
+import android.hardware.biometrics.face.V1_0.OptionalBool;
+import android.hardware.biometrics.face.V1_0.OptionalUint64;
+import android.hardware.biometrics.face.V1_0.Status;
+import android.hardware.biometrics.face.V1_1.IBiometricsFace;
+import android.os.NativeHandle;
+import android.os.RemoteException;
+
+import java.util.ArrayList;
+
+public class TestHal extends IBiometricsFace.Stub {
+    @Nullable
+    private IBiometricsFaceClientCallback mCallback;
+
+    @Override
+    public OptionalUint64 setCallback(IBiometricsFaceClientCallback clientCallback) {
+        mCallback = clientCallback;
+        final OptionalUint64 result = new OptionalUint64();
+        result.status = Status.OK;
+        return new OptionalUint64();
+    }
+
+    @Override
+    public int setActiveUser(int userId, String storePath) {
+        return 0;
+    }
+
+    @Override
+    public OptionalUint64 generateChallenge(int challengeTimeoutSec) {
+        final OptionalUint64 result = new OptionalUint64();
+        result.status = Status.OK;
+        result.value = 0;
+        return result;
+    }
+
+    @Override
+    public int enroll(ArrayList<Byte> hat, int timeoutSec, ArrayList<Integer> disabledFeatures) {
+        return 0;
+    }
+
+    @Override
+    public int revokeChallenge() {
+        return 0;
+    }
+
+    @Override
+    public int setFeature(int feature, boolean enabled, ArrayList<Byte> hat, int faceId) {
+        return 0;
+    }
+
+    @Override
+    public OptionalBool getFeature(int feature, int faceId) {
+        final OptionalBool result = new OptionalBool();
+        result.status = Status.OK;
+        result.value = true;
+        return result;
+    }
+
+    @Override
+    public OptionalUint64 getAuthenticatorId() {
+        final OptionalUint64 result = new OptionalUint64();
+        result.status = Status.OK;
+        result.value = 0;
+        return result;
+    }
+
+    @Override
+    public int cancel() throws RemoteException {
+        if (mCallback != null) {
+            mCallback.onError(0 /* deviceId */, 0 /* userId */, FaceError.CANCELED,
+                    0 /* vendorCode */);
+        }
+        return 0;
+    }
+
+    @Override
+    public int enumerate() {
+        return 0;
+    }
+
+    @Override
+    public int remove(int faceId) {
+        return 0;
+    }
+
+    @Override
+    public int authenticate(long operationId) {
+        return 0;
+    }
+
+    @Override
+    public int userActivity() {
+        return 0;
+    }
+
+    @Override
+    public int resetLockout(ArrayList<Byte> hat) {
+        return 0;
+    }
+
+    @Override
+    public int enrollRemotely(ArrayList<Byte> hat, int timeoutSec,
+            ArrayList<Integer> disabledFeatures) {
+        return 0;
+    }
+
+    @Override
+    public int enroll_1_1(ArrayList<Byte> hat, int timeoutSec, ArrayList<Integer> disabledFeatures,
+            NativeHandle nativeHandle) {
+        return 0;
+    }
+}
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 9f9d9cc..1616457 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
@@ -16,8 +16,11 @@
 
 package com.android.server.biometrics.sensors.fingerprint;
 
+import android.annotation.NonNull;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.fingerprint.IFingerprintService;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -39,12 +42,28 @@
     }
 
     @Override
+    public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException {
+        return mFingerprintService.createTestSession(mSensorId, opPackageName);
+    }
+
+    @Override
+    public SensorPropertiesInternal getSensorProperties(@NonNull String opPackageName)
+            throws RemoteException {
+        return mFingerprintService.getSensorProperties(mSensorId, opPackageName);
+    }
+
+    @Override
+    public byte[] dumpSensorServiceStateProto() throws RemoteException {
+        return mFingerprintService.dumpSensorServiceStateProto();
+    }
+
+    @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
+            String opPackageName, int cookie)
             throws RemoteException {
         mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
-                sensorReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId);
+                sensorReceiver, opPackageName, cookie);
     }
 
     @Override
@@ -53,10 +72,9 @@
     }
 
     @Override
-    public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
-            int callingPid, int callingUserId) throws RemoteException {
-        mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName,
-                callingUid, callingPid, callingUserId);
+    public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+            throws RemoteException {
+        mFingerprintService.cancelAuthenticationFromService(mSensorId, token, 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 b84d095..af0935f 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
@@ -100,21 +100,37 @@
      */
     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
         @Override
-        public ITestSession createTestSession(int sensorId, String opPackageName) {
+        public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
             Utils.checkPermission(getContext(), TEST_BIOMETRIC);
 
-            for (ServiceProvider provider : mServiceProviders) {
-                if (provider.containsSensor(sensorId)) {
-                    return provider.createTestSession(sensorId, opPackageName);
-                }
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for createTestSession, sensorId: " + sensorId);
+                return null;
             }
 
-            return null;
+            return provider.createTestSession(sensorId, opPackageName);
+        }
+
+        @Override
+        public byte[] dumpSensorServiceStateProto() {
+            Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+            final ProtoOutputStream proto = new ProtoOutputStream();
+            for (ServiceProvider provider : mServiceProviders) {
+                for (FingerprintSensorPropertiesInternal props
+                        : provider.getSensorProperties()) {
+                    provider.dumpProtoState(props.sensorId, proto);
+                }
+            }
+            proto.flush();
+            return proto.getBytes();
         }
 
         @Override // Binder call
         public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(
-                String opPackageName) {
+                @NonNull String opPackageName) {
             if (getContext().checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
                     != PackageManager.PERMISSION_GRANTED) {
                 Utils.checkPermission(getContext(), TEST_BIOMETRIC);
@@ -128,6 +144,20 @@
             return properties;
         }
 
+        @Override
+        public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId,
+                @NonNull String opPackageName) {
+            Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "No matching sensor for getSensorProperties, sensorId: " + sensorId
+                        + ", caller: " + opPackageName);
+                return null;
+            }
+            return provider.getSensorProperties(sensorId);
+        }
+
         @Override // Binder call
         public void generateChallenge(IBinder token, int sensorId, int userId,
                 IFingerprintServiceReceiver receiver, String opPackageName) {
@@ -262,7 +292,7 @@
         @Override // Binder call
         public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
                 int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
-                int cookie, int callingUid, int callingPid, int callingUserId) {
+                int cookie) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -334,7 +364,7 @@
 
         @Override // Binder call
         public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
-                final String opPackageName, int callingUid, int callingPid, int callingUserId) {
+                final String opPackageName) {
             Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
 
             final ServiceProvider provider = getProviderForSensor(sensorId);
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 c13a656..6e36cd2 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
@@ -64,6 +64,9 @@
     @NonNull
     List<FingerprintSensorPropertiesInternal> getSensorProperties();
 
+    @NonNull
+    FingerprintSensorPropertiesInternal getSensorProperties(int sensorId);
+
     void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken);
 
     void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
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 0ebfe93..5f3be488c1 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
@@ -226,6 +226,12 @@
         return props;
     }
 
+    @NonNull
+    @Override
+    public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId) {
+        return mSensors.get(sensorId).getSensorProperties();
+    }
+
     private void scheduleLoadAuthenticatorIds(int sensorId) {
         for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
             scheduleLoadAuthenticatorIdsForUser(sensorId, user.id);
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 2e78912..380608f 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
@@ -39,10 +39,10 @@
 
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.SensorServiceStateProto;
+import com.android.server.biometrics.SensorStateProto;
+import com.android.server.biometrics.UserStateProto;
 import com.android.server.biometrics.Utils;
-import com.android.server.biometrics.fingerprint.FingerprintServiceStateProto;
-import com.android.server.biometrics.fingerprint.SensorStateProto;
-import com.android.server.biometrics.fingerprint.UserStateProto;
 import com.android.server.biometrics.sensors.AcquisitionClient;
 import com.android.server.biometrics.sensors.AuthenticationConsumer;
 import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -491,7 +491,7 @@
     }
 
     void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
-        final long sensorToken = proto.start(FingerprintServiceStateProto.SENSOR_STATES);
+        final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
 
         proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
         proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
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 8c766d6..9924d47 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
@@ -49,13 +49,13 @@
 
 import com.android.internal.R;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.SensorServiceStateProto;
+import com.android.server.biometrics.SensorStateProto;
+import com.android.server.biometrics.UserStateProto;
 import com.android.server.biometrics.Utils;
 import com.android.server.biometrics.fingerprint.FingerprintServiceDumpProto;
-import com.android.server.biometrics.fingerprint.FingerprintServiceStateProto;
 import com.android.server.biometrics.fingerprint.FingerprintUserStatsProto;
 import com.android.server.biometrics.fingerprint.PerformanceStatsProto;
-import com.android.server.biometrics.fingerprint.SensorStateProto;
-import com.android.server.biometrics.fingerprint.UserStateProto;
 import com.android.server.biometrics.sensors.AcquisitionClient;
 import com.android.server.biometrics.sensors.AuthenticationClient;
 import com.android.server.biometrics.sensors.AuthenticationConsumer;
@@ -397,7 +397,9 @@
 
     private synchronized IBiometricsFingerprint getDaemon() {
         if (mTestHalEnabled) {
-            return new TestHal();
+            final TestHal testHal = new TestHal();
+            testHal.setNotify(mHalResultController);
+            return testHal;
         }
 
         if (mDaemon != null) {
@@ -504,6 +506,12 @@
         return properties;
     }
 
+    @NonNull
+    @Override
+    public FingerprintSensorPropertiesInternal getSensorProperties(int sensorId) {
+        return mSensorProperties;
+    }
+
     @Override
     public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
         // Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler
@@ -701,7 +709,7 @@
 
     @Override
     public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
-        final long sensorToken = proto.start(FingerprintServiceStateProto.SENSOR_STATES);
+        final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
 
         proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
         proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java
index 86c0875..b7aec0e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/TestHal.java
@@ -16,6 +16,8 @@
 
 package com.android.server.biometrics.sensors.fingerprint.hidl;
 
+import android.annotation.Nullable;
+import android.hardware.biometrics.fingerprint.V2_1.FingerprintError;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
 import android.hardware.biometrics.fingerprint.V2_3.IBiometricsFingerprint;
 import android.os.RemoteException;
@@ -24,6 +26,9 @@
  * Test HAL that provides only provides no-ops.
  */
 public class TestHal extends IBiometricsFingerprint.Stub {
+    @Nullable
+    private IBiometricsFingerprintClientCallback mCallback;
+
     @Override
     public boolean isUdfps(int sensorId) {
         return false;
@@ -41,6 +46,7 @@
 
     @Override
     public long setNotify(IBiometricsFingerprintClientCallback clientCallback) {
+        mCallback = clientCallback;
         return 0;
     }
 
@@ -65,7 +71,10 @@
     }
 
     @Override
-    public int cancel() {
+    public int cancel() throws RemoteException {
+        if (mCallback != null) {
+            mCallback.onError(0, FingerprintError.ERROR_CANCELED, 0 /* vendorCode */);
+        }
         return 0;
     }
 
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 b756d8e..6f437a7 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
@@ -16,8 +16,11 @@
 
 package com.android.server.biometrics.sensors.iris;
 
+import android.annotation.NonNull;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.SensorPropertiesInternal;
 import android.hardware.iris.IIrisService;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -36,10 +39,25 @@
     }
 
     @Override
+    public ITestSession createTestSession(@NonNull String opPackageName) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public SensorPropertiesInternal getSensorProperties(@NonNull String opPackageName)
+            throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public byte[] dumpSensorServiceStateProto() throws RemoteException {
+        return null;
+    }
+
+    @Override
     public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
             long sessionId, int userId, IBiometricSensorReceiver sensorReceiver,
-            String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
-            throws RemoteException {
+            String opPackageName, int cookie) throws RemoteException {
     }
 
     @Override
@@ -47,8 +65,8 @@
     }
 
     @Override
-    public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
-            int callingPid, int callingUserId) throws RemoteException {
+    public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+            throws RemoteException {
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 34019c7..4a799b5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -320,6 +320,10 @@
         final ArraySet<File> unclaimedStages = newArraySet(
                 stagingDir.listFiles(sStageFilter));
 
+        // We also need to clean up orphaned staging directory for staged sessions
+        final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
+        unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
+
         // Ignore stages claimed by active sessions
         for (int i = 0; i < mSessions.size(); i++) {
             final PackageInstallerSession session = mSessions.valueAt(i);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ab5b9d1..ef947d8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1678,6 +1678,10 @@
         destroyInternal();
         // Dispatch message to remove session from PackageInstallerService.
         dispatchSessionFinished(error, detailMessage, null);
+        // TODO(b/173194203): clean up staged session in destroyInternal() call instead
+        if (isStaged() && stageDir != null) {
+            cleanStageDir();
+        }
     }
 
     private void onSessionVerificationFailure(int error, String msg) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 955e51f..f819063 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3372,16 +3372,28 @@
                 SystemConfig.getInstance().getSplitPermissions());
     }
 
+    @NonNull
     private OneTimePermissionUserManager getOneTimePermissionUserManager(@UserIdInt int userId) {
         OneTimePermissionUserManager oneTimePermissionUserManager;
         synchronized (mLock) {
-            oneTimePermissionUserManager =
-                    mOneTimePermissionUserManagers.get(userId);
+            oneTimePermissionUserManager = mOneTimePermissionUserManagers.get(userId);
             if (oneTimePermissionUserManager != null) {
                 return oneTimePermissionUserManager;
             }
-            oneTimePermissionUserManager = new OneTimePermissionUserManager(
-                    mContext.createContextAsUser(UserHandle.of(userId), /*flags*/ 0));
+        }
+        // We cannot create a new instance of OneTimePermissionUserManager while holding our own
+        // lock, which may lead to a deadlock with the package manager lock. So we do it in a
+        // retry-like way, and just discard the newly created instance if someone else managed to be
+        // a little bit faster than us when we dropped our own lock.
+        final OneTimePermissionUserManager newOneTimePermissionUserManager =
+                new OneTimePermissionUserManager(mContext.createContextAsUser(UserHandle.of(userId),
+                        /*flags*/ 0));
+        synchronized (mLock) {
+            oneTimePermissionUserManager = mOneTimePermissionUserManagers.get(userId);
+            if (oneTimePermissionUserManager != null) {
+                return oneTimePermissionUserManager;
+            }
+            oneTimePermissionUserManager = newOneTimePermissionUserManager;
             mOneTimePermissionUserManagers.put(userId, oneTimePermissionUserManager);
         }
         oneTimePermissionUserManager.registerUninstallListener();
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index a82133d..2de4a71 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -244,12 +244,12 @@
         setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy());
         updateSourceFrame();
         if (mControl != null) {
-            final Rect frame = mWin.getWindowFrames().mFrame;
-            if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
+            final Point position = getWindowFrameSurfacePosition();
+            if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) {
                 if (!mWin.getWindowFrames().didFrameSizeChange()) {
-                    updateLeashPosition(frame, -1 /* frameNumber */);
+                    updateLeashPosition(-1 /* frameNumber */);
                 } else if (mWin.mInRelayout) {
-                    updateLeashPosition(frame, mWin.getFrameNumber());
+                    updateLeashPosition(mWin.getFrameNumber());
                 } else {
                     mWin.mPendingPositionChanged = this;
                 }
@@ -258,20 +258,26 @@
         }
     }
 
-    void updateLeashPosition(Rect frame, long frameNumber) {
+    void updateLeashPosition(long frameNumber) {
         if (mControl == null) {
             return;
         }
         final SurfaceControl leash = mControl.getLeash();
         if (leash != null) {
             final Transaction t = mDisplayContent.getPendingTransaction();
-            Point position = new Point();
-            mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
+            final Point position = mControl.getSurfacePosition();
             t.setPosition(leash, position.x, position.y);
             deferTransactionUntil(t, leash, frameNumber);
         }
     }
 
+    private Point getWindowFrameSurfacePosition() {
+        final Rect frame = mWin.getFrame();
+        final Point position = new Point();
+        mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
+        return position;
+    }
+
     private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
         if (frameNumber >= 0) {
             final SurfaceControl barrier = mWin.getClientViewRootSurface();
@@ -319,7 +325,8 @@
             setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
             return;
         }
-        mAdapter = new ControlAdapter();
+        final Point surfacePosition = getWindowFrameSurfacePosition();
+        mAdapter = new ControlAdapter(surfacePosition);
         if (getSource().getType() == ITYPE_IME) {
             setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
         }
@@ -343,8 +350,7 @@
         }
         mControlTarget = target;
         updateVisibility();
-        mControl = new InsetsSourceControl(mSource.getType(), leash,
-                new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
+        mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition);
         ProtoLog.d(WM_DEBUG_IME,
                 "InsetsSource Control %s for target %s", mControl, mControlTarget);
     }
@@ -527,8 +533,13 @@
 
     private class ControlAdapter implements AnimationAdapter {
 
+        private final Point mSurfacePosition;
         private SurfaceControl mCapturedLeash;
 
+        ControlAdapter(Point surfacePosition) {
+            mSurfacePosition = surfacePosition;
+        }
+
         @Override
         public boolean getShowWallpaper() {
             return false;
@@ -549,11 +560,7 @@
                     mControlTarget);
 
             mCapturedLeash = animationLeash;
-            final Rect frame = mWin.getWindowFrames().mFrame;
-            Point position = new Point();
-            mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
-
-            t.setPosition(mCapturedLeash, position.x, position.y);
+            t.setPosition(mCapturedLeash, mSurfacePosition.x, mSurfacePosition.y);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8a09bd4..9b91e3a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2195,7 +2195,7 @@
             }
 
             if (win.mPendingPositionChanged != null) {
-                win.mPendingPositionChanged.updateLeashPosition(win.getFrame(), frameNumber);
+                win.mPendingPositionChanged.updateLeashPosition(frameNumber);
                 win.mPendingPositionChanged = null;
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index c1f83cb..eae4a08 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -452,22 +452,15 @@
                 new long[]{10, 10, 10}, new int[]{100, 200, 50}, -1);
         vibrate(service, effect);
 
-        verify(mNativeWrapperMock).vibratorOff();
-
-        // Wait for VibrateThread to turn vibrator ON with total timing and no callback.
-        Thread.sleep(5);
-        verify(mNativeWrapperMock).vibratorOn(eq(30L), anyLong());
-
-        // First amplitude set right away.
-        verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
-
-        // Second amplitude set after first timing is finished.
-        Thread.sleep(10);
-        verify(mNativeWrapperMock).vibratorSetAmplitude(eq(200));
-
-        // Third amplitude set after second timing is finished.
-        Thread.sleep(10);
-        verify(mNativeWrapperMock).vibratorSetAmplitude(eq(50));
+        // Wait for VibrateThread to finish: 10ms 100, 10ms 200, 10ms 50.
+        Thread.sleep(40);
+        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(30L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorSetAmplitude(eq(200));
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorSetAmplitude(eq(50));
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
     }
 
     @Test
@@ -696,7 +689,7 @@
                 HAPTIC_FEEDBACK_ATTRS);
 
         // Waveform effect runs on a separate thread.
-        Thread.sleep(5);
+        Thread.sleep(15);
 
         // Alarm vibration is never scaled.
         verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index e011c797..e4be448 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -47,7 +47,6 @@
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.AdditionalMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -170,10 +169,7 @@
                 eq(userId),
                 eq(mReceiver),
                 eq(TEST_OP_PACKAGE_NAME),
-                eq(promptInfo),
-                eq(Binder.getCallingUid()),
-                eq(Binder.getCallingPid()),
-                eq(UserHandle.getCallingUserId()));
+                eq(promptInfo));
     }
 
     @Test
@@ -202,10 +198,7 @@
                 eq(userId),
                 eq(mReceiver),
                 eq(TEST_OP_PACKAGE_NAME),
-                eq(promptInfo),
-                eq(Binder.getCallingUid()),
-                eq(Binder.getCallingPid()),
-                eq(UserHandle.getCallingUserId()));
+                eq(promptInfo));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 6b000f3..8d890b9c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -19,6 +19,8 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
 
+import static com.android.server.biometrics.BiometricServiceStateProto.*;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -29,7 +31,6 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -108,10 +109,7 @@
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
                 0 /* operationId */,
-                0 /* userId */,
-                0 /* callingUid */,
-                0 /* callingPid */,
-                0 /* callingUserId */);
+                0 /* userId */);
 
         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
             assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
@@ -126,18 +124,12 @@
         final boolean requireConfirmation = true;
         final long operationId = 123;
         final int userId = 10;
-        final int callingUid = 100;
-        final int callingPid = 1000;
-        final int callingUserId = 10000;
 
         final AuthSession session = createAuthSession(mSensors,
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
                 operationId,
-                userId,
-                callingUid,
-                callingPid,
-                callingUserId);
+                userId);
         assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
 
         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
@@ -156,10 +148,7 @@
                     eq(userId),
                     eq(mSensorReceiver),
                     eq(TEST_PACKAGE),
-                    eq(sensor.getCookie()),
-                    eq(callingUid),
-                    eq(callingPid),
-                    eq(callingUserId));
+                    eq(sensor.getCookie()));
         }
 
         final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
@@ -200,10 +189,7 @@
                 false /* checkDevicePolicyManager */,
                 Authenticators.BIOMETRIC_STRONG,
                 operationId,
-                userId,
-                callingUid,
-                callingPid,
-                callingUserId);
+                userId);
         assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
 
         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
@@ -225,13 +211,13 @@
         assertTrue(session.allCookiesReceived());
 
         // UDFPS does not start even if all cookies are received
-        assertEquals(AuthSession.STATE_AUTH_STARTED, session.getState());
+        assertEquals(STATE_AUTH_STARTED, session.getState());
         verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
                 anyBoolean(), anyBoolean(), anyInt(), any(), anyLong());
 
         // Notify AuthSession that the UI is shown. Then, UDFPS sensor should be started.
         session.onDialogAnimatedIn();
-        assertEquals(AuthSession.STATE_AUTH_STARTED_UI_SHOWING, session.getState());
+        assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
         assertEquals(BiometricSensor.STATE_AUTHENTICATING,
                 session.mPreAuthInfo.eligibleSensors.get(0).getSensorState());
 
@@ -251,9 +237,7 @@
 
     private AuthSession createAuthSession(List<BiometricSensor> sensors,
             boolean checkDevicePolicyManager, @Authenticators.Types int authenticators,
-            long operationId, int userId,
-            int callingUid, int callingPid, int callingUserId)
-            throws RemoteException {
+            long operationId, int userId) throws RemoteException {
 
         final PromptInfo promptInfo = createPromptInfo(authenticators);
 
@@ -261,8 +245,8 @@
                 checkDevicePolicyManager);
         return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore,
                 mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId,
-                mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, callingUid,
-                callingPid, callingUserId, false /* debugEnabled */, mFingerprintSensorProps);
+                mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
+                false /* debugEnabled */, mFingerprintSensorProps);
     }
 
     private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) {
@@ -299,7 +283,7 @@
     }
 
     private void setupFace(int id, boolean confirmationAlwaysRequired) throws RemoteException {
-        IBiometricAuthenticator  faceAuthenticator = mock(IBiometricAuthenticator.class);
+        IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
         when(faceAuthenticator.isHardwareDetected(any())).thenReturn(true);
         when(faceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
         mSensors.add(new BiometricSensor(id,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 435c700..0c95e05 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -18,6 +18,8 @@
 
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 
+import static com.android.server.biometrics.BiometricServiceStateProto.*;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -174,8 +176,7 @@
                 0 /* vendorCode */);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_AUTH_PAUSED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState());
 
         mBiometricService.mCurrentAuthSession.binderDied();
         waitForIdle();
@@ -195,22 +196,18 @@
         verify(mReceiver1.asBinder()).linkToDeath(eq(mBiometricService.mCurrentAuthSession),
                 anyInt());
 
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
         mBiometricService.mCurrentAuthSession.binderDied();
         waitForIdle();
 
         assertNotNull(mBiometricService.mCurrentAuthSession);
         verify(mBiometricService.mStatusBarService, never()).hideAuthenticationDialog();
-        assertEquals(AuthSession.STATE_CLIENT_DIED_CANCELLING,
+        assertEquals(STATE_CLIENT_DIED_CANCELLING,
                 mBiometricService.mCurrentAuthSession.getState());
 
         verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl)
                 .cancelAuthenticationFromService(any(),
-                        any(),
-                        anyInt(),
-                        anyInt(),
-                        anyInt());
+                        any());
 
         // Simulate ERROR_CANCELED received from HAL
         mBiometricService.mBiometricSensorReceiver.onError(
@@ -256,7 +253,7 @@
         waitForIdle();
 
         assertNotNull(mBiometricService.mCurrentAuthSession);
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         // StatusBar showBiometricDialog invoked
         verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
@@ -406,7 +403,7 @@
                 HAT);
         waitForIdle();
         // Confirmation is required
-        assertEquals(AuthSession.STATE_AUTH_PENDING_CONFIRM,
+        assertEquals(STATE_AUTH_PENDING_CONFIRM,
                 mBiometricService.mCurrentAuthSession.getState());
 
         // Enrolled, not disabled in settings, user doesn't require confirmation in settings
@@ -422,7 +419,7 @@
                 HAT);
         waitForIdle();
         // Confirmation not required, waiting for dialog to dismiss
-        assertEquals(AuthSession.STATE_AUTHENTICATED_PENDING_SYSUI,
+        assertEquals(STATE_AUTHENTICATED_PENDING_SYSUI,
                 mBiometricService.mCurrentAuthSession.getState());
 
     }
@@ -447,8 +444,7 @@
         waitForIdle();
 
         // Creates a pending auth session with the correct initial states
-        assertEquals(AuthSession.STATE_AUTH_CALLED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState());
 
         // Invokes <Modality>Service#prepareForAuthentication
         ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -460,16 +456,12 @@
                 anyInt() /* userId */,
                 any(IBiometricSensorReceiver.class),
                 anyString() /* opPackageName */,
-                cookieCaptor.capture() /* cookie */,
-                anyInt() /* callingUid */,
-                anyInt() /* callingPid */,
-                anyInt() /* callingUserId */);
+                cookieCaptor.capture() /* cookie */);
 
         // onReadyForAuthentication, mCurrentAuthSession state OK
         mBiometricService.mImpl.onReadyForAuthentication(cookieCaptor.getValue());
         waitForIdle();
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
 
         // startPreparedClient invoked
         verify(mBiometricService.mSensors.get(0).impl)
@@ -493,7 +485,7 @@
                 HAT);
         waitForIdle();
         // Waiting for SystemUI to send dismissed callback
-        assertEquals(AuthSession.STATE_AUTHENTICATED_PENDING_SYSUI,
+        assertEquals(STATE_AUTHENTICATED_PENDING_SYSUI,
                 mBiometricService.mCurrentAuthSession.getState());
         // Notify SystemUI hardware authenticated
         verify(mBiometricService.mStatusBarService).onBiometricAuthenticated();
@@ -526,7 +518,7 @@
                 Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         assertEquals(Authenticators.DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators());
@@ -566,8 +558,7 @@
                 HAT);
         waitForIdle();
         // Waiting for SystemUI to send confirmation callback
-        assertEquals(AuthSession.STATE_AUTH_PENDING_CONFIRM,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_PENDING_CONFIRM, mBiometricService.mCurrentAuthSession.getState());
         verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
 
         // SystemUI sends confirm, HAT is sent to keystore and client is notified.
@@ -615,8 +606,7 @@
                 eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED),
                 eq(0 /* vendorCode */));
         verify(mReceiver1).onAuthenticationFailed();
-        assertEquals(AuthSession.STATE_AUTH_PAUSED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     @Test
@@ -634,8 +624,7 @@
                 eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED),
                 eq(0 /* vendorCode */));
         verify(mReceiver1).onAuthenticationFailed();
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     @Test
@@ -670,8 +659,7 @@
                 0 /* vendorCode */);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_AUTH_PAUSED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState());
         verify(mBiometricService.mStatusBarService).onBiometricError(
                 eq(BiometricAuthenticator.TYPE_FACE),
                 eq(BiometricConstants.BIOMETRIC_ERROR_TIMEOUT),
@@ -680,8 +668,7 @@
         verify(mReceiver1, never()).onAuthenticationFailed();
 
         // No auth session. Pressing try again will create one.
-        assertEquals(AuthSession.STATE_AUTH_PAUSED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_PAUSED, mBiometricService.mCurrentAuthSession.getState());
 
         // Pressing "Try again" on SystemUI
         mBiometricService.mSysuiReceiver.onTryAgainPressed();
@@ -689,8 +676,7 @@
         verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
 
         // AuthSession is now resuming
-        assertEquals(AuthSession.STATE_AUTH_PAUSED_RESUMING,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_PAUSED_RESUMING, mBiometricService.mCurrentAuthSession.getState());
 
         // Test resuming when hardware becomes ready. SystemUI should not be requested to
         // show another dialog since it's already showing.
@@ -755,8 +741,7 @@
         waitForIdle();
 
         // Sends error to SystemUI and does not notify client yet
-        assertEquals(AuthSession.STATE_ERROR_PENDING_SYSUI,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_ERROR_PENDING_SYSUI, mBiometricService.mCurrentAuthSession.getState());
         verify(mBiometricService.mStatusBarService).onBiometricError(
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
                 eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS),
@@ -783,8 +768,7 @@
                 Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_AUTH_CALLED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState());
         mBiometricService.mBiometricSensorReceiver.onError(
                 SENSOR_ID_FINGERPRINT,
                 getCookieForPendingSession(mBiometricService.mCurrentAuthSession),
@@ -794,7 +778,7 @@
 
         // We should be showing device credential now
         assertNotNull(mBiometricService.mCurrentAuthSession);
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         assertEquals(Authenticators.DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators());
@@ -873,7 +857,7 @@
 
         verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
         assertNotNull(mBiometricService.mCurrentAuthSession);
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         assertEquals(Authenticators.DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.mPromptInfo.getAuthenticators());
@@ -950,7 +934,7 @@
         mBiometricService.mSysuiReceiver.onDeviceCredentialPressed();
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
 
@@ -961,7 +945,7 @@
                 0 /* vendorCode */);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
     }
@@ -973,8 +957,7 @@
                 false /* requireConfirmation */,
                 Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
 
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
 
         mBiometricService.mBiometricSensorReceiver.onError(
                 SENSOR_ID_FINGERPRINT,
@@ -983,7 +966,7 @@
                 0 /* vendorCode */);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         verify(mBiometricService.mStatusBarService).onBiometricError(
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -997,8 +980,7 @@
         invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                 false /* requireConfirmation */, null /* authenticators */);
 
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
 
         mBiometricService.mBiometricSensorReceiver.onError(
                 SENSOR_ID_FINGERPRINT,
@@ -1007,7 +989,7 @@
                 0 /* vendorCode */);
         waitForIdle();
 
-        assertEquals(AuthSession.STATE_ERROR_PENDING_SYSUI,
+        assertEquals(STATE_ERROR_PENDING_SYSUI,
                 mBiometricService.mCurrentAuthSession.getState());
         verify(mBiometricService.mStatusBarService).onBiometricError(
                 eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -1031,10 +1013,7 @@
                 eq(0 /* vendorCode */));
         verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService(
                 any(),
-                any(),
-                anyInt(),
-                anyInt(),
-                anyInt());
+                any());
         assertNull(mBiometricService.mCurrentAuthSession);
     }
 
@@ -1056,10 +1035,7 @@
         verify(mBiometricService.mSensors.get(0).impl,
                 never()).cancelAuthenticationFromService(
                 any(),
-                any(),
-                anyInt(),
-                anyInt(),
-                anyInt());
+                any());
     }
 
     @Test
@@ -1081,10 +1057,7 @@
         verify(mBiometricService.mSensors.get(0).impl,
                 never()).cancelAuthenticationFromService(
                 any(),
-                any(),
-                anyInt(),
-                anyInt(),
-                anyInt());
+                any());
     }
 
     @Test
@@ -1104,10 +1077,7 @@
         verify(mBiometricService.mSensors.get(0).impl,
                 never()).cancelAuthenticationFromService(
                 any(),
-                any(),
-                anyInt(),
-                anyInt(),
-                anyInt());
+                any());
         verify(mReceiver1).onError(
                 eq(BiometricAuthenticator.TYPE_FACE),
                 eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
@@ -1134,8 +1104,7 @@
         // string is retrieved for now, but it's also very unlikely to break anyway.
         verify(mBiometricService.mStatusBarService)
                 .onBiometricHelp(anyString());
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     @Test
@@ -1145,7 +1114,7 @@
                 false /* requireConfirmation */, null /* authenticators */);
 
         mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken,
-                TEST_PACKAGE_NAME, 0 /* callingUId */, 0 /* callingPid */, 0 /* callingUserId */);
+                TEST_PACKAGE_NAME);
         waitForIdle();
 
         // Pretend that the HAL has responded to cancel with ERROR_CANCELED
@@ -1491,12 +1460,10 @@
         invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1,
                 Authenticators.BIOMETRIC_STRONG);
         waitForIdle();
-        assertEquals(AuthSession.STATE_AUTH_CALLED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState());
         startPendingAuthSession(mBiometricService);
         waitForIdle();
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     @Test
@@ -1508,8 +1475,7 @@
         invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                 false /* requireConfirmation */, Authenticators.BIOMETRIC_STRONG);
         waitForIdle();
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     @Test
@@ -1522,12 +1488,10 @@
         invokeAuthenticateForWorkApp(mBiometricService.mImpl, mReceiver1,
                 Authenticators.BIOMETRIC_STRONG);
         waitForIdle();
-        assertEquals(AuthSession.STATE_AUTH_CALLED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_CALLED, mBiometricService.mCurrentAuthSession.getState());
         startPendingAuthSession(mBiometricService);
         waitForIdle();
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     @Test
@@ -1549,7 +1513,7 @@
                 Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL);
         waitForIdle();
         assertNotNull(mBiometricService.mCurrentAuthSession);
-        assertEquals(AuthSession.STATE_SHOWING_DEVICE_CREDENTIAL,
+        assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
                 mBiometricService.mCurrentAuthSession.getState());
         verify(mReceiver2, never()).onError(anyInt(), anyInt(), anyInt());
     }
@@ -1647,8 +1611,7 @@
         waitForIdle();
 
         assertNotNull(mBiometricService.mCurrentAuthSession);
-        assertEquals(AuthSession.STATE_AUTH_STARTED,
-                mBiometricService.mCurrentAuthSession.getState());
+        assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
     }
 
     private static void startPendingAuthSession(BiometricService service) throws Exception {
@@ -1674,10 +1637,7 @@
                 receiver,
                 TEST_PACKAGE_NAME /* packageName */,
                 createTestPromptInfo(requireConfirmation, authenticators,
-                        false /* checkDevicePolicy */),
-                0 /* callingUid */,
-                0 /* callingPid */,
-                0 /* callingUserId */);
+                        false /* checkDevicePolicy */));
     }
 
     private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service,
@@ -1689,10 +1649,7 @@
                 receiver,
                 TEST_PACKAGE_NAME /* packageName */,
                 createTestPromptInfo(false /* requireConfirmation */, authenticators,
-                        true /* checkDevicePolicy */),
-                0 /* callingUid */,
-                0 /* callingPid */,
-                0 /* callingUserId */);
+                        true /* checkDevicePolicy */));
     }
 
     private static PromptInfo createTestPromptInfo(
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 981ed450..7661a32 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -5,8 +5,11 @@
 import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
 
 import android.telephony.AccessNetworkConstants.EutranBand;
+import android.telephony.AccessNetworkConstants.GeranBand;
+import android.telephony.AccessNetworkConstants.UtranBand;
 import android.telephony.ServiceState.DuplexMode;
 
+import java.util.Arrays;
 
 /**
  * Utilities to map between radio constants.
@@ -20,6 +23,9 @@
 
     public static final int INVALID_BAND = -1;
 
+    /** ISO country code of Japan. */
+    private static final String JAPAN_ISO_COUNTRY_CODE = "jp";
+
     /**
      * Gets the duplex mode for the given EUTRAN operating band.
      *
@@ -50,7 +56,7 @@
     /**
      * Gets the EUTRAN Operating band for a given downlink EARFCN.
      *
-     * <p>See 3GPP 36.101 sec 5.7.3-1 for calculation.
+     * <p>See 3GPP TS 36.101 clause 5.7.3-1 for calculation.
      *
      * @param earfcn The downlink EARFCN
      * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
@@ -198,4 +204,125 @@
 
         return INVALID_BAND;
     }
+
+    /**
+     * Gets the GERAN Operating band for a given ARFCN.
+     *
+     * <p>See 3GPP TS 45.005 clause 2 for calculation.
+     *
+     * @param arfcn The ARFCN
+     * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
+     */
+    public static int getOperatingBandForArfcn(int arfcn) {
+        if (arfcn >= 0 && arfcn <= 124) {
+            return GeranBand.BAND_E900;
+        } else if (arfcn >= 128 && arfcn <= 251) {
+            return GeranBand.BAND_850;
+        } else if (arfcn >= 259 && arfcn <= 293) {
+            return GeranBand.BAND_450;
+        } else if (arfcn >= 306 && arfcn <= 340) {
+            return GeranBand.BAND_480;
+        } else if (arfcn >= 438 && arfcn <= 511) {
+            return GeranBand.BAND_750;
+        } else if (arfcn >= 512 && arfcn <= 885) {
+            // ARFCN between 512 and 810 are also part of BAND_PCS1900.
+            // Returning BAND_DCS1800 in both cases.
+            return GeranBand.BAND_DCS1800;
+        } else if (arfcn >= 940 && arfcn <= 974) {
+            return GeranBand.BAND_ER900;
+        } else if (arfcn >= 975 && arfcn <= 1023) {
+            return GeranBand.BAND_E900;
+        }
+        return INVALID_BAND;
+    }
+
+    /**
+     * Gets the UTRAN Operating band for a given downlink UARFCN.
+     *
+     * <p>See 3GPP TS 25.101 clause 5.4.4 for calculation.
+     *
+     * @param uarfcn The downlink UARFCN
+     * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
+     */
+    public static int getOperatingBandForUarfcn(int uarfcn) {
+        // List of additional bands defined in TS 25.101.
+        int[] addlBand2 = {412, 437, 462, 487, 512, 537, 562, 587, 612, 637, 662, 687};
+        int[] addlBand4 = {1887, 1912, 1937, 1962, 1987, 2012, 2037, 2062, 2087};
+        int[] addlBand5 = {1007, 1012, 1032, 1037, 1062, 1087};
+        int[] addlBand6 = {1037, 1062};
+        int[] addlBand7 =
+                {2587, 2612, 2637, 2662, 2687, 2712, 2737, 2762, 2787, 2812, 2837, 2862,
+                2887, 2912};
+        int[] addlBand10 =
+                {3412, 3437, 3462, 3487, 3512, 3537, 3562, 3587, 3612, 3637, 3662, 3687};
+        int[] addlBand12 = {3932, 3957, 3962, 3987, 3992};
+        int[] addlBand13 = {4067, 4092};
+        int[] addlBand14 = {4167, 4192};
+        int[] addlBand19 = {787, 812, 837};
+        int[] addlBand25 =
+                {6292, 6317, 6342, 6367, 6392, 6417, 6442, 6467, 6492, 6517, 6542, 6567, 6592};
+        int[] addlBand26 = {5937, 5962, 5987, 5992, 6012, 6017, 6037, 6042, 6062, 6067, 6087};
+
+        if (uarfcn >= 10562 && uarfcn <= 10838) {
+            return UtranBand.BAND_1;
+        } else if ((uarfcn >= 9662 && uarfcn <= 9938)
+                || Arrays.binarySearch(addlBand2, uarfcn) >= 0) {
+            return UtranBand.BAND_2;
+        } else if (uarfcn >= 1162 && uarfcn <= 1513) {
+            return UtranBand.BAND_3;
+        } else if ((uarfcn >= 1537 && uarfcn <= 1738)
+                || Arrays.binarySearch(addlBand4, uarfcn) >= 0) {
+            return UtranBand.BAND_4;
+        } else if (uarfcn >= 4387 && uarfcn <= 4413) {
+            // Band 6 is a subset of band 5. Only Japan uses band 6 and Japan does not have band 5.
+            String country = TelephonyManager.getDefault().getNetworkCountryIso();
+            if (JAPAN_ISO_COUNTRY_CODE.compareToIgnoreCase(country) == 0) {
+                return UtranBand.BAND_6;
+            } else {
+                return UtranBand.BAND_5;
+            }
+        } else if ((uarfcn >= 4357 && uarfcn <= 4458)
+                || Arrays.binarySearch(addlBand5, uarfcn) >= 0) {
+            return UtranBand.BAND_5;
+        } else if (Arrays.binarySearch(addlBand6, uarfcn) >= 0) {
+            return UtranBand.BAND_6;
+        } else if ((uarfcn >= 2237 && uarfcn <= 2563)
+                || Arrays.binarySearch(addlBand7, uarfcn) >= 0) {
+            return UtranBand.BAND_7;
+        } else if (uarfcn >= 2937 && uarfcn <= 3088) {
+            return UtranBand.BAND_8;
+        } else if (uarfcn >= 9237 && uarfcn <= 9387) {
+            return UtranBand.BAND_9;
+        } else if ((uarfcn >= 3112 && uarfcn <= 3388)
+                || Arrays.binarySearch(addlBand10, uarfcn) >= 0) {
+            return UtranBand.BAND_10;
+        } else if (uarfcn >= 3712 && uarfcn <= 3787) {
+            return UtranBand.BAND_11;
+        } else if ((uarfcn >= 3842 && uarfcn <= 3903)
+                || Arrays.binarySearch(addlBand12, uarfcn) >= 0) {
+            return UtranBand.BAND_12;
+        } else if ((uarfcn >= 4017 && uarfcn <= 4043)
+                || Arrays.binarySearch(addlBand13, uarfcn) >= 0) {
+            return UtranBand.BAND_13;
+        } else if ((uarfcn >= 4117 && uarfcn <= 4143)
+                || Arrays.binarySearch(addlBand14, uarfcn) >= 0) {
+            return UtranBand.BAND_14;
+        } else if ((uarfcn >= 712 && uarfcn <= 763)
+                || Arrays.binarySearch(addlBand19, uarfcn) >= 0) {
+            return UtranBand.BAND_19;
+        } else if (uarfcn >= 4512 && uarfcn <= 4638) {
+            return UtranBand.BAND_20;
+        } else if (uarfcn >= 862 && uarfcn <= 912) {
+            return UtranBand.BAND_21;
+        } else if (uarfcn >= 4662 && uarfcn <= 5038) {
+            return UtranBand.BAND_22;
+        } else if ((uarfcn >= 5112 && uarfcn <= 5413)
+                || Arrays.binarySearch(addlBand25, uarfcn) >= 0) {
+            return UtranBand.BAND_25;
+        } else if ((uarfcn >= 5762 && uarfcn <= 5913)
+                || Arrays.binarySearch(addlBand26, uarfcn) >= 0) {
+            return UtranBand.BAND_26;
+        }
+        return INVALID_BAND;
+    }
 }
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index e5411de..2a601e5 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -127,6 +127,19 @@
         InstallUtils.getPackageInstaller().abandonSession(id4);
     }
 
+    @Test
+    public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
+        InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
+                Install.single(TestApp.AIncompleteSplit).setStaged());
+    }
+
+    @Test
+    public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage()
+            throws Exception {
+        InstallUtils.commitExpectingFailure(AssertionError.class, "INSTALL_FAILED_INVALID_APK",
+                Install.multi(TestApp.AIncompleteSplit, TestApp.B1, TestApp.Apex1).setStaged());
+    }
+
     private static void assertSessionReady(int sessionId) {
         assertSessionState(sessionId,
                 (session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 702f871..27ccbc78 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -30,6 +30,7 @@
 import com.android.ddmlib.Log;
 import com.android.tests.rollback.host.AbandonSessionsRule;
 import com.android.tests.util.ModuleTestUtils;
+import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 import com.android.tradefed.util.CommandResult;
@@ -250,9 +251,40 @@
         assertThat(after).isEqualTo(before);
     }
 
-    private List<String> getStagingDirectories() {
+    @Test
+    public void testStagedInstallationShouldCleanUpOnValidationFailure() throws Exception {
+        List<String> before = getStagingDirectories();
+        runPhase("testStagedInstallationShouldCleanUpOnValidationFailure");
+        List<String> after = getStagingDirectories();
+        assertThat(after).isEqualTo(before);
+    }
+
+    @Test
+    public void testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage()
+            throws Exception {
+        List<String> before = getStagingDirectories();
+        runPhase("testStagedInstallationShouldCleanUpOnValidationFailureMultiPackage");
+        List<String> after = getStagingDirectories();
+        assertThat(after).isEqualTo(before);
+    }
+
+    @Test
+    public void testOrphanedStagingDirectoryGetsCleanedUpOnReboot() throws Exception {
+        //create random directories in /data/app-staging folder
+        getDevice().enableAdbRoot();
+        getDevice().executeShellCommand("mkdir /data/app-staging/session_123");
+        getDevice().executeShellCommand("mkdir /data/app-staging/random_name");
+        getDevice().disableAdbRoot();
+
+        assertThat(getStagingDirectories()).isNotEmpty();
+        getDevice().reboot();
+        assertThat(getStagingDirectories()).isEmpty();
+    }
+
+    private List<String> getStagingDirectories() throws DeviceNotAvailableException {
         String baseDir = "/data/app-staging";
         try {
+            getDevice().enableAdbRoot();
             return getDevice().getFileEntry(baseDir).getChildren(false)
                     .stream().filter(entry -> entry.getName().matches("session_\\d+"))
                     .map(entry -> entry.getName())
@@ -260,6 +292,8 @@
         } catch (Exception e) {
             // Return an empty list if any error
             return Collections.EMPTY_LIST;
+        } finally {
+            getDevice().disableAdbRoot();
         }
     }