首页 >> 大全

修改Android 12解锁失败等待时间规则详解

2023-11-04 大全 35 作者:考证青年

前言

解锁的类型有:Pin码解锁、密码解锁、图案解锁和指纹解锁

修改解锁失败的等待时间:做过相关模块都知道解锁这一块的验证密码等等操作一般是通过JNI通过做的验证操作,数据获取一般也是涉及到C的逻辑。由于考虑其实系统其他的界面功能上也会有解锁的这几种方式,例如:里面的设置解锁方式那里,因此修改锁屏上的解锁等待时间,要修改到共有接口,因此这个功能的添加,并不是这么简单的去修改的,但是在网上搜索相关修改等待时间的blog,资料比较少,因此在这把修改的步骤记录下来。

主要需求有以下3点:

1.每次都有5次解锁。

2.随着尝试次数的增加,时间增长。

3.关机重启后仍然能计算时间。(指纹解锁不需要)

1.定位修改的起始点

定位需要修改的地方,尝试使用 获取界面失败了,使用工具,获取如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--31)(///.png)]

就可以获取某个控件的id,然后锁定布局了,然后就可以找到相关的代码了。

2.分析整体的修改逻辑

以此类推,因此我们发现要修改的这几种解锁方式主要分为两大类,两大类为:1、PIN码、密码和图案 2、指纹解锁

分为两大类的主要原因是因为指纹解锁的主要逻辑并不在里面而是模块里面,因为在 7.0的代码上和是分开的, 12则合到了一起。

3.具体修改的实现

修改PIN码、密码和图案解锁

通过上面的工具定位代码得知,相关类如下:

如图,其实相关类为、和

这几个就是PIN码、密码和图案对应的自定义View,而其中的点击并操作的逻辑也是在这里面,感觉根据MVC的设计原则,感觉有点不符合这点啊哈哈哈。。。结果View和Model放到一起了。

其实为什么PIN码和密码放到一起呢?因为他们有个共同的父类iew.java,关于解锁逻辑的显示控制也在父类里,因此PIN码和密码解锁在这个父类里做操作就可以了。

com....java其中代码如下:

_android自定义等待框_android让主线程等待

new LockPatternChecker.OnCheckCallback() {@Overridepublic void onEarlyMatched() {mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL);onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,true /* isValidPassword */);password.zeroize();}@Overridepublic void onChecked(boolean matched, int timeoutMs) {mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);mView.setPasswordEntryInputEnabled(true);mPendingLockCheck = null;if (!matched) {onPasswordChecked(userId, false /* matched */, timeoutMs,true /* isValidPassword */);}password.zeroize();}@Overridepublic void onCancelled() {// We already got dismissed with the early matched callback, so we cancelled// the check. However, we still need to note down the latency.mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);password.zeroize();}
}

其实关于锁屏PIN码、密码和图案解锁都是依靠这个.方法去验证密码,然后利用.这个回调来返回验证结果,这个验证结果的回调也是通过JNI一系列步骤完成的。

先看其中的两个回调方法

1、 这个回调方法是当验证失败的时候才会回调,这里会返回,这里会返回false,这里就是时间间隔

2、 这个回调方法是当验证成功的时候才会回调。

发现问题:

其实刚开始做这个功能的时候并没有考虑做全局的,就想在这里做一个时间的拦截,然后自己把这个时间间隔改了,就能完成需求,其实后来测试并不行,所以这里就牵扯出了发现的几个问题。

经测试发现,如下问题:

1、系统默认返回都是30×1000

2、默认锁屏第三次尝试解锁时候,并不是5次。

3、就算你强制能让第三次尝试的还能输入密码尝试解锁,但是系统下边是锁定的,并不能进行正常的解锁尝试(即输入的正常密码,并不能解锁成功,返回仍然是失败)

因此,根据需求要做成全局的,就找到根源把这个返回时间修改成自己想要的这样,所有实现这个回调的应用都能获取到新制定规则的时间(这里是指(其实每个应用)那边其实也是实现这边的回调接口,然后系统返回这个时间都能接受到最新的时间规则)。

这样就一直追,追到了这个类.cpp。(其实做系统开发,修改或者添加功能,就是找到一个突破口,一直追追)其实真正的返回时间的是在这里写好的。如下:

///.cpp 的函数

原生代码:

/** Calculates the timeout in milliseconds as a function of the failure* counter 'x' as follows:** [0, 4] -> 0* 5 -> 30* [6, 10] -> 0* [11, 29] -> 30* [30, 139] -> 30 * (2^((x - 30)/10))* [140, inf) -> 1 day**/
uint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) {static const int failure_timeout_ms = 30000;if (record->failure_counter == 0) return 0;if (record->failure_counter > 0 && record->failure_counter <= 10) {if (record->failure_counter % 5 == 0) {return failure_timeout_ms;}  else {return 0;}} else if (record->failure_counter < 30) {return failure_timeout_ms;} else if (record->failure_counter < 140) {return failure_timeout_ms << ((record->failure_counter - 30) / 10);}return DAY_IN_MS;
}

根据上边可以看出,30000这个数字很敏感嘛,系统一直返回的就是这个,终于找到了,是一个固定值。其实细看这个方法可以看出来,它是通过记录失败的次数然后进行了判断,返回时间间隔。

总结上边代码:

1、当失败0次,返回0ms

2、当失败大于0,失败小于10次,就是当前两次时,每次失败5次后,返回,意思是这总前两次都可以尝试5次机会

3、当失败次数小于30次,就是当总次数是10次到30次时,返回,意思是第二次以后为每次就只有一次尝试机会解锁,就要等待时间。直到总次数为30次时。

4、当总次数大于30次到140次,就是需要左移运算出毫秒数。

这里有两种次数,一种是每次解锁都有5次尝试机会(但是只有前两次),后边每次都要等待时间,这里就是前边我们遇到的问题。

因此修改这个方法的规则,解决问题

修改后代码:

uint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) {static const int failure_timeout_ms = 60*1000;if (record->failure_counter == 0) return 0;if (record->failure_counter > 0) {if (record->failure_counter % 5 == 0) {if(record->failure_counter/5 == 1){return 2*failure_timeout_ms;}else if(record->failure_counter/5 == 2){return 5*failure_timeout_ms;}else if(record->failure_counter/5 == 3){return 15*failure_timeout_ms;}else if(record->failure_counter/5 == 4){return 30*failure_timeout_ms;}else if(record->failure_counter/5 == 5){return 60*failure_timeout_ms;}else if(record->failure_counter/5 >= 6){return 120*failure_timeout_ms;}}  else {return 0;}}return 2*failure_timeout_ms;
}

这样,我们就修改了它原生的规则。实现时间的动态改变,随着尝试次数的增加。

写到这已经满足了需求上的前两条需求了,现在就要满足实现第三条关机重启仍然能计算时间。

根据逻辑如下代码:

void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) {boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;if (matched) {getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);if (dismissKeyguard) {mDismissing = true;mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);getKeyguardSecurityCallback().dismiss(true, userId);}} else {if (isValidPassword) {getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);if (timeoutMs > 0) {long deadline = mLockPatternUtils.setLockoutAttemptDeadline(userId, timeoutMs);handleAttemptLockout(deadline);}}if (timeoutMs == 0) {mMessageAreaController.setMessage(mView.getWrongPasswordStringId());}mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);}
}

其实这里就是上边说的回调接口调用的方法,来处理验证密码失败或者成功的逻辑,其中上边逻辑处理成功就是为true的时候,失败为false的时候,因此看false这边通过这句代码

long deadline = mLockPatternUtils.setLockoutAttemptDeadline(userId, timeoutMs);

设置了时间,然后返回一个终止时间(就是计时结束的时间戳),然后去实现倒计时处理的。

来看一下,这个方法是怎么记录时间戳的?

//base/core/java/com////.java

