am adb41d8f: am 01b079f7: Merge "Make ContentObservers work across profiles" into mnc-dev

* commit 'adb41d8f6cfb2f33240c11cc6850994579952ea1':
  Make ContentObservers work across profiles
This commit is contained in:
Benjamin Franz
2015-06-30 08:00:48 +00:00
committed by Android Git Automerger
2 changed files with 37 additions and 14 deletions

View File

@@ -1593,7 +1593,11 @@ public abstract class ContentResolver {
@NonNull ContentObserver observer) { @NonNull ContentObserver observer) {
Preconditions.checkNotNull(uri, "uri"); Preconditions.checkNotNull(uri, "uri");
Preconditions.checkNotNull(observer, "observer"); Preconditions.checkNotNull(observer, "observer");
registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId()); registerContentObserver(
ContentProvider.getUriWithoutUserId(uri),
notifyForDescendents,
observer,
ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
} }
/** @hide - designated user version */ /** @hide - designated user version */
@@ -1659,7 +1663,11 @@ public abstract class ContentResolver {
public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer, public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
boolean syncToNetwork) { boolean syncToNetwork) {
Preconditions.checkNotNull(uri, "uri"); Preconditions.checkNotNull(uri, "uri");
notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId()); notifyChange(
ContentProvider.getUriWithoutUserId(uri),
observer,
syncToNetwork,
ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
} }
/** /**

View File

@@ -23,12 +23,14 @@ import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.IContentService; import android.content.IContentService;
import android.content.Intent;
import android.content.ISyncStatusObserver; import android.content.ISyncStatusObserver;
import android.content.PeriodicSync; import android.content.PeriodicSync;
import android.content.SyncAdapterType; import android.content.SyncAdapterType;
import android.content.SyncInfo; import android.content.SyncInfo;
import android.content.SyncRequest; import android.content.SyncRequest;
import android.content.SyncStatusInfo; import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
import android.database.IContentObserver; import android.database.IContentObserver;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.net.Uri; import android.net.Uri;
@@ -161,8 +163,9 @@ public final class ContentService extends IContentService.Stub {
* Register a content observer tied to a specific user's view of the provider. * Register a content observer tied to a specific user's view of the provider.
* @param userHandle the user whose view of the provider is to be observed. May be * @param userHandle the user whose view of the provider is to be observed. May be
* the calling user without requiring any permission, otherwise the caller needs to * the calling user without requiring any permission, otherwise the caller needs to
* hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and * hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri.
* USER_CURRENT are properly handled; all other pseudousers are forbidden. * Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers
* are forbidden.
*/ */
@Override @Override
public void registerContentObserver(Uri uri, boolean notifyForDescendants, public void registerContentObserver(Uri uri, boolean notifyForDescendants,
@@ -171,8 +174,17 @@ public final class ContentService extends IContentService.Stub {
throw new IllegalArgumentException("You must pass a valid uri and observer"); throw new IllegalArgumentException("You must pass a valid uri and observer");
} }
enforceCrossUserPermission(userHandle, final int uid = Binder.getCallingUid();
"no permission to observe other users' provider view"); final int pid = Binder.getCallingPid();
final int callingUserHandle = UserHandle.getCallingUserId();
// Registering an observer for any user other than the calling user requires uri grant or
// cross user permission
if (callingUserHandle != userHandle &&
mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
enforceCrossUserPermission(userHandle,
"no permission to observe other users' provider view");
}
if (userHandle < 0) { if (userHandle < 0) {
if (userHandle == UserHandle.USER_CURRENT) { if (userHandle == UserHandle.USER_CURRENT) {
@@ -185,7 +197,7 @@ public final class ContentService extends IContentService.Stub {
synchronized (mRootNode) { synchronized (mRootNode) {
mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
Binder.getCallingUid(), Binder.getCallingPid(), userHandle); uid, pid, userHandle);
if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
" with notifyForDescendants " + notifyForDescendants); " with notifyForDescendants " + notifyForDescendants);
} }
@@ -211,8 +223,9 @@ public final class ContentService extends IContentService.Stub {
* Notify observers of a particular user's view of the provider. * Notify observers of a particular user's view of the provider.
* @param userHandle the user whose view of the provider is to be notified. May be * @param userHandle the user whose view of the provider is to be notified. May be
* the calling user without requiring any permission, otherwise the caller needs to * the calling user without requiring any permission, otherwise the caller needs to
* hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and * hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri.
* USER_CURRENT are properly interpreted; no other pseudousers are allowed. * Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are
* allowed.
*/ */
@Override @Override
public void notifyChange(Uri uri, IContentObserver observer, public void notifyChange(Uri uri, IContentObserver observer,
@@ -223,11 +236,14 @@ public final class ContentService extends IContentService.Stub {
+ " from observer " + observer + ", syncToNetwork " + syncToNetwork); + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
} }
// Notify for any user other than the caller's own requires permission. final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final int callingUserHandle = UserHandle.getCallingUserId(); final int callingUserHandle = UserHandle.getCallingUserId();
if (userHandle != callingUserHandle) { // Notify for any user other than the caller requires uri grant or cross user permission
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS, if (callingUserHandle != userHandle &&
"no permission to notify other users"); mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
enforceCrossUserPermission(userHandle, "no permission to notify other users");
} }
// We passed the permission check; resolve pseudouser targets as appropriate // We passed the permission check; resolve pseudouser targets as appropriate
@@ -240,7 +256,6 @@ public final class ContentService extends IContentService.Stub {
} }
} }
final int uid = Binder.getCallingUid();
// This makes it so that future permission checks will be in the context of this // This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning. // process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity(); long identityToken = clearCallingIdentity();