From 82549387c0c2aa12255b6b257a242eeb7598886e Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Fri, 2 Jul 2021 10:02:26 -0700 Subject: [PATCH] Do not update RM config with previous sequence If an application info update is pending and RM#applyConfigurationToResourcesLocked is called with a config with an older sequence that RM's current global config, the application info update should not be applied, nor should the global config be updated with the older config. Similarly, when an application is updated and there is a pending application info change for the previous version of the package, clear the currently pending application info updates for that package to prevent the old overlays from being applied on top of the newly updated application. Bug: 189100984 Bug: 192449747 Test: toggle wallpaper and observe QS has correct colors Change-Id: I4bab55960febdae16df7150ccac44e06245e8333 --- core/java/android/app/ActivityThread.java | 12 +- core/java/android/app/ResourcesManager.java | 146 +++++++++++--------- 2 files changed, 82 insertions(+), 76 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 00ba55c4cb1cb..3915abe1e9ebf 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1169,7 +1169,7 @@ public final class ActivityThread extends ClientTransactionHandler } public void scheduleApplicationInfoChanged(ApplicationInfo ai) { - mResourcesManager.updatePendingAppInfoUpdates(ai); + mResourcesManager.appendPendingAppInfoUpdate(new String[]{ai.sourceDir}, ai); mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai); sendMessage(H.APPLICATION_INFO_CHANGED, ai); } @@ -6001,16 +6001,12 @@ public final class ActivityThread extends ClientTransactionHandler resApk = ref != null ? ref.get() : null; } - final String[] oldResDirs = new String[2]; - if (apk != null) { - oldResDirs[0] = apk.getResDir(); final ArrayList oldPaths = new ArrayList<>(); LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths); apk.updateApplicationInfo(ai, oldPaths); } if (resApk != null) { - oldResDirs[1] = resApk.getResDir(); final ArrayList oldPaths = new ArrayList<>(); LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths); resApk.updateApplicationInfo(ai, oldPaths); @@ -6018,7 +6014,7 @@ public final class ActivityThread extends ClientTransactionHandler synchronized (mResourcesManager) { // Update all affected Resources objects to use new ResourcesImpl - mResourcesManager.applyNewResourceDirs(ai, oldResDirs); + mResourcesManager.applyAllPendingAppInfoUpdates(); } } @@ -6274,7 +6270,9 @@ public final class ActivityThread extends ClientTransactionHandler synchronized (mResourcesManager) { // Update affected Resources objects to use new ResourcesImpl - mResourcesManager.applyNewResourceDirs(aInfo, oldResDirs); + mResourcesManager.appendPendingAppInfoUpdate(oldResDirs, + aInfo); + mResourcesManager.applyAllPendingAppInfoUpdates(); } } catch (RemoteException e) { } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index dfd1e2b61fae6..20afffc1f562e 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -42,6 +42,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.view.Display; import android.view.DisplayAdjustments; @@ -101,7 +102,7 @@ public class ResourcesManager { * ApplicationInfo changes that need to be applied to Resources when the next configuration * change occurs. */ - private ArrayList mPendingAppInfoUpdates; + private ArrayList> mPendingAppInfoUpdates; /** * A mapping of ResourceImpls and their configurations. These are heavy weight objects @@ -1273,19 +1274,33 @@ public class ResourcesManager { return newKey; } - public void updatePendingAppInfoUpdates(@NonNull ApplicationInfo appInfo) { + public void appendPendingAppInfoUpdate(@NonNull String[] oldSourceDirs, + @NonNull ApplicationInfo appInfo) { synchronized (mLock) { if (mPendingAppInfoUpdates == null) { mPendingAppInfoUpdates = new ArrayList<>(); } - // Clear previous app info changes for the package to prevent multiple ResourcesImpl - // recreations when only the last recreation will be used. + // Clear previous app info changes for a package to prevent multiple ResourcesImpl + // recreations when the recreation caused by this update completely overrides the + // previous pending changes. for (int i = mPendingAppInfoUpdates.size() - 1; i >= 0; i--) { - if (appInfo.sourceDir.equals(mPendingAppInfoUpdates.get(i).sourceDir)) { + if (ArrayUtils.containsAll(oldSourceDirs, mPendingAppInfoUpdates.get(i).first)) { mPendingAppInfoUpdates.remove(i); } } - mPendingAppInfoUpdates.add(appInfo); + mPendingAppInfoUpdates.add(new Pair<>(oldSourceDirs, appInfo)); + } + } + + public final void applyAllPendingAppInfoUpdates() { + synchronized (mLock) { + if (mPendingAppInfoUpdates != null) { + for (int i = 0, n = mPendingAppInfoUpdates.size(); i < n; i++) { + final Pair appInfo = mPendingAppInfoUpdates.get(i); + applyNewResourceDirsLocked(appInfo.first, appInfo.second); + } + mPendingAppInfoUpdates = null; + } } } @@ -1302,18 +1317,7 @@ public class ResourcesManager { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#applyConfigurationToResources"); - final boolean assetsUpdated = mPendingAppInfoUpdates != null - && config.assetsSeq > mResConfiguration.assetsSeq; - if (assetsUpdated) { - for (int i = 0, n = mPendingAppInfoUpdates.size(); i < n; i++) { - final ApplicationInfo appInfo = mPendingAppInfoUpdates.get(i); - applyNewResourceDirs(appInfo, new String[]{appInfo.sourceDir}); - } - mPendingAppInfoUpdates = null; - } - - if (!assetsUpdated && !mResConfiguration.isOtherSeqNewer(config) - && compat == null) { + if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { if (DEBUG || DEBUG_CONFIGURATION) { Slog.v(TAG, "Skipping new config: curSeq=" + mResConfiguration.seq + ", newSeq=" + config.seq); @@ -1330,6 +1334,13 @@ public class ResourcesManager { | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; } + // If a application info update was scheduled to occur in this process but has not + // occurred yet, apply it now so the resources objects will have updated paths when + // the assets sequence changes. + if ((changes & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { + applyAllPendingAppInfoUpdates(); + } + DisplayMetrics displayMetrics = getDisplayMetrics(); if (adjustments != null) { // Currently the only case where the adjustment takes effect is to simulate @@ -1353,7 +1364,7 @@ public class ResourcesManager { } } - return assetsUpdated || changes != 0; + return changes != 0; } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } @@ -1440,61 +1451,58 @@ public class ResourcesManager { } } - // TODO(adamlesinski): Make this accept more than just overlay directories. - void applyNewResourceDirs(@NonNull final ApplicationInfo appInfo, - @Nullable final String[] oldPaths) { - synchronized (mLock) { - try { - Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, - "ResourcesManager#applyNewResourceDirsLocked"); + private void applyNewResourceDirsLocked(@Nullable final String[] oldSourceDirs, + @NonNull final ApplicationInfo appInfo) { + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#applyNewResourceDirsLocked"); - String baseCodePath = appInfo.getBaseCodePath(); + String baseCodePath = appInfo.getBaseCodePath(); - final int myUid = Process.myUid(); - String[] newSplitDirs = appInfo.uid == myUid - ? appInfo.splitSourceDirs - : appInfo.splitPublicSourceDirs; + final int myUid = Process.myUid(); + String[] newSplitDirs = appInfo.uid == myUid + ? appInfo.splitSourceDirs + : appInfo.splitPublicSourceDirs; - // ApplicationInfo is mutable, so clone the arrays to prevent outside modification - String[] copiedSplitDirs = ArrayUtils.cloneOrNull(newSplitDirs); - String[] copiedResourceDirs = combinedOverlayPaths(appInfo.resourceDirs, - appInfo.overlayPaths); + // ApplicationInfo is mutable, so clone the arrays to prevent outside modification + String[] copiedSplitDirs = ArrayUtils.cloneOrNull(newSplitDirs); + String[] copiedResourceDirs = combinedOverlayPaths(appInfo.resourceDirs, + appInfo.overlayPaths); - if (appInfo.uid == myUid) { - addApplicationPathsLocked(baseCodePath, copiedSplitDirs); - } - - final ArrayMap updatedResourceKeys = new ArrayMap<>(); - final int implCount = mResourceImpls.size(); - for (int i = 0; i < implCount; i++) { - final ResourcesKey key = mResourceImpls.keyAt(i); - final WeakReference weakImplRef = mResourceImpls.valueAt(i); - final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; - - if (impl == null) { - continue; - } - - if (key.mResDir == null - || key.mResDir.equals(baseCodePath) - || ArrayUtils.contains(oldPaths, key.mResDir)) { - updatedResourceKeys.put(impl, new ResourcesKey( - baseCodePath, - copiedSplitDirs, - copiedResourceDirs, - key.mLibDirs, - key.mDisplayId, - key.mOverrideConfiguration, - key.mCompatInfo, - key.mLoaders - )); - } - } - - redirectResourcesToNewImplLocked(updatedResourceKeys); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + if (appInfo.uid == myUid) { + addApplicationPathsLocked(baseCodePath, copiedSplitDirs); } + + final ArrayMap updatedResourceKeys = new ArrayMap<>(); + final int implCount = mResourceImpls.size(); + for (int i = 0; i < implCount; i++) { + final ResourcesKey key = mResourceImpls.keyAt(i); + final WeakReference weakImplRef = mResourceImpls.valueAt(i); + final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; + + if (impl == null) { + continue; + } + + if (key.mResDir == null + || key.mResDir.equals(baseCodePath) + || ArrayUtils.contains(oldSourceDirs, key.mResDir)) { + updatedResourceKeys.put(impl, new ResourcesKey( + baseCodePath, + copiedSplitDirs, + copiedResourceDirs, + key.mLibDirs, + key.mDisplayId, + key.mOverrideConfiguration, + key.mCompatInfo, + key.mLoaders + )); + } + } + + redirectResourcesToNewImplLocked(updatedResourceKeys); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } }