Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d33ef566 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

ActivityThread: Only update code paths that have been added

When an ApplicationInfo object is updated and we want to update
code paths without restarting the app's process, we need to make
sure that we only update the paths that have changed. This means
diffing between the old paths and the new paths.

Test: watch /proc/<pid>/maps for dex entries before and after
      running adb exec-out am update-appinfos all <package>
Change-Id: I6855d860478ade3184bbb578a5483d8548396daa
parent 4ea4f63d
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -4919,18 +4919,27 @@ public final class ActivityThread {
    }

    void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
        // Updates triggered by package installation go through a package update
        // receiver. Here we try to capture ApplicationInfo changes that are
        // caused by other sources, such as overlays. That means we want to be as conservative
        // about code changes as possible. Take the diff of the old ApplicationInfo and the new
        // to see if anything needs to change.
        synchronized (mResourcesManager) {
            // Update all affected loaded packages with new package information
            WeakReference<LoadedApk> ref = mPackages.get(ai.packageName);
            LoadedApk apk = ref != null ? ref.get() : null;
            if (apk != null) {
                apk.updateApplicationInfo(ai, null);
                final ArrayList<String> oldPaths = new ArrayList<>();
                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths, null /*outLibPaths*/);
                apk.updateApplicationInfo(ai, oldPaths);
            }

            ref = mResourcePackages.get(ai.packageName);
            apk = ref != null ? ref.get() : null;
            if (apk != null) {
                apk.updateApplicationInfo(ai, null);
                final ArrayList<String> oldPaths = new ArrayList<>();
                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths, null /*outLibPaths*/);
                apk.updateApplicationInfo(ai, oldPaths);
            }

            // Update all affected Resources objects to use new ResourcesImpl
+11 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.app;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -262,7 +264,15 @@ public final class LoadedApk {
        return ai.sharedLibraryFiles;
    }

    public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) {
    /**
     * Update the ApplicationInfo for an app. If oldPaths is null, all the paths are considered
     * new.
     * @param aInfo The new ApplicationInfo to use for this LoadedApk
     * @param oldPaths The code paths for the old ApplicationInfo object. null means no paths can
     *                 be reused.
     */
    public void updateApplicationInfo(@NonNull ApplicationInfo aInfo,
            @Nullable List<String> oldPaths) {
        setApplicationInfo(aInfo);

        final List<String> newPaths = new ArrayList<>();