Loading services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +30 −8 Original line number Diff line number Diff line Loading @@ -425,7 +425,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { if (isOrganizerRegistered(organizer)) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } Loading Loading @@ -502,19 +502,27 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { // Keep the calling identity to avoid unsecure change. synchronized (mGlobalLock) { if (isValidTransaction(wct)) { applyTransaction(wct, transitionType, shouldApplyIndependently); final TaskFragmentOrganizerState state = validateAndGetState( wct.getTaskFragmentOrganizer()); } // Even if the transaction is empty, we still need to invoke #onTransactionFinished // unless the organizer has been unregistered. final ITaskFragmentOrganizer organizer = wct.getTaskFragmentOrganizer(); final TaskFragmentOrganizerState state = organizer != null ? mTaskFragmentOrganizerState.get(organizer.asBinder()) : null; if (state != null) { state.onTransactionFinished(transactionToken); } } } @Override public void applyTransaction(@NonNull WindowContainerTransaction wct, @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { // Keep the calling identity to avoid unsecure change. synchronized (mGlobalLock) { if (wct.isEmpty()) { if (!isValidTransaction(wct)) { return; } mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType, Loading Loading @@ -655,7 +663,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } organizer = organizedTf[0].getTaskFragmentOrganizer(); } if (!mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { if (!isOrganizerRegistered(organizer)) { Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists"); return; } Loading Loading @@ -701,7 +709,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).remove(event); } boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) { private boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) { return mTaskFragmentOrganizerState.containsKey(organizer.asBinder()); } Loading Loading @@ -738,6 +746,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return state; } boolean isValidTransaction(@NonNull WindowContainerTransaction t) { if (t.isEmpty()) { return false; } final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer(); if (t.getTaskFragmentOrganizer() == null || !isOrganizerRegistered(organizer)) { // Transaction from an unregistered organizer should not be applied. This can happen // when the organizer process died before the transaction is applied. Slog.e(TAG, "Caller organizer=" + organizer + " is no longer registered"); return false; } return true; } /** * A class to store {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments} with different pending event request. Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +1 −16 Original line number Diff line number Diff line Loading @@ -403,9 +403,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub */ void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct, @WindowManager.TransitionType int type, boolean shouldApplyIndependently) { if (!isValidTransaction(wct)) { return; } enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()", Objects.requireNonNull(wct.getTaskFragmentOrganizer()), Objects.requireNonNull(wct)); Loading Loading @@ -459,7 +456,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // calls startSyncSet. () -> mTransitionController.moveToCollecting(nextTransition), () -> { if (isValidTransaction(wct)) { if (mTaskFragmentOrganizerController.isValidTransaction(wct)) { applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); mTransitionController.requestStartTransition(nextTransition, null /* startTask */, null /* remoteTransition */, Loading Loading @@ -1620,18 +1617,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return (cfgChanges & CONTROLLABLE_CONFIGS) == 0; } private boolean isValidTransaction(@NonNull WindowContainerTransaction t) { if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController .isOrganizerRegistered(t.getTaskFragmentOrganizer())) { // Transaction from an unregistered organizer should not be applied. This can happen // when the organizer process died before the transaction is applied. Slog.e(TAG, "Caller organizer=" + t.getTaskFragmentOrganizer() + " is no longer registered"); return false; } return true; } /** * Makes sure that the transaction only contains operations that are allowed for the * {@link WindowContainerTransaction#getTaskFragmentOrganizer()}. Loading services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +15 −0 Original line number Diff line number Diff line Loading @@ -821,6 +821,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); } @Test public void testOnTransactionHandled_skipTransactionForUnregisterOrganizer() { mController.unregisterOrganizer(mIOrganizer); final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent); final IBinder fragmentToken = new Binder(); // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment. createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken); mController.onTransactionHandled(new Binder(), mTransaction, getTransitionType(mTransaction), false /* shouldApplyIndependently */); // Nothing should happen as the organizer is not registered. assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); } @Test public void testOrganizerRemovedWithPendingEvents() { final TaskFragment tf0 = new TaskFragmentBuilder(mAtm) Loading Loading
services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +30 −8 Original line number Diff line number Diff line Loading @@ -425,7 +425,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task fragment organizer=%s uid=%d pid=%d", organizer.asBinder(), uid, pid); if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { if (isOrganizerRegistered(organizer)) { throw new IllegalStateException( "Replacing existing organizer currently unsupported"); } Loading Loading @@ -502,19 +502,27 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { // Keep the calling identity to avoid unsecure change. synchronized (mGlobalLock) { if (isValidTransaction(wct)) { applyTransaction(wct, transitionType, shouldApplyIndependently); final TaskFragmentOrganizerState state = validateAndGetState( wct.getTaskFragmentOrganizer()); } // Even if the transaction is empty, we still need to invoke #onTransactionFinished // unless the organizer has been unregistered. final ITaskFragmentOrganizer organizer = wct.getTaskFragmentOrganizer(); final TaskFragmentOrganizerState state = organizer != null ? mTaskFragmentOrganizerState.get(organizer.asBinder()) : null; if (state != null) { state.onTransactionFinished(transactionToken); } } } @Override public void applyTransaction(@NonNull WindowContainerTransaction wct, @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) { // Keep the calling identity to avoid unsecure change. synchronized (mGlobalLock) { if (wct.isEmpty()) { if (!isValidTransaction(wct)) { return; } mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType, Loading Loading @@ -655,7 +663,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } organizer = organizedTf[0].getTaskFragmentOrganizer(); } if (!mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) { if (!isOrganizerRegistered(organizer)) { Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists"); return; } Loading Loading @@ -701,7 +709,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).remove(event); } boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) { private boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) { return mTaskFragmentOrganizerState.containsKey(organizer.asBinder()); } Loading Loading @@ -738,6 +746,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return state; } boolean isValidTransaction(@NonNull WindowContainerTransaction t) { if (t.isEmpty()) { return false; } final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer(); if (t.getTaskFragmentOrganizer() == null || !isOrganizerRegistered(organizer)) { // Transaction from an unregistered organizer should not be applied. This can happen // when the organizer process died before the transaction is applied. Slog.e(TAG, "Caller organizer=" + organizer + " is no longer registered"); return false; } return true; } /** * A class to store {@link ITaskFragmentOrganizer} and its organized * {@link TaskFragment TaskFragments} with different pending event request. Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +1 −16 Original line number Diff line number Diff line Loading @@ -403,9 +403,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub */ void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct, @WindowManager.TransitionType int type, boolean shouldApplyIndependently) { if (!isValidTransaction(wct)) { return; } enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()", Objects.requireNonNull(wct.getTaskFragmentOrganizer()), Objects.requireNonNull(wct)); Loading Loading @@ -459,7 +456,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // calls startSyncSet. () -> mTransitionController.moveToCollecting(nextTransition), () -> { if (isValidTransaction(wct)) { if (mTaskFragmentOrganizerController.isValidTransaction(wct)) { applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); mTransitionController.requestStartTransition(nextTransition, null /* startTask */, null /* remoteTransition */, Loading Loading @@ -1620,18 +1617,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return (cfgChanges & CONTROLLABLE_CONFIGS) == 0; } private boolean isValidTransaction(@NonNull WindowContainerTransaction t) { if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController .isOrganizerRegistered(t.getTaskFragmentOrganizer())) { // Transaction from an unregistered organizer should not be applied. This can happen // when the organizer process died before the transaction is applied. Slog.e(TAG, "Caller organizer=" + t.getTaskFragmentOrganizer() + " is no longer registered"); return false; } return true; } /** * Makes sure that the transaction only contains operations that are allowed for the * {@link WindowContainerTransaction#getTaskFragmentOrganizer()}. Loading
services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +15 −0 Original line number Diff line number Diff line Loading @@ -821,6 +821,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); } @Test public void testOnTransactionHandled_skipTransactionForUnregisterOrganizer() { mController.unregisterOrganizer(mIOrganizer); final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent); final IBinder fragmentToken = new Binder(); // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment. createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken); mController.onTransactionHandled(new Binder(), mTransaction, getTransitionType(mTransaction), false /* shouldApplyIndependently */); // Nothing should happen as the organizer is not registered. assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); } @Test public void testOrganizerRemovedWithPendingEvents() { final TaskFragment tf0 = new TaskFragmentBuilder(mAtm) Loading