Skip to content

Commit c85e16c

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Make RegisteredServicesCache multi-user aware." into jb-mr1-dev
2 parents 0aaffb1 + 6ab72d7 commit c85e16c

File tree

9 files changed

+379
-333
lines changed

9 files changed

+379
-333
lines changed

core/java/android/accounts/AccountAuthenticatorCache.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@
1616

1717
package android.accounts;
1818

19+
import android.content.Context;
1920
import android.content.pm.PackageManager;
2021
import android.content.pm.RegisteredServicesCache;
2122
import android.content.pm.XmlSerializerAndParser;
2223
import android.content.res.Resources;
2324
import android.content.res.TypedArray;
24-
import android.content.Context;
25-
import android.util.AttributeSet;
2625
import android.text.TextUtils;
26+
import android.util.AttributeSet;
27+
2728
import org.xmlpull.v1.XmlPullParser;
28-
import org.xmlpull.v1.XmlSerializer;
2929
import org.xmlpull.v1.XmlPullParserException;
30+
import org.xmlpull.v1.XmlSerializer;
3031

3132
import java.io.IOException;
3233

core/java/android/accounts/AccountManagerService.java

Lines changed: 64 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import android.Manifest;
2020
import android.app.ActivityManager;
21-
import android.app.AppGlobals;
21+
import android.app.ActivityManagerNative;
2222
import android.app.Notification;
2323
import android.app.NotificationManager;
2424
import android.app.PendingIntent;
@@ -32,10 +32,9 @@
3232
import android.content.pm.ApplicationInfo;
3333
import android.content.pm.PackageInfo;
3434
import android.content.pm.PackageManager;
35+
import android.content.pm.PackageManager.NameNotFoundException;
3536
import android.content.pm.RegisteredServicesCache;
3637
import android.content.pm.RegisteredServicesCacheListener;
37-
import android.content.pm.UserInfo;
38-
import android.content.res.Resources;
3938
import android.database.Cursor;
4039
import android.database.DatabaseUtils;
4140
import android.database.sqlite.SQLiteDatabase;
@@ -59,6 +58,8 @@
5958

6059
import com.android.internal.R;
6160
import com.android.internal.util.IndentingPrintWriter;
61+
import com.google.android.collect.Lists;
62+
import com.google.android.collect.Sets;
6263

6364
import java.io.File;
6465
import java.io.FileDescriptor;
@@ -67,8 +68,8 @@
6768
import java.util.Arrays;
6869
import java.util.Collection;
6970
import java.util.HashMap;
71+
import java.util.HashSet;
7072
import java.util.LinkedHashMap;
71-
import java.util.List;
7273
import java.util.Map;
7374
import java.util.concurrent.atomic.AtomicInteger;
7475
import java.util.concurrent.atomic.AtomicReference;
@@ -243,8 +244,7 @@ public void onReceive(Context context, Intent intent) {
243244
}
244245

245246
public void systemReady() {
246-
mAuthenticatorCache.generateServicesMap();
247-
initUser(0);
247+
initUser(UserHandle.USER_OWNER);
248248
}
249249

