Merge "fix issues with VoiceInteractionService start"
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7ea7cf1..faa98fa 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -191,6 +191,7 @@
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -243,6 +244,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AttributeCache;
+import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
@@ -425,6 +427,9 @@
     private static final long START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT =
             START_AS_CALLER_TOKEN_TIMEOUT_IMPL + 20 * MINUTE_IN_MILLIS;
 
+    // How long to whitelist the Services for when requested.
+    private static final int SERVICE_LAUNCH_IDLE_WHITELIST_DURATION_MS = 5 * 1000;
+
     // Activity tokens of system activities that are delegating their call to
     // #startActivityByCaller, keyed by the permissionToken granted to the delegate.
     final HashMap<IBinder, IBinder> mStartActivitySources = new HashMap<>();
@@ -2967,7 +2972,8 @@
             if (TextUtils.equals(pae.intent.getAction(),
                     android.service.voice.VoiceInteractionService.SERVICE_INTERFACE)) {
                 pae.intent.putExtras(pae.extras);
-                mContext.startServiceAsUser(pae.intent, new UserHandle(pae.userHandle));
+
+                startVoiceInteractionServiceAsUser(pae.intent, pae.userHandle, "AssistContext");
             } else {
                 pae.intent.replaceExtras(pae.extras);
                 pae.intent.setFlags(FLAG_ACTIVITY_NEW_TASK
@@ -2986,6 +2992,34 @@
         }
     }
 
+    /**
+     * Workaround for historical API which starts the Assist service with a non-foreground
+     * {@code startService()} call.
+     */
+    private void startVoiceInteractionServiceAsUser(
+            Intent intent, int userHandle, String reason) {
+        // Resolve the intent to find out which package we need to whitelist.
+        ResolveInfo resolveInfo =
+                mContext.getPackageManager().resolveServiceAsUser(intent, 0, userHandle);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            Slog.e(TAG, "VoiceInteractionService intent does not resolve. Not starting.");
+            return;
+        }
+        intent.setPackage(resolveInfo.serviceInfo.packageName);
+
+        // Whitelist background services temporarily.
+        LocalServices.getService(DeviceIdleController.LocalService.class)
+                .addPowerSaveTempWhitelistApp(Process.myUid(), intent.getPackage(),
+                        SERVICE_LAUNCH_IDLE_WHITELIST_DURATION_MS, userHandle, false, reason);
+
+        // Finally, try to start the service.
+        try {
+            mContext.startServiceAsUser(intent, UserHandle.of(userHandle));
+        } catch (RuntimeException e) {
+            Slog.e(TAG, "VoiceInteractionService failed to start.", e);
+        }
+    }
+
     @Override
     public int addAppTask(IBinder activityToken, Intent intent,
             ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException {