Android11.0(R) 预留清空锁屏密码接口

简介: Android11.0(R) 预留清空锁屏密码接口

前言


出厂的设备有些客户喜欢设置锁屏密码,无奈记性不好,忘记密码后就只能恢复出厂或者重新刷机了,啊这客户肯定不接受的。


为了防止客户逼逼赖赖,我们就未雨绸缪,给它加个清除接口。


先说结论,系统锁屏密码数据库存储位于 /data/system/locksettings.db


经过测试 O 版本直接删除 locksettings.db 就已经达到要求


测试 Q、R 版本直接删除 locksettings.db 后,系统锁屏界面确实没了,但一直卡在安卓正在启动界面了,


无法进入桌面,进入设置中查看 Launcher3 应用丢了,目测此路不通。


那就曲线救国去研究 Settings 中是如何验证密码并取消密码的。


Settings 中各版本存储密码传递对象,已图案密码为例 ConfirmLockPattern.java


O、P 版本 密码 String intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, LockPatternUtils.patternToString(pattern));


Q 版本 密码 Byte[] intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, LockPatternUtils.patternToByteArray(pattern));


R 版本 密码 LockscreenCredential intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pattern);


framework 往下加解密流程可参考这篇 AndroidQ 锁屏密码验证流程之GateKeeper解析


解决思路


一:找到 Settings 中与用户交互设置锁屏密码核心代码,将绘制图案或者密码字符保存起来(数据库、prop、ContentProvider等)


二:增加清除接口(AIDL、广播、ContentResolver监听等)


三:取出用户设置密码转换为 framework 所需要 LockscreenCredential 对象


四:移除密码


上代码


4.1、找到锁屏图案保存核心代码


vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\password\ChooseLockPattern.java

        protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
                new LockPatternView.OnPatternListener() {
        ....
                public void onPatternDetected(List<LockPatternView.Cell> pattern) {
                    if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                        if (mChosenPattern == null) throw new IllegalStateException(
                                "null chosen pattern in stage 'need to confirm");
                        try (LockscreenCredential confirmPattern =
                                LockscreenCredential.createPattern(pattern)) {
                            if (mChosenPattern.equals(confirmPattern)) {
                                //20200903 cczheng add save lockdata start
                                mScreenLockHelper.saveCurrentLockData(pattern);
                                //20200903 cczheng add save lockdata end
                                updateStage(Stage.ChoiceConfirmed);
                            } else {
                                updateStage(Stage.ConfirmWrong);
                            }
                        }
                    } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                        if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
                            updateStage(Stage.ChoiceTooShort);
                        } else {
                            mChosenPattern = LockscreenCredential.createPattern(pattern);
                            updateStage(Stage.FirstChoiceValid);
                        }
                    } else {
                        throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
                                + "entering the pattern.");
                    }
                }


mChosenPattern 第一次绘制图案密码,confirmPattern 第二次绘制图案密码,两次一致设置成功,


就地保存图案密码。图案密码九宫格每个点 Cell 对应一个 Row, 一个 Column,实际规则如下


(0,0) (0,1) (0,2)


(1,0) (1,1) (1,2)


(2,0) (2,1) (2,2)


最终画线将每一个 cell 添加到集合中。


实际图案密码对象 LockscreenCredential.createPattern(pattern);


4.2、找到PIN码和密码保存核心代码


vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\password\ChooseLockPassword.java

    public void handleNext() {
            if (mSaveAndFinishWorker != null) return;
            // TODO(b/120484642): This is a point of entry for passwords from the UI
            final Editable passwordText = mPasswordEntry.getText();
            if (TextUtils.isEmpty(passwordText)) {
                return;
            }
            mChosenPassword = mIsAlphaMode ? LockscreenCredential.createPassword(passwordText)
                    : LockscreenCredential.createPin(passwordText);
            if (mUiStage == Stage.Introduction) {
                if (validatePassword(mChosenPassword)) {
                    mFirstPassword = mChosenPassword;
                    mPasswordEntry.setText("");
                    updateStage(Stage.NeedToConfirm);
                } else {
                    mChosenPassword.zeroize();
                }
            } else if (mUiStage == Stage.NeedToConfirm) {
                if (mChosenPassword.equals(mFirstPassword)) {
                    //20200903 cczheng add save lockdata start
                    mScreenLockHelper.saveCurrentLockData(mIsAlphaMode, passwordText.toString());
                    //20200903 cczheng add save lockdata end
                    startSaveAndFinish();
                } else {
                    CharSequence tmp = mPasswordEntry.getText();
                    if (tmp != null) {
                        Selection.setSelection((Spannable) tmp, 0, tmp.length());
                    }
                    updateStage(Stage.ConfirmWrong);
                    mChosenPassword.zeroize();
                }
            }
        }


mIsAlphaMode 用来区分是 PIN 码还是密码


实际密码对象 LockscreenCredential.createPassword(passwordText)


实际PIN码对象 LockscreenCredential.createPin(passwordText)


4.3、找到移除密码核心代码


设置完锁屏密码后再次进入锁屏选择页面,此时需要验证刚刚设置密码,验证成功后才能进入锁屏选择界面。


验证成功就获取到了 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pattern);


这个很关键,一会需要用它来移除锁屏密码


vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\password\ChooseLockGeneric.java

 void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) {
      .....
            if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                // Clearing of user biometrics when screen lock is cleared is done at
                // LockSettingsService.removeBiometricsForUser().
                if (mUserPassword != null) {
                    // No need to call setLockCredential if the user currently doesn't
                    // have a password
                    mChooseLockSettingsHelper.utils().setLockCredential(
                            LockscreenCredential.createNone(), mUserPassword, mUserId);
                }
                mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
                getActivity().setResult(Activity.RESULT_OK);
                finish();
            }
        }

关键方法就两个

setLockCredential(新密码,旧密码,用户id)

setLockScreenDisabled(移除密码,用户id)


4.4、造数据移除密码

package com.android.settings.password;
import android.content.Context;
import android.util.Log;
import android.os.SystemProperties;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockscreenCredential;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ScreenLockHelper{
  private static final String TAG = "ScreenLockHelper";
  //value startwith 
  //pt&xxxx  LockPattern
  //pn&xxxx  LockPin
  //ps&xxxx  LockPassword
  private final String KEY = "persist.android.screen.lock";
  private final String HEAD_PAT = "pt&";
  private final String HEAD_PIN = "pn&";
  private final String HEAD_PWD = "ps&";
  private Context mContext;
  private LockPatternUtils mLockPatternUtils;
  public ScreenLockHelper(Context context) {
        mContext = context;
        mLockPatternUtils = new LockPatternUtils(context);
    }
    public void saveCurrentLockData(boolean mIsPwd, String pwd) {
       pwd = (mIsPwd ? HEAD_PWD : HEAD_PIN) + pwd;
       SystemProperties.set(KEY, pwd);
    }
    public void saveCurrentLockData(List<LockPatternView.Cell> pattern) {
      String pwd = HEAD_PAT;
    StringBuilder builder = new StringBuilder();
    builder.append(pwd);
      for (int i=0; i<pattern.size(); i++) {
        LockPatternView.Cell cell = pattern.get(i);
        builder.append(cell.getRow());
        builder.append("*");
        builder.append(cell.getColumn());
            if (i != pattern.size() - 1) {
              builder.append("+");
            }
            Log.i(TAG,"cell="+cell.toString());
        }
        pwd = builder.toString();
        SystemProperties.set(KEY, pwd);
    }
    public void  clearScreenLock() {
       LockscreenCredential emptyCredential = LockscreenCredential.createNone();
       LockscreenCredential savedCredential;
       String pwdValue = SystemProperties.get(KEY, "");
       if (pwdValue.startsWith(HEAD_PIN)) {
          savedCredential = LockscreenCredential.createPin(pwdValue.substring(3));
       }else if (pwdValue.startsWith(HEAD_PWD)) {
          savedCredential = LockscreenCredential.createPassword(pwdValue.substring(3));
       }else if (pwdValue.startsWith(HEAD_PAT)) {
          pwdValue = pwdValue.substring(3);
          List<LockPatternView.Cell> pattern = new ArrayList<LockPatternView.Cell>();
          String[] cellArray = pwdValue.split("\\+");
          for (String cellStr : cellArray) {
            String[] cell = cellStr.split("\\*");
            pattern.add(Cell.of(Integer.parseInt(cell[0]), Integer.parseInt(cell[1])));
          }
          savedCredential = LockscreenCredential.createPattern(pattern);
       }else{
          savedCredential = LockscreenCredential.createNone();
       }
       mLockPatternUtils.setLockCredential(emptyCredential, savedCredential, 0);
       mLockPatternUtils.setLockScreenDisabled(true, 0);
    }
}


目录
相关文章
|
1月前
|
Android开发
Android MediaTek 平台增加UART接口的红外模块支持,支持NEC红外遥控
Android MediaTek 平台增加UART接口的红外模块支持,支持NEC红外遥控
28 0
|
1月前
|
Linux Android开发
Android 正常运行所需的一系列 Linux 内核接口
Android 正常运行所需的一系列 Linux 内核接口
65 0
Android-kotlin-接口与多态的表现,面经解析
Android-kotlin-接口与多态的表现,面经解析
|
24天前
|
XML 网络协议 Java
53. 【Android教程】Socket 网络接口
53. 【Android教程】Socket 网络接口
19 0
|
1月前
|
Java 开发工具 Android开发
如何访问 android系统hide的类或接口
如何访问 android系统hide的类或接口
50 1
|
1月前
|
XML JSON Java
Android App网络通信中通过okhttp调用HTTP接口讲解及实战(包括GET、表单格式POST、JSON格式POST 附源码)
Android App网络通信中通过okhttp调用HTTP接口讲解及实战(包括GET、表单格式POST、JSON格式POST 附源码)
361 0
|
1月前
|
数据安全/隐私保护 Android开发
Android Studio APP实战开发之找回密码及忘记密码(附源码 超实用必看)
Android Studio APP实战开发之找回密码及忘记密码(附源码 超实用必看)
201 0
|
1月前
|
XML Java API
Android App开发之创建JNI接口获取CPU指令集讲解及实战(附源码 简单易懂)
Android App开发之创建JNI接口获取CPU指令集讲解及实战(附源码 简单易懂)
67 0
|
1月前
|
XML Java 定位技术
Android Studio App开发之网络通信中使用GET方式调用HTTP接口的讲解及实战(附源码 超详细必看)
Android Studio App开发之网络通信中使用GET方式调用HTTP接口的讲解及实战(附源码 超详细必看)
142 0
|
1月前
|
SQL 数据库 数据安全/隐私保护
Android Studio App开发中数据库SQLite的解析及实战使用(包括创建数据库,增删改查,记住密码等 附源码必看)
Android Studio App开发中数据库SQLite的解析及实战使用(包括创建数据库,增删改查,记住密码等 附源码必看)
276 0