Android10.0 SystemUI—keyguard鎖屏加載分析

學(xué)習(xí)筆記:參考資源 https://blog.csdn.net/qq_15347925/article/details/116722133

一痴颊、流程概述

1、SystemUI啟動完成后废麻,進入的第一個界面為鎖屏界面。
2、鎖屏keyguard屬于SystemUI爱咬。
3驰唬、鎖屏開機大致分為兩部分,第一部分是從WindowManagerService開始芯丧,處理鎖屏顯示等流程芍阎。第二部分是KeyguardViewMediator的啟動;


Keyguard時序圖.png

二缨恒、詳細介紹

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()的方法上轮听,最后調(diào)用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();
    }

繼續(xù)跟進岭佳,會發(fā)現(xiàn)WindowManagerService的onSystemUiStarted方法血巍,實際調(diào)用的是PhoneWindowManager中的onSystemUiStarted();(通過接口進行回調(diào))

    @Override
    public void onSystemUiStarted() {
        bindKeyguard();
    }

在PhoneWindowManager中會調(diào)用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的連接成功回調(diào)中,創(chuàng)建KeyguardService包裝類KeyguardServiceWrapper叶洞。包裝類除了KeyguardService鲫凶,還有KeyguardStateMonitor狀態(tài)監(jiān)視器。實際調(diào)用還是通過KeyguardService京办。

 private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
         // KeyguardServiceWrapper包裝類調(diào)用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);
             }
            // 調(diào)用KeyguardService的IPC接口
           
            ..
            ..
     }

     @Override
     public void onServiceDisconnected(ComponentName name) {
         if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
         mKeyguardService = null;
         mKeyguardState.reset();
         ..
     }
 }

在綁定以后掀序,PhoneWindowManager可以調(diào)用代理類KeyguardServiceDelegate間接調(diào)用KeyguardService的binder接口進行各種鎖屏相關(guān)狀態(tài)回調(diào)。

2 KeyguardViewMediato 部分

初次開機Keyguard showLock流程:

系統(tǒng)啟動完成-->PhoneWindowManager.systemReady()-->mKeyguardDelegate.onSystemReady()
-->mKeyguardService.onSystemReady()-->KeyguardService.onSystemReady()

在KeyguardService綁定成功后調(diào)用了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();    //權(quán)限的檢查.
            mKeyguardViewMediator.onSystemReady();
            Trace.endSection();
        }

KeyguardViewMediator中的onSystemReady方法發(fā)送了一條handler消息不恭。經(jīng)過消息傳遞會由handleSystemReady方法處理。handleSystemReady方法的關(guān)鍵調(diào)用是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;
            //關(guān)鍵處理
            doKeyguardLocked(null);  // handleSystemReady方法的關(guān)鍵調(diào)用是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) {
        //如果其他應(yīng)用阻止我們顯示,那么就不顯示钥星。沾瓦。例如:接打電話
        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中沒有啟用鎖屏
        ......
        //經(jīng)過上述判斷后谦炒,再去顯示鎖屏
        showLocked(options);
    }

   
    /**
      * showLocked顯示鎖屏方法主要處理:請求CPU不休眠贯莺,發(fā)送顯示鎖屏消息。
      */
    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進入休眠狀態(tài) 
        mShowKeyguardWakeLock.acquire();    // 獲取之后是無法讓CPU休眠,不要忘記釋放还蹲,不讓會增加系統(tǒng)功耗爹耗。
        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中調(diào)用StatusBarKeyguardViewManager方法,鎖屏處理由KeyguardViewMediator轉(zhuǎn)移到StatusBarKeyguardViewManager谜喊。

3 其他各重要部分

3.1 StatusBarKeyguardViewManager

StatusBarKeyguardViewManager中show方法設(shè)置keyguard是否顯示潭兽,通知statusbar顯示鎖屏,重置view的狀態(tài)斗遏,進行鎖屏山卦。

 public void show(Bundle options) {
        mShowing = true;
        mStatusBarWindowManager.setKeyguardShowing(true);
        //重置狀態(tài)
        reset(true /* hideBouncerWhenShowing */);
        StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
            StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
    }

StatusBarKeyguardViewManager中reset方法,主要調(diào)用showBouncerOrKeyguard方法诵次。判斷顯示默認鎖屏界面還是顯示密碼鎖屏怒坯。默認鎖屏界面由StatusBar管理炫狱,而密碼解鎖則調(diào)用KeyguardBouncer類。

// 判斷是調(diào)用安全鎖屏還是調(diào)用滑動鎖屏
protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
   //是否需要顯示密碼鎖屏界面剔猿,即獲得當(dāng)前是哪一種安全模式
    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();
}

在我這手機打日志归敬,發(fā)現(xiàn)走的是else分支酷含,mStatusBar.showKeyguard()應(yīng)該是手機鎖解鎖界面的前面那個屏幕鎖屏界面。因為我將else分支的mStatusBar.showKeyguard()改為了mStatusBar.hideKeyguard()就沒有了屏幕鎖屏界面汪茧。

3.2 KeyguardBouncer

在StatusBarKeyguardViewManager類中椅亚,StatusBar類則管理默認鎖屏界面,KeyguardBouncer類控制密碼解鎖界面的舱污,KeyguardBouncer會進行鎖屏view的填充呀舔,KeyguardHostView是自定義容器,內(nèi)部鎖屏相關(guān)的處理在KeyguardSecurityContainer中扩灯。

private void showPrimarySecurityScreen() {
        mKeyguardView.showPrimarySecurityScreen();
    }

繼續(xù)往下跟進媚赖,會發(fā)現(xiàn)最終會調(diào)用到KeyguardSecurityContainer類中,在showSecurityScreen方法中會根據(jù)鎖屏的類型獲得鎖屏的view,并添加到KeyguardSecurityViewFlipper 珠插。

  // 該方法showSecurityScreen()惧磺,用來判斷加載哪種解鎖界面,例如:pin鎖捻撑、密碼鎖磨隘。如果當(dāng)前類型,與傳過來的參數(shù)類型一樣顾患,則是同一類型番捂,不需要重新加載,否則重新添加視圖江解。
  private void showSecurityScreen(SecurityMode securityMode) {
        if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
        
        //判斷此參數(shù)安全模式是否與當(dāng)前安全模式相同设预,如果相同則直接返回。
        if (securityMode == mCurrentSecuritySelection) return;
                
        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
        KeyguardSecurityView newView = getSecurityView(securityMode);    // 關(guān)鍵方法膘流,根據(jù)安全模式獲得對應(yīng)的view

        // Emulate Activity life cycle
        //設(shè)置相關(guān)回調(diào)
        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();
        //尋找當(dāng)前安全模式對應(yīng)的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;
            }
        }
        // 更新當(dāng)前的安全選擇
        mCurrentSecuritySelection = securityMode;
        mSecurityCallback.onSecurityModeChanged(securityMode,
                securityMode != SecurityMode.None && newView.needsInput());
    }
    
    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
        // 獲取對應(yīng)類型鎖的視圖 id,
        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
        KeyguardSecurityView view = null;
        final int children = mSecurityViewFlipper.getChildCount();
        // 從mSecurityViewFlipper中取出此安全模式對應(yīng)view id的view画恰,按照開機初次抵達這里的情況彭谁,此時獲取的view為null
        for (int child = 0; child < children; child++) {
            if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
                view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
                break;
            }
        }
        //根據(jù)安全模式獲得對應(yīng)的layoutId
        int layoutId = getLayoutIdFor(securityMode);
        //如果mSecurityViewFlipper還沒有此view并且存在此安全模式對應(yīng)的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則需要設(shè)置phoneid缠局,KeyguardSimPinPukMeView將根據(jù)此phoneid展示對應(yīng)資源
            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展示,其啟動流程也到此結(jié)束狭园。

3.3 StatusBar

StatusBar也是繼承SystemUI读处,啟動流程和SystemUI一致。并在start的時候添加創(chuàng)建StatusBar相關(guān)的view唱矛。

public void start() {

    // 省略部分代碼...

    // 創(chuàng)建整個SystemUI視圖并添加到WindowManager中
    createAndAddWindows(result);

    // 省略部分代碼...
}

public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {

    // 創(chuàng)建整個SystemUI視圖

    makeStatusBarView(result);

    // 把視圖添加到Window中

    mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);

    mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());

}

makeStatusBarView()負責(zé)創(chuàng)建整個SystemUI視圖罚舱,其中包括狀態(tài)欄。
代碼路徑: packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {

      // ...

      // 1. 實例化整個SystemUI視圖绎谦,包括狀態(tài)欄,通知面版, 鎖屏

      mStatusBarWindow = (StatusBarWindowView) mInjectionInflater.injectable(

      LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null);

}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末管闷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子窃肠,更是在濱河造成了極大的恐慌包个,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冤留,死亡現(xiàn)場離奇詭異碧囊,居然都是意外死亡,警方通過查閱死者的電腦和手機搀菩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門呕臂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肪跋,你說我怎么就攤上這事歧蒋。” “怎么了州既?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵谜洽,是天一觀的道長。 經(jīng)常有香客問我吴叶,道長阐虚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任蚌卤,我火速辦了婚禮实束,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逊彭。我一直安慰自己咸灿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布侮叮。 她就那樣靜靜地躺著避矢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上审胸,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天亥宿,我揣著相機與錄音,去河邊找鬼砂沛。 笑死烫扼,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尺上。 我是一名探鬼主播材蛛,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怎抛!你這毒婦竟也來了卑吭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤马绝,失蹤者是張志新(化名)和其女友劉穎豆赏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體富稻,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡掷邦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了椭赋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抚岗。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖哪怔,靈堂內(nèi)的尸體忽然破棺而出宣蔚,到底是詐尸還是另有隱情,我是刑警寧澤认境,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布胚委,位于F島的核電站,受9級特大地震影響叉信,放射性物質(zhì)發(fā)生泄漏亩冬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一硼身、第九天 我趴在偏房一處隱蔽的房頂上張望硅急。 院中可真熱鬧,春花似錦佳遂、人聲如沸营袜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽连茧。三九已至,卻和暖如春巍糯,著一層夾襖步出監(jiān)牢的瞬間啸驯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工祟峦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留罚斗,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓宅楞,卻偏偏與公主長得像针姿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厌衙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容