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
This commit is contained in:
@ -190,10 +190,10 @@ public class AccountManagerService
|
|||||||
private final HashMap<String, Account[]> accountCache =
|
private final HashMap<String, Account[]> accountCache =
|
||||||
new LinkedHashMap<String, Account[]>();
|
new LinkedHashMap<String, Account[]>();
|
||||||
/** protected by the {@link #cacheLock} */
|
/** 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>>();
|
new HashMap<Account, HashMap<String, String>>();
|
||||||
/** protected by the {@link #cacheLock} */
|
/** 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>>();
|
new HashMap<Account, HashMap<String, String>>();
|
||||||
|
|
||||||
UserAccounts(Context context, int userId) {
|
UserAccounts(Context context, int userId) {
|
||||||
@ -475,6 +475,7 @@ public class AccountManagerService
|
|||||||
validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
|
validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getPassword(Account account) {
|
public String getPassword(Account account) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "getPassword: " + account
|
Log.v(TAG, "getPassword: " + account
|
||||||
@ -514,6 +515,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getUserData(Account account, String key) {
|
public String getUserData(Account account, String key) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "getUserData: " + account
|
Log.v(TAG, "getUserData: " + account
|
||||||
@ -533,6 +535,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public AuthenticatorDescription[] getAuthenticatorTypes() {
|
public AuthenticatorDescription[] getAuthenticatorTypes() {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "getAuthenticatorTypes: "
|
Log.v(TAG, "getAuthenticatorTypes: "
|
||||||
@ -763,6 +766,7 @@ public class AccountManagerService
|
|||||||
return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
|
return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void hasFeatures(IAccountManagerResponse response,
|
public void hasFeatures(IAccountManagerResponse response,
|
||||||
Account account, String[] features) {
|
Account account, String[] features) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
@ -840,6 +844,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void removeAccount(IAccountManagerResponse response, Account account) {
|
public void removeAccount(IAccountManagerResponse response, Account account) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "removeAccount: " + account
|
Log.v(TAG, "removeAccount: " + account
|
||||||
@ -1049,6 +1054,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String peekAuthToken(Account account, String authTokenType) {
|
public String peekAuthToken(Account account, String authTokenType) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "peekAuthToken: " + account
|
Log.v(TAG, "peekAuthToken: " + account
|
||||||
@ -1068,6 +1074,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setAuthToken(Account account, String authTokenType, String authToken) {
|
public void setAuthToken(Account account, String authTokenType, String authToken) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "setAuthToken: " + account
|
Log.v(TAG, "setAuthToken: " + account
|
||||||
@ -1087,6 +1094,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setPassword(Account account, String password) {
|
public void setPassword(Account account, String password) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "setAuthToken: " + account
|
Log.v(TAG, "setAuthToken: " + account
|
||||||
@ -1135,6 +1143,7 @@ public class AccountManagerService
|
|||||||
mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
|
mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clearPassword(Account account) {
|
public void clearPassword(Account account) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "clearPassword: " + account
|
Log.v(TAG, "clearPassword: " + account
|
||||||
@ -1152,6 +1161,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setUserData(Account account, String key, String value) {
|
public void setUserData(Account account, String key, String value) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "setUserData: " + account
|
Log.v(TAG, "setUserData: " + account
|
||||||
@ -1225,6 +1235,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
|
public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
|
||||||
final String authTokenType)
|
final String authTokenType)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
@ -1271,6 +1282,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void getAuthToken(IAccountManagerResponse response, final Account account,
|
public void getAuthToken(IAccountManagerResponse response, final Account account,
|
||||||
final String authTokenType, final boolean notifyOnAuthFailure,
|
final String authTokenType, final boolean notifyOnAuthFailure,
|
||||||
final boolean expectActivityLaunch, Bundle loginOptionsIn) {
|
final boolean expectActivityLaunch, Bundle loginOptionsIn) {
|
||||||
@ -1284,8 +1296,22 @@ public class AccountManagerService
|
|||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
if (response == null) throw new IllegalArgumentException("response is null");
|
if (response == null) throw new IllegalArgumentException("response is null");
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
try {
|
||||||
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
|
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);
|
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
|
||||||
final UserAccounts accounts = getUserAccountsForCaller();
|
final UserAccounts accounts = getUserAccountsForCaller();
|
||||||
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
|
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
|
||||||
@ -1294,11 +1320,6 @@ public class AccountManagerService
|
|||||||
final boolean customTokens =
|
final boolean customTokens =
|
||||||
authenticatorInfo != null && authenticatorInfo.type.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
|
// skip the check if customTokens
|
||||||
final int callerUid = Binder.getCallingUid();
|
final int callerUid = Binder.getCallingUid();
|
||||||
final boolean permissionGranted = customTokens ||
|
final boolean permissionGranted = customTokens ||
|
||||||
@ -1472,6 +1493,7 @@ public class AccountManagerService
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void addAccount(final IAccountManagerResponse response, final String accountType,
|
public void addAccount(final IAccountManagerResponse response, final String accountType,
|
||||||
final String authTokenType, final String[] requiredFeatures,
|
final String authTokenType, final String[] requiredFeatures,
|
||||||
final boolean expectActivityLaunch, final Bundle optionsIn) {
|
final boolean expectActivityLaunch, final Bundle optionsIn) {
|
||||||
@ -1582,6 +1604,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateCredentials(IAccountManagerResponse response, final Account account,
|
public void updateCredentials(IAccountManagerResponse response, final Account account,
|
||||||
final String authTokenType, final boolean expectActivityLaunch,
|
final String authTokenType, final boolean expectActivityLaunch,
|
||||||
final Bundle loginOptions) {
|
final Bundle loginOptions) {
|
||||||
@ -1620,6 +1643,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void editProperties(IAccountManagerResponse response, final String accountType,
|
public void editProperties(IAccountManagerResponse response, final String accountType,
|
||||||
final boolean expectActivityLaunch) {
|
final boolean expectActivityLaunch) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
@ -1657,7 +1681,7 @@ public class AccountManagerService
|
|||||||
private volatile Account[] mAccountsOfType = null;
|
private volatile Account[] mAccountsOfType = null;
|
||||||
private volatile ArrayList<Account> mAccountsWithFeatures = null;
|
private volatile ArrayList<Account> mAccountsWithFeatures = null;
|
||||||
private volatile int mCurrentAccount = 0;
|
private volatile int mCurrentAccount = 0;
|
||||||
private int mCallingUid;
|
private final int mCallingUid;
|
||||||
|
|
||||||
public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
|
public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
|
||||||
IAccountManagerResponse response, String type, String[] features, int callingUid) {
|
IAccountManagerResponse response, String type, String[] features, int callingUid) {
|
||||||
@ -1941,6 +1965,7 @@ public class AccountManagerService
|
|||||||
return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
|
return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void getAccountsByFeatures(IAccountManagerResponse response,
|
public void getAccountsByFeatures(IAccountManagerResponse response,
|
||||||
String type, String[] features) {
|
String type, String[] features) {
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
@ -2069,6 +2094,7 @@ public class AccountManagerService
|
|||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
mResponse = null;
|
mResponse = null;
|
||||||
close();
|
close();
|
||||||
@ -2112,6 +2138,7 @@ public class AccountManagerService
|
|||||||
mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
|
mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
|
mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
|
||||||
try {
|
try {
|
||||||
@ -2122,6 +2149,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
mAuthenticator = null;
|
mAuthenticator = null;
|
||||||
IAccountManagerResponse response = getResponseAndClose();
|
IAccountManagerResponse response = getResponseAndClose();
|
||||||
@ -2217,8 +2245,15 @@ public class AccountManagerService
|
|||||||
Log.v(TAG, getClass().getSimpleName()
|
Log.v(TAG, getClass().getSimpleName()
|
||||||
+ " calling onResult() on response " + response);
|
+ " 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);
|
response.onResult(result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// if the caller is dead then there is no one to care about remote exceptions
|
// if the caller is dead then there is no one to care about remote exceptions
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
@ -2228,10 +2263,12 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onRequestContinued() {
|
public void onRequestContinued() {
|
||||||
mNumRequestContinued++;
|
mNumRequestContinued++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onError(int errorCode, String errorMessage) {
|
public void onError(int errorCode, String errorMessage) {
|
||||||
mNumErrors++;
|
mNumErrors++;
|
||||||
IAccountManagerResponse response = getResponseAndClose();
|
IAccountManagerResponse response = getResponseAndClose();
|
||||||
@ -2731,6 +2768,7 @@ public class AccountManagerService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
|
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
final int callingUid = getCallingUid();
|
final int callingUid = getCallingUid();
|
||||||
|
Reference in New Issue
Block a user