More mult-user API work.
- You can now use android:singleUser with receivers and providers.
- New API to send ordered broadcasts as a user.
- New Process.myUserHandle() API.
For now I am trying out "user handle" as the name for the numbers
representing users.
Change-Id: I754c713ab172494bb4251bc7a37a17324a2e235e
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index c6d46fc..76ddb96 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -20,12 +20,15 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -249,7 +252,7 @@
finishReceiverLocked(br, br.resultCode, br.resultData,
br.resultExtras, br.resultAbort, true);
scheduleBroadcastsLocked();
- // We need to reset the state if we fails to start the receiver.
+ // We need to reset the state if we failed to start the receiver.
br.state = BroadcastRecord.IDLE;
throw new RuntimeException(e.getMessage());
}
@@ -659,6 +662,9 @@
ResolveInfo info =
(ResolveInfo)nextReceiver;
+ ComponentName component = new ComponentName(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
boolean skip = false;
if (r.onlySendToCaller) {
@@ -667,6 +673,7 @@
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ + " to " + component.flattenToShortString()
+ " not allowed to go to different app "
+ info.activityInfo.applicationInfo.uid);
skip = true;
@@ -682,16 +689,14 @@
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
+ " is not exported from uid " + info.activityInfo.applicationInfo.uid
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
+ + " due to receiver " + component.flattenToShortString());
} else {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
+ " requires " + info.activityInfo.permission
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
+ + " due to receiver " + component.flattenToShortString());
}
skip = true;
}
@@ -707,13 +712,33 @@
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: receiving "
+ r.intent + " to "
- + info.activityInfo.applicationInfo.packageName
+ + component.flattenToShortString()
+ " requires " + r.requiredPermission
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}
}
+ boolean isSingleton = false;
+ try {
+ isSingleton = mService.isSingleton(info.activityInfo.processName,
+ info.activityInfo.applicationInfo,
+ info.activityInfo.name, info.activityInfo.flags);
+ } catch (SecurityException e) {
+ Slog.w(TAG, e.getMessage());
+ skip = true;
+ }
+ if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
+ if (ActivityManager.checkUidPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ info.activityInfo.applicationInfo.uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
+ + " requests FLAG_SINGLE_USER, but app does not hold "
+ + android.Manifest.permission.INTERACT_ACROSS_USERS);
+ skip = true;
+ }
+ }
if (r.curApp != null && r.curApp.crashing) {
// If the target process is crashing, just skip it.
if (DEBUG_BROADCAST) Slog.v(TAG,
@@ -736,14 +761,9 @@
r.state = BroadcastRecord.APP_RECEIVE;
String targetProcess = info.activityInfo.processName;
- r.curComponent = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- if (r.callingUid != Process.SYSTEM_UID) {
- boolean isSingleton = mService.isSingleton(info.activityInfo.processName,
- info.activityInfo.applicationInfo);
- int targetUserId = isSingleton ? 0 : UserId.getUserId(r.callingUid);
- info.activityInfo = mService.getActivityInfoForUser(info.activityInfo,targetUserId);
+ r.curComponent = component;
+ if (r.callingUid != Process.SYSTEM_UID && isSingleton) {
+ info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
}
r.curReceiver = info.activityInfo;
if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {