在系统服务里面添加方法解决锁屏失败信息不同步问题

问题:

在设置里面解锁多次失败后,系统提示30秒之后才能继续做解锁操作。如果此时到锁屏界面,锁屏界面能够做解锁操作。这是不合理的,应该在上次解锁失败30秒之后才能做解锁操作。

问题分析:

在Setting和SystemUI中,在解锁失败之后会把解锁失败的时间点保存在LockPatternUtils对象中,然后应用判断当前时间与这个之间差是否小于30秒,小于就冻结锁屏的view使之无法解锁,然后倒计时提示用户。但是该对象在SystemUI和Setting中没有任何关联,使得在Setting解锁失败,SystemUI是无法失败。
LockPatternUtils.java

    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;
    }

解决思路

如果要使得在Setting LockPatternUtils对象保存的信息要SystemUI一致,就需要让解锁失败的信息的传过来,由于这个是在不同的进程中,所以需要跨进程传递。

Android进程间通讯的方式:

  1. AIDL等Binder在内的方式,包括message
  2. Bundle/Intent,通过intent传过去
  3. socket
  4. ContentProvider
  5. 广播

广播有延迟,这里不能用,ContentProvider需要新建ContentProvider,很麻烦,socket也麻烦。使用binder是最好的方式,系统服务也是binder,于是使用LockSetting这个系统服务,LockSetting同一个管理解锁服务,那么增加一个管理解锁失败的最后时间也是没有不妥的。

具体实现

  1. 首先修改LockSetting;作为一个系统服务,他是通过binder方式与应用交互的,找到base/core/java/com/android/internal/widget/ILockSettings.aidl
    增加获取和设置解锁失败时间方法
    ILockSettings.aidl
@@ -71,19 +71,21 @@ interface ILockSettings {

     void closeSession(in String sessionId);
+    long setLockoutAttemptDeadline(int userId,int timeoutMs);
+    long getLockoutAttemptDeadline(int userId);
 }

  1. 在LockSettings实现其API
    LockSettingsService.java
     @Override
     public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
         checkPasswordReadPermission(userId);
-        return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
+        VerifyCredentialResponse retResponse = doVerifyCredential(credential, type, false, 0, userId, progressCallback);
+        if(retResponse.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+                 setLockoutAttemptDeadline(userId,retResponse.getTimeout());
+        }
+        return retResponse;
+    }
+
+    public long setLockoutAttemptDeadline(int userId,int timeoutMs) {
+        final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
+        //Special user id for triggering the FRP verification flow.
+        if (userId == android.os.UserHandle.USER_NULL + 1) {
+            // 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;
     }
 
+    public long getLockoutAttemptDeadline(int userId) {
+        final long deadline = mLockoutDeadlines.get(userId, 0L);
+        final long now = SystemClock.elapsedRealtime();
+        if (deadline < now && deadline != 0) {
+            // timeout expired
+            mLockoutDeadlines.put(userId, 0);
+            return 0L;
+        }
+        return deadline;
+    }
+
+

setLockoutAttemptDeadline设置锁屏失败的时间

getLockoutAttemptDeadline获取锁屏失败的时间

之所以要在checkCredentialdia设置锁屏失败的时间,是为了防止应用那边忘了写,正常情况在检查
,即checkCredentialdia后,如果返回RESPONSE_RETRY就应用设置的。

  1. client端
    Setting和SystemUI应用都是通过LockPatternUtils这个类设置锁屏失败时间的;
    LockPatternUtils.java
     public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
+        try {
+          Log.d(TAG,"setLockoutAttemptDeadline uid = "+ userId + " timeoutMs = " + timeoutMs);
+          getLockSettings().setLockoutAttemptDeadline(userId,timeoutMs);
+        } catch (RemoteException re) {
+          Log.e(TAG,"setLockoutAttemptDeadline RemoteException error");
+        }
         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;
     }
 
     /**
      * @return The elapsed time 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 getLockoutAttemptDeadline(int userId) {
+        try {
+          Log.e(TAG,"getLockoutAttemptDeadline");
+          return getLockSettings().getLockoutAttemptDeadline(userId);
+        } catch (RemoteException re) {
+          Log.e(TAG,"getLockoutAttemptDeadline RemoteException error");
+        }
+
         final long deadline = mLockoutDeadlines.get(userId, 0L);
         final long now = SystemClock.elapsedRealtime();
         if (deadline < now && deadline != 0) {
             // timeout expired
             mLockoutDeadlines.put(userId, 0);
             return 0L;
         }
         return deadline;
     }
 

getLockSettings()获取LocakSettingSerivice的代理类,调用增加方法setLockoutAttemptDeadline设置时间,调用getLockoutAttemptDeadline获取时间,这样无论在哪解锁失败了,其他应用使用这个解锁都会知道。

发布了67 篇原创文章 · 获赞 42 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/w1764662543/article/details/89214240
今日推荐