Android支持Smart Lock 人脸解锁

平台

RK3288 + Android 7.1

需求

支持人脸解锁

方案说明

使用Smart Lock 中的 "可信面孔" 功能实现人脸解锁

实现步骤

  • 内置GMS(若PUSH进去, 请重置)
    GMS包内容如下:
drwxrwxrwx 2 root root 4096 2013-01-21 17:32 FaceLock
drwxrwxrwx 2 root root 4096 2013-01-21 17:32 GoogleBackupTransport
drwxrwxrwx 2 root root 4096 2013-01-21 17:32 GoogleContactsSyncAdapter
drwxrwxrwx 3 root root 4096 2013-01-21 17:32 GoogleGmsCore
drwxrwxrwx 2 root root 4096 2013-01-21 17:32 GoogleLoginService
drwxrwxrwx 2 root root 4096 2013-01-21 17:33 GooglePartnerSetup
drwxrwxrwx 3 root root 4096 2013-01-21 17:32 GooglePlay
drwxrwxrwx 2 root root 4096 2013-01-21 17:33 GoogleServicesFramework

  • 确认FaceLock是否已安装
rk3288:/system/priv-app # dumpsys package com.android.facelock                                                                 
Permissions:
  Permission [com.google.android.gms.auth.permission.FACE_UNLOCK] (e0424d2):
    sourcePackage=com.android.facelock
    uid=10024 gids=null type=0 prot=signature
    perm=Permission{767d9a3 com.google.android.gms.auth.permission.FACE_UNLOCK}
    packageSetting=PackageSetting{29984a0 com.android.facelock/10024}

Key Set Manager:
  [com.android.facelock]
      Signing KeySets: 6

Packages:
  Package [com.android.facelock] (29984a0):
    userId=10024
    pkg=Package{5866859 com.android.facelock}
    codePath=/system/priv-app/FaceLock
    resourcePath=/system/priv-app/FaceLock
    legacyNativeLibraryDir=/system/priv-app/FaceLock/lib
    primaryCpuAbi=null
    secondaryCpuAbi=null
    versionCode=25 minSdk=15 targetSdk=25
    versionName=7.1.2
    splits=[base]
    apkSigningVersion=2
    applicationInfo=ApplicationInfo{bdbbc1e com.android.facelock}
    flags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ]
    privateFlags=[ PRIVILEGED RESIZEABLE_ACTIVITIES ]
    dataDir=/data/user/0/com.android.facelock
    supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity]
    timeStamp=2019-10-15 10:09:32
    firstInstallTime=2019-10-15 10:09:32
    lastUpdateTime=2019-10-15 10:09:32
    signatures=PackageSignatures{d146cff [e3ca78d8]}
    installPermissionsFixed=false installStatus=1
    pkgFlags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ]
    declared permissions:
      com.google.android.gms.auth.permission.FACE_UNLOCK: prot=signature, INSTALLED
    requested permissions:
      android.permission.CAMERA
      com.google.android.gms.auth.permission.FACE_UNLOCK
    install permissions:
      com.google.android.gms.auth.permission.FACE_UNLOCK: granted=true
    User 0: ceDataInode=513 installed=true hidden=false suspended=false stopped=false notLaunched=false enabled=0
      runtime permissions:


Dexopt state:
  [com.android.facelock]
    Instruction Set: arm
      path: /system/priv-app/FaceLock/FaceLock.apk
      status: /data/dalvik-cache/arm/system@priv-app@[email protected]@classes.dex [compilation_filter=interpret-onl
      y, status=kOatUpToDate]


Compiler stats:
  [com.android.facelock]
     FaceLock.apk - 252

  • 连接VPN
    内置的GMS包版本较旧, 需要联接GOOGLE更新和支持库等内容.
  • 设置锁屏方式
    设置>安全>屏幕锁定
    要使用smart lock, 需设置屏幕锁定方式为图案/PIN码/密码
  • 打开 可信面孔
    设置>安全>Smart Lock > 可信面孔, 按操作即可

杂项

一些问题
  1. 在GMS更新的过程中, Smart Lock中的选项可能出现的个数在0-3之间, 不稳定
  2. Smart Lock的人脸解锁并不会直接跳过锁屏, 在实际使用过程中, 用户使用电源唤醒设备, 设备开始识别人脸, 识别成功后, 屏幕下方会有解锁动画, 表示已成功解锁, 但 不会 直接进入系统, 需要用户执行上滑动画以完成解锁动作.
  3. 在Android Q(10)开始, GOOGLE出于安全原因, 删除了可信面孔
锁屏相关代码
锁屏程序接收面部识别广播
|--frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java

	//人脸解锁广播
    private static final String ACTION_FACE_UNLOCK_STARTED
            = "com.android.facelock.FACE_UNLOCK_STARTED";
    private static final String ACTION_FACE_UNLOCK_STOPPED
            = "com.android.facelock.FACE_UNLOCK_STOPPED";
    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
    
    

        @Override
        public void onReceive(Context context, Intent intent) {
    
    
            final String action = intent.getAction();
            if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {
    
    
                mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
            } else if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
    
    
                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,
                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));
            } else if (ACTION_FACE_UNLOCK_STARTED.equals(action)) {
    
    
                Trace.beginSection("KeyguardUpdateMonitor.mBroadcastAllReceiver#onReceive ACTION_FACE_UNLOCK_STARTED");
                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 1,
                        getSendingUserId()));
                Trace.endSection();
            } else if (ACTION_FACE_UNLOCK_STOPPED.equals(action)) {
    
    
                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 0,
                        getSendingUserId()));
            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                    .equals(action)) {
    
    
                mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
            } else if (ACTION_USER_UNLOCKED.equals(action)) {
    
    
                mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);
            }
        }
    };

