Loading core/java/android/app/ActivityThread.java +46 −11 Original line number Diff line number Diff line Loading @@ -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() { Loading Loading @@ -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(); Loading Loading @@ -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) -> { Loading @@ -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(); Loading core/java/android/content/res/flags.aconfig +12 −0 Original line number Diff line number Diff line Loading @@ -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 } } core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 Loading Loading
core/java/android/app/ActivityThread.java +46 −11 Original line number Diff line number Diff line Loading @@ -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() { Loading Loading @@ -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(); Loading Loading @@ -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) -> { Loading @@ -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(); Loading
core/java/android/content/res/flags.aconfig +12 −0 Original line number Diff line number Diff line Loading @@ -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 } }
core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 Loading