* commit 'adb41d8f6cfb2f33240c11cc6850994579952ea1': Make ContentObservers work across profiles
This commit is contained in:
@@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user