link:Android 8.1 开机启动流程的收尾_bootanimation开机动画结束和BOOT_COMPLETE广播发送流程整理
1.问题
FDE设备在输入图案密码start android时,boot_progress_enable_screen到sf_stop_bootanim花费15s
boot_progress_enable_screen AMS启动完成后开始激活屏幕,从此以后屏幕才能响应用户的触摸,它在WindowManagerService发出退出开机动画的时间节点之前,而真正退出开机动画还会花费少许时间,具体依赖animation zip 包中的desc.txt。wm_boot_animation_done才是用户感知到的动画结束时间节点
sf_stop_bootanim SF设置service.bootanim.exit属性值为1,标志系统要结束开机动画了,可以用来跟踪开机动画结尾部分消耗的时间
wm_boot_animation_done 开机动画结束,这一步用户能直观感受到开机结束
2.分析
enable_scrren到bootani finish从如下方法说起
//最后的值performEnableScreen: mDisplayEnabled=false mForceDisplayEnabled=false mShowingBootMessages=false mSystemBooted=true mOnlyCore=false
@/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private void performEnableScreen() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
+ " mForceDisplayEnabled=" + mForceDisplayEnabled
+ " mShowingBootMessages=" + mShowingBootMessages
+ " mSystemBooted=" + mSystemBooted
+ " mOnlyCore=" + mOnlyCore,
new RuntimeException("here").fillInStackTrace());
if (mDisplayEnabled) {
return;
}
if (!mSystemBooted && !mShowingBootMessages) {
return;
}
if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {
return;
}
// Don't enable the screen until all existing windows have been drawn.
if (!mForceDisplayEnabled
// TODO(multidisplay): Expand to all displays?
&& getDefaultDisplayContentLocked().checkWaitingForWindows()) {
return;
}
//设置属性,通知surfaceflinger退出开机动画
if (!mBootAnimationStopped) {
Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
SystemProperties.set("service.bootanim.exit", "1");
mBootAnimationStopped = true;
}
if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
return;
}
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
}
//写event log wm_boot_animation_done,sys log打印ENABLING SCREEN
EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
mDisplayEnabled = true;
if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!");
// Enable input dispatch.
mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
}
try {
mActivityManager.bootAnimationComplete();
} catch (RemoteException e) {
}
mPolicy.enableScreenAfterBoot();
// Make sure the last requested orientation has been applied.
updateRotationUnchecked(false, false);
}
07-03 10:20:27.762 3015 3037 I WindowManager: performEnableScreen: mDisplayEnabled=false mForceDisplayEnabled=false mShowingBootMessages=false mSystemBooted=true mOnlyCore=false
07-03 10:20:27.762 3015 3037 I WindowManager: java.lang.RuntimeException: here
07-03 10:20:27.762 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.762 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.-wrap6(Unknown Source:0)
07-03 10:20:27.762 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5266)
07-03 10:20:27.762 3015 3037 I WindowManager: at android.os.Handler.dispatchMessage(Handler.java:106)
07-03 10:20:27.762 3015 3037 I WindowManager: at android.os.Looper.loop(Looper.java:164)
07-03 10:20:27.762 3015 3037 I WindowManager: at android.os.HandlerThread.run(HandlerThread.java:65)
07-03 10:20:27.762 3015 3037 I WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:46)
07-03 10:20:27.763 3015 3037 I WindowManager: ******** booted=true msg=false haveBoot=false haveApp=false haveWall=true wallEnabled=true haveKeyguard=true
//不会一次就ok,会多次,我这里时候出问题是卡在getDefaultDisplayContentLocked().checkWaitingForWindows,花费15s,因此检测为什么
07-03 10:20:26.756 3015 3030 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.832 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.851 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.869 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.879 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.895 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.913 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.916 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:26.939 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.089 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.095 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.135 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.144 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.226 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.249 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.261 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.312 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.357 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
07-03 10:20:27.762 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
检查在如下位置return true了,大概是说有wallpaper keyguard statusbar之类没有画完
@/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
boolean checkWaitingForWindows() {
...
final WindowState visibleWindow = getWindow(w -> {
if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
return true; //添加log发现这里一直return true
}
if (w.isDrawnLw()) {
if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
mHaveBootMsg = true;
} else if (w.mAttrs.type == TYPE_APPLICATION
|| w.mAttrs.type == TYPE_DRAWN_APPLICATION) {
mHaveApp = true;
} else if (w.mAttrs.type == TYPE_WALLPAPER) {
mHaveWallpaper = true;
} else if (w.mAttrs.type == TYPE_STATUS_BAR) {
mHaveKeyguard = mService.mPolicy.isKeyguardDrawnLw();
}
}
return false;
});
...
if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM,
"******** booted=" + mService.mSystemBooted
+ " msg=" + mService.mShowingBootMessages
+ " haveBoot=" + mHaveBootMsg + " haveApp=" + mHaveApp
+ " haveWall=" + mHaveWallpaper + " wallEnabled=" + wallpaperEnabled
+ " haveKeyguard=" + mHaveKeyguard);
// If we are turning on the screen to show the boot message, don't do it until the boot
// message is actually displayed.
if (!mService.mSystemBooted && !mHaveBootMsg) {
return true;
}
// If we are turning on the screen after the boot is completed normally, don't do so until
// we have the application and wallpaper.
if (mService.mSystemBooted
&& ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) {
return true;
}
return false;
}
搜索keygaurd字眼,发现keyguard show确认花费很长时间
keyguard显示从doKeyguardLocked到showLocked,这里添加log发现是卡在了checkVoldPassword
@/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
/**
* 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
if (!mExternallyEnabled) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
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;
}
// In split system user mode, we never unlock system user.
if (!mustNotUnlockCurrentUser()
|| !mUpdateMonitor.isDeviceProvisioned()) {
...
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 (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
// Without this, settings is not enabled until the lock screen first appears
setShowingLocked(false, mAodShowing);
hideLocked();
return;
}
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked(options);
}
/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsService.java
@Override
public boolean checkVoldPassword(int userId) throws RemoteException {
...
final IStorageManager service = mInjector.getStorageManager();
String password;
long identity = Binder.clearCallingIdentity();
try {
password = service.getPassword();
service.clearPassword();
} finally {
Binder.restoreCallingIdentity(identity);
}
//有图案密码,就去认证
try {
if (mLockPatternUtils.isLockPatternEnabled(userId)) {
if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
null /* progressCallback */)
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
return true;
}
}
} catch (Exception e) {
}
...
return false;
}
@Override
public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
}
//锁屏checkpattern都是在这里,密码验证错误,一般都是gatekeeper返回是error
private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
VerifyCredentialResponse response = null;
response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge,
userId, progressCallback);
// The user employs synthetic password based credential.
if (response != null) {
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
mRecoverableKeyStoreManager.lockScreenSecretAvailable(credentialType, credential,
userId);
}
return response;
}
...
return response;
}
private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
credentialType, boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
...
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
notifyActivePasswordMetricsAvailable(userCredential, userId);
unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
unlockUser(userId, null, secret); //here
...
onAuthTokenKnownForUser(userId, authResult.authToken);
}
...
}
终于到我们卡住的位置了,接着看mActivityManager.unlockUser为什么15s也没有执行onFinished
@/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsService.java
private void unlockUser(int userId, byte[] token, byte[] secret) {
// TODO: make this method fully async so we can update UI with progress strings
final CountDownLatch latch = new CountDownLatch(1);
//定义listener
final IProgressListener listener = new IProgressListener.Stub() {
@Override
public void onStarted(int id, Bundle extras) throws RemoteException {
Log.d(TAG, "unlockUser started");
}
@Override
public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
Log.d(TAG, "unlockUser progress " + progress);
}
@Override
public void onFinished(int id, Bundle extras) throws RemoteException {
Log.d(TAG, "unlockUser finished");
latch.countDown();
}
};
//mActivityManager.unlockUser
try {
mActivityManager.unlockUser(userId, token, secret, listener);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
//没有调用onFinished的话,会等15s,然后timeout才能过去,这里就是我们开机慢的位置
try {
latch.await(15, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
...
}
//接下来看unlockUser干什么的,最终到UserController.java
/frameworks/base/services/core/java/com/android/server/am/UserController.java
boolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) {
final long binderToken = Binder.clearCallingIdentity();
try {
return unlockUserCleared(userId, token, secret, listener);
} finally {
Binder.restoreCallingIdentity(binderToken);
}
}
private boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
IProgressListener listener) {
UserState uss;
synchronized (mLock) {
// Register the given listener to watch for unlock progress
uss = mStartedUsers.get(userId);
if (uss != null) {
uss.mUnlockProgress.addListener(listener); //这里是关于onfinish操作
uss.tokenProvided = (token != null);
}
}
// Bail if user isn't actually running
if (uss == null) {
notifyFinished(userId, listener);
return false;
}
finishUserUnlocking(uss);
...
for (int testUserId : userIds) {
final UserInfo parent = mInjector.getUserManager().getProfileParent(testUserId);
if (parent != null && parent.id == userId && testUserId != userId) {
Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
+ "): attempting unlock because parent was just unlocked");
maybeUnlockUser(testUserId);
}
}
return true;
}
//STATE_FINISHED就会回调onFinished,就不会timeout
@/frameworks/base/core/java/com/android/internal/util/ProgressReporter.java
public void addListener(@Nullable IProgressListener listener) {
if (listener == null) return;
synchronized (this) {
mListeners.register(listener);
switch (mState) {
case STATE_INIT:
// Nothing has happened yet
break;
case STATE_STARTED:
try {
listener.onStarted(mId, null);
listener.onProgress(mId, mProgress, mExtras);
} catch (RemoteException ignored) {
}
break;
case STATE_FINISHED:
try {
listener.onFinished(mId, null);
} catch (RemoteException ignored) {
}
break;
}
}
}
//只有这里赋值
public void finish() {
synchronized (this) {
mState = STATE_FINISHED;
notifyFinished(mId, null);
mListeners.kill();
}
}
private void finishUserUnlocking(final UserState uss) {
uss.mUnlockProgress.start();
// Call onBeforeUnlockUser on a worker thread that allows disk I/O
FgThread.getHandler().post(() -> {
uss.mUnlockProgress.setProgress(20);
// Dispatch unlocked to system services; when fully dispatched,
// that calls through to the next "unlocked" phase
mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
.sendToTarget();
});
}
/**
* Step from {@link UserState#STATE_RUNNING_UNLOCKING} to
* {@link UserState#STATE_RUNNING_UNLOCKED}.
*/
void finishUserUnlocked(final UserState uss) {
...
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
uss.mUnlockProgress.finish(); //finish,理论上执行到这里就可以notifyFinish
// Get unaware persistent apps running and start any unaware providers
// in already-running apps that are partially aware
if (userId == UserHandle.USER_SYSTEM) {
mInjector.startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
}
mInjector.installEncryptionUnawareProviders(userId);
// Dispatch unlocked to external apps
final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
unlockedIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
userId);
final UserInfo info = getUserInfo(userId);
if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
mInjector.sendPreBootBroadcast(userId, quiet,
() -> finishUserUnlockedCompleted(uss));
} else {
finishUserUnlockedCompleted(uss);
}
}
3.结论
1.耗费15s是因为在执行mActivityManager.unlockUser没有回调完成,导致timeout,需要在继续加log看为什么会这样
2.把15s改小,不过这个AOSP的值,改小也只能规避而已
4.继续前序
---------------------------------------------------------------------------------
正如前面说 canDismissBootAnimation 是keygauard画完的判断,但是这里卡的是在checkWaitingForWindow,最后add log看应该是statusBars和NavigationBar导致
if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {
return;
}
// Don't enable the screen until all existing windows have been drawn.
if (!mForceDisplayEnabled
// TODO(multidisplay): Expand to all displays?
&& getDefaultDisplayContentLocked().checkWaitingForWindows()) {
return;
}
开机在systemReady时候执行keygaurd绘制,执行到doKeyguard时blocked在checkVoldPassword
@/frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
/**
* Enable the keyguard if the settings are appropriate.
*/
private void doKeyguardLocked(Bundle options) {
if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
// Without this, settings is not enabled until the lock screen first appears
setShowingLocked(false, mAodShowing);
hideLocked();
return;
}
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked(options);
}
从接下来看,systemBooted后,system会判断如果5s,keyguard没有finish drawn,会发送timeout通知
//可以add callback看是不是这里调用的
/** {@inheritDoc} */
@Override
public void systemBooted() {
bindKeyguard();
synchronized (mLock) {
mSystemBooted = true;
if (mSystemReady) {
mKeyguardDelegate.onBootCompleted();
}
}
startedWakingUp();
screenTurningOn(null);
screenTurnedOn();
}
@Override
public void screenTurningOn(final ScreenOnListener screenOnListener) {
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
updateScreenOffSleepToken(false);
synchronized (mLock) {
mScreenOnEarly = true;
mScreenOnFully = false;
mKeyguardDrawComplete = false;
mWindowManagerDrawComplete = false;
mScreenOnListener = screenOnListener;
if (mKeyguardDelegate != null) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
getKeyguardDrawnTimeout()); //5s 后发送timeout message
mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
} else {
if (DEBUG_WAKEUP) Slog.d(TAG,
"null mKeyguardDelegate: setting mKeyguardDrawComplete.");
finishKeyguardDrawn();
}
}
}
//如果keyguard drawn 那么 remove MSG_KEYGUARD_DRAWN_TIMEOUT
private void finishKeyguardDrawn() {
synchronized (mLock) {
if (!mScreenOnEarly || mKeyguardDrawComplete) {
return; // We are not awake yet or we have already informed of this event.
}
mKeyguardDrawComplete = true;
if (mKeyguardDelegate != null) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
}
mWindowManagerDrawComplete = false;
}
// ... eventually calls finishWindowsDrawn which will finalize our screen turn on
// as well as enabling the orientation change logic/sensor.
mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
WAITING_FOR_DRAWN_TIMEOUT);
}
如果timeout会执行 finishKeyguardDrawn ,把 mKeyguardDrawComplete 置为true,同事等所有window Drawn
//开机时应该没启动完,timeout时间为5s,具体可以add log确认
private long getKeyguardDrawnTimeout() {
final boolean bootCompleted =
LocalServices.getService(SystemServiceManager.class).isBootCompleted();
// Set longer timeout if it has not booted yet to prevent showing empty window.
return bootCompleted ? 1000 : 5000;
}
private void finishKeyguardDrawn() {
synchronized (mLock) {
if (!mScreenOnEarly || mKeyguardDrawComplete) {
return; // We are not awake yet or we have already informed of this event.
}
mKeyguardDrawComplete = true;
if (mKeyguardDelegate != null) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
}
mWindowManagerDrawComplete = false;
}
// ... eventually calls finishWindowsDrawn which will finalize our screen turn on
// as well as enabling the orientation change logic/sensor.
mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
WAITING_FOR_DRAWN_TIMEOUT);
}
mKeyguardDrawComplete 置为true后,performEnableScreen 就会跳到 checkWaitingForWindow,检测是否所有window都drawn
@Override
public boolean canDismissBootAnimation() {
synchronized (mLock) {
return mKeyguardDrawComplete;
}
}
此时正常Navigationbar StatusBar WallPaper都会画好,window状态会从 DRAW_PENDING 依次到 HAS_DEAWN(4)
/** This is set when there is no Surface */
static final int NO_SURFACE = 0;
/** This is set after the Surface has been created but before the window has been drawn. During
* this time the surface is hidden. */
static final int DRAW_PENDING = 1;
/** This is set after the window has finished drawing for the first time but before its surface
* is shown. The surface will be displayed when the next layout is run. */
static final int COMMIT_DRAW_PENDING = 2;
/** This is set during the time after the window's drawing has been committed, and before its
* surface is actually shown. It is used to delay showing the surface until all windows in a
* token are ready to be shown. */
static final int READY_TO_SHOW = 3;
/** Set when the window has been shown in the screen the first time. */
static final int HAS_DRAWN = 4;
每次drawn状态变化都会调用 commitFinishDrawingLocked,最后打印finishDrawingLocked
// This must be called while inside a transaction.
boolean commitFinishDrawingLocked() {
if (DEBUG_STARTING_WINDOW_VERBOSE &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
+ drawStateToString());
}
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceController);
}
mDrawState = READY_TO_SHOW;
boolean result = false;
final AppWindowToken atoken = mWin.mAppToken;
if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = mWin.performShowLocked();
}
return result;
}
boolean finishDrawingLocked() {
final boolean startingWindow =
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
if (DEBUG_STARTING_WINDOW && startingWindow) {
Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
+ drawStateToString());
}
boolean layoutNeeded = mWin.clearAnimatingWithSavedSurface();
if (mDrawState == DRAW_PENDING) {
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
+ mSurfaceController);
if (DEBUG_STARTING_WINDOW && startingWindow) {
Slog.v(TAG, "Draw state now committed in " + mWin);
}
mDrawState = COMMIT_DRAW_PENDING;
layoutNeeded = true;
}
return layoutNeeded;
}
目前的问题就是P上并不会HAS_DRAWN,一直是在DRAW_PENDING 。
小结:
ANdroid O行为:当keyguard blocked时,发生timeout ,然后checkWaitingForWindow,此时在2s左右内,statusbar navigationbar wallpaper都会finish drawn,然后就会执行到bootAnimationComplete,bootAnimationComplete完成后unlockuser就会执行finish,keyguard就会收到notifyfinished从而show,直到开机
ANdorid P行为:当keyguard blocked时,发生timeout ,然后checkWaitingForWindow,此时在15sunlockuser timeout,dokeygaurd可以通过,然后statusbar navigationbar wallpaper才会陆续finish drawn,直到开机