summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYurii Zubrytskyi <zyy@google.com>2023-11-01 19:05:46 -0700
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-11-16 18:44:22 +0000
commitf6e816f08ee45c71435c26f3656e4c488656e90f (patch)
tree1855b7d19ce7ec3274d35b8759bbd9319196527f
parent5d204d1ca15bca69bd0003176d2fbf4e435204cc (diff)
downloadbase-f6e816f08ee45c71435c26f3656e4c488656e90f.tar.gz
Runtime: fix the theme colors on device reset
When launching an activity we may handle the launch before applying the application info update that carries new overlay paths for the app. In this case the activity will have enough time to load the resources with no overlays applied, and use e.g. wrong accent colors. This change makes sure we apply pending application info updates on any activity launch, and that the resource paths are up to date on the very first Resources object creation. Bug: 299064578 Test: manual, factory reset for 8a, 10x (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7230cdf9d79e634a03eb126f89d0bf2591dccb8a) Merged-In: I501d9ce39f6e0437484632c85bf2773fe4a16474 Change-Id: I501d9ce39f6e0437484632c85bf2773fe4a16474
-rw-r--r--core/java/android/app/ActivityThread.java49
-rw-r--r--core/java/android/app/LoadedApk.java13
2 files changed, 56 insertions, 6 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f4caef0f2553..016d7214bda9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -359,6 +359,15 @@ public final class ActivityThread extends ClientTransactionHandler
/** Maps from activity token to the pending override configuration. */
@GuardedBy("mPendingOverrideConfigs")
private final ArrayMap<IBinder, Configuration> mPendingOverrideConfigs = new ArrayMap<>();
+
+ /**
+ * A queue of pending ApplicationInfo updates. In case when we get a concurrent update
+ * this queue allows us to only apply the latest object, and it can be applied on demand
+ * instead of waiting for the handler thread to reach the scheduled callback.
+ */
+ @GuardedBy("mResourcesManager")
+ private final ArrayMap<String, ApplicationInfo> mPendingAppInfoUpdates = new ArrayMap<>();
+
/** The activities to be truly destroyed (not include relaunch). */
final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed =
Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>());
@@ -1260,9 +1269,19 @@ public final class ActivityThread extends ClientTransactionHandler
}
public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
+ synchronized (mResourcesManager) {
+ var oldAi = mPendingAppInfoUpdates.put(ai.packageName, ai);
+ if (oldAi != null && oldAi.createTimestamp > ai.createTimestamp) {
+ Slog.w(TAG, "Skipping application info changed for obsolete AI with TS "
+ + ai.createTimestamp + " < already pending TS "
+ + oldAi.createTimestamp);
+ mPendingAppInfoUpdates.put(ai.packageName, oldAi);
+ return;
+ }
+ }
mResourcesManager.appendPendingAppInfoUpdate(new String[]{ai.sourceDir}, ai);
- mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai);
- sendMessage(H.APPLICATION_INFO_CHANGED, ai);
+ mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai.packageName);
+ sendMessage(H.APPLICATION_INFO_CHANGED, ai.packageName);
}
public void updateTimeZone() {
@@ -2437,7 +2456,7 @@ public final class ActivityThread extends ClientTransactionHandler
break;
}
case APPLICATION_INFO_CHANGED:
- handleApplicationInfoChanged((ApplicationInfo) msg.obj);
+ applyPendingApplicationInfoChanges((String) msg.obj);
break;
case RUN_ISOLATED_ENTRY_POINT:
handleRunIsolatedEntryPoint((String) ((SomeArgs) msg.obj).arg1,
@@ -3922,7 +3941,8 @@ public final class ActivityThread extends ClientTransactionHandler
mProfiler.startProfiling();
}
- // Make sure we are running with the most recent config.
+ // Make sure we are running with the most recent config and resource paths.
+ applyPendingApplicationInfoChanges(r.activityInfo.packageName);
mConfigurationController.handleConfigurationChanged(null, null);
updateDeviceIdForNonUIContexts(deviceId);
@@ -6248,6 +6268,17 @@ public final class ActivityThread extends ClientTransactionHandler
r.mLastReportedWindowingMode = newWindowingMode;
}
+ private void applyPendingApplicationInfoChanges(String packageName) {
+ final ApplicationInfo ai;
+ synchronized (mResourcesManager) {
+ ai = mPendingAppInfoUpdates.remove(packageName);
+ }
+ if (ai == null) {
+ return;
+ }
+ handleApplicationInfoChanged(ai);
+ }
+
/**
* Updates the application info.
*
@@ -6273,6 +6304,16 @@ public final class ActivityThread extends ClientTransactionHandler
apk = ref != null ? ref.get() : null;
ref = mResourcePackages.get(ai.packageName);
resApk = ref != null ? ref.get() : null;
+ for (ActivityClientRecord ar : mActivities.values()) {
+ if (ar.activityInfo.applicationInfo.packageName.equals(ai.packageName)) {
+ ar.activityInfo.applicationInfo = ai;
+ if (apk != null || resApk != null) {
+ ar.packageInfo = apk != null ? apk : resApk;
+ } else {
+ apk = ar.packageInfo;
+ }
+ }
+ }
}
if (apk != null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b5efb73225d6..f092ce2363aa 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -343,7 +343,9 @@ public final class LoadedApk {
*/
public void updateApplicationInfo(@NonNull ApplicationInfo aInfo,
@Nullable List<String> oldPaths) {
- setApplicationInfo(aInfo);
+ if (!setApplicationInfo(aInfo)) {
+ return;
+ }
final List<String> newPaths = new ArrayList<>();
makePaths(mActivityThread, aInfo, newPaths);
@@ -388,7 +390,13 @@ public final class LoadedApk {
mAppComponentFactory = createAppFactory(aInfo, mDefaultClassLoader);
}
- private void setApplicationInfo(ApplicationInfo aInfo) {
+ private boolean setApplicationInfo(ApplicationInfo aInfo) {
+ if (mApplicationInfo != null && mApplicationInfo.createTimestamp > aInfo.createTimestamp) {
+ Slog.w(TAG, "New application info for package " + aInfo.packageName
+ + " is out of date with TS " + aInfo.createTimestamp + " < the current TS "
+ + mApplicationInfo.createTimestamp);
+ return false;
+ }
final int myUid = Process.myUid();
aInfo = adjustNativeLibraryPaths(aInfo);
mApplicationInfo = aInfo;
@@ -411,6 +419,7 @@ public final class LoadedApk {
if (aInfo.requestsIsolatedSplitLoading() && !ArrayUtils.isEmpty(mSplitNames)) {
mSplitLoader = new SplitDependencyLoaderImpl(aInfo.splitDependencies);
}
+ return true;
}
void setSdkSandboxStorage(@Nullable String sdkSandboxClientAppVolumeUuid,