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

[java] view plain copy
  1. //frameworks/base/services/java/com/android/server/SystemServer.java
  2. private void startOtherServices() {
  3. ...
  4. wm = WindowManagerService.main(context, inputManager,
  5. mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
  6. !mFirstBoot, mOnlyCore);
  7. ...
  8. try {
  9. wm.systemReady();
  10. Slog.i("jason11", "SystemServer wm.systemReady");
  11. } catch (Throwable e) {
  12. reportWtf("making Window Manager Service ready", e);
  13. }
  14. ...
  15. }

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

[java] view plain copy
  1. //frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
  2. //final WindowManagerPolicy mPolicy = new PhoneWindowManager();
  3. public void systemReady() {
  4. mPolicy.systemReady();
  5. }

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

[java] view plain copy
  1. //frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
  2. /** {@inheritDoc} */
  3. @Override
  4. public void systemReady() {
  5. mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
  6. mKeyguardDelegate.onSystemReady();
  7. readCameraLensCoverState();
  8. updateUiMode();
  9. boolean bindKeyguardNow;
  10. synchronized (mLock) {
  11. updateOrientationListenerLp();
  12. mSystemReady = true;
  13. mHandler.post(new Runnable() {
  14. @Override
  15. public void run() {
  16. updateSettings();
  17. }
  18. });
  19. bindKeyguardNow = mDeferBindKeyguard;
  20. if (bindKeyguardNow) {
  21. // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
  22. mDeferBindKeyguard = false;
  23. }
  24. }
  25. if (bindKeyguardNow) {
  26. mKeyguardDelegate.bindService(mContext);
  27. mKeyguardDelegate.onBootCompleted();
  28. }
  29. mSystemGestures.systemReady();
  30. }

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

[java] view plain copy
  1. //frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
  2. /** {@inheritDoc} */
  3. @Override
  4. public void systemBooted() {
  5. boolean bindKeyguardNow = false;
  6. synchronized (mLock) {
  7. // Time to bind Keyguard; take care to only bind it once, either here if ready or
  8. // in systemReady if not.
  9. if (mKeyguardDelegate != null) {
  10. bindKeyguardNow = true;
  11. } else {
  12. // Because mKeyguardDelegate is null, we know that the synchronized block in
  13. // systemReady didn't run yet and setting this will actually have an effect.
  14. mDeferBindKeyguard = true;
  15. }
  16. }
  17. if (bindKeyguardNow) {
  18. mKeyguardDelegate.bindService(mContext);
  19. mKeyguardDelegate.onBootCompleted();
  20. }
  21. synchronized (mLock) {
  22. mSystemBooted = true;
  23. }
  24. startedWakingUp();
  25. screenTurningOn(null);
  26. screenTurnedOn();
  27. }

下面就通过如下的时序图看看是如何调用到systemBooted的,就不在一步步跟了

通过上面的分析知道,无论是在systemReady或systemBooted,都调用了KeyguardServiceDelegate对象的bindService方法,下面就以这个方法开始,看看锁屏界面是怎么显示出来的,先看看下面的时序图,再来分步讲解

1、先来看看在KeyguardServiceDelegate如何绑定KeyguardService的

[java] view plain copy
  1. //frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
  2. public class KeyguardServiceDelegate {
  3. ...
  4. public void bindService(Context context) {
  5. Intent intent = new Intent();
  6. final Resources resources = context.getApplicationContext().getResources();
  7. final ComponentName keyguardComponent = ComponentName.unflattenFromString(
  8. resources.getString(com.android.internal.R.string.config_keyguardComponent));
  9. intent.setComponent(keyguardComponent);
  10. if (!context.bindServiceAsUser(intent, mKeyguardConnection,
  11. Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
  12. Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
  13. mKeyguardState.showing = false;
  14. mKeyguardState.showingAndNotOccluded = false;
  15. mKeyguardState.secure = false;
  16. synchronized (mKeyguardState) {
  17. // TODO: Fix synchronisation model in this class. The other state in this class
  18. // is at least self-healing but a race condition here can lead to the scrim being
  19. // stuck on keyguard-less devices.
  20. mKeyguardState.deviceHasKeyguard = false;
  21. hideScrim();
  22. }
  23. } else {
  24. if (DEBUG) Log.v(TAG, "*** Keyguard started");
  25. }
  26. }
  27. ...
  28. }

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

[html] view plain copy
  1. //frameworks/base/core/res/res/values/config.xml
  2. <!-- Keyguard component -->
  3. <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>

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

[java] view plain copy
  1. //frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
  2. public class KeyguardServiceDelegate {
  3. ...
  4. private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
  5. @Override
  6. public void onServiceConnected(ComponentName name, IBinder service) {
  7. if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
  8. mKeyguardService = new KeyguardServiceWrapper(mContext,
  9. IKeyguardService.Stub.asInterface(service));
  10. if (mKeyguardState.systemIsReady) {
  11. // If the system is ready, it means keyguard crashed and restarted.
  12. mKeyguardService.onSystemReady();
  13. // This is used to hide the scrim once keyguard displays.
  14. if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
  15. mKeyguardService.onStartedWakingUp();
  16. }
  17. if (mKeyguardState.screenState == SCREEN_STATE_ON
  18. || mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) {
  19. mKeyguardService.onScreenTurningOn(
  20. new KeyguardShowDelegate(mDrawnListenerWhenConnect));
  21. }
  22. if (mKeyguardState.screenState == SCREEN_STATE_ON) {
  23. mKeyguardService.onScreenTurnedOn();
  24. }
  25. mDrawnListenerWhenConnect = null;
  26. }
  27. if (mKeyguardState.bootCompleted) {
  28. mKeyguardService.onBootCompleted();
  29. }
  30. if (mKeyguardState.occluded) {
  31. mKeyguardService.setOccluded(mKeyguardState.occluded);
  32. }
  33. }
  34. @Override
  35. public void onServiceDisconnected(ComponentName name) {
  36. if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
  37. mKeyguardService = null;
  38. }
  39. };
  40. ...
  41. }

当mKeyguardState.systemIsReady为true是,就会通过KeyguardServiceWrapper的实例mKeyguardService调用onSystemReady方法,在 KeyguardServiceWrapper的onSystemReady里调用了上面刚刚绑定成功的KeyguardService的onSystemReady方法

[java] view plain copy
  1. //frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
  2. public class KeyguardServiceWrapper implements IKeyguardService {
  3. ...
  4. @Override // Binder interface
  5. public void onSystemReady() {
  6. try {
  7. mService.onSystemReady();
  8. } catch (RemoteException e) {
  9. Slog.w(TAG , "Remote Exception", e);
  10. }
  11. }
  12. ...
  13. }

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

2、KeyguardViewMediator.onSystemReady

[java] view plain copy
  1. //frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
  2. public class KeyguardViewMediator extends SystemUI {
  3. ...
  4. public void onSystemReady() {
  5. mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
  6. synchronized (this) {
  7. if (DEBUG) Log.d(TAG, "onSystemReady");
  8. mSystemReady = true;
  9. doKeyguardLocked(null);
  10. mUpdateMonitor.registerCallback(mUpdateCallback);
  11. }
  12. // Most services aren't available until the system reaches the ready state, so we
  13. // send it here when the device first boots.
  14. maybeSendUserPresentBroadcast();
  15. }
  16. ...
  17. }

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

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

[java] view plain copy
  1. //frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
  2. public class KeyguardViewMediator extends SystemUI {
  3. ...
  4. private void doKeyguardLocked(Bundle options) {
  5. // if another app is disabling us, don't show
  6. if (!mExternallyEnabled) {
  7. if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
  8. // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes
  9. // for an occasional ugly flicker in this situation:
  10. // 1) receive a call with the screen on (no keyguard) or make a call
  11. // 2) screen times out
  12. // 3) user hits key to turn screen back on
  13. // instead, we reenable the keyguard when we know the screen is off and the call
  14. // ends (see the broadcast receiver below)
  15. // TODO: clean this up when we have better support at the window manager level
  16. // for apps that wish to be on top of the keyguard
  17. return;
  18. }
  19. // if the keyguard is already showing, don't bother
  20. if (mStatusBarKeyguardViewManager.isShowing()) {
  21. if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
  22. resetStateLocked();
  23. return;
  24. }
  25. // if the setup wizard hasn't run yet, don't show
  26. final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
  27. final boolean absent = SubscriptionManager.isValidSubscriptionId(
  28. mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.ABSENT));
  29. final boolean disabled = SubscriptionManager.isValidSubscriptionId(
  30. mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));
  31. final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
  32. || ((absent || disabled) && requireSim);
  33. if (!lockedOrMissing && shouldWaitForProvisioning()) {
  34. if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
  35. + " and the sim is not locked or missing");
  36. return;
  37. }
  38. if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
  39. && !lockedOrMissing) {
  40. if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
  41. return;
  42. }
  43. if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
  44. if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
  45. // Without this, settings is not enabled until the lock screen first appears
  46. setShowingLocked(false);
  47. hideLocked();
  48. mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
  49. return;
  50. }
  51. if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
  52. showLocked(options);
  53. }
  54. ...
  55. }

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

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

[java] view plain copy
  1. //frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
  2. public class KeyguardViewMediator extends SystemUI {
  3. ...
  4. private void handleShow(Bundle options) {
  5. synchronized (KeyguardViewMediator.this) {
  6. if (!mSystemReady) {
  7. if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
  8. return;
  9. } else {
  10. if (DEBUG) Log.d(TAG, "handleShow");
  11. }
  12. setShowingLocked(true);
  13. mStatusBarKeyguardViewManager.show(options);
  14. mHiding = false;
  15. mWakeAndUnlocking = false;
  16. resetKeyguardDonePendingLocked();
  17. mHideAnimationRun = false;
  18. updateActivityLockScreenState();
  19. adjustStatusBarLocked();
  20. userActivity();
  21. mShowKeyguardWakeLock.release();
  22. }
  23. mKeyguardDisplayManager.show();
  24. }
  25. ...
  26. }

5、通过调用StatusBarKeyguardViewManager的show重置当前状态显示keyguard

[java] view plain copy
  1. //frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
  2. public class StatusBarKeyguardViewManager {
  3. ...
  4. public void show(Bundle options) {
  5. mShowing = true;
  6. mStatusBarWindowManager.setKeyguardShowing(true);
  7. mScrimController.abortKeyguardFadingOut();
  8. reset();
  9. }
  10. ...
  11. }

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

6、KeyguardSecurityContainer.showPrimarySecurityScreen

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

[java] view plain copy
  1. //frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
  2. public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
  3. ...
  4. void showPrimarySecurityScreen(boolean turningOff) {
  5. SecurityMode securityMode = mSecurityModel.getSecurityMode();
  6. if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
  7. showSecurityScreen(securityMode);
  8. }
  9. ...
  10. }

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

[java] view plain copy
  1. //frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
  2. public class KeyguardSecurityModel {
  3. public enum SecurityMode {
  4. Invalid, // NULL state
  5. None, // No security enabled
  6. Pattern, // Unlock by drawing a pattern.
  7. Password, // Unlock by entering an alphanumeric password
  8. PIN, // Strictly numeric password
  9. SimPin, // Unlock by entering a sim pin.
  10. SimPuk // Unlock by entering a sim puk
  11. }
  12. ...
  13. }

showSecurityScreen方法如下:

[java] view plain copy
  1. //frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
  2. public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
  3. ...
  4. private void showSecurityScreen(SecurityMode securityMode) {
  5. if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
  6. if (securityMode == mCurrentSecuritySelection) return;
  7. KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
  8. KeyguardSecurityView newView = getSecurityView(securityMode);//根据securityMode获取对应的view
  9. // Emulate Activity life cycle
  10. if (oldView != null) {
  11. oldView.onPause();
  12. oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
  13. }
  14. if (securityMode != SecurityMode.None) {
  15. newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
  16. newView.setKeyguardCallback(mCallback);
  17. }
  18. // Find and show this child.
  19. final int childCount = mSecurityViewFlipper.getChildCount();
  20. final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
  21. for (int i = 0; i < childCount; i++) {
  22. if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
  23. mSecurityViewFlipper.setDisplayedChild(i);
  24. break;
  25. }
  26. }
  27. mCurrentSecuritySelection = securityMode;
  28. mSecurityCallback.onSecurityModeChanged(securityMode,
  29. securityMode != SecurityMode.None && newView.needsInput());
  30. }
  31. ...
  32. }

到这里锁屏就启动完成了,这里简单总结一下:
   1. 在KeyguardServiceDelegate里绑定KeyguardService,并调用onSystemReady方法。
   2. KeyguardViewMediator里调用doKeyguardLocked来决定是否需要显示锁屏界面;如果显示则调用StatusBarKeyguardViewManager的show,最后调用到KeyguardHostView的showPrimarySecurityScreen()。

3. 在KeyguardSecurityContainer的showPrimarySecurityScreen利用mSecurityModel.getSecurityMode()获取当前的securityMode,传入showSecurityScreen来显示不同锁屏界面。

原文地址: http://blog.csdn.net/yin1031468524/article/details/56284449

Android 7.1.1 锁屏界面启动流程相关推荐

  1. Android 9.0 去除锁屏界面及SystemUI无sim卡拨打紧急电话控件显示功能实现

    1.1概述 在9.0的系统rom定制化开发中,关于SystemUI的定制化功能也是比较多的,在SystemUI的锁屏页面和状态栏提示无sim卡拨打紧急电话控件显示等相关提示 的功能中,在有些syste ...

  2. android开发笔记之锁屏界面未读短信未接来电提醒(android 4.4)

    客户需求 最近在做一个项目,android 4.4系统,客户要求在锁屏界面有未读短信未接来电的提醒功能.而平台没有此功能,要自己实现.并且时间非常紧,---.(其实软件工程师基本上都是这样,坑,坑,坑 ...

  3. Android 10.0去除锁屏界面及SystemUI无sim卡拨打紧急电话控件显示

    在开发定制化wifi版平板时,需要去掉所有紧急拨打电话的功能,而紧急拨打电话在锁屏界面 和SystemUI 的下拉快捷里面有这些功能 所以就从这两个地方入手,屏蔽到紧急拨打电话功能 1.SystemU ...

  4. Android 9.0 SystemUI 锁屏界面禁止状态栏下拉

    目录 1.概述 2.SystemUI 锁屏界面禁止状态栏下拉的核心类 3.SystemUI 锁屏界面禁止状

  5. android锁屏时间大小,Android 4.4.4 锁屏界面时间大小修改

    源码所在目录: frameworks\base\packages\Keyguard\res\values\dimens.xml 80dp 其中的80dp即代表时间字体的大小,修改这个值,即可改变字体的 ...

  6. android锁屏界面快捷键,Funtouch新特性 锁屏快捷键可以自定义

    凤凰数码讯 5月1日 vivo的Funtouch OS系统日前曝出新特性,用户可以自定义锁屏快捷键,大大提升了锁屏界面的易用性. 中关村在线消息,由于设计风格华丽.UI特色鲜明,vivo基于Andro ...

  7. 《SystemUI》修改SystemUI锁屏界面时间格式

    要求:修改SystemUI锁屏界面时间格式 Android P 上Sysyemui锁屏界面上的日期显示不在DateView处理了,使用KeyguardSliceProvider来处理,继承Conten ...

  8. android 锁屏界面处理

    锁屏相关的文件在android对应package:com.android.internal.policy.impl. phoneWindowManager.java可以派发各种物理key,如Power ...

  9. android 游戏 锁屏界面开发,android 锁屏程序开发

    参考http://blog.csdn.net/wdaming1986/article/details/8837023 锁屏程序的步骤如下: 1.替换系统锁屏 2.屏蔽Home键,back键.menu键 ...

最新文章

  1. 自动驾驶真的会来得那么快吗:关于自动驾驶的7个疑问
  2. 浅析网站流量出现异常情况应怎样解决?
  3. python运用实例视频_python爬视频实例
  4. Day 4 - PB级规模数据的Elasticsearch分库分表实践
  5. matlab都有什么接口,介绍MATLAB与C++的几种接口方式
  6. 转:【Java集合源码剖析】LinkedHashmap源码剖析
  7. Linux学习笔记5
  8. jsoup爬虫简书首页数据做个小Demo
  9. java 里面怎么截取倒数第几个字_Java反射是什么
  10. 超越Hadoop的大数据分析之图形处理尺寸
  11. node.js 与 nvm安装教程
  12. 中国大学生在线官方微博入围全国十大中央机构微博、全国十大教育微博
  13. 转载:分配器、切换器、同屏器、分屏器 区别
  14. 最新的ESD(ElectroStatic Discharge)静电介绍及其标准下载(见文尾)
  15. 莫队算法完整总结(普通莫队、带修莫队、树上莫队、回滚莫队)
  16. 某网站登录接口password参数还原
  17. 查看pcie总线上的设备ID以及带宽计算
  18. Error while extracting response for type [class xxx] and content type application/xml;charset=UTF-8
  19. html网页页面制作用到了什么技术,技术干货|常用的HTML5网页制作软件,这些你有在用吗?...
  20. 12月份参加工作的年假怎么休_请问我的年假可以在12月份休吗?单位说可以12月1日就不用上班了,我可以上到12月28日吗?...

热门文章

  1. Uber新功能:隐藏司机乘客们的手机号码
  2. SharePoint 2013 Error - TypeError: Unable to get property 'replace' of undefined or null reference
  3. 《JavaScript语言精髓与编程实践》读书笔记二
  4. Unity3d webplayer发布的问题和100%自适应浏览器
  5. Python学习笔记:错误和异常
  6. Git bash:初步入门(1)
  7. Matlab 基于svm的图像物体分类
  8. 一个操作系统的实现(1):分析linux下如何运行一个执行文件
  9. 科大星云诗社动态20210905
  10. 荣耀X8碎屏2020-05-14