Add verification for setting ACTIVITY_TYPE_DREAM

Bug: 152281628

Test: m && flash && check that dream starts normally
Change-Id: Ie0d8849aeb0c2de46a0e36bb0f9958091e0d28f4
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 78d6e27..a037751 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -36,6 +36,7 @@
 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
 import static android.app.WaitResult.INVALID_DELAY;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -269,6 +270,8 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.service.dreams.DreamActivity;
+import android.service.dreams.DreamManagerInternal;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -2035,6 +2038,26 @@
         return false;
     }
 
+    static boolean canLaunchDreamActivity(String packageName) {
+        final DreamManagerInternal dreamManager =
+                LocalServices.getService(DreamManagerInternal.class);
+
+        // Verify that the package is the current active dream. The getActiveDreamComponent()
+        // call path does not acquire the DreamManager lock and thus is safe to use.
+        final ComponentName activeDream = dreamManager.getActiveDreamComponent(false /* doze */);
+        if (activeDream == null || activeDream.getPackageName() == null
+                || !activeDream.getPackageName().equals(packageName)) {
+            return false;
+        }
+
+        // Verify that the device is dreaming.
+        if (!LocalServices.getService(ActivityTaskManagerInternal.class).isDreaming()) {
+            return false;
+        }
+
+        return true;
+    }
+
     private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
             ActivityOptions options, ActivityRecord sourceRecord) {
         int activityType = ACTIVITY_TYPE_UNDEFINED;
@@ -2054,6 +2077,10 @@
         } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
                 && canLaunchAssistActivity(launchedFromPackage)) {
             activityType = ACTIVITY_TYPE_ASSISTANT;
+        } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_DREAM
+                && canLaunchDreamActivity(launchedFromPackage)
+                && DreamActivity.class.getName() == info.name) {
+            activityType = ACTIVITY_TYPE_DREAM;
         }
         setActivityType(activityType);
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 2263795..d48df9f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -290,6 +290,11 @@
     public abstract void notifyActiveVoiceInteractionServiceChanged(ComponentName component);
 
     /**
+     * Called when the device changes its dreaming state.
+     */
+    public abstract void notifyDreamStateChanged(boolean dreaming);
+
+    /**
      * Set a uid that is allowed to bypass stopped app switches, launching an app
      * whenever it wants.
      *
@@ -318,6 +323,7 @@
     public abstract void clearHeavyWeightProcessIfEquals(WindowProcessController proc);
     public abstract void finishHeavyWeightApp();
 
+    public abstract boolean isDreaming();
     public abstract boolean isSleeping();
     public abstract boolean isShuttingDown();
     public abstract boolean shuttingDown(boolean booted, int timeout);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 6921816..e83ac7b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -599,6 +599,13 @@
     private boolean mSleeping = false;
 
     /**
+     * The mDreaming state is set by the {@link DreamManagerService} when it receives a request to
+     * start/stop the dream. It is set to true shortly  before the {@link DreamService} is started.
+     * It is set to false after the {@link DreamService} is stopped.
+     */
+    private boolean mDreaming = false;
+
+    /**
      * The process state used for processes that are running the top activities.
      * This changes between TOP and TOP_SLEEPING to following mSleeping.
      */
@@ -6331,6 +6338,13 @@
         }
 
         @Override
+        public void notifyDreamStateChanged(boolean dreaming) {
+            synchronized (mGlobalLock) {
+                mDreaming = dreaming;
+            }
+        }
+
+        @Override
         public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
             if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
                 return;
@@ -6432,6 +6446,13 @@
             }
         }
 
+        @Override
+        public boolean isDreaming() {
+            synchronized (mGlobalLock) {
+                return mDreaming;
+            }
+        }
+
         @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public boolean isSleeping() {