一開始還是以為是Launcher起來後線程空閒回調Ams的接口開始進行關閉開機動畫,但實際上看了下不僅僅是這個條件。不過還是從這裡開始結合日誌一起看。
在ActivityThread::handleLaunchActivity的過程中,會在resume階段handleResumeActivity方法裡面在加載完window之後將自己實現的Idlehandler添加到自己的消息隊列裡面,當Looper發現消息隊列空閒的時候就會回調queueIdle方法
r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) Slog.v( TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler());
Idler實現的MessageQueue.IdleHandler接口就一個queueIdle方法,裡面關鍵的就是會回調ams的activityIdle。
private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; boolean stopProfiling = false; if (mBoundApplication != null && mProfiler.profileFd != null && mProfiler.autoStopProfiler) { stopProfiling = true; } if (a != null) { mNewActivities = null; IActivityManager am = ActivityManager.getService(); ActivityClientRecord prev; do { if (localLOGV) Slog.v( TAG, "Reporting idle of " + a + " finished=" + (a.activity != null && a.activity.mFinished)); if (a.activity != null && !a.activity.mFinished) { try { am.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } prev = a; a = a.nextIdle; prev.nextIdle = null; } while (a != null); } if (stopProfiling) { mProfiler.stopProfiling(); } ensureJitEnabled(); return false; } }
Ams
@Override public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { final long origId = Binder.clearCallingIdentity(); synchronized (this) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack != null) { ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */, false /* processPausingActivities */, config); if (stopProfiling) { if ((mProfileProc == r.app) && mProfilerInfo != null) { clearProfilerLocked(); } } } } Binder.restoreCallingIdentity(origId); }
ActivityStackSuperVisor的activityIdleInternalLocked方法,會報告啟動時間結束,還有就是檢查是否是還在開機階段然後結束開機流程。意思就是桌面都已經拿到焦點顯示好了,開機動畫可以退役了。在這裡會修改Ams的mBooting全局變量為true,然後enableScreen也是true,發送Message給Ams進行處理,也就是開篇提到的。
//Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout); if (isFocusedStack(r.getStack()) || fromTimeout) { booting = checkFinishBootingLocked(); }
/** * Called when the frontmost task is idle. * @return the state of mService.mBooting before this was called. */ private boolean checkFinishBootingLocked() { final boolean booting = mService.mBooting; boolean enableScreen = false; mService.mBooting = false; if (!mService.mBooted) { mService.mBooted = true; enableScreen = true; } if (booting || enableScreen) { mService.postFinishBooting(booting, enableScreen); } return booting; }
void postFinishBooting(boolean finishBooting, boolean enableScreen) { Exception e = new Exception("xian postFinishBooting"); e.printStackTrace(); mHandler.sendMessage(mHandler.obtainMessage(FINISH_BOOTING_MSG, finishBooting ? 1 : 0, enableScreen ? 1 : 0)); }
這是對應的log列印的棧
07-03 10:20:26.632 3015 3027 W System.err: java.lang.Exception: xian postFinishBooting07-03 10:20:26.633 3015 3027 W System.err: at com.android.server.am.ActivityManagerService.postFinishBooting(ActivityManagerService.java:7244)07-03 10:20:26.633 3015 3027 W System.err: at com.android.server.am.ActivityStackSupervisor.checkFinishBootingLocked(ActivityStackSupervisor.java:1874)07-03 10:20:26.633 3015 3027 W System.err: at com.android.server.am.ActivityStackSupervisor.activityIdleInternalLocked(ActivityStackSupervisor.java:1916)07-03 10:20:26.633 3015 3027 W System.err: at com.android.server.am.ActivityManagerService.activityIdle(ActivityManagerService.java:7231)07-03 10:20:26.633 3015 3027 W System.err: at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:309)07-03 10:20:26.633 3015 3027 W System.err: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2919)07-03 10:20:26.633 3015 3027 W System.err: at android.os.Binder.execTransact(Binder.java:697)
case FINISH_BOOTING_MSG: { if (msg.arg1 != 0) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting"); finishBooting(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } if (msg.arg2 != 0) { enableScreenAfterBoot(); } break; }
final void finishBooting() { synchronized (this) { if (!mBootAnimationComplete) { mCallFinishBooting = true; return; } mCallFinishBooting = false; }...... // Let system services know. mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);...... mUserController.sendBootCompletedLocked( new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { synchronized (ActivityManagerService.this) { requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); } } }); scheduleStartProfilesLocked(); }
剛進來這裡的時候mBootAnimationComplete肯定是false,所以沒戲唱了,但是注意到mCallFinishBooting是賦值為true的, ,後面是有用的。實際上它只會在系統結束開機動畫之後才會變成true,然後再進行一遍finishBooting的動作。bootAnimationComplete方法是由Wms回調的,等下再說。繼續看上面的第二件事enableScreenAfterBoot.
public void enableScreenAfterBoot() { synchronized(mWindowMap) { if (DEBUG_BOOT) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Slog.i(TAG_WM, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled + " mForceDisplayEnabled=" + mForceDisplayEnabled + " mShowingBootMessages=" + mShowingBootMessages + " mSystemBooted=" + mSystemBooted, here); } if (mSystemBooted) { return; } mSystemBooted = true; hideBootMessagesLocked(); // If the screen still doesn't come up after 30 seconds, give // up and turn it on. mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000); } mPolicy.systemBooted(); performEnableScreen(); }
這裡會將mSystemBooted設置為true,然後在hideBootMessagesLocked方法裡面把mShowingBootMessages true改成false,然後設定一個強制的30s啟動超時Message,隨後調用PhoneWindowManager的systemBooted方法,通知keyguard進行相關動作,最後也是我們這次分析的重點,進行performEnableScreen。performEnableScreen裡面會關掉開機動畫,通知SurfaceFlinger開機結束等等,但是一次就能關掉嗎?先看下列印的日誌。
Line 3801: 07-03 10:20:26.756 3015 3030 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 3930: 07-03 10:20:26.832 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 3974: 07-03 10:20:26.851 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4013: 07-03 10:20:26.869 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4046: 07-03 10:20:26.879 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4069: 07-03 10:20:26.895 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4096: 07-03 10:20:26.913 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4114: 07-03 10:20:26.916 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4133: 07-03 10:20:26.939 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4196: 07-03 10:20:27.089 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4215: 07-03 10:20:27.095 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4279: 07-03 10:20:27.135 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4302: 07-03 10:20:27.144 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4358: 07-03 10:20:27.226 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4390: 07-03 10:20:27.249 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4411: 07-03 10:20:27.261 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4451: 07-03 10:20:27.312 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4490: 07-03 10:20:27.357 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487) Line 4600: 07-03 10:20:27.762 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService.performEnableScreen(WindowManagerService.java:3487)
除了這個從Launcher發起的流程是第一次的調用之外,其他的都是這樣的。也就是在Wms裡面經enableScreenIfNeededLocked方法發送ENABLE_SCREEN Message給在android.display線程的H Handler進行處理。
07-03 10:20:26.939 3015 3037 I WindowManager: java.lang.RuntimeException: here07-03 10:20:26.939 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.-wrap6(Unknown Source:0)07-03 10:20:26.939 3015 3037 I WindowManager: at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5065)07-03 10:20:26.939 3015 3037 I WindowManager: at android.os.Handler.dispatchMessage(Handler.java:106)07-03 10:20:26.939 3015 3037 I WindowManager: at android.os.Looper.loop(Looper.java:164)07-03 10:20:26.939 3015 3037 I WindowManager: at android.os.HandlerThread.run(HandlerThread.java:65)07-03 10:20:26.939 3015 3037 I WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:46)
enableScreenIfNeededLocked調用非常的頻繁,調用點也是有多個位置,在wms進行每次performSurfacePlacement等主要是完成繪製布局之後都會檢查進行調用。主要的棧是這個
07-03 10:20:26.628 3015 3070 I WindowManager: enableScreenIfNeededLocked: mDisplayEnabled=false mForceDisplayEnabled=false mShowingBootMessages=false mSystemBooted=false07-03 10:20:26.628 3015 3070 I WindowManager: java.lang.RuntimeException: here07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.WindowManagerService.enableScreenIfNeededLocked(WindowManagerService.java:3445)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:822)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:197)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:145)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:135)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.WindowSurfacePlacer.lambda$-com_android_server_wm_WindowSurfacePlacer_5337(WindowSurfacePlacer.java:108)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.-$Lambda$aEpJ2RCAIjecjyIIYTv6ricEwh4.$m$12(Unknown Source:4)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.wm.-$Lambda$aEpJ2RCAIjecjyIIYTv6ricEwh4.run(Unknown Source:59)07-03 10:20:26.628 3015 3070 I WindowManager: at android.os.Handler.handleCallback(Handler.java:790)07-03 10:20:26.628 3015 3070 I WindowManager: at android.os.Handler.dispatchMessage(Handler.java:99)07-03 10:20:26.628 3015 3070 I WindowManager: at android.os.Looper.loop(Looper.java:164)07-03 10:20:26.628 3015 3070 I WindowManager: at android.os.HandlerThread.run(HandlerThread.java:65)07-03 10:20:26.628 3015 3070 I WindowManager: at com.android.server.ServiceThread.run(ServiceThread.java:46)
在發送ENABLE_SCREEN Message之前,會判斷mDisplayEnabled, 是否enable的狀態變量,peformEnableScreen完成後置為true,避免重複操作。mSystemBooted就是Launcher啟動空閒後通過Idler回調Ams設置的狀態標記位,前面已經設置為true了,mShowingBootMessages是是否在顯示「Android系統正在啟動」,或者「Android系統正在升級」,在SystemServer啟動時會調用PKMS進行packages的dexoat升級,然後在enableScreenAfterBoot裡面會調用hideBootMessagesLocked取消掉這個dialog,現在這個肯定是false了。所以只要mSystemBooted開關一打開,後面就開始調用performEnableScreen嘗試幹活。
void enableScreenIfNeededLocked() { if (DEBUG_BOOT) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Slog.i(TAG_WM, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled + " mForceDisplayEnabled=" + mForceDisplayEnabled + " mShowingBootMessages=" + mShowingBootMessages + " mSystemBooted=" + mSystemBooted, here); } if (mDisplayEnabled) { return; } if (!mSystemBooted && !mShowingBootMessages) { return; } mH.sendEmptyMessage(H.ENABLE_SCREEN); }
前面幾個判斷已經做過一遍了,現在主要要等checkWaitingForWindows,除非是現有的windows都已經完成繪製了,否則還是不能說系統真正啟動了。除了Launcher,還有SystemUI的壁紙,導航欄, Keyguard等。當然每個Window完成繪製的時候都會再重來一遍看要不要performEnableScreen.
然後終於要停止開機動畫了,SystemProperties.set("service.bootanim.exit", "1"); system/bin/bootanimation一般會在顯示的時候循環進行這個prop的檢查,變成1它就可以退出了,本身它就是一個線程。checkBootAnimationCompleteLocked是ServiceManager找不到bootanimation服務了,然後就通知SurfaceFlinger啟動已經完成,列印也是經典的日誌「******* TELLING SURFACE FLINGER WE ARE BOOTED!」。然後再回調AMS的bootAnimationComplete,這裡會處理開機廣播的發送工作。
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; } 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!"); } 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=false07-03 10:20:27.762 3015 3037 I WindowManager: java.lang.RuntimeException: here07-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=true07-03 10:20:27.763 3015 3037 I WindowManager: checkBootAnimationComplete: Animation complete!07-03 10:20:27.765 3015 3037 I WindowManager: ******* TELLING SURFACE FLINGER WE ARE BOOTED!07-03 10:20:27.765 2764 2938 I SurfaceFlinger: Boot is finished (44022 ms)07-03 10:20:27.773 3015 3037 I WindowManager: ******************** ENABLING SCREEN!07-03 10:20:27.778 3015 3037 I SystemServiceManager: Starting phase 1000
Ams在這裡打開了開關mBootAnimationComplete
public void bootAnimationComplete() { final boolean callFinishBooting; synchronized (this) { callFinishBooting = mCallFinishBooting; mBootAnimationComplete = true; } if (callFinishBooting) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting"); finishBooting(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } }
finishBooting裡面,startBootPhase(SystemService.PHASE_BOOT_COMPLETED)對應著上面日誌的start phase 1000,這是最後了。隨後就是通過UserController發送開機廣播,帶的IIntentReceiver.Stub主要是完成各個進程的信息搜集工作。
..... // Let system services know. mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);...... mUserController.sendBootCompletedLocked( new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { synchronized (ActivityManagerService.this) { requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); } } });......
UserController主要是來做多用戶方面的動作。
void sendBootCompletedLocked(IIntentReceiver resultTo) { for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); finishUserBoot(uss, resultTo); } }
先發了一個鎖屏開機廣播ACTION_LOCKED_BOOT_COMPLETED,然後是maybeUnlockUser,解鎖用戶的 credential-encrypted storage,這是7.0引入的direct boot mode相關的,應用的數據都是放在這裡的,解鎖前不能用。
private void finishUserBoot(UserState uss, IIntentReceiver resultTo) { final int userId = uss.mHandle.getIdentifier(); Slog.d(TAG, "Finishing user boot " + userId); synchronized (mLock) { // Bail if we ended up with a stale user if (mStartedUsers.get(userId) != uss) return; // We always walk through all the user lifecycle states to send // consistent developer events. We step into RUNNING_LOCKED here, // but we might immediately step into RUNNING below if the user // storage is already unlocked. if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) { ...... Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mInjector.broadcastIntentLocked(intent, null, resultTo, 0, null, null, new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } // We need to delay unlocking managed profiles until the parent user // is also unlocked. if (mInjector.getUserManager().isManagedProfile(userId)) { final UserInfo parent = mInjector.getUserManager().getProfileParent(userId); ..... maybeUnlockUser(userId); ...... }
StorageManagerService unlockUserKey就是解鎖的邏輯,然後是finishUserUnlocking
/** * Attempt to unlock user without a credential token. This typically * succeeds when the device doesn't have credential-encrypted storage, or * when the the credential-encrypted storage isn't tied to a user-provided * PIN or pattern. */ boolean maybeUnlockUser(final int userId) { // Try unlocking storage using empty token return unlockUserCleared(userId, null, null, null); }
boolean unlockUserCleared(final int userId, byte[] token, byte[] secret, IProgressListener listener) { UserState uss; synchronized (mLock) { // TODO Move this block outside of synchronized if it causes lock contention if (!StorageManager.isUserKeyUnlocked(userId)) { final UserInfo userInfo = getUserInfo(userId); final IStorageManager storageManager = getStorageManager(); try { // We always want to unlock user storage, even user is not started yet storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret); } catch (RemoteException | RuntimeException e) { Slog.w(TAG, "Failed to unlock: " + e.getMessage()); } } // Bail if user isn't actually running, otherwise register the given // listener to watch for unlock progress uss = mStartedUsers.get(userId); if (uss == null) { notifyFinished(userId, listener); return false; } else { uss.mUnlockProgress.addListener(listener); uss.tokenProvided = (token != null); } } finishUserUnlocking(uss);.....}
/** * Step from {@link UserState#STATE_RUNNING_LOCKED} to * {@link UserState#STATE_RUNNING_UNLOCKING}. */ private void finishUserUnlocking(final UserState uss) { .... if (proceedWithUnlock) { uss.mUnlockProgress.start(); // Prepare app storage before we go any further uss.mUnlockProgress.setProgress(5, mInjector.getContext().getString(R.string.android_start_title)); mInjector.getUserManager().onBeforeUnlockUser(userId); 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(); } }
case SYSTEM_USER_UNLOCK_MSG: { final int userId = msg.arg1; mSystemServiceManager.unlockUser(userId); synchronized (ActivityManagerService.this) { mRecentTasks.loadUserRecentsLocked(userId); } if (userId == UserHandle.USER_SYSTEM) { startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } installEncryptionUnawareProviders(userId); mUserController.finishUserUnlocked((UserState) msg.obj); break; }
需要的話先發ACTION_USER_INITIALIZE廣播去給user初始化,然後列印關鍵日誌「Sending BOOT_COMPLETE user # 」,最後發送開機廣播ACTION_BOOT_COMPLETED,發完後列印「Finished processing BOOT_COMPLETED for u」
private void finishUserUnlockedCompleted(UserState uss) {.... if (!userInfo.isInitialized()) { if (userId != UserHandle.USER_SYSTEM) { Slog.d(TAG, "Initializing user #" + userId); Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mInjector.broadcastIntentLocked(intent, null,...... Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);... final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mInjector.broadcastIntentLocked(bootIntent, null, new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId); } }, 0, null, null, new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);}