summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sandra Kwan <sandrakwan@google.com> 2016-01-25 18:40:51 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2016-01-25 18:40:51 +0000
commit1ebdb21753ebb2db559f453b643ae84928ab566c (patch)
tree538134051e7f6935edffea8f8bdb5377818f299c
parent76c70c8f5cefe35c99eab08af8d3a46146ddb2dd (diff)
parent0b84b456a79d83527665a5ac399cba73f1a85821 (diff)
Merge "AccountManager: add finishSessionAsUser api."
-rw-r--r--api/system-current.txt1
-rw-r--r--core/java/android/accounts/AccountManager.java71
-rw-r--r--core/java/android/accounts/IAccountManager.aidl6
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java39
4 files changed, 95 insertions, 22 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 0b31525963a1..783524934144 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2903,6 +2903,7 @@ package android.accounts {
method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+ method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public static android.accounts.AccountManager get(android.content.Context);
method public android.accounts.Account[] getAccounts();
method public android.accounts.Account[] getAccountsByType(java.lang.String);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 259f0dac5492..1d9e3bb4b4bb 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -592,6 +592,7 @@ public class AccountManager {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
return new Future2Task<String>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
}
@@ -637,9 +638,11 @@ public class AccountManager {
if (account == null) throw new IllegalArgumentException("account is null");
if (features == null) throw new IllegalArgumentException("features is null");
return new Future2Task<Boolean>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
}
+ @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -689,10 +692,12 @@ public class AccountManager {
AccountManagerCallback<Account[]> callback, Handler handler) {
if (type == null) throw new IllegalArgumentException("type is null");
return new Future2Task<Account[]>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.getAccountsByFeatures(mResponse, type, features,
mContext.getOpPackageName());
}
+ @Override
public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_ACCOUNTS)) {
throw new AuthenticatorException("no result in response");
@@ -971,6 +976,7 @@ public class AccountManager {
if (userHandle == null)
throw new IllegalArgumentException("userHandle is null");
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccountAsUser(mResponse, account, activity != null,
userHandle.getIdentifier());
@@ -1051,7 +1057,7 @@ public class AccountManager {
* is needed for those platforms. See docs for this function in API level 22.
*
* @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
- * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
+ * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
* @return The cached auth token for this account and type, or null if
* no auth token is cached or the account does not exist.
* @see #getAuthToken
@@ -1245,7 +1251,7 @@ public class AccountManager {
* tokens to access Gmail and Google Calendar for the same account.
*
* <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
- * USE_CREDENTIALS permission is needed for those platforms. See docs for
+ * USE_CREDENTIALS permission is needed for those platforms. See docs for
* this function in API level 22.
*
* <p>This method may be called from any thread, but the returned
@@ -1295,6 +1301,7 @@ public class AccountManager {
}
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.getAuthToken(mResponse, account, authTokenType,
false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
@@ -1412,7 +1419,7 @@ public class AccountManager {
* {@link AccountManagerFuture} must not be used on the main thread.
*
* <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
- * USE_CREDENTIALS permission is needed for those platforms. See docs for
+ * USE_CREDENTIALS permission is needed for those platforms. See docs for
* this function in API level 22.
*
* @param account The account to fetch an auth token for
@@ -1463,6 +1470,7 @@ public class AccountManager {
}
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(null, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.getAuthToken(mResponse, account, authTokenType,
notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
@@ -1478,7 +1486,7 @@ public class AccountManager {
*
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
- *
+ *
* <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
* MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
* this function in API level 22.
@@ -1532,6 +1540,7 @@ public class AccountManager {
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.addAccount(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn);
@@ -1556,6 +1565,7 @@ public class AccountManager {
optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.addAccountAsUser(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
@@ -1732,6 +1742,7 @@ public class AccountManager {
if (account == null) throw new IllegalArgumentException("account is null");
final int userId = userHandle.getIdentifier();
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
userId);
@@ -1794,6 +1805,7 @@ public class AccountManager {
final Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.updateCredentials(mResponse, account, authTokenType, activity != null,
options);
@@ -1847,6 +1859,7 @@ public class AccountManager {
final Handler handler) {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.editProperties(mResponse, accountType, activity != null);
}
@@ -1886,6 +1899,7 @@ public class AccountManager {
final AccountManagerFuture<Bundle> future) {
handler = handler == null ? mMainHandler : handler;
handler.post(new Runnable() {
+ @Override
public void run() {
callback.run(future);
}
@@ -1900,6 +1914,7 @@ public class AccountManager {
System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
handler = (handler == null) ? mMainHandler : handler;
handler.post(new Runnable() {
+ @Override
public void run() {
try {
listener.onAccountsUpdated(accountsCopy);
@@ -1919,6 +1934,7 @@ public class AccountManager {
final Activity mActivity;
public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
super(new Callable<Bundle>() {
+ @Override
public Bundle call() throws Exception {
throw new IllegalStateException("this should never be called");
}
@@ -1939,6 +1955,7 @@ public class AccountManager {
return this;
}
+ @Override
protected void set(Bundle bundle) {
// TODO: somehow a null is being set as the result of the Future. Log this
// case to help debug where this is occurring. When this bug is fixed this
@@ -1989,16 +2006,19 @@ public class AccountManager {
throw new OperationCanceledException();
}
+ @Override
public Bundle getResult()
throws OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(null, null);
}
+ @Override
public Bundle getResult(long timeout, TimeUnit unit)
throws OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(timeout, unit);
}
+ @Override
protected void done() {
if (mCallback != null) {
postToHandler(mHandler, mCallback, this);
@@ -2007,6 +2027,7 @@ public class AccountManager {
/** Handles the responses from the AccountManager */
private class Response extends IAccountManagerResponse.Stub {
+ @Override
public void onResult(Bundle bundle) {
Intent intent = bundle.getParcelable(KEY_INTENT);
if (intent != null && mActivity != null) {
@@ -2026,6 +2047,7 @@ public class AccountManager {
}
}
+ @Override
public void onError(int code, String message) {
if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
|| code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
@@ -2046,6 +2068,7 @@ public class AccountManager {
public BaseFutureTask(Handler handler) {
super(new Callable<T>() {
+ @Override
public T call() throws Exception {
throw new IllegalStateException("this should never be called");
}
@@ -2072,6 +2095,7 @@ public class AccountManager {
}
protected class Response extends IAccountManagerResponse.Stub {
+ @Override
public void onResult(Bundle bundle) {
try {
T result = bundleToResult(bundle);
@@ -2088,6 +2112,7 @@ public class AccountManager {
onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
}
+ @Override
public void onError(int code, String message) {
if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
|| code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
@@ -2109,9 +2134,11 @@ public class AccountManager {
mCallback = callback;
}
+ @Override
protected void done() {
if (mCallback != null) {
postRunnableToHandler(new Runnable() {
+ @Override
public void run() {
mCallback.run(Future2Task.this);
}
@@ -2162,11 +2189,13 @@ public class AccountManager {
throw new OperationCanceledException();
}
+ @Override
public T getResult()
throws OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(null, null);
}
+ @Override
public T getResult(long timeout, TimeUnit unit)
throws OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(timeout, unit);
@@ -2218,9 +2247,11 @@ public class AccountManager {
final AccountManagerCallback<Bundle> mMyCallback;
private volatile int mNumAccounts = 0;
+ @Override
public void doWork() throws RemoteException {
getAccountsByTypeAndFeatures(mAccountType, mFeatures,
new AccountManagerCallback<Account[]>() {
+ @Override
public void run(AccountManagerFuture<Account[]> future) {
Account[] accounts;
try {
@@ -2271,6 +2302,7 @@ public class AccountManager {
if (mActivity != null) {
IAccountManagerResponse chooseResponse =
new IAccountManagerResponse.Stub() {
+ @Override
public void onResult(Bundle value) throws RemoteException {
Account account = new Account(
value.getString(KEY_ACCOUNT_NAME),
@@ -2279,6 +2311,7 @@ public class AccountManager {
mActivity, mMyCallback, mHandler);
}
+ @Override
public void onError(int errorCode, String errorMessage)
throws RemoteException {
mResponse.onError(errorCode, errorMessage);
@@ -2311,6 +2344,7 @@ public class AccountManager {
}}, mHandler);
}
+ @Override
public void run(AccountManagerFuture<Bundle> future) {
try {
final Bundle result = future.getResult();
@@ -2531,6 +2565,7 @@ public class AccountManager {
* in mAccountsUpdatedListeners.
*/
private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(final Context context, final Intent intent) {
final Account[] accounts = getAccounts();
// send the result to the listeners
@@ -2851,6 +2886,25 @@ public class AccountManager {
final Activity activity,
AccountManagerCallback<Bundle> callback,
Handler handler) {
+ return finishSessionAsUser(
+ sessionBundle,
+ activity,
+ Process.myUserHandle(),
+ callback,
+ handler);
+ }
+
+ /**
+ * @see #finishSession
+ * @hide
+ */
+ @SystemApi
+ public AccountManagerFuture<Bundle> finishSessionAsUser(
+ final Bundle sessionBundle,
+ final Activity activity,
+ final UserHandle userHandle,
+ AccountManagerCallback<Bundle> callback,
+ Handler handler) {
if (sessionBundle == null) {
throw new IllegalArgumentException("sessionBundle is null");
}
@@ -2862,7 +2916,12 @@ public class AccountManager {
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
- mService.finishSession(mResponse, sessionBundle, activity != null, appInfo);
+ mService.finishSessionAsUser(
+ mResponse,
+ sessionBundle,
+ activity != null,
+ appInfo,
+ userHandle.getIdentifier());
}
}.start();
}
@@ -2898,12 +2957,14 @@ public class AccountManager {
}
return new Future2Task<Boolean>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.isCredentialsUpdateSuggested(
mResponse,
account,
statusToken);
}
+ @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 39dedf489887..7199288426f2 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -92,9 +92,9 @@ interface IAccountManager {
void startUpdateCredentialsSession(in IAccountManagerResponse response, in Account account,
String authTokenType, boolean expectActivityLaunch, in Bundle options);
- /* Finish session started by startAddAccountSession(...) or startUpdateCredentialsSession(...) */
- void finishSession(in IAccountManagerResponse response, in Bundle sessionBundle,
- boolean expectActivityLaunch, in Bundle appInfo);
+ /* Finish session started by startAddAccountSession(...) or startUpdateCredentialsSession(...) for user */
+ void finishSessionAsUser(in IAccountManagerResponse response, in Bundle sessionBundle,
+ boolean expectActivityLaunch, in Bundle appInfo, int userId);
/* Check if an account exists on any user on the device. */
boolean someUserHasAccount(in Account account);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b86b3fd47e07..2683be66b347 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2486,16 +2486,20 @@ public class AccountManagerService
}
@Override
- public void finishSession(IAccountManagerResponse response,
+ public void finishSessionAsUser(IAccountManagerResponse response,
@NonNull Bundle sessionBundle,
boolean expectActivityLaunch,
- Bundle appInfo) {
+ Bundle appInfo,
+ int userId) {
+ int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
- "finishSession: response " + response
+ "finishSession: response "+ response
+ ", expectActivityLaunch " + expectActivityLaunch
- + ", caller's uid " + Binder.getCallingUid()
- + ", pid " + Binder.getCallingPid());
+ + ", caller's uid " + callingUid
+ + ", caller's user id " + UserHandle.getCallingUserId()
+ + ", pid " + Binder.getCallingPid()
+ + ", for user id " + userId);
}
if (response == null) {
throw new IllegalArgumentException("response is null");
@@ -2507,17 +2511,24 @@ public class AccountManagerService
throw new IllegalArgumentException("sessionBundle is empty");
}
- final int uid = Binder.getCallingUid();
+ // Only allow the system process to finish session for other users
+ if (isCrossUser(callingUid, userId)) {
+ throw new SecurityException(
+ String.format(
+ "User %s trying to finish session for %s without cross user permission",
+ UserHandle.getCallingUserId(),
+ userId));
+ }
+
// Only allow system to finish session
- if (!isSystemUid(uid)) {
+ if (!isSystemUid(callingUid)) {
String msg = String.format(
- "uid %s cannot finish session.",
- uid);
+ "uid %s cannot finish session because it's not system uid.",
+ callingUid);
throw new SecurityException(msg);
}
- final int userId = UserHandle.getUserId(uid);
- if (!canUserModifyAccounts(userId, uid)) {
+ if (!canUserModifyAccounts(userId, callingUid)) {
sendErrorResponse(response,
AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2559,7 +2570,7 @@ public class AccountManagerService
}
// Add info that may be used by add account or update credentials flow.
- decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, uid);
+ decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
} catch (GeneralSecurityException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -2572,7 +2583,7 @@ public class AccountManagerService
return;
}
- if (!canUserModifyAccountsForType(userId, accountType, uid)) {
+ if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
sendErrorResponse(
response,
AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
@@ -2589,7 +2600,7 @@ public class AccountManagerService
accounts,
DebugDbHelper.ACTION_CALLED_ACCOUNT_SESSION_FINISH,
TABLE_ACCOUNTS,
- uid);
+ callingUid);
new Session(
accounts,
response,