summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2012-09-23 13:22:26 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-09-23 13:22:27 -0700
commit11820f7386ce86fd89e9e6b49d9231dce6e1ed07 (patch)
tree9437ce9ba5b311f4b95c05121a9df6ec7f062379
parentb939e35274334d1f5e71a526efe8d235eb6d7387 (diff)
parent6d51571835737c7502a2e111ee9dc2527ebad984 (diff)
downloadframeworks_base-11820f7386ce86fd89e9e6b49d9231dce6e1ed07.zip
frameworks_base-11820f7386ce86fd89e9e6b49d9231dce6e1ed07.tar.gz
frameworks_base-11820f7386ce86fd89e9e6b49d9231dce6e1ed07.tar.bz2
Merge "Allow acquiring ContentProviders across users." into jb-mr1-dev
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java56
-rw-r--r--core/java/android/app/ActivityManagerNative.java15
-rw-r--r--core/java/android/app/ActivityThread.java64
-rw-r--r--core/java/android/app/ContextImpl.java59
-rw-r--r--core/java/android/app/IActivityManager.java4
-rw-r--r--core/java/android/app/Notification.java14
-rw-r--r--core/java/android/content/Context.java11
-rw-r--r--core/java/android/content/ContextWrapper.java7
-rw-r--r--core/java/android/widget/RemoteViews.java20
-rw-r--r--core/java/com/android/internal/statusbar/StatusBarNotification.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java5
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java7
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java18
-rw-r--r--test-runner/src/android/test/mock/MockContext.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java6
15 files changed, 235 insertions, 109 deletions
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index bd9eb9a..787fbdb 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -25,6 +25,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
+import android.os.UserHandle;
import android.text.TextUtils;
/**
@@ -63,7 +64,8 @@ public class Content {
private static final String USAGE =
"usage: adb shell content [subcommand] [options]\n"
+ "\n"
- + "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]\n"
+ + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
+ + " --bind <BINDING> [--bind <BINDING>...]\n"
+ " <URI> a content provider URI.\n"
+ " <BINDING> binds a typed value to a column and is formatted:\n"
+ " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
@@ -75,7 +77,7 @@ public class Content {
+ " adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+ " --bind value:s:new_value\n"
+ "\n"
- + "usage: adb shell content update --uri <URI> [--where <WHERE>]\n"
+ + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
+ " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+ " - see example below).\n"
+ " Example:\n"
@@ -83,15 +85,15 @@ public class Content {
+ " adb shell content update --uri content://settings/secure --bind"
+ " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+ "\n"
- + "usage: adb shell content delete --uri <URI> --bind <BINDING>"
+ + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
+ " [--bind <BINDING>...] [--where <WHERE>]\n"
+ " Example:\n"
+ " # Remove \"new_setting\" secure setting.\n"
+ " adb shell content delete --uri content://settings/secure "
+ "--where \"name=\'new_setting\'\"\n"
+ "\n"
- + "usage: adb shell content query --uri <URI> [--projection <PROJECTION>]"
- + " [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+ + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
+ + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+ " <PROJECTION> is a list of colon separated column names and is formatted:\n"
+ " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+ " <SORT_OREDER> is the order in which rows in the result should be sorted.\n"
@@ -110,6 +112,7 @@ public class Content {
private static final String ARGUMENT_WHERE = "--where";
private static final String ARGUMENT_BIND = "--bind";
private static final String ARGUMENT_URI = "--uri";
+ private static final String ARGUMENT_USER = "--user";
private static final String ARGUMENT_PROJECTION = "--projection";
private static final String ARGUMENT_SORT = "--sort";
private static final String TYPE_BOOLEAN = "b";
@@ -150,10 +153,13 @@ public class Content {
private InsertCommand parseInsertCommand() {
Uri uri = null;
+ int userId = UserHandle.USER_OWNER;
ContentValues values = new ContentValues();
for (String argument; (argument = mTokenizer.nextArg()) != null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_USER.equals(argument)) {
+ userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_BIND.equals(argument)) {
parseBindValue(values);
} else {
@@ -168,15 +174,18 @@ public class Content {
throw new IllegalArgumentException("Bindings not specified."
+ " Did you specify --bind argument(s)?");
}
- return new InsertCommand(uri, values);
+ return new InsertCommand(uri, userId, values);
}
private DeleteCommand parseDeleteCommand() {
Uri uri = null;
+ int userId = UserHandle.USER_OWNER;
String where = null;
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_USER.equals(argument)) {
+ userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
where = argumentValueRequired(argument);
} else {
@@ -187,16 +196,19 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new DeleteCommand(uri, where);
+ return new DeleteCommand(uri, userId, where);
}
private UpdateCommand parseUpdateCommand() {
Uri uri = null;
+ int userId = UserHandle.USER_OWNER;
String where = null;
ContentValues values = new ContentValues();
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_USER.equals(argument)) {
+ userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
where = argumentValueRequired(argument);
} else if (ARGUMENT_BIND.equals(argument)) {
@@ -213,17 +225,20 @@ public class Content {
throw new IllegalArgumentException("Bindings not specified."
+ " Did you specify --bind argument(s)?");
}
- return new UpdateCommand(uri, values, where);
+ return new UpdateCommand(uri, userId, values, where);
}
public QueryCommand parseQueryCommand() {
Uri uri = null;
+ int userId = UserHandle.USER_OWNER;
String[] projection = null;
String sort = null;
String where = null;
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_USER.equals(argument)) {
+ userId = Integer.parseInt(argumentValueRequired(argument));
} else if (ARGUMENT_WHERE.equals(argument)) {
where = argumentValueRequired(argument);
} else if (ARGUMENT_SORT.equals(argument)) {
@@ -238,7 +253,7 @@ public class Content {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
- return new QueryCommand(uri, projection, where, sort);
+ return new QueryCommand(uri, userId, projection, where, sort);
}
private void parseBindValue(ContentValues values) {
@@ -298,9 +313,11 @@ public class Content {
private static abstract class Command {
final Uri mUri;
+ final int mUserId;
- public Command(Uri uri) {
+ public Command(Uri uri, int userId) {
mUri = uri;
+ mUserId = userId;
}
public final void execute() {
@@ -311,7 +328,7 @@ public class Content {
IBinder token = new Binder();
try {
ContentProviderHolder holder = activityManager.getContentProviderExternal(
- providerName, token);
+ providerName, mUserId, token);
if (holder == null) {
throw new IllegalStateException("Could not find provider: " + providerName);
}
@@ -334,8 +351,8 @@ public class Content {
private static class InsertCommand extends Command {
final ContentValues mContentValues;
- public InsertCommand(Uri uri, ContentValues contentValues) {
- super(uri);
+ public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
+ super(uri, userId);
mContentValues = contentValues;
}
@@ -348,8 +365,8 @@ public class Content {
private static class DeleteCommand extends Command {
final String mWhere;
- public DeleteCommand(Uri uri, String where) {
- super(uri);
+ public DeleteCommand(Uri uri, int userId, String where) {
+ super(uri, userId);
mWhere = where;
}
@@ -363,8 +380,9 @@ public class Content {
final String[] mProjection;
final String mSortOrder;
- public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) {
- super(uri, where);
+ public QueryCommand(
+ Uri uri, int userId, String[] projection, String where, String sortOrder) {
+ super(uri, userId, where);
mProjection = projection;
mSortOrder = sortOrder;
}
@@ -426,8 +444,8 @@ public class Content {
private static class UpdateCommand extends InsertCommand {
final String mWhere;
- public UpdateCommand(Uri uri, ContentValues contentValues, String where) {
- super(uri, contentValues);
+ public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
+ super(uri, userId, contentValues);
mWhere = where;
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b0df660..c3f57e8 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -632,8 +632,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String name = data.readString();
+ int userId = data.readInt();
boolean stable = data.readInt() != 0;
- ContentProviderHolder cph = getContentProvider(app, name, stable);
+ ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
reply.writeNoException();
if (cph != null) {
reply.writeInt(1);
@@ -647,8 +648,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String name = data.readString();
+ int userId = data.readInt();
IBinder token = data.readStrongBinder();
- ContentProviderHolder cph = getContentProviderExternal(name, token);
+ ContentProviderHolder cph = getContentProviderExternal(name, userId, token);
reply.writeNoException();
if (cph != null) {
reply.writeInt(1);
@@ -2495,12 +2497,13 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
public ContentProviderHolder getContentProvider(IApplicationThread caller,
- String name, boolean stable) throws RemoteException {
+ String name, int userId, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
+ data.writeInt(userId);
data.writeInt(stable ? 1 : 0);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
@@ -2513,13 +2516,13 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return cph;
}
- public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
- throws RemoteException
- {
+ public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(name);
+ data.writeInt(userId);
data.writeStrongBinder(token);
mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 67ecf5b..aa8ef21 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -89,6 +89,7 @@ import android.renderscript.RenderScript;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
+import com.android.internal.util.Objects;
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
@@ -214,9 +215,33 @@ public final class ActivityThread {
= new ArrayList<ActivityClientRecord>();
Configuration mPendingConfiguration = null;
+ private static final class ProviderKey {
+ final String authority;
+ final int userId;
+
+ public ProviderKey(String authority, int userId) {
+ this.authority = authority;
+ this.userId = userId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ProviderKey) {
+ final ProviderKey other = (ProviderKey) o;
+ return Objects.equal(authority, other.authority) && userId == other.userId;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return ((authority != null) ? authority.hashCode() : 0) ^ userId;
+ }
+ }
+
// The lock of mProviderMap protects the following variables.
- final HashMap<String, ProviderClientRecord> mProviderMap
- = new HashMap<String, ProviderClientRecord>();
+ final HashMap<ProviderKey, ProviderClientRecord> mProviderMap
+ = new HashMap<ProviderKey, ProviderClientRecord>();
final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap
= new HashMap<IBinder, ProviderRefCount>();
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
@@ -4360,8 +4385,9 @@ public final class ActivityThread {
}
}
- public final IContentProvider acquireProvider(Context c, String name, boolean stable) {
- IContentProvider provider = acquireExistingProvider(c, name, stable);
+ public final IContentProvider acquireProvider(
+ Context c, String auth, int userId, boolean stable) {
+ final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
@@ -4375,11 +4401,11 @@ public final class ActivityThread {
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
- getApplicationThread(), name, stable);
+ getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
- Slog.e(TAG, "Failed to find provider info for " + name);
+ Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
@@ -4456,10 +4482,11 @@ public final class ActivityThread {
}
}
- public final IContentProvider acquireExistingProvider(Context c, String name,
- boolean stable) {
+ public final IContentProvider acquireExistingProvider(
+ Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
- ProviderClientRecord pr = mProviderMap.get(name);
+ final ProviderKey key = new ProviderKey(auth, userId);
+ final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
@@ -4639,17 +4666,20 @@ public final class ActivityThread {
}
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
- ContentProvider localProvider,IActivityManager.ContentProviderHolder holder) {
- String names[] = PATTERN_SEMICOLON.split(holder.info.authority);
- ProviderClientRecord pcr = new ProviderClientRecord(names, provider,
- localProvider, holder);
- for (int i = 0; i < names.length; i++) {
- ProviderClientRecord existing = mProviderMap.get(names[i]);
+ ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
+ final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
+ final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
+
+ final ProviderClientRecord pcr = new ProviderClientRecord(
+ auths, provider, localProvider, holder);
+ for (String auth : auths) {
+ final ProviderKey key = new ProviderKey(auth, userId);
+ final ProviderClientRecord existing = mProviderMap.get(key);
if (existing != null) {
Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
- + " already published as " + names[i]);
+ + " already published as " + auth);
} else {
- mProviderMap.put(names[i], pcr);
+ mProviderMap.put(key, pcr);
}
}
return pcr;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 56b745f..a6ec9b6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -17,6 +17,7 @@
package android.app;
import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.Preconditions;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -35,6 +36,7 @@ import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -183,6 +185,7 @@ class ContextImpl extends Context {
private Display mDisplay; // may be null if default display
private Context mReceiverRestrictedContext = null;
private boolean mRestricted;
+ private UserHandle mUser;
private final Object mSync = new Object();
@@ -1676,7 +1679,13 @@ class ContextImpl extends Context {
@Override
public Context createPackageContext(String packageName, int flags)
- throws PackageManager.NameNotFoundException {
+ throws NameNotFoundException {
+ return createPackageContextAsUser(packageName, flags, Process.myUserHandle());
+ }
+
+ @Override
+ public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
+ throws NameNotFoundException {
if (packageName.equals("system") || packageName.equals("android")) {
final ContextImpl context = new ContextImpl(mMainThread.getSystemContext());
context.mBasePackageName = mBasePackageName;
@@ -1688,7 +1697,7 @@ class ContextImpl extends Context {
if (pi != null) {
ContextImpl c = new ContextImpl();
c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
- c.init(pi, null, mMainThread, mResources, mBasePackageName);
+ c.init(pi, null, mMainThread, mResources, mBasePackageName, user);
if (c.mResources != null) {
return c;
}
@@ -1769,8 +1778,8 @@ class ContextImpl extends Context {
}
static ContextImpl createSystemContext(ActivityThread mainThread) {
- ContextImpl context = new ContextImpl();
- context.init(Resources.getSystem(), mainThread);
+ final ContextImpl context = new ContextImpl();
+ context.init(Resources.getSystem(), mainThread, Process.myUserHandle());
return context;
}
@@ -1790,18 +1799,17 @@ class ContextImpl extends Context {
mResources = context.mResources;
mMainThread = context.mMainThread;
mContentResolver = context.mContentResolver;
+ mUser = context.mUser;
mDisplay = context.mDisplay;
mOuterContext = this;
}
- final void init(LoadedApk packageInfo,
- IBinder activityToken, ActivityThread mainThread) {
- init(packageInfo, activityToken, mainThread, null, null);
+ final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) {
+ init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle());
}
- final void init(LoadedApk packageInfo,
- IBinder activityToken, ActivityThread mainThread,
- Resources container, String basePackageName) {
+ final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread,
+ Resources container, String basePackageName, UserHandle user) {
mPackageInfo = packageInfo;
mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
mResources = mPackageInfo.getResources(mainThread);
@@ -1818,16 +1826,18 @@ class ContextImpl extends Context {
null, container.getCompatibilityInfo());
}
mMainThread = mainThread;
- mContentResolver = new ApplicationContentResolver(this, mainThread);
mActivityToken = activityToken;
+ mContentResolver = new ApplicationContentResolver(this, mainThread, user);
+ mUser = user;
}
- final void init(Resources resources, ActivityThread mainThread) {
+ final void init(Resources resources, ActivityThread mainThread, UserHandle user) {
mPackageInfo = null;
mBasePackageName = null;
mResources = resources;
mMainThread = mainThread;
- mContentResolver = new ApplicationContentResolver(this, mainThread);
+ mContentResolver = new ApplicationContentResolver(this, mainThread, user);
+ mUser = user;
}
final void scheduleFinalCleanup(String who, String what) {
@@ -1912,19 +1922,24 @@ class ContextImpl extends Context {
// ----------------------------------------------------------------------
private static final class ApplicationContentResolver extends ContentResolver {
- public ApplicationContentResolver(Context context, ActivityThread mainThread) {
+ private final ActivityThread mMainThread;
+ private final UserHandle mUser;
+
+ public ApplicationContentResolver(
+ Context context, ActivityThread mainThread, UserHandle user) {
super(context);
- mMainThread = mainThread;
+ mMainThread = Preconditions.checkNotNull(mainThread);
+ mUser = Preconditions.checkNotNull(user);
}
@Override
- protected IContentProvider acquireProvider(Context context, String name) {
- return mMainThread.acquireProvider(context, name, true);
+ protected IContentProvider acquireProvider(Context context, String auth) {
+ return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);
}
@Override
- protected IContentProvider acquireExistingProvider(Context context, String name) {
- return mMainThread.acquireExistingProvider(context, name, true);
+ protected IContentProvider acquireExistingProvider(Context context, String auth) {
+ return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true);
}
@Override
@@ -1933,8 +1948,8 @@ class ContextImpl extends Context {
}
@Override
- protected IContentProvider acquireUnstableProvider(Context c, String name) {
- return mMainThread.acquireProvider(c, name, false);
+ protected IContentProvider acquireUnstableProvider(Context c, String auth) {
+ return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
}
@Override
@@ -1946,7 +1961,5 @@ class ContextImpl extends Context {
public void unstableProviderDied(IContentProvider icp) {
mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
}
-
- private final ActivityThread mMainThread;
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ed17d0e..2b2679e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -117,8 +117,8 @@ public interface IActivityManager extends IInterface {
public void reportThumbnail(IBinder token,
Bitmap thumbnail, CharSequence description) throws RemoteException;
public ContentProviderHolder getContentProvider(IApplicationThread caller,
- String name, boolean stable) throws RemoteException;
- public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
+ String name, int userId, boolean stable) throws RemoteException;
+ public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
throws RemoteException;
public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException;
public void removeContentProviderExternal(String name, IBinder token) throws RemoteException;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 17c2c6b..182ebef 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -29,6 +29,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IntProperty;
import android.util.Log;
@@ -893,6 +894,19 @@ public class Notification implements Parcelable
return sb.toString();
}
+ /** {@hide} */
+ public void setUser(UserHandle user) {
+ if (tickerView != null) {
+ tickerView.setUser(user);
+ }
+ if (contentView != null) {
+ contentView.setUser(user);
+ }
+ if (bigContentView != null) {
+ bigContentView.setUser(user);
+ }
+ }
+
/**
* Builder class for {@link Notification} objects.
*
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 161670f..524962cb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2574,6 +2574,17 @@ public abstract class Context {
int flags) throws PackageManager.NameNotFoundException;
/**
+ * Similar to {@link #createPackageContext(String, int)}, but with a
+ * different {@link UserHandle}. For example, {@link #getContentResolver()}
+ * will open any {@link Uri} as the given user.
+ *
+ * @hide
+ */
+ public abstract Context createPackageContextAsUser(
+ String packageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException;
+
+ /**
* Return a new Context object for the current Context but whose resources
* are adjusted to match the given Configuration. Each call to this method
* returns a new instance of a Context object; Context objects are not
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 6101f4e..d824f1e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -586,6 +586,13 @@ public class ContextWrapper extends Context {
return mBase.createPackageContext(packageName, flags);
}
+ /** @hide */
+ @Override
+ public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException {
+ return mBase.createPackageContextAsUser(packageName, flags, user);
+ }
+
@Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
return mBase.createConfigurationContext(overrideConfiguration);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1a47ce2..90f55bf 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -23,7 +23,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -35,9 +34,9 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
-import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.LayoutInflater.Filter;
import android.view.RemotableViewMethod;
@@ -72,6 +71,13 @@ public class RemoteViews implements Parcelable, Filter {
static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
/**
+ * User that these views should be applied as. Requires
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} when
+ * crossing user boundaries.
+ */
+ private UserHandle mUser = android.os.Process.myUserHandle();
+
+ /**
* The package name of the package containing the layout
* resource. (Added to the parcel)
*/
@@ -1446,11 +1452,16 @@ public class RemoteViews implements Parcelable, Filter {
recalculateMemoryUsage();
}
+ /** {@hide} */
+ public void setUser(UserHandle user) {
+ mUser = user;
+ }
+
private boolean hasLandscapeAndPortraitLayouts() {
return (mLandscape != null) && (mPortrait != null);
}
- /**
+ /**
* Create a new RemoteViews object that will inflate as the specified
* landspace or portrait RemoteViews, depending on the current configuration.
*
@@ -2309,7 +2320,8 @@ public class RemoteViews implements Parcelable, Filter {
if (packageName != null) {
try {
- c = context.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
+ c = context.createPackageContextAsUser(
+ packageName, Context.CONTEXT_RESTRICTED, mUser);
} catch (NameNotFoundException e) {
Log.e(LOG_TAG, "Package name " + packageName + " not found");
c = context;
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java
index cb87ac4..f9a38a5 100644
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.java
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java
@@ -20,8 +20,6 @@ import android.app.Notification;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
-import android.widget.RemoteViews;
-
/*
boolean clearable = !n.ongoingEvent && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
@@ -39,19 +37,25 @@ if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
* Class encapsulating a Notification. Sent by the NotificationManagerService to the IStatusBar (in System UI).
*/
public class StatusBarNotification implements Parcelable {
- public String pkg;
- public int id;
- public String tag;
- public int uid;
- public int initialPid;
- public Notification notification;
- public int score;
-
- public StatusBarNotification() {
+ public final String pkg;
+ public final int id;
+ public final String tag;
+ public final int uid;
+ public final int initialPid;
+ // TODO: make this field private and move callers to an accessor that
+ // ensures sourceUser is applied.
+ public final Notification notification;
+ public final int score;
+ public final UserHandle user;
+
+ @Deprecated
+ public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
+ Notification notification) {
+ this(pkg, id, tag, uid, initialPid, score, notification, UserHandle.OWNER);
}
- public StatusBarNotification(String pkg, int id, String tag,
- int uid, int initialPid, int score, Notification notification) {
+ public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
+ Notification notification, UserHandle user) {
if (pkg == null) throw new NullPointerException();
if (notification == null) throw new NullPointerException();
@@ -62,13 +66,11 @@ public class StatusBarNotification implements Parcelable {
this.initialPid = initialPid;
this.score = score;
this.notification = notification;
+ this.user = user;
+ this.notification.setUser(user);
}
public StatusBarNotification(Parcel in) {
- readFromParcel(in);
- }
-
- public void readFromParcel(Parcel in) {
this.pkg = in.readString();
this.id = in.readInt();
if (in.readInt() != 0) {
@@ -80,6 +82,8 @@ public class StatusBarNotification implements Parcelable {
this.initialPid = in.readInt();
this.score = in.readInt();
this.notification = new Notification(in);
+ this.user = UserHandle.readFromParcel(in);
+ this.notification.setUser(user);
}
public void writeToParcel(Parcel out, int flags) {
@@ -95,6 +99,7 @@ public class StatusBarNotification implements Parcelable {
out.writeInt(this.initialPid);
out.writeInt(this.score);
this.notification.writeToParcel(out, flags);
+ user.writeToParcel(out, flags);
}
public int describeContents() {
@@ -115,14 +120,16 @@ public class StatusBarNotification implements Parcelable {
}
};
+ @Override
public StatusBarNotification clone() {
- return new StatusBarNotification(this.pkg, this.id, this.tag,
- this.uid, this.initialPid, this.score, this.notification.clone());
+ return new StatusBarNotification(this.pkg, this.id, this.tag, this.uid, this.initialPid,
+ this.score, this.notification.clone(), this.user);
}
+ @Override
public String toString() {
- return "StatusBarNotification(pkg=" + pkg + " id=" + id + " tag=" + tag
- + " score=" + score + " notn=" + notification + ")";
+ return "StatusBarNotification(pkg=" + pkg + " id=" + id + " tag=" + tag + " score=" + score
+ + " notn=" + notification + " user=" + user + ")";
}
public boolean isOngoing() {
@@ -139,5 +146,3 @@ public class StatusBarNotification implements Parcelable {
return UserHandle.getUserId(this.uid);
}
}
-
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 7153ec7..3335dfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1370,9 +1370,8 @@ public class TabletStatusBar extends BaseStatusBar implements
iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0);
mNotificationDNDDummyEntry = new NotificationData.Entry(
- null,
- new StatusBarNotification("", 0, "", 0, 0, Notification.PRIORITY_MAX, dndNotification),
- iconView);
+ null, new StatusBarNotification("", 0, "", 0, 0, Notification.PRIORITY_MAX,
+ dndNotification, android.os.Process.myUserHandle()), iconView);
mIconLayout.addView(iconView, params);
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 3caba1f..71e6e66 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -63,6 +63,7 @@ import android.util.Slog;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.widget.RemoteViews;
import android.widget.Toast;
import com.android.internal.statusbar.StatusBarNotification;
@@ -877,7 +878,6 @@ public class NotificationManagerService extends INotificationManager.Stub
return (x < low) ? low : ((x > high) ? high : x);
}
-
// Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
// uid/pid of another application)
public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
@@ -992,8 +992,9 @@ public class NotificationManagerService extends INotificationManager.Stub
}
if (notification.icon != 0) {
- StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
- r.uid, r.initialPid, score, notification);
+ final UserHandle user = new UserHandle(userId);
+ final StatusBarNotification n = new StatusBarNotification(
+ pkg, id, tag, r.uid, r.initialPid, score, notification, user);
if (old != null && old.statusBarKey != null) {
r.statusBarKey = old.statusBarKey;
long identity = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f162dae..a6f2974 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6414,10 +6414,6 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " (pid=" + Binder.getCallingPid()
+ ") when getting content provider " + name);
}
- if (r.userId != userId) {
- throw new SecurityException("Calling requested user " + userId
- + " but app is user " + r.userId);
- }
}
// First check if this content provider has been published...
@@ -6666,7 +6662,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
public final ContentProviderHolder getContentProvider(
- IApplicationThread caller, String name, boolean stable) {
+ IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
@@ -6675,14 +6671,18 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new SecurityException(msg);
}
- return getContentProviderImpl(caller, name, null, stable,
- UserHandle.getCallingUserId());
+ userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ false, true, "getContentProvider", null);
+ return getContentProviderImpl(caller, name, null, stable, userId);
}
- public ContentProviderHolder getContentProviderExternal(String name, IBinder token) {
+ public ContentProviderHolder getContentProviderExternal(
+ String name, int userId, IBinder token) {
enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
"Do not have permission in call getContentProviderExternal()");
- return getContentProviderExternalUnchecked(name, token, UserHandle.getCallingUserId());
+ userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ false, true, "getContentProvider", null);
+ return getContentProviderExternalUnchecked(name, token, userId);
}
private ContentProviderHolder getContentProviderExternalUnchecked(String name,
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 5c9282e..1f815e7 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -523,6 +523,13 @@ public class MockContext extends Context {
throw new UnsupportedOperationException();
}
+ /** {@hide} */
+ @Override
+ public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
throw new UnsupportedOperationException();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 428c4c2..80478ba 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -920,6 +920,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) {
+ // pass
+ return null;
+ }
+
+ @Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
// pass
return null;