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..5fb23b0a 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) {