Modifies APIs for retrieving managed profile accounts.
This is needed for Account Settings UI.
Bug: 13656853
Change-Id: I33129e4b7b33b428a7bf670259accacb60f62d9b
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 12fcdcf..806a55b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -359,7 +359,29 @@
*/
public AuthenticatorDescription[] getAuthenticatorTypes() {
try {
- return mService.getAuthenticatorTypes();
+ return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @hide
+ * Lists the currently registered authenticators for a given user id.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>The caller has to be in the same user or have the permission
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ *
+ * @return An array of {@link AuthenticatorDescription} for every
+ * authenticator known to the AccountManager service. Empty (never
+ * null) if no authenticators are known.
+ */
+ public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
+ try {
+ return mService.getAuthenticatorTypes(userId);
} catch (RemoteException e) {
// will never happen
throw new RuntimeException(e);
@@ -389,6 +411,28 @@
/**
* @hide
+ * Lists all accounts of any type registered on the device for a given
+ * user id. Equivalent to getAccountsByType(null).
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @return An array of {@link Account}, one for each account. Empty
+ * (never null) if no accounts have been added.
+ */
+ public Account[] getAccountsAsUser(int userId) {
+ try {
+ return mService.getAccountsAsUser(null, userId);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @hide
* For use by internal activities. Returns the list of accounts that the calling package
* is authorized to use, particularly for shared accounts.
* @param packageName package name of the calling app.
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 86e279f..1373dc8 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -29,7 +29,7 @@
interface IAccountManager {
String getPassword(in Account account);
String getUserData(in Account account, String key);
- AuthenticatorDescription[] getAuthenticatorTypes();
+ AuthenticatorDescription[] getAuthenticatorTypes(int userId);
Account[] getAccounts(String accountType);
Account[] getAccountsForPackage(String packageName, int uid);
Account[] getAccountsByTypeForPackage(String type, String packageName);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 914c170..afbf983 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
package android.os;
+import android.util.SparseArray;
+
import java.io.PrintWriter;
+import java.util.HashMap;
/**
* Representation of a user on the device.
@@ -66,6 +69,8 @@
final int mHandle;
+ private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
+
/**
* Checks to see if the user id is the same for the two uids, i.e., they belong to the same
* user.
@@ -124,6 +129,18 @@
return getUserId(Binder.getCallingUid());
}
+ /** @hide */
+ public static final UserHandle getCallingUserHandle() {
+ int userId = getUserId(Binder.getCallingUid());
+ UserHandle userHandle = userHandles.get(userId);
+ // Intentionally not synchronized to save time
+ if (userHandle == null) {
+ userHandle = new UserHandle(userId);
+ userHandles.put(userId, userHandle);
+ }
+ return userHandle;
+ }
+
/**
* Returns the uid that is composed from the userId and the appId.
* @hide
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b2aaf74..e152ebe 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -537,13 +537,16 @@
}
@Override
- public AuthenticatorDescription[] getAuthenticatorTypes() {
+ public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthenticatorTypes: "
+ + "for user id " + userId
+ "caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- final int userId = UserHandle.getCallingUserId();
+ // Only allow the system process to read accounts of other users
+ enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ + " trying get authenticator types for " + userId);
final long identityToken = clearCallingIdentity();
try {
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
@@ -562,6 +565,16 @@
}
}
+ private void enforceCrossUserPermission(int userId, String errorMessage) {
+ if (userId != UserHandle.getCallingUserId()
+ && Binder.getCallingUid() != Process.myUid()
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(errorMessage);
+ }
+ }
+
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1567,14 +1580,8 @@
final Account account, final Bundle options, final boolean expectActivityLaunch,
int userId) {
// Only allow the system process to read accounts of other users
- if (userId != UserHandle.getCallingUserId()
- && Binder.getCallingUid() != Process.myUid()
- && mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("User " + UserHandle.getCallingUserId()
+ enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ " trying to confirm account credentials for " + userId);
- }
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "confirmCredentials: " + account