Android8.1 SystemUI Keyguard之啓動流程

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

相關文章
相關標籤/搜索