diff options
| author | 2016-01-27 00:12:06 +0000 | |
|---|---|---|
| committer | 2016-01-27 00:12:06 +0000 | |
| commit | 3cdbc806ff52d02bf215a5aa696b670434d9f401 (patch) | |
| tree | eab04a41f3f4a96f01dfc5253867f14a35266083 | |
| parent | d475e1a27c719de3c07e83fdf1ed598442e4dba8 (diff) | |
| parent | 918c55a67c2bf0cec79f75dec6ca468e914a5fd1 (diff) | |
Merge "Permissions: Get rid of GET_ACCOUNTS"
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | api/test-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/accounts/AccountManager.java | 124 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 3 | ||||
| -rw-r--r-- | docs/html/preview/support.jd | 25 | ||||
| -rw-r--r-- | docs/html/training/id-auth/identify.jd | 65 | ||||
| -rw-r--r-- | services/core/java/com/android/server/accounts/AccountManagerService.java | 59 |
8 files changed, 150 insertions, 132 deletions
diff --git a/api/current.txt b/api/current.txt index fd68192159e4..9419b1ce3639 100644 --- a/api/current.txt +++ b/api/current.txt @@ -67,7 +67,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 java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final deprecated 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 09136a9397c5..1ca34ec5d231 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -95,7 +95,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 java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final deprecated 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 e1d1fdedb22b..62b049efd7e5 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -67,7 +67,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 java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final deprecated 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 1d9e3bb4b4bb..35695c47d19b 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -430,47 +430,46 @@ public class AccountManager { } /** - * Lists all accounts of any type registered on the device. - * Equivalent to getAccountsByType(null). + * List every {@link Account} registered on the device that are managed by + * applications whose signatures match the caller. * - * <p>It is safe to call this method from the main thread. + * <p>This method can be called safely from the main thread. It is + * equivalent to calling <code>getAccountsByType(null)</code>. * - * <p>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. + * <p><b>NOTE:</b> 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. * - * @return An array of {@link Account}, one for each account. Empty - * (never null) if no accounts have been added. + * @return Array of Accounts. The array may be empty if no accounts are + * available to the caller. */ @NonNull - @RequiresPermission(GET_ACCOUNTS) public Account[] getAccounts() { - try { - return mService.getAccounts(null, mContext.getOpPackageName()); - } catch (RemoteException e) { - // won't ever happen - throw new RuntimeException(e); - } + return getAccountsByType(null); } /** * @hide - * Lists all accounts of any type registered on the device for a given - * user id. Equivalent to getAccountsByType(null). + * List every {@link Account} registered on the device for a specific User + * that are managed by applications whose signatures match the caller. * - * <p>It is safe to call this method from the main thread. + * <p><b>NOTE:</b> 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. * - * <p>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. + * <p>This method can be called safely from the main thread. * - * @return An array of {@link Account}, one for each account. Empty - * (never null) if no accounts have been added. + * @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. */ @NonNull - @RequiresPermission(GET_ACCOUNTS) public Account[] getAccountsAsUser(int userId) { try { return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName()); @@ -501,10 +500,11 @@ 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 An array of {@link Account}, one per matching account. Empty - * (never null) if no accounts of the specified type have been added. + * @return Array of Accounts. The array may be empty if no accounts of th + * specified type are visible to the caller. */ @NonNull public Account[] getAccountsByTypeForPackage(String type, String packageName) { @@ -518,29 +518,22 @@ public class AccountManager { } /** - * 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. + * List every {@link Account} of a specified type managed by applications + * whose signatures match the caller. * - * <p>It is safe to call this method from the main thread. - * - * <p>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. + * <p><b>NOTE:</b> 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. * - * <p><b>NOTE:</b> 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. + * <p>This method can be called safely from the main thread. * - * @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. + * @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. */ @NonNull - @RequiresPermission(GET_ACCOUNTS) public Account[] getAccountsByType(String type) { return getAccountsByTypeAsUser(type, Process.myUserHandle()); } @@ -586,6 +579,7 @@ public class AccountManager { * @return a future containing the label string * @hide */ + @NonNull public AccountManagerFuture<String> getAuthTokenLabel( final String accountType, final String authTokenType, AccountManagerCallback<String> callback, Handler handler) { @@ -618,9 +612,13 @@ 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>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. + * <p><b>Note:</b>The specified account must be managed by an application + * whose signature matches the caller. + * + * <p><b>Further note:</b>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. * * @param account The {@link Account} to test * @param features An array of the account features to check @@ -629,9 +627,11 @@ 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. + * 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. */ - @RequiresPermission(GET_ACCOUNTS) + @NonNull public AccountManagerFuture<Boolean> hasFeatures(final Account account, final String[] features, AccountManagerCallback<Boolean> callback, Handler handler) { @@ -654,9 +654,10 @@ public class AccountManager { /** * Lists all accounts of a type which have certain features. The account - * type identifies the authenticator (see {@link #getAccountsByType}). - * Account features are authenticator-specific string tokens identifying - * boolean account properties (see {@link #hasFeatures}). + * 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}). * * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator, * which may contact the server or do other work to check account features, @@ -665,19 +666,14 @@ 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>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. + * <p><b>NOTE:</b> 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. * * @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 - * - * <p><b>NOTE:</b> 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, @@ -686,7 +682,7 @@ public class AccountManager { * {@link Account}, one per account of the specified type which * matches the requested features. */ - @RequiresPermission(GET_ACCOUNTS) + @NonNull public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( final String type, final String[] features, AccountManagerCallback<Account[]> callback, Handler handler) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f5e704d78bad..56c3fc88cf23 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1208,7 +1208,8 @@ <eat-comment /> <!-- Allows access to the list of accounts in the Accounts Service. - <p>Protection level: normal + <p>Protection level: dangerous + @deprecated Not operative for apps apps with targetSdkVersion >= 24. --> <permission android:name="android.permission.GET_ACCOUNTS" android:permissionGroup="android.permission-group.CONTACTS" diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd index cfd94671604f..8c392aac2545 100644 --- a/docs/html/preview/support.jd +++ b/docs/html/preview/support.jd @@ -160,20 +160,21 @@ page.image=images/cards/card-support_16-9_2x.png still perform BTLE and WiFi scans, but only when they are in the foreground. While in the background, those apps will get no results from BTLE and WiFi scans.</li> </ul> </li> - <li>Permission changes + <li>Accessing accounts <ul> - <li>Updated the user interface for permissions and enhanced some of the permissions - behaviors.</li> - <li>The {@link android.Manifest.permission#GET_ACCOUNTS} permission is now a member of the - {@link android.Manifest.permission_group#CONTACTS} permission group and it has a - {@code android:protectionLevel} of {@code dangerous}. This change means that when - targeting Android 6.0 (API level 23), you must check for and request this permission if - your app requires it. + <li>Updated the behavior of {@link android.accounts.AccountManager} account + discovery methods. </li> - - <li>The {@code android.permission.READ_PROFILE} and {@code android.permission.WRITE_PROFILE} - permissions have been removed from the {@link android.Manifest.permission_group#CONTACTS} - permission group. + <li>The GET_ACCOUNTS permission has been deprecated. + </li> + <li>Apps targeting API level 24 should start the intent returned by + newChooseAccountIntent(...) and await the result to acquire a reference + to the user's selected account. AccountManager methods like getAccounts and + related methods will only return those accounts managed by + authenticators that match the signatures of the calling app. + </li> + <li>Apps targeting API level 23 or earlier will continue to behave as + before. </li> </ul> </li> diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd index db9ab3a671e5..4c399f9abf39 100644 --- a/docs/html/training/id-auth/identify.jd +++ b/docs/html/training/id-auth/identify.jd @@ -15,8 +15,7 @@ next.link=authenticate.html <ol> <li><a href="#ForYou">Determine if AccountManager is for You</a></li> <li><a href="#TaskTwo">Decide What Type of Account to Use</a></li> - <li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li> - <li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li> + <li><a href="#QueryAccounts">Query the user for an Account</a></li> <li><a href="#IdentifyUser">Use the Account Object to Personalize Your App</a></li> <li><a href="#IdIsEnough">Decide Whether an Account Name is Enough</a></li> </ol> @@ -71,48 +70,46 @@ UI.</p> <h2 id="TaskTwo">Decide What Type of Account to Use</h2> <p>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."</p> +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."</p> +<h2 id="QueryAccounts">Query the user for an Account</h2> -<h2 id="GetPermission">Request GET_ACCOUNT permission</h2> - -<p>In order to get a list of accounts on the device, your app needs the {@link -android.Manifest.permission#GET_ACCOUNTS} -permission. Add a <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code -<uses-permission>}</a> tag in your manifest file to request -this permission:</p> +<p>Once an account type has been determined, you can prompt the user with an +account chooser as follows: <pre> -<manifest ... > - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - ... -</manifest> +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); </pre> - -<h2 id="TaskFive">Query AccountManager for a List of Accounts</h2> - -<p>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()}.</p> +<p>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: <pre> -AccountManager am = AccountManager.get(this); // "this" references the current Context - -Account[] accounts = am.getAccountsByType("com.google"); +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); + } +} </pre> -<p>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.</p> - - <h2 id="IdentifyUser">Use the Account Object to Personalize Your App</h2> <p>The {@link android.accounts.Account} object contains an account name, which for Google accounts diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 2683be66b347..d0006aa5c95c 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4266,21 +4266,6 @@ 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 { @@ -4355,12 +4340,50 @@ public class AccountManagerService private List<String> getTypesVisibleToCaller(int callingUid, int userId, String opPackageName) { - boolean isPermitted = - isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS, - Manifest.permission.GET_ACCOUNTS_PRIVILEGED); + List<String> permissionsToCheck = new ArrayList<String>(2); + permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS_PRIVILEGED); + 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); + } + boolean isPermitted = isPermitted(opPackageName, callingUid, permissionsToCheck); return getTypesForCaller(callingUid, userId, isPermitted); } + private boolean isPermitted(String opPackageName, int callingUid, List<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 List<String> getTypesManagedByCaller(int callingUid, int userId) { return getTypesForCaller(callingUid, userId, false); } |