學(xué)習(xí)筆記:參考資源 https://blog.csdn.net/qq_15347925/article/details/116722133
一痴颊、流程概述
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()的方法上轮听,最后調(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);
}