Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70882cd6 authored by Alexandra Gherghina's avatar Alexandra Gherghina Committed by Android (Google) Code Review
Browse files

Merge "Expose per-user APIs for content services."

parents 65f48301 0363c3eb
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -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);
        }
+99 −1
Original line number Diff line number Diff line
@@ -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
+9 −0
Original line number Diff line number Diff line
@@ -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.
+13 −0
Original line number Diff line number Diff line
@@ -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.
     *
+116 −14
Original line number Diff line number Diff line
@@ -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,
        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
Loading