学习笔记:Android小白,这位置网上没资料,通过自己打日志阅读代码走的流程,可能有理解错误的地方。欢迎指正,大家共同进步。
深色主题设置方法:两种设置方法流程是一样的。
通过下拉状态栏的快捷按钮深色主题切换;
通过 设置→显示→深色主题开关 切换;
本文以下拉状态栏的快捷按钮深色主题切换为例; 该快捷按钮类为 UiModeNightTile.java ,直接看点击事件:
frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
1 2 3 4 5 6 7 8 9 10 11 @Override protected void handleClick (@Nullable View view) { if (getState().state == Tile.STATE_UNAVAILABLE) { return ; } boolean newState = !mState.value; mUiModeManager.setNightModeActivated(newState); refreshState(newState); }
根据上面的我们直接找 UiModeManager.java 的 setNightModeActivated() 方法: UiModeManager#setNightModeActivated()frameworks/base/core/java/android/app/UiModeManager.java
1 2 3 4 5 6 7 8 9 10 11 12 @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) public boolean setNightModeActivated (boolean active) { if (mService != null ) { try { return mService.setNightModeActivated(active); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return false ; }
UiModeManagerService#setNightModeActivated()frameworks/base/services/core/java/com/android/server/UiModeManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 @Override public boolean setNightModeActivated (boolean active) { return setNightModeActivatedForModeInternal(mNightModeCustomType, active); } private boolean setNightModeActivatedForModeInternal (int modeCustomType, boolean active) { synchronized (mLock) { final long ident = Binder.clearCallingIdentity(); try { if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) { unregisterScreenOffEventLocked(); mOverrideNightModeOff = !active; mOverrideNightModeOn = active; mOverrideNightModeUser = mCurrentUser; persistNightModeOverrides(mCurrentUser); } else if (mNightMode == UiModeManager.MODE_NIGHT_NO && active) { mNightMode = UiModeManager.MODE_NIGHT_YES; } else if (mNightMode == UiModeManager.MODE_NIGHT_YES && !active) { mNightMode = UiModeManager.MODE_NIGHT_NO; } updateConfigurationLocked(); applyConfigurationExternallyLocked(); persistNightMode(mCurrentUser); return true ; } finally { Binder.restoreCallingIdentity(ident); } } }
根据上述代码这里主要看下 applyConfigurationExternallyLocked()、persistNightMode() 两个方法; persistNightMode() 方法简单,先看 UiModeManagerService#persistNightMode()frameworks/base/services/core/java/com/android/server/UiModeManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private void persistNightMode (int user) { if (mCarModeEnabled || mCar) return ; Secure.putIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, mNightMode, user); Secure.putLongForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE_CUSTOM_TYPE, mNightModeCustomType, user); Secure.putLongForUser(getContext().getContentResolver(), Secure.DARK_THEME_CUSTOM_START_TIME, mCustomAutoNightModeStartMilliseconds.toNanoOfDay() / 1000 , user); Secure.putLongForUser(getContext().getContentResolver(), Secure.DARK_THEME_CUSTOM_END_TIME, mCustomAutoNightModeEndMilliseconds.toNanoOfDay() / 1000 , user); }
再接着看 UiModeManagerService#applyConfigurationExternallyLocked() 方法:frameworks/base/services/core/java/com/android/server/UiModeManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void applyConfigurationExternallyLocked () { if (mSetUiMode != mConfiguration.uiMode) { mSetUiMode = mConfiguration.uiMode; mWindowManager.clearSnapshotCache(); try { ActivityTaskManager.getService().updateConfiguration(mConfiguration); } catch (RemoteException e) { Slog.w(TAG, "Failure communicating with activity manager" , e); } catch (SecurityException e) { Slog.e(TAG, "Activity does not have the " , e); } } }
上述代码将调到 ActivityTaskManagerService#updateConfiguration()frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 @Override public boolean updateConfiguration (Configuration values) { mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()" ); synchronized (mGlobalLock) { if (mWindowManager == null ) { Slog.w(TAG, "Skip updateConfiguration because mWindowManager isn't set" ); return false ; } if (values == null ) { values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY); } mH.sendMessage(PooledLambda.obtainMessage( ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal, DEFAULT_DISPLAY)); final long origId = Binder.clearCallingIdentity(); try { if (values != null ) { Settings.System.clearConfiguration(values); } updateConfigurationLocked(values, null , false , false , UserHandle.USER_NULL, false , mTmpUpdateConfigurationResult); return mTmpUpdateConfigurationResult.changes != 0 ; } finally { Binder.restoreCallingIdentity(origId); } } } boolean updateConfigurationLocked (Configuration values, ActivityRecord starting, boolean initLocale, boolean persistent, int userId, boolean deferResume, ActivityTaskManagerService.UpdateConfigurationResult result) { int changes = 0 ; boolean kept = true ; deferWindowLayout(); try { if (values != null ) { changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId); } if (!deferResume) { kept = ensureConfigAndVisibilityAfterUpdate(starting, changes); } } finally { continueWindowLayout(); } if (result != null ) { result.changes = changes; result.activityRelaunched = !kept; } return kept; }
这里直接看更新 updateGlobalConfigurationLocked() 方法:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int updateGlobalConfigurationLocked (@NonNull Configuration values, boolean initLocale, boolean persistent, int userId) { SparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap(); for (int i = pidMap.size() - 1 ; i >= 0 ; i--) { final int pid = pidMap.keyAt(i); final WindowProcessController app = pidMap.get(pid); ProtoLog.v(WM_DEBUG_CONFIGURATION, "Update process config of %s to new " + "config %s" , app.mName, mTempConfig); app.onConfigurationChanged(mTempConfig); } final Message msg = PooledLambda.obtainMessage( ActivityManagerInternal::broadcastGlobalConfigurationChanged, mAmInternal, changes, initLocale); mH.sendMessage(msg); mRootWindowContainer.onConfigurationChanged(mTempConfig); return changes; }
上述代码跟进去,将会回调 WindowProcessController#onConfigurationChanged()frameworks/base/services/core/java/com/android/server/wm/WindowProcessController.java
1 2 3 4 5 6 @Override public void onConfigurationChanged (Configuration newGlobalConfig) { super .onConfigurationChanged(newGlobalConfig); updateConfiguration(); }
接着看 ConfigurationContainer#onConfigurationChanged()frameworks/base/services/core/java/com/android/server/wm/ConfigurationContainer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public void onConfigurationChanged (Configuration newParentConfig) { mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration); resolveOverrideConfiguration(newParentConfig); mFullConfiguration.setTo(newParentConfig); mFullConfiguration.windowConfiguration.unsetAlwaysOnTop(); mFullConfiguration.updateFrom(mResolvedOverrideConfiguration); onMergedOverrideConfigurationChanged(); if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) { for (int i = mChangeListeners.size() - 1 ; i >= 0 ; --i) { mChangeListeners.get(i).onRequestedOverrideConfigurationChanged( mResolvedOverrideConfiguration); } } Log.d("yeruilai" ,"yeruilai:" +mChangeListeners.size()); for (int i = mChangeListeners.size() - 1 ; i >= 0 ; --i) { Log.d("yeruilai" ,"yeruilai:" +mChangeListeners.get(i)); mChangeListeners.get(i).onMergedOverrideConfigurationChanged( mMergedOverrideConfiguration); } for (int i = getChildCount() - 1 ; i >= 0 ; --i) { dispatchConfigurationToChild(getChildAt(i), mFullConfiguration); } }
这里看一个堆栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 09-24 16 :35 :18.717 3118 3118 D yeruilai : java.lang.Throwable 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.content.res.AssetManager.rebaseTheme(AssetManager.java:1243 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.content.res.ResourcesImpl$ThemeImpl.rebase(ResourcesImpl.java:1457 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.content.res.Resources$Theme.rebase(Resources.java:1874 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.content.res.Resources.setImpl(Resources.java:372 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ResourcesManager.updateResourcesForActivity(ResourcesManager.java:1224 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ResourcesManager.createBaseTokenResources(ResourcesManager.java:867 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ContextImpl.createActivityContext(ContextImpl.java:3148 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread.createBaseContextForActivity(ActivityThread.java:3799 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3605 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3853 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5832 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5723 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2345 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.os.Handler.dispatchMessage(Handler.java:106 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.os.Looper.loopOnce(Looper.java:208 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.os.Looper.loop(Looper.java:295 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at android.app.ActivityThread.main(ActivityThread.java:7941 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at java.lang.reflect.Method.invoke(Native Method) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:569 ) 09-24 16 :35 :18.717 3118 3118 D yeruilai : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1015 )
配置改变后通过 binder 调用 IApplicationThread.scheduleTransaction() 方法。 留下问题:配置改变后通过 binder 调用,这中间的流程是怎样的? ClientTransaction#schedule()frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
1 2 3 public void schedule () throws RemoteException { mClient.scheduleTransaction(this ); }
然后配置改变消息会进入应用进程,经过ActivityThread.H发送消息,执行 mTransactionExecutor.execute(transaction),进入 TransactionExecutor#executeCallbacks() 方法:frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @VisibleForTesting public void executeCallbacks (ClientTransaction transaction) { final int size = callbacks.size(); for (int i = 0 ; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); } }
ClientTransactionItem 的实现方法在 ActivityTransactionItem 中,所以进入到 ActivityTransactionItem#execute()frameworks/base/core/java/android/app/servertransaction/ActivityTransactionItem.java
1 2 3 4 5 6 7 @Override public final void execute (ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { final ActivityClientRecord r = getActivityClientRecord(client, token); execute(client, r, pendingActions); }
ActivityRelaunchItem#execute()frameworks/base/core/java/android/app/servertransaction/ActivityRelaunchItem.java
1 2 3 4 5 6 7 8 9 10 11 12 @Override public void execute (ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { if (mActivityClientRecord == null ) { if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled" ); return ; } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart" ); client.handleRelaunchActivity(mActivityClientRecord, pendingActions); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); }
后面就不详细分析了;
后续流程:ActivityThread#handleRelaunchActivity() → ActivityThread#handleRelaunchActivityInner() → ActivityThread#handleLaunchActivity() → ActivityThread#performLaunchActivity()→ ActivityThread#createBaseContextForActivity() → ContextImpl #createActivityContext() → ResourcesManager#createBaseTokenResources() → ResourcesManager#updateResourcesForActivity() → Resources #setImpl() → Resources#Theme.rebase() → AssetManager#rebaseTheme() 这里注意:在 ActivityThread.java 中有 performActivityConfigurationChanged() 和 performLaunchActivity() 两个方法,都可以更新资源主题,我个人认为一个是配置单独某个应用的,一个是配置全局的。
到此完成应用进程回调。 那么系统进程如何传送配置信息到应用进程? 这里回到 ActivityTaskManagerService.java。通过ensureConfigAndVisibilityAfterUpdate方法,确保目前启动的activity,重启来加载新的资源 ActivityTaskManagerService#ensureConfigAndVisibilityAfterUpdate()frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 boolean ensureConfigAndVisibilityAfterUpdate (ActivityRecord starting, int changes) { boolean kept = true ; final Task mainRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); if (mainRootTask != null ) { if (changes != 0 && starting == null ) { starting = mainRootTask.topRunningActivity(); } if (starting != null ) { kept = starting.ensureActivityConfiguration(changes, false ); mRootWindowContainer.ensureActivitiesVisible(starting, changes, !PRESERVE_WINDOWS); } } return kept; }
starting 是 ActivityRecord 对象,所有看 ActivityRecord #ensureActivityConfiguration()frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 boolean ensureActivityConfiguration (int globalChanges, boolean preserveWindow, boolean ignoreVisibility) { if (changes == 0 && !forceNewConfig) { ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration no differences in %s" , this ); if (displayChanged) { scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); } else { scheduleConfigurationChanged(newMergedOverrideConfig); } return true ; } return true ; }
displayChanged未改变的前提下,走 scheduleConfigurationChanged(),通知应用进程。 ActivityRecord#scheduleConfigurationChangedframeworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void scheduleConfigurationChanged (Configuration config) { if (!attachedToProcess()) { ProtoLog.w(WM_DEBUG_CONFIGURATION, "Can't report activity configuration " + "update - client not running, activityRecord=%s" , this ); return ; } try { ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, " + "config: %s" , this , config); mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token, ActivityConfigurationChangeItem.obtain(config)); } catch (RemoteException e) { } }
至此,应用进程可以根据新配置更新布局等信息。
本文链接: http://longzhiye.top/2023/09/24/2023-09-25/