//mHandler 消息处理
	                case MSG_FACE_UNLOCK_STATE_CHANGED:
                    Trace.beginSection("KeyguardUpdateMonitor#handler MSG_FACE_UNLOCK_STATE_CHANGED");
                    handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
                    Trace.endSection();
                    break;

    private void handleFaceUnlockStateChanged(boolean running, int userId) {
    
    
        mUserFaceUnlockRunning.put(userId, running);
        for (int i = 0; i < mCallbacks.size(); i++) {
    
    
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
    
    
                cb.onFaceUnlockStateChanged(running, userId);
            }
        }
    }

|--frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
//空函数
    /**
     * Called when the state of face unlock changed.
     */
    public void onFaceUnlockStateChanged(boolean running, int userId) {
    
     }

|--frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
    
    
		//...

        @Override
        public void onFaceUnlockStateChanged(boolean running, int userId) {
    
    
            update(false /* updateAlways */);
        }
	}
    private void update(boolean updateAlways) {
    
    
        Trace.beginSection("UnlockMethodCache#update");
        int user = KeyguardUpdateMonitor.getCurrentUser();
        boolean secure = mLockPatternUtils.isSecure(user);
        boolean canSkipBouncer = !secure ||  mKeyguardUpdateMonitor.getUserCanSkipBouncer(user);
        boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
        boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
        boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user)
                && trustManaged;
        boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer ||
                trustManaged != mTrustManaged  || faceUnlockRunning != mFaceUnlockRunning;
        if (changed || updateAlways) {
    
    
            mSecure = secure;
            mCanSkipBouncer = canSkipBouncer;
            mTrusted = trusted;
            mTrustManaged = trustManaged;
            mFaceUnlockRunning = faceUnlockRunning;
            notifyListeners();
        }
        Trace.endSection();
    }

	private void notifyListeners() {
    
    
        for (OnUnlockMethodChangedListener listener : mListeners) {
    
    
            listener.onUnlockMethodStateChanged();
        }
    }


|--frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    @Override  // UnlockMethodCache.OnUnlockMethodChangedListener
    public void onUnlockMethodStateChanged() {
    
    
        logStateToEventlog();
    }
    private void logStateToEventlog() {
    
    
        boolean isShowing = mStatusBarKeyguardViewManager.isShowing();
        boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
        boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
        boolean isSecure = mUnlockMethodCache.isMethodSecure();
        boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
        int stateFingerprint = getLoggingFingerprint(mState,
                isShowing,
                isOccluded,
                isBouncerShowing,
                isSecure,
                canSkipBouncer);
        if (stateFingerprint != mLastLoggedStateFingerprint) {
    
    
            EventLogTags.writeSysuiStatusBarState(mState,
                    isShowing ? 1 : 0,
                    isOccluded ? 1 : 0,
                    isBouncerShowing ? 1 : 0,
                    isSecure ? 1 : 0,
                    canSkipBouncer ? 1 : 0);
            mLastLoggedStateFingerprint = stateFingerprint;
        }
    }
|--frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
        UnlockMethodCache.OnUnlockMethodChangedListener,
        AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
    
    

    @Override
    public void onUnlockMethodStateChanged() {
    
    
        mLockIcon.update();
        updateCameraVisibility();
    }
}


|--frameworks/base/services/core/java/com/android/server/trust/TrustManagerService.java
     public void updateTrust(int userId, int flags) {
    
    
        boolean managed = aggregateIsTrustManaged(userId);
        dispatchOnTrustManagedChanged(managed, userId);
        if (mStrongAuthTracker.isTrustAllowedForUser(userId)
                && isTrustUsuallyManagedInternal(userId) != managed) {
    
    
            updateTrustUsuallyManaged(userId, managed);
        }
        boolean trusted = aggregateIsTrusted(userId);
        boolean changed;
        synchronized (mUserIsTrusted) {
    
    
            changed = mUserIsTrusted.get(userId) != trusted;
            mUserIsTrusted.put(userId, trusted);
        }
        dispatchOnTrustChanged(trusted, userId, flags);
        if (changed) {
    
    
            refreshDeviceLockedForUser(userId);
        }
    }
	private void dispatchOnTrustChanged(boolean enabled, int userId, int flags) {
    
    
        if (DEBUG) {
    
    
            Log.i(TAG, "onTrustChanged(" + enabled + ", " + userId + ", 0x"
                    + Integer.toHexString(flags) + ")");
        }
        if (!enabled) flags = 0;
        for (int i = 0; i < mTrustListeners.size(); i++) {
    
    
            try {
    
    
                mTrustListeners.get(i).onTrustChanged(enabled, userId, flags);
            } catch (DeadObjectException e) {
    
    
                Slog.d(TAG, "Removing dead TrustListener.");
                mTrustListeners.remove(i);
                i--;
            } catch (RemoteException e) {
    
    
                Slog.e(TAG, "Exception while notifying TrustListener.", e);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/ansondroider/article/details/102592602