Introduce security checks to startDreamActivity

This CL checks that the caller is the dream package and that the
device is dreaming when the activity is started.

isDream was instroduced in order to exempt the DreamActivity from
background start check. setAllowBackgroundActivityStart does that
more cleanly.

Bug: 152281628

Test: m && flashall && verify dream works

Change-Id: Id6161f923f3350d482b3452a78a792a541dcf1a1
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e83ac7b..a75420e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -212,7 +212,6 @@
 import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.service.dreams.DreamActivity;
-import android.service.dreams.DreamManagerInternal;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.sysprop.DisplayProperties;
@@ -1245,36 +1244,29 @@
         }
     }
 
-    @Override
-    public boolean startDreamActivity(Intent intent) {
-        final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
+    private void enforceCallerIsDream(String callerPackageName) {
         final long origId = Binder.clearCallingIdentity();
-
-        // The dream activity is only called for non-doze dreams.
-        final ComponentName currentDream = LocalServices.getService(DreamManagerInternal.class)
-                .getActiveDreamComponent(/* doze= */ false);
-
-        if (currentDream == null || currentDream.getPackageName() == null
-                || !currentDream.getPackageName().equals(process.mInfo.packageName)) {
-            Slog.e(TAG, "Calling package is not the current dream package. "
-                    + "Aborting startDreamActivity...");
-            return false;
+        try {
+            if (!ActivityRecord.canLaunchDreamActivity(callerPackageName)) {
+                throw new SecurityException("The dream activity can be started only when the device"
+                        + " is dreaming and only by the active dream package.");
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
+    }
+
+    @Override
+    public boolean startDreamActivity(@NonNull Intent intent) {
+        assertPackageMatchesCallingUid(intent.getPackage());
+        enforceCallerIsDream(intent.getPackage());
 
         final ActivityInfo a = new ActivityInfo();
         a.theme = com.android.internal.R.style.Theme_Dream;
         a.exported = true;
         a.name = DreamActivity.class.getName();
-
-
-        a.packageName = process.mInfo.packageName;
-        a.applicationInfo = process.mInfo;
-        a.processName = process.mInfo.processName;
-        a.uiOptions = process.mInfo.uiOptions;
-        a.taskAffinity = "android:" + a.packageName + "/dream";
         a.enabled = true;
         a.launchMode = ActivityInfo.LAUNCH_SINGLE_INSTANCE;
-
         a.persistableMode = ActivityInfo.PERSIST_NEVER;
         a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
         a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
@@ -1283,15 +1275,34 @@
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
 
-        try {
-            getActivityStartController().obtainStarter(intent, "dream")
-                    .setActivityInfo(a)
-                    .setActivityOptions(options.toBundle())
-                    .setIsDream(true)
-                    .execute();
-            return true;
-        } finally {
-            Binder.restoreCallingIdentity(origId);
+        synchronized (mGlobalLock) {
+            final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
+
+            a.packageName = process.mInfo.packageName;
+            a.applicationInfo = process.mInfo;
+            a.processName = process.mInfo.processName;
+            a.uiOptions = process.mInfo.uiOptions;
+            a.taskAffinity = "android:" + a.packageName + "/dream";
+
+            final int callingUid = Binder.getCallingUid();
+            final int callingPid = Binder.getCallingPid();
+
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                getActivityStartController().obtainStarter(intent, "dream")
+                        .setCallingUid(callingUid)
+                        .setCallingPid(callingPid)
+                        .setActivityInfo(a)
+                        .setActivityOptions(options.toBundle())
+                        // To start the dream from background, we need to start it from a persistent
+                        // system process. Here we set the real calling uid to the system server uid
+                        .setRealCallingUid(Binder.getCallingUid())
+                        .setAllowBackgroundActivityStart(true)
+                        .execute();
+                return true;
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
         }
     }
 
@@ -2478,7 +2489,7 @@
         final ActivityStarter starter = getActivityStartController().obtainStarter(
                 null /* intent */, "moveTaskToFront");
         if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
-                -1, callerApp, null, false, false, null)) {
+                -1, callerApp, null, false, null)) {
             if (!isBackgroundActivityStartsEnabled()) {
                 return;
             }