Loading core/java/android/app/ActivityThread.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -238,6 +238,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.ApplicationSharedMemory; import com.android.internal.os.ApplicationSharedMemory; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; import com.android.internal.os.BinderInternal; import com.android.internal.os.DebugStore; import com.android.internal.os.DebugStore; Loading Loading @@ -7794,6 +7795,16 @@ public final class ActivityThread extends ClientTransactionHandler // Propagate Content Capture options // Propagate Content Capture options app.setContentCaptureOptions(data.contentCaptureOptions); app.setContentCaptureOptions(data.contentCaptureOptions); if (android.view.contentcapture.flags.Flags.warmUpBackgroundThreadForContentCapture() && data.contentCaptureOptions != null) { if (data.contentCaptureOptions.enableReceiver && !data.contentCaptureOptions.lite) { // Warm up the background thread when: // 1) app is launched with content capture enabled, and // 2) the app is NOT launched with content capture lite enabled. BackgroundThread.startIfNeeded(); } } sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName); sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName); mInitialApplication = app; mInitialApplication = app; Loading core/java/android/view/contentcapture/flags/content_capture_flags.aconfig +10 −0 Original line number Original line Diff line number Diff line Loading @@ -34,3 +34,13 @@ flag { purpose: PURPOSE_BUGFIX purpose: PURPOSE_BUGFIX } } } } flag { name: "warm_up_background_thread_for_content_capture" namespace: "system_performance" description: "Feature flag to warm up the background thread for content capture" bug: "408273598" metadata { purpose: PURPOSE_BUGFIX } } core/java/com/android/internal/os/BackgroundThread.java +20 −4 Original line number Original line Diff line number Diff line Loading @@ -40,10 +40,17 @@ public final class BackgroundThread extends HandlerThread { super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND); super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND); } } private static void ensureThreadLocked() { private static void ensureThreadStartedLocked() { if (sInstance == null) { if (sInstance == null) { sInstance = new BackgroundThread(); sInstance = new BackgroundThread(); sInstance.start(); sInstance.start(); } } private static void ensureThreadReadyLocked() { ensureThreadStartedLocked(); if (sHandler == null) { // This will block until the looper is initialized on the background thread. final Looper looper = sInstance.getLooper(); final Looper looper = sInstance.getLooper(); looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); looper.setSlowLogThresholdMs( looper.setSlowLogThresholdMs( Loading @@ -54,10 +61,19 @@ public final class BackgroundThread extends HandlerThread { } } } } /** * Starts the thread if needed, but doesn't block on thread initialization or readiness. */ public static void startIfNeeded() { synchronized (BackgroundThread.class) { ensureThreadStartedLocked(); } } @NonNull @NonNull public static BackgroundThread get() { public static BackgroundThread get() { synchronized (BackgroundThread.class) { synchronized (BackgroundThread.class) { ensureThreadLocked(); ensureThreadReadyLocked(); return sInstance; return sInstance; } } } } Loading @@ -65,7 +81,7 @@ public final class BackgroundThread extends HandlerThread { @NonNull @NonNull public static Handler getHandler() { public static Handler getHandler() { synchronized (BackgroundThread.class) { synchronized (BackgroundThread.class) { ensureThreadLocked(); ensureThreadReadyLocked(); return sHandler; return sHandler; } } } } Loading @@ -73,7 +89,7 @@ public final class BackgroundThread extends HandlerThread { @NonNull @NonNull public static Executor getExecutor() { public static Executor getExecutor() { synchronized (BackgroundThread.class) { synchronized (BackgroundThread.class) { ensureThreadLocked(); ensureThreadReadyLocked(); return sHandlerExecutor; return sHandlerExecutor; } } } } Loading core/tests/coretests/src/com/android/internal/os/BackgroundThreadTest.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -51,4 +51,22 @@ public class BackgroundThreadTest { boolean success = done.block(5000); boolean success = done.block(5000); assertThat(success).isTrue(); assertThat(success).isTrue(); } } @Test public void test_startIfNeeded() { BackgroundThread.startIfNeeded(); BackgroundThread thread = BackgroundThread.get(); assertThat(thread.getLooper()).isNotEqualTo(Looper.getMainLooper()); } @Test public void test_startIfNeededMultipleTimes() { BackgroundThread.startIfNeeded(); BackgroundThread.startIfNeeded(); BackgroundThread.startIfNeeded(); BackgroundThread thread = BackgroundThread.get(); assertThat(thread.getLooper()).isNotEqualTo(Looper.getMainLooper()); } } } Loading
core/java/android/app/ActivityThread.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -238,6 +238,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.ApplicationSharedMemory; import com.android.internal.os.ApplicationSharedMemory; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; import com.android.internal.os.BinderInternal; import com.android.internal.os.DebugStore; import com.android.internal.os.DebugStore; Loading Loading @@ -7794,6 +7795,16 @@ public final class ActivityThread extends ClientTransactionHandler // Propagate Content Capture options // Propagate Content Capture options app.setContentCaptureOptions(data.contentCaptureOptions); app.setContentCaptureOptions(data.contentCaptureOptions); if (android.view.contentcapture.flags.Flags.warmUpBackgroundThreadForContentCapture() && data.contentCaptureOptions != null) { if (data.contentCaptureOptions.enableReceiver && !data.contentCaptureOptions.lite) { // Warm up the background thread when: // 1) app is launched with content capture enabled, and // 2) the app is NOT launched with content capture lite enabled. BackgroundThread.startIfNeeded(); } } sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName); sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName); mInitialApplication = app; mInitialApplication = app; Loading
core/java/android/view/contentcapture/flags/content_capture_flags.aconfig +10 −0 Original line number Original line Diff line number Diff line Loading @@ -34,3 +34,13 @@ flag { purpose: PURPOSE_BUGFIX purpose: PURPOSE_BUGFIX } } } } flag { name: "warm_up_background_thread_for_content_capture" namespace: "system_performance" description: "Feature flag to warm up the background thread for content capture" bug: "408273598" metadata { purpose: PURPOSE_BUGFIX } }
core/java/com/android/internal/os/BackgroundThread.java +20 −4 Original line number Original line Diff line number Diff line Loading @@ -40,10 +40,17 @@ public final class BackgroundThread extends HandlerThread { super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND); super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND); } } private static void ensureThreadLocked() { private static void ensureThreadStartedLocked() { if (sInstance == null) { if (sInstance == null) { sInstance = new BackgroundThread(); sInstance = new BackgroundThread(); sInstance.start(); sInstance.start(); } } private static void ensureThreadReadyLocked() { ensureThreadStartedLocked(); if (sHandler == null) { // This will block until the looper is initialized on the background thread. final Looper looper = sInstance.getLooper(); final Looper looper = sInstance.getLooper(); looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER); looper.setSlowLogThresholdMs( looper.setSlowLogThresholdMs( Loading @@ -54,10 +61,19 @@ public final class BackgroundThread extends HandlerThread { } } } } /** * Starts the thread if needed, but doesn't block on thread initialization or readiness. */ public static void startIfNeeded() { synchronized (BackgroundThread.class) { ensureThreadStartedLocked(); } } @NonNull @NonNull public static BackgroundThread get() { public static BackgroundThread get() { synchronized (BackgroundThread.class) { synchronized (BackgroundThread.class) { ensureThreadLocked(); ensureThreadReadyLocked(); return sInstance; return sInstance; } } } } Loading @@ -65,7 +81,7 @@ public final class BackgroundThread extends HandlerThread { @NonNull @NonNull public static Handler getHandler() { public static Handler getHandler() { synchronized (BackgroundThread.class) { synchronized (BackgroundThread.class) { ensureThreadLocked(); ensureThreadReadyLocked(); return sHandler; return sHandler; } } } } Loading @@ -73,7 +89,7 @@ public final class BackgroundThread extends HandlerThread { @NonNull @NonNull public static Executor getExecutor() { public static Executor getExecutor() { synchronized (BackgroundThread.class) { synchronized (BackgroundThread.class) { ensureThreadLocked(); ensureThreadReadyLocked(); return sHandlerExecutor; return sHandlerExecutor; } } } } Loading
core/tests/coretests/src/com/android/internal/os/BackgroundThreadTest.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -51,4 +51,22 @@ public class BackgroundThreadTest { boolean success = done.block(5000); boolean success = done.block(5000); assertThat(success).isTrue(); assertThat(success).isTrue(); } } @Test public void test_startIfNeeded() { BackgroundThread.startIfNeeded(); BackgroundThread thread = BackgroundThread.get(); assertThat(thread.getLooper()).isNotEqualTo(Looper.getMainLooper()); } @Test public void test_startIfNeededMultipleTimes() { BackgroundThread.startIfNeeded(); BackgroundThread.startIfNeeded(); BackgroundThread.startIfNeeded(); BackgroundThread thread = BackgroundThread.get(); assertThat(thread.getLooper()).isNotEqualTo(Looper.getMainLooper()); } } }