am 11820f73
: Merge "Allow acquiring ContentProviders across users." into jb-mr1-dev
* commit '11820f7386ce86fd89e9e6b49d9231dce6e1ed07': Allow acquiring ContentProviders across users.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -2573,6 +2573,17 @@ public abstract class Context {
|
||||
public abstract Context createPackageContext(String packageName,
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
@ -71,6 +70,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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -919,6 +919,12 @@ public final class BridgeContext extends Context {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) {
|
||||
// pass
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context createConfigurationContext(Configuration overrideConfiguration) {
|
||||
// pass
|
||||
|
Reference in New Issue
Block a user