android锁屏流程_Android 7.1.1 锁屏界面启动流程

本文详细分析了Android 7.1.1系统中锁屏界面从启动到显示的过程,涉及SystemServer、WindowManagerService、PhoneWindowManager、KeyguardServiceDelegate等多个组件。首先,Zygote启动SystemServer进程,接着通过WindowManagerService调用systemReady()方法。在PhoneWindowManager中,根据系统准备状态决定是否绑定keyguard服务。锁屏显示流程包括:通过KeyguardServiceDelegate绑定KeyguardService,然后在KeyguardViewMediator的onSystemReady中调用doKeyguardLocked,最终在KeyguardSecurityContainer中根据当前安全模式显示相应的锁屏界面。
摘要由CSDN通过智能技术生成

前几天遇到一个低概率复现锁屏界面不显示,只显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看。前面简单介绍了下Zygote启动流程,  Zygote进程启动后会首先创建一个SystemServer进程, SystemServer进程在调用startOtherServices同时也会调用WindowManagerService的systemReady()方法

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

private void startOtherServices() {

...

wm = WindowManagerService.main(context, inputManager,

mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,

!mFirstBoot, mOnlyCore);

...

try {

wm.systemReady();

Slog.i("jason11", "SystemServer wm.systemReady");

} catch (Throwable e) {

reportWtf("making Window Manager Service ready", e);

}

...

}

在 WindowManagerService中直接调用了PhoneWindowManager里的systemReady()

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

//final WindowManagerPolicy mPolicy = new PhoneWindowManager();

public void systemReady() {

mPolicy.systemReady();

}

PhoneWindowManager 的 systemReady()会根据一个Boolean值bindKeyguardNow来决定是否绑定keyguard service

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

/** {@inheritDoc} */

@Override

public void systemReady() {

mKeyguardDelegate = new KeyguardServiceDelegate(mContext);

mKeyguardDelegate.onSystemReady();

readCameraLensCoverState();

updateUiMode();

boolean bindKeyguardNow;

synchronized (mLock) {

updateOrientationListenerLp();

mSystemReady = true;

mHandler.post(new Runnable() {

@Override

public void run() {

updateSettings();

}

});

bindKeyguardNow = mDeferBindKeyguard;

if (bindKeyguardNow) {

// systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.

mDeferBindKeyguard = false;

}

}

if (bindKeyguardNow) {

mKeyguardDelegate.bindService(mContext);

mKeyguardDelegate.onBootCompleted();

}

mSystemGestures.systemReady();

}

看到这里,可能会想到如果bindKeyguardNow为false就会不绑定,后面通过继续跟踪发现在 PhoneWindowManager的 systemBooted()里也会去绑定keyguard service,如果在 systemBooted里绑定了就不在systemReady里再去绑定,自己测试的时候是在 systemBooted绑定的

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

/** {@inheritDoc} */

@Override

public void systemBooted() {

boolean bindKeyguardNow = false;

synchronized (mLock) {

// Time to bind Keyguard; take care to only bind it once, either here if ready or

// in systemReady if not.

if (mKeyguardDelegate != null) {

bindKeyguardNow = true;

} else {

// Because mKeyguardDelegate is null, we know that the synchronized block in

// systemReady didn't run yet and setting this will actually have an effect.

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的

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

public class KeyguardServiceDelegate {

...

public void bindService(Context context) {

Intent intent = new Intent();

final Resources resources = context.getApplicationContext().getResources();

final ComponentName keyguardComponent = 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't bind to " + keyguardComponent);

mKeyguardState.showing = false;

mKeyguardState.showingAndNotOccluded = false;

mKeyguardState.secure = false;

synchronized (mKeyguardState) {

// TODO: Fix synchronisation model in this class. The other state in this class

// is at least self-healing but a race condition here can lead to the scrim being

// stuck on keyguard-less devices.

mKeyguardState.deviceHasKeyguard = false;

hideScrim();

}

} else {

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

}

}

...

}

在bindService中调用了bindServiceAsUser绑定指定intent的service,config_keyguardComponent的定义如下

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

com.android.systemui/com.android.systemui.keyguard.KeyguardService

当绑定成功后会调用mKeyguardConnection里的onServiceConnected方法

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

public class KeyguardServiceDelegate {

...

private final ServiceConnection mKeyguardConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

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

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.

if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {

mKeyguardService.onStartedWakingUp();

}

if (mKeyguardState.screenState == SCREEN_STATE_ON

|| mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) {

mKeyguardService.onScreenTurningOn(

new KeyguardShowDelegate(mDrawnListenerWhenConnect));

}

if (mKeyguardState.screenState == SCREEN_STATE_ON) {

mKeyguardService.onScreenTurnedOn();

}

mDrawnListenerWhenConnect = null;

}

if (mKeyguardState.bootCompleted) {

mKeyguardService.onBootCompleted();

}

if (mKeyguardState.occluded) {

mKeyguardService.setOccluded(mKeyguardState.occluded);

}

}

@Override

public void onServiceDisconnected(ComponentName name) {

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

mKeyguardService = null;

}

};

...

}

当mKeyguardState.systemIsReady为true是,就会通过KeyguardServiceWrapper的实例mKeyguardService调用onSystemReady方法,在

KeyguardServiceWrapper的onSystemReady里调用了上面刚刚绑定成功的KeyguardService的 onSystemReady方法

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

public class KeyguardServiceWrapper implements IKeyguardService {

...

@Override // Binder interface

public void onSystemReady() {

try {

mService.onSystemReady();

} catch (RemoteException e) {

Slog.w(TAG , "Remote Exception", e);

}

}

...

}

在 KeyguardService的 onSystemReady里调用了KeyguardViewMediator里的 onSystemReady,在这里就不贴这个代码了,直接看看 KeyguardViewMediator. onSystemReady这个里面干啥了

2、KeyguardViewMediator.onSystemReady

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

public class KeyguardViewMediator extends SystemUI {

...

public void onSystemReady() {

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

synchronized (this) {

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

mSystemReady = true;

doKeyguardLocked(null);

mUpdateMonitor.registerCallback(mUpdateCallback);

}

// Most services aren't available until the system reaches the ready state, so we

// send it here when the device first boots.

maybeSendUserPresentBroadcast();

}

...

}

在这个方法里主要调用了doKeyguardLocked和注册了KeyguardUpdateMonitorCallback

3、通过调用 doKeyguardLocked显示锁屏界面

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

public class KeyguardViewMediator extends SystemUI {

...

private void doKeyguardLocked(Bundle options) {

// if another app is disabling us, don't show

if (!mExternallyEnabled) {

if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");

// note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes

// for an occasional ugly flicker in this situation:

// 1) receive a call with the screen on (no keyguard) or make a call

// 2) screen times out

// 3) user hits key to turn screen back on

// instead, we reenable the keyguard when we know the screen is off and the call

// ends (see the broadcast receiver below)

// TODO: clean this up when we have better support at the window manager level

// for apps that wish to be on top of the keyguard

return;

}

// if the keyguard is already showing, don't bother

if (mStatusBarKeyguardViewManager.isShowing()) {

if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");

resetStateLocked();

return;

}

// if the setup wizard hasn't run yet, don't show

final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);

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(KeyguardUpdateMonitor.getCurrentUser())

&& !lockedOrMissing) {

if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");

return;

}

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

if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");

// Without this, settings is not enabled until the lock screen first appears

setShowingLocked(false);

hideLocked();

mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();

return;

}

if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");

showLocked(options);

}

...

}

这段代码主要是在是否要显示锁屏之前做了5个判断:1.如果启用第三方锁屏界面,不显示原生界面;2.锁屏界面已经显示了话,重新更新下状态;3.如果第一次开机引导界面setup wizard 还没有运行,也先不显示;4.屏幕没有亮不显示;5.当前正在解密界面不显示。如果这几个条件都不满足,则调用showLocked显示锁屏界面。在

showLocked通过mHandler发送Message,在handleMessage里“ case SHOW: ”时调用handleShow

4、在 handleShow里设置一些锁屏状态和显示锁屏界面

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

public class KeyguardViewMediator extends SystemUI {

...

private void handleShow(Bundle options) {

synchronized (KeyguardViewMediator.this) {

if (!mSystemReady) {

if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");

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

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

public class StatusBarKeyguardViewManager {

...

public void show(Bundle options) {

mShowing = true;

mStatusBarWindowManager.setKeyguardShowing(true);

mScrimController.abortKeyguardFadingOut();

reset();

}

...

}

在reset里调用本类的showBouncerOrKeyguard,在这个方法里通过KeyguardBouncer的实例mBouncer调用prepare(),在

prepare里调用了KeyguardHostView的showPrimarySecurityScreen

6、 KeyguardSecurityContainer. showPrimarySecurityScreen

在KeyguardHostView的 showPrimarySecurityScreen里调用KeyguardSecurityContainer的 showPrimarySecurityScreen方法,如下

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

public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {

...

void showPrimarySecurityScreen(boolean turningOff) {

SecurityMode securityMode = mSecurityModel.getSecurityMode();

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

showSecurityScreen(securityMode);

}

...

}

在这个方法里调用了showSecurityScreen,根据mSecurityModel.getSecurityMode()获取的SecurityMode来显示不同界面,SecurityMode定义如下

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

public class KeyguardSecurityModel {

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

}

...

}

showSecurityScreen方法如下:

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

public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {

...

private void showSecurityScreen(SecurityMode securityMode) {

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

if (securityMode == mCurrentSecuritySelection) return;

KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);

KeyguardSecurityView newView = getSecurityView(securityMode);//根据securityMode获取对应的view

// Emulate Activity life cycle

if (oldView != null) {

oldView.onPause();

oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view

}

if (securityMode != SecurityMode.None) {

newView.onResume(KeyguardSecurityView.VIEW_REVEALED);

newView.setKeyguardCallback(mCallback);

}

// Find and show this child.

final int childCount = mSecurityViewFlipper.getChildCount();

final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);

for (int i = 0; i < childCount; 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来显示不同锁屏界面。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值