View Hierarchy & locksettingsservice

View Hierarchy不能启动的原因

To preserve security, Hierarchy Viewer can only connect to devices running a developer version of the Android system

即:出于安全考虑,Hierarchy Viewer只能连接Android开发版手机或是模拟器(准确地说,只有ro.secure参数等于0且ro.debuggable等于1的android系统)。

Hierarchy Viewer在连接手机时,手机上必须启动一个叫View Server的客户端与其进行socket通信。而在商业手机上,是无法开启View Server的,故Hierarchy Viewer是无法连接到普通的商业手机。

Android源码实现这一限制的地方在:

ANDROID源码根目录\frameworks\base\services\java\com\android\server\wm\WindowManageService.java

中的一段:

/**
 * Starts the view server on the specified port.
 *
 * @param port The port to listener to.
 *
 * @return True if the server was successfully started, false otherwise.
 *
 * @see com.android.server.wm.ViewServer
 * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
 */
@Override
public boolean startViewServer(int port) {
    if (isSystemSecure()) {
        return false;
    }

    if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
        return false;
    }

    if (port < 1024) {
        return false;
    }

    if (mViewServer != null) {
        if (!mViewServer.isRunning()) {

 

检验一台手机是否开启了View Server的办法为:

adb shell service call window 3

若返回值是:Result: Parcel(00000000 00000000 ‘……..’)” 说明View Server处于关闭状态

若返回值是:Result: Parcel(00000000 00000001 ‘……..’)” 说明View Server处于开启状态

若是一台可以打开View Server的手机(Android开发版手机 、模拟器or 按照本帖步骤给系统打补丁的手机),我们可以使用以下命令打开View Server:

adb shell service call window 1 i32 4939

使用以下命令关闭View Server:

adb shell service call window 2 i32 4939

 

布局优化必备 Hierarchy Viewer 工具使用

https://blog.csdn.net/u012792686/article/details/72921379

 

Android Framework------之Keyguard 简单分析

https://www.cnblogs.com/haiming/p/2989678.html

 

https://blog.csdn.net/qq_36946260/article/details/75232263

Android中锁屏密码算法解析以及破解方案

https://blog.csdn.net/po__oq/article/details/80985658

 

 

 // 设置中选不同的锁屏密码会到这里
830         private boolean setUnlockMethod(String unlockMethod) {
831             EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
832 
833             ScreenLockType lock = ScreenLockType.fromKey(unlockMethod);
834             if (lock != null) {
835                 switch (lock) {
836                     case NONE:
837                     case SWIPE:
838                         updateUnlockMethodAndFinish(
839                                 lock.defaultQuality,
840                                 lock == ScreenLockType.NONE,
841                                 false /* chooseLockSkipped */);
842                         return true;
843                     case PATTERN:
844                     case PIN:
845                     case PASSWORD:
846                     case MANAGED:
847                         maybeEnableEncryption(lock.defaultQuality, false);
848                         return true;
849                 }
850             }
851             Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
852             return false;
853         }
854 
 

 

 

frameworks\base\packages\SystemUI\src\com\android\keyguard\KeyguardSecurityModel.java

getSecurityMode=>

frameworks\base\core\java\com\android\internal\widget\LockPatternUtils.java

=>getActivePasswordQuality

这里是获取密码的质量,比如是简单的数字pin 码,复杂的数值和字符码等。

 

这些信息是保存在数据库中的,/data/system/locksettings.db 中,

View Hierarchy & locksettingsservice_第1张图片

 

getKeyguardStoredPasswordQuality 就是获取lockscreen.password_type    密码复杂类型

 

    /**
     * Used by device policy manager to validate the current password
     * information it has.
     */
    public int getActivePasswordQuality(int userId) {
        int quality = getKeyguardStoredPasswordQuality(userId);

        if (isLockPasswordEnabled(quality, userId)) {
            // Quality is a password and a password exists. Return the quality.
            return quality;
        }

        if (isLockPatternEnabled(quality, userId)) {
            // Quality is a pattern and a pattern exists. Return the quality.
            return quality;
        }

        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    }

 

 

    private boolean isLockPasswordEnabled(int mode, int userId) {
        final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
                || mode == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
        return passwordEnabled && savedPasswordExists(userId);
    }

    private boolean savedPasswordExists(int userId) {
        try {
            return getLockSettings().havePassword(userId);
        } catch (RemoteException re) {
            return false;
        }
    }

frameworks\base\services\core\java\com\android\server\locksettings\LockSettingsService.java

    @Override
    public boolean havePassword(int userId) throws RemoteException {
        checkPasswordHavePermission(userId);
        synchronized (mSpManager) {
            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                long handle = getSyntheticPasswordHandleLocked(userId);
                return mSpManager.getCredentialType(handle, userId) ==
                        LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
            }
        }
        // Do we need a permissions check here?
        return mStorage.hasPassword(userId);
    }
 

这里从数据库中获取了密码的复杂类型,需要进一步从保存的sp-hadle.pwd 中获取是否存在passwd 与pattern 类型密码

frameworks\base\services\core\java\com\android\server\locksettings\SyntheticPasswordManager.java

havePassword这里判断对应用户是否存在基于凭据的合成password

1、从locksettings.db 中获取合成handle , 即字段数据库字段 "sp-handle"

2、根据sp-handle 获取对应用户的凭据mSpManager.getCredentialType(handle, userId),这里是读文件

/data/system_de/0/spblob/sp-hadle.pwd 

0 对应userId  ,sp-handle  对应合成hadle 

 

pattern 与passwd 同一个文件,一样通过获取SyntheticPasswordManager 中凭据结构体PasswordData的类型字段判读是passwd 还是pattern类型

    private boolean isLockPatternEnabled(int mode, int userId) {
        return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
                && savedPatternExists(userId);
    }
    /**
     * Check to see if the user has stored a lock pattern.
     * @return Whether a saved pattern exists.
     */
    private boolean savedPatternExists(int userId) {
        try {
            return getLockSettings().havePattern(userId);
        } catch (RemoteException re) {
            return false;
        }
    }

 


    static class PasswordData {
        byte scryptN;
        byte scryptR;
        byte scryptP;
        public int passwordType;
        byte[] salt;
        // For GateKeeper-based credential, this is the password handle returned by GK,
        // for weaver-based credential, this is empty.
        public byte[] passwordHandle;

        public static PasswordData create(int passwordType) {
            PasswordData result = new PasswordData();
            result.scryptN = PASSWORD_SCRYPT_N;
            result.scryptR = PASSWORD_SCRYPT_R;
            result.scryptP = PASSWORD_SCRYPT_P;
            result.passwordType = passwordType;
            result.salt = secureRandom(PASSWORD_SALT_LENGTH);
            return result;
        }

        public static PasswordData fromBytes(byte[] data) {
            PasswordData result = new PasswordData();
            ByteB

 

 

如果数据库lockscreen.password_type与sp-hadle.pwd  两者一直获取的信息一致,就会根据根据类型信息下一个输入密码的view。

 

滑动显示pin 码界面
01-12 22:22:00.271  1114  1114 D KeyguardSecurityView: showNextSecurityScreenOrFinish(false)
01-12 22:22:00.271  1114  1114 D KeyguardSecurityView: showNext.. mCurrentSecuritySelection = PIN
01-12 22:22:00.271  1114  1114 D KeyguardSecurityView: showNextSecurityScreenOrFinish() - return finish = false
01-12 22:22:00.271  1114  1114 D KeyguardSecurityView: showNextSecurityScreenOrFinish(false)
01-12 22:22:00.271  1114  1114 D KeyguardSecurityView: showNext.. mCurrentSecuritySelection = PIN
01-12 22:22:00.272  1114  1114 D KeyguardSecurityView: showNextSecurityScreenOrFinish() - return finish = false
01-12 22:22:00.392  1114  1114 D KeyguardViewBase: screen on, instance 925d934
 

灭屏
01-12 22:22:10.085  1114  1114 D KeyguardViewBase: screen off, instance 925d934 at 40443586
01-12 22:22:10.090  1114  1114 V KeyguardSecurityView: showPrimarySecurityScreen(turningOff=true)
01-12 22:22:10.091  1114  1114 V KeyguardSecurityView: showPrimarySecurityScreen(securityMode=PIN)
01-12 22:22:10.091  1114  1114 D KeyguardSecurityView: showSecurityScreen(PIN)
01-12 22:22:10.198  1114  1114 D KeyguardViewBase: show()
01-12 22:22:10.201  1114  1114 V KeyguardSecurityView: showPrimarySecurityScreen(turningOff=false)
01-12 22:22:10.201  1114  1114 V KeyguardSecurityView: showPrimarySecurityScreen(securityMode=PIN)
01-12 22:22:10.201  1114  1114 D KeyguardSecurityView: showSecurityScreen(PIN)

 

 

 

在设置中录入pin、pattern点确定,或设置为滑动、或设置为 none 时,

frameworks\base\core\java\com\android\internal\widget\LockPatternUtils.java

设置为none 与滑动,或从pin/passwd/pattern 切换到none 与滑动

/**
 * Clear any lock pattern or password.
 */
public void clearLock(String savedCredential, int userHandle) {

。。。

}

//设置为手势码

/**
 * Save a lock pattern.
 * @param pattern The new pattern to save.
 * @param savedPattern The previously saved pattern, converted to String format
 * @param userId the user whose pattern is to be saved.
 */
public void saveLockPattern(List pattern, String savedPattern, int userId) {

。。。

}

//设置为pin/passwd

/**
 * Save a lock password.  Does not ensure that the password is as good
 * as the requested mode, but will adjust the mode to be as good as the
 * password.
 * @param password The password to save
 * @param savedPassword The previously saved lock password, or null if none
 * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
 * @param userHandle The userId of the user to change the password for
 */
public void saveLockPassword(String password, String savedPassword, int requestedQuality,
        int userHandle) {

。。。

}

 

// This method should be called by LockPatternUtil only, all internal methods in this class
// should call setLockCredentialInternal.
@Override
public void setLockCredential(String credential, int type, String savedCredential,
        int requestedQuality, int userId)
        throws RemoteException {
    checkWritePermission(userId);
    synchronized (mSeparateChallengeLock) {
        setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
        setSeparateProfileChallengeEnabled(userId, true, null);
        notifyPasswordChanged(userId);
    }
}

credential = pin 码或者手势码对应的数字 或者设置为滑动、none 则 null

type  类型其中一种

    public static final int CREDENTIAL_TYPE_NONE = -1;
    public static final int CREDENTIAL_TYPE_PATTERN = 1;
    public static final int CREDENTIAL_TYPE_PASSWORD = 2;

savedCredential上一次的credential 

 


    private void setLockCredentialInternal(String credential, int credentialType,
            String savedCredential, int requestedQuality, int userId) throws RemoteException {
        // Normalize savedCredential and credential such that empty string is always represented
        // as null.
        if (TextUtils.isEmpty(savedCredential)) {
            savedCredential = null;
        }
        if (TextUtils.isEmpty(credential)) {
            credential = null;
        }
        synchronized (mSpManager) {
            if (isSyntheticPasswordBasedCredentialLocked(userId)) {

                //locksettings.db 中对应用户数据库字段 "sp-handle" 是否存在,存在这里
                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
                        requestedQuality, userId);
                return;
            }
        }

     //locksettings.db 中对应用户数据库字段 "sp-handle" 是否存在,不存在这里

        if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
            if (credential != null) {
                Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
            }
            clearUserKeyProtection(userId);
            getGateKeeperService().clearSecureUserId(userId);
            mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
            setKeystorePassword(null, userId);
            fixateNewestUserKeyAuth(userId);
            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
            notifyActivePasswordMetricsAvailable(null, userId);
            return;
        }
        if (credential == null) {
            throw new RemoteException("Null credential with mismatched credential type");
        }

        CredentialHash currentHandle = mStorage.readCredentialHash(userId);
        if (isManagedProfileWithUnifiedLock(userId)) {
            // get credential from keystore when managed profile has unified lock
            if (savedCredential == null) {
                try {
                    savedCredential = getDecryptedPasswordForTiedProfile(userId);
                } catch (FileNotFoundException e) {
                    Slog.i(TAG, "Child profile key not found");
                } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
                        | NoSuchAlgorithmException | NoSuchPaddingException
                        | InvalidAlgorithmParameterException | IllegalBlockSizeException
                        | BadPaddingException | CertificateException | IOException e) {
                    Slog.e(TAG, "Failed to decrypt child profile key", e);
                }
            }
        } else {
            if (currentHandle.hash == null) {
                if (savedCredential != null) {
                    Slog.w(TAG, "Saved credential provided, but none stored");
                }
                savedCredential = null;
            }
        }
        synchronized (mSpManager) {
            if (shouldMigrateToSyntheticPasswordLocked(userId)) {
                initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
                        currentHandle.type, requestedQuality, userId);
                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
                        requestedQuality, userId);
                return;
            }
        }
        if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
        byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
                userId);
        if (enrolledHandle != null) {
            CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
            mStorage.writeCredentialHash(willStore, userId);
            // push new secret and auth token to vold
            GateKeeperResponse gkResponse = getGateKeeperService()
                    .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
            setUserKeyProtection(userId, credential, convertResponse(gkResponse));
            fixateNewestUserKeyAuth(userId);
            // Refresh the auth token
            doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
        } else {
            throw new RemoteException("Failed to enroll " +
                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
                            : "pattern"));
        }
    }
 

 

