Keyguard 与 SystemUI
PATH: /frameworks/base/packages/SystemUI/src/com/android/
Keyguard 与 SystemUI 进程
Keyguard 与 SystemUI 运行在同一进程中,即com.android.systemui进程。这点可以从manifest.xml文件就可以看出。
Keyguard
<application android:label="@string/app_name"
android:process="com.android.systemui"
android:persistent="true"
android:supportsRtl="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
SystemUI
<application
android:name=".SystemUIApplication"
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
android:icon="@drawable/icon"
android:process="com.android.systemui"
android:supportsRtl="true"
android:theme="@style/systemui_theme"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
通过Android.mk可知:在编译过程中,keyguard被打包成静态Java库. Keygaurd实际是由SystemUI来管理的.
# Keyguard Android.mk
include $(BUILD_STATIC_JAVA_LIBRARY)
# SystemUI:
LOCAL_STATIC_JAVA_LIBRARIES := \
com.mediatek.systemui.ext \
Keyguard \
类的简单含义
Android锁屏流程分析,主要用到的核心类如下:
keyguardUpdateMonitor是状态回调的管理类, 类似于一个监视器, 用于监听keyguard的更新变化.
keyguardBouncer 是锁屏view的通信交互类。
KeyguardServiceDelegate.java 继承了接口IKeyguardService; 同时KeyguardService完成了IKeyguardService的远程实现. 即这两个类通过底层aidl进行远程通信. 进入系统可以控制Keyguard服务的启动.
KeyguardServiceDelegate.java 是一个局部类,保存keyguard在崩溃之前的状态,用来恢复。同时它也可以运行时选择本地或远程的keyguard实例.
KeyguardViewMediator.java 作为一个中介类, 连接Keyguard与Systemui.其职能包括查询keyguard的状态, Keyguard在开关键的事件的动作,如显示或重置等。(KeyguardViewMediator 继承SystemUI, 是锁屏的核心类, 是交互的中转类,其它对象都通过KeyguardViewMediator对象相互交互。)
KeyguardSecurityContainer.java 这个类主要用于装载Pattern, password, pin等解锁视图的容器.
StatusBarKeyguardViewManger.java 在status bar中, 管理创建, 显示, 隐藏, 重置 状态栏中的 Keyguard.
锁屏流程概述
- SystemServer这个系统服务线程由底层开启, 该系统服务将开启一系列的服务, 其中Keyguard的流程会流到WindowManagerPolicy进行处理。
- WindowManagerPolicy的实现类是PhoneWindowManager。其将 keyguard 事件分发到 KeyguardServiceDelegate 进行处理.
- KeyguardServiceDelegate里绑定 KeyguardService 服务。 并调用onSystemReady方法。此时进入到SystemUI, 并调用KeyguardViewMediator决定是否显示视图。
(IkeyguardService 由KeyguardServiceWrapper包装类继承, 由KeyguardService远程实现. 实现底层与Systemui的通信,保证两者之间数据共享)。
- keyguard事件传递到了SystemUI, 并由KeyguardViewMediator进行事件的分派. 如部分视图由SystemUI显示, 即如StatusBarKeyguardViewManager来处理,并进入到KeyguardBouncer。 部分视图将传递到Keyguard, 由Keyguard来绘制, 如 KeyguardSecurityContainer来处理。
锁屏流程详述
- Zygote进程启动后会首先创建一个SystemServer进程;
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/* Request to fork the system server process */
pid = Zygote.forkSystemServer ...
- SystemServer进程在调用startOtherServices时,同时也会调用WindowManagerService的systemReady()方法;
/frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
...
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
...
try {
wm.systemReady(); //WindowManagerService的systemReady()方法
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
}
- 在WindowManagerService服务中,直接调用了WindowManagerPolicy.java的systemReady()方法,而具体方法的实现在PhoneWindowManager.java中。
注: 窗口管理服务WindowManagerService的职责是对系统中的所有窗口进行管理
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@VisibleForTesting
WindowManagerPolicy mPolicy;
public void systemReady() {
mSystemReady = true;
mPolicy.systemReady();
...
}
- 在PhoneWindowManager的systemReady()中,会依据一个Boolean值bindKeyguardNow来决定是否绑定keyguard service
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
public void systemReady() {
mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
mKeyguardDelegate.onSystemReady(); //分派到KeyguardDelegate进行处理,开机时不做任何处理.
...
synchronized (mLock) {
...
bindKeyguardNow = mDeferBindKeyguard;
if (bindKeyguardNow) {
// systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
mDeferBindKeyguard = false;
}
}
if (bindKeyguardNow) {//如果已经绑定KeyguardService,进行处理.
mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
...
}
- 看到这里,假设 bindKeyguardNow 为false就会不绑定,后面通过继续跟踪发现PhoneWindowManager的systemBooted()里也会去绑定keyguard service。假设在systemBooted里绑定,就不在systemReady里再去绑定(某大佬描述:是在systemBooted绑定)。
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
/** {@inheritDoc} */
@Override
public void systemBooted() {
bindKeyguard();
synchronized (mLock) {
mSystemBooted = true;
if (mSystemReady) {
mKeyguardDelegate.onBootCompleted();
}
}
mSideFpsEventHandler.onFingerprintSensorReady();
startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
int defaultDisplayState = mDisplayManager.getDisplay(DEFAULT_DISPLAY).getState(); boolean defaultDisplayOn = defaultDisplayState == Display.STATE_ON;
boolean defaultScreenTurningOn = mDefaultDisplayPolicy.getScreenOnListener() != null;
if (defaultDisplayOn || defaultScreenTurningOn) {
// Now that system is booted, wait for keyguard and windows to be drawn before
// updating the orientation listener, stopping the boot animation and enabling screen.
screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener());
screenTurnedOn(DEFAULT_DISPLAY);
} else {
// We're not turning the screen on, so don't wait for keyguard to be drawn
// to dismiss the boot animation and finish booting
mBootAnimationDismissable = true;
enableScreen(null, false /* report */);
}
}
private void bindKeyguard() {
synchronized (mLock) {
if (mKeyguardBound) {
return;
}
mKeyguardBound = true;
}
mKeyguardDelegate.bindService(mContext);
}
- 通过时序图看看是如何调用到systemBooted的

- 不管是在systemReady或systemBooted,都调用了KeyguardServiceDelegate对象的bindService方法
显示锁屏界面
锁屏界面是怎么显示出来的,先看看以下的时序图

- 进入KeyguardServiceDelegate.java中, 将绑定keyguardService服务.
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);
/* notice */
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");
}
}
- 在 bindService 中调用了 bindServiceAsUser, 绑定指定intent的service。
frameworks/base/core/res/res/values/config.xml
config_keyguardComponent的定义, 例如
<!-- Keyguard component -->
<string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
- 当绑定成功后会调用mKeyguardConnection里的onServiceConnected方法。mKeyguardDelegate.onServiceConnected()进入到了KeyguardServiceWrapper。并将任务分派到KeyguardService, 启动Keyguard服务。
frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
...
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();
...
...
}
...
};
- 当mKeyguardState.systemIsReady为true时,就会通过KeyguardServiceWrapper的实例mKeyguardService,调用onSystemReady方法。在KeyguardServiceWrapper的onSystemReady里, 调用了上面刚刚绑定成功的KeyguardService的onSystemReady方法。
frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
public class KeyguardServiceWrapper implements IKeyguardService {
...
@Override // Binder interface
public void onSystemReady() {
try {
mService.onSystemReady();
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
}
...
}
- 在KeyguardService的onSystemReady里调用了KeyguardViewMediator里的onSystemReady。
/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
public void onSystemReady() {
checkPermission(); //权限的检查
mKeyguardViewMediator.onSystemReady();
}
}
可以看出,其实这两个类就是跨进程通信.通过IKeyguardService这个接口来进行framework与Systemui之间的跨进程通信.此时,流程就进入到了SystemUI.
进入SystemUI这个应用后, 将进入Keyguard的一个重要的类KeyguardViewMediator。该方法主要是进行广播:标志这系统在启动后已经准备好了.接着,doKeyguardLocked()方法收到了null参数。可以看到这个方法主要是针对不同的keyguard模式进行判别.
- KeyguardViewMediator.onSystemReady
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
public class KeyguardViewMediator extends SystemUI {
...
public void onSystemReady() {
mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
synchronized (this) {
if (DEBUG) Log.d(TAG, "onSystemReady");
mSystemReady = true;
doKeyguardLocked(null); //锁屏路径
mUpdateMonitor.registerCallback(mUpdateCallback); // 注冊了KeyguardUpdateMonitorCallback
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
}
...
}
- 通过调用doKeyguardLocked显示锁屏界面
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
这段代码主要是在是否要显示锁屏之前做了5个推断:
1. 当前正在解密界面不显示。
2. 假设启用第三方锁屏界面, 不显示原生界面;
3. 锁屏界面已经显示了话,又一次更新下状态;
4. 假设第一次开机引导界面setup wizard 还没有执行,也先不显示;
5. 屏幕没有亮不显示;
假设这几个条件都不满足, 则调用showLocked显示锁屏界面。
/**
* 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 another app is disabling us, don't show
// 外置apk的keyguard等
if (!mExternallyEnabled) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
mNeedToReshowWhenReenabled = true;
return;
}
// if the keyguard is already showing, don't bother. check flags in both files
// to account for the hiding animation which results in a delay and discrepancy
// between flags
if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
resetStateLocked();
return;
}
// In split system user mode, we never unlock system user.
if (!mustNotUnlockCurrentUser()
|| !mUpdateMonitor.isDeviceProvisioned()) {
// if the setup wizard hasn't run yet, don't show
final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
final boolean absent = SubscriptionManager.isValidSubscriptionId(
mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_ABSENT));
final boolean disabled = SubscriptionManager.isValidSubscriptionId(
mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PERM_DISABLED));
final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
|| ((absent || disabled) && requireSim);
if (!lockedOrMissing && shouldWaitForProvisioning()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
+ " and the sim is not locked or missing");
return;
}
boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false);
if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
&& !lockedOrMissing && !forceShow) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
}
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked(options);
}
- 在showLocked通过mHandler发送Message。在handleMessage里“case SHOW:”时调用 handleShow
frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
private void showLocked(Bundle options) {
setReadyToShow(true); //设置参数.
updateActivityLockScreenState(); //更新锁屏状态,使用进程间通信技术
// ensure we stay awake until we are finished displaying the keyguard
mShowKeyguardWakeLock.acquire(); //获取唤醒锁.不受电源影响,不让cpu进入休眠状态.
Message msg = mHandler.obtainMessage(SHOW, options);
mHandler.sendMessage(msg); //使用handler子线程来处理显示
}
- 在 handleShow 里设置一些锁屏状态和显示锁屏界面
/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
// 注意链接前面的 mHandler
private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW:
handleShow((Bundle) msg.obj);
break;
/**
* Handle message sent by {@link #showLocked}.
* @see #SHOW
*/
private void handleShow(Bundle options) {
Trace.beginSection("KeyguardViewMediator#handleShow");
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
if (mLockPatternUtils.isSecure(currentUser)) {
mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
}
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
return;
} else {
if (DEBUG) Log.d(TAG, "handleShow");
}
mHiding = false;
mKeyguardExitAnimationRunner = null;
mWakeAndUnlocking = false;
setPendingLock(false);
setShowingLocked(true);
mKeyguardViewControllerLazy.get().show(options); // 跳转到StatusBarKeyguardViewManager中的show()方法
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
userActivity();
mUpdateMonitor.setKeyguardGoingAway(false);
mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false);
mShowKeyguardWakeLock.release();
}
mKeyguardDisplayManager.show();
// schedule 4hr idle timeout after which non-strong biometrics (i.e. weak or convenience
// biometric) can't be used to unlock device until unlocking with strong biometric or
// primary auth (i.e. PIN/pattern/password)
mLockPatternUtils.scheduleNonStrongBiometricIdleTimeout(
KeyguardUpdateMonitor.getCurrentUser());
Trace.endSection();
}
- 通过调用 StatusBarKeyguardViewManager 的show()方法重置当前状态, 显示keyguard
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
/**
* Show the keyguard. Will handle creating and attaching to the view manager
* lazily.
*/
@Override
public void show(Bundle options) {
Trace.beginSection("StatusBarKeyguardViewManager#show");
mShowing = true;
mNotificationShadeWindowController.setKeyguardShowing(true);
mKeyguardStateController.notifyKeyguardState(mShowing,
mKeyguardStateController.isOccluded());
reset(true /* hideBouncerWhenShowing */);
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
Trace.endSection();
}
- 在reset()方法里调用本类的 showBouncerOrKeyguard。
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@Override
public void reset(boolean hideBouncerWhenShowing) {
if (mShowing) {
// Hide quick settings.
mNotificationPanelViewController.resetViews(/* animate= */ true);
// Hide bouncer and quick-quick settings.
if (mOccluded && !mDozing) { // mOccluded代表是否被其他窗口中断
// 参数为true, 表示隐藏安全锁界面
mCentralSurfaces.hideKeyguard();
if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) {
hideBouncer(false /* destroyView */);
}
} else {
showBouncerOrKeyguard(hideBouncerWhenShowing); // 滑动锁或Keyguard锁
}
resetAlternateAuth(false);
mKeyguardUpdateManager.sendKeyguardReset();
updateStates();
}
}
- showBouncerOrKeyguard()方法使用 KeyguardBouncer.java 的needsFullscreenBouncer()方法判断显示常规锁屏还是Bouncer安全锁屏。
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
protected void showBouncerOrKeyguard() { //判断锁使用的锁类型.
...
if (mBouncer.needsFullscreenBouncer()) {
// The keyguard might be showing (already). So we need to hide it.
mPhoneStatusBar.hideKeyguard();
mBouncer.show(true /* resetSecuritySelection */);
} else {
mPhoneStatusBar.showKeyguard(); // 显示滑动锁屏
mBouncer.hide(false /* destroyView */);
mBouncer.prepare();
}
}
- 当前获取的Bouncer的类型是SimPin或者SimPuk时,通过mKeyguardView.getSecurityMode()获取当前Bouncer的类型时最终是调到KeyguardSecurityModel的getSecurityMode方法,通过KeyguardUpdateMonitor 这个类获取当前SIM卡的状态来判断的,当状态是PIN_REQUIRED或者PUK_REQUIRED, 则说明应该直接显示类型为SecurityMode.SimPin或者SecurityMode.SimPuk的密码锁屏(这类直接在systemui中处理了),所以当我们插入一张带密码的SIM卡时会立即显示sim pin界面
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
public boolean needsFullscreenBouncer() {
SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser());
return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
}
- 其他则为一般解锁, 其将进入到Keyguard中去进行处理, 称为:notification keyguard, 包括pattern, password, PIN。这种 keyguard 视图的父视图为 KeyguardSecurityContainer。SecurityMode定义如下:
/frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
public enum SecurityMode {
Invalid, // NULL state
None, // No security enabled
Pattern, // Unlock by drawing a pattern.
Password, // Unlock by entering an alphanumeric password
PIN, // Strictly numeric password
SimPin, // Unlock by entering a sim pin.
SimPuk // Unlock by entering a sim puk
}
- 在mBouncer.prepare()方法中,调用 showPrimarySecurityScreen。
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
public void prepare() {
boolean wasInitialized = mInitialized;
ensureView();
if (wasInitialized) {
showPrimarySecurityScreen();
}
mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
}
- 通过 KeyguardHostViewController的showPrimarySecurityScreen 再调用 KeyguardSecurityContainer 的showPrimarySecurityScreen() 方法。
/frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
public void showPrimarySecurityScreen() {
if (DEBUG) Log.d(TAG, "show()");
mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
- 最后根据不同的keyguard模式来进行界面的重绘。利用mSecurityModel.getSecurityMode()获取当前的securityMode,传入showSecurityScreen来显示不同锁屏界面。
frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
public void showPrimarySecurityScreen(boolean turningOff) {
SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser()));
if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
showSecurityScreen(securityMode);
}
参考链接
http://t.zoukankan.com/blfbuaa-p-7288867.html
https://developer.aliyun.com/article/1124660
本文详细介绍了Android系统中Keyguard与SystemUI的关系,它们在同一进程中运行。Keyguard由SystemUI管理,核心类如KeyguardViewMediator作为中介,连接Keyguard与SystemUI,处理锁屏的显示和隐藏。锁屏流程涉及SystemServer、PhoneWindowManager、KeyguardServiceDelegate等多个组件,通过IKeyguardService接口进行跨进程通信。当系统准备好后,调用KeyguardService的onSystemReady方法,进而显示锁屏界面。
1196

被折叠的 条评论
为什么被折叠?



