Add verification for setting ACTIVITY_TYPE_DREAM
Bug: 152281628
Test: m && flash && check that dream starts normally
Change-Id: Ie0d8849aeb0c2de46a0e36bb0f9958091e0d28f4
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 41fdd0b..7bf5c38 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -49,6 +49,12 @@
* Called by the ActivityTaskManagerService to verify that the startDreamActivity
* request comes from the current active dream component.
*
+ * This function and its call path should not acquire the DreamManagerService lock
+ * to avoid deadlock with the ActivityTaskManager lock.
+ *
+ * TODO: Make this interaction push-based - the DreamManager should inform the
+ * ActivityTaskManager whenever the active dream component changes.
+ *
* @param doze If true returns the current active doze component. Otherwise, returns the
* active dream component.
*/
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index eb0257e..bcf262d 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -51,6 +51,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -75,6 +76,7 @@
private final PowerManager mPowerManager;
private final PowerManagerInternal mPowerManagerInternal;
private final PowerManager.WakeLock mDozeWakeLock;
+ private final ActivityTaskManagerInternal mAtmInternal;
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
@@ -97,6 +99,7 @@
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
+ mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
mDozeConfig = new AmbientDisplayConfiguration(mContext);
}
@@ -383,8 +386,10 @@
PowerManager.WakeLock wakeLock = mPowerManager
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
- mHandler.post(wakeLock.wrap(
- () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
+ mHandler.post(wakeLock.wrap(() -> {
+ mAtmInternal.notifyDreamStateChanged(true);
+ mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock);
+ }));
}
private void stopDreamLocked(final boolean immediate) {
@@ -422,6 +427,7 @@
}
mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ mAtmInternal.notifyDreamStateChanged(false);
}
private void checkPermission(String permission) {
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() {