FileDocCategorySizeDatePackage
ContentService.javaAPI DocAndroid 5.1 API47102Thu Mar 12 22:22:42 GMT 2015com.android.server.content

ContentService

public final class ContentService extends IContentService.Stub
{@hide}

Fields Summary
private static final String
TAG
private android.content.Context
mContext
private boolean
mFactoryTest
private final ObserverNode
mRootNode
private SyncManager
mSyncManager
private final Object
mSyncManagerLock
Constructors Summary
ContentService(android.content.Context context, boolean factoryTest)

        mContext = context;
        mFactoryTest = factoryTest;
    
Methods Summary
public voidaddPeriodicSync(android.accounts.Account account, java.lang.String authority, android.os.Bundle extras, long pollFrequency)
Old API. Schedule periodic sync with default flex time.

        if (account == null) {
            throw new IllegalArgumentException("Account must not be null");
        }
        if (TextUtils.isEmpty(authority)) {
            throw new IllegalArgumentException("Authority must not be empty.");
        }
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");

        int userId = UserHandle.getCallingUserId();
        if (pollFrequency < 60) {
            Slog.w(TAG, "Requested poll frequency of " + pollFrequency
                    + " seconds being rounded up to 60 seconds.");
            pollFrequency = 60;
        }
        long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);

        long identityToken = clearCallingIdentity();
        try {
            SyncStorageEngine.EndPoint info =
                    new SyncStorageEngine.EndPoint(account, authority, userId);
            getSyncManager().getSyncStorageEngine()
                .updateOrAddPeriodicSync(info,
                        pollFrequency,
                        defaultFlex,
                        extras);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidaddStatusChangeListener(int mask, android.content.ISyncStatusObserver callback)

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null && callback != null) {
                syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidcancelRequest(android.content.SyncRequest request)

        SyncManager syncManager = getSyncManager();
        if (syncManager == null) return;
        int userId = UserHandle.getCallingUserId();

        long identityToken = clearCallingIdentity();
        try {
            SyncStorageEngine.EndPoint info;
            Bundle extras = new Bundle(request.getBundle());
            Account account = request.getAccount();
            String provider = request.getProvider();
            info = new SyncStorageEngine.EndPoint(account, provider, userId);
            if (request.isPeriodic()) {
                // Remove periodic sync.
                mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                        "no permission to write the sync settings");
                getSyncManager().getSyncStorageEngine().removePeriodicSync(info, extras);
            }
            // Cancel active syncs and clear pending syncs from the queue.
            syncManager.cancelScheduledSyncOperation(info, extras);
            syncManager.cancelActiveSync(info, extras);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidcancelSync(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname)
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.

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
cname cancel syncs running on this service, or null for provider/account.

        cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId());
    
public voidcancelSyncAsUser(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname, int userId)
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.

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.

        if (authority != null && authority.length() == 0) {
            throw new IllegalArgumentException("Authority must be non-empty");
        }
        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();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                SyncStorageEngine.EndPoint info;
                if (cname == null) {
                    info = new SyncStorageEngine.EndPoint(account, authority, userId);
                } else {
                    info = new SyncStorageEngine.EndPoint(cname, userId);
                }
                syncManager.clearScheduledSyncOperations(info);
                syncManager.cancelActiveSync(info, null /* all syncs for this adapter */);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
protected synchronized voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)

        mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
                "caller doesn't have the DUMP permission");

        // 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();
        try {
            if (mSyncManager == null) {
                pw.println("No SyncManager created!  (Disk full?)");
            } else {
                mSyncManager.dump(fd, pw);
            }
            pw.println();
            pw.println("Observer tree:");
            synchronized (mRootNode) {
                int[] counts = new int[2];
                final SparseIntArray pidCounts = new SparseIntArray();
                mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
                pw.println();
                ArrayList<Integer> sorted = new ArrayList<Integer>();
                for (int i=0; i<pidCounts.size(); i++) {
                    sorted.add(pidCounts.keyAt(i));
                }
                Collections.sort(sorted, new Comparator<Integer>() {
                    @Override
                    public int compare(Integer lhs, Integer rhs) {
                        int lc = pidCounts.get(lhs);
                        int rc = pidCounts.get(rhs);
                        if (lc < rc) {
                            return 1;
                        } else if (lc > rc) {
                            return -1;
                        }
                        return 0;
                    }

                });
                for (int i=0; i<sorted.size(); i++) {
                    int pid = sorted.get(i);
                    pw.print("  pid "); pw.print(pid); pw.print(": ");
                            pw.print(pidCounts.get(pid)); pw.println(" observers");
                }
                pw.println();
                pw.print(" Total number of nodes: "); pw.println(counts[0]);
                pw.print(" Total number of observers: "); pw.println(counts[1]);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
private voidenforceCrossUserPermission(int userHandle, java.lang.String message)
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.

        final int callingUser = UserHandle.getCallingUserId();
        if (callingUser != userHandle) {
            mContext.enforceCallingOrSelfPermission(
                    Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
        }
    
public java.util.ListgetCurrentSyncs()

        return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
    
public java.util.ListgetCurrentSyncsAsUser(int userId)
If the user id supplied is different to the calling user, the caller must hold the INTERACT_ACROSS_USERS_FULL permission.

        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");

        long identityToken = clearCallingIdentity();
        try {
            return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public intgetIsSyncable(android.accounts.Account account, java.lang.String providerName)

        return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
    
public intgetIsSyncableAsUser(android.accounts.Account account, java.lang.String providerName, int userId)
If the user id supplied is different to the calling user, the caller must hold the INTERACT_ACROSS_USERS_FULL permission.

        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");

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                return syncManager.getIsSyncable(
                        account, userId, providerName);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
        return -1;
    
public booleangetMasterSyncAutomatically()

        return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
    
public booleangetMasterSyncAutomaticallyAsUser(int userId)
If the user id supplied is different to the calling user, the caller must hold the INTERACT_ACROSS_USERS_FULL permission.

        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");

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
        return false;
    
public java.util.ListgetPeriodicSyncs(android.accounts.Account account, java.lang.String providerName, android.content.ComponentName cname)

        if (account == null) {
            throw new IllegalArgumentException("Account must not be null");
        }
        if (TextUtils.isEmpty(providerName)) {
            throw new IllegalArgumentException("Authority must not be empty");
        }
        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                "no permission to read the sync settings");

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
                    new SyncStorageEngine.EndPoint(account, providerName, userId));
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public android.content.SyncAdapterType[]getSyncAdapterTypes()
Get information about the SyncAdapters that are known to the system.

return
an array of SyncAdapters that have registered with the system

        return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
    
public android.content.SyncAdapterType[]getSyncAdapterTypesAsUser(int userId)
Get information about the SyncAdapters that are known to the system for a particular user.

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

        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 long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            return syncManager.getSyncAdapterTypes(userId);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public booleangetSyncAutomatically(android.accounts.Account account, java.lang.String providerName)

        return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
    
public booleangetSyncAutomaticallyAsUser(android.accounts.Account account, java.lang.String providerName, int userId)
If the user id supplied is different to the calling user, the caller must hold the INTERACT_ACROSS_USERS_FULL permission.

        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");

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                return syncManager.getSyncStorageEngine()
                        .getSyncAutomatically(account, userId, providerName);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
        return false;
    
private SyncManagergetSyncManager()


       
        if (SystemProperties.getBoolean("config.disable_network", false)) {
            return null;
        }

        synchronized(mSyncManagerLock) {
            try {
                // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
                if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
            } catch (SQLiteException e) {
                Log.e(TAG, "Can't create SyncManager", e);
            }
            return mSyncManager;
        }
    
public android.content.SyncStatusInfogetSyncStatus(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname)

        return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
    
public android.content.SyncStatusInfogetSyncStatusAsUser(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname, int userId)
If the user id supplied is different to the calling user, the caller must hold the INTERACT_ACROSS_USERS_FULL permission.

        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 callerUid = Binder.getCallingUid();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager == null) {
                return null;
            }
            SyncStorageEngine.EndPoint info;
            if (!(account == null || authority == null)) {
                info = new SyncStorageEngine.EndPoint(account, authority, userId);
            } else {
                throw new IllegalArgumentException("Must call sync status with valid authority");
            }
            return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public booleanisSyncActive(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname)

        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                "no permission to read the sync stats");
        int userId = UserHandle.getCallingUserId();
        int callingUid = Binder.getCallingUid();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager == null) {
                return false;
            }
            return syncManager.getSyncStorageEngine().isSyncActive(
                    new SyncStorageEngine.EndPoint(account, authority, userId));
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public booleanisSyncPending(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname)

        return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
    
public booleanisSyncPendingAsUser(android.accounts.Account account, java.lang.String authority, android.content.ComponentName cname, int userId)

        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                "no permission to read the sync stats");
        enforceCrossUserPermission(userId,
                "no permission to retrieve the sync settings for user " + userId);
        int callerUid = Binder.getCallingUid();
        long identityToken = clearCallingIdentity();
        SyncManager syncManager = getSyncManager();
        if (syncManager == null) return false;

        try {
            SyncStorageEngine.EndPoint info;
            if (!(account == null || authority == null)) {
                info = new SyncStorageEngine.EndPoint(account, authority, userId);
            } else {
                throw new IllegalArgumentException("Invalid authority specified");
            }
            return syncManager.getSyncStorageEngine().isSyncPending(info);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public static com.android.server.content.ContentServicemain(android.content.Context context, boolean factoryTest)

        ContentService service = new ContentService(context, factoryTest);
        ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
        return service;
    
public voidnotifyChange(android.net.Uri uri, android.database.IContentObserver observer, boolean observerWantsSelfNotifications, boolean syncToNetwork)

        notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
                UserHandle.getCallingUserId());
    
public voidnotifyChange(android.net.Uri uri, android.database.IContentObserver observer, boolean observerWantsSelfNotifications, boolean syncToNetwork, int userHandle)
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 the calling user without requiring any permission, otherwise the caller needs to hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are allowed.

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle
                    + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
        }

        // Notify for any user other than the caller's own requires permission.
        final int callingUserHandle = UserHandle.getCallingUserId();
        if (userHandle != callingUserHandle) {
            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS,
                    "no permission to notify other users");
        }

        // We passed the permission check; resolve pseudouser targets as appropriate
        if (userHandle < 0) {
            if (userHandle == UserHandle.USER_CURRENT) {
                userHandle = ActivityManager.getCurrentUser();
            } else if (userHandle != UserHandle.USER_ALL) {
                throw new InvalidParameterException("Bad user handle for notifyChange: "
                        + userHandle);
            }
        }

        final int uid = 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.
        long identityToken = clearCallingIdentity();
        try {
            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
            synchronized (mRootNode) {
                mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
                        userHandle, calls);
            }
            final int numCalls = calls.size();
            for (int i=0; i<numCalls; i++) {
                ObserverCall oc = calls.get(i);
                try {
                    oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
                        Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
                    }
                } catch (RemoteException ex) {
                    synchronized (mRootNode) {
                        Log.w(TAG, "Found dead observer, removing");
                        IBinder binder = oc.mObserver.asBinder();
                        final ArrayList<ObserverNode.ObserverEntry> list
                                = oc.mNode.mObservers;
                        int numList = list.size();
                        for (int j=0; j<numList; j++) {
                            ObserverNode.ObserverEntry oe = list.get(j);
                            if (oe.observer.asBinder() == binder) {
                                list.remove(j);
                                j--;
                                numList--;
                            }
                        }
                    }
                }
            }
            if (syncToNetwork) {
                SyncManager syncManager = getSyncManager();
                if (syncManager != null) {
                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
                            uri.getAuthority());
                }
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public booleanonTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

        try {
            return super.onTransact(code, data, reply, flags);
        } catch (RuntimeException e) {
            // The content service only throws security exceptions, so let's
            // log all others.
            if (!(e instanceof SecurityException)) {
                Slog.wtf(TAG, "Content Service Crash", e);
            }
            throw e;
        }
    
public voidregisterContentObserver(android.net.Uri uri, boolean notifyForDescendants, android.database.IContentObserver observer, int userHandle)
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 the calling user without requiring any permission, otherwise the caller needs to hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers are forbidden.

        if (observer == null || uri == null) {
            throw new IllegalArgumentException("You must pass a valid uri and observer");
        }

        enforceCrossUserPermission(userHandle,
                "no permission to observe other users' provider view");

        if (userHandle < 0) {
            if (userHandle == UserHandle.USER_CURRENT) {
                userHandle = ActivityManager.getCurrentUser();
            } else if (userHandle != UserHandle.USER_ALL) {
                throw new InvalidParameterException("Bad user handle for registerContentObserver: "
                        + userHandle);
            }
        }

        synchronized (mRootNode) {
            mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
                    Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
            if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
                    " with notifyForDescendants " + notifyForDescendants);
        }
    
public voidregisterContentObserver(android.net.Uri uri, boolean notifyForDescendants, android.database.IContentObserver observer)

        registerContentObserver(uri, notifyForDescendants, observer,
                UserHandle.getCallingUserId());
    
public voidremovePeriodicSync(android.accounts.Account account, java.lang.String authority, android.os.Bundle extras)

        if (account == null) {
            throw new IllegalArgumentException("Account must not be null");
        }
        if (TextUtils.isEmpty(authority)) {
            throw new IllegalArgumentException("Authority must not be empty");
        }
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            getSyncManager().getSyncStorageEngine()
                .removePeriodicSync(
                        new SyncStorageEngine.EndPoint(account, authority, userId),
                        extras);
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidremoveStatusChangeListener(android.content.ISyncStatusObserver callback)

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null && callback != null) {
                syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidrequestSync(android.accounts.Account account, java.lang.String authority, android.os.Bundle extras)

        ContentResolver.validateSyncExtrasBundle(extras);
        int userId = UserHandle.getCallingUserId();
        int uId = 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.
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                syncManager.scheduleSync(account, userId, uId, authority, extras,
                        0 /* no delay */, 0 /* no delay */,
                        false /* onlyThoseWithUnkownSyncableState */);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidsetIsSyncable(android.accounts.Account account, java.lang.String providerName, int syncable)

        if (TextUtils.isEmpty(providerName)) {
            throw new IllegalArgumentException("Authority must not be empty");
        }
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                syncManager.getSyncStorageEngine().setIsSyncable(
                        account, userId, providerName, syncable);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidsetMasterSyncAutomatically(boolean flag)

        setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId());
    
public voidsetMasterSyncAutomaticallyAsUser(boolean flag, int userId)

        enforceCrossUserPermission(userId,
                "no permission to set the sync status for user " + userId);
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidsetSyncAutomatically(android.accounts.Account account, java.lang.String providerName, boolean sync)

        setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
    
public voidsetSyncAutomaticallyAsUser(android.accounts.Account account, java.lang.String providerName, boolean sync, int userId)

        if (TextUtils.isEmpty(providerName)) {
            throw new IllegalArgumentException("Authority must be non-empty");
        }
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");
        enforceCrossUserPermission(userId,
                "no permission to modify the sync settings for user " + userId);

        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager != null) {
                syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
                        providerName, sync);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidsync(android.content.SyncRequest request)
Request a sync with a generic {@link android.content.SyncRequest} object. This will be either: periodic OR one-off sync. and anonymous OR provider sync. Depending on the request, we enqueue to suit in the SyncManager.

param
request The request object. Validation of this object is done by its builder.

        syncAsUser(request, UserHandle.getCallingUserId());
    
public voidsyncAsUser(android.content.SyncRequest request, int userId)
If the user id supplied is different to the calling user, the caller must hold the INTERACT_ACROSS_USERS_FULL permission.

        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.
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
            if (syncManager == null) {
                return;
            }

            Bundle extras = request.getBundle();
            long flextime = request.getSyncFlexTime();
            long runAtTime = request.getSyncRunTime();
            if (request.isPeriodic()) {
                mContext.enforceCallingOrSelfPermission(
                        Manifest.permission.WRITE_SYNC_SETTINGS,
                        "no permission to write the sync settings");
                SyncStorageEngine.EndPoint info;
                info = new SyncStorageEngine.EndPoint(
                        request.getAccount(), request.getProvider(), userId);
                if (runAtTime < 60) {
                    Slog.w(TAG, "Requested poll frequency of " + runAtTime
                            + " seconds being rounded up to 60 seconds.");
                    runAtTime = 60;
                }
                // Schedule periodic sync.
                getSyncManager().getSyncStorageEngine()
                    .updateOrAddPeriodicSync(info, runAtTime, flextime, extras);
            } else {
                long beforeRuntimeMillis = (flextime) * 1000;
                long runtimeMillis = runAtTime * 1000;
                syncManager.scheduleSync(
                        request.getAccount(), userId, callerUid, request.getProvider(), extras,
                        beforeRuntimeMillis, runtimeMillis,
                        false /* onlyThoseWithUnknownSyncableState */);
            }
        } finally {
            restoreCallingIdentity(identityToken);
        }
    
public voidsystemReady()

        getSyncManager();
    
public voidunregisterContentObserver(android.database.IContentObserver observer)

        if (observer == null) {
            throw new IllegalArgumentException("You must pass a valid observer");
        }
        synchronized (mRootNode) {
            mRootNode.removeObserverLocked(observer);
            if (false) Log.v(TAG, "Unregistered observer " + observer);
        }