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

Commit d4011635 authored by Dmitry Dementyev's avatar Dmitry Dementyev Committed by Android (Google) Code Review
Browse files

Merge "Make visible only accounts for which authenticator supports contacts...

Merge "Make visible only accounts for which authenticator supports contacts operations for callers with READ_CONTACTS permission." into oc-dev
parents c922c482 d6f0672e
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -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 =
+41 −11
Original line number Diff line number Diff line
@@ -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,16 +5022,22 @@ 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) {
                    // 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) {
            /* ignore - local call */
        } finally {
@@ -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;
    }

    /**