一、流程概述
1、SystemUI启动完成后,进入的第一个界面为锁屏界面。
2、锁屏keyguard属于SystemUI。
3、锁屏开机大致分为两部分,第一部分是从WindowManagerService开始,处理锁屏显示等流程。第二部分是KeyguardViewMediator的启动;
二、详细介绍
1 WindowManagerService部分:
WindowManagerService在SystemService中的startOtherServices()方法里启动。
t.traceBegin("StartWindowManagerService"); // WMS needs sensor service ready ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE); mSensorServiceStart = null; wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore, new SprdPhoneWindowManager(), mActivityManagerService.mActivityTaskManager); ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO); ServiceManager.addService(Context.INPUT_SERVICE, inputManager, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL); t.traceEnd();
SystemServer在启动SystemUI()的方法上,最后调用WindowManagerService的onSystemUiStarted方法。
private static void startSystemUi(Context context, WindowManagerService windowManager) { PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); Intent intent = new Intent(); intent.setComponent(pm.getSystemUiServiceComponent()); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); //Slog.d(TAG, "Starting service: " + intent); context.startServiceAsUser(intent, UserHandle.SYSTEM); windowManager.onSystemUiStarted(); }
继续跟进,会发现WindowManagerService的onSystemUiStarted方法,实际调用的是PhoneWindowManager中的onSystemUiStarted();(通过接口进行回调)
@Override public void onSystemUiStarted() { bindKeyguard(); }
在PhoneWindowManager中会调用bindKeyguard,KeyguardServiceDelegate作为KeyguardService的委派。
private void bindKeyguard() { synchronized (mLock) { if (mKeyguardBound) { return; } mKeyguardBound = true; } mKeyguardDelegate.bindService(mContext); }
在KeyguardServiceDelegate的bindService方法中绑定KeyguardService。
public void bindService(Context context) { Intent intent = new Intent(); final Resources resources = context.getApplicationContext().getResources(); //从配置文件中获取KeyguardService final ComponentName keyguardComponent = ComponentName.unflattenFromString( resources.getString(com.android.internal.R.string.config_keyguardComponent)); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); intent.setComponent(keyguardComponent); //绑定KeyguardService if (!context.bindServiceAsUser(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) { 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; } } else { if (DEBUG) Log.v(TAG, "*** Keyguard started"); } }
在ServiceConnection的连接成功回调中,创建KeyguardService包装类KeyguardServiceWrapper。包装类除了KeyguardService,还有KeyguardStateMonitor状态监视器。实际调用还是通过KeyguardService。
private final ServiceConnection mKeyguardConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)"); // KeyguardServiceWrapper包装类调用KeyguardService的Binder实例 mKeyguardService = new KeyguardServiceWrapper(mContext, IKeyguardService.Stub.asInterface(service), mCallback); if (mKeyguardState.systemIsReady) { // If the system is ready, it means keyguard crashed and restarted. mKeyguardService.onSystemReady(); if (mKeyguardState.currentUser != UserHandle.USER_NULL) { // There has been a user switch earlier mKeyguardService.setCurrentUser(mKeyguardState.currentUser); } // 调用KeyguardService的IPC接口 .. .. } @Override public void onServiceDisconnected(ComponentName name) { if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)"); mKeyguardService = null; mKeyguardState.reset(); .. } }
在绑定以后,PhoneWindowManager可以调用代理类KeyguardServiceDelegate间接调用KeyguardService的binder接口进行各种锁屏相关状态回调。
2 KeyguardViewMediato 部分
初次开机Keyguard showLock流程:
系统启动完成-->PhoneWindowManager.systemReady()-->mKeyguardDelegate.onSystemReady()
-->mKeyguardService.onSystemReady()-->KeyguardService.onSystemReady()
在KeyguardService绑定成功后调用了onSystemReady方法。onSystemReady最终的处理流程是在KeyguardViewMediator的onSystemReady方法
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@Override // Binder interface public void onSystemReady() { Trace.beginSection("KeyguardService.mBinder#onSystemReady"); checkPermission(); //权限的检查. mKeyguardViewMediator.onSystemReady(); Trace.endSection(); }
KeyguardViewMediator中的onSystemReady方法发送了一条handler消息。经过消息传递会由handleSystemReady方法处理。handleSystemReady方法的关键调用是doKeyguardLocked。
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
public void onSystemReady() { mHandler.obtainMessage(SYSTEM_READY).sendToTarget(); } private void handleSystemReady() { synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); mSystemReady = true; //关键处理 doKeyguardLocked(null); // handleSystemReady方法的关键调用是doKeyguardLocked。 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(); } /** * Enable the keyguard if the settings are appropriate. */ private void doKeyguardLocked(Bundle options) { //如果其他应用阻止我们显示,那么就不显示。。例如:接打电话 if (!mExternallyEnabled || PowerOffAlarmManager.isAlarmBoot()) { return; } //如果锁屏正在显示,那我们就不去显示 if (mStatusBarKeyguardViewManager.isShowing()) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); resetStateLocked(); if (DEBUG) { Log.d(TAG, "doKeyguard: not showing because it is already showing"); } return; } // 判断是否无sim卡也可使用手机 // Settings中没有启用锁屏 ...... //经过上述判断后,再去显示锁屏 showLocked(options); } /** * showLocked显示锁屏方法主要处理:请求CPU不休眠,发送显示锁屏消息。 */ private void showLocked(Bundle options) { Trace.beginSection("KeyguardViewMediator#showLocked aqcuiring mShowKeyguardWakeLock"); if (DEBUG) Log.d(TAG, "showLocked"); // ensure we stay awake until we are finished displaying the keyguard // 获取PARTIAL_WAKE_LOCK,不受电源键影响,不让CPU进入休眠状态 mShowKeyguardWakeLock.acquire(); // 获取之后是无法让CPU休眠,不要忘记释放,不让会增加系统功耗。 Message msg = mHandler.obtainMessage(SHOW, options); mHandler.sendMessage(msg); Trace.endSection(); } /** * handleShow() 处理锁屏消息的方法 */ private void handleShow(Bundle options) { .. synchronized (KeyguardViewMediator.this) { .. setShowingLocked(true); // 显示keyguard mStatusBarKeyguardViewManager.show(options); .. // 释放mShowKeyguardWakeLock mShowKeyguardWakeLock.release(); } mKeyguardDisplayManager.show(); Trace.endSection(); }
在handleShow中调用StatusBarKeyguardViewManager方法,锁屏处理由KeyguardViewMediator转移到StatusBarKeyguardViewManager。
3 其他各重要部分
3.1 StatusBarKeyguardViewManager
StatusBarKeyguardViewManager中show方法设置keyguard是否显示,通知statusbar显示锁屏,重置view的状态,进行锁屏。
public void show(Bundle options) { mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); //重置状态 reset(true /* hideBouncerWhenShowing */); StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); }
StatusBarKeyguardViewManager中reset方法,主要调用showBouncerOrKeyguard方法。判断显示默认锁屏界面还是显示密码锁屏。默认锁屏界面由StatusBar管理,而密码解锁则调用KeyguardBouncer类。
// 判断是调用安全锁屏还是调用滑动锁屏 protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) { //是否需要显示密码锁屏界面,即获得当前是哪一种安全模式 if (mBouncer.needsFullscreenBouncer() && !mDozing) { // The keyguard might be showing (already). So we need to hide it. //隐藏锁屏,显示密码解锁界面 mStatusBar.hideKeyguard(); mBouncer.show(true /* resetSecuritySelection */); } else { mStatusBar.showKeyguard(); //显示锁屏,隐藏密码解锁界面 if (hideBouncerWhenShowing) { hideBouncer(shouldDestroyViewOnReset() /* destroyView */); mBouncer.prepare(); } } updateStates(); }
在我这手机打日志,发现走的是else分支,mStatusBar.showKeyguard()应该是手机锁解锁界面的前面那个屏幕锁屏界面。因为我将else分支的mStatusBar.showKeyguard()改为了mStatusBar.hideKeyguard()就没有了屏幕锁屏界面。
3.2 KeyguardBouncer
在StatusBarKeyguardViewManager类中,StatusBar类则管理默认锁屏界面,KeyguardBouncer类控制密码解锁界面的,KeyguardBouncer会进行锁屏view的填充,KeyguardHostView是自定义容器,内部锁屏相关的处理在KeyguardSecurityContainer中。
private void showPrimarySecurityScreen() { mKeyguardView.showPrimarySecurityScreen(); }
继续往下跟进,会发现最终会调用到KeyguardSecurityContainer类中,在showSecurityScreen方法中会根据锁屏的类型获得锁屏的view,并添加到KeyguardSecurityViewFlipper 。
// 该方法showSecurityScreen(),用来判断加载哪种解锁界面,例如:pin锁、密码锁。如果当前类型,与传过来的参数类型一样,则是同一类型,不需要重新加载,否则重新添加视图。 private void showSecurityScreen(SecurityMode securityMode) { if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); //判断此参数安全模式是否与当前安全模式相同,如果相同则直接返回。 if (securityMode == mCurrentSecuritySelection) return; KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); KeyguardSecurityView newView = getSecurityView(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(); //寻找当前安全模式对应的view,并进行展示。(此时PIN码解锁解锁已在getSecurityView()中添加至mSecurityViewFlipper) //到这里view的展示也到达了本文流程的终点。 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()); } private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { // 获取对应类型锁的视图 id, final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); KeyguardSecurityView view = null; final int children = mSecurityViewFlipper.getChildCount(); // 从mSecurityViewFlipper中取出此安全模式对应view id的view,按照开机初次抵达这里的情况,此时获取的view为null for (int child = 0; child < children; child++) { if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) { view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child)); break; } } //根据安全模式获得对应的layoutId int layoutId = getLayoutIdFor(securityMode); //如果mSecurityViewFlipper还没有此view并且存在此安全模式对应的layoutId if (view == null && layoutId != 0) { //inflater Layout final LayoutInflater inflater = LayoutInflater.from(mContext); View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);//view在这里被绘制,进行各项初始化。 view = (KeyguardSecurityView) v;// //如果是KeyguardSimPinPukMeView则需要设置phoneid,KeyguardSimPinPukMeView将根据此phoneid展示对应资源 if (view instanceof KeyguardSimPinPukMeView) { KeyguardSimPinPukMeView pinPukView = (KeyguardSimPinPukMeView) view; final int phoneId = mSecurityModel.getPhoneIdUsingSecurityMode(securityMode); pinPukView.setPhoneId(phoneId); } //将此view添加入mSecurityViewFlipper中 mSecurityViewFlipper.addView(v);//在这里添加view至mSecurityViewFlipper updateSecurityView(v); //更新KeyguardSecurityView } return view; } private int getSecurityViewIdForMode(SecurityMode securityMode) { switch (securityMode) { case Pattern: return R.id.keyguard_pattern_view; case PIN: return R.id.keyguard_pin_view; case Password: return R.id.keyguard_password_view; case SimPinPukMe1: case SimPinPukMe2: case SimPinPukMe3: case SimPinPukMe4: return R.id.keyguard_sim_pin_puk_me_view ; } return 0; } protected int getLayoutIdFor(SecurityMode securityMode) { switch (securityMode) { case Pattern: return R.layout.keyguard_pattern_view;//手势 case PIN: return R.layout.keyguard_pin_view;//PIN码 case Password: return R.layout.keyguard_password_view;//密码解锁 case SimPinPukMe1: case SimPinPukMe2: case SimPinPukMe3: case SimPinPukMe4: return R.layout.mtk_keyguard_sim_pin_puk_me_view;//sim_pin_puk_me default: return 0; } }
到这里,view展示,其启动流程也到此结束。
3.3 StatusBar
StatusBar也是继承SystemUI,启动流程和SystemUI一致。并在start的时候添加创建StatusBar相关的view。
public void start() { // 省略部分代码... // 创建整个SystemUI视图并添加到WindowManager中 createAndAddWindows(result); // 省略部分代码... } public void createAndAddWindows(@Nullable RegisterStatusBarResult result) { // 创建整个SystemUI视图 makeStatusBarView(result); // 把视图添加到Window中 mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); }
makeStatusBarView()负责创建整个SystemUI视图,其中包括状态栏。
代码路径: packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { // ... // 1. 实例化整个SystemUI视图,包括状态栏,通知面版, 锁屏 mStatusBarWindow = (StatusBarWindowView) mInjectionInflater.injectable( LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null); }