/**
* Set and store the lockout deadline, meaning the user can't attempt their unlock
* pattern until the deadline has passed.
* @return the chosen deadline.
*/
@UnsupportedAppUsage
public long setLockoutAttemptDeadline(int userId, int timeoutMs) {final long deadline = SystemClock.elapsedRealtime() + timeoutMs;if (userId == USER_FRP) {// For secure password storage (that is required for FRP), the underlying storage also// enforces the deadline. Since we cannot store settings for the FRP user, don't.return deadline;}mLockoutDeadlines.put(userId, deadline);return deadline;
}

由代码得知,其实参数是时间间隔,然后通过**.()**这个方法获取开机时间加上时间间隔,然后得到计时结束的时间戳存储起来。

其实每次亮屏后会出现倒计时的界面是重新获取了计时结束的时间戳,如下代码:

@Override
public void onPause() {super.onPause();mResumed = false;if (mCountdownTimer != null) {mCountdownTimer.cancel();mCountdownTimer = null;}if (mPendingLockCheck != null) {mPendingLockCheck.cancel(false);mPendingLockCheck = null;}reset();
}@Override
public void reset() {// start freshmDismissing = false;mView.resetPasswordText(false /* animate */, false /* announce */);// if the user is currently locked out, enforce it.long deadline = mLockPatternUtils.getLockoutAttemptDeadline(KeyguardUpdateMonitor.getCurrentUser());/* UNISOC: Modify for bug1692403, 1760268 {@ */if (shouldLockout(deadline)) {handleAttemptLockout(deadline);} else if (KeyguardSecurityContainerController.mDeadLine == 0&& mView.getVisibility() == View.VISIBLE) {resetState();}
}

其中的**.dline(r.());**方法就是获取的计时结束时间戳,通过判断是否时间戳是否失效,设置界面倒计时是否显示,所以再看一下获取的计时结束时间戳的方法如下

/*** @return The elapsed time in millis in the future when the user is allowed to*   attempt to enter their lock pattern, or 0 if the user is welcome to*   enter a pattern.*/
public long getLockoutAttemptDeadline(int userId) {final long deadline = mLockoutDeadlines.get(userId, 0L);final long now = SystemClock.elapsedRealtime();if (deadline < now && deadline != 0) {// timeout expiredmLockoutDeadlines.put(userId, 0);return 0L;}if (deadline > (now + timeoutMs)) {// device was rebooted, set new deadlinedeadline = now + timeoutMs;setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);}return deadline;
}

通过获取存储的计时结束时间戳,然后对比现在的时间,因为**.()**获取的是开机到现在的时间,所以只要关机重启,就会走下边的判断会根据最新的时间加上时间间隔,存储起来作为开机后的计时结束时间戳。因此就看到开后会重新等待30秒的现象,因此我们在这里想要实现效果修改逻辑。

添加代码接口,一个set,一个get,如下代码:

/*** Set and store the lockout deadline by SystemCurrentTime, meaning the user can't attempt his/her unlock* pattern until the deadline has passed.* @return the chosen deadline.*/
public long setLockoutAttemptDeadlineBySystemCurrentTime(int userId, int timeoutMs) {final long deadline = System.currentTimeMillis() + timeoutMs;setLong(LOCKOUT_ATTEMPT_DEADLINE_CURRENTTIME, deadline, userId);setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);return deadline;
}/*** @return The SystemCurrentTime in millis in the future when the user is allowed to*   attempt to enter his/her lock pattern, or 0 if the user is welcome to*   enter a pattern.*/
public long getLockoutAttemptDeadlineBySystemCurrentTime(int userId) {long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE_CURRENTTIME, 0L, userId);final long now = System.currentTimeMillis();if (deadline < now && deadline != 0) {// timeout expiredsetLong(LOCKOUT_ATTEMPT_DEADLINE_CURRENTTIME, 0, userId);setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);return 0L;}return deadline;
}

这样把对应的方法set和get方法替换了(iew.java这是PIN码和密码解锁,.java这里是图案的),就可以了。这样就满足了PIN码、密码和图案解锁的需求。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了