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

Commit 58d536c5 authored by Hao Dong's avatar Hao Dong
Browse files

Fix settings activity showing background bp when

createConfirmDeviceCredentialIntent() API is used.

If the app uses createConfirmDeviceCredentialIntent(),
ConfirmDeviceCredentialActivity is the top activity which has "settings"
as package name. Then if the app switches to settings, since previous
foreground check only checks package name, biometric prompt isn't
cancelled. This CL adds a class name check for this case.

Flag: EXEMPT bugfix
Bug: 339532378
Test: manual test with sample app
Change-Id: I722e285cd15869799b9fadd2324014cf3c6d44ad
parent 1fee29d6
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -638,17 +638,17 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
         * Set caller's component name for getting logo icon/description. This should only be used
         * by ConfirmDeviceCredentialActivity, see b/337082634 for more context.
         *
         * @param componentNameForConfirmDeviceCredentialActivity set the component name for
         * @param realCaller set the component name of real caller for
         *                   ConfirmDeviceCredentialActivity.
         * @return This builder.
         * @hide
         */
        @NonNull
        @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL})
        public Builder setComponentNameForConfirmDeviceCredentialActivity(
                ComponentName componentNameForConfirmDeviceCredentialActivity) {
            mPromptInfo.setComponentNameForConfirmDeviceCredentialActivity(
                    componentNameForConfirmDeviceCredentialActivity);
        public Builder setRealCallerForConfirmDeviceCredentialActivity(ComponentName realCaller) {
            mPromptInfo.setRealCallerForConfirmDeviceCredentialActivity(realCaller);
            mPromptInfo.setClassNameIfItIsConfirmDeviceCredentialActivity(
                    mContext.getClass().getName());
            return this;
        }

+26 −10
Original line number Diff line number Diff line
@@ -57,7 +57,8 @@ public class PromptInfo implements Parcelable {
    private boolean mIsForLegacyFingerprintManager = false;
    private boolean mShowEmergencyCallButton = false;
    private boolean mUseParentProfileForDeviceCredential = false;
    private ComponentName mComponentNameForConfirmDeviceCredentialActivity = null;
    private ComponentName mRealCallerForConfirmDeviceCredentialActivity = null;
    private String mClassNameIfItIsConfirmDeviceCredentialActivity = null;

    public PromptInfo() {

@@ -89,8 +90,9 @@ public class PromptInfo implements Parcelable {
        mIsForLegacyFingerprintManager = in.readBoolean();
        mShowEmergencyCallButton = in.readBoolean();
        mUseParentProfileForDeviceCredential = in.readBoolean();
        mComponentNameForConfirmDeviceCredentialActivity = in.readParcelable(
        mRealCallerForConfirmDeviceCredentialActivity = in.readParcelable(
                ComponentName.class.getClassLoader(), ComponentName.class);
        mClassNameIfItIsConfirmDeviceCredentialActivity = in.readString();
    }

    public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -136,7 +138,8 @@ public class PromptInfo implements Parcelable {
        dest.writeBoolean(mIsForLegacyFingerprintManager);
        dest.writeBoolean(mShowEmergencyCallButton);
        dest.writeBoolean(mUseParentProfileForDeviceCredential);
        dest.writeParcelable(mComponentNameForConfirmDeviceCredentialActivity, 0);
        dest.writeParcelable(mRealCallerForConfirmDeviceCredentialActivity, 0);
        dest.writeString(mClassNameIfItIsConfirmDeviceCredentialActivity);
    }

    // LINT.IfChange
@@ -155,7 +158,7 @@ public class PromptInfo implements Parcelable {
            return true;
        } else if (mShowEmergencyCallButton) {
            return true;
        } else if (mComponentNameForConfirmDeviceCredentialActivity != null) {
        } else if (mRealCallerForConfirmDeviceCredentialActivity != null) {
            return true;
        }
        return false;
@@ -321,10 +324,8 @@ public class PromptInfo implements Parcelable {
        mShowEmergencyCallButton = showEmergencyCallButton;
    }

    public void setComponentNameForConfirmDeviceCredentialActivity(
            ComponentName componentNameForConfirmDeviceCredentialActivity) {
        mComponentNameForConfirmDeviceCredentialActivity =
                componentNameForConfirmDeviceCredentialActivity;
    public void setRealCallerForConfirmDeviceCredentialActivity(ComponentName realCaller) {
        mRealCallerForConfirmDeviceCredentialActivity = realCaller;
    }

    public void setUseParentProfileForDeviceCredential(
@@ -332,6 +333,14 @@ public class PromptInfo implements Parcelable {
        mUseParentProfileForDeviceCredential = useParentProfileForDeviceCredential;
    }

    /**
     * Set the class name of ConfirmDeviceCredentialActivity.
     */
    void setClassNameIfItIsConfirmDeviceCredentialActivity(String className) {
        mClassNameIfItIsConfirmDeviceCredentialActivity = className;
    }


    // Getters

    /**
@@ -455,8 +464,15 @@ public class PromptInfo implements Parcelable {
        return mShowEmergencyCallButton;
    }

    public ComponentName getComponentNameForConfirmDeviceCredentialActivity() {
        return mComponentNameForConfirmDeviceCredentialActivity;
    public ComponentName getRealCallerForConfirmDeviceCredentialActivity() {
        return mRealCallerForConfirmDeviceCredentialActivity;
    }

    /**
     * Get the class name of ConfirmDeviceCredentialActivity. Returns null if the direct caller is
     * not ConfirmDeviceCredentialActivity.
     */
    public String getClassNameIfItIsConfirmDeviceCredentialActivity() {
       return mClassNameIfItIsConfirmDeviceCredentialActivity;
    }
}
+39 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics

import android.Manifest
import android.app.ActivityTaskManager
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
@@ -35,6 +36,7 @@ import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.SensorPropertiesInternal
import android.os.UserManager
import android.util.DisplayMetrics
import android.util.Log
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManager
@@ -45,6 +47,8 @@ import com.android.internal.widget.LockPatternUtils
import com.android.systemui.biometrics.shared.model.PromptKind

object Utils {
    private const val TAG = "SysUIBiometricUtils"

    /** Base set of layout flags for fingerprint overlay widgets. */
    const val FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
        (WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
@@ -148,4 +152,39 @@ object Utils {
        draw(canvas)
        return bitmap
    }

    // LINT.IfChange
    @JvmStatic
    /**
     * Checks if a client package is running in the background or it's a system app.
     *
     * @param clientPackage The name of the package to be checked.
     * @param clientClassNameIfItIsConfirmDeviceCredentialActivity The class name of
     *   ConfirmDeviceCredentialActivity.
     * @return Whether the client package is running in background
     */
    fun ActivityTaskManager.isSystemAppOrInBackground(
        context: Context,
        clientPackage: String,
        clientClassNameIfItIsConfirmDeviceCredentialActivity: String?
    ): Boolean {
        Log.v(TAG, "Checking if the authenticating is in background, clientPackage:$clientPackage")
        val tasks = getTasks(Int.MAX_VALUE)
        if (tasks == null || tasks.isEmpty()) {
            Log.w(TAG, "No running tasks reported")
            return false
        }

        val topActivity = tasks[0].topActivity
        val isSystemApp = isSystem(context, clientPackage)
        val topPackageEqualsToClient = topActivity!!.packageName == clientPackage
        val isClientConfirmDeviceCredentialActivity =
            clientClassNameIfItIsConfirmDeviceCredentialActivity != null
        // b/339532378: If it's ConfirmDeviceCredentialActivity, we need to check further on
        // class name.
        return !(isSystemApp || topPackageEqualsToClient) ||
            (isClientConfirmDeviceCredentialActivity &&
                topActivity.className != clientClassNameIfItIsConfirmDeviceCredentialActivity)
    }
    // LINT.ThenChange(frameworks/base/services/core/java/com/android/server/biometrics/Utils.java)
}
+5 −0
Original line number Diff line number Diff line
@@ -833,6 +833,11 @@ public class AuthContainerView extends LinearLayout
        return mConfig.mOpPackageName;
    }

    @Override
    public String getClassNameIfItIsConfirmDeviceCredentialActivity() {
        return  mConfig.mPromptInfo.getClassNameIfItIsConfirmDeviceCredentialActivity();
    }

    @Override
    public long getRequestId() {
        return mConfig.mRequestId;
+13 −15
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
@@ -187,7 +186,7 @@ public class AuthController implements
    final TaskStackListener mTaskStackListener = new TaskStackListener() {
        @Override
        public void onTaskStackChanged() {
            if (!isOwnerInForeground()) {
            if (isOwnerInBackground()) {
                mHandler.post(AuthController.this::cancelIfOwnerIsNotInForeground);
            }
        }
@@ -227,21 +226,20 @@ public class AuthController implements
        }
    }

    private boolean isOwnerInForeground() {
    private boolean isOwnerInBackground() {
        if (mCurrentDialog != null) {
            final String clientPackage = mCurrentDialog.getOpPackageName();
            final List<ActivityManager.RunningTaskInfo> runningTasks =
                    mActivityTaskManager.getTasks(1);
            if (!runningTasks.isEmpty()) {
                final String topPackage = runningTasks.get(0).topActivity.getPackageName();
                if (!topPackage.contentEquals(clientPackage)
                        && !Utils.isSystem(mContext, clientPackage)) {
                    Log.w(TAG, "Evicting client due to: " + topPackage);
                    return false;
                }
            final String clientClassNameIfItIsConfirmDeviceCredentialActivity =
                    mCurrentDialog.getClassNameIfItIsConfirmDeviceCredentialActivity();
            final boolean isInBackground = Utils.isSystemAppOrInBackground(mActivityTaskManager,
                    mContext, clientPackage,
                    clientClassNameIfItIsConfirmDeviceCredentialActivity);
            if (isInBackground) {
                Log.w(TAG, "Evicting client due to top activity is not : " + clientPackage);
            }
            return isInBackground;
        }
        return true;
        return false;
    }

    private void cancelIfOwnerIsNotInForeground() {
@@ -1259,9 +1257,9 @@ public class AuthController implements
        }
        mCurrentDialog = newDialog;

        // TODO(b/339532378): We should check whether |allowBackgroundAuthentication| should be
        // TODO(b/353597496): We should check whether |allowBackgroundAuthentication| should be
        //  removed.
        if (!promptInfo.isAllowBackgroundAuthentication() && !isOwnerInForeground()) {
        if (!promptInfo.isAllowBackgroundAuthentication() && isOwnerInBackground()) {
            cancelIfOwnerIsNotInForeground();
        } else {
            mCurrentDialog.show(mWindowManager);
Loading