//locksettings.db 中对应用户数据库字段 "sp-handle" 是否存在,存在这里


    private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
            String savedCredential, int requestedQuality, int userId){ AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
                getGateKeeperService(), handle, savedCredential, userId);


   long handle = getSyntheticPasswordHandleLocked(userId);//从数据库或者缓存获取sp-handle  

          AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
                getGateKeeperService(), handle, savedCredential, userId);
        VerifyCredentialResponse response = authResult.gkResponse;
        AuthenticationToken auth = authResult.authToken;   

// unwrapPasswordBasedSyntheticPassword  获取上一次的AT


        // If existing credential is provided, then it must match.
        if (savedCredential != null && auth == null) {
            throw new RemoteException("Failed to enroll " +
                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
                            : "pattern"));
        }

        if (auth != null) { //有设置过pin/pattern或当次是设置pin/pattern,就会到这之前通过initializeSyntheticPasswordLocked

//已经保存密码相关信息
            // We are performing a trusted credential change i.e. a correct existing credential
            // is provided
            setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
                    userId);//设置这一次的信息
            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);//删除上一次的信息
        } else if (response != null
                && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){
            // We are performing an untrusted credential change i.e. by DevicePolicyManager.
            // So provision a new SP and SID. This would invalidate existing escrow tokens.
            // Still support this for now but this flow will be removed in the next release.

            Slog.w(TAG, "Untrusted credential change invoked");
            initializeSyntheticPasswordLocked(null, credential, credentialType, requestedQuality,
                    userId);
            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);

            notifyActivePasswordMetricsAvailable(credential, userId);
        } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
            Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
                    (response != null ? "rate limit exceeded" : "failed"));
            return;
        }  

}

 

 /**
     * Decrypt a synthetic password by supplying the user credential and corresponding password
     * blob handle generated previously. If the decryption is successful, initiate a GateKeeper
     * verification to referesh the SID & Auth token maintained by the system.
     * Note: the credential type is not validated here since there are call sites where the type is
     * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType
     */
    public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
            long handle, String credential, int userId) throws RemoteException {
        if (credential == null) {
            credential = DEFAULT_PASSWORD;//滑动或者none ,为 "default-password"
        }
        AuthenticationResult result = new AuthenticationResult();
        PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, userId));

           //从/data/system_de/0/spblob/sp-hadle.pwd 读并构造PasswordData对象。
        result.credentialType = pwd.passwordType;
        byte[] pwdToken = computePasswordToken(credential, pwd);

        //根据pin 码等并和PasswordData(有盐值字段) 一起加密得到pwdToken

 

        final byte[] applicationId;
        final long sid;
        int weaverSlot = loadWeaverSlot(handle, userId);// SyntheticPasswordManager: Device does not support weaver
        if (weaverSlot != INVALID_WEAVER_SLOT) {
            // Weaver based user password,不支持,跳过
            if (!isWeaverAvailable()) {
                Log.e(TAG, "No weaver service to unwrap password based SP");
                result.gkResponse = VerifyCredentialResponse.ERROR;
                return result;
            }
            result.gkResponse = weaverVerify(weaverSlot, passwordTokenToWeaverKey(pwdToken));
            if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
                return result;
            }
            sid = GateKeeper.INVALID_SECURE_USER_ID;
            applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload());
        } else {
            byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);//加密及hash 相关
            GateKeeperResponse response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
                    pwd.passwordHandle, gkPwdToken);//gatekeeper 验证
            int responseCode = response.getResponseCode();
            if (responseCode == GateKeeperResponse.RESPONSE_OK) {
                result.gkResponse = VerifyCredentialResponse.OK;
                if (response.getShouldReEnroll()) {
                    GateKeeperResponse reenrollResponse = gatekeeper.enroll(fakeUid(userId),
                            pwd.passwordHandle, gkPwdToken, gkPwdToken);
                    if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
                        pwd.passwordHandle = reenrollResponse.getPayload();
                        saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
                        synchronizeFrpPassword(pwd,
                                pwd.passwordType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
                                ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
                                : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                                /* TODO(roosa): keep the same password quality */,
                                userId);
                    } else {
                        Log.w(TAG, "Fail to re-enroll user password for user " + userId);
                        // continue the flow anyway
                    }
                }
            } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
                result.gkResponse = new VerifyCredentialResponse(response.getTimeout());
                return result;
            } else  {
                result.gkResponse = VerifyCredentialResponse.ERROR;
                return result;
            }
            sid = sidFromPasswordHandle(pwd.passwordHandle);//从native 层获取sid
            applicationId = transformUnderSecdiscardable(pwdToken,
                    loadSecdiscardable(handle, userId));

