android關閉開機啟動 - CSDN

2020-12-26 CSDN技術社區

一開始還是以為是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)

處理Message是要幹兩件事,一件是finishBooting,一件是enableScreenAfterBoot。

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; }

在finishBooting裡面,一開始會判斷mBootAnimationComplete,然後啟動一些一直被hold的進程等,最後會通過UserController的sendBootCompletedLocked發送開機廣播,這個也不是一下子就發了最後再說。

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);.....}

UserState從STATE_RUNNING_LOCKED變成STATE_RUNNING_UNLOCKING,發送message給Ams在UIThread上處理

/** * 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(); } }

SystemService先unlockUser,加載RecentTask,啟動符合條件的Persistent應用進程,加載encryption-unaware providers,最後再調回UserController執行解鎖的收尾工作。

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);}






相關焦點

  • android啟動頁設計專題及常見問題 - CSDN
    轉載請註明出處:http://blog.csdn.net/wangjihuanghun/article/details/63255144啟動頁幾乎成為了每個app的標配,有些商家在啟動頁中增加了開屏廣告以此帶來更多的收入。
  • android判斷edittext獲取焦點 - CSDN
    進入正題,頁面的代碼我就不寫在這裡了,如果需要完整Demo,我也傳到csdn了,可以到這裡下載:https://download.csdn.net/download/z806899669/11087630實時監聽代碼
  • android 從後臺啟動頁面專題及常見問題 - CSDN
    這三個Tesseract語言包合起來約有70M左右,APK文件中拷貝語言包到手機存儲中需要幾秒時間,所以我們做了一個啟動頁面,在為用戶展示App第一印象的同時,後臺拷貝這三個語言包。經過比較,知乎日報的啟動頁面有從中心點展開逼進用戶的效果,我們決定利用此效果來設計啟動頁面。
  • linux關閉開機啟動服務 加快啟動速度
    可能會有很多服務需要啟動。大部分的 Linux 系統會啟動 sshd(安全Shell服務)、syslog(系統日誌工具)和 lpd(列印服務),但還會有更多的服務需要啟動。過多的服務會增加開機的時間,優化關閉不需要的服務將會提高啟動時間。輸入system-config-services看看系統都啟動那些服務.
  • android開發中分享功能 - CSDN
    :enable要設置為true如果要動態設置是否在列表中出現時,可以在代碼中設置enable的值 <activity android:theme="@style/No_title_transparent" android:label="@string/other_apps" android:name="
  • android開發 自我優勢 - CSDN
    6、熟悉android手機屏幕適配及屏幕適配的原則,提高應用的兼容性(解決不同尺寸手機顯示圖片大小問題)7、熟悉Android的數據存儲方式(File,SharedPrefrence,Sqlite,ContentProvider,Net)8、掌握APP應用開發框架結構的基本搭建,抽取activity,fragment,adapter,holder等公用代碼,
  • android 排列 - CSDN
    每一個LinearLayout裡面又可分為垂直布局(android:orientation="vertical")和水平布局(android:orientation="horizontal" )。當垂直布局時,每一行就只有一個元素,多個元素依次垂直往下;水平布局時,只有一行,每一個元素依次向右排列。
  • android常用的五大布局 - CSDN
    ><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent
  • android布局和界面 - CSDN
    android:layout_gravity用於設置組件自身在父組件中的對齊方式。需要注意的是,此屬性與布局屬性android: gravity的區別。android:gravity用於設置View組件的對齊方式。
  • android 垂直約束 - CSDN
    :constraint-layout:1.0.2'<android.support.constraint.ConstraintLayoutandroid:layout_width="match_parent"
  • android 水平布局寬度 - CSDN
    ><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:gravity="center
  • 如何使用am命令啟動Android應用
    本文將詳細介紹使用am命令啟動應用的四種方法,相信會對你的測試開發工作有所幫助。一、使用am命令啟動一般的Android App。命令格式為:adb shell am start -n package/launch_activity示例:打開設置App命令:adb shell am start -n com.android.settings/com.android.settings.Settings命令的關鍵在於獲取package和launch_activity。
  • 支持智能電視開機廣告「一鍵關閉」
    11月18日,江蘇省消費者權益保護委員會發布消息表示,2020年11月10日,南京市中級人民法院一審宣判樂視電視所屬企業樂融致新電子科技(天津)有限公司智能電視開機廣告侵犯了消費者選擇權和公平交易權,應予整改,江蘇省消保委主張的「一鍵關閉」功能得到判決支持。
  • android可文本框專題及常見問題 - CSDN
    <EditTextandroid:id="@+id/textNormal"android:layout_width="fill_parent"android:layout_height="wrap_content"android:hint="Normaltext"android:inputType="text
  • android布局詳解專題及常見問題 - CSDN
    <include android:id=」@+id/cell3 layout=」@layout/workspace_screen」 /></LinearLayout>  上面的代碼中的<include>標籤還使用了一個android:id屬性,實際上,該屬性指定的是workspace_screen.xml布局文件中的根節點的android
  • 電視開機廣告「一鍵關閉」,手機APP呢?
    最近,智能電視開機廣告再度引發關注。歷時近一年的「智能電視開機廣告」消費民事公益訴訟終於有了結果。近期,江蘇消保委向法院主張的智能電視開機廣告必須擁有「一鍵關閉」功能,得到判決支持。(12月21日澎湃新聞)  關不掉的開機廣告讓消費者不堪其擾,「一鍵關閉」撫慰人心。一直以來,人們對智能電視開機廣告的討論和爭辯未曾停止過,究其原因就是開機廣告越來越長。很多消費者發現,逐漸加長的開機時間已經成了電視廠商獲利增長點。開機廣告時長短則十幾秒,長則幾分鐘,而且不能跳過、不能快進,更有甚者連關機都不行。
  • android 獲取某個控制項的焦點專題及常見問題 - CSDN
    schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/edit_layout"
  • Android啟動頁面延遲跳轉與第二次啟動分支跳轉
    準備工作打開Android Studio,新建一個projectMyStudy,新建一個SplashActivity並在清單文件中將其設置為啟動Activity。在布局文件中將SplashActivity的背景設置為一張圖片(可以是手機壁紙)。
  • Android手機十大必備應用軟體
    今天小編就為大家推薦十款android手機必備軟體,讓你輕輕鬆鬆玩轉智慧型手機。 Android是 Google 推出的國際流行的新銳智慧型手機平臺,吸引著越來越多的用戶和開發者加入其陣營,目前已然是各平臺中的佼佼者。今天小編就為大家推薦十款android手機必備軟體,讓你輕輕鬆鬆玩轉智慧型手機。
  • android 進度條顯示時間專題及常見問題 - CSDN
    定義一個attrs.xml自定義CircleProgressViewpackage com.sample.circleprogressview.widget;import android.animation.ValueAnimator;import android.content.Context