Start cross profile intents as caller.
The system should always be using new startActivityAsCaller() when
starting activities on behalf of someone else, to ensure that
security checks are enforced as the original caller.
Bug: 17983737
Change-Id: Ic40816a797cfdb13c0adb48b86ed4ed7d6aae8eb
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0e98175..4b705dd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3847,14 +3847,14 @@
* their launch had come from the original activity.
* @hide
*/
- public void startActivityAsCaller(Intent intent, @Nullable Bundle options) {
+ public void startActivityAsCaller(Intent intent, @Nullable Bundle options, int userId) {
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivityAsCaller(
this, mMainThread.getApplicationThread(), mToken, this,
- intent, -1, options);
+ intent, -1, options, userId);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, -1, ar.getResultCode(),
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6c67c09..4e2ff0b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -184,8 +184,9 @@
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
+ int userId = data.readInt();
int result = startActivityAsCaller(app, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
+ resultTo, resultWho, requestCode, startFlags, profilerInfo, options, userId);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -2435,7 +2436,7 @@
}
public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
+ int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2459,6 +2460,7 @@
} else {
data.writeInt(0);
}
+ data.writeInt(userId);
mRemote.transact(START_ACTIVITY_AS_CALLER_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b72addf..be26f30 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -69,7 +69,7 @@
ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;
public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int flags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
+ int flags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;
public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho,
int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index ba3a234..60a013e 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1671,7 +1671,7 @@
*/
public ActivityResult execStartActivityAsCaller(
Context who, IBinder contextThread, IBinder token, Activity target,
- Intent intent, int requestCode, Bundle options) {
+ Intent intent, int requestCode, Bundle options, int userId) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1695,7 +1695,7 @@
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
- requestCode, 0, null, options);
+ requestCode, 0, null, options, userId);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2eba29a..8917928 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -439,14 +439,20 @@
= "android.app.action.SET_NEW_PASSWORD";
/**
- * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from a
- * managed profile to its parent.
+ * Flag used by {@link #addCrossProfileIntentFilter} to allow access
+ * <em>from</em> a managed profile <em>to</em> its parent. That is, any
+ * matching activities in the parent profile are included in the
+ * disambiguation list shown when an app in the managed profile calls
+ * {@link Activity#startActivity(Intent)}.
*/
public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 0x0001;
/**
- * Flag used by {@link #addCrossProfileIntentFilter} to allow access of certain intents from the
- * parent to its managed profile.
+ * Flag used by {@link #addCrossProfileIntentFilter} to allow access
+ * <em>from</em> a parent <em>to</em> its managed profile. That is, any
+ * matching activities in the managed profile are included in the
+ * disambiguation list shown when an app in the parent profile calls
+ * {@link Activity#startActivity(Intent)}.
*/
public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index d9493752..6e2f84a 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -20,26 +20,28 @@
import android.app.Activity;
import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
import android.app.AppGlobals;
-import android.os.Bundle;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
+import android.os.Bundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.widget.Toast;
+
import java.util.List;
-import java.util.Set;
-/*
- * This is used in conjunction with the {@link setCrossProfileIntentFilter} method of
- * {@link DevicePolicyManager} to enable intents to be passed in and out of a managed profile.
+/**
+ * This is used in conjunction with
+ * {@link DevicePolicyManager#addCrossProfileIntentFilter} to enable intents to
+ * be passed in and out of a managed profile.
*/
-
public class IntentForwarderActivity extends Activity {
public static String TAG = "IntentForwarderActivity";
@@ -104,7 +106,23 @@
final boolean shouldShowDisclosure =
!UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID);
- startActivityAsUser(newIntent, userDest);
+ try {
+ startActivityAsCaller(newIntent, null, userDest.getIdentifier());
+ } catch (RuntimeException e) {
+ int launchedFromUid = -1;
+ String launchedFromPackage = "?";
+ try {
+ launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
+ getActivityToken());
+ launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+ getActivityToken());
+ } catch (RemoteException ignored) {
+ }
+
+ Slog.wtf(TAG, "Unable to launch as UID " + launchedFromUid + " package "
+ + launchedFromPackage + ", while running in "
+ + ActivityThread.currentProcessName(), e);
+ }
if (shouldShowDisclosure) {
Toast.makeText(this, getString(userMessageId), Toast.LENGTH_LONG).show();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index aa55d23..0062e2d 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -641,7 +641,7 @@
return;
}
try {
- startActivityAsCaller(intent, null);
+ startActivityAsCaller(intent, null, UserHandle.USER_NULL);
} catch (RuntimeException e) {
String launchedFromPackage;
try {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8357366..8dfb321 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3561,7 +3561,7 @@
@Override
public final int startActivityAsCaller(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle options) {
+ int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
// This is very dangerous -- it allows you to perform a start activity (including
// permission grants) as any app that may launch one of your own activities. So
@@ -3599,11 +3599,15 @@
targetPackage = sourceRecord.launchedFromPackage;
}
+ if (userId == UserHandle.USER_NULL) {
+ userId = UserHandle.getUserId(sourceRecord.app.uid);
+ }
+
// TODO: Switch to user app stacks here.
try {
int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
- null, null, options, UserHandle.getUserId(sourceRecord.app.uid), null, null);
+ null, null, options, userId, null, null);
return ret;
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.