//loadSecdiscardable从/data/system_de/0/spblob/sp-hadle.secdis 获取

//pwdToken 与secdis 根据加密及hash 得到applicationId

        }

        result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
                applicationId, sid, userId);

//从/data/system_de/0/spblob/sp-hadle.spblob 文件读的到AuthenticationToken

        // Perform verifyChallenge to refresh auth tokens for GK if user password exists.
        result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);//gatekeeper 验证
        return result;
    }

 

//locksettings.db 中对应用户数据库字段 "sp-handle" 是否存在,不存在这里,说明没有设置过pin/patter码

 

    private void setLockCredentialInternal(String credential, int credentialType,
            String savedCredential, int requestedQuality, int userId) throws RemoteException {
           。。。

 

        if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {//选中滑动或者NONE
            Slog.d(TAG,"locksetting credentialType=NONE");
            if (credential != null) {
                Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
            }
            clearUserKeyProtection(userId);
            getGateKeeperService().clearSecureUserId(userId);
            mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);

//writeCredentialHash创建 /data/system/gatekeeper.password.key、/data/system/gatekeeper.pattern.key ,但内容为空
            setKeystorePassword(null, userId);
            fixateNewestUserKeyAuth(userId);
            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
            notifyActivePasswordMetricsAvailable(null, userId);
            return;

          }

        synchronized (mSpManager) {
            if (shouldMigrateToSyntheticPasswordLocked(userId)) {

          //SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT  默认1,支持混合passworld (sp-handle),这里

                initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
                        currentHandle.type, requestedQuality, userId);

                 //initializeSyntheticPasswordLocked  创建与保存相关信息,这里sp-handle 就存在数据库
                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
                        requestedQuality, userId);

               //spBasedSetLockCredentialInternalLocked,这里跟上边分支locksettings.db 中对应用户数据库字段 "sp-handle" 存在是处理一样。
                return;
            }

         //SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT 为 0,不支持混合passworld(sp-handle)

          这里密码信息保存在 /data/system/gatekeeper.password.key、/data/system/gatekeeper.pattern.key 等文件中

        byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
                userId);
        if (enrolledHandle != null) {
            CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
            mStorage.writeCredentialHash(willStore, userId);
            // push new secret and auth token to vold
            GateKeeperResponse gkResponse = getGateKeeperService()
                    .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
            setUserKeyProtection(userId, credential, convertResponse(gkResponse));
            fixateNewestUserKeyAuth(userId);
            // Refresh the auth token
            doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
        } else {
            throw new RemoteException("Failed to enroll " +
                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
                            : "pattern"));
        }

 }

 

 

 

 

 

 

 

 

原因:

这个问题是由于从数据库中获取的锁屏码方式跟从保存的文件中读取的信息并解析的锁屏码方式不匹配导致的,

这个问题可能是某种原因导致数据库写入失败或错误。设置中与systemUI 中不一致是由于设置中是直接从数据

库获取锁屏方式,而systemUI从数据库与文件中分别获取并比较,不一致则认为没有设置锁屏方式。

 

措施:

现在的修改措施是将写入数据库的信息在写入数据库前保存到文件中,获取的时候先获取文件中的,再获取数据库

中的并比较,如果不一致则以文件中的为准。

 

frameworks\base\services\core\java\com\android\server\locksettings\LockSettingsStorage.java

public void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) {

    if(LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY.equals(key) || LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
        byte[] stored = readFile(getFileNameForKey(key, userId));
        if(stored != null && new String(stored).length() > value.length()) {
            new File(getFileNameForKey(key, userId)).delete();
        }
        writeFile(getFileNameForKey(key, userId), value.getBytes());
    }

 

public String readKeyValue(String key, String defaultValue, int userId) {
    int version;
    synchronized (mCache) {
        if (mCache.hasKeyValue(key, userId)) {
            return mCache.peekKeyValue(key, defaultValue, userId);
        }
        version = mCache.getVersion();
    }

    Cursor cursor;
    Object result = DEFAULT;
    SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
            COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
            new String[] { Integer.toString(userId), key },
            null, null, null)) != null) {
        if (cursor.moveToFirst()) {
            result = cursor.getString(0);
        }
        cursor.close();
    }

    if(LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY.equals(key) || LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
        byte[] stored = readFile(getFileNameForKey(key, userId));
        if(stored != null) {
            if(result == DEFAULT || !new String(stored).equals((String) result)) {
                result = new String(stored);
            }
        }
    }
    mCache.putKeyValueIfUnchanged(key, result, userId, version);
    return result == DEFAULT ? defaultValue : (String) result;
}

 

 

 

 

View Hierarchy & locksettingsservice_第2张图片

 

 

 

 

 

 

 

你可能感兴趣的:(java,android)