Android8.1 SystemUI Keyguard之启动流
今天开始梳理SystemUI Keyguard源码
话不多说首先从启动流程开始:
起点是在 SystemUI/src/com/android/systemui/SystemUIService.java
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.java
@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: android developer文档关于WakeLock的解释
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.java
@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.java
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接口进行各种锁屏相关状态回调。
初次开机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
https://blog.csdn.net/qq_28147169/article/details/79467159