summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matthew Williams <mjwilliams@google.com> 2016-01-21 18:07:55 +0000
committer android-build-merger <android-build-merger@google.com> 2016-01-21 18:07:55 +0000
commit06ef7dfdf0a3efb44326228c55309ec6df134376 (patch)
tree36cad5c46755b9bb870827f83b0cf587309610fa
parent294611faa8bd1bdbf75adc3cee835b69d348df86 (diff)
parenta5cafd2a93ce1c481328e2ce25c3bf2a19b81601 (diff)
DO NOT MERGE Redact Account info from getCurrentSyncs
am: a5cafd2a93 * commit 'a5cafd2a93ce1c481328e2ce25c3bf2a19b81601': DO NOT MERGE Redact Account info from getCurrentSyncs
-rw-r--r--core/java/android/content/SyncInfo.java18
-rw-r--r--services/java/com/android/server/content/ContentService.java33
-rw-r--r--services/java/com/android/server/content/SyncStorageEngine.java16
3 files changed, 61 insertions, 6 deletions
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index cffc653e44ef..51292c4ad1e1 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -25,6 +25,13 @@ import android.os.Parcelable.Creator;
* Information about the sync operation that is currently underway.
*/
public class SyncInfo implements Parcelable {
+ /**
+ * Used when the caller receiving this object doesn't have permission to access the accounts
+ * on device.
+ * @See Manifest.permission.GET_ACCOUNTS
+ */
+ private static final Account REDACTED_ACCOUNT = new Account("*****", "*****");
+
/** @hide */
public final int authorityId;
@@ -45,6 +52,17 @@ public class SyncInfo implements Parcelable {
*/
public final long startTime;
+ /**
+ * Creates a SyncInfo object with an unusable Account. Used when the caller receiving this
+ * object doesn't have access to the accounts on the device.
+ * @See Manifest.permission.GET_ACCOUNTS
+ * @hide
+ */
+ public static SyncInfo createAccountRedacted(
+ int authorityId, String authority, long startTime) {
+ return new SyncInfo(authorityId, REDACTED_ACCOUNT, authority, startTime);
+ }
+
/** @hide */
public SyncInfo(int authorityId, Account account, String authority,
long startTime) {
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 023bf2b20614..3c4e07b1b19a 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -28,6 +28,7 @@ import android.content.SyncAdapterType;
import android.content.SyncInfo;
import android.content.SyncRequest;
import android.content.SyncStatusInfo;
+import android.content.pm.PackageManager;
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
@@ -654,13 +655,26 @@ 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();
+ final boolean canAccessAccounts =
+ mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
+ == PackageManager.PERMISSION_GRANTED;
long identityToken = clearCallingIdentity();
try {
- return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
+ return getSyncManager().getSyncStorageEngine()
+ .getCurrentSyncsCopy(userId, canAccessAccounts);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -735,6 +749,21 @@ public final class ContentService extends IContentService.Stub {
}
/**
+ * 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
* @hide
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 781280ed69bc..2a57f9e91430 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -1306,15 +1306,23 @@ public class SyncStorageEngine extends Handler {
}
/**
- * @return a copy of the current syncs data structure. Will not return
- * null.
+ * @param userId Id of user to return current sync info.
+ * @param canAccessAccounts Determines whether to redact Account information from the result.
+ * @return a copy of the current syncs data structure. Will not return null.
*/
- public List<SyncInfo> getCurrentSyncsCopy(int userId) {
+ public List<SyncInfo> getCurrentSyncsCopy(int userId, boolean canAccessAccounts) {
synchronized (mAuthorities) {
final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
for (SyncInfo sync : syncs) {
- syncsCopy.add(new SyncInfo(sync));
+ SyncInfo copy;
+ if (!canAccessAccounts) {
+ copy = SyncInfo.createAccountRedacted(
+ sync.authorityId, sync.authority, sync.startTime);
+ } else {
+ copy = new SyncInfo(sync);
+ }
+ syncsCopy.add(copy);
}
return syncsCopy;
}