Loading core/java/android/accounts/AccountManager.java +9 −3 Original line number Diff line number Diff line Loading @@ -1029,7 +1029,9 @@ public class AccountManager { * @param password The password to associate with the account, null for none * @param extras String values to use for the account's userdata, null for none * @param visibility Map from packageName to visibility values which will be set before account * is added. See {@link #getAccountVisibility} for possible values. * is added. See {@link #getAccountVisibility} for possible values. Declaring * <a href="/training/basics/intents/package-visibility">package visibility</a> needs for * package names in the map is needed, if the caller is targeting API level 34 and above. * * @return True if the account was successfully added, false if the account already exists, the * account is null, or another error occurs. Loading Loading @@ -1113,7 +1115,9 @@ public class AccountManager { * the specified account. * * @param account {@link Account} to update visibility * @param packageName Package name of the application to modify account visibility * @param packageName Package name of the application to modify account visibility. Declaring * <a href="/training/basics/intents/package-visibility">package visibility</a> needs * for it is needed, if the caller is targeting API level 34 and above. * @param visibility New visibility value * * @return True, if visibility value was successfully updated. Loading Loading @@ -1145,7 +1149,9 @@ public class AccountManager { * @param account {@link Account} to get visibility * @param packageName Package name of the application to get account visibility * * @return int Visibility of given account. * @return int Visibility of given account. For the caller targeting API level 34 and above, * {@link #VISIBILITY_NOT_VISIBLE} is returned if the given package is filtered by the rules of * <a href="/training/basics/intents/package-visibility">package visibility</a>. */ public @AccountVisibility int getAccountVisibility(Account account, String packageName) { if (account == null) Loading services/core/java/com/android/server/accounts/AccountManagerService.java +50 −22 Original line number Diff line number Diff line Loading @@ -45,6 +45,9 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ComponentName; Loading @@ -70,6 +73,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteFullException; import android.database.sqlite.SQLiteStatement; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; Loading Loading @@ -196,6 +200,14 @@ public class AccountManagerService private static final int SIGNATURE_CHECK_MATCH = 1; private static final int SIGNATURE_CHECK_UID_MATCH = 2; /** * Apps targeting Android U and above need to declare the package visibility needs in the * manifest to access the AccountManager APIs. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) private static final long ENFORCE_PACKAGE_VISIBILITY_FILTERING = 154726397; static { ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION); ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT Loading Loading @@ -527,7 +539,7 @@ public class AccountManagerService */ private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName, List<String> accountTypes, Integer callingUid, UserAccounts accounts) { if (!packageExistsForUser(packageName, accounts.userId)) { if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { Log.w(TAG, "getAccountsAndVisibilityForPackage#Package not found " + packageName); return new LinkedHashMap<>(); } Loading Loading @@ -629,6 +641,9 @@ public class AccountManagerService return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE; } } if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { return AccountManager.VISIBILITY_NOT_VISIBLE; } return resolveAccountVisibility(account, packageName, accounts); } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -779,7 +794,7 @@ public class AccountManagerService try { UserAccounts accounts = getUserAccounts(userId); return setAccountVisibility(account, packageName, newVisibility, true /* notify */, accounts); accounts, callingUid); } finally { restoreCallingIdentity(identityToken); } Loading @@ -798,11 +813,12 @@ public class AccountManagerService * @param newVisibility New visibility calue * @param notify if the flag is set applications will get notification about visibility change * @param accounts UserAccount that currently hosts the account and application * @param callingUid The caller's uid. * * @return True if account visibility was changed. */ private boolean setAccountVisibility(Account account, String packageName, int newVisibility, boolean notify, UserAccounts accounts) { boolean notify, UserAccounts accounts, int callingUid) { synchronized (accounts.dbLock) { synchronized (accounts.cacheLock) { Map<String, Integer> packagesToVisibility; Loading @@ -813,8 +829,8 @@ public class AccountManagerService getRequestingPackages(account, accounts); accountRemovedReceivers = getAccountRemovedReceivers(account, accounts); } else { if (!packageExistsForUser(packageName, accounts.userId)) { return false; // package is not installed. if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { return false; // package is not installed or not visible. } packagesToVisibility = new HashMap<>(); packagesToVisibility.put(packageName, Loading @@ -826,8 +842,8 @@ public class AccountManagerService } } else { // Notifications will not be send - only used during add account. if (!isSpecialPackageKey(packageName) && !packageExistsForUser(packageName, accounts.userId)) { if (!isSpecialPackageKey(packageName) && !canCallerAccessPackage(packageName, callingUid, accounts.userId)) { // package is not installed and not meta value. return false; } Loading Loading @@ -1045,20 +1061,6 @@ public class AccountManagerService return (receivers != null && receivers.size() > 0); } private boolean packageExistsForUser(String packageName, int userId) { try { final long identityToken = clearCallingIdentity(); try { mPackageManager.getPackageUidAsUser(packageName, userId); return true; } finally { restoreCallingIdentity(identityToken); } } catch (NameNotFoundException e) { return false; } } /** * Returns true if packageName is one of special values. */ Loading Loading @@ -1903,7 +1905,7 @@ public class AccountManagerService for (Entry<String, Integer> entry : packageToVisibility.entrySet()) { setAccountVisibility(account, entry.getKey() /* package */, entry.getValue() /* visibility */, false /* notify */, accounts); accounts, callingUid); } } accounts.accountsDb.setTransactionSuccessful(); Loading Loading @@ -5915,6 +5917,32 @@ public class AccountManagerService return (dpmi != null) && (dpmi.isActiveProfileOwner(uid) || dpmi.isActiveDeviceOwner(uid)); } /** * Filter the access to the target package by rules of the package visibility if the caller * targeting API level U and above. Otherwise, returns true if the package is installed on * the device. * * @param targetPkgName The package name to check. * @param callingUid The caller that is going to access the package. * @param userId The user ID where the target package resides. * @return true if the caller is able to access the package. */ private boolean canCallerAccessPackage(@NonNull String targetPkgName, int callingUid, int userId) { final PackageManagerInternal pmInternal = LocalServices.getService(PackageManagerInternal.class); if (!CompatChanges.isChangeEnabled(ENFORCE_PACKAGE_VISIBILITY_FILTERING, callingUid)) { return pmInternal.getPackageUid( targetPkgName, 0 /* flags */, userId) != Process.INVALID_UID; } final boolean canAccess = !pmInternal.filterAppAccess(targetPkgName, callingUid, userId); if (!canAccess && Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Package " + targetPkgName + " is not visible to caller " + callingUid + " for user " + userId); } return canAccess; } @Override public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) throws RemoteException { Loading Loading
core/java/android/accounts/AccountManager.java +9 −3 Original line number Diff line number Diff line Loading @@ -1029,7 +1029,9 @@ public class AccountManager { * @param password The password to associate with the account, null for none * @param extras String values to use for the account's userdata, null for none * @param visibility Map from packageName to visibility values which will be set before account * is added. See {@link #getAccountVisibility} for possible values. * is added. See {@link #getAccountVisibility} for possible values. Declaring * <a href="/training/basics/intents/package-visibility">package visibility</a> needs for * package names in the map is needed, if the caller is targeting API level 34 and above. * * @return True if the account was successfully added, false if the account already exists, the * account is null, or another error occurs. Loading Loading @@ -1113,7 +1115,9 @@ public class AccountManager { * the specified account. * * @param account {@link Account} to update visibility * @param packageName Package name of the application to modify account visibility * @param packageName Package name of the application to modify account visibility. Declaring * <a href="/training/basics/intents/package-visibility">package visibility</a> needs * for it is needed, if the caller is targeting API level 34 and above. * @param visibility New visibility value * * @return True, if visibility value was successfully updated. Loading Loading @@ -1145,7 +1149,9 @@ public class AccountManager { * @param account {@link Account} to get visibility * @param packageName Package name of the application to get account visibility * * @return int Visibility of given account. * @return int Visibility of given account. For the caller targeting API level 34 and above, * {@link #VISIBILITY_NOT_VISIBLE} is returned if the given package is filtered by the rules of * <a href="/training/basics/intents/package-visibility">package visibility</a>. */ public @AccountVisibility int getAccountVisibility(Account account, String packageName) { if (account == null) Loading
services/core/java/com/android/server/accounts/AccountManagerService.java +50 −22 Original line number Diff line number Diff line Loading @@ -45,6 +45,9 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ComponentName; Loading @@ -70,6 +73,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteFullException; import android.database.sqlite.SQLiteStatement; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; Loading Loading @@ -196,6 +200,14 @@ public class AccountManagerService private static final int SIGNATURE_CHECK_MATCH = 1; private static final int SIGNATURE_CHECK_UID_MATCH = 2; /** * Apps targeting Android U and above need to declare the package visibility needs in the * manifest to access the AccountManager APIs. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) private static final long ENFORCE_PACKAGE_VISIBILITY_FILTERING = 154726397; static { ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION); ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT Loading Loading @@ -527,7 +539,7 @@ public class AccountManagerService */ private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName, List<String> accountTypes, Integer callingUid, UserAccounts accounts) { if (!packageExistsForUser(packageName, accounts.userId)) { if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { Log.w(TAG, "getAccountsAndVisibilityForPackage#Package not found " + packageName); return new LinkedHashMap<>(); } Loading Loading @@ -629,6 +641,9 @@ public class AccountManagerService return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE; } } if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { return AccountManager.VISIBILITY_NOT_VISIBLE; } return resolveAccountVisibility(account, packageName, accounts); } finally { restoreCallingIdentity(identityToken); Loading Loading @@ -779,7 +794,7 @@ public class AccountManagerService try { UserAccounts accounts = getUserAccounts(userId); return setAccountVisibility(account, packageName, newVisibility, true /* notify */, accounts); accounts, callingUid); } finally { restoreCallingIdentity(identityToken); } Loading @@ -798,11 +813,12 @@ public class AccountManagerService * @param newVisibility New visibility calue * @param notify if the flag is set applications will get notification about visibility change * @param accounts UserAccount that currently hosts the account and application * @param callingUid The caller's uid. * * @return True if account visibility was changed. */ private boolean setAccountVisibility(Account account, String packageName, int newVisibility, boolean notify, UserAccounts accounts) { boolean notify, UserAccounts accounts, int callingUid) { synchronized (accounts.dbLock) { synchronized (accounts.cacheLock) { Map<String, Integer> packagesToVisibility; Loading @@ -813,8 +829,8 @@ public class AccountManagerService getRequestingPackages(account, accounts); accountRemovedReceivers = getAccountRemovedReceivers(account, accounts); } else { if (!packageExistsForUser(packageName, accounts.userId)) { return false; // package is not installed. if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { return false; // package is not installed or not visible. } packagesToVisibility = new HashMap<>(); packagesToVisibility.put(packageName, Loading @@ -826,8 +842,8 @@ public class AccountManagerService } } else { // Notifications will not be send - only used during add account. if (!isSpecialPackageKey(packageName) && !packageExistsForUser(packageName, accounts.userId)) { if (!isSpecialPackageKey(packageName) && !canCallerAccessPackage(packageName, callingUid, accounts.userId)) { // package is not installed and not meta value. return false; } Loading Loading @@ -1045,20 +1061,6 @@ public class AccountManagerService return (receivers != null && receivers.size() > 0); } private boolean packageExistsForUser(String packageName, int userId) { try { final long identityToken = clearCallingIdentity(); try { mPackageManager.getPackageUidAsUser(packageName, userId); return true; } finally { restoreCallingIdentity(identityToken); } } catch (NameNotFoundException e) { return false; } } /** * Returns true if packageName is one of special values. */ Loading Loading @@ -1903,7 +1905,7 @@ public class AccountManagerService for (Entry<String, Integer> entry : packageToVisibility.entrySet()) { setAccountVisibility(account, entry.getKey() /* package */, entry.getValue() /* visibility */, false /* notify */, accounts); accounts, callingUid); } } accounts.accountsDb.setTransactionSuccessful(); Loading Loading @@ -5915,6 +5917,32 @@ public class AccountManagerService return (dpmi != null) && (dpmi.isActiveProfileOwner(uid) || dpmi.isActiveDeviceOwner(uid)); } /** * Filter the access to the target package by rules of the package visibility if the caller * targeting API level U and above. Otherwise, returns true if the package is installed on * the device. * * @param targetPkgName The package name to check. * @param callingUid The caller that is going to access the package. * @param userId The user ID where the target package resides. * @return true if the caller is able to access the package. */ private boolean canCallerAccessPackage(@NonNull String targetPkgName, int callingUid, int userId) { final PackageManagerInternal pmInternal = LocalServices.getService(PackageManagerInternal.class); if (!CompatChanges.isChangeEnabled(ENFORCE_PACKAGE_VISIBILITY_FILTERING, callingUid)) { return pmInternal.getPackageUid( targetPkgName, 0 /* flags */, userId) != Process.INVALID_UID; } final boolean canAccess = !pmInternal.filterAppAccess(targetPkgName, callingUid, userId); if (!canAccess && Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Package " + targetPkgName + " is not visible to caller " + callingUid + " for user " + userId); } return canAccess; } @Override public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) throws RemoteException { Loading