Merge "Fix potential crash when TaskFragmentOrganizer died" into tm-qpr-dev am: 66dbafa0a1
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20505176 Change-Id: I6445f15e726d10802333e4a380e1cc5b9c93c4eb Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -425,7 +425,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
|
||||||
"Register task fragment organizer=%s uid=%d pid=%d",
|
"Register task fragment organizer=%s uid=%d pid=%d",
|
||||||
organizer.asBinder(), uid, pid);
|
organizer.asBinder(), uid, pid);
|
||||||
if (mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) {
|
if (isOrganizerRegistered(organizer)) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Replacing existing organizer currently unsupported");
|
"Replacing existing organizer currently unsupported");
|
||||||
}
|
}
|
||||||
@@ -502,19 +502,27 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||||
// Keep the calling identity to avoid unsecure change.
|
// Keep the calling identity to avoid unsecure change.
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
|
if (isValidTransaction(wct)) {
|
||||||
applyTransaction(wct, transitionType, shouldApplyIndependently);
|
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);
|
state.onTransactionFinished(transactionToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyTransaction(@NonNull WindowContainerTransaction wct,
|
public void applyTransaction(@NonNull WindowContainerTransaction wct,
|
||||||
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
@WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
|
||||||
// Keep the calling identity to avoid unsecure change.
|
// Keep the calling identity to avoid unsecure change.
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
if (wct.isEmpty()) {
|
if (!isValidTransaction(wct)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType,
|
mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType,
|
||||||
@@ -655,7 +663,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
}
|
}
|
||||||
organizer = organizedTf[0].getTaskFragmentOrganizer();
|
organizer = organizedTf[0].getTaskFragmentOrganizer();
|
||||||
}
|
}
|
||||||
if (!mTaskFragmentOrganizerState.containsKey(organizer.asBinder())) {
|
if (!isOrganizerRegistered(organizer)) {
|
||||||
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
|
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -701,7 +709,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).remove(event);
|
mPendingTaskFragmentEvents.get(event.mTaskFragmentOrg.asBinder()).remove(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) {
|
private boolean isOrganizerRegistered(@NonNull ITaskFragmentOrganizer organizer) {
|
||||||
return mTaskFragmentOrganizerState.containsKey(organizer.asBinder());
|
return mTaskFragmentOrganizerState.containsKey(organizer.asBinder());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,6 +746,20 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
|||||||
return state;
|
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
|
* A class to store {@link ITaskFragmentOrganizer} and its organized
|
||||||
* {@link TaskFragment TaskFragments} with different pending event request.
|
* {@link TaskFragment TaskFragments} with different pending event request.
|
||||||
|
|||||||
@@ -403,9 +403,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
*/
|
*/
|
||||||
void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct,
|
void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct,
|
||||||
@WindowManager.TransitionType int type, boolean shouldApplyIndependently) {
|
@WindowManager.TransitionType int type, boolean shouldApplyIndependently) {
|
||||||
if (!isValidTransaction(wct)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()",
|
enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()",
|
||||||
Objects.requireNonNull(wct.getTaskFragmentOrganizer()),
|
Objects.requireNonNull(wct.getTaskFragmentOrganizer()),
|
||||||
Objects.requireNonNull(wct));
|
Objects.requireNonNull(wct));
|
||||||
@@ -459,7 +456,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
// calls startSyncSet.
|
// calls startSyncSet.
|
||||||
() -> mTransitionController.moveToCollecting(nextTransition),
|
() -> mTransitionController.moveToCollecting(nextTransition),
|
||||||
() -> {
|
() -> {
|
||||||
if (isValidTransaction(wct)) {
|
if (mTaskFragmentOrganizerController.isValidTransaction(wct)) {
|
||||||
applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
|
applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
|
||||||
mTransitionController.requestStartTransition(nextTransition,
|
mTransitionController.requestStartTransition(nextTransition,
|
||||||
null /* startTask */, null /* remoteTransition */,
|
null /* startTask */, null /* remoteTransition */,
|
||||||
@@ -1620,18 +1617,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
return (cfgChanges & CONTROLLABLE_CONFIGS) == 0;
|
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
|
* Makes sure that the transaction only contains operations that are allowed for the
|
||||||
* {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
|
* {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
|
||||||
|
|||||||
@@ -821,6 +821,21 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
|
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
|
@Test
|
||||||
public void testOrganizerRemovedWithPendingEvents() {
|
public void testOrganizerRemovedWithPendingEvents() {
|
||||||
final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
|
final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
|
||||||
|
|||||||
Reference in New Issue
Block a user