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

Commit a7dd87ce authored by Dmitry Dementyev's avatar Dmitry Dementyev Committed by android-build-merger
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
am: d4011635

Change-Id: Ia6c1d5008ed4884f7214d589f1d2b4e02413cf8e
parents e7534f48 d4011635
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;
    }

    /**