Android 7.1.1 鎖屏界面啟動流程介紹

Android 7.1.1 鎖屏界面啟動流程介紹,前幾天遇到一個低概率復現鎖屏界面不顯示,隻顯示狀態欄的問題,跟瞭下鎖屏界面啟動顯示的流程,在這分享下,也方便以後自己查看。前面簡單介紹瞭下Zygote啟動流程,Zygote進程啟動後會首先創建一個SystemServer進程,SystemServer進程在調用startOtherServices同時也會調用WindowManagerService的systemReady()方法

[java]view plaincopy

//frameworks/base/services/java/com/android/server/SystemServer.java

privatevoidstartOtherServices(){

wm=WindowManagerService.main(context,inputManager,

mFactoryTestMode!=FactoryTest.FACTORY_TEST_LOW_LEVEL,

!mFirstBoot,mOnlyCore);

try{

wm.systemReady();

Slog.i("jason11","SystemServerwm.systemReady");

}catch(Throwablee){

reportWtf("makingWindowManagerServiceready",e);

}

}

在WindowManagerService中直接調用瞭PhoneWindowManager裡的systemReady()

[java]view plaincopy

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

//finalWindowManagerPolicymPolicy=newPhoneWindowManager();

publicvoidsystemReady(){

mPolicy.systemReady();

} 在PhoneWindowManager的systemReady()會根據一個Boolean值bindKeyguardNow來決定是否綁定keyguard service

[java]view plaincopy

//frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

/**{@inheritDoc}*/

@Override

publicvoidsystemReady(){

mKeyguardDelegate=newKeyguardServiceDelegate(mContext);

mKeyguardDelegate.onSystemReady();

readCameraLensCoverState();

updateUiMode();

booleanbindKeyguardNow;

synchronized(mLock){

updateOrientationListenerLp();

mSystemReady=true;

mHandler.post(newRunnable(){

@Override

publicvoidrun(){

updateSettings();

}

});

bindKeyguardNow=mDeferBindKeyguard;

if(bindKeyguardNow){

//systemBootedranbutwasn'tabletobindtotheKeyguard,we'lldoitnow.

mDeferBindKeyguard=false;

}

}

if(bindKeyguardNow){

mKeyguardDelegate.bindService(mContext);

mKeyguardDelegate.onBootCompleted();

}

mSystemGestures.systemReady();

}

看到這裡,可能會想到如果bindKeyguardNow為false就會不綁定,後面通過繼續跟蹤發現在PhoneWindowManager的systemBooted()裡也會去綁定keyguard service,如果在systemBooted裡綁定瞭就不在systemReady裡再去綁定,自己測試的時候是在systemBooted綁定的

[java]view plaincopy

//frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

/**{@inheritDoc}*/

@Override

publicvoidsystemBooted(){

booleanbindKeyguardNow=false;

synchronized(mLock){

//TimetobindKeyguard;takecaretoonlybinditonce,eitherhereifreadyor

//insystemReadyifnot.

if(mKeyguardDelegate!=null){

bindKeyguardNow=true;

}else{

//BecausemKeyguardDelegateisnull,weknowthatthesynchronizedblockin

//systemReadydidn'trunyetandsettingthiswillactuallyhaveaneffect.

mDeferBindKeyguard=true;

}

}

if(bindKeyguardNow){

mKeyguardDelegate.bindService(mContext);

mKeyguardDelegate.onBootCompleted();

}

synchronized(mLock){

mSystemBooted=true;

}

startedWakingUp();

screenTurningOn(null);

screenTurnedOn();

}

下面就通過如下的時序圖看看是如何調用到systemBooted的,就不在一步步跟瞭

 

 

通過上面的分析知道,無論是在systemReady或systemBooted,都調用瞭KeyguardServiceDelegate對象的bindService方法,下面就以這個方法開始,看看鎖屏界面是怎麼顯示出來的,先看看下面的時序圖,再來分步講解

 

 

1、先來看看在KeyguardServiceDelegate如何綁定KeyguardService的

[java]view plaincopy

//frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java

publicclassKeyguardServiceDelegate{

publicvoidbindService(Contextcontext){

Intentintent=newIntent();

finalResourcesresources=context.getApplicationContext().getResources();

finalComponentNamekeyguardComponent=ComponentName.unflattenFromString(

resources.getString(com.android.internal.R.string.config_keyguardComponent));

intent.setComponent(keyguardComponent);

if(!context.bindServiceAsUser(intent,mKeyguardConnection,

Context.BIND_AUTO_CREATE,UserHandle.OWNER)){

Log.v(TAG,"***Keyguard:can'tbindto"+keyguardComponent);

mKeyguardState.showing=false;

mKeyguardState.showingAndNotOccluded=false;

mKeyguardState.secure=false;

synchronized(mKeyguardState){

//TODO:Fixsynchronisationmodelinthisclass.Theotherstateinthisclass

//isatleastself-healingbutaraceconditionherecanleadtothescrimbeing

//stuckonkeyguard-lessdevices.

mKeyguardState.deviceHasKeyguard=false;

hideScrim();

}

}else{

if(DEBUG)Log.v(TAG,"***Keyguardstarted");

}

}

} 在bindService中調用瞭bindServiceAsUser綁定指定intent的service,config_keyguardComponent的定義如下

[html]view plaincopy

//frameworks/base/core/res/res/values/config.xml

com.android.systemui/com.android.systemui.keyguard.KeyguardService 當綁定成功後會調用mKeyguardConnection裡的onServiceConnected方法

[java]view plaincopy

//frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java

publicclassKeyguardServiceDelegate{

privatefinalServiceConnectionmKeyguardConnection=newServiceConnection(){

@Override

publicvoidonServiceConnected(ComponentNamename,IBinderservice){

if(DEBUG)Log.v(TAG,"***Keyguardconnected(yay!)");

mKeyguardService=newKeyguardServiceWrapper(mContext,

IKeyguardService.Stub.asInterface(service));

if(mKeyguardState.systemIsReady){

//Ifthesystemisready,itmeanskeyguardcrashedandrestarted.

mKeyguardService.onSystemReady();

//Thisisusedtohidethescrimoncekeyguarddisplays.

if(mKeyguardState.interactiveState==INTERACTIVE_STATE_AWAKE){

mKeyguardService.onStartedWakingUp();

}

if(mKeyguardState.screenState==SCREEN_STATE_ON

||mKeyguardState.screenState==SCREEN_STATE_TURNING_ON){

mKeyguardService.onScreenTurningOn(

newKeyguardShowDelegate(mDrawnListenerWhenConnect));

}

if(mKeyguardState.screenState==SCREEN_STATE_ON){

mKeyguardService.onScreenTurnedOn();

}

mDrawnListenerWhenConnect=null;

}

if(mKeyguardState.bootCompleted){

mKeyguardService.onBootCompleted();

}

if(mKeyguardState.occluded){

mKeyguardService.setOccluded(mKeyguardState.occluded);

}

}

@Override

publicvoidonServiceDisconnected(ComponentNamename){

if(DEBUG)Log.v(TAG,"***Keyguarddisconnected(boo!)");

mKeyguardService=null;

}

};

} 當mKeyguardState.systemIsReady為true是,就會通過KeyguardServiceWrapper的實例mKeyguardService調用onSystemReady方法,在KeyguardServiceWrapper的onSystemReady裡調用瞭上面剛剛綁定成功的KeyguardService的onSystemReady方法

[java]view plaincopy

//frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java

publicclassKeyguardServiceWrapperimplementsIKeyguardService{

@Override//Binderinterface

publicvoidonSystemReady(){

try{

mService.onSystemReady();

}catch(RemoteExceptione){

Slog.w(TAG,"RemoteException",e);

}

}

}

在KeyguardService的onSystemReady裡調用瞭KeyguardViewMediator裡的onSystemReady,在這裡就不貼這個代碼瞭,直接看看KeyguardViewMediator.onSystemReady這個裡面幹啥瞭

2、KeyguardViewMediator.onSystemReady

[java]view plaincopy

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

publicclassKeyguardViewMediatorextendsSystemUI{

publicvoidonSystemReady(){

mSearchManager=(SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE);

synchronized(this){

if(DEBUG)Log.d(TAG,"onSystemReady");

mSystemReady=true;

doKeyguardLocked(null);

mUpdateMonitor.registerCallback(mUpdateCallback);

}

//Mostservicesaren'tavailableuntilthesystemreachesthereadystate,sowe

//senditherewhenthedevicefirstboots.

maybeSendUserPresentBroadcast();

}

} 在這個方法裡主要調用瞭doKeyguardLocked和註冊瞭KeyguardUpdateMonitorCallback

3、通過調用doKeyguardLocked顯示鎖屏界面

[java]view plaincopy

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

publicclassKeyguardViewMediatorextendsSystemUI{

privatevoiddoKeyguardLocked(Bundleoptions){

//ifanotherappisdisablingus,don'tshow

if(!mExternallyEnabled){

if(DEBUG)Log.d(TAG,"doKeyguard:notshowingbecauseexternallydisabled");

//note:we*should*setmNeedToReshowWhenReenabled=truehere,butthatmakes

//foranoccasionaluglyflickerinthissituation:

//1)receiveacallwiththescreenon(nokeyguard)ormakeacall

//2)screentimesout

//3)userhitskeytoturnscreenbackon

//instead,wereenablethekeyguardwhenweknowthescreenisoffandthecall

//ends(seethebroadcastreceiverbelow)

//TODO:cleanthisupwhenwehavebettersupportatthewindowmanagerlevel

//forappsthatwishtobeontopofthekeyguard

return;

}

//ifthekeyguardisalreadyshowing,don'tbother

if(mStatusBarKeyguardViewManager.isShowing()){

if(DEBUG)Log.d(TAG,"doKeyguard:notshowingbecauseitisalreadyshowing");

resetStateLocked();

return;

}

//ifthesetupwizardhasn'trunyet,don'tshow

finalbooleanrequireSim=!SystemProperties.getBoolean("keyguard.no_require_sim",false);

finalbooleanabsent=SubscriptionManager.isValidSubscriptionId(

mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.ABSENT));

finalbooleandisabled=SubscriptionManager.isValidSubscriptionId(

mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));

finalbooleanlockedOrMissing=mUpdateMonitor.isSimPinSecure()

||((absent||disabled)&&requireSim);

if(!lockedOrMissing&&shouldWaitForProvisioning()){

if(DEBUG)Log.d(TAG,"doKeyguard:notshowingbecausedeviceisn'tprovisioned"

+"andthesimisnotlockedormissing");

return;

}

if(mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())

&&!lockedOrMissing){

if(DEBUG)Log.d(TAG,"doKeyguard:notshowingbecauselockscreenisoff");

return;

}

if(mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())){

if(DEBUG)Log.d(TAG,"Notshowinglockscreensincejustdecrypted");

//Withoutthis,settingsisnotenableduntilthelockscreenfirstappears

setShowingLocked(false);

hideLocked();

mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();

return;

}

if(DEBUG)Log.d(TAG,"doKeyguard:showingthelockscreen");

showLocked(options);

}

} 這段代碼主要是在是否要顯示鎖屏之前做瞭5個判斷:1.如果啟用第三方鎖屏界面,不顯示原生界面;2.鎖屏界面已經顯示瞭話,重新更新下狀態;3.如果第一次開機引導界面setup wizard還沒有運行,也先不顯示;4.屏幕沒有亮不顯示;5.當前正在解密界面不顯示。如果這幾個條件都不滿足,則調用showLocked顯示鎖屏界面。在showLocked通過mHandler發送Message,在handleMessage裡“case SHOW:”時調用handleShow

4、在handleShow裡設置一些鎖屏狀態和顯示鎖屏界面

[java]view plaincopy

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

publicclassKeyguardViewMediatorextendsSystemUI{

privatevoidhandleShow(Bundleoptions){

synchronized(KeyguardViewMediator.this){

if(!mSystemReady){

if(DEBUG)Log.d(TAG,"ignoringhandleShowbecausesystemisnotready.");

return;

}else{

if(DEBUG)Log.d(TAG,"handleShow");

}

setShowingLocked(true);

mStatusBarKeyguardViewManager.show(options);

mHiding=false;

mWakeAndUnlocking=false;

resetKeyguardDonePendingLocked();

mHideAnimationRun=false;

updateActivityLockScreenState();

adjustStatusBarLocked();

userActivity();

mShowKeyguardWakeLock.release();

}

mKeyguardDisplayManager.show();

}

}

5、通過調用StatusBarKeyguardViewManager的show重置當前狀態顯示keyguard

[java]view plaincopy

//frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java

publicclassStatusBarKeyguardViewManager{

publicvoidshow(Bundleoptions){

mShowing=true;

mStatusBarWindowManager.setKeyguardShowing(true);

mScrimController.abortKeyguardFadingOut();

reset();

}

} 在reset裡調用本類的showBouncerOrKeyguard,在這個方法裡通過KeyguardBouncer的實例mBouncer調用prepare(),在prepare裡調用瞭KeyguardHostView的showPrimarySecurityScreen

6、KeyguardSecurityContainer.showPrimarySecurityScreen

在KeyguardHostView的showPrimarySecurityScreen裡調用KeyguardSecurityContainer的showPrimarySecurityScreen方法,如下

[java]view plaincopy

//frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java

publicclassKeyguardSecurityContainerextendsFrameLayoutimplementsKeyguardSecurityView{

voidshowPrimarySecurityScreen(booleanturningOff){

SecurityModesecurityMode=mSecurityModel.getSecurityMode();

if(DEBUG)Log.v(TAG,"showPrimarySecurityScreen(turningOff="+turningOff+")");

showSecurityScreen(securityMode);

}

} 在這個方法裡調用瞭showSecurityScreen,根據mSecurityModel.getSecurityMode()獲取的SecurityMode來顯示不同界面,SecurityMode定義如下

[java]view plaincopy

//frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java

publicclassKeyguardSecurityModel{

publicenumSecurityMode{

Invalid,//NULLstate

None,//Nosecurityenabled

Pattern,//Unlockbydrawingapattern.

Password,//Unlockbyenteringanalphanumericpassword

PIN,//Strictlynumericpassword

SimPin,//Unlockbyenteringasimpin.

SimPuk//Unlockbyenteringasimpuk

}

}

showSecurityScreen方法如下:

[java]view plaincopy

//frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java

publicclassKeyguardSecurityContainerextendsFrameLayoutimplementsKeyguardSecurityView{

privatevoidshowSecurityScreen(SecurityModesecurityMode){

if(DEBUG)Log.d(TAG,"showSecurityScreen("+securityMode+")");

if(securityMode==mCurrentSecuritySelection)return;

KeyguardSecurityViewoldView=getSecurityView(mCurrentSecuritySelection);

KeyguardSecurityViewnewView=getSecurityView(securityMode);//根據securityMode獲取對應的view

//EmulateActivitylifecycle

if(oldView!=null){

oldView.onPause();

oldView.setKeyguardCallback(mNullCallback);//ignorerequestsfromoldview

}

if(securityMode!=SecurityMode.None){

newView.onResume(KeyguardSecurityView.VIEW_REVEALED);

newView.setKeyguardCallback(mCallback);

}

//Findandshowthischild.

finalintchildCount=mSecurityViewFlipper.getChildCount();

finalintsecurityViewIdForMode=getSecurityViewIdForMode(securityMode);

for(inti=0;i if(mSecurityViewFlipper.getChildAt(i).getId()==securityViewIdForMode){

mSecurityViewFlipper.setDisplayedChild(i);

break;

}

}

mCurrentSecuritySelection=securityMode;

mSecurityCallback.onSecurityModeChanged(securityMode,

securityMode!=SecurityMode.None&&newView.needsInput());

}

}

到這裡鎖屏就啟動完成瞭,這裡簡單總結一下:

1. 在KeyguardServiceDelegate裡綁定KeyguardService,並調用onSystemReady方法。

2. KeyguardViewMediator裡調用doKeyguardLocked來決定是否需要顯示鎖屏界面;如果顯示則調用StatusBarKeyguardViewManager的show,最後調用到KeyguardHostView的showPrimarySecurityScreen()。

3. 在KeyguardSecurityContainer的showPrimarySecurityScreen利用mSecurityModel.getSecurityMode()獲取當前的securityMode,傳入showSecurityScreen來顯示不同鎖屏界面。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *