diff options
author | 2017-04-10 18:30:47 +0000 | |
---|---|---|
committer | 2017-04-10 18:30:53 +0000 | |
commit | d4011635995d6f0b8975e65a3bfa95d4f10f0606 (patch) | |
tree | ce6e4e60cd0ae13696b4cfbd0243ec6ae08e1f0d | |
parent | c922c4827a94fe436d2005c63e8b8d51a6bbb159 (diff) | |
parent | d6f0672e883f506c965ce6a05c9acdfa375af9e6 (diff) |
Merge "Make visible only accounts for which authenticator supports contacts operations for callers with READ_CONTACTS permission." into oc-dev
-rw-r--r-- | core/java/android/accounts/AccountManager.java | 18 | ||||
-rw-r--r-- | services/core/java/com/android/server/accounts/AccountManagerService.java | 52 |
2 files changed, 54 insertions, 16 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 2a2fdbd272d3..80522886c78f 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -364,11 +364,19 @@ public class AccountManager { "android.accounts.key_legacy_visible"; /** - * Key to set visibility for applications targeting API level below - * {@link android.os.Build.VERSION_CODES#O} with - * {@link android.Manifest.permission#GET_ACCOUNTS} permission, or applications with any - * targeting API level with the same signature as authenticator. See - * {@link #getAccountVisibility}. If the value was not set by authenticator + * Key to set visibility for applications which satisfy one of the following conditions: + * <ul> + * <li>Target API level below {@link android.os.Build.VERSION_CODES#O} and have + * deprecated {@link android.Manifest.permission#GET_ACCOUNTS} permission. + * </li> + * <li> Have {@link android.Manifest.permission#GET_ACCOUNTS_PRIVILEGED} permission. </li> + * <li> Have the same signature as authenticator. </li> + * <li> Have {@link android.Manifest.permission#READ_CONTACTS} permission and + * account type may be associated with contacts data - (verified by + * {@link android.Manifest.permission#WRITE_CONTACTS} permission check for the authenticator). + * </li> + * </ul> + * See {@link #getAccountVisibility}. If the value was not set by authenticator * {@link #VISIBILITY_USER_MANAGED_VISIBLE} is used. */ public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 738365d5b36f..5f585cc799c9 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -652,20 +652,20 @@ public class AccountManagerService return visibility; } - boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId, + boolean isPrivileged = isPermittedForPackage(packageName, uid, accounts.userId, Manifest.permission.GET_ACCOUNTS_PRIVILEGED); // Device/Profile owner gets visibility by default. if (isProfileOwner(uid)) { return AccountManager.VISIBILITY_VISIBLE; } - // Apps with READ_CONTACTS permission get visibility by default even post O. - boolean canReadContacts = checkReadContactsPermission(packageName, accounts.userId); boolean preO = isPreOApplication(packageName); if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH) - || (preO && checkGetAccountsPermission(packageName, accounts.userId)) - || canReadContacts || isPrivileged) { + || (preO && checkGetAccountsPermission(packageName, uid, accounts.userId)) + || (checkReadContactsPermission(packageName, uid, accounts.userId) + && accountTypeManagesContacts(account.type, accounts.userId)) + || isPrivileged) { // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature // match. visibility = getAccountVisibilityFromCache(account, @@ -5022,14 +5022,20 @@ public class AccountManagerService } } - private boolean isPermittedForPackage(String packageName, int userId, String... permissions) { + private boolean isPermittedForPackage(String packageName, int uid, int userId, + String... permissions) { final long identity = Binder.clearCallingIdentity(); try { IPackageManager pm = ActivityThread.getPackageManager(); for (String perm : permissions) { if (pm.checkPermission(perm, packageName, userId) == PackageManager.PERMISSION_GRANTED) { - return true; + // Checks runtime permission revocation. + final int opCode = AppOpsManager.permissionToOpCode(perm); + if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp( + opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) { + return true; + } } } } catch (RemoteException e) { @@ -5145,13 +5151,37 @@ public class AccountManagerService // Method checks visibility for applications targeing API level below {@link // android.os.Build.VERSION_CODES#O}, // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission. - private boolean checkGetAccountsPermission(String packageName, int userId) { - return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS, + private boolean checkGetAccountsPermission(String packageName, int uid, int userId) { + return isPermittedForPackage(packageName, uid, userId, Manifest.permission.GET_ACCOUNTS, Manifest.permission.GET_ACCOUNTS_PRIVILEGED); } - private boolean checkReadContactsPermission(String packageName, int userId) { - return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS); + private boolean checkReadContactsPermission(String packageName, int uid, int userId) { + return isPermittedForPackage(packageName, uid, userId, Manifest.permission.READ_CONTACTS); + } + + // Heuristic to check that account type may be associated with some contacts data and + // therefore READ_CONTACTS permission grants the access to account by default. + private boolean accountTypeManagesContacts(String accountType, int userId) { + if (accountType == null) { + return false; + } + long identityToken = Binder.clearCallingIdentity(); + Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos; + try { + serviceInfos = mAuthenticatorCache.getAllServices(userId); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + // Check contacts related permissions for authenticator. + for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo + : serviceInfos) { + if (accountType.equals(serviceInfo.type.type)) { + return isPermittedForPackage(serviceInfo.type.packageName, serviceInfo.uid, userId, + Manifest.permission.WRITE_CONTACTS); + } + } + return false; } /** |