Do not allow moveToFront() and moveTaskToFront() when app is in background

Bug: 129063631
Test: Unable to start activity / move task in background
Change-Id: Icb5ebad3567b911719341f221483df1a1512109b
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 395c867..53cd675 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2001,7 +2001,10 @@
     @RequiresPermission(android.Manifest.permission.REORDER_TASKS)
     public void moveTaskToFront(int taskId, @MoveTaskFlags int flags, Bundle options) {
         try {
-            getTaskService().moveTaskToFront(taskId, flags, options);
+            ActivityThread thread = ActivityThread.currentActivityThread();
+            IApplicationThread appThread = thread.getApplicationThread();
+            String packageName = mContext.getPackageName();
+            getTaskService().moveTaskToFront(appThread, packageName, taskId, flags, options);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4212,7 +4215,10 @@
          */
         public void moveToFront() {
             try {
-                mAppTaskImpl.moveToFront();
+                ActivityThread thread = ActivityThread.currentActivityThread();
+                IApplicationThread appThread = thread.getApplicationThread();
+                String packageName = ActivityThread.currentPackageName();
+                mAppTaskImpl.moveToFront(appThread, packageName);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 65f1080..1785d2a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -130,7 +130,8 @@
     List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType,
             int ignoreWindowingMode);
     @UnsupportedAppUsage
-    void moveTaskToFront(int task, int flags, in Bundle options);
+    void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task,
+            int flags, in Bundle options);
     @UnsupportedAppUsage
     int getTaskForActivity(in IBinder token, in boolean onlyRoot);
     ContentProviderHolder getContentProvider(in IApplicationThread caller, in String callingPackage,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index a6b76cb..7953d42 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -149,7 +149,8 @@
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
     boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
             in Intent resultData);
-    void moveTaskToFront(int task, int flags, in Bundle options);
+    void moveTaskToFront(in IApplicationThread app, in String callingPackage, int task,
+            int flags, in Bundle options);
     int getTaskForActivity(in IBinder token, in boolean onlyRoot);
     void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
     ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
diff --git a/core/java/android/app/IAppTask.aidl b/core/java/android/app/IAppTask.aidl
index 61f6264..3ce7190 100644
--- a/core/java/android/app/IAppTask.aidl
+++ b/core/java/android/app/IAppTask.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.app.ActivityManager;
+import android.app.IApplicationThread;
 import android.content.Intent;
 import android.os.Bundle;
 
@@ -25,7 +26,7 @@
     void finishAndRemoveTask();
     @UnsupportedAppUsage
     ActivityManager.RecentTaskInfo getTaskInfo();
-    void moveToFront();
+    void moveToFront(in IApplicationThread appThread, in String callingPackage);
     int startActivity(IBinder whoThread, String callingPackage,
             in Intent intent, String resolvedType, in Bundle options);
     void setExcludeFromRecents(boolean exclude);
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
index 7735d84..0152387 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -16,11 +16,11 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.IApplicationThread;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
@@ -29,13 +29,14 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.View;
-import android.view.Window;
 import android.view.View.OnClickListener;
+import android.view.Window;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.R;
+
 /**
  * This activity is displayed when the system attempts to start an Intent for
  * which there is more than one matching activity, allowing the user to decide
@@ -127,7 +128,10 @@
     private OnClickListener mSwitchOldListener = new OnClickListener() {
         public void onClick(View v) {
             try {
-                ActivityTaskManager.getService().moveTaskToFront(mCurTask, 0, null);
+                ActivityThread thread = ActivityThread.currentActivityThread();
+                IApplicationThread appThread = thread.getApplicationThread();
+                ActivityTaskManager.getService().moveTaskToFront(appThread, getPackageName(),
+                        mCurTask, 0, null);
             } catch (RemoteException e) {
             }
             finish();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1757c98..0b9e3bb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6147,8 +6147,9 @@
     }
 
     @Override
-    public void moveTaskToFront(int taskId, int flags, Bundle bOptions) {
-        mActivityTaskManager.moveTaskToFront(taskId, flags, bOptions);
+    public void moveTaskToFront(IApplicationThread appThread, String callingPackage, int taskId,
+            int flags, Bundle bOptions) {
+        mActivityTaskManager.moveTaskToFront(appThread, callingPackage, taskId, flags, bOptions);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 53dc1df..f573b7d 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2776,8 +2776,8 @@
                         true /* forceSend */, targetActivity);
                 mActivityMetricsLogger.notifyActivityLaunching(task.intent);
                 try {
-                    mService.moveTaskToFrontLocked(task.taskId, 0, options,
-                            true /* fromRecents */);
+                    mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
+                            task.taskId, 0, options, true /* fromRecents */);
                     // Apply options to prevent pendingOptions be taken by client to make sure
                     // the override pending app transition will be applied immediately.
                     targetActivity.applyOptionsLocked();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 3b358e8..a187bf73 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -759,8 +759,8 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                         "shouldAbortBackgroundActivityStart");
-                abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                        callingPackage, realCallingUid, realCallingPid, callerApp,
+                abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid,
+                        callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                         originatingPendingIntent, allowBackgroundActivityStart, intent);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -768,14 +768,7 @@
             abort |= (abortBackgroundStart && !mService.isBackgroundActivityStartsEnabled());
             // TODO: remove this toast after feature development is done
             if (abortBackgroundStart) {
-                final Resources res = mService.mContext.getResources();
-                final String toastMsg = res.getString(abort
-                            ? R.string.activity_starter_block_bg_activity_starts_enforcing
-                            : R.string.activity_starter_block_bg_activity_starts_permissive,
-                        callingPackage);
-                mService.mUiHandler.post(() -> {
-                    Toast.makeText(mService.mContext, toastMsg, Toast.LENGTH_LONG).show();
-                });
+                showBackgroundActivityBlockedToast(abort, callingPackage);
             }
         }
 
@@ -935,7 +928,7 @@
         return res;
     }
 
-    private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
+    boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
             final String callingPackage, int realCallingUid, int realCallingPid,
             WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
             boolean allowBackgroundActivityStart, Intent intent) {
@@ -1048,7 +1041,7 @@
                 + "; realCallingUid: " + realCallingUid
                 + "; isRealCallingUidForeground: " + isRealCallingUidForeground
                 + "; isRealCallingUidPersistentSystemProcess: "
-                        + isRealCallingUidPersistentSystemProcess
+                + isRealCallingUidPersistentSystemProcess
                 + "; originatingPendingIntent: " + originatingPendingIntent
                 + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
                 + "; intent: " + intent
@@ -1076,6 +1069,18 @@
         return false;
     }
 
+    // TODO: remove this toast after feature development is done
+    void showBackgroundActivityBlockedToast(boolean abort, String callingPackage) {
+        final Resources res = mService.mContext.getResources();
+        final String toastMsg = res.getString(abort
+                        ? R.string.activity_starter_block_bg_activity_starts_enforcing
+                        : R.string.activity_starter_block_bg_activity_starts_permissive,
+                callingPackage);
+        mService.mUiHandler.post(() -> {
+            Toast.makeText(mService.mContext, toastMsg, Toast.LENGTH_LONG).show();
+        });
+    }
+
     /**
      * Creates a launch intent for the given auxiliary resolution data.
      */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b64abdb..2c27654 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2280,25 +2280,48 @@
      * TODO: Add mController hook
      */
     @Override
-    public void moveTaskToFront(int taskId, int flags, Bundle bOptions) {
+    public void moveTaskToFront(IApplicationThread appThread, String callingPackage, int taskId,
+            int flags, Bundle bOptions) {
         mAmInternal.enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
 
         if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
         synchronized (mGlobalLock) {
-            moveTaskToFrontLocked(taskId, flags, SafeActivityOptions.fromBundle(bOptions),
-                    false /* fromRecents */);
+            moveTaskToFrontLocked(appThread, callingPackage, taskId, flags,
+                    SafeActivityOptions.fromBundle(bOptions), false /* fromRecents */);
         }
     }
 
-    void moveTaskToFrontLocked(int taskId, int flags, SafeActivityOptions options,
+    void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
+            @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
             boolean fromRecents) {
 
-        if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
-                Binder.getCallingUid(), -1, -1, "Task to front")) {
+        final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
+        if (!isSameApp(callingUid, callingPackage)) {
+            String msg = "Permission Denial: moveTaskToFrontLocked() from pid="
+                    + Binder.getCallingPid() + " as package " + callingPackage;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        if (!checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, "Task to front")) {
             SafeActivityOptions.abort(options);
             return;
         }
         final long origId = Binder.clearCallingIdentity();
+        WindowProcessController callerApp = null;
+        if (appThread != null) {
+            callerApp = getProcessController(appThread);
+        }
+        final ActivityStarter starter = getActivityStartController().obtainStarter(
+                null /* intent */, "moveTaskToFront");
+        if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
+                -1, callerApp, null, false, null)) {
+            boolean abort = !isBackgroundActivityStartsEnabled();
+            starter.showBackgroundActivityBlockedToast(abort, callingPackage);
+            if (abort) {
+                return;
+            }
+        }
         try {
             final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
             if (task == null) {
@@ -2330,6 +2353,26 @@
         }
     }
 
+    /**
+     * Return true if callingUid is system, or packageName belongs to that callingUid.
+     */
+    boolean isSameApp(int callingUid, @Nullable String packageName) {
+        try {
+            if (callingUid != 0 && callingUid != SYSTEM_UID) {
+                if (packageName == null) {
+                    return false;
+                }
+                final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+                        UserHandle.getUserId(callingUid));
+                return UserHandle.isSameApp(callingUid, uid);
+            }
+        } catch (RemoteException e) {
+            // Should not happen
+        }
+        return true;
+    }
+
     boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
             int callingPid, int callingUid, String name) {
         if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -5290,7 +5333,10 @@
         return mAmInternal.isBackgroundActivityStartsEnabled();
     }
 
-    boolean isPackageNameWhitelistedForBgActivityStarts(String packageName) {
+    boolean isPackageNameWhitelistedForBgActivityStarts(@Nullable String packageName) {
+        if (packageName == null) {
+            return false;
+        }
         return mAmInternal.isPackageNameWhitelistedForBgActivityStarts(packageName);
     }
 
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 441c593..e967a92f 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
+import android.util.Slog;
 
 /**
  * An implementation of IAppTask, that allows an app to manage its own tasks via
@@ -34,6 +35,7 @@
  * only the process that calls getAppTasks() can call the AppTask methods.
  */
 class AppTaskImpl extends IAppTask.Stub {
+    private static final String TAG = "AppTaskImpl";
     private ActivityTaskManagerService mService;
 
     private int mTaskId;
@@ -90,16 +92,36 @@
     }
 
     @Override
-    public void moveToFront() {
+    public void moveToFront(IApplicationThread appThread, String callingPackage) {
         checkCaller();
         // Will bring task to front if it already has a root activity.
         final int callingPid = Binder.getCallingPid();
         final int callingUid = Binder.getCallingUid();
+        if (!mService.isSameApp(callingUid, callingPackage)) {
+            String msg = "Permission Denial: moveToFront() from pid="
+                    + Binder.getCallingPid() + " as package " + callingPackage;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mService.mGlobalLock) {
-                mService.mStackSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,
-                        null);
+                WindowProcessController callerApp = null;
+                if (appThread != null) {
+                    callerApp = mService.getProcessController(appThread);
+                }
+                final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
+                        null /* intent */, "moveToFront");
+                if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
+                        callingPackage, -1, -1, callerApp, null, false, null)) {
+                    boolean abort = !mService.isBackgroundActivityStartsEnabled();
+                    starter.showBackgroundActivityBlockedToast(abort, callingPackage);
+                    if (abort) {
+                        return;
+                    }
+                }
+                mService.mStackSupervisor.startActivityFromRecents(callingPid,
+                        callingUid, mTaskId, null);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index d8a01b9..1880ef5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -39,7 +39,6 @@
 import android.support.test.uiautomator.UiDevice;
 import android.text.TextUtils;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import com.android.internal.annotations.GuardedBy;
@@ -207,7 +206,8 @@
 
         // Test for onTaskMovedToFront.
         assertEquals(1, taskMovedToFrontLatch.getCount());
-        mService.moveTaskToFront(id, 0, null);
+        mService.moveTaskToFront(null, getInstrumentation().getContext().getPackageName(), id, 0,
+                null);
         waitForCallback(taskMovedToFrontLatch);
         assertEquals(activity.getTaskId(), params[0]);
 
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index 548a0c22..5fb23b0 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -40,7 +40,7 @@
     @SmallTest
     public void testREORDER_TASKS() {
         try {
-            mAm.moveTaskToFront(0, 0, null);
+            mAm.moveTaskToFront(null, null, 0, 0, null);
             fail("IActivityManager.moveTaskToFront did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {