From 8edc50d8bf69e184327514510e797f6cd9ab5548 Mon Sep 17 00:00:00 2001 From: Joanne Chung Date: Fri, 8 Apr 2022 19:39:28 +0800 Subject: [PATCH] Fix Assistant breaks after stopping the app. Android 13 introduces a feature that allows users to kill foreground services that will break the home screen mic function. The root cause is because we don't handle the binding die case. Ideally we should migrate the force stop, package update cases to onBindingDied but we would like to minimize the risk before release. From the fgs task manager description, we can check new REASON_USER_REQUESTED reason on ApplicationExitInfo, we only handle this case to rebind the service to minimize the scope. Bug: 225166047 Test: atest CtsVoiceInteractionTestCases Test: manual. The function still works after adb shell cmd activity stop-app com.google.android.googlequicksearchbox Change-Id: Ia8395fc6f7b6df36b158f0578d57d948748a43b3 --- .../VoiceInteractionManagerService.java | 17 +++++++++++ .../VoiceInteractionManagerServiceImpl.java | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 8cbbe947d32d7..9f6a609102600 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -323,6 +323,16 @@ public class VoiceInteractionManagerService extends SystemService { new RoleObserver(mContext.getMainExecutor()); } + void handleUserStop(String packageName, int userHandle) { + synchronized (VoiceInteractionManagerServiceStub.this) { + ComponentName curInteractor = getCurInteractor(userHandle); + if (curInteractor != null && packageName.equals(curInteractor.getPackageName())) { + Slog.d(TAG, "switchImplementation for user stop."); + switchImplementationIfNeededLocked(true); + } + } + } + @Override public @NonNull IVoiceInteractionSoundTriggerSession createSoundTriggerSessionAsOriginator( @NonNull Identity originatorIdentity, IBinder client) { @@ -2045,6 +2055,7 @@ public class VoiceInteractionManagerService extends SystemService { } PackageMonitor mPackageMonitor = new PackageMonitor() { + @Override public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit); @@ -2077,11 +2088,17 @@ public class VoiceInteractionManagerService extends SystemService { } setCurInteractor(null, userHandle); + // TODO: should not reset null here. But even remove this line, the + // initForUser() still reset it because the interactor will be null. Keep + // it now but we should still need to fix it. setCurRecognizer(null, userHandle); resetCurAssistant(userHandle); initForUser(userHandle); switchImplementationIfNeededLocked(true); + // When resetting the interactor, the recognizer and the assistant settings + // value, we also need to reset the assistant role to keep the values + // consistent. Clear the assistant role will reset to the default value. Context context = getContext(); context.getSystemService(RoleManager.class).clearRoleHoldersAsUser( RoleManager.ROLE_ASSISTANT, 0, UserHandle.of(userHandle), diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index edf1002221ba9..055864834b3bd 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -29,6 +29,7 @@ import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.AppGlobals; +import android.app.ApplicationExitInfo; import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.content.BroadcastReceiver; @@ -38,6 +39,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.ServiceInfo; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; @@ -149,6 +151,32 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne resetHotwordDetectionConnectionLocked(); } } + + @Override + public void onBindingDied(ComponentName name) { + Slog.d(TAG, "onBindingDied to " + name); + String packageName = name.getPackageName(); + ParceledListSlice plistSlice = null; + try { + plistSlice = mAm.getHistoricalProcessExitReasons(packageName, 0, 1, mUser); + } catch (RemoteException e) { + // do nothing. The local binder so it can not throw it. + } + if (plistSlice == null) { + return; + } + List list = plistSlice.getList(); + if (list.isEmpty()) { + return; + } + // TODO(b/229956310): Refactor the logic of PackageMonitor and onBindingDied + ApplicationExitInfo info = list.get(0); + if (info.getReason() == ApplicationExitInfo.REASON_USER_REQUESTED + && info.getSubReason() == ApplicationExitInfo.SUBREASON_STOP_APP) { + // only handle user stopped the application from the task manager + mServiceStub.handleUserStop(packageName, mUser); + } + } }; VoiceInteractionManagerServiceImpl(Context context, Handler handler,