DO NOT MERGE Redact Account info from getCurrentSyncs

am: a5cafd2a93

* commit 'a5cafd2a93ce1c481328e2ce25c3bf2a19b81601':
  DO NOT MERGE Redact Account info from getCurrentSyncs
This commit is contained in:
Matthew Williams
2016-01-21 18:07:55 +00:00
committed by android-build-merger
3 changed files with 61 additions and 6 deletions

View File

@@ -25,6 +25,13 @@ import android.os.Parcelable.Creator;
* Information about the sync operation that is currently underway. * Information about the sync operation that is currently underway.
*/ */
public class SyncInfo implements Parcelable { 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 */ /** @hide */
public final int authorityId; public final int authorityId;
@@ -45,6 +52,17 @@ public class SyncInfo implements Parcelable {
*/ */
public final long startTime; 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 */ /** @hide */
public SyncInfo(int authorityId, Account account, String authority, public SyncInfo(int authorityId, Account account, String authority,
long startTime) { long startTime) {

View File

@@ -28,6 +28,7 @@ import android.content.SyncAdapterType;
import android.content.SyncInfo; import android.content.SyncInfo;
import android.content.SyncRequest; import android.content.SyncRequest;
import android.content.SyncStatusInfo; import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
import android.database.IContentObserver; import android.database.IContentObserver;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.net.Uri; import android.net.Uri;
@@ -654,13 +655,26 @@ public final class ContentService extends IContentService.Stub {
} }
public List<SyncInfo> getCurrentSyncs() { 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, mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the 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(); long identityToken = clearCallingIdentity();
try { try {
return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId); return getSyncManager().getSyncStorageEngine()
.getCurrentSyncsCopy(userId, canAccessAccounts);
} finally { } finally {
restoreCallingIdentity(identityToken); restoreCallingIdentity(identityToken);
} }
@@ -734,6 +748,21 @@ public final class ContentService extends IContentService.Stub {
return service; 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, * Hide this class since it is not part of api,
* but current unittest framework requires it to be public * but current unittest framework requires it to be public

View File

@@ -1306,15 +1306,23 @@ public class SyncStorageEngine extends Handler {
} }
/** /**
* @return a copy of the current syncs data structure. Will not return * @param userId Id of user to return current sync info.
* null. * @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) { synchronized (mAuthorities) {
final List<SyncInfo> syncs = getCurrentSyncsLocked(userId); final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>(); final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
for (SyncInfo sync : syncs) { 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; return syncsCopy;
} }