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

Commit 09e7e0ef authored by Jatin Lodhia's avatar Jatin Lodhia
Browse files

Delegate existence of account check to Authenticator.

Current AccountManager code for getAuthToken checks if the account
in the request exists. If the account does not exist then it throws
an exception which leads to a runtime exception being thrown by
AccountManager in the client. In perticular, Checkin client code
hits this issue when accounts are deleted by user. As the exception
is thrown from the getAuthToken method call and is a RuntimeException
it is not caught by the client. Futhermore, Checkin runs in one of the
important processes and this exception makes the process crash.

This cl, does the following:
1) Delegates the account exists check to Authentictor which in turn
would cause an AuthenticatorException which is a checked exception.
2) Replaces some of the runtime exceptions thrown by AccountManagerService
with calling AccountManagerResponse.onError() which causes more graceful
failure on the client.
3) Correctly passes on the error returned by Authenticator to
AccountManager. Earlier if Authenticator returned an error code to
the AccountManager, it ignored the error and returned null token to the
client which was incorrect.

Bug: 10856295
Change-Id: Ie250fec601d46f6dfecd74677b478bfd4e9dcfad
parent fed822cb
Loading
Loading
Loading
Loading
+49 −11
Original line number Diff line number Diff line
@@ -190,10 +190,10 @@ public class AccountManagerService
        private final HashMap<String, Account[]> accountCache =
                new LinkedHashMap<String, Account[]>();
        /** protected by the {@link #cacheLock} */
        private HashMap<Account, HashMap<String, String>> userDataCache =
        private final HashMap<Account, HashMap<String, String>> userDataCache =
                new HashMap<Account, HashMap<String, String>>();
        /** protected by the {@link #cacheLock} */
        private HashMap<Account, HashMap<String, String>> authTokenCache =
        private final HashMap<Account, HashMap<String, String>> authTokenCache =
                new HashMap<Account, HashMap<String, String>>();

        UserAccounts(Context context, int userId) {
@@ -475,6 +475,7 @@ public class AccountManagerService
        validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
    }

    @Override
    public String getPassword(Account account) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "getPassword: " + account
@@ -514,6 +515,7 @@ public class AccountManagerService
        }
    }

    @Override
    public String getUserData(Account account, String key) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "getUserData: " + account
@@ -533,6 +535,7 @@ public class AccountManagerService
        }
    }

    @Override
    public AuthenticatorDescription[] getAuthenticatorTypes() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "getAuthenticatorTypes: "
@@ -763,6 +766,7 @@ public class AccountManagerService
        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
    }

    @Override
    public void hasFeatures(IAccountManagerResponse response,
            Account account, String[] features) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -840,6 +844,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void removeAccount(IAccountManagerResponse response, Account account) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "removeAccount: " + account
@@ -1049,6 +1054,7 @@ public class AccountManagerService
        }
    }

    @Override
    public String peekAuthToken(Account account, String authTokenType) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "peekAuthToken: " + account
@@ -1068,6 +1074,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void setAuthToken(Account account, String authTokenType, String authToken) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "setAuthToken: " + account
@@ -1087,6 +1094,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void setPassword(Account account, String password) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "setAuthToken: " + account
@@ -1135,6 +1143,7 @@ public class AccountManagerService
        mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
    }

    @Override
    public void clearPassword(Account account) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "clearPassword: " + account
@@ -1152,6 +1161,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void setUserData(Account account, String key, String value) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "setUserData: " + account
@@ -1225,6 +1235,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
                                  final String authTokenType)
            throws RemoteException {
@@ -1271,6 +1282,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void getAuthToken(IAccountManagerResponse response, final Account account,
            final String authTokenType, final boolean notifyOnAuthFailure,
            final boolean expectActivityLaunch, Bundle loginOptionsIn) {
@@ -1284,8 +1296,22 @@ public class AccountManagerService
                    + ", pid " + Binder.getCallingPid());
        }
        if (response == null) throw new IllegalArgumentException("response is null");
        if (account == null) throw new IllegalArgumentException("account is null");
        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
        try {
            if (account == null) {
                Slog.w(TAG, "getAuthToken called with null account");
                response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
                return;
            }
            if (authTokenType == null) {
                Slog.w(TAG, "getAuthToken called with null authTokenType");
                response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
                return;
            }
        } catch (RemoteException e) {
            Slog.w(TAG, "Failed to report error back to the client." + e);
            return;
        }

        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
        final UserAccounts accounts = getUserAccountsForCaller();
        final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
@@ -1294,11 +1320,6 @@ public class AccountManagerService
        final boolean customTokens =
            authenticatorInfo != null && authenticatorInfo.type.customTokens;

        // Check to see that the app is authorized to access the account, in case it's a
        // restricted account.
        if (!ArrayUtils.contains(getAccounts((String) null), account)) {
            throw new IllegalArgumentException("no such account");
        }
        // skip the check if customTokens
        final int callerUid = Binder.getCallingUid();
        final boolean permissionGranted = customTokens ||
@@ -1472,6 +1493,7 @@ public class AccountManagerService
        return id;
    }

    @Override
    public void addAccount(final IAccountManagerResponse response, final String accountType,
            final String authTokenType, final String[] requiredFeatures,
            final boolean expectActivityLaunch, final Bundle optionsIn) {
@@ -1582,6 +1604,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void updateCredentials(IAccountManagerResponse response, final Account account,
            final String authTokenType, final boolean expectActivityLaunch,
            final Bundle loginOptions) {
@@ -1620,6 +1643,7 @@ public class AccountManagerService
        }
    }

    @Override
    public void editProperties(IAccountManagerResponse response, final String accountType,
            final boolean expectActivityLaunch) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1657,7 +1681,7 @@ public class AccountManagerService
        private volatile Account[] mAccountsOfType = null;
        private volatile ArrayList<Account> mAccountsWithFeatures = null;
        private volatile int mCurrentAccount = 0;
        private int mCallingUid;
        private final int mCallingUid;

        public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
                IAccountManagerResponse response, String type, String[] features, int callingUid) {
@@ -1941,6 +1965,7 @@ public class AccountManagerService
        return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
    }

    @Override
    public void getAccountsByFeatures(IAccountManagerResponse response,
            String type, String[] features) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2069,6 +2094,7 @@ public class AccountManagerService
            unbind();
        }

        @Override
        public void binderDied() {
            mResponse = null;
            close();
@@ -2112,6 +2138,7 @@ public class AccountManagerService
            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
            try {
@@ -2122,6 +2149,7 @@ public class AccountManagerService
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mAuthenticator = null;
            IAccountManagerResponse response = getResponseAndClose();
@@ -2217,8 +2245,15 @@ public class AccountManagerService
                            Log.v(TAG, getClass().getSimpleName()
                                    + " calling onResult() on response " + response);
                        }
                        if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
                                (intent == null)) {
                            // All AccountManager error codes are greater than 0
                            response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
                                    result.getString(AccountManager.KEY_ERROR_MESSAGE));
                        } else {
                            response.onResult(result);
                        }
                    }
                } catch (RemoteException e) {
                    // if the caller is dead then there is no one to care about remote exceptions
                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2228,10 +2263,12 @@ public class AccountManagerService
            }
        }

        @Override
        public void onRequestContinued() {
            mNumRequestContinued++;
        }

        @Override
        public void onError(int errorCode, String errorMessage) {
            mNumErrors++;
            IAccountManagerResponse response = getResponseAndClose();
@@ -2731,6 +2768,7 @@ public class AccountManagerService
        return true;
    }

    @Override
    public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
            throws RemoteException {
        final int callingUid = getCallingUid();