前言
上一篇我們簡單介紹了應用的窗口屬性WindowConfiguration這個類,該類存儲了當前窗口的顯示區域、屏幕的旋轉方向、窗口模式等參數,當設備屏幕發生旋轉的時候就是通過該類將具體的旋轉數據傳遞給應用的、而應用在加載資源文件的時候也會結合該類的AppBounds屬性,自動加載特定分辨率的資源文件。而在這些屬性發生變化之后,系統一般都是在onConfigurationChanged方法中作出響應的,這篇文章我們將會結合系統深淺主題發生切換到時候,新的系統配置是如何通過onConfigurationChanged回調給Activity的。
一、用戶行為觸發深淺模式主題切換
這里我們以下拉狀態欄的快捷按鈕深色主題切換為切入口來做具體源碼分析,我們點擊該按鈕,首先會觸發UiModeNightTile的handleClick方法。
1.1 SystemUI階段
frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implementsConfigurationController.ConfigurationListener,BatteryController.BatteryStateChangeCallback {private UiModeManager mUiModeManager;@Overrideprotected void handleClick(@Nullable View view) {if (getState().state == Tile.STATE_UNAVAILABLE) {return;}boolean newState = !mState.value;//注釋1mUiModeManager.setNightModeActivated(newState);refreshState(newState);}
}
在注釋1處調用UiModeManager的setNightModeActivated方法。
1.2 UiModeManager階段
frameworks/base/core/java/android/app/UiModeManager.java
public class UiModeManager {private IUiModeManager mService;UiModeManager(Context context) throws ServiceNotFoundException {mService = IUiModeManager.Stub.asInterface(ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE));mContext = context;}/*** 激活當前用戶的夜間模式UI視圖*/public boolean setNightModeActivated(boolean active) {if (mService != null) {try {//注釋1,調用UiModeManagerService的setNightModeActivated方法return mService.setNightModeActivated(active);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}return false;}
}
在注釋1處調用UiModeManagerService的setNightModeActivated方法。
1.3 UiModeManagerService階段
frameworks/base/services/core/java/com/android/server/UiModeManagerService.java
final class UiModeManagerService extends SystemService {private Configuration mConfiguration = new Configuration();@Overridepublic boolean setNightModeActivated(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;}//注釋1,更新ConfigurationupdateConfigurationLocked();//注釋2,應用ConfigurationapplyConfigurationExternallyLocked();//為當前用戶對應的Secure添加配置信息persistNightMode(mCurrentUser);return true;} finally {Binder.restoreCallingIdentity(ident);}}}private void updateConfigurationLocked() {...代碼省略...if (!mHoldingConfiguration && (!mWaitForScreenOff || mPowerSave)) {//將新的UIMode賦值給mConfigurationmConfiguration.uiMode = uiMode;}}private void applyConfigurationExternallyLocked() {if (mSetUiMode != mConfiguration.uiMode) {mSetUiMode = mConfiguration.uiMode;//清除窗口戶的快照緩存mWindowManager.clearSnapshotCache();try {//注釋3,調用ATMS的updateConfiguration方法,更新當前用戶對應的ConfigurationActivityTaskManager.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);}}}}
在注釋1處調用updateConfigurationLocked方法,該方法會將新的UIMode賦值給mConfiguration;在注釋2處調用
applyConfigurationExternallyLocked方法,該方法內部也就是注釋3處,會調用ATMS的updateConfiguration方法,將當前用戶包含了新UiMode的Configuration同步給系統中的其他模塊和應用。
二、ActivityTaskManagerService通知ActivityThread
2.1 ActivityTaskManagerService階段
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {@Overridepublic 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) {//從WMS中獲取當前系統默認屏幕設備對應的配置信息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);}//注釋1,繼續調用updateConfigurationLocked,更新配置信息updateConfigurationLocked(values, null, false, false /* persistent */,UserHandle.USER_NULL, false /* deferResume */,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) {//注釋2,更新全局配置changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId);}if (!deferResume) {//注釋4,更新后確保配置和可見性kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);}} finally {continueWindowLayout();}if (result != null) {result.changes = changes;result.activityRelaunched = !kept;}return kept;}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);//注釋3,調用app的onConfigurationChanged方法app.onConfigurationChanged(mTempConfig);}final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::broadcastGlobalConfigurationChanged,mAmInternal, changes, initLocale);mH.sendMessage(msg);mRootWindowContainer.onConfigurationChanged(mTempConfig);return changes;}}
注釋1處ATMS的updateConfiguration方法繼續調用updateConfigurationLocked;
注釋2處調用updateGlobalConfigurationLocked方法更新當前系統的全局配置;
注釋3獲取當前系統中的每一個窗口管理者,調用app.onConfigurationChanged方法,告知他們系統配置發生了變化。
2.2 WindowProcessController階段
frameworks/base/services/core/java/com/android/server/wm/WindowProcessController.java
public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer>implements ConfigurationContainerListener {private final ActivityTaskManagerService mAtm;@Overridepublic void onConfigurationChanged(Configuration newGlobalConfig) {super.onConfigurationChanged(newGlobalConfig);//調用updateConfiguration方法updateConfiguration();}private void updateConfiguration() {final Configuration config = getConfiguration();if (mLastReportedConfiguration.diff(config) == 0) {if (Build.IS_DEBUGGABLE && mHasImeService) {Slog.w(TAG_CONFIGURATION, "Current config: " + config+ " unchanged for IME proc " + mName);}return;}if (mPauseConfigurationDispatchCount > 0) {mHasPendingConfigurationChange = true;return;}//調用dispatchConfiguration方法dispatchConfiguration(config);}void dispatchConfiguration(Configuration config) {mHasPendingConfigurationChange = false;if (mThread == null) {if (Build.IS_DEBUGGABLE && mHasImeService) {Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName+ ": no app thread");}return;}try {config.seq = mAtm.increaseConfigurationSeqLocked();//注釋1,獲取ClientLifecycleManager實例//調用其scheduleTransaction方法,并傳入ConfigurationChangeItem對象實例mAtm.getLifecycleManager().scheduleTransaction(mThread,ConfigurationChangeItem.obtain(config));setLastReportedConfiguration(config);} catch (Exception e) {Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);}}
} public class ActivityTaskManagerService extends IActivityTaskManager.Stub {private final ClientLifecycleManager mLifecycleManager;ClientLifecycleManager getLifecycleManager() {return mLifecycleManager;}
}>frameworks/base/services/core/java/com/android/server/wm/ClientLifecycleManager.java
class ClientLifecycleManager {void scheduleTransaction(@NonNull IApplicationThread client,@NonNull ClientTransactionItem callback) throws RemoteException {final ClientTransaction clientTransaction = transactionWithCallback(client,null /* activityToken */, callback);//調用scheduleTransaction方法scheduleTransaction(clientTransaction);}private static ClientTransaction transactionWithCallback(@NonNull IApplicationThread client,IBinder activityToken, @NonNull ClientTransactionItem callback) {//獲取clientTransaction 對象實例final clientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken);clientTransaction.addCallback(callback);return clientTransaction;}void scheduleTransaction(ClientTransaction transaction) throws RemoteException {final IApplicationThread client = transaction.getClient();//調用ClientTransaction的scheduleTransactiontransaction.schedule();if (!(client instanceof Binder)) {transaction.recycle();}}
}
>frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
public class ClientTransaction implements Parcelable, ObjectPoolItem {private IApplicationThread mClient;public void schedule() throws RemoteException {//注釋2,調用IApplicationThread的scheduleTransaction方法mClient.scheduleTransaction(this);}
}public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {private class ApplicationThread extends IApplicationThread.Stub {@Overridepublic void scheduleTransaction(ClientTransaction transaction) throws RemoteException {//注釋3,調用scheduleTransaction方法,該方法位于父類ClientTransactionHandler中ActivityThread.this.scheduleTransaction(transaction);}}
}public abstract class ClientTransactionHandler {void scheduleTransaction(ClientTransaction transaction) {transaction.preExecute(this);//注釋3,調用sendMessagesendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);}
}public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal {private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);final H mH = new H();void sendMessage(int what, Object obj) {sendMessage(what, obj, 0, 0, false);}private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {Message msg = Message.obtain();msg.what = what;msg.obj = obj;msg.arg1 = arg1;msg.arg2 = arg2;if (async) {msg.setAsynchronous(true);}mH.sendMessage(msg);}class H extends Handler {public static final int EXECUTE_TRANSACTION = 159;public void handleMessage(Message msg) { case EXECUTE_TRANSACTION:final ClientTransaction transaction = (ClientTransaction) msg.obj;//注釋4,調用TransactionExecutor的execute方法mTransactionExecutor.execute(transaction);if (isSystem()) {transaction.recycle();}break;}}
}public class TransactionExecutor {public void execute(ClientTransaction transaction) {...代碼省略...//繼續調用executeCallbacks方法executeCallbacks(transaction);executeLifecycleState(transaction);mPendingActions.clear();}public void executeCallbacks(ClientTransaction transaction) {...代碼省略... final int size = callbacks.size();for (int i = 0; i < size; ++i) {final ClientTransactionItem item = callbacks.get(i);...代碼省略...//注釋4,調用每個ClientTransactionItem對象實例的execute方法item.execute(mTransactionHandler, token, mPendingActions);item.postExecute(mTransactionHandler, token, mPendingActions);...代碼省略...}}
}public class ConfigurationChangeItem extends ClientTransactionItem {//獲取ConfigurationChangeItem實例對象public static ConfigurationChangeItem obtain(Configuration config) {ConfigurationChangeItem instance = ObjectPool.obtain(ConfigurationChangeItem.class);if (instance == null) {instance = new ConfigurationChangeItem();}instance.mConfiguration = config;return instance;}@Overridepublic void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {//注釋5,這里會觸發ActivityThreade的handleConfigurationChanged方法client.handleConfigurationChanged(mConfiguration);}
}public class ActivityRelaunchItem extends ActivityTransactionItem {@Overridepublic 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");//注釋6,調用ActivityThread的handleRelaunchActivity方法client.handleRelaunchActivity(mActivityClientRecord, pendingActions);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}public class ActivityConfigurationChangeItem extends ActivityTransactionItem {@Overridepublic void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");//注釋7,調用ActivityThread的handleActivityConfigurationChanged方法client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY);Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}
}
對以上代碼做個簡單概述。
- WindowProcessController的onConfigurationChanged方法經過層層調用,最終會在注釋1處觸發一個關鍵調用,調用ATM的getLifecycleManager方法獲取ClientLifecycleManager實例,并調用該對象的scheduleTransaction方法,傳入ConfigurationChangeItem對象實例作為參數,這個我們后面還會提到。
- ClientLifecycleManager的scheduleTransaction方法繼續往下走,會在注釋2處觸發IApplicationThread的scheduleTransaction方法,該方法位于父類ClientTransactionHandler中,在注釋3處調用sendMessage方法,發送ActivityThread.H.EXECUTE_TRANSACTION的消息類型,最終會走到注釋4處,調用TransactionExecutor的execute方法。
- TransactionExecutor的execute方法繼續調用executeCallbacks方法,然后在注釋5處調用每個ClientTransactionItem對象實例的execute方法,我們在前面注釋1處提過到過ConfigurationChangeItem對象作為參數。
- 默認情況下在UIMode發生切換的時候,這里的ClientTransactionItem對象實例其實是ActivityRelaunchItem,執行execute方法,也就是注釋6處會觸發ActivityThread的handleRelaunchActivity,最終會觸發Activity的onCreate方法。
- 如果Activity頁面不希望UIMode發生切換的時候重新執行onCreate方法,這里的ClientTransactionItem對象實例其實是ActivityConfigurationChangeItem,執行execute方法,也就是注釋7處會觸發ActivityThread的handleActivityConfigurationChanged,最終會觸發Activity的onConfigurationChanged方法。
三、ActivityThread通知應用
3.1 回調Activity的onCreate方法
public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {@Overridepublic void handleRelaunchActivity(ActivityClientRecord tmp,PendingTransactionActions pendingActions) {...代碼省略...//注釋1,調用handleRelaunchActivityInner方法handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");...代碼省略...}private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,PendingTransactionActions pendingActions, boolean startsNotResumed,Configuration overrideConfig, String reason) {// Preserve last used intent, it may be set from Activity#setIntent().final Intent customIntent = r.activity.mIntent;// Need to ensure state is saved.if (!r.paused) {performPauseActivity(r, false, reason, null /* pendingActions */);}if (!r.stopped) {callActivityOnStop(r, true /* saveState */, reason);}//注釋2,調用handleDestroyActivityhandleDestroyActivity(r, false, configChanges, true, reason);r.activity = null;r.window = null;r.hideForNow = false;r.nextIdle = null;// Merge any pending results and pending intents; don't just replace themif (pendingResults != null) {if (r.pendingResults == null) {r.pendingResults = pendingResults;} else {r.pendingResults.addAll(pendingResults);}}if (pendingIntents != null) {if (r.pendingIntents == null) {r.pendingIntents = pendingIntents;} else {r.pendingIntents.addAll(pendingIntents);}}r.startsNotResumed = startsNotResumed;r.overrideConfig = overrideConfig;//注釋3,調用handleLaunchActivity方法handleLaunchActivity(r, pendingActions, customIntent);}@Overridepublic void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,...代碼省略...WindowManager wm = r.activity.getWindowManager();View v = r.activity.mDecor;...代碼省略...//將當前activity對應的viwe從WMS中移除wm.removeViewImmediate(v);...代碼省略...}}
}
注釋1處繼續調用handleRelaunchActivityInner方法;
注釋2處調用handleDestroyActivity方法將當前Activity對應的視圖從WMS中移除。
注釋3處調用handleLaunchActivity方法將當前Activity對應的視圖重新添加到WMS中。
3.2 回調Activity的onConfigurationChanged方法
public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {public void handleActivityConfigurationChanged(ActivityClientRecord r,@NonNull Configuration overrideConfig, int displayId) {...代碼省略...r.overrideConfig = overrideConfig;final ViewRootImpl viewRoot = r.activity.mDecor != null? r.activity.mDecor.getViewRootImpl() : null;//注釋1,調用performConfigurationChangedForActivity方法final Configuration reportedConfig = performConfigurationChangedForActivity(r,mConfigurationController.getCompatConfiguration(),movedToDifferentDisplay ? displayId : r.activity.getDisplayId());if (viewRoot != null) {if (movedToDifferentDisplay) {viewRoot.onMovedToDisplay(displayId, reportedConfig);}viewRoot.updateConfiguration(displayId);}mSomeActivitiesChanged = true;}private Configuration performConfigurationChangedForActivity(ActivityClientRecord r,Configuration newBaseConfig, int displayId) {r.tmpConfig.setTo(newBaseConfig);if (r.overrideConfig != null) {r.tmpConfig.updateFrom(r.overrideConfig);}//注釋2,調用performActivityConfigurationChanged方法final Configuration reportedConfig = performActivityConfigurationChanged(r.activity,r.tmpConfig, r.overrideConfig, displayId);freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));return reportedConfig;}private Configuration performActivityConfigurationChanged(Activity activity,Configuration newConfig, Configuration amOverrideConfig, int displayId) {...代碼省略...//調用activity的onConfigurationChanged方法activity.onConfigurationChanged(configToReport);...代碼省略...}
}
注釋1處繼續調用performConfigurationChangedForActivity方法;
注釋2處調用performActivityConfigurationChanged方法;
注釋3處調用Activity的onConfigurationChanged方法。
參考文章:Android 13 深色主題切換流程