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
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 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 @@
= 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 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 @@
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 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 @@
}
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;