Android 7.1.1 锁屏界面启动流程

      前几天遇到一个低概率复现锁屏界面不显示,只显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看。前面简单介绍了下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.   }  
PhoneWindowManagersystemReady()会根据一个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.   
  8.       readCameraLensCoverState();  
  9.       updateUiMode();  
  10.       boolean bindKeyguardNow;  
  11.       synchronized (mLock) {  
  12.           updateOrientationListenerLp();  
  13.           mSystemReady = true;  
  14.           mHandler.post(new Runnable() {  
  15.               @Override  
  16.               public void run() {  
  17.                   updateSettings();  
  18.               }  
  19.           });  
  20.   
  21.           bindKeyguardNow = mDeferBindKeyguard;  
  22.           if (bindKeyguardNow) {  
  23.               // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.  
  24.               mDeferBindKeyguard = false;  
  25.           }  
  26.       }  
  27.       if (bindKeyguardNow) {  
  28.           mKeyguardDelegate.bindService(mContext);  
  29.           mKeyguardDelegate.onBootCompleted();  
  30.       }  
  31.       mSystemGestures.systemReady();  
  32.   }  

看到这里,可能会想到如果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.   
  8.         final ComponentName keyguardComponent = ComponentName.unflattenFromString(  
  9.                 resources.getString(com.android.internal.R.string.config_keyguardComponent));  
  10.         intent.setComponent(keyguardComponent);  
  11.   
  12.         if (!context.bindServiceAsUser(intent, mKeyguardConnection,  
  13.                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {  
  14.             Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);  
  15.             mKeyguardState.showing = false;  
  16.             mKeyguardState.showingAndNotOccluded = false;  
  17.             mKeyguardState.secure = false;  
  18.             synchronized (mKeyguardState) {  
  19.                 // TODO: Fix synchronisation model in this class. The other state in this class  
  20.                 // is at least self-healing but a race condition here can lead to the scrim being  
  21.                 // stuck on keyguard-less devices.  
  22.                 mKeyguardState.deviceHasKeyguard = false;  
  23.                 hideScrim();  
  24.             }  
  25.         } else {  
  26.             if (DEBUG) Log.v(TAG, "*** Keyguard started");  
  27.         }  
  28.     }  
  29.     ...  
  30. }  
在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.   
  35.         @Override  
  36.         public void onServiceDisconnected(ComponentName name) {  
  37.             if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");  
  38.             mKeyguardService = null;  
  39.         }  
  40.   
  41.     };  
  42.     ...  
  43. }  
当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.   
  9.             // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes  
  10.             // for an occasional ugly flicker in this situation:  
  11.             // 1) receive a call with the screen on (no keyguard) or make a call  
  12.             // 2) screen times out  
  13.             // 3) user hits key to turn screen back on  
  14.             // instead, we reenable the keyguard when we know the screen is off and the call  
  15.             // ends (see the broadcast receiver below)  
  16.             // TODO: clean this up when we have better support at the window manager level  
  17.             // for apps that wish to be on top of the keyguard  
  18.             return;  
  19.         }  
  20.   
  21.         // if the keyguard is already showing, don't bother  
  22.         if (mStatusBarKeyguardViewManager.isShowing()) {  
  23.             if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");  
  24.             resetStateLocked();  
  25.             return;  
  26.         }  
  27.   
  28.         // if the setup wizard hasn't run yet, don't show  
  29.         final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim"false);  
  30.         final boolean absent = SubscriptionManager.isValidSubscriptionId(  
  31.                 mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.ABSENT));  
  32.         final boolean disabled = SubscriptionManager.isValidSubscriptionId(  
  33.                 mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));  
  34.         final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()  
  35.                 || ((absent || disabled) && requireSim);  
  36.   
  37.         if (!lockedOrMissing && shouldWaitForProvisioning()) {  
  38.             if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"  
  39.                     + " and the sim is not locked or missing");  
  40.             return;  
  41.         }  
  42.   
  43.         if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())  
  44.                 && !lockedOrMissing) {  
  45.             if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");  
  46.             return;  
  47.         }  
  48.   
  49.         if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {  
  50.             if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");  
  51.             // Without this, settings is not enabled until the lock screen first appears  
  52.             setShowingLocked(false);  
  53.             hideLocked();  
  54.             mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();  
  55.             return;  
  56.         }  
  57.   
  58.         if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");  
  59.         showLocked(options);  
  60.     }  
  61.     ...  
  62. }  
这段代码主要是在是否要显示锁屏之前做了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.   
  13.             setShowingLocked(true);  
  14.             mStatusBarKeyguardViewManager.show(options);  
  15.             mHiding = false;  
  16.             mWakeAndUnlocking = false;  
  17.             resetKeyguardDonePendingLocked();  
  18.             mHideAnimationRun = false;  
  19.             updateActivityLockScreenState();  
  20.             adjustStatusBarLocked();  
  21.             userActivity();  
  22.   
  23.             mShowKeyguardWakeLock.release();  
  24.         }  
  25.         mKeyguardDisplayManager.show();  
  26.     }  
  27.     ...  
  28. }  

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.   
  7.         if (securityMode == mCurrentSecuritySelection) return;  
  8.   
  9.         KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);  
  10.         KeyguardSecurityView newView = getSecurityView(securityMode);//根据securityMode获取对应的view  
  11.   
  12.         // Emulate Activity life cycle  
  13.         if (oldView != null) {  
  14.             oldView.onPause();  
  15.             oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view  
  16.         }  
  17.         if (securityMode != SecurityMode.None) {  
  18.             newView.onResume(KeyguardSecurityView.VIEW_REVEALED);  
  19.             newView.setKeyguardCallback(mCallback);  
  20.         }  
  21.   
  22.         // Find and show this child.  
  23.         final int childCount = mSecurityViewFlipper.getChildCount();  
  24.   
  25.         final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);  
  26.         for (int i = 0; i < childCount; i++) {  
  27.             if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {  
  28.                 mSecurityViewFlipper.setDisplayedChild(i);  
  29.                 break;  
  30.             }  
  31.         }  
  32.   
  33.         mCurrentSecuritySelection = securityMode;  
  34.         mSecurityCallback.onSecurityModeChanged(securityMode,  
  35.                 securityMode != SecurityMode.None && newView.needsInput());  
  36.     }  
  37.     ...  
  38. }  

到这里锁屏就启动完成了,这里简单总结一下:
   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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值