Loading core/java/android/app/ActivityThread.java +10 −0 Original line number Diff line number Diff line Loading @@ -208,9 +208,11 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.webkit.WebView; import android.window.ITaskFragmentOrganizer; import android.window.SizeConfigurationBuckets; import android.window.SplashScreen; import android.window.SplashScreenView; import android.window.TaskFragmentTransaction; import android.window.WindowContextInfo; import android.window.WindowProviderService; import android.window.WindowTokenClientController; Loading Loading @@ -2046,6 +2048,14 @@ public final class ActivityThread extends ClientTransactionHandler ActivityThread.this.scheduleTransaction(transaction); } @Override public void scheduleTaskFragmentTransaction(@NonNull ITaskFragmentOrganizer organizer, @NonNull TaskFragmentTransaction transaction) throws RemoteException { // TODO(b/260873529): ITaskFragmentOrganizer can be cleanup to be a IBinder token // after flag removal. organizer.onTransactionReady(transaction); } @Override public void requestDirectActions(@NonNull IBinder activityToken, @NonNull IVoiceInteractor interactor, @Nullable RemoteCallback cancellationCallback, Loading core/java/android/app/IApplicationThread.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ import android.os.SharedMemory; import android.view.autofill.AutofillId; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentTransaction; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; Loading Loading @@ -157,6 +159,8 @@ oneway interface IApplicationThread { void scheduleApplicationInfoChanged(in ApplicationInfo ai); void setNetworkBlockSeq(long procStateSeq); void scheduleTransaction(in ClientTransaction transaction); void scheduleTaskFragmentTransaction(in ITaskFragmentOrganizer organizer, in TaskFragmentTransaction transaction); void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor, in RemoteCallback cancellationCallback, in RemoteCallback callback); void performDirectAction(IBinder activityToken, String actionId, Loading services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +28 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.IApplicationThread; import android.content.Intent; import android.content.res.Configuration; import android.os.Binder; Loading Loading @@ -106,6 +107,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr */ private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); private final IApplicationThread mAppThread; private final ITaskFragmentOrganizer mOrganizer; private final int mOrganizerPid; private final int mOrganizerUid; Loading Loading @@ -169,6 +171,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr TaskFragmentOrganizerState(@NonNull ITaskFragmentOrganizer organizer, int pid, int uid, boolean isSystemOrganizer) { if (Flags.bundleClientTransactionFlag()) { mAppThread = getAppThread(pid, uid); } else { mAppThread = null; } mOrganizer = organizer; mOrganizerPid = pid; mOrganizerUid = uid; Loading Loading @@ -407,7 +414,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return; } try { if (Flags.bundleClientTransactionFlag()) { // Dispatch through IApplicationThread to ensure the binder call is in order // with ClientTransaction. mAppThread.scheduleTaskFragmentTransaction(mOrganizer, transaction); } else { mOrganizer.onTransactionReady(transaction); } } catch (RemoteException e) { Slog.d(TAG, "Exception sending TaskFragmentTransaction", e); return; Loading Loading @@ -1198,6 +1211,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } @VisibleForTesting @NonNull IApplicationThread getAppThread(int pid, int uid) { final WindowProcessController wpc = mAtmService.mProcessMap.getProcess(pid); final IApplicationThread appThread = wpc != null && wpc.mUid == uid ? wpc.getThread() : null; if (appThread == null) { throw new IllegalArgumentException("Cannot find process for pid=" + pid + " uid=" + uid); } return appThread; } /** * Trims the given Intent to only those that are needed to for embedding rules. This helps to * make it safer for cross-uid embedding even if we only send the Intent for trusted embedding. Loading services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +50 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; Loading Loading @@ -74,6 +75,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -86,6 +88,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.view.RemoteAnimationDefinition; import android.view.SurfaceControl; import android.window.IRemoteTransition; Loading @@ -104,7 +107,10 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; Loading @@ -123,7 +129,9 @@ import java.util.List; @Presubmit @RunWith(WindowTestRunner.class) public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private static final int TASK_ID = 10; @Rule public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); private TaskFragmentOrganizerController mController; private WindowOrganizerController mWindowOrganizerController; Loading @@ -143,6 +151,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private TaskFragmentInfo mTaskFragmentInfo; @Mock private Task mTask; @Mock private IApplicationThread mAppThread; @Captor private ArgumentCaptor<TaskFragmentTransaction> mTransactionCaptor; Loading Loading @@ -178,6 +188,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl(); doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken(); doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration(); doReturn(mAppThread).when(mController).getAppThread(anyInt(), anyInt()); doAnswer(invocation -> { final ITaskFragmentOrganizer organizer = (ITaskFragmentOrganizer) invocation.getArguments()[0]; final TaskFragmentTransaction taskFragmentTransaction = (TaskFragmentTransaction) invocation.getArguments()[1]; organizer.onTransactionReady(taskFragmentTransaction); return null; }).when(mAppThread).scheduleTaskFragmentTransaction(any(), any()); // To prevent it from calling the real server. doNothing().when(mOrganizer).applyTransaction(any(), anyInt(), anyBoolean()); Loading @@ -204,12 +223,40 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test public void testOnTaskFragmentAppeared() { public void testOnTaskFragmentAppeared_throughTaskFragmentOrganizer() throws RemoteException { mSetFlagsRule.disableFlags(Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); // No-op when the TaskFragment is not attached. mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTransactionReady(any()); verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); // Send callback when the TaskFragment is attached. setupMockParent(mTaskFragment, mTask); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); assertTaskFragmentParentInfoChangedTransaction(mTask); assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */); verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); } @Test public void testOnTaskFragmentAppeared_throughApplicationThread() throws RemoteException { mSetFlagsRule.enableFlags(Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); // Re-register the organizer in case the flag was disabled during setup. mController.unregisterOrganizer(mIOrganizer); mController.registerOrganizer(mIOrganizer); // No-op when the TaskFragment is not attached. mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTransactionReady(any()); verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); // Send callback when the TaskFragment is attached. setupMockParent(mTaskFragment, mTask); Loading @@ -217,6 +264,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mAppThread).scheduleTaskFragmentTransaction(eq(mIOrganizer), any()); assertTaskFragmentParentInfoChangedTransaction(mTask); assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */); } Loading services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +4 −1 Original line number Diff line number Diff line Loading @@ -40,11 +40,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.wm.testing.Assert.assertThrows; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; import static com.android.server.wm.testing.Assert.assertThrows; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -154,6 +154,9 @@ public class WindowOrganizerTests extends WindowTestsBase { @Before public void setUp() { mSystemServicesTestRule.addProcess("pkgName", "procName", WindowManagerService.MY_PID, WindowManagerService.MY_UID); // We defer callbacks since we need to adjust task surface visibility, but for these tests, // just run the callbacks synchronously mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run()); Loading Loading
core/java/android/app/ActivityThread.java +10 −0 Original line number Diff line number Diff line Loading @@ -208,9 +208,11 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.webkit.WebView; import android.window.ITaskFragmentOrganizer; import android.window.SizeConfigurationBuckets; import android.window.SplashScreen; import android.window.SplashScreenView; import android.window.TaskFragmentTransaction; import android.window.WindowContextInfo; import android.window.WindowProviderService; import android.window.WindowTokenClientController; Loading Loading @@ -2046,6 +2048,14 @@ public final class ActivityThread extends ClientTransactionHandler ActivityThread.this.scheduleTransaction(transaction); } @Override public void scheduleTaskFragmentTransaction(@NonNull ITaskFragmentOrganizer organizer, @NonNull TaskFragmentTransaction transaction) throws RemoteException { // TODO(b/260873529): ITaskFragmentOrganizer can be cleanup to be a IBinder token // after flag removal. organizer.onTransactionReady(transaction); } @Override public void requestDirectActions(@NonNull IBinder activityToken, @NonNull IVoiceInteractor interactor, @Nullable RemoteCallback cancellationCallback, Loading
core/java/android/app/IApplicationThread.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ import android.os.SharedMemory; import android.view.autofill.AutofillId; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentTransaction; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; Loading Loading @@ -157,6 +159,8 @@ oneway interface IApplicationThread { void scheduleApplicationInfoChanged(in ApplicationInfo ai); void setNetworkBlockSeq(long procStateSeq); void scheduleTransaction(in ClientTransaction transaction); void scheduleTaskFragmentTransaction(in ITaskFragmentOrganizer organizer, in TaskFragmentTransaction transaction); void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor, in RemoteCallback cancellationCallback, in RemoteCallback callback); void performDirectAction(IBinder activityToken, String actionId, Loading
services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +28 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.IApplicationThread; import android.content.Intent; import android.content.res.Configuration; import android.os.Binder; Loading Loading @@ -106,6 +107,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr */ private class TaskFragmentOrganizerState implements IBinder.DeathRecipient { private final ArrayList<TaskFragment> mOrganizedTaskFragments = new ArrayList<>(); private final IApplicationThread mAppThread; private final ITaskFragmentOrganizer mOrganizer; private final int mOrganizerPid; private final int mOrganizerUid; Loading Loading @@ -169,6 +171,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr TaskFragmentOrganizerState(@NonNull ITaskFragmentOrganizer organizer, int pid, int uid, boolean isSystemOrganizer) { if (Flags.bundleClientTransactionFlag()) { mAppThread = getAppThread(pid, uid); } else { mAppThread = null; } mOrganizer = organizer; mOrganizerPid = pid; mOrganizerUid = uid; Loading Loading @@ -407,7 +414,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return; } try { if (Flags.bundleClientTransactionFlag()) { // Dispatch through IApplicationThread to ensure the binder call is in order // with ClientTransaction. mAppThread.scheduleTaskFragmentTransaction(mOrganizer, transaction); } else { mOrganizer.onTransactionReady(transaction); } } catch (RemoteException e) { Slog.d(TAG, "Exception sending TaskFragmentTransaction", e); return; Loading Loading @@ -1198,6 +1211,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } @VisibleForTesting @NonNull IApplicationThread getAppThread(int pid, int uid) { final WindowProcessController wpc = mAtmService.mProcessMap.getProcess(pid); final IApplicationThread appThread = wpc != null && wpc.mUid == uid ? wpc.getThread() : null; if (appThread == null) { throw new IllegalArgumentException("Cannot find process for pid=" + pid + " uid=" + uid); } return appThread; } /** * Trims the given Intent to only those that are needed to for embedding rules. This helps to * make it safer for cross-uid embedding even if we only send the Intent for trusted embedding. Loading
services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +50 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; Loading Loading @@ -74,6 +75,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.app.IApplicationThread; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -86,6 +88,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.view.RemoteAnimationDefinition; import android.view.SurfaceControl; import android.window.IRemoteTransition; Loading @@ -104,7 +107,10 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; Loading @@ -123,7 +129,9 @@ import java.util.List; @Presubmit @RunWith(WindowTestRunner.class) public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private static final int TASK_ID = 10; @Rule public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); private TaskFragmentOrganizerController mController; private WindowOrganizerController mWindowOrganizerController; Loading @@ -143,6 +151,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { private TaskFragmentInfo mTaskFragmentInfo; @Mock private Task mTask; @Mock private IApplicationThread mAppThread; @Captor private ArgumentCaptor<TaskFragmentTransaction> mTransactionCaptor; Loading Loading @@ -178,6 +188,15 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { doReturn(new SurfaceControl()).when(mTaskFragment).getSurfaceControl(); doReturn(mFragmentToken).when(mTaskFragment).getFragmentToken(); doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration(); doReturn(mAppThread).when(mController).getAppThread(anyInt(), anyInt()); doAnswer(invocation -> { final ITaskFragmentOrganizer organizer = (ITaskFragmentOrganizer) invocation.getArguments()[0]; final TaskFragmentTransaction taskFragmentTransaction = (TaskFragmentTransaction) invocation.getArguments()[1]; organizer.onTransactionReady(taskFragmentTransaction); return null; }).when(mAppThread).scheduleTaskFragmentTransaction(any(), any()); // To prevent it from calling the real server. doNothing().when(mOrganizer).applyTransaction(any(), anyInt(), anyBoolean()); Loading @@ -204,12 +223,40 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { } @Test public void testOnTaskFragmentAppeared() { public void testOnTaskFragmentAppeared_throughTaskFragmentOrganizer() throws RemoteException { mSetFlagsRule.disableFlags(Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); // No-op when the TaskFragment is not attached. mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTransactionReady(any()); verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); // Send callback when the TaskFragment is attached. setupMockParent(mTaskFragment, mTask); mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); assertTaskFragmentParentInfoChangedTransaction(mTask); assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */); verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); } @Test public void testOnTaskFragmentAppeared_throughApplicationThread() throws RemoteException { mSetFlagsRule.enableFlags(Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); // Re-register the organizer in case the flag was disabled during setup. mController.unregisterOrganizer(mIOrganizer); mController.registerOrganizer(mIOrganizer); // No-op when the TaskFragment is not attached. mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mOrganizer, never()).onTransactionReady(any()); verify(mAppThread, never()).scheduleTaskFragmentTransaction(any(), any()); // Send callback when the TaskFragment is attached. setupMockParent(mTaskFragment, mTask); Loading @@ -217,6 +264,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment); mController.dispatchPendingEvents(); verify(mAppThread).scheduleTaskFragmentTransaction(eq(mIOrganizer), any()); assertTaskFragmentParentInfoChangedTransaction(mTask); assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */); } Loading
services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +4 −1 Original line number Diff line number Diff line Loading @@ -40,11 +40,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.wm.testing.Assert.assertThrows; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; import static com.android.server.wm.testing.Assert.assertThrows; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -154,6 +154,9 @@ public class WindowOrganizerTests extends WindowTestsBase { @Before public void setUp() { mSystemServicesTestRule.addProcess("pkgName", "procName", WindowManagerService.MY_PID, WindowManagerService.MY_UID); // We defer callbacks since we need to adjust task surface visibility, but for these tests, // just run the callbacks synchronously mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run()); Loading