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
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 8cbbe94..9f6a609 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 @@
             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 @@
         }
 
         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 @@
                         }
 
                         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 edf1002..0558648 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.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.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 @@
                 resetHotwordDetectionConnectionLocked();
             }
         }
+
+        @Override
+        public void onBindingDied(ComponentName name) {
+            Slog.d(TAG, "onBindingDied to " + name);
+            String packageName = name.getPackageName();
+            ParceledListSlice<ApplicationExitInfo> 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<ApplicationExitInfo> 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,