From b9fe1923d9622d5deaef1ed62685d1ece797ae7a Mon Sep 17 00:00:00 2001 From: Joanne Chung Date: Thu, 10 Mar 2022 16:28:06 +0800 Subject: [PATCH] Fix finishTranslation doesn't work if start Activity in the same task If the app starts a new Activity in the same task then the finishTranslation() is called, the finish translation doesn't work because our logic is to check if task top Activity is our expected translation Activity. In this case, the top Activity is the new Activity, the original Activity is paused in the same task. To fix the problem, we get all non-finishing Activities in the task and check if the target Activity in this task. Bug: 202570916 Test: atest UiTranslationManagerTest Test: atest CtsVoiceInteractionTestCases Test: atest CtsAssistTestCases Change-Id: I2471e04b894890777e13dd45c290f059dbe5f487 --- .../wm/ActivityTaskManagerInternal.java | 11 ++++-- .../server/wm/ActivityTaskManagerService.java | 36 ++++++++++++------- .../TranslationManagerServiceImpl.java | 25 +++++++------ .../VoiceInteractionManagerServiceImpl.java | 8 ++--- 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 01dfb91d12be6..9bf69bcc2eaab 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -387,11 +387,16 @@ public abstract class ActivityTaskManagerInternal { public abstract ComponentName getActivityName(IBinder activityToken); /** - * @return the activity token and IApplicationThread for the top activity in the task or null - * if there isn't a top activity with a valid process. + * Returns non-finishing Activity that have a process attached for the given task and the token + * with the activity token and the IApplicationThread or null if there is no Activity with a + * valid process. Given the null token for the task will return the top Activity in the task. + * + * @param taskId the Activity task id. + * @param token the Activity token, set null if get top Activity for the given task id. */ @Nullable - public abstract ActivityTokens getTopActivityForTask(int taskId); + public abstract ActivityTokens getAttachedNonFinishingActivityForTask(int taskId, + IBinder token); public abstract IIntentSender getIntentSender(int type, String packageName, @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 14436bc4ed669..1f7c0efa572ee 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2944,7 +2944,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final long callingId = Binder.clearCallingIdentity(); LocalService.ActivityTokens tokens = null; try { - tokens = mInternal.getTopActivityForTask(taskId); + tokens = mInternal.getAttachedNonFinishingActivityForTask(taskId, null); } finally { Binder.restoreCallingIdentity(callingId); } @@ -5804,7 +5804,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public ActivityTokens getTopActivityForTask(int taskId) { + public ActivityTokens getAttachedNonFinishingActivityForTask(int taskId, + IBinder token) { synchronized (mGlobalLock) { final Task task = mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_ONLY); @@ -5813,19 +5814,30 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { + " Requested task not found"); return null; } - final ActivityRecord activity = task.getTopNonFinishingActivity(); - if (activity == null) { - Slog.w(TAG, "getApplicationThreadForTopActivity failed:" - + " Requested activity not found"); + final List list = new ArrayList<>(); + task.forAllActivities(r -> { + if (!r.finishing) { + list.add(r); + } + }); + if (list.size() <= 0) { return null; } - if (!activity.attachedToProcess()) { - Slog.w(TAG, "getApplicationThreadForTopActivity failed: No process for " - + activity); - return null; + // pass null, get top Activity + if (token == null && list.get(0).attachedToProcess()) { + ActivityRecord topRecord = list.get(0); + return new ActivityTokens(topRecord.token, topRecord.assistToken, + topRecord.app.getThread(), topRecord.shareableActivityToken); } - return new ActivityTokens(activity.token, activity.assistToken, - activity.app.getThread(), activity.shareableActivityToken); + // find the expected Activity + for (int i = 0; i < list.size(); i++) { + ActivityRecord record = list.get(i); + if (record.shareableActivityToken == token && record.attachedToProcess()) { + return new ActivityTokens(record.token, record.assistToken, + record.app.getThread(), record.shareableActivityToken); + } + } + return null; } } diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java index d3a589668808e..97d5215213a9a 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -232,23 +232,26 @@ final class TranslationManagerServiceImpl extends public void updateUiTranslationStateLocked(@UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, List viewIds, IBinder token, int taskId, UiTranslationSpec uiTranslationSpec) { - // Get top activity for a given task id - final ActivityTokens taskTopActivityTokens = - mActivityTaskManagerInternal.getTopActivityForTask(taskId); - if (taskTopActivityTokens == null - || taskTopActivityTokens.getShareableActivityToken() != token) { - Slog.w(TAG, "Unknown activity or it was finished to query for update translation " - + "state for token=" + token + " taskId=" + taskId + " for state= " + state); + // If the app starts a new Activity in the same task then the finish or pause API + // is called, the operation doesn't work if we only check task top Activity. The top + // Activity is the new Activity, the original Activity is paused in the same task. + // To make sure the operation still work, we use the token to find the target Activity in + // this task, not the top Activity only. + ActivityTokens candidateActivityTokens = + mActivityTaskManagerInternal.getAttachedNonFinishingActivityForTask(taskId, token); + if (candidateActivityTokens == null) { + Slog.w(TAG, "Unknown activity or it was finished to query for update " + + "translation state for token=" + token + " taskId=" + taskId + " for " + + "state= " + state); return; } - mLastActivityTokens = new WeakReference<>(taskTopActivityTokens); + mLastActivityTokens = new WeakReference<>(candidateActivityTokens); if (state == STATE_UI_TRANSLATION_FINISHED) { mWaitingFinishedCallbackActivities.add(token); } - - IBinder activityToken = taskTopActivityTokens.getActivityToken(); + IBinder activityToken = candidateActivityTokens.getActivityToken(); try { - taskTopActivityTokens.getApplicationThread().updateUiTranslationState( + candidateActivityTokens.getApplicationThread().updateUiTranslationState( activityToken, state, sourceSpec, targetSpec, viewIds, uiTranslationSpec); } catch (RemoteException e) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 0519873810b54..edf1002221ba9 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -311,8 +311,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne callback.sendResult(null); return; } - final ActivityTokens tokens = LocalServices.getService( - ActivityTaskManagerInternal.class).getTopActivityForTask(taskId); + final ActivityTokens tokens = LocalServices.getService(ActivityTaskManagerInternal.class) + .getAttachedNonFinishingActivityForTask(taskId, null); if (tokens == null || tokens.getAssistToken() != assistToken) { Slog.w(TAG, "Unknown activity to query for direct actions"); callback.sendResult(null); @@ -336,8 +336,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne resultCallback.sendResult(null); return; } - final ActivityTokens tokens = LocalServices.getService( - ActivityTaskManagerInternal.class).getTopActivityForTask(taskId); + final ActivityTokens tokens = LocalServices.getService(ActivityTaskManagerInternal.class) + .getAttachedNonFinishingActivityForTask(taskId, null); if (tokens == null || tokens.getAssistToken() != assistToken) { Slog.w(TAG, "Unknown activity to perform a direct action"); resultCallback.sendResult(null);