250250
private UserManager getUserManager() {
@@ -300,6 +300,14 @@ private void purgeOldGrants(UserAccounts accounts) {
300300
}
301301

302302
private void validateAccountsAndPopulateCache(UserAccounts accounts) {
303+
mAuthenticatorCache.invalidateCache(accounts.userId);
304+
305+
final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
306+
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
307+
mAuthenticatorCache.getAllServices(accounts.userId)) {
308+
knownAuth.add(service.type);
309+
}
310+
303311
synchronized (accounts.cacheLock) {
304312
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
305313
boolean accountDeleted = false;
@@ -314,8 +322,8 @@ private void validateAccountsAndPopulateCache(UserAccounts accounts) {
314322
final long accountId = cursor.getLong(0);
315323
final String accountType = cursor.getString(1);
316324
final String accountName = cursor.getString(2);
317-
if (mAuthenticatorCache.getServiceInfo(
318-
AuthenticatorDescription.newKey(accountType)) == null) {
325+
326+
if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
319327
Log.d(TAG, "deleting account " + accountName + " because type "
320328
+ accountType + " no longer has a registered authenticator");
321329
db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
@@ -390,20 +398,9 @@ private void onUserRemoved(Intent intent) {
390398
}
391399
}
392400

393-
private List<UserInfo> getAllUsers() {
394-
return getUserManager().getUsers();
395-
}
396-
397-
public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
398-
// Validate accounts for all users
399-
List<UserInfo> users = getAllUsers();
400-
if (users == null) {
401-
validateAccountsAndPopulateCache(getUserAccountsForCaller());
402-
} else {
403-
for (UserInfo user : users) {
404-
validateAccountsAndPopulateCache(getUserAccounts(user.id));
405-
}
406-
}
401+
@Override
402+
public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
403+
validateAccountsAndPopulateCache(getUserAccounts(userId));
407404
}
408405

409406
public String getPassword(Account account) {
@@ -470,10 +467,11 @@ public AuthenticatorDescription[] getAuthenticatorTypes() {
470467
+ "caller's uid " + Binder.getCallingUid()
471468
+ ", pid " + Binder.getCallingPid());
472469
}
473-
long identityToken = clearCallingIdentity();
470+
final int userId = UserHandle.getCallingUserId();
471+
final long identityToken = clearCallingIdentity();
474472
try {
475473
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
476-
authenticatorCollection = mAuthenticatorCache.getAllServices();
474+
authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
477475
AuthenticatorDescription[] types =
478476
new AuthenticatorDescription[authenticatorCollection.size()];
479477
int i = 0;
@@ -1055,9 +1053,9 @@ public void getAuthToken(IAccountManagerResponse response, final Account account
10551053
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
10561054
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
10571055
final UserAccounts accounts = getUserAccountsForCaller();
1058-
AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1059-
mAuthenticatorCache.getServiceInfo(
1060-
AuthenticatorDescription.newKey(account.type));
1056+
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
1057+
authenticatorInfo = mAuthenticatorCache.getServiceInfo(
1058+
AuthenticatorDescription.newKey(account.type), accounts.userId);
10611059
final boolean customTokens =
10621060
authenticatorInfo != null && authenticatorInfo.type.customTokens;
10631061

@@ -1074,7 +1072,7 @@ public void getAuthToken(IAccountManagerResponse response, final Account account
10741072
if (notifyOnAuthFailure) {
10751073
loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
10761074
}
1077-
1075+
10781076
long identityToken = clearCallingIdentity();
10791077
try {
10801078
// if the caller has permission, do the peek. otherwise go the more expensive
@@ -1183,28 +1181,6 @@ private void createNoCredentialsPermissionNotification(Account account, Intent i
11831181
account, authTokenType, uid), n, user);
11841182
}
11851183

1186-
String getAccountLabel(String accountType) {
1187-
RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
1188-
mAuthenticatorCache.getServiceInfo(
1189-
AuthenticatorDescription.newKey(accountType));
1190-
if (serviceInfo == null) {
1191-
throw new IllegalArgumentException("unknown account type: " + accountType);
1192-
}
1193-
1194-
final Context authContext;
1195-
try {
1196-
authContext = mContext.createPackageContext(
1197-
serviceInfo.type.packageName, 0);
1198-
} catch (PackageManager.NameNotFoundException e) {
1199-
throw new IllegalArgumentException("unknown account type: " + accountType);
1200-
}
1201-
try {
1202-
return authContext.getString(serviceInfo.type.labelId);
1203-
} catch (Resources.NotFoundException e) {
1204-
throw new IllegalArgumentException("unknown account type: " + accountType);
1205-
}
1206-
}
1207-
12081184
private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
12091185
AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
12101186

@@ -1506,28 +1482,35 @@ public Account[] getAccounts(int userId) {
15061482
}
15071483

15081484
/**
1509-
* Returns all the accounts qualified by user.
1485+
* Returns accounts for all running users.
1486+
*
15101487
* @hide
15111488
*/
1512-
public AccountAndUser[] getAllAccounts() {
1513-
ArrayList<AccountAndUser> allAccounts = new ArrayList<AccountAndUser>();
1514-
List<UserInfo> users = getAllUsers();
1515-
if (users == null) return new AccountAndUser[0];
1516-
1517-
synchronized(mUsers) {
1518-
for (UserInfo user : users) {
1519-
UserAccounts userAccounts = getUserAccounts(user.id);
1489+
public AccountAndUser[] getRunningAccounts() {
1490+
final int[] runningUserIds;
1491+
try {
1492+
runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
1493+
} catch (RemoteException e) {
1494+
// Running in system_server; should never happen
1495+
throw new RuntimeException(e);
1496+
}
1497+
1498+
final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
1499+
synchronized (mUsers) {
1500+
for (int userId : runningUserIds) {
1501+
UserAccounts userAccounts = getUserAccounts(userId);
15201502
if (userAccounts == null) continue;
15211503
synchronized (userAccounts.cacheLock) {
15221504
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null);
15231505
for (int a = 0; a < accounts.length; a++) {
1524-
allAccounts.add(new AccountAndUser(accounts[a], user.id));
1506+
runningAccounts.add(new AccountAndUser(accounts[a], userId));
15251507
}
15261508
}
15271509
}
15281510
}
1529-
AccountAndUser[] accountsArray = new AccountAndUser[allAccounts.size()];
1530-
return allAccounts.toArray(accountsArray);
1511+
1512+
AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
1513+
return runningAccounts.toArray(accountsArray);
15311514
}
15321515

15331516
public Account[] getAccounts(String type) {
@@ -1836,9 +1819,9 @@ public void onError(int errorCode, String errorMessage) {
18361819
* if no authenticator or the bind fails then return false, otherwise return true
18371820
*/
18381821
private boolean bindToAuthenticator(String authenticatorType) {
1839-
AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1840-
mAuthenticatorCache.getServiceInfo(
1841-
AuthenticatorDescription.newKey(authenticatorType));
1822+
final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
1823+
authenticatorInfo = mAuthenticatorCache.getServiceInfo(
1824+
AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
18421825
if (authenticatorInfo == null) {
18431826
if (Log.isLoggable(TAG, Log.VERBOSE)) {
18441827
Log.v(TAG, "there is no authenticator for " + authenticatorType
@@ -2083,7 +2066,7 @@ private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter
20832066
}
20842067

20852068
fout.println();
2086-
mAuthenticatorCache.dump(fd, fout, args);
2069+
mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
20872070
}
20882071
}
20892072
}
@@ -2154,11 +2137,21 @@ private void checkBinderPermission(String... permissions) {
21542137
throw new SecurityException(msg);
21552138
}
21562139

2157-
private boolean inSystemImage(int callerUid) {
2158-
String[] packages = mPackageManager.getPackagesForUid(callerUid);
2140+
private boolean inSystemImage(int callingUid) {
2141+
final int callingUserId = UserHandle.getUserId(callingUid);
2142+
2143+
final PackageManager userPackageManager;
2144+
try {
2145+
userPackageManager = mContext.createPackageContextAsUser(
2146+
"android", 0, new UserHandle(callingUserId)).getPackageManager();
2147+
} catch (NameNotFoundException e) {
2148+
return false;
2149+
}
2150+
2151+
String[] packages = userPackageManager.getPackagesForUid(callingUid);
21592152
for (String name : packages) {
21602153
try {
2161-
PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
2154+
PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
21622155
if (packageInfo != null
21632156
&& (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
21642157
return true;
@@ -2186,8 +2179,9 @@ private boolean permissionIsGranted(Account account, String authTokenType, int c
21862179
}
21872180

21882181
private boolean hasAuthenticatorUid(String accountType, int callingUid) {
2182+
final int callingUserId = UserHandle.getUserId(callingUid);
21892183
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
2190-
mAuthenticatorCache.getAllServices()) {
2184+
mAuthenticatorCache.getAllServices(callingUserId)) {
21912185
if (serviceInfo.type.type.equals(accountType)) {
21922186
return (serviceInfo.uid == callingUid) ||
21932187
(mPackageManager.checkSignatures(serviceInfo.uid, callingUid)

core/java/android/accounts/IAccountAuthenticatorCache.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,19 @@ public interface IAccountAuthenticatorCache {
3939
* matches the account type or null if none is present
4040
*/
4141
RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> getServiceInfo(
42-
AuthenticatorDescription type);
42+
AuthenticatorDescription type, int userId);
4343

4444
/**
4545
* @return A copy of a Collection of all the current Authenticators.
4646
*/
47-
Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> getAllServices();
47+
Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> getAllServices(
48+
int userId);
4849

4950
/**
5051
* Dumps the state of the cache. See
5152
* {@link android.os.Binder#dump(java.io.FileDescriptor, java.io.PrintWriter, String[])}
5253
*/
53-
void dump(FileDescriptor fd, PrintWriter fout, String[] args);
54+
void dump(FileDescriptor fd, PrintWriter fout, String[] args, int userId);
5455

5556
/**
5657
* Sets a listener that will be notified whenever the authenticator set changes
@@ -61,8 +62,5 @@ RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> getServiceInfo(
6162
void setListener(RegisteredServicesCacheListener<AuthenticatorDescription> listener,
6263
Handler handler);
6364

64-
/**
65-
* Refreshes the authenticator cache.
66-
*/
67-
void generateServicesMap();
68-
}
65+
void invalidateCache(int userId);
66+
}

core/java/android/content/ContentService.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,11 @@ public void cancelSync(Account account, String authority) {
345345
public SyncAdapterType[] getSyncAdapterTypes() {
346346
// This makes it so that future permission checks will be in the context of this
347347
// process rather than the caller's process. We will restore this before returning.
348-
long identityToken = clearCallingIdentity();
348+
final int userId = UserHandle.getCallingUserId();
349+
final long identityToken = clearCallingIdentity();
349350
try {
350351
SyncManager syncManager = getSyncManager();
351-
return syncManager.getSyncAdapterTypes();
352+
return syncManager.getSyncAdapterTypes(userId);
352353
} finally {
353354
restoreCallingIdentity(identityToken);
354355
}

0 commit comments

Comments
 (0)