Expose per-user APIs for content services.
Bug: 15466880 Change-Id: Ib5a030e78559307627fe0d2e80ce6f1a7825109d
This commit is contained in:
@@ -621,10 +621,15 @@ final class ApplicationPackageManager extends PackageManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderInfo resolveContentProvider(String name,
|
||||
int flags) {
|
||||
public ProviderInfo resolveContentProvider(String name, int flags) {
|
||||
return resolveContentProviderAsUser(name, flags, mContext.getUserId());
|
||||
}
|
||||
|
||||
/** @hide **/
|
||||
@Override
|
||||
public ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId) {
|
||||
try {
|
||||
return mPM.resolveContentProvider(name, flags, mContext.getUserId());
|
||||
return mPM.resolveContentProvider(name, flags, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("Package manager has died", e);
|
||||
}
|
||||
|
||||
@@ -1751,6 +1751,15 @@ public abstract class ContentResolver {
|
||||
* @param extras any extras to pass to the SyncAdapter.
|
||||
*/
|
||||
public static void requestSync(Account account, String authority, Bundle extras) {
|
||||
requestSyncAsUser(account, authority, UserHandle.getCallingUserId(), extras);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #requestSync(Account, String, Bundle)
|
||||
* @hide
|
||||
*/
|
||||
public static void requestSyncAsUser(Account account, String authority, int userId,
|
||||
Bundle extras) {
|
||||
if (extras == null) {
|
||||
throw new IllegalArgumentException("Must specify extras.");
|
||||
}
|
||||
@@ -1760,7 +1769,11 @@ public abstract class ContentResolver {
|
||||
.setExtras(extras)
|
||||
.syncOnce() // Immediate sync.
|
||||
.build();
|
||||
requestSync(request);
|
||||
try {
|
||||
getContentService().syncAsUser(request, userId);
|
||||
} catch(RemoteException e) {
|
||||
// Shouldn't happen.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1838,6 +1851,17 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #cancelSync(Account, String)
|
||||
* @hide
|
||||
*/
|
||||
public static void cancelSyncAsUser(Account account, String authority, int userId) {
|
||||
try {
|
||||
getContentService().cancelSyncAsUser(account, authority, null, userId);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the SyncAdapters that are known to the system.
|
||||
* @return an array of SyncAdapters that have registered with the system
|
||||
@@ -1850,6 +1874,18 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getSyncAdapterTypes()
|
||||
* @hide
|
||||
*/
|
||||
public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
|
||||
try {
|
||||
return getContentService().getSyncAdapterTypesAsUser(userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("the ContentService should always be reachable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provider should be synced when a network tickle is received
|
||||
* <p>This method requires the caller to hold the permission
|
||||
@@ -1867,6 +1903,19 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getSyncAutomatically(Account, String)
|
||||
* @hide
|
||||
*/
|
||||
public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
|
||||
int userId) {
|
||||
try {
|
||||
return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("the ContentService should always be reachable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the provider is synced when it receives a network tickle.
|
||||
* <p>This method requires the caller to hold the permission
|
||||
@@ -2031,6 +2080,18 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getIsSyncable(Account, String)
|
||||
* @hide
|
||||
*/
|
||||
public static int getIsSyncableAsUser(Account account, String authority, int userId) {
|
||||
try {
|
||||
return getContentService().getIsSyncableAsUser(account, authority, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("the ContentService should always be reachable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this account/provider is syncable.
|
||||
* <p>This method requires the caller to hold the permission
|
||||
@@ -2062,6 +2123,18 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getMasterSyncAutomatically()
|
||||
* @hide
|
||||
*/
|
||||
public static boolean getMasterSyncAutomaticallyAsUser(int userId) {
|
||||
try {
|
||||
return getContentService().getMasterSyncAutomaticallyAsUser(userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("the ContentService should always be reachable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the master auto-sync setting that applies to all the providers and accounts.
|
||||
* If this is false then the per-provider auto-sync setting is ignored.
|
||||
@@ -2146,6 +2219,18 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getCurrentSyncs()
|
||||
* @hide
|
||||
*/
|
||||
public static List<SyncInfo> getCurrentSyncsAsUser(int userId) {
|
||||
try {
|
||||
return getContentService().getCurrentSyncsAsUser(userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("the ContentService should always be reachable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status that matches the authority.
|
||||
* @param account the account whose setting we are querying
|
||||
@@ -2161,6 +2246,19 @@ public abstract class ContentResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getSyncStatus(Account, String)
|
||||
* @hide
|
||||
*/
|
||||
public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
|
||||
int userId) {
|
||||
try {
|
||||
return getContentService().getSyncStatusAsUser(account, authority, null, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("the ContentService should always be reachable", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the pending status is true of any matching authorities.
|
||||
* <p>This method requires the caller to hold the permission
|
||||
|
||||
@@ -60,7 +60,9 @@ interface IContentService {
|
||||
* Start a sync given a request.
|
||||
*/
|
||||
void sync(in SyncRequest request);
|
||||
void syncAsUser(in SyncRequest request, int userId);
|
||||
void cancelSync(in Account account, String authority, in ComponentName cname);
|
||||
void cancelSyncAsUser(in Account account, String authority, in ComponentName cname, int userId);
|
||||
|
||||
/** Cancel a sync, providing information about the sync to be cancelled. */
|
||||
void cancelRequest(in SyncRequest request);
|
||||
@@ -71,6 +73,7 @@ interface IContentService {
|
||||
* @return true if the provider should be synced when a network tickle is received
|
||||
*/
|
||||
boolean getSyncAutomatically(in Account account, String providerName);
|
||||
boolean getSyncAutomaticallyAsUser(in Account account, String providerName, int userId);
|
||||
|
||||
/**
|
||||
* Set whether or not the provider is synced when it receives a network tickle.
|
||||
@@ -114,6 +117,7 @@ interface IContentService {
|
||||
* @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
|
||||
*/
|
||||
int getIsSyncable(in Account account, String providerName);
|
||||
int getIsSyncableAsUser(in Account account, String providerName, int userId);
|
||||
|
||||
/**
|
||||
* Set whether this account/provider is syncable.
|
||||
@@ -124,14 +128,17 @@ interface IContentService {
|
||||
void setMasterSyncAutomatically(boolean flag);
|
||||
|
||||
boolean getMasterSyncAutomatically();
|
||||
boolean getMasterSyncAutomaticallyAsUser(int userId);
|
||||
|
||||
List<SyncInfo> getCurrentSyncs();
|
||||
List<SyncInfo> getCurrentSyncsAsUser(int userId);
|
||||
|
||||
/**
|
||||
* Returns the types of the SyncAdapters that are registered with the system.
|
||||
* @return Returns the types of the SyncAdapters that are registered with the system.
|
||||
*/
|
||||
SyncAdapterType[] getSyncAdapterTypes();
|
||||
SyncAdapterType[] getSyncAdapterTypesAsUser(int userId);
|
||||
|
||||
/**
|
||||
* Returns true if there is currently a operation for the given account/authority or service
|
||||
@@ -152,6 +159,8 @@ interface IContentService {
|
||||
* non-null.
|
||||
*/
|
||||
SyncStatusInfo getSyncStatus(in Account account, String authority, in ComponentName cname);
|
||||
SyncStatusInfo getSyncStatusAsUser(in Account account, String authority, in ComponentName cname,
|
||||
int userId);
|
||||
|
||||
/**
|
||||
* Return true if the pending status is true of any matching authorities.
|
||||
|
||||
@@ -2477,6 +2477,19 @@ public abstract class PackageManager {
|
||||
public abstract ProviderInfo resolveContentProvider(String name,
|
||||
int flags);
|
||||
|
||||
/**
|
||||
* Find a single content provider by its base path name.
|
||||
*
|
||||
* @param name The name of the provider to find.
|
||||
* @param flags Additional option flags. Currently should always be 0.
|
||||
* @param userId The user id.
|
||||
*
|
||||
* @return ContentProviderInfo Information about the provider, if found,
|
||||
* else null.
|
||||
* @hide
|
||||
*/
|
||||
public abstract ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId);
|
||||
|
||||
/**
|
||||
* Retrieve content provider information.
|
||||
*
|
||||
|
||||
@@ -172,11 +172,8 @@ public final class ContentService extends IContentService.Stub {
|
||||
throw new IllegalArgumentException("You must pass a valid uri and observer");
|
||||
}
|
||||
|
||||
final int callingUser = UserHandle.getCallingUserId();
|
||||
if (callingUser != userHandle) {
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
"no permission to observe other users' provider view");
|
||||
}
|
||||
enforceCrossUserPermission(userHandle,
|
||||
"no permission to observe other users' provider view");
|
||||
|
||||
if (userHandle < 0) {
|
||||
if (userHandle == UserHandle.USER_CURRENT) {
|
||||
@@ -346,7 +343,15 @@ public final class ContentService extends IContentService.Stub {
|
||||
* @param request The request object. Validation of this object is done by its builder.
|
||||
*/
|
||||
public void sync(SyncRequest request) {
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
syncAsUser(request, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*/
|
||||
public void syncAsUser(SyncRequest request, int userId) {
|
||||
enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
|
||||
int callerUid = Binder.getCallingUid();
|
||||
// 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.
|
||||
@@ -399,11 +404,30 @@ public final class ContentService extends IContentService.Stub {
|
||||
*/
|
||||
@Override
|
||||
public void cancelSync(Account account, String authority, ComponentName cname) {
|
||||
cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all scheduled sync operations that match the uri and cancel the active sync
|
||||
* if they match the authority and account, if they are present.
|
||||
*
|
||||
* <p> If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*
|
||||
* @param account filter the pending and active syncs to cancel using this account, or null.
|
||||
* @param authority filter the pending and active syncs to cancel using this authority, or
|
||||
* null.
|
||||
* @param userId the user id for which to cancel sync operations.
|
||||
* @param cname cancel syncs running on this service, or null for provider/account.
|
||||
*/
|
||||
@Override
|
||||
public void cancelSyncAsUser(Account account, String authority, ComponentName cname,
|
||||
int userId) {
|
||||
if (authority != null && authority.length() == 0) {
|
||||
throw new IllegalArgumentException("Authority must be non-empty");
|
||||
}
|
||||
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to modify the sync settings for user " + userId);
|
||||
// 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.
|
||||
long identityToken = clearCallingIdentity();
|
||||
@@ -456,9 +480,23 @@ public final class ContentService extends IContentService.Stub {
|
||||
*/
|
||||
@Override
|
||||
public SyncAdapterType[] getSyncAdapterTypes() {
|
||||
return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the SyncAdapters that are known to the system for a particular user.
|
||||
*
|
||||
* <p> If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*
|
||||
* @return an array of SyncAdapters that have registered with the system
|
||||
*/
|
||||
@Override
|
||||
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to read sync settings for user " + userId);
|
||||
// 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.
|
||||
final int userId = UserHandle.getCallingUserId();
|
||||
final long identityToken = clearCallingIdentity();
|
||||
try {
|
||||
SyncManager syncManager = getSyncManager();
|
||||
@@ -470,10 +508,20 @@ public final class ContentService extends IContentService.Stub {
|
||||
|
||||
@Override
|
||||
public boolean getSyncAutomatically(Account account, String providerName) {
|
||||
return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*/
|
||||
@Override
|
||||
public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) {
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to read the sync settings for user " + userId);
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
|
||||
"no permission to read the sync settings");
|
||||
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
long identityToken = clearCallingIdentity();
|
||||
try {
|
||||
SyncManager syncManager = getSyncManager();
|
||||
@@ -588,9 +636,18 @@ public final class ContentService extends IContentService.Stub {
|
||||
}
|
||||
|
||||
public int getIsSyncable(Account account, String providerName) {
|
||||
return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*/
|
||||
public int getIsSyncableAsUser(Account account, String providerName, int userId) {
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to read the sync settings for user " + userId);
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
|
||||
"no permission to read the sync settings");
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
|
||||
long identityToken = clearCallingIdentity();
|
||||
try {
|
||||
@@ -627,10 +684,20 @@ public final class ContentService extends IContentService.Stub {
|
||||
|
||||
@Override
|
||||
public boolean getMasterSyncAutomatically() {
|
||||
return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*/
|
||||
@Override
|
||||
public boolean getMasterSyncAutomaticallyAsUser(int userId) {
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to read the sync settings for user " + userId);
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
|
||||
"no permission to read the sync settings");
|
||||
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
long identityToken = clearCallingIdentity();
|
||||
try {
|
||||
SyncManager syncManager = getSyncManager();
|
||||
@@ -679,10 +746,19 @@ public final class ContentService extends IContentService.Stub {
|
||||
}
|
||||
|
||||
public List<SyncInfo> getCurrentSyncs() {
|
||||
return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*/
|
||||
public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to read the sync settings for user " + userId);
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
|
||||
"no permission to read the sync stats");
|
||||
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
long identityToken = clearCallingIdentity();
|
||||
try {
|
||||
return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
|
||||
@@ -692,13 +768,24 @@ public final class ContentService extends IContentService.Stub {
|
||||
}
|
||||
|
||||
public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
|
||||
return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user id supplied is different to the calling user, the caller must hold the
|
||||
* INTERACT_ACROSS_USERS_FULL permission.
|
||||
*/
|
||||
public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
|
||||
ComponentName cname, int userId) {
|
||||
if (TextUtils.isEmpty(authority)) {
|
||||
throw new IllegalArgumentException("Authority must not be empty");
|
||||
}
|
||||
|
||||
enforceCrossUserPermission(userId,
|
||||
"no permission to read the sync stats for user " + userId);
|
||||
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
|
||||
"no permission to read the sync stats");
|
||||
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
int callerUid = Binder.getCallingUid();
|
||||
long identityToken = clearCallingIdentity();
|
||||
try {
|
||||
@@ -771,6 +858,21 @@ public final class ContentService extends IContentService.Stub {
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
|
||||
* permission, if the userHandle is not for the caller.
|
||||
*
|
||||
* @param userHandle the user handle of the user we want to act on behalf of.
|
||||
* @param message the message to log on security exception.
|
||||
*/
|
||||
private void enforceCrossUserPermission(int userHandle, String message) {
|
||||
final int callingUser = UserHandle.getCallingUserId();
|
||||
if (callingUser != userHandle) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide this class since it is not part of api,
|
||||
* but current unittest framework requires it to be public
|
||||
|
||||
@@ -305,6 +305,12 @@ public class MockPackageManager extends PackageManager {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
Reference in New Issue
Block a user