Skip to content

Commit 11820f7

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Allow acquiring ContentProviders across users." into jb-mr1-dev
2 parents b939e35 + 6d51571 commit 11820f7

File tree

15 files changed

+235
-109
lines changed

15 files changed

+235
-109
lines changed

cmds/content/src/com/android/commands/content/Content.java

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.net.Uri;
2626
import android.os.Binder;
2727
import android.os.IBinder;
28+
import android.os.UserHandle;
2829
import android.text.TextUtils;
2930

3031
/**
@@ -63,7 +64,8 @@ public class Content {
6364
private static final String USAGE =
6465
"usage: adb shell content [subcommand] [options]\n"
6566
+ "\n"
66-
+ "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]\n"
67+
+ "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
68+
+ " --bind <BINDING> [--bind <BINDING>...]\n"
6769
+ " <URI> a content provider URI.\n"
6870
+ " <BINDING> binds a typed value to a column and is formatted:\n"
6971
+ " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
@@ -75,23 +77,23 @@ public class Content {
7577
+ " adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
7678
+ " --bind value:s:new_value\n"
7779
+ "\n"
78-
+ "usage: adb shell content update --uri <URI> [--where <WHERE>]\n"
80+
+ "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
7981
+ " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
8082
+ " - see example below).\n"
8183
+ " Example:\n"
8284
+ " # Change \"new_setting\" secure setting to \"newer_value\".\n"
8385
+ " adb shell content update --uri content://settings/secure --bind"
8486
+ " value:s:newer_value --where \"name=\'new_setting\'\"\n"
8587
+ "\n"
86-
+ "usage: adb shell content delete --uri <URI> --bind <BINDING>"
88+
+ "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
8789
+ " [--bind <BINDING>...] [--where <WHERE>]\n"
8890
+ " Example:\n"
8991
+ " # Remove \"new_setting\" secure setting.\n"
9092
+ " adb shell content delete --uri content://settings/secure "
9193
+ "--where \"name=\'new_setting\'\"\n"
9294
+ "\n"
93-
+ "usage: adb shell content query --uri <URI> [--projection <PROJECTION>]"
94-
+ " [--where <WHERE>] [--sort <SORT_ORDER>]\n"
95+
+ "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
96+
+ " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
9597
+ " <PROJECTION> is a list of colon separated column names and is formatted:\n"
9698
+ " <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
9799
+ " <SORT_OREDER> is the order in which rows in the result should be sorted.\n"
@@ -110,6 +112,7 @@ private static class Parser {
110112
private static final String ARGUMENT_WHERE = "--where";
111113
private static final String ARGUMENT_BIND = "--bind";
112114
private static final String ARGUMENT_URI = "--uri";
115+
private static final String ARGUMENT_USER = "--user";
113116
private static final String ARGUMENT_PROJECTION = "--projection";
114117
private static final String ARGUMENT_SORT = "--sort";
115118
private static final String TYPE_BOOLEAN = "b";
@@ -150,10 +153,13 @@ public Command parseCommand() {
150153

151154
private InsertCommand parseInsertCommand() {
152155
Uri uri = null;
156+
int userId = UserHandle.USER_OWNER;
153157
ContentValues values = new ContentValues();
154158
for (String argument; (argument = mTokenizer.nextArg()) != null;) {
155159
if (ARGUMENT_URI.equals(argument)) {
156160
uri = Uri.parse(argumentValueRequired(argument));
161+
} else if (ARGUMENT_USER.equals(argument)) {
162+
userId = Integer.parseInt(argumentValueRequired(argument));
157163
} else if (ARGUMENT_BIND.equals(argument)) {
158164
parseBindValue(values);
159165
} else {
@@ -168,15 +174,18 @@ private InsertCommand parseInsertCommand() {
168174
throw new IllegalArgumentException("Bindings not specified."
169175
+ " Did you specify --bind argument(s)?");
170176
}
171-
return new InsertCommand(uri, values);
177+
return new InsertCommand(uri, userId, values);
172178
}
173179

174180
private DeleteCommand parseDeleteCommand() {
175181
Uri uri = null;
182+
int userId = UserHandle.USER_OWNER;
176183
String where = null;
177184
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
178185
if (ARGUMENT_URI.equals(argument)) {
179186
uri = Uri.parse(argumentValueRequired(argument));
187+
} else if (ARGUMENT_USER.equals(argument)) {
188+
userId = Integer.parseInt(argumentValueRequired(argument));
180189
} else if (ARGUMENT_WHERE.equals(argument)) {
181190
where = argumentValueRequired(argument);
182191
} else {
@@ -187,16 +196,19 @@ private DeleteCommand parseDeleteCommand() {
187196
throw new IllegalArgumentException("Content provider URI not specified."
188197
+ " Did you specify --uri argument?");
189198
}
190-
return new DeleteCommand(uri, where);
199+
return new DeleteCommand(uri, userId, where);
191200
}
192201

193202
private UpdateCommand parseUpdateCommand() {
194203
Uri uri = null;
204+
int userId = UserHandle.USER_OWNER;
195205
String where = null;
196206
ContentValues values = new ContentValues();
197207
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
198208
if (ARGUMENT_URI.equals(argument)) {
199209
uri = Uri.parse(argumentValueRequired(argument));
210+
} else if (ARGUMENT_USER.equals(argument)) {
211+
userId = Integer.parseInt(argumentValueRequired(argument));
200212
} else if (ARGUMENT_WHERE.equals(argument)) {
201213
where = argumentValueRequired(argument);
202214
} else if (ARGUMENT_BIND.equals(argument)) {
@@ -213,17 +225,20 @@ private UpdateCommand parseUpdateCommand() {
213225
throw new IllegalArgumentException("Bindings not specified."
214226
+ " Did you specify --bind argument(s)?");
215227
}
216-
return new UpdateCommand(uri, values, where);
228+
return new UpdateCommand(uri, userId, values, where);
217229
}
218230

219231
public QueryCommand parseQueryCommand() {
220232
Uri uri = null;
233+
int userId = UserHandle.USER_OWNER;
221234
String[] projection = null;
222235
String sort = null;
223236
String where = null;
224237
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
225238
if (ARGUMENT_URI.equals(argument)) {
226239
uri = Uri.parse(argumentValueRequired(argument));
240+
} else if (ARGUMENT_USER.equals(argument)) {
241+
userId = Integer.parseInt(argumentValueRequired(argument));
227242
} else if (ARGUMENT_WHERE.equals(argument)) {
228243
where = argumentValueRequired(argument);
229244
} else if (ARGUMENT_SORT.equals(argument)) {
@@ -238,7 +253,7 @@ public QueryCommand parseQueryCommand() {
238253
throw new IllegalArgumentException("Content provider URI not specified."
239254
+ " Did you specify --uri argument?");
240255
}
241-
return new QueryCommand(uri, projection, where, sort);
256+
return new QueryCommand(uri, userId, projection, where, sort);
242257
}
243258

244259
private void parseBindValue(ContentValues values) {
@@ -298,9 +313,11 @@ private String nextArg() {
298313

299314
private static abstract class Command {
300315
final Uri mUri;
316+
final int mUserId;
301317

302-
public Command(Uri uri) {
318+
public Command(Uri uri, int userId) {
303319
mUri = uri;
320+
mUserId = userId;
304321
}
305322

306323
public final void execute() {
@@ -311,7 +328,7 @@ public final void execute() {
311328
IBinder token = new Binder();
312329
try {
313330
ContentProviderHolder holder = activityManager.getContentProviderExternal(
314-
providerName, token);
331+
providerName, mUserId, token);
315332
if (holder == null) {
316333
throw new IllegalStateException("Could not find provider: " + providerName);
317334
}
@@ -334,8 +351,8 @@ public final void execute() {
334351
private static class InsertCommand extends Command {
335352
final ContentValues mContentValues;
336353

337-
public InsertCommand(Uri uri, ContentValues contentValues) {
338-
super(uri);
354+
public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
355+
super(uri, userId);
339356
mContentValues = contentValues;
340357
}
341358

@@ -348,8 +365,8 @@ public void onExecute(IContentProvider provider) throws Exception {
348365
private static class DeleteCommand extends Command {
349366
final String mWhere;
350367

351-
public DeleteCommand(Uri uri, String where) {
352-
super(uri);
368+
public DeleteCommand(Uri uri, int userId, String where) {
369+
super(uri, userId);
353370
mWhere = where;
354371
}
355372

@@ -363,8 +380,9 @@ private static class QueryCommand extends DeleteCommand {
363380
final String[] mProjection;
364381
final String mSortOrder;
365382

366-
public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) {
367-
super(uri, where);
383+
public QueryCommand(
384+
Uri uri, int userId, String[] projection, String where, String sortOrder) {
385+
super(uri, userId, where);
368386
mProjection = projection;
369387
mSortOrder = sortOrder;
370388
}
@@ -426,8 +444,8 @@ public void onExecute(IContentProvider provider) throws Exception {
426444
private static class UpdateCommand extends InsertCommand {
427445
final String mWhere;
428446

429-
public UpdateCommand(Uri uri, ContentValues contentValues, String where) {
430-
super(uri, contentValues);
447+
public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
448+
super(uri, userId, contentValues);
431449
mWhere = where;
432450
}
433451

core/java/android/app/ActivityManagerNative.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,9 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
632632
IBinder b = data.readStrongBinder();
633633
IApplicationThread app = ApplicationThreadNative.asInterface(b);
634634
String name = data.readString();
635+
int userId = data.readInt();
635636
boolean stable = data.readInt() != 0;
636-
ContentProviderHolder cph = getContentProvider(app, name, stable);
637+
ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
637638
reply.writeNoException();
638639
if (cph != null) {
639640
reply.writeInt(1);
@@ -647,8 +648,9 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
647648
case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
648649
data.enforceInterface(IActivityManager.descriptor);
649650
String name = data.readString();
651+
int userId = data.readInt();
650652
IBinder token = data.readStrongBinder();
651-
ContentProviderHolder cph = getContentProviderExternal(name, token);
653+
ContentProviderHolder cph = getContentProviderExternal(name, userId, token);
652654
reply.writeNoException();
653655
if (cph != null) {
654656
reply.writeInt(1);
@@ -2495,12 +2497,13 @@ public void reportThumbnail(IBinder token,
24952497
reply.recycle();
24962498
}
24972499
public ContentProviderHolder getContentProvider(IApplicationThread caller,
2498-
String name, boolean stable) throws RemoteException {
2500+
String name, int userId, boolean stable) throws RemoteException {
24992501
Parcel data = Parcel.obtain();
25002502
Parcel reply = Parcel.obtain();
25012503
data.writeInterfaceToken(IActivityManager.descriptor);
25022504
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
25032505
data.writeString(name);
2506+
data.writeInt(userId);
25042507
data.writeInt(stable ? 1 : 0);
25052508
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
25062509
reply.readException();
@@ -2513,13 +2516,13 @@ public ContentProviderHolder getContentProvider(IApplicationThread caller,
25132516
reply.recycle();
25142517
return cph;
25152518
}
2516-
public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
2517-
throws RemoteException
2518-
{
2519+
public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
2520+
throws RemoteException {
25192521
Parcel data = Parcel.obtain();
25202522
Parcel reply = Parcel.obtain();
25212523
data.writeInterfaceToken(IActivityManager.descriptor);
25222524
data.writeString(name);
2525+
data.writeInt(userId);
25232526
data.writeStrongBinder(token);
25242527
mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
25252528
reply.readException();

core/java/android/app/ActivityThread.java

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
import com.android.internal.os.BinderInternal;
9090
import com.android.internal.os.RuntimeInit;
9191
import com.android.internal.os.SamplingProfilerIntegration;
92+
import com.android.internal.util.Objects;
9293

9394
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
9495

@@ -214,9 +215,33 @@ public final class ActivityThread {
214215
= new ArrayList<ActivityClientRecord>();
215216
Configuration mPendingConfiguration = null;
216217

218+
private static final class ProviderKey {
219+
final String authority;
220+
final int userId;
221+
222+
public ProviderKey(String authority, int userId) {
223+
this.authority = authority;
224+
this.userId = userId;
225+
}
226+
227+
@Override
228+
public boolean equals(Object o) {
229+
if (o instanceof ProviderKey) {
230+
final ProviderKey other = (ProviderKey) o;
231+
return Objects.equal(authority, other.authority) && userId == other.userId;
232+
}
233+
return false;
234+
}
235+
236+
@Override
237+
public int hashCode() {
238+
return ((authority != null) ? authority.hashCode() : 0) ^ userId;
239+
}
240+
}
241+
217242
// The lock of mProviderMap protects the following variables.
218-
final HashMap<String, ProviderClientRecord> mProviderMap
219-
= new HashMap<String, ProviderClientRecord>();
243+
final HashMap<ProviderKey, ProviderClientRecord> mProviderMap
244+
= new HashMap<ProviderKey, ProviderClientRecord>();
220245
final HashMap<IBinder, ProviderRefCount> mProviderRefCountMap
221246
= new HashMap<IBinder, ProviderRefCount>();
222247
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
@@ -4360,8 +4385,9 @@ private void installContentProviders(
43604385
}
43614386
}
43624387

4363-
public final IContentProvider acquireProvider(Context c, String name, boolean stable) {
4364-
IContentProvider provider = acquireExistingProvider(c, name, stable);
4388+
public final IContentProvider acquireProvider(
4389+
Context c, String auth, int userId, boolean stable) {
4390+
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
43654391
if (provider != null) {
43664392
return provider;
43674393
}
@@ -4375,11 +4401,11 @@ public final IContentProvider acquireProvider(Context c, String name, boolean st
43754401
IActivityManager.ContentProviderHolder holder = null;
43764402
try {
43774403
holder = ActivityManagerNative.getDefault().getContentProvider(
4378-
getApplicationThread(), name, stable);
4404+
getApplicationThread(), auth, userId, stable);
43794405
} catch (RemoteException ex) {
43804406
}
43814407
if (holder == null) {
4382-
Slog.e(TAG, "Failed to find provider info for " + name);
4408+
Slog.e(TAG, "Failed to find provider info for " + auth);
43834409
return null;
43844410
}
43854411

@@ -4456,10 +4482,11 @@ private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
44564482
}
44574483
}
44584484

4459-
public final IContentProvider acquireExistingProvider(Context c, String name,
4460-
boolean stable) {
4485+
public final IContentProvider acquireExistingProvider(
4486+
Context c, String auth, int userId, boolean stable) {
44614487
synchronized (mProviderMap) {
4462-
ProviderClientRecord pr = mProviderMap.get(name);
4488+
final ProviderKey key = new ProviderKey(auth, userId);
4489+
final ProviderClientRecord pr = mProviderMap.get(key);
44634490
if (pr == null) {
44644491
return null;
44654492
}
@@ -4639,17 +4666,20 @@ final void handleUnstableProviderDied(IBinder provider, boolean fromClient) {
46394666
}
46404667

46414668
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
4642-
ContentProvider localProvider,IActivityManager.ContentProviderHolder holder) {
4643-
String names[] = PATTERN_SEMICOLON.split(holder.info.authority);
4644-
ProviderClientRecord pcr = new ProviderClientRecord(names, provider,
4645-
localProvider, holder);
4646-
for (int i = 0; i < names.length; i++) {
4647-
ProviderClientRecord existing = mProviderMap.get(names[i]);
4669+
ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
4670+
final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
4671+
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
4672+
4673+
final ProviderClientRecord pcr = new ProviderClientRecord(
4674+
auths, provider, localProvider, holder);
4675+
for (String auth : auths) {
4676+
final ProviderKey key = new ProviderKey(auth, userId);
4677+
final ProviderClientRecord existing = mProviderMap.get(key);
46484678
if (existing != null) {
46494679
Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
4650-
+ " already published as " + names[i]);
4680+
+ " already published as " + auth);
46514681
} else {
4652-
mProviderMap.put(names[i], pcr);
4682+
mProviderMap.put(key, pcr);
46534683
}
46544684
}
46554685
return pcr;

0 commit comments

Comments
 (0)