今天开始梳理SystemUI Keyguard源码
话很少说首先从启动流程开始:java
起点是在 SystemUI/src/com/android/systemui/SystemUIService.javaandroid
onCreate() -> ((SystemUIApplication) getApplication()).startServicesIfNeeded();
启动SystemUI各个模块
SystemUI/src/com/android/systemui/SystemUIApplication.java安全
public void startServicesIfNeeded() { startServicesIfNeeded(SERVICES); } private void startServicesIfNeeded(Class<?>[] services) { .. startServicesIfNeeded()-> Object newService = SystemUIFactory.getInstance().createInstance(cl); .. mServices[i].start(); .. if (mBootCompleted) { mServices[i].onBootCompleted(); } }
咱们这里主要关注KeyguardViewMediator:
SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.javaapp
@Override public void start() { synchronized (this) { setupLocked(); } putComponent(KeyguardViewMediator.class, this); } private void setupLocked() { // 获取PowerManager mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); // 获取TrustManager mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); // 建立PARTIAL_WAKE_LOCK mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); // 设置WakeLock为不计数机制 mShowKeyguardWakeLock.setReferenceCounted(false); // 注册广播监听 IntentFilter filter = new IntentFilter(); filter.addAction(DELAYED_KEYGUARD_ACTION); filter.addAction(DELAYED_LOCK_PROFILE_ACTION); filter.addAction(Intent.ACTION_SHUTDOWN); mContext.registerReceiver(mBroadcastReceiver, filter); mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); // KeyguardUpdateMontitor注册一堆广播监听和Listener mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mLockPatternUtils = new LockPatternUtils(mContext); KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser()); // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard // is disabled. if (mContext.getResources().getBoolean( com.android.keyguard.R.bool.config_enableKeyguardService)) { setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled( KeyguardUpdateMonitor.getCurrentUser()), mSecondaryDisplayShowing, true /* forceCallbacks */); } // 把statusbar和keyguard关联起来,将mViewMediatorCallback传给mStatusBarKeyguardViewManager mStatusBarKeyguardViewManager = SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext, mViewMediatorCallback, mLockPatternUtils); final ContentResolver cr = mContext.getContentResolver(); /* 获取设备可交互状态 true : 包括dreaming false: dozing或asleep * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on} * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast * whenever the interactive state of the device changes. For historical reasons, * the names of these broadcasts refer to the power state of the screen * but they are actually sent in response to changes in the overall interactive * state of the device, as described by this method.*/ mDeviceInteractive = mPM.isInteractive(); // 加载锁屏解锁音频和音量 mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0); String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND); if (soundPath != null) { mLockSoundId = mLockSounds.load(soundPath, 1); } .. .. int lockSoundDefaultAttenuation = mContext.getResources().getInteger( com.android.internal.R.integer.config_lockSoundVolumeDb); mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20); // 加载动画 (仅用于得到动画时间偏移量) mHideAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.lock_screen_behind_enter); mWorkLockController = new WorkLockActivityController(mContext); }
关于WakeLock:less
android developer文档关于WakeLock的解释ide
WakeLock计数机制(setReferenceCounted):
在建立了PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另外一种是计数锁机制。这能够经过setReferenceCounted( boolean value) 来指定,默认为计数机制。这两种机制的区别在于,前者不管acquire() 了多少次,只要经过一次release() 便可解锁。然后者正真解锁是在(--count == 0 )的时候,一样当(count == 0) 的时候才会去申请加锁,其余状况下isHeld 状态是不会改变的。因此PowerManager.WakeLock 的计数机制并非正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计。动画
KeyguardService的启动:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javaui
@Override /** * Called when the system is done booting to the point where the * user can start interacting with it. */ public void systemBooted() { bindKeyguard(); .. }
frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.javathis
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.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); intent.setComponent(keyguardComponent); if (!context.bindServiceAsUser(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) { .. } 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接口进行各类锁屏相关状态回调。google
初次开机Keyguard showLock流程:
系统启动完成-->PhoneWindowManager.systemReady()-->mKeyguardDelegate.onSystemReady()
-->mKeyguardService.onSystemReady()-->KeyguardService.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(); }
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
public void onSystemReady() { 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(); } /** * Enable the keyguard if the settings are appropriate. */ private void doKeyguardLocked(Bundle options) { // 判断是否是安全启动 if (KeyguardUpdateMonitor.CORE_APPS_ONLY) { // Don't show keyguard during half-booted cryptkeeper stage. if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper"); 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 (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); showLocked(options); } /** * Send message to keyguard telling it to show itself * @see #handleShow */ private void showLocked(Bundle options) { // 持有mShowKeyguardWakeLock // ensure we stay awake until we are finished displaying the keyguard mShowKeyguardWakeLock.acquire(); Message msg = mHandler.obtainMessage(SHOW, options); mHandler.sendMessage(msg); Trace.endSection(); } /** * Handle message sent by {@link #showLocked}. * @see #SHOW */ private void handleShow(Bundle options) { .. synchronized (KeyguardViewMediator.this) { .. setShowingLocked(true); // 显示keyguard mStatusBarKeyguardViewManager.show(options); .. // 释放mShowKeyguardWakeLock mShowKeyguardWakeLock.release(); } mKeyguardDisplayManager.show(); Trace.endSection(); }
接下来就要处理Keyguard绘制的逻辑了,这部分主要是在StatusBarKeyguardViewManager中
调用showBouncerOrKeyguard()方法去显示notification keyguard仍是bouncer,在灭屏的状况下,再次亮屏看到的通常是notification keyguard,就是有消息通知、时间之类的那个view,上滑才会显示密码解锁界面,也就是bouncer。接着就会调用showKeyguard(),固然因为尚未绘制内容,因此会进行keyguard的绘制。这里会调用hideBouncer()去隐藏已有的bouncer,由于下次亮屏的时候可能不是原来的锁屏方式。例如原来是PIN解锁,而咱们在settings去重置了锁屏为pattern,那下次亮屏就应该显示pattern的view。
/** * Show the keyguard. Will handle creating and attaching to the view manager * lazily. */ public void show(Bundle options) { mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); mScrimController.abortKeyguardFadingOut(); reset(true /* hideBouncerWhenShowing */); } /** * Shows the notification keyguard or the bouncer depending on * {@link KeyguardBouncer#needsFullscreenBouncer()}. */ 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(false /* destroyView */); mBouncer.prepare(); } } updateStates(); }
参考文档:
https://developer.android.google.cn/reference/android/os/PowerManager
https://blog.csdn.net/zhandoushi1982/article/details/8513203
http://www.javashuo.com/article/p-mlfdipgm-mh.html