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

Commit be73c3a3 authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Handle application info change for system context

When handling application info changes, we update the application infos
of all the tracked packages. However, we also have the system package,
which is not directly tracked, and thus not updated in this case.

The system context (corresponding to the system package) does not have a
base resources path initially, and it won't have one set, as it is not
updated with the new application info. However, while handling
application info changes, we also update in-place all the tracked
ResourceImpls (including the one from the system context) using the new
application info. Thus, the system context has its resources updated,
despite its package info being stale.

From the system context is derived a system UI context, which has the
same underlying info. When creating a new context from this system UI
context, we try to initialize the resources based on the package info.
As this info is stale, we only have the base system resources, but we
are missing (along other state) the color overlays.

This ensures that the package info of the system context is also updated
when handling application info changes, so that any contexts created
from this one would have the correct state.

Flag: android.content.res.system_context_handle_app_info_changed
Test: atest testHandleApplicationInfoChanged_systemContext
Bug: 362420029
Change-Id: I027ce41419944e2af3c66cb753e7a0f97c8f57f3
parent 374bde7e
Loading
Loading
Loading
Loading
+46 −11
Original line number Diff line number Diff line
@@ -3100,6 +3100,19 @@ public final class ActivityThread extends ClientTransactionHandler
        mResourcesManager = ResourcesManager.getInstance();
    }

    /**
     * Creates and initialize a new system activity thread, to be used for testing. This does not
     * call {@link #attach}, so it does not modify static state.
     */
    @VisibleForTesting
    @NonNull
    public static ActivityThread createSystemActivityThreadForTesting() {
        final var thread = new ActivityThread();
        thread.mSystemThread = true;
        initializeSystemThread(thread);
        return thread;
    }

    @UnsupportedAppUsage
    public ApplicationThread getApplicationThread()
    {
@@ -6806,6 +6819,16 @@ public final class ActivityThread extends ClientTransactionHandler
            LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);
            resApk.updateApplicationInfo(ai, oldPaths);
        }
        if (android.content.res.Flags.systemContextHandleAppInfoChanged() && mSystemThread) {
            final var systemContext = getSystemContext();
            if (systemContext.getPackageName().equals(ai.packageName)) {
                // The system package is not tracked directly, but still needs to receive updates to
                // its application info.
                final ArrayList<String> oldPaths = new ArrayList<>();
                LoadedApk.makePaths(this, systemContext.getApplicationInfo(), oldPaths);
                systemContext.mPackageInfo.updateApplicationInfo(ai, oldPaths);
            }
        }

        ResourcesImpl beforeImpl = getApplication().getResources().getImpl();

@@ -8560,17 +8583,7 @@ public final class ActivityThread extends ClientTransactionHandler
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                mInstrumentation.basicInit(this);
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
            initializeSystemThread(this);
        }

        ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
@@ -8595,6 +8608,28 @@ public final class ActivityThread extends ClientTransactionHandler
        ViewRootImpl.addConfigCallback(configChangedCallback);
    }

    /**
     * Initializes the given system activity thread, setting up its instrumentation and initial
     * application. This only has an effect if the given thread is a {@link #mSystemThread}.
     *
     * @param thread the given system activity thread to initialize.
     */
    private static void initializeSystemThread(@NonNull ActivityThread thread) {
        if (!thread.mSystemThread) {
            return;
        }
        try {
            thread.mInstrumentation = new Instrumentation();
            thread.mInstrumentation.basicInit(thread);
            ContextImpl context = ContextImpl.createAppContext(
                    thread, thread.getSystemContext().mPackageInfo);
            thread.mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);
            thread.mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException("Unable to instantiate Application():" + e, e);
        }
    }

    @UnsupportedAppUsage
    public static ActivityThread systemMain() {
        ThreadedRenderer.initForSystemProcess();
+12 −0
Original line number Diff line number Diff line
@@ -83,3 +83,15 @@ flag {
    bug: "364035303"
}

flag {
    name: "system_context_handle_app_info_changed"
    is_exported: true
    namespace: "resource_manager"
    description: "Feature flag for allowing system context to handle application info changes"
    bug: "362420029"
    # This flag is read at boot time.
    is_fixed_read_only: true
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+35 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -59,6 +60,7 @@ import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.StopActivityItem;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -67,7 +69,11 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -129,6 +135,9 @@ public class ActivityThreadTest {
    @Rule(order = 1)
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);

    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    private ActivityWindowInfoListener mActivityWindowInfoListener;
    private WindowTokenClientController mOriginalWindowTokenClientController;
    private Configuration mOriginalAppConfig;
@@ -911,6 +920,32 @@ public class ActivityThreadTest {
        });
    }

    /**
     * Verifies that {@link ActivityThread#handleApplicationInfoChanged} does send updates to the
     * system context, when given the system application info.
     */
    @RequiresFlagsEnabled(android.content.res.Flags.FLAG_SYSTEM_CONTEXT_HANDLE_APP_INFO_CHANGED)
    @Test
    public void testHandleApplicationInfoChanged_systemContext() {
        Looper.prepare();
        final var systemThread = ActivityThread.createSystemActivityThreadForTesting();

        final Context systemContext = systemThread.getSystemContext();
        final var appInfo = systemContext.getApplicationInfo();
        // sourceDir must not be null, and contain at least a '/', for handleApplicationInfoChanged.
        appInfo.sourceDir = "/";

        // Create a copy of the application info.
        final var newAppInfo = new ApplicationInfo(appInfo);
        newAppInfo.sourceDir = "/";
        assertWithMessage("New application info is a separate instance")
                .that(systemContext.getApplicationInfo()).isNotSameInstanceAs(newAppInfo);

        systemThread.handleApplicationInfoChanged(newAppInfo);
        assertWithMessage("Application info was updated successfully")
                .that(systemContext.getApplicationInfo()).isSameInstanceAs(newAppInfo);
    }

    /**
     * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord,
     * Configuration, int, ActivityWindowInfo)} to try to push activity configuration to the