前几天遇到一个低概率复现锁屏界面不显示,仅仅显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看。前面简介了下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
<!-- Keyguard component -->
<string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>

当绑定成功后会调用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来显示不同锁屏界面。

Android 7.1.1 锁屏界面启动流程的更多相关文章

  1. android------锁屏(手机启动出现锁屏界面)

    以前用过一个红包锁屏的软件,第一次打开手机出现锁屏,滑动领取收益,当时觉得这功能不错,就查阅资料,写了一个案例, apk运行流程: 进入软件--->启动服务--->关闭手机(可先退出应用) ...

  2. Android框架浅析之锁屏(Keyguard)机制原理

    最近终于成功的摆脱了FM收音机,迈向了新的模块:锁屏.状态栏.Launcher---姑且称之为“IDLE”小组,或许叫手机 美容小组,要是能施展下周星星同学的还我漂漂拳,岂不快哉. OK,闲话打住,咱 ...

  3. 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义重复

    从图片中我们可以看到,这里在语义上有一定的重复,当然这是谷歌的原始设计.这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,不过由于Android4.3在锁屏功能上比起老版本做了很大的改动,而 ...

  4. 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义反复

    从图片中我们能够看到,这里在语义上有一定的反复,当然这是谷歌的原始设计.这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,只是因为Android4.3在锁屏功能上比起老版本号做了非常大的修改 ...

  5. RK3399 删除开机锁屏界面

    CPU:RK3399 系统:Android 7.1 删除开机锁屏界面 diff --git a/frameworks/base/packages/SettingsProvider/res/values ...

  6. iOS开发--QQ音乐练习,后台播放和锁屏界面

    一.设置后台播放 首先允许程序后台播放 代码实现 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOpti ...

  7. win10锁屏界面无法更新

    win10的锁屏界面都是巨硬公司推送过来的,质量还不错,最近锁屏界面无法更新,解决方案如下: 以管理员身份运行cmd,分别运行如下两个命令 del /f /s /q /a "%userpro ...

  8. Qt - 锁屏界面加虚拟小键盘

    一.实现效果 鼠标点击"密码输入栏",弹出虚拟键盘,输入锁屏密码后,点击虚拟键盘外部区域,则会隐藏虚拟键盘,再点击登录,成功进入主界面. 二.虚拟键盘-程序设计 2.1 frmNu ...

  9. 【Android N 7.1.1】 处于锁屏界面时可以转屏

    frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.ja ...

随机推荐

  1. vim 中Taglist的安装和使用

    将vim 改造成功能强大的IDE系列之二 『插件介绍』 Taglist是vim的一个插件,提供源代码符号的结构化视图. 效果图:(直接使用了别人的图片.在我机器上也差不多-) 『下载和安装』 1)从h ...

  2. ZOJ - 3725 Painting Storages

    Description There is a straight highway with N storages alongside it labeled by 1,2,3,...,N. Bob ask ...

  3. PHP 导出 CSV 文件用 Excel 打开出现中文乱码

    本篇文章由:http://xinpure.com/php-export-csv-file-opened-by-excel-appear-garbled/ 乱码情况 写了一段导出 CSV 文件的代码,可 ...

  4. 自己动手写CPU之第五阶段(2)——OpenMIPS对数据相关问题的解决措施

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第16篇.我尽量每周四篇 5.2 OpenMIPS对数据相关问题的解决措施 OpenMIPS处理器採用数据前推的方法来解决流水 ...

  5. linux一条命令添加一个root级别账户并设置密码

    内网机器提权添加账户,无回显,设置密码就不好弄,下面就是添加一个root级别的账户并设置密码的命令   ? 1 useradd -p `openssl passwd -1 -salt 'lsof' a ...

  6. IOS 拍照旋转修正

    - (UIImage *)fixOrientation:(UIImage *)aImage { // No-op if the orientation is already correct if (a ...

  7. 多线程-CAS原理

    背景 在JDK1.5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁,锁机制存在以下问题: (1)在多线程竞争中,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题 ...

  8. Atitit.词法分析的理论原理 part2

    Atitit.词法分析的理论原理 part2 1.  转换图1 1.1. 转换图是由程序流程图改进而成的.同样,转换图也可以等价地转换为程序流程图3 1.2. 2.2.3  构造词法分析器(2)流程程 ...

  9. Atitit.  单列索引与多列索引 多个条件的查询原理与设计实现

    Atitit.  单列索引与多列索引 多个条件的查询原理与设计实现 1. MySQL只能使用一个索引1 1.1. 最左前缀1 1.2. 从另一方面理解,它相当于我们创建了(firstname,last ...

  10. PHP7:10件事情你需要知道的

    你是一个Web开发人员或网站所有者?做你的网站上的PHP-enabledCMS如WordPress,Drupal的是,Joomla或Magento的运行?然后,我对你的好消息:新的PHP 7的功能完整 ...