Android6.0之后支持了指纹解锁,但是指纹本身的安全性是不如密码的,所以Android系统加入了StrongAuth机制,要求用户在某些情况下必须用密码解锁(例如手机重启后),之后才能用指纹解锁。
StrongAuth的相关定义
锁屏密码安全涉及到两个比较重要的类,LockPatternUtils和LockSettingsService,StrongAuth的相关常量定义和接口也被定义在这两个类里面,此外,还有一个专门的类LockSettingsStrongAuth.java用于处理一些核心事件
LockPatternUtils.java中定义了一个静态内部类StrongAuthTracker,里面定义了一些非常重要的常量
/**
* Strong authentication is not required.
*/
public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
/**
* Strong authentication is required because the user has not authenticated since boot.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
/**
* Strong authentication is required because a device admin has requested it.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
/**
* Some authentication is required because the user has temporarily disabled trust.
*/
public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
/**
* Strong authentication is required because the user has been locked out after too many
* attempts.
*/
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
/**
* Strong auth flags that do not prevent fingerprint from being accepted as auth.
*
* If any other flags are set, fingerprint is disabled.
*/
private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
| SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
根据这些常量的定义,不难看到以下的几种情况是无法使用指纹解锁的
- 系统重启 STRONG_AUTH_REQUIRED_AFTER_BOOT
- 设备管理器锁定 STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW
- 错误次数过多 STRONG_AUTH_REQUIRED_AFTER_LOCKOUT
除此之外,其他情况下都是可以使用指纹解锁的
同时我们也可以发现,这些常量是16进制的int类型,会和ALLOWING_FINGERPRINT 进行位运算来判断当前是否能使用指纹解锁,这一点从StrongAuthTracker的对外接口就可以看出
/**
* @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
* current strong authentication requirements.
*/
public boolean isFingerprintAllowedForUser(int userId) {
return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
}
锁屏继承了这个类并加以扩展,用来判断当前系统是否允许指纹解锁
public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
public StrongAuthTracker(Context context) {
super(context);
}
public boolean isUnlockingWithFingerprintAllowed() {
int userId = getCurrentUser();
return isFingerprintAllowedForUser(userId);
}
public boolean hasUserAuthenticatedSinceBoot() {
int userId = getCurrentUser();
return (getStrongAuthForUser(userId)
& STRONG_AUTH_REQUIRED_AFTER_BOOT) == 0;
}
@Override
public void onStrongAuthRequiredChanged(int userId) {
notifyStrongAuthStateChanged(userId);
}
}
StrongAuth的作用机制
前面说了LockSettingsStrongAuth.java是符合核心的处理逻辑,开机后会启动system server,LockSettingsService会实例化一个LockSettingsStrongAuth对象,调用其构造函数,根据系统设置的默认值来设置对应的flag
public LockSettingsStrongAuth(Context context) {
mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context);
}
public static @StrongAuthFlags int getDefaultFlags(Context context) {
boolean strongAuthRequired = context.getResources().getBoolean(
com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
}
完成初始化之后,锁屏也会建立起和LockSettingsService的联系,锁屏继承了静态类StrongAuthTracker,在这里面查询当前是否能够指纹解锁。
用户成功使用密码解锁之后会调用到LockSettingsStrongAuth的reportUnlock方法,这里面会重新设置flag
public void reportUnlock(int userId) {
requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
}
最后来到这个函数
private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
int oldValue = mStrongAuthForUser.get(userId, mDefaultStrongAuthFlags);
int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
? STRONG_AUTH_NOT_REQUIRED
: (oldValue | strongAuthReason);
if (oldValue != newValue) {
mStrongAuthForUser.put(userId, newValue);
notifyStrongAuthTrackers(newValue, userId);
}
}
当新旧的值不一样的时候就会通过notifyStrongAuthTrackers来通知各个继承了静态类StrongAuthTracker的类
/**
* Called when the strong authentication requirements for {@param userId} changed.
*/
public void onStrongAuthRequiredChanged(int userId) {
}
其他的情况也是一样的,最终都会调到handleRequireStrongAuthOneUser来改变当前的flag
8.0的新变化
前面说了三种无法使用指纹解锁的情况,但是系统还有一种情况也是不能使用指纹解锁的,即StrongAuthTimeOut,长时间没有使用密码解锁,但是这个功能被集成在锁屏的KeyguardUpdateMonitor里面,没有在LockSettingsService直接体现,默认时间是三天
public boolean isUnlockingWithFingerprintAllowed() {
return mStrongAuthTracker.isUnlockingWithFingerprintAllowed()
&& !hasFingerprintUnlockTimedOut(sCurrentUser);
}
/**
* Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
* i.e. the user has to use a strong authentication method like password, PIN or pattern.
*
* @hide
*/
public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h
8.0之后这部分代码转移到了StrongAuthTracker中,也是出于安全和封装性的考虑,具体代码就不贴了,有兴趣可以查看8.0的源码
网友评论