博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AndroidL 开机展示Keyguard锁屏机制初探
阅读量:2071 次
发布时间:2019-04-29

本文共 12776 字,大约阅读时间需要 42 分钟。

目录

目录
锁屏时序图
开机启动到PhoneWindowManager的systemReady方法
锁屏加载流程
PhoneWindowManager
KeyguardServiceDelegate
KeyguardServiceWrapper
KeyguardService
KeyguardViewMediator
onSystemReady
onKeyguardLocked
showLocked
handleShow
重点一
重点二
StatusBarKeyguardViewManager
show
reset
showBouncerOrKeyguard
锁屏时序图
研究了将近两天的Android5.1 Keyguard锁屏机制,不得不说,各种饶。这里先把锁屏流程时序图贡献给大家: 

使用的是线编辑工具ProcessOn,用来编辑时序图效果看起来不是太好。不过没有太大关系,这个时序图只是为了方便我们能清晰的对锁屏流程有个大致的了解,接下来,我会详细的分析每个类的具体流程。

声明:本文基于AndroidLollipop 5.1.1_r6版本进行的源码分析。

开机启动到PhoneWindowManager的systemReady方法

准备先从开机启动到PhoneWindowManager类的systemReady方法调用开始介绍。开机启动流程其实也很复杂,但是本文重点在于Keyguard锁屏的展示,所以这里只是大体列出如何从开机启动调用到PhoneWindowManager的systemReady()方法。具体流程如下: 
init进程->zygote进程(java世界)->system server进程。 
而在system server进程中,它的SystemServer.java中main函数会调用startOtherServices()方法,相关源码如下:

private void startOtherServices() {

    WindowManagerService wm = null;
    wm = WindowManagerService.main(context, inputManager,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
            !mFirstBoot, mOnlyCore);
    try {
        wm.systemReady();
    } catch (Throwable e) {
        reportWtf("makeing Window Manager Service ready", e);
    }
}
既然wm是WindowManagerServer类的实例,那就需要继续看一下这个类关于systemReady()方法的实现:

public class WindowManagerService extends IWindowManager.Stub

        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
    public void systemReady() {
        mPolicy.systemReady();
    }
}
其中,mPolicy实例的生成依赖于Java的反射机制,具体流程如下:

public final class PolicyManager {

    private static final String POLICY_IMPL_CLASS_NAME = 
        "com.android.internal.policy.impl.Policy";
    private static final IPolicy sPolicy;
    static {
        try {
            // 获取了Policy的类类型
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
            // 通过Policy的类类型获取Policy的对象实例
            sPolicy = (IPolicy)policyClass.newInstance();
        } catch (Exception e) {
        }
    }
    public static Window makeNewWindowManager(Context context) {
        return sPolicy.makeNewWindowManager(context);
    }
}

// Policy中继续调用反射机制进行预加载

public class Policy implements IPolicy {
    public Window makeNewWindowManager(Context context) {
        return new PhoneWindowManager();
    }
}
通过上述代码的跟踪,终于来到了我们时序图的第一个类PhonewWindowManager的systemReady()方法了。

锁屏加载流程

既然上述分析到了PhoneWindowManager,我们也就是按照时序图,根据时序图上的每个类,进行相关源码分析(重点难点的源码我会中文注释)。

PhoneWindowManager

路径

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

源码:

public class PhoneWindowManager implements WindowManagerPolicy {

    public void systemReady() {
        // 调用Keygurad代理类的onSystemReady方法
        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
        mKeyguardDelegate.onSystemReady();
        // ... 省略不相关源码 
    }
}
KeyguardServiceDelegate
路径:

frameworks/base/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java

源码:

public class KeyguardServiceDelegate {

    protected KeyguardServiceWrapper mKeyguardService;

    public void onSystemReady() {

        if (mKeyguardService != null) {
            mKeyguardService.onSystemReady();
        } else {
            mKeyguardState.systemIsReady = true;
        }   
    } 
}
KeyguardServiceWrapper
路径:

frameworks/base/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java

源码:

public class KeyguardServiceWrapper implements IKeyguardService {

    private IkeyguardService mService;
    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
        // 构造函数中对mService进行了初始化
        mService = service;
    }
    public void onSystemReady() {
        try {
            mService.onSystemReady();
        } catch (RemoteException e) {
            Slog.w(TAG , "Remote Exception", e); 
        }   
    }
}
由于mService是IKeyguardService接口实现类的实例,并且mService又是在KeyguardServiceWrapper的构造函数中传递进来初始化的。所以,我们又需要回到KeyguardServiceDelegate类,去看一下KeyguardServiceWrapper初始化的过程,相关代码如下:

public class KeyguardServiceDelegate {

    public static final String KEYGUARD_PACKAGE = "com.android.systemui";
    public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";

    /**

     * 使用bindService的方式来绑定服务。利用bindService的方式:
     * 调用者与服务绑定在一起,调用者退出,服务即终止。
     * ps => bind方式绑定服务,服务的执行顺序为:
     * onCreate()->onBind()->onUnbind()->onDestroy()
     */
    public void bindService(Context context) {
        Intent intent = new Intent();
        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
            Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
            mKeyguardState.showing = false;
            mKeyguardState.showingAndNotOccluded = false;
            mKeyguardState.secure = false;
            mKeyguardState.deviceHasKeyguard = false;
            hideScrim();
        } else {
            if (DEBUG) Log.v(TAG, "*** Keyguard started");
        }   
    }   

    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {

       
        public void onServiceConnected(ComponentName name, IBinder service) {
            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
            // 当和服务绑定后,这IKeyguardService.Stub.asInterface(service)获取的就是KeyguardService的类实例
            mKeyguardService = new KeyguardServiceWrapper(mContext,
                    IKeyguardService.Stub.asInterface(service));
            if (mKeyguardState.systemIsReady) {
                // If the system is ready, it means keyguard crashed and restarted.
                mKeyguardService.onSystemReady();
                // This is used to hide the scrim once keyguard displays.
                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(
                        mShowListenerWhenConnect));
                mShowListenerWhenConnect = null;
            }
            if (mKeyguardState.bootCompleted) {
                mKeyguardService.onBootCompleted();
            }
        }

       

        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
            mKeyguardService = null;
        }
    };
}
接下来,就需要去看一下KeyguardService类的onSystemReady方法了。

KeyguardService

路径:

/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java

源码:

public class KeyguardService extends Service {

    private KeyguardViewMediator mKeyguardViewMediator;

    // Binder interface

    public void onSystemReady() {
        // 检查调用进程是否具体SYSTEM权限
        checkPermission();
        // 真正的锁屏入口
        mKeyguardViewMediator.onSystemReady();
    }
}
Wow,终于到了我们的主角KeyguardViewMediator登场了。

KeyguardViewMediator

路径:

frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

虽然KeyguardViewMediator是锁屏的入口,但是从这里到锁屏的真正展现还有很长一段路。接下来,为了方便,我们都是基于当前类的函数进行分析。

onSystemReady

public class KeyguardViewMediator extends SystemUI {
    // 开机显示锁屏入口函数   
    public void onSystemReady() {
        synchronized (this) {
            if (DEBUG) Log.d(TAG, "onSystemReady");
            mSystemReady = true;            

            // 判断是否使用生物识别解锁(类似:人脸识别、声音识别等)

            if (mLockPatternUtils.usingBiometricWeak()
                    && mLockPatternUtils.isBiometricWeakInstalled()) {
                if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
                mUpdateMonitor.setAlternateUnlockEnabled(false);
            } else {
                mUpdateMonitor.setAlternateUnlockEnabled(true);
            }
            // 进行锁屏预处理判断等操作
            doKeyguardLocked(null);
        }
    }
}
onKeyguardLocked()
其中,doKeyguardLocked是来做启动锁屏界面的预处理方法,我们来看一下这个函数的具体实现:

public class KeyguardViewMediator extends SystemUI {

    private void doKeyguardLocked(Bundle options) {
        if (!mExternallyEnabled) {
            // 其他应用禁止锁屏呈现,例如接电话等操作.
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
            return;
        }

        // 判断锁屏是否正在展示

        if (mStatusBarKeyguardViewManager.isShowing()) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
            resetStateLocked();
            return;
        }

        // 判断是否无sim卡也可使用手机

        final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
        // 获取sim卡状态
        final boolean absent = SubscriptionManager.isValidSubscriptionId(
            mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.ABSENT));
        final boolean disabled = SubscriptionManager.isValidSubscriptionId(
            mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));
        final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
                || ((absent || disabled) && requireSim);

        if (!lockedOrMissing && shouldWaitForProvisioning()) {

            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
                    + " and the sim is not locked or missing");
            return;
        }

        if (mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {

            // Settings中没有启用锁屏
            return;
        }

        if (mLockPatternUtils.checkVoldPassword()) {

            setShowingLocked(false);
            hideLocked();
            return;
        }

        // 经过上述判断后,去展示锁屏

        showLocked(options);
    }
}
注意showLocked(options)方法调用,这个是启动锁屏的关键方法。这里的options传递的值为null。

showLocked()

public class KeyguardViewMediator extends SystemUI {
   private void showLocked(Bundle options) {
        if (DEBUG) Log.d(TAG, "showLocked");
        // 获取PARTIAL_WAKE_LOCK,不受电源键影响,不让CPU进入休眠状态 
        mShowKeyguardWakeLock.acquire();
        // 发送msg.what为SHOW类型的message
        Message msg = mHandler.obtainMessage(SHOW, options);
        mHandler.sendMessage(msg);
    }
}
注意:

mShowKeyguardWakeLock.acquire(); ⇒ 获取之后是无法让CPU休眠,不要忘记释放,不让会增加系统功耗。

跟mShowKeyguardWakeLock相关的代码如下:

public class KeyguardViewMediator extends SystemUI {

    private PowerManager.WakeLock mShowKeyguardWakeLock;
    private void setupLocked() {
        // 获取了PARTIAL_WAKE_LOCK锁,即不受电源键控制,即使按下电源键也不能使系统进入休眠状态
        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
        mShowKeyguardWakeLock.setReferenceCounted(false);
    }

    private void showLocked(Bundle options) {

        // 获取PARTIAL_WAKE_LOCK
        mShowKeyguardWakeLock.acquire();
    }

    private void handleShow(Bundle options) {

        synchronized (KeyguardViewMediator.this) {
            // 释放PARTIAL_WAKE_LOCK
            mShowKeyguardWakeLock.release();
        }
    }
}
handleShow()
既然是Handler Message机制,那我们就要去看一下mHandler类实例是如何处理SHOW类型的消息了。mHandle处理SHOW类型消息的方法如下:

public class KeyguardViewMediator extends SystemUI {

    private Handler mHandler = new Handler(Looper.myLooper(), null /*callback*/, true /*async*/) {
       
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SHOW:
                    handleShow((Bundle) msg.obj);
            }
        }
    }

    private void handleShow(Bundle options) {

        synchronized (KeyguardViewMediator.this) {
            if (!mSystemReady) {
                // 系统未Ready,则不呈现锁屏
                return;
            } else {
                if (DEBUG) Log.d(TAG, "handleShow");
            }

            setShowingLocked(true);

            // 展示锁屏界面
            mStatusBarKeyguardViewManager.show(options);
            mHiding = false;
            resetKeyguardDonePendingLocked();
            mHideAnimationRun = false;
            updateActivityLockScreenState();
            adjustStatusBarLocked();
            userActivity();

            // Do this at the end to not slow down display of the keyguard.

            playSounds(true);

            mShowKeyguardWakeLock.release();

        }
        mKeyguardDisplayManager.show();
    }
}
针对这个方法,有几个重点需要强调一下。

重点一

Android5.1和Android4.4锁屏机制展示的区别?

解答:在Android5.1中,keyguard本身不再是一个独立的apk,而是跟SystemUI进行了合并,作为SystemUI的静态库进行调用。对比Android5.1和Android4.4的SystemUI模块的Android.mk文件可以更加直观的对比。

Android5.1 SystemUI Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java--files-under, src)

# 指定Keyguard作为静态库

LOCAL_STATIC_JAVA_LIBRARIES := Keyguard

LOCAL_JAVA_LIBRATIES := telephony-common

# 指定名称
LOCAL_PACKAGE_NAME := SystemUI
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_RESOURCE_DIR := \
    frameworks/base/packages/Keyguard/res \
    $(LOCAL_PATH)/res
LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.keyguard
# 编译成apk
include $(BUILD_PACKAGE)
Android4.4 SystemUI Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
    src/com/android/systemui/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_PACKAGE_NAME := SystemUI
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
include $(BUILD_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
所以,系统调试锁屏,只需要单独编译SystemUI模块,然后替换SystemUI.apk即可。

重点二

如何替换系统锁屏,改为我们的锁屏应用?

解答:个人认为,如果能够修改SystemUI方法,那最好就是重载handleShow()方法,在这个方法中实现我们自己的锁屏界面。例如通过Activity跳转,别忘了释放PARTIAL_WEAK_LOCK。

重载这个方法,可以最大程度的不影响Android系统逻辑(ps:个人意见,大家有更好的办法可以指点我)。

StatusBarKeyguardViewManager

位置:

framework/base/package/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java

分析这个类,我们肯定是先从show方法开始入手。

show()

show方法的源码如下:

public class StatusBarKeyguardViewManager {

    public void show(Bundle options) {
        // 设置keguard是否显示的标志
        mShowing = true;
        mStatusBarWindowManager.setKeyguardShowing(true);
        // 重置view的状态,进行keyguard锁屏显示
        reset();
    }
}
reset()
源码如下:

public class StatusBarKeyguardViewManager {

    public void reset() {
        Log.e("TAG", "mShowing:" + mShowing + ", mOccluded:" + mOccluded);
        if (mShowing) {
            if (mOccluded) {
                mPhoneStatusBar.hideKeyguard();
                mBouncer.hide(false /* destroyView */);
            } else {
                // 判断是调用安全锁屏还是调用滑动锁屏
                showBouncerOrKeyguard();
            }
            updateStates();
        }
    }
}
showBouncerOrKeyguard()
public class StatusBarKeyguardViewManager {
    private void showBouncerOrKeyguard() {
        if (mBouncer.needsFullscreenBouncer()) {

            // The keyguard might be showing (already). So we need to hide it.

            mPhoneStatusBar.hideKeyguard();
            mBouncer.show(true);
        } else {
            mPhoneStatusBar.showKeyguard();
            mBouncer.hide(false);
            mBouncer.prepare();
        }
    }
}
接下来,就是view展示的过程了。其中,mBouncer是用来显示安全锁屏,例如图案、密码、PIN码等。有兴趣的同学可以继续跟踪一下mBouncer的展示或者mPhoneStatusBar的展示过程。

设置开机默认无keyguard

阅读数 58

设置开机默认无keyguard文章目录设置开机默认无keyguard1.Description2.Analysis3.solution4.summary1.Description默认情况下keygua...

博文
 

转载地址:http://apvmf.baihongyu.com/

你可能感兴趣的文章
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>
散落人间知识点记录one
查看>>
Leetcode C++ 随手刷 547.朋友圈
查看>>
手抄笔记:深入理解linux内核-1
查看>>
内存堆与栈
查看>>
Leetcode C++《每日一题》20200621 124.二叉树的最大路径和
查看>>
Leetcode C++《每日一题》20200622 面试题 16.18. 模式匹配
查看>>
Leetcode C++《每日一题》20200625 139. 单词拆分
查看>>
Leetcode C++《每日一题》20200626 338. 比特位计数
查看>>
Leetcode C++ 《拓扑排序-1》20200626 207.课程表
查看>>
Go语言学习Part1:包、变量和函数
查看>>
Go语言学习Part2:流程控制语句:for、if、else、switch 和 defer
查看>>
Go语言学习Part3:struct、slice和映射
查看>>
Go语言学习Part4-1:方法和接口
查看>>
Leetcode Go 《精选TOP面试题》20200628 69.x的平方根
查看>>
leetcode 130. Surrounded Regions
查看>>
【Python】详解Python多线程Selenium跨浏览器测试
查看>>
Jmeter之参数化
查看>>
Shell 和Python的区别。
查看>>