resolved conflicts for merge of 94b51810 to master
Change-Id: Ida818f066b66c356a84c80e5eab0a4e2cf4ebd49
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 40e8d39..656597e 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1922,13 +1922,13 @@
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 (invalidPeriodicExtras(extras)) {
+ if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
+ || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
+ || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
+ || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
+ || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
+ || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
+ || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
throw new IllegalArgumentException("illegal extras were set");
}
try {
@@ -1971,12 +1971,6 @@
*/
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) {
@@ -2019,12 +2013,6 @@
* @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, null);
} catch (RemoteException e) {
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 201a8b3..db88680 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -454,6 +454,9 @@
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;
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 48b3259..11c3fa0 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -42,6 +42,7 @@
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;
@@ -344,12 +345,9 @@
* 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.
*/
public void sync(SyncRequest request) {
- Bundle extras = request.getBundle();
- ContentResolver.validateSyncExtrasBundle(extras);
-
int userId = UserHandle.getCallingUserId();
int callerUid = Binder.getCallingUid();
// This makes it so that future permission checks will be in the context of this
@@ -357,8 +355,11 @@
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager == null) return;
+ if (syncManager == null) {
+ return;
+ }
+ Bundle extras = request.getBundle();
long flextime = request.getSyncFlexTime();
long runAtTime = request.getSyncRunTime();
if (request.isPeriodic()) {
@@ -412,9 +413,13 @@
* null.
* @param cname cancel syncs running on this service, or null for provider/account.
*/
+ @Override
public void cancelSync(Account account, String authority, ComponentName cname) {
- 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();
@@ -491,8 +496,8 @@
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();
@@ -508,10 +513,13 @@
@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();
@@ -525,12 +533,19 @@
}
/** 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.");
@@ -553,10 +568,16 @@
}
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 {
getSyncManager().getSyncStorageEngine()
@@ -568,13 +589,20 @@
}
}
+
public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
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();
- int callerUid = Binder.getCallingUid();
+ int callerUid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
if (cname == null) {
@@ -611,10 +639,13 @@
}
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();
@@ -670,8 +701,8 @@
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();
@@ -688,8 +719,8 @@
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();
@@ -729,8 +760,8 @@
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);
@@ -740,8 +771,12 @@
}
public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
+ 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 callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
@@ -768,8 +803,9 @@
public boolean isSyncPending(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
- int userId = UserHandle.getCallingUserId();
+
int callerUid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
SyncManager syncManager = getSyncManager();
if (syncManager == null) return false;
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 5c0f902..18bf115 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -68,6 +68,7 @@
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;
@@ -2149,6 +2150,13 @@
for (Pair<AuthorityInfo, SyncStatusInfo> info : infos) {
final AuthorityInfo authorityInfo = info.first;
final SyncStatusInfo status = info.second;
+
+ if (TextUtils.isEmpty(authorityInfo.target.provider)) {
+ Log.e(TAG, "Got an empty provider string. Skipping: "
+ + authorityInfo.target.provider);
+ continue;
+ }
+
if (!isDispatchable(authorityInfo.target)) {
continue;
}
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 1d8ca5a..1227374 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -1486,9 +1486,9 @@
*/
public SyncStatusInfo getStatusByAuthority(EndPoint info) {
if (info.target_provider && (info.account == null || info.provider == null)) {
- throw new IllegalArgumentException();
+ return null;
} else if (info.target_service && info.service == null) {
- throw new IllegalArgumentException();
+ return null;
}
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index 0354ffd..70fd810 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -825,6 +825,61 @@
assertEquals(0, engine.getIsSyncable(account, 0, "other3"));
assertEquals(1, engine.getIsSyncable(account, 0, "other4"));
}
+
+ /**
+ * Verify that the API cannot cause a run-time reboot by passing in the empty string as an
+ * authority. The problem here is that
+ * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register
+ * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}.
+ * This is not strictly a SSE test, but it does depend on the SSE data structures.
+ */
+ @SmallTest
+ public void testExpectedIllegalArguments() throws Exception {
+ try {
+ ContentResolver.setSyncAutomatically(account1, "", true);
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L);
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY);
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.cancelSync(account1, "");
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.setIsSyncable(account1, "", 0);
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.cancelSync(account1, "");
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.requestSync(account1, "", Bundle.EMPTY);
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ ContentResolver.getSyncStatus(account1, "");
+ fail("empty provider string should throw IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {}
+
+ // Make sure we aren't blocking null account/provider for those functions that use it
+ // to specify ALL accounts/providers.
+ ContentResolver.requestSync(null, null, Bundle.EMPTY);
+ ContentResolver.cancelSync(null, null);
+ }
}
class TestContext extends ContextWrapper {