今天開始梳理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