Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e14118f authored by Galia Peycheva's avatar Galia Peycheva
Browse files

Do not kill dream process when stopping dream

The DreamController currently force stops the dream with
ActivityTaskManagerService.removeRootTask. Unintuitively, that method
kills the client process if the dream task is the last task in the
process.

We want to keep the dream client process warm and leave it up to the LMK
to decide when to kill it.

In this CL we pass an IAppTask to the DreamController, which allows it
to stop the dream task without killing the process.

Bug: 281960746
Test: atest DreamManagerServiceTests
Test: atest DreamOverlayTest
Test: atest DreamServiceTest

Change-Id: I83f267657812cb776fc65919bc0f5727fdc15b30
parent c7753c32
Loading
Loading
Loading
Loading
+0 −9
Original line number Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import android.app.GrantedUriPermission;
import android.app.IApplicationThread;
import android.app.IApplicationThread;
import android.app.IActivityClientController;
import android.app.IActivityClientController;
import android.app.IActivityController;
import android.app.IActivityController;
import android.app.IAppTask;
import android.app.IAssistDataReceiver;
import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
import android.app.IProcessObserver;
@@ -107,14 +106,6 @@ interface IActivityTaskManager {
            in ProfilerInfo profilerInfo, in Bundle options, int userId);
            in ProfilerInfo profilerInfo, in Bundle options, int userId);
    boolean startNextMatchingActivity(in IBinder callingActivity,
    boolean startNextMatchingActivity(in IBinder callingActivity,
            in Intent intent, in Bundle options);
            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,
    int startActivityIntentSender(in IApplicationThread caller,
            in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent,
            in IIntentSender target, in IBinder whitelistToken, in Intent fillInIntent,
            in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
            in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
+1 −4
Original line number Original line Diff line number Diff line
@@ -26,7 +26,6 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.TestApi;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.AlarmManager;
import android.app.Service;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
@@ -1268,9 +1267,7 @@ public class DreamService extends Service implements Window.Callback {
                    fetchDreamLabel(this, serviceInfo, isPreviewMode));
                    fetchDreamLabel(this, serviceInfo, isPreviewMode));


            try {
            try {
                if (!ActivityTaskManager.getService().startDreamActivity(i)) {
                mDreamManager.startDreamActivity(i);
                    detach();
                }
            } catch (SecurityException e) {
            } catch (SecurityException e) {
                Log.w(mTag,
                Log.w(mTag,
                        "Received SecurityException trying to start DreamActivity. "
                        "Received SecurityException trying to start DreamActivity. "
+2 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package android.service.dreams;
package android.service.dreams;


import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor;
import android.os.IBinder;
import android.os.IBinder;
@@ -45,4 +46,5 @@ interface IDreamManager {
    void setDreamComponentsForUser(int userId, in ComponentName[] componentNames);
    void setDreamComponentsForUser(int userId, in ComponentName[] componentNames);
    void setSystemDreamComponent(in ComponentName componentName);
    void setSystemDreamComponent(in ComponentName componentName);
    void registerDreamOverlayService(in ComponentName componentName);
    void registerDreamOverlayService(in ComponentName componentName);
    void startDreamActivity(in Intent intent);
}
}
+31 −3
Original line number Original line Diff line number Diff line
@@ -16,11 +16,11 @@


package com.android.server.dreams;
package com.android.server.dreams;


import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;


import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager;
import android.app.BroadcastOptions;
import android.app.BroadcastOptions;
import android.app.IAppTask;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
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.
     * Stops dreaming.
     *
     *
@@ -303,8 +324,14 @@ final class DreamController {
                    mSentStartBroadcast = false;
                    mSentStartBroadcast = false;
                }
                }


                mActivityTaskManager.removeRootTasksWithActivityTypes(
                if (mCurrentDream != null && mCurrentDream.mAppTask != null) {
                        new int[] {ACTIVITY_TYPE_DREAM});
                    // 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);
                mListener.onDreamStopped(dream.mToken);
            }
            }
@@ -364,6 +391,7 @@ final class DreamController {
        public final boolean mIsPreviewMode;
        public final boolean mIsPreviewMode;
        public final boolean mCanDoze;
        public final boolean mCanDoze;
        public final int mUserId;
        public final int mUserId;
        public IAppTask mAppTask;


        public PowerManager.WakeLock mWakeLock;
        public PowerManager.WakeLock mWakeLock;
        public boolean mBound;
        public boolean mBound;
+62 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.IAppTask;
import android.app.TaskInfo;
import android.app.TaskInfo;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ComponentName;
@@ -37,6 +38,7 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.AmbientDisplayConfiguration;
@@ -116,6 +118,7 @@ public final class DreamManagerService extends SystemService {
    private final PowerManagerInternal mPowerManagerInternal;
    private final PowerManagerInternal mPowerManagerInternal;
    private final PowerManager.WakeLock mDozeWakeLock;
    private final PowerManager.WakeLock mDozeWakeLock;
    private final ActivityTaskManagerInternal mAtmInternal;
    private final ActivityTaskManagerInternal mAtmInternal;
    private final PackageManagerInternal mPmInternal;
    private final UserManager mUserManager;
    private final UserManager mUserManager;
    private final UiEventLogger mUiEventLogger;
    private final UiEventLogger mUiEventLogger;
    private final DreamUiEventLogger mDreamUiEventLogger;
    private final DreamUiEventLogger mDreamUiEventLogger;
@@ -216,6 +219,7 @@ public final class DreamManagerService extends SystemService {
        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
        mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
        mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
        mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
        mPmInternal = getLocalService(PackageManagerInternal.class);
        mUserManager = context.getSystemService(UserManager.class);
        mUserManager = context.getSystemService(UserManager.class);
        mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, DOZE_WAKE_LOCK_TAG);
        mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, DOZE_WAKE_LOCK_TAG);
        mDozeConfig = new AmbientDisplayConfiguration(mContext);
        mDozeConfig = new AmbientDisplayConfiguration(mContext);
@@ -1064,6 +1068,64 @@ public final class DreamManagerService extends SystemService {
                Binder.restoreCallingIdentity(ident);
                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 {
    private final class LocalService extends DreamManagerInternal {
Loading