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

Commit 632515b9 authored by Matthew Williams's avatar Matthew Williams
Browse files

Fix infinite boot-loop bug in SM.

Bug:11064918
If the ContentResolver sync API is used with the empty ("")
string as a provider, the ContentService will throw an RTE.
This cl addresses all the entry points of the API that could
allow this, as well as adds an ifEmpty check at the point of
failure.
Also removed RTE throws from public functions(no point in
crashing the phone).

Change-Id: I57427d12a6cafb3e6d7a32ca0c10b05315b20580
parent 9dc7e12c
Loading
Loading
Loading
Loading
+0 −18
Original line number Diff line number Diff line
@@ -1914,12 +1914,6 @@ public abstract class ContentResolver {
    public static void addPeriodicSync(Account account, String authority, Bundle extras,
            long pollFrequency) {
        validateSyncExtrasBundle(extras);
        if (account == null) {
            throw new IllegalArgumentException("account must not be null");
        }
        if (authority == null) {
            throw new IllegalArgumentException("authority must not be null");
        }
        if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
                || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
                || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
@@ -1949,12 +1943,6 @@ public abstract class ContentResolver {
     */
    public static void removePeriodicSync(Account account, String authority, Bundle extras) {
        validateSyncExtrasBundle(extras);
        if (account == null) {
            throw new IllegalArgumentException("account must not be null");
        }
        if (authority == null) {
            throw new IllegalArgumentException("authority must not be null");
        }
        try {
            getContentService().removePeriodicSync(account, authority, extras);
        } catch (RemoteException e) {
@@ -1972,12 +1960,6 @@ public abstract class ContentResolver {
     * @return a list of PeriodicSync objects. This list may be empty but will never be null.
     */
    public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
        if (account == null) {
            throw new IllegalArgumentException("account must not be null");
        }
        if (authority == null) {
            throw new IllegalArgumentException("authority must not be null");
        }
        try {
            return getContentService().getPeriodicSyncs(account, authority);
        } catch (RemoteException e) {
+3 −0
Original line number Diff line number Diff line
@@ -408,6 +408,9 @@ public class SyncRequest implements Parcelable {
            if (mSyncTarget != SYNC_TARGET_UNKNOWN) {
                throw new IllegalArgumentException("Sync target has already been defined.");
            }
            if (authority != null && authority.length() == 0) {
                throw new IllegalArgumentException("Authority must be non-empty");
            }
            mSyncTarget = SYNC_TARGET_ADAPTER;
            mAccount = account;
            mAuthority = authority;
+45 −18
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -342,13 +343,11 @@ public final class ContentService extends IContentService.Stub {
     * and
     *   anonymous OR provider sync.
     * Depending on the request, we enqueue to suit in the SyncManager.
     * @param request
     * @param request The request object. Validation of this object is done by its builder.
     */
    @Override
    public void sync(SyncRequest request) {
        Bundle extras = request.getBundle();
        ContentResolver.validateSyncExtrasBundle(extras);

        long flextime = request.getSyncFlexTime();
        long runAtTime = request.getSyncRunTime();
        int userId = UserHandle.getCallingUserId();
@@ -401,8 +400,11 @@ public final class ContentService extends IContentService.Stub {
     */
    @Override
    public void cancelSync(Account account, String authority) {
        int userId = UserHandle.getCallingUserId();
        if (authority != null && authority.length() == 0) {
            throw new IllegalArgumentException("Authority must be non-empty");
        }

        int userId = UserHandle.getCallingUserId();
        // 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();
@@ -439,8 +441,8 @@ public final class ContentService extends IContentService.Stub {
    public boolean getSyncAutomatically(Account account, String providerName) {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                "no permission to read the sync settings");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
@@ -456,10 +458,13 @@ public final class ContentService extends IContentService.Stub {

    @Override
    public void setSyncAutomatically(Account account, String providerName, boolean sync) {
        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");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
@@ -472,16 +477,20 @@ public final class ContentService extends IContentService.Stub {
        }
    }

    /**
     * Old API. Schedule periodic sync with default flex time.
     */
    /** Old API. Schedule periodic sync with default flex time. */
    @Override
    public void addPeriodicSync(Account account, String authority, Bundle extras,
            long pollFrequency) {
        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();

        int userId = UserHandle.getCallingUserId();
        if (pollFrequency < 60) {
            Slog.w(TAG, "Requested poll frequency of " + pollFrequency
                    + " seconds being rounded up to 60 seconds.");
@@ -503,10 +512,16 @@ public final class ContentService extends IContentService.Stub {

    @Override
    public void removePeriodicSync(Account account, String authority, 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();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            PeriodicSync syncToRemove = new PeriodicSync(account, authority, extras,
@@ -527,10 +542,16 @@ public final class ContentService extends IContentService.Stub {

    @Override
    public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
        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();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
@@ -560,10 +581,13 @@ public final class ContentService extends IContentService.Stub {

    @Override
    public void setIsSyncable(Account account, 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();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
@@ -580,8 +604,8 @@ public final class ContentService extends IContentService.Stub {
    public boolean getMasterSyncAutomatically() {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                "no permission to read the sync settings");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
@@ -598,8 +622,8 @@ public final class ContentService extends IContentService.Stub {
    public void setMasterSyncAutomatically(boolean flag) {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
@@ -632,8 +656,8 @@ public final class ContentService extends IContentService.Stub {
    public List<SyncInfo> getCurrentSyncs() {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                "no permission to read the sync stats");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
@@ -643,10 +667,13 @@ public final class ContentService extends IContentService.Stub {
    }

    public SyncStatusInfo getSyncStatus(Account account, String authority) {
        if (TextUtils.isEmpty(authority)) {
            throw new IllegalArgumentException("Authority must not be empty");
        }
        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                "no permission to read the sync stats");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
@@ -663,8 +690,8 @@ public final class ContentService extends IContentService.Stub {
    public boolean isSyncPending(Account account, String authority) {
        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                "no permission to read the sync stats");
        int userId = UserHandle.getCallingUserId();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
+6 −2
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.os.WorkSource;
import android.provider.Settings;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
@@ -2009,8 +2010,11 @@ public class SyncManager {
            for (Pair<AuthorityInfo, SyncStatusInfo> info : infos) {
                final AuthorityInfo authorityInfo = info.first;
                final SyncStatusInfo status = info.second;
                // skip the sync if the account of this operation no longer
                // exists
                if (TextUtils.isEmpty(authorityInfo.authority)) {
                    Log.e(TAG, "Got an empty provider string. Skipping: " + authorityInfo);
                    continue;
                }
                // skip the sync if the account of this operation no longer exists
                if (!containsAccountAndUser(
                        accounts, authorityInfo.account, authorityInfo.userId)) {
                    continue;
+2 −2
Original line number Diff line number Diff line
@@ -1357,12 +1357,12 @@ public class SyncStorageEngine extends Handler {
     *
     * @param account the account we want to check
     * @param authority the authority whose row should be selected
     * @return the SyncStatusInfo for the authority
     * @return the SyncStatusInfo for the authority or null if none found.
     */
    public SyncStatusInfo getStatusByAccountAndAuthority(Account account, int userId,
            String authority) {
        if (account == null || authority == null) {
          throw new IllegalArgumentException();
          return null;
        }
        synchronized (mAuthorities) {
            final int N = mSyncStatus.size();
Loading