diff options
author | Jeff Sharkey <jsharkey@android.com> | 2012-09-20 16:06:08 -0700 |
---|---|---|
committer | Jeff Sharkey <jsharkey@android.com> | 2012-09-21 19:49:43 -0700 |
commit | 6d51571835737c7502a2e111ee9dc2527ebad984 (patch) | |
tree | 8298f3a36bdfbdb95a4fdd52681f82e7f396d31b | |
parent | 08681adda06f4699f85838861170fbb062c9fdfe (diff) | |
download | frameworks_base-6d51571835737c7502a2e111ee9dc2527ebad984.zip frameworks_base-6d51571835737c7502a2e111ee9dc2527ebad984.tar.gz frameworks_base-6d51571835737c7502a2e111ee9dc2527ebad984.tar.bz2 |
Allow acquiring ContentProviders across users.
Otherwise services like SystemUI will always open content://-style
Uris as USER_OWNER. Surfaces through createPackageContextAsUser()
which points all ContentResolver operations towards a given user.
Start using in RemoteViews, so that Notifications correctly resolve
image Uris to the sending user. Also add user support for "content"
shell tool.
Bug: 7202982
Change-Id: I8cb7fb8a812e825bb0b5833799dba87055ff8699
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 87ef23f..5d65324 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) */ @@ -1438,11 +1444,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. * @@ -2301,7 +2312,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; |