diff --git a/api/current.txt b/api/current.txt index cb12fda699fa7..566c195b5f834 100644 --- a/api/current.txt +++ b/api/current.txt @@ -68,7 +68,7 @@ package android { field public static final java.lang.String DUMP = "android.permission.DUMP"; field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST"; - field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS"; diff --git a/api/system-current.txt b/api/system-current.txt index 965889c30fbc5..391779d8f887a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -97,7 +97,7 @@ package android { field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST"; field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK"; field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES"; - field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS"; field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE"; diff --git a/api/test-current.txt b/api/test-current.txt index 795f9cc1b4c11..d240a23b8f823 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -68,7 +68,7 @@ package android { field public static final java.lang.String DUMP = "android.permission.DUMP"; field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST"; - field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE"; field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS"; diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index ae930bf3b9e96..e520b406656bf 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -426,46 +426,46 @@ public class AccountManager { } /** - * List every {@link Account} registered on the device that are managed by - * applications whose signatures match the caller. + * Lists all accounts of any type registered on the device. + * Equivalent to getAccountsByType(null). * - *

This method can be called safely from the main thread. It is - * equivalent to calling getAccountsByType(null). + *

It is safe to call this method from the main thread. * - *

NOTE: Apps declaring a {@code targetSdkVersion<=23} in their - * manifests will continue to behave as they did on devices that support - * API level 23. In particular the GET_ACCOUNTS permission is required to - * see all the Accounts registered with the AccountManager. See docs for - * this function in API level 23 for more information. + *

Clients of this method that have not been granted the + * {@link android.Manifest.permission#GET_ACCOUNTS} permission, + * will only see those accounts managed by AbstractAccountAuthenticators whose + * signature matches the client. * - * @return Array of Accounts. The array may be empty if no accounts are - * available to the caller. + * @return An array of {@link Account}, one for each account. Empty + * (never null) if no accounts have been added. */ @NonNull + @RequiresPermission(GET_ACCOUNTS) public Account[] getAccounts() { - return getAccountsByType(null); + try { + return mService.getAccounts(null, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** * @hide - * List every {@link Account} registered on the device for a specific User - * that are managed by applications whose signatures match the caller. + * Lists all accounts of any type registered on the device for a given + * user id. Equivalent to getAccountsByType(null). * - *

NOTE: Apps declaring a {@code targetSdkVersion<=23} in their - * manifests will continue to behave as they did on devices that support - * API level 23. In particular the GET_ACCOUNTS permission is required to - * see all the Accounts registered with the AccountManager for the - * specified userId. See docs for this function in API level 23 for more - * information. + *

It is safe to call this method from the main thread. * - *

This method can be called safely from the main thread. + *

Clients of this method that have not been granted the + * {@link android.Manifest.permission#GET_ACCOUNTS} permission, + * will only see those accounts managed by AbstractAccountAuthenticators whose + * signature matches the client. * - * @param int userId associated with the User whose accounts should be - * queried. - * @return Array of Accounts. The array may be empty if no accounts are - * available to the caller. + * @return An array of {@link Account}, one for each account. Empty + * (never null) if no accounts have been added. */ @NonNull + @RequiresPermission(GET_ACCOUNTS) public Account[] getAccountsAsUser(int userId) { try { return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName()); @@ -494,11 +494,10 @@ public class AccountManager { /** * Returns the accounts visible to the specified package, in an environment where some apps * are not authorized to view all accounts. This method can only be called by system apps. - * * @param type The type of accounts to return, null to retrieve all accounts * @param packageName The package name of the app for which the accounts are to be returned - * @return Array of Accounts. The array may be empty if no accounts of th - * specified type are visible to the caller. + * @return An array of {@link Account}, one per matching account. Empty + * (never null) if no accounts of the specified type have been added. */ @NonNull public Account[] getAccountsByTypeForPackage(String type, String packageName) { @@ -511,22 +510,29 @@ public class AccountManager { } /** - * List every {@link Account} of a specified type managed by applications - * whose signatures match the caller. + * Lists all accounts of a particular type. The account type is a + * string token corresponding to the authenticator and useful domain + * of the account. For example, there are types corresponding to Google + * and Facebook. The exact string token to use will be published somewhere + * associated with the authenticator in question. * - *

NOTE: Apps declaring a {@code targetSdkVersion<=23} in their - * manifests will continue to behave as they did on devices that support - * API level 23. See docs for this function in API level 23 for more - * information. + *

It is safe to call this method from the main thread. * - *

This method can be called safely from the main thread. + *

Clients of this method that have not been granted the + * {@link android.Manifest.permission#GET_ACCOUNTS} permission, + * will only see those accounts managed by AbstractAccountAuthenticators whose + * signature matches the client. * - * @param type String denoting the type of the accounts to return, - * {@code null} to retrieve all accounts visible to the caller. - * @return An array of Accounts. Empty (never null) if no accounts - * are available to the caller. + *

NOTE: If targeting your app to work on API level 22 and before, + * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid + * or signature match. See docs for this function in API level 22. + * + * @param type The type of accounts to return, null to retrieve all accounts + * @return An array of {@link Account}, one per matching account. Empty + * (never null) if no accounts of the specified type have been added. */ @NonNull + @RequiresPermission(GET_ACCOUNTS) public Account[] getAccountsByType(String type) { return getAccountsByTypeAsUser(type, Process.myUserHandle()); } @@ -570,7 +576,6 @@ public class AccountManager { * @return a future containing the label string * @hide */ - @NonNull public AccountManagerFuture getAuthTokenLabel( final String accountType, final String authTokenType, AccountManagerCallback callback, Handler handler) { @@ -603,13 +608,9 @@ public class AccountManager { *

This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - *

Note:The specified account must be managed by an application - * whose signature matches the caller. - * - *

Further note:Apps targeting API level 23 or earlier will continue to - * behave as they did on devices that support API level 23. In particular - * they may still require the GET_ACCOUNTS permission. See docs for this - * function in API level 23. + *

This method requires the caller to hold the permission + * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature + * match with the AbstractAccountAuthenticator that manages the account. * * @param account The {@link Account} to test * @param features An array of the account features to check @@ -618,11 +619,9 @@ public class AccountManager { * @param handler {@link Handler} identifying the callback thread, * null for the main thread * @return An {@link AccountManagerFuture} which resolves to a Boolean, - * true if the account exists and has all of the specified features. - * @throws SecurityException if the specified account is managed by an - * application whose signature doesn't match the caller's signature. + * true if the account exists and has all of the specified features. */ - @NonNull + @RequiresPermission(GET_ACCOUNTS) public AccountManagerFuture hasFeatures(final Account account, final String[] features, AccountManagerCallback callback, Handler handler) { @@ -645,10 +644,9 @@ public class AccountManager { /** * Lists all accounts of a type which have certain features. The account - * type identifies the authenticator (see {@link #getAccountsByType}). Said - * authenticator must be in a package whose signature matches the callers - * package signature. Account features are authenticator-specific string tokens - * identifying boolean account properties (see {@link #hasFeatures}). + * type identifies the authenticator (see {@link #getAccountsByType}). + * Account features are authenticator-specific string tokens identifying + * boolean account properties (see {@link #hasFeatures}). * *

Unlike {@link #getAccountsByType}, this method calls the authenticator, * which may contact the server or do other work to check account features, @@ -657,14 +655,19 @@ public class AccountManager { *

This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - *

NOTE: Apps targeting API level 23 or earlier will continue to - * behave as they did on devices that support API level 23. In particular - * they may still require the GET_ACCOUNTS permission. See docs for this - * function in API level 23. + *

Clients of this method that have not been granted the + * {@link android.Manifest.permission#GET_ACCOUNTS} permission, + * will only see those accounts managed by AbstractAccountAuthenticators whose + * signature matches the client. * * @param type The type of accounts to return, must not be null * @param features An array of the account features to require, * may be null or empty + * + *

NOTE: If targeting your app to work on API level 22 and before, + * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid + * or signature match. See docs for this function in API level 22. + * * @param callback Callback to invoke when the request completes, * null for no callback * @param handler {@link Handler} identifying the callback thread, @@ -673,7 +676,7 @@ public class AccountManager { * {@link Account}, one per account of the specified type which * matches the requested features. */ - @NonNull + @RequiresPermission(GET_ACCOUNTS) public AccountManagerFuture getAccountsByTypeAndFeatures( final String type, final String[] features, AccountManagerCallback callback, Handler handler) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 55d1d048f9897..6444c6c94dc4d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1240,8 +1240,7 @@ -

  • Accessing accounts +
  • Permission changes
  • diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd index 4c399f9abf391..db9ab3a671e5e 100644 --- a/docs/html/training/id-auth/identify.jd +++ b/docs/html/training/id-auth/identify.jd @@ -15,7 +15,8 @@ next.link=authenticate.html
    1. Determine if AccountManager is for You
    2. Decide What Type of Account to Use
    3. -
    4. Query the user for an Account
    5. +
    6. Request GET_ACCOUNT permission
    7. +
    8. Query AccountManager for a List of Accounts
    9. Use the Account Object to Personalize Your App
    10. Decide Whether an Account Name is Enough
    @@ -70,46 +71,48 @@ UI.

    Decide What Type of Account to Use

    Android devices can store multiple accounts from many different providers. -When you query {@link android.accounts.AccountManager} for account names, you -can choose to filter by account type. The account type is a string that -uniquely identifies the entity that issued the account. For instance, Google -accounts have type "com.google," while Twitter uses -"com.twitter.android.auth.login."

    +When you query {@link android.accounts.AccountManager} for account names, you can choose to filter +by +account type. The account type is a string that uniquely identifies the entity +that issued the account. For instance, Google accounts have type "com.google," +while Twitter uses "com.twitter.android.auth.login."

    -

    Query the user for an Account

    -

    Once an account type has been determined, you can prompt the user with an -account chooser as follows: +

    Request GET_ACCOUNT permission

    + +

    In order to get a list of accounts on the device, your app needs the {@link +android.Manifest.permission#GET_ACCOUNTS} +permission. Add a {@code +} tag in your manifest file to request +this permission:

    -AccountManager am = AccountManager.get(this);  // "this" reference the current Context
    -Intent chooserIntent = am.newChooseAccountIntent(
    -        null, // currently select account
    -        null, // list of accounts that are allowed to be shown
    -        new String[] { "com.google" }, // Only allow the user to select Google accounts
    -        false,
    -        null,  // description text
    -        null, // add account auth token type
    -        null, // required features for added accounts
    -        null);  // options for adding an account
    -this.startActivityForResult(chooserIntent, MY_REQUEST_CODE);
    +<manifest ... >
    +    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    +    ...
    +</manifest>
     
    -

    Once the chooser intent is started, the user will be presented with a list of -appropriately typed accounts. From this list they will select one which will be -returned to your app upon onActivityResult as follows: + +

    Query AccountManager for a List of Accounts

    + +

    Once you decide what account type you're interested in, you need to query for accounts of that +type. Get an instance of {@link android.accounts.AccountManager} by calling {@link +android.accounts.AccountManager#get(android.content.Context) AccountManager.get()}. Then use that +instance to call {@link android.accounts.AccountManager#getAccountsByType(java.lang.String) +getAccountsByType()}.

    -protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    -    if (requestCode == MY_REQUEST_CODE && resultCode == RESULT_OK) {
    -        String name = data.getStringExtra(AccountManage.KEY_ACCOUNT_NAME);
    -        String type = data.getStringExtra(AccountManage.KEY_ACCOUNT_TYPE);
    -        Account selectedAccount = new Account(name, type);
    -        doSomethingWithSelectedAccount(selectedAccount);
    -    }
    -}
    +AccountManager am = AccountManager.get(this); // "this" references the current Context
    +
    +Account[] accounts = am.getAccountsByType("com.google");
     
    +

    This returns an array of {@link android.accounts.Account} objects. If there's more than one +{@link android.accounts.Account} in +the array, you should present a dialog asking the user to select one.

    + +

    Use the Account Object to Personalize Your App

    The {@link android.accounts.Account} object contains an account name, which for Google accounts diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml index b773e4679e4ee..54972b4bae294 100644 --- a/packages/Keyguard/AndroidManifest.xml +++ b/packages/Keyguard/AndroidManifest.xml @@ -23,7 +23,7 @@ - + diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index fcd5b9822be9e..5b865f97281bb 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -93,7 +93,7 @@ - + diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 1f19c072ce874..334035cb5dff7 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -103,7 +103,7 @@ - + diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 8c69cfb0bc3a4..d4dd50590c8a8 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1327,9 +1327,8 @@ public class AccountManagerService * arbitrary applications (like competing authenticators). */ UserHandle user = new UserHandle(userId); - - if (!isSystemUid(callingUid) - && !isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())) { + if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier()) + && !isSystemUid(callingUid)) { String msg = String.format( "uid %s cannot remove accounts of type: %s", callingUid, @@ -4357,6 +4356,21 @@ public class AccountManagerService } } + private boolean isPermitted(String opPackageName, int callingUid, String... permissions) { + for (String perm : permissions) { + if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, " caller uid " + callingUid + " has " + perm); + } + final int opCode = AppOpsManager.permissionToOpCode(perm); + if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp( + opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) { + return true; + } + } + } + return false; + } private int handleIncomingUser(int userId) { try { @@ -4431,53 +4445,12 @@ public class AccountManagerService private List getTypesVisibleToCaller(int callingUid, int userId, String opPackageName) { - List permissionsToCheck = new ArrayList(2); - permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS_PRIVILEGED); - long id = Binder.clearCallingIdentity(); - try { - ApplicationInfo appInfo = mPackageManager.getApplicationInfo( - opPackageName, 0 /* flags */); - /* - * At or before SDK 23, clients discover all the accounts in their - * user profile (via AccountManager.getAccounts(...)) by declaring - * the GET_ACCOUNTS permission. - * - * After SDK 23 the GET_ACCOUNTS permission is deprecated. Instead - * apps will be able to retrieve those accounts managed by - * authenticators sharing a package signature without any special - * permissions. The only clients able to discover all the accounts - * on the device will be those with the GET_ACCOUNTS_PRVILEGED - * system permission. - */ - if (23 >= appInfo.targetSdkVersion) { - permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS); - } - } catch (NameNotFoundException e) { - // No application associated with the specified package. - Log.w(TAG, "No application associated with package: " + opPackageName); - } finally { - Binder.restoreCallingIdentity(id); - } - boolean isPermitted = isPermitted(opPackageName, callingUid, permissionsToCheck); + boolean isPermitted = + isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS, + Manifest.permission.GET_ACCOUNTS_PRIVILEGED); return getTypesForCaller(callingUid, userId, isPermitted); } - private boolean isPermitted(String opPackageName, int callingUid, List permissions) { - for (String perm : permissions) { - if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, " caller uid " + callingUid + " has " + perm); - } - final int opCode = AppOpsManager.permissionToOpCode(perm); - if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp( - opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) { - return true; - } - } - } - return false; - } - private List getTypesManagedByCaller(int callingUid, int userId) { return getTypesForCaller(callingUid, userId, false); } @@ -4499,10 +4472,6 @@ public class AccountManagerService managedAccountTypes.add(serviceInfo.type.type); } } - if (managedAccountTypes.isEmpty()) { - throw new SecurityException("The calling uid " + callingUid + - " is not permitted access any types of accounts!"); - } return managedAccountTypes; }