Merge "Do not kill dream process when stopping dream" into udc-qpr-dev

This commit is contained in:
Galia Peycheva
2023-06-29 13:57:53 +00:00
committed by Android (Google) Code Review
7 changed files with 129 additions and 53 deletions

View File

@@ -24,7 +24,6 @@ import android.app.GrantedUriPermission;
import android.app.IApplicationThread;
import android.app.IActivityClientController;
import android.app.IActivityController;
import android.app.IAppTask;
import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
@@ -107,14 +106,6 @@ interface IActivityTaskManager {
in ProfilerInfo profilerInfo, in Bundle options, int userId);
boolean startNextMatchingActivity(in IBinder callingActivity,
in Intent intent, in Bundle options);
/**
* The DreamActivity has to be started in a special way that does not involve the PackageParser.
* The DreamActivity is a framework component inserted in the dream application process. Hence,
* it is not declared in the application's manifest and cannot be parsed. startDreamActivity
* creates the activity and starts it without reaching out to the PackageParser.
*/
boolean startDreamActivity(in Intent intent);
int startActivityIntentSender(in IApplicationThread caller,
in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent,
in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,

View File

@@ -26,7 +26,6 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
@@ -1268,9 +1267,7 @@ public class DreamService extends Service implements Window.Callback {
fetchDreamLabel(this, serviceInfo, isPreviewMode));
try {
if (!ActivityTaskManager.getService().startDreamActivity(i)) {
detach();
}
mDreamManager.startDreamActivity(i);
} catch (SecurityException e) {
Log.w(mTag,
"Received SecurityException trying to start DreamActivity. "

View File

@@ -17,6 +17,7 @@
package android.service.dreams;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.IBinder;
@@ -45,4 +46,5 @@ interface IDreamManager {
void setDreamComponentsForUser(int userId, in ComponentName[] componentNames);
void setSystemDreamComponent(in ComponentName componentName);
void registerDreamOverlayService(in ComponentName componentName);
void startDreamActivity(in Intent intent);
}

View File

@@ -16,11 +16,11 @@
package com.android.server.dreams;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import android.app.ActivityTaskManager;
import android.app.BroadcastOptions;
import android.app.IAppTask;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -213,6 +213,27 @@ final class DreamController {
}
}
/**
* Provides an appTask for the dream with token {@code dreamToken}, so that the dream controller
* can stop the dream task when necessary.
*/
void setDreamAppTask(Binder dreamToken, IAppTask appTask) {
if (mCurrentDream == null || mCurrentDream.mToken != dreamToken
|| mCurrentDream.mAppTask != null) {
Slog.e(TAG, "Illegal dream activity start. mCurrentDream.mToken = "
+ mCurrentDream.mToken + ", illegal dreamToken = " + dreamToken
+ ". Ending this dream activity.");
try {
appTask.finishAndRemoveTask();
} catch (RemoteException | RuntimeException e) {
Slog.e(TAG, "Unable to stop illegal dream activity.");
}
return;
}
mCurrentDream.mAppTask = appTask;
}
/**
* Stops dreaming.
*
@@ -303,8 +324,14 @@ final class DreamController {
mSentStartBroadcast = false;
}
mActivityTaskManager.removeRootTasksWithActivityTypes(
new int[] {ACTIVITY_TYPE_DREAM});
if (mCurrentDream != null && mCurrentDream.mAppTask != null) {
// Finish the dream task in case it hasn't finished by itself already.
try {
mCurrentDream.mAppTask.finishAndRemoveTask();
} catch (RemoteException | RuntimeException e) {
Slog.e(TAG, "Unable to stop dream activity.");
}
}
mListener.onDreamStopped(dream.mToken);
}
@@ -364,6 +391,7 @@ final class DreamController {
public final boolean mIsPreviewMode;
public final boolean mCanDoze;
public final int mUserId;
public IAppTask mAppTask;
public PowerManager.WakeLock mWakeLock;
public boolean mBound;

View File

@@ -27,6 +27,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IAppTask;
import android.app.TaskInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -37,6 +38,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
@@ -116,6 +118,7 @@ public final class DreamManagerService extends SystemService {
private final PowerManagerInternal mPowerManagerInternal;
private final PowerManager.WakeLock mDozeWakeLock;
private final ActivityTaskManagerInternal mAtmInternal;
private final PackageManagerInternal mPmInternal;
private final UserManager mUserManager;
private final UiEventLogger mUiEventLogger;
private final DreamUiEventLogger mDreamUiEventLogger;
@@ -216,6 +219,7 @@ public final class DreamManagerService extends SystemService {
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
mPmInternal = getLocalService(PackageManagerInternal.class);
mUserManager = context.getSystemService(UserManager.class);
mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, DOZE_WAKE_LOCK_TAG);
mDozeConfig = new AmbientDisplayConfiguration(mContext);
@@ -1064,6 +1068,64 @@ public final class DreamManagerService extends SystemService {
Binder.restoreCallingIdentity(ident);
}
}
@Override // Binder call
public void startDreamActivity(@NonNull Intent intent) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
// We post here, because startDreamActivity and setDreamAppTask have to run
// synchronously and DreamController#setDreamAppTask has to run on mHandler.
mHandler.post(() -> {
final Binder dreamToken;
final String dreamPackageName;
synchronized (mLock) {
if (mCurrentDream == null) {
Slog.e(TAG, "Attempt to start DreamActivity, but the device is not "
+ "dreaming. Aborting without starting the DreamActivity.");
return;
}
dreamToken = mCurrentDream.token;
dreamPackageName = mCurrentDream.name.getPackageName();
}
if (!canLaunchDreamActivity(dreamPackageName, intent.getPackage(),
callingUid)) {
Slog.e(TAG, "The dream activity can be started only when the device is dreaming"
+ " and only by the active dream package.");
return;
}
final IAppTask appTask = mAtmInternal.startDreamActivity(intent, callingUid,
callingPid);
if (appTask == null) {
Slog.e(TAG, "Could not start dream activity.");
stopDreamInternal(true, "DreamActivity not started");
return;
}
mController.setDreamAppTask(dreamToken, appTask);
});
}
boolean canLaunchDreamActivity(String dreamPackageName, String packageName,
int callingUid) {
if (dreamPackageName == null || packageName == null) {
Slog.e(TAG, "Cannot launch dream activity due to invalid state. dream component= "
+ dreamPackageName + ", packageName=" + packageName);
return false;
}
if (!mPmInternal.isSameApp(packageName, callingUid, UserHandle.getUserId(callingUid))) {
Slog.e(TAG, "Cannot launch dream activity because package="
+ packageName + " does not match callingUid=" + callingUid);
return false;
}
if (packageName.equals(dreamPackageName)) {
return true;
}
Slog.e(TAG, "Dream packageName does not match active dream. Package " + packageName
+ " does not match " + dreamPackageName);
return false;
}
}
private final class LocalService extends DreamManagerInternal {

View File

@@ -23,6 +23,7 @@ import android.app.ActivityManager;
import android.app.AppProtoEnums;
import android.app.BackgroundStartPrivileges;
import android.app.IActivityManager;
import android.app.IAppTask;
import android.app.IApplicationThread;
import android.app.ITaskStackListener;
import android.app.ProfilerInfo;
@@ -307,6 +308,12 @@ public abstract class ActivityTaskManagerInternal {
*/
public abstract void notifyActiveDreamChanged(@Nullable ComponentName activeDreamComponent);
/**
* Starts a dream activity in the DreamService's process.
*/
public abstract IAppTask startDreamActivity(@NonNull Intent intent, int callingUid,
int callingPid);
/**
* Set a uid that is allowed to bypass stopped app switches, launching an app
* whenever it wants.

View File

@@ -1467,23 +1467,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return false;
}
private void enforceCallerIsDream(String callerPackageName) {
final long origId = Binder.clearCallingIdentity();
try {
if (!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());
private IAppTask startDreamActivityInternal(@NonNull Intent intent, int callingUid,
int callingPid) {
final ActivityInfo a = new ActivityInfo();
a.theme = com.android.internal.R.style.Theme_Dream;
a.exported = true;
@@ -1501,7 +1486,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
synchronized (mGlobalLock) {
final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
final WindowProcessController process = mProcessMap.getProcess(callingPid);
a.packageName = process.mInfo.packageName;
a.applicationInfo = process.mInfo;
@@ -1509,26 +1494,25 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
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)
.setCallingPackage(intent.getPackage())
.setActivityInfo(a)
.setActivityOptions(createSafeActivityOptionsWithBalAllowed(options))
// 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())
.setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
return true;
} finally {
Binder.restoreCallingIdentity(origId);
}
final ActivityRecord[] outActivity = new ActivityRecord[1];
getActivityStartController().obtainStarter(intent, "dream")
.setCallingUid(callingUid)
.setCallingPid(callingPid)
.setCallingPackage(intent.getPackage())
.setActivityInfo(a)
.setActivityOptions(createSafeActivityOptionsWithBalAllowed(options))
.setOutActivity(outActivity)
// 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())
.setBackgroundStartPrivileges(BackgroundStartPrivileges.ALLOW_BAL)
.execute();
final ActivityRecord started = outActivity[0];
final IAppTask appTask = started == null ? null :
new AppTaskImpl(this, started.getTask().mTaskId, callingUid);
return appTask;
}
}
@@ -5925,6 +5909,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
@Override
public IAppTask startDreamActivity(@NonNull Intent intent, int callingUid, int callingPid) {
return startDreamActivityInternal(intent, callingUid, callingPid);
}
@Override
public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {