Android: Keyguard分析之一:开机流程篇

Keyguard 与 SystemUI运行在同一进程中,即com.android.systemui进程。这点可以从manifest.xml文件就可以看出:

# Keyguard Android.mk
    
    <application android:label="@string/app_name"
        android:process="com.android.systemui"
        android:persistent="true"
        android:supportsRtl="true"
        android:defaultToDeviceProtectedStorage="true"
        android:directBootAware="true">
        
        
# SystemUI Android.mk

<application
        android:name=".SystemUIApplication"
        android:persistent="true"
        android:allowClearUserData="false"
        android:allowBackup="false"
        android:hardwareAccelerated="true"
        android:label="@string/app_label"
        android:icon="@drawable/icon"
        android:process="com.android.systemui"
        android:supportsRtl="true"
        android:theme="@style/systemui_theme"
        android:defaultToDeviceProtectedStorage="true"
        android:directBootAware="true">

通过Android.mk可知:在编译过程中,keyguard被打包成静态Java库. Keygaurd实际是由SystemUI来管理的.

# Keyguard Android.mk

include $(BUILD_STATIC_JAVA_LIBRARY)

# SystemUI:

LOCAL_STATIC_JAVA_LIBRARIES := \
    com.mediatek.systemui.ext \
    Keyguard \

 

开机时, keyguard视图的绘制流程
 

开机,  Keyguard视图的形成过程:伴随着系统的启动,SystemServer将启动各种服务.对于Keyguard的服务而言.首先从startOtherServices()方法开始.

# SystemServer.java  

    private void startOtherServices() {
         ...
       wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
        ...
        try {
            wm.systemReady();
        } catch (Throwable e) {
            reportWtf("making Window Manager Service ready", e);
        }
}

因为开机需要对Keyguard的视图进行绘制, 所以进入到了WindowManagerService服务中(对系统中的所有窗口进行管理是窗口管理服务WindowManagerService的职责).在WindowManagerService.java中直接调用了WindowManagerPolicy.java的systemReady()方法,而具体方法的实现在PhoneWindowManager.java中。

# PhoneWindowManager.java

public void systemReady() {
        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
        mKeyguardDelegate.onSystemReady(); //分派到KeyguardDelegate进行处理,开机时不做任何处理.
        ...
        synchronized (mLock) {
            ...
            bindKeyguardNow = mDeferBindKeyguard;
            if (bindKeyguardNow) {
                // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
                mDeferBindKeyguard = false;
            }
        }

        if (bindKeyguardNow) {//如果已经绑定KeyguardService,进行处理.
            mKeyguardDelegate.bindService(mContext);
            mKeyguardDelegate.onBootCompleted();
        }
        ...
    }

在进入KeyguardServiceDelegate.java, 将绑定keyguardService服务.

private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
                ...
                mKeyguardService.onSystemReady();
                ...
        }
     ...
    };

可以发现 mKeyguardDelegate.onSystemReady()进入到了KeyguardServiceWrapper,并将任务分派到KeyguardService,启动Keyguard服务.

# KeyguardServiceWrapper.java

public class KeyguardServiceWrapper implements IKeyguardService {}



# KeyguardService.java

   private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {   
        public void onSystemReady() {
            checkPermission(); //权限的检查.
            mKeyguardViewMediator.onSystemReady();
        }
    }

可以看出,其实这两个类就是跨进程通信.通过IKeyguardService这个接口来进行framework与Systemui之间的跨进程通信.此时,流程就进入到了SystemUI.


进入SystemUI这个应用后, 将进入Keyguard的一个重要的类KeyguardViewMediator.先看看调用的方法.该方法主要是进行广播:标志这系统在启动后已经准备好了.接着,doKeyguardLocked()方法收到了null参数. 可以看到这个方法主要是针对不同的keyguard模式进行判别.

# KeyguardViewMediator.java
    //Let us know that the system is ready after startup.
    public void onSystemReady() {
        mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
        synchronized (this) {
            ...
            mSystemReady = true;
            doKeyguardLocked(null); //锁屏路径
            mUpdateMonitor.registerCallback(mUpdateCallback);
            mPowerOffAlarmManager.onSystemReady();
        }
        mIsPerUserLock = StorageManager.isFileEncryptedNativeOrEmulated();
        // Most services aren't available until the system reaches the ready state, so we
        // send it here when the device first boots.
        maybeSendUserPresentBroadcast();
    }
    
    
    private void doKeyguardLocked(Bundle options) {
        // if another app is disabling us, don't show
        if (!mExternallyEnabled) {//外置apk的keyguard等
            return;
        }

        // if the keyguard is already showing, don't bother
        if (mStatusBarKeyguardViewManager.isShowing()) {
            resetStateLocked();
            return;
        }
        ...

        //doKeyguard: not showing because device isn't provisioned
        //and the sim is not locked or missing
        if (!lockedOrMissing && shouldWaitForProvisioning() && !antiTheftLocked) {
            return;
        }
        //doKeyguard: not showing because lockscreen is off
        if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
            && !lockedOrMissing && !antiTheftLocked) {
            return;
        }
        //解密后的状态也不显示keyguard.
        if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())
            && KeyguardUtils.isSystemEncrypted()) {
           
            setShowingLocked(false);
            hideLocked();
            mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
              return;
        }
        ...
        showLocked(options);
    }
    
     private void showLocked(Bundle options) {
        setReadyToShow(true) ;设置参数.
        updateActivityLockScreenState();//更新锁屏状态,使用进程间通信技术
        // ensure we stay awake until we are finished displaying the keyguard
        mShowKeyguardWakeLock.acquire(); //获取唤醒锁.不受电源影响,不让cpu进入休眠状态.
        Message msg = mHandler.obtainMessage(SHOW, options);
        mHandler.sendMessage(msg); //使用handler子线程来处理显示
    }
    
    private void handleShow(Bundle options) {
        final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
        if (mLockPatternUtils.isSecure(currentUser)) {
            mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
        }
        synchronized (KeyguardViewMediator.this) {
            setShowingLocked(true);
            mStatusBarKeyguardViewManager.show(options);//keyguard的显示.
            mHiding = false;
            mWakeAndUnlocking = false;
            resetKeyguardDonePendingLocked();
            ///M: reset mReadyToShow
            setReadyToShow(false) ;
            mHideAnimationRun = false;
            updateActivityLockScreenState();
            adjustStatusBarLocked();
            userActivity();
            mShowKeyguardWakeLock.release();
        }

        if (mKeyguardDisplayManager != null) {
            mKeyguardDisplayManager.show();
        } 
    }

最后跳转到Keyguard中去显示.通过开机时的log,亦发现开机显示keyguard的一瞬间,打印出了"show". 

# KeyguardDisplayManager.java

    public void show() {
        if (!mShowing) {
            ...
            mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
                    mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
            updateDisplays(true);
        }
        mShowing = true;
    }

现在显示keyguard的流程就结束了.当然这个流程显示的是 ++滑动进入锁屏界面前的那个界面++.

<br/>

再来看看mStatusBarKeyguardViewManager.show(options).

# StatusBarKeyguardViewManager.java

    public void show(Bundle options) {
        mShowing = true;
        mStatusBarWindowManager.setKeyguardShowing(true);
        mScrimController.abortKeyguardFadingOut();
        reset();
    }

reset()这个方法判断显示状态,再进行处理

# StatusBarKeyguardViewManager.java

    public void reset() {
        ...
        if (mShowing) {
            if (mOccluded) {//是否被其他窗口中断
                mPhoneStatusBar.hideKeyguard();
                mPhoneStatusBar.stopWaitingForKeyguardExit();
                mBouncer.hide(false /* destroyView */);
            } else {
                showBouncerOrKeyguard();//滑动锁或Keyguard锁.
            }
            KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
            updateStates();
        }
    }
    // showBouncerOrKeyguard()方法使用KeyguardBouncer.java的needsFullscreenBo
    // uncer()方法判断显示常规锁屏还是Bouncer安全锁屏(比如图案锁屏、密码锁屏
    // PIN码锁屏等);

    protected void showBouncerOrKeyguard() {//判断锁使用的锁的类型.
        ...
        if (mBouncer.needsFullscreenBouncer()) {
            // The keyguard might be showing (already). So we need to hide it.
            mPhoneStatusBar.hideKeyguard();
            mBouncer.show(true /* resetSecuritySelection */);
        } else {
            mPhoneStatusBar.showKeyguard();
            mBouncer.hide(false /* destroyView */);
            mBouncer.prepare();
        }
    }

看看mBouncer是哪几种keyguard.这类被称为: Bouncer安全锁屏, 包括: PIM码 , PUK码等锁屏方式的锁屏界面,这类所直接在systemui中处理了.通过KeyguardBouncer.java来开始控制show()和hide();

# KeyguardBouncer.java

    public boolean needsFullscreenBouncer() {
        ...
        return mode == SecurityMode.SimPinPukMe1
                || mode == SecurityMode.SimPinPukMe2
                || mode == SecurityMode.SimPinPukMe3
                || mode == SecurityMode.SimPinPukMe4
                || mode == SecurityMode.AntiTheft
                || mode == SecurityMode.AlarmBoot;
    }
    

# KeyguardSecuritymodel.java

    public enum SecurityMode {
        Invalid, // NULL state
        None, // No security enabled
        Pattern, // Unlock by drawing a pattern.
        Password, // Unlock by entering an alphanumeric password
        PIN, // Strictly numeric password
        // SimPin, // Unlock by entering a sim pin.
        // SimPuk, // Unlock by entering a sim puk
        SimPinPukMe1, // Unlock by entering a sim pin/puk/me for sim or gemini sim1.
        SimPinPukMe2, // Unlock by entering a sim pin/puk/me for sim or gemini sim2.
        SimPinPukMe3, // Unlock by entering a sim pin/puk/me for sim or gemini sim3.
        SimPinPukMe4, // Unlock by entering a sim pin/puk/me for sim or gemini sim4.
        AlarmBoot, // add for power-off alarm.
        Biometric,  // Unlock with a biometric key (e.g. voice unlock)
        Voice, // Unlock with voice password
        AntiTheft // Antitheft feature
    }


则其他为一般解锁, 其将进入到Keyguard中去进行处理. 称为:notification keyguard, 包括 品pattern, password,PIN,None(滑动解锁).这中解锁方式有个特点:在进入解锁界面前,会出现我们之前分析的界面, ++滑动进入锁屏界面前的那个界面++. 这种keyguard的视图的父视图为KeyguardSecurityContainer.

<br/>

接着,还是进入KeyguardBouncer进行keyguard视图的绘制.

# KeyguardBouncer.java

    public void prepare() {
        ...
        if (wasInitialized) {
            mKeyguardView.showPrimarySecurityScreen();
        }
        ...
    }

之后直接跳到了KeyguardHostView.java,并传入了false参数, 进入到KeyguardSecurityContainer.java. 

# KeyguardSecurityContainer.java

    void showPrimarySecurityScreen(boolean turningOff) {
        ...
        showSecurityScreen(securityMode);
    }

最后根据不同的keyguard的模式来进行界面的重绘

# KeyguardSecurityContainer.java

private void showSecurityScreen(SecurityMode securityMode) {
        ...
        mCurrentSecuritySelection) ;
        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
        Log.d(TAG, "showSecurityScreen() - get newview for" + securityMode) ;
        KeyguardSecurityView newView = getSecurityView(securityMode);
        ...
    }

通过该方法通过传入的mode来绘制出相应的keyguard视图.

# KeyguardSecurityContainer.java 

    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
        ...
        int layoutId = getLayoutIdFor(securityMode);//通过mode选择对应的keyguard的view视图.
        if (view == null && layoutId != 0) {
            final LayoutInflater inflater = LayoutInflater.from(mContext);
            
            View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);
            view = (KeyguardSecurityView) v;
            ...
            mSecurityViewFlipper.addView(v);
            updateSecurityView(v);
            // view = (KeyguardSecurityView)v;
        }
        ...
        return view;
    }

在完成一系列的绘制视图工作后.

<br/>

1. 从SystemServer开始, 通过WindowManagerPolicy进入到KeyguardServiceDelegate.
2. KeyguardServiceDelegate绑定KeyService服务,此时进入到SystemUI.并调用KeyguardViewMediator决定是否显示视图.
3. 若显示视图,将StatusBarKeyguardViewManager来重置,并进入到KeyguardBouncer.
4. 最后进入到KeyguardSecurityContainer,根据不同的模式绘制不同的keyguard视图.

---

> KeyguardServiceDelegate.java 继承了接口IKeyguardService; 同时KeyguardService完成了IKeyguardService的远程实现. 即这两个类通过底层aidl进行远程通信. 进入系统可以控制Keyguard服务的启动.

> KeyguardServiceDelegate.java 是一个局部类,保存keyguard在崩溃之前的状态,用来恢复. 同时它也可以运行时选择本地或远程的keyguard实例.

> KeyguardViewMediator.java 作为一个中介类, 连接Keyguard与Systemui.其职能包括查询keyguard的状态, Keyguard在开关键的事件的动作,如显示或重置等.

> KeyguardSecurityContainer.java 这个类主要用于装载Pattern, password, pin等解锁视图的容器.

> KeyguardUpdateMonitor.java 类似于一个监视器, 用于监听keyguard的更新变化. 

> StatusBarKeyguardViewManger.java 在status bar中, 管理创建, 显示, 隐藏, 重置 状态栏中的 Keyguard.

---

<br/>

现在根据上述流程, 打印log, 来验证流程的正确性.

```
01-03 21:49:03.050   698   698 D @ying   : SystemServer.startOtherservices.wm.systemReady begin
01-03 21:49:03.050   698   698 D @ying   : PhoneWindowManager.systemReady begin
01-03 21:49:03.051   698   698 D @ying   : PhoneWindowManager.systemReady end
01-03 21:49:03.054   698   698 D @ying   : SystemServer.startOtherservices.wm.systemReady end
01-03 21:49:06.938   698   725 D @ying   : KeyguardServiceDelegate.mKeyguardConnection begin
01-03 21:49:06.942   698   725 D @ying   : KeyguardServiceDelegate.mKeyguardConnection:mKeyguardState.systemIsReady begin
01-03 21:49:06.942   698   725 D @ying   : KeyguardServiceWrapper.onSystemReady begin
01-03 21:49:06.942   698   725 D @ying   : KeyguardServiceWrapper.onSystemReady end
01-03 21:49:06.942   698   725 D @ying   : KeyguardServiceDelegate.mKeyguardConnection:mKeyguardState.systemIsReady begin
01-03 21:49:06.943   698   725 D @ying   : KeyguardServiceDelegate.mKeyguardConnection begin
01-03 21:49:06.945   935  1204 D @ying   : KeyguardService.onSystemReady begin
01-03 21:49:06.945   935  1204 D @ying   : KeyguardViewMediator.onSystemReady begin
01-03 21:49:06.958   935  1204 D @ying   : KeyguardViewMediator.doKeyguardLocked begin
01-03 21:49:06.958   935  1204 D @ying   : KeyguardViewMediator.showLocked begin
01-03 21:49:06.965   935  1204 D @ying   : KeyguardViewMediator.showLocked end
01-03 21:49:06.966   935  1204 D @ying   : KeyguardViewMediator.doKeyguardLocked end
01-03 21:49:06.966   935  1204 D @ying   : KeyguardViewMediator.onSystemReady begin
01-03 21:49:06.976   935  1204 D @ying   : KeyguardService.onSystemReady end
01-03 21:49:07.104   935   935 D @ying   : KeyguardViewMeditor.handleShow begin
01-03 21:49:07.104   935   935 D @ying   : StatusBarKeyguardViewManager.show begin
01-03 21:49:07.105   935   935 D @ying   : StatusBarKeyguardViewManager.reset begin
01-03 21:49:07.105   935   935 D @ying   : StatusBarKeyguardViewManager.reset:mOccluded-false begin
01-03 21:49:07.105   935   935 D @ying   : StatusBarKeyguardViewManager.showBouncerOrKeyguard begin
01-03 21:49:07.118   935   935 D @ying   : KeyguardSecurityContainer.showPrimarySecurityScreen begin
01-03 21:49:07.120   935   935 D @ying   : KeyguardSecurityContainer.showPrimarySecurityScreen:showSecurityScreen
01-03 21:49:07.121   935   935 D @ying   : KeyguardSecurityContainer.showSecurityScreen begin
01-03 21:49:07.122   935   935 D @ying   : KeyguardSecurityContainer.showSecurityScreen newView begin
01-03 21:49:07.202   935   935 D @ying   : KeyguardSecurityContainer.showSecurityScreen newView end
01-03 21:49:07.225   935   935 D @ying   : KeyguardSecurityContainer.showSecurityScreen end
01-03 21:49:07.225   935   935 D @ying   : KeyguardSecurityContainer.showPrimarySecurityScreen end
01-03 21:49:07.336   935   935 D @ying   : needsFullscreenBouncer() is false,show "Notification Keyguard" view.
01-03 21:49:07.397   935   935 D @ying   : KeyguardBouncer.prepare begin
01-03 21:49:07.397   935   935 D @ying   : KeyguardBouncer.prepare:wasInitialized
01-03 21:49:07.398   935   935 D @ying   : KeyguardSecurityContainer.showPrimarySecurityScreen begin
01-03 21:49:07.401   935   935 D @ying   : KeyguardSecurityContainer.showPrimarySecurityScreen:showSecurityScreen
01-03 21:49:07.401   935   935 D @ying   : KeyguardSecurityContainer.showSecurityScreen begin
01-03 21:49:07.401   935   935 D @ying   : KeyguardSecurityContainer.showPrimarySecurityScreen end
01-03 21:49:07.422   935   935 D @ying   : KeyguardBouncer.prepare end
01-03 21:49:07.422   935   935 D @ying   : StatusBarKeyguardViewManager.showBouncerOrKeyguard end
01-03 21:49:07.422   935   935 D @ying   : StatusBarKeyguardViewManager.reset:mOccluded-false end
01-03 21:49:07.442   935   935 D @ying   : StatusBarKeyguardViewManager.reset end
01-03 21:49:07.443   935   935 D @ying   : StatusBarKeyguardViewManager.show end
01-03 21:49:07.443   935   935 D @ying   : KeyguardViewMeditor.handleShow end
01-03 21:49:07.451   935   935 D @ying   : KeyguardViewMediator.handleShow:mKeyguardDisplayManager begin
01-03 21:49:07.451   935   935 D @ying   : KeyguardViewMediator.handleShow:mKeyguardDisplayManager end

```

从 Log 日志再来梳理一遍开机时, Keyguard的流程走向.

>1. 开机, 完成开机动画后, SystemServer这个系统服务线程由底层开启, 该系统服务将开启一系列的服务, 其中Keyguard的流程会流到WindowManagerPolicy进行处理.

>2. WindowManagerPolicy的实现类是PhoneWindowManager. 其将 keyguard 事件分发到 KeyguardServiceDelegate进行处理.

>3. KeyguardServiceDelegate 开启了Keyguard服务, IkeyguardService由KeyguardServiceWrapper包装类继承,由KeyguardService远程实现. 实现底层与Systemui的通信,保证两者之间数据共享.

>4. keyguard事件传递到了SystemUI, 并由KeyguardViewMediator进行事件的分派. 如部分视图由SystemUI显示,即如StatusBarKeyguardViewManager来处理.  部分视图将传递到Keyguard,由Keyguard来绘制, 如 KeyguardSecurityContainer来处理.

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值