am 8074e98b
: Merge "Fix crashes when quickly adding and removing users" into jb-mr1-dev
* commit '8074e98b20ac04fdc032a1ed00dd6763b7e04147': Fix crashes when quickly adding and removing users
This commit is contained in:
@ -2430,7 +2430,8 @@ public class Intent implements Parcelable, Cloneable {
|
||||
/**
|
||||
* Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USER_HANDLE that has
|
||||
* the userHandle of the user. It is sent to all running users except the
|
||||
* one that has been removed. You must hold
|
||||
* one that has been removed. The user will not be completely removed until all receivers have
|
||||
* handled the broadcast. You must hold
|
||||
* {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
|
||||
* @hide
|
||||
*/
|
||||
|
@ -265,7 +265,9 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void doDatabaseCleanup() {
|
||||
for (UserInfo user : mUserManager.getUsers()) {
|
||||
for (UserInfo user : mUserManager.getUsers(true)) {
|
||||
// Skip any partially created/removed users
|
||||
if (user.partial) continue;
|
||||
Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(user.id);
|
||||
mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
|
||||
}
|
||||
|
@ -2575,7 +2575,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentActivities(Intent intent,
|
||||
String resolvedType, int flags, int userId) {
|
||||
if (!sUserManager.exists(userId)) return null;
|
||||
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");
|
||||
ComponentName comp = intent.getComponent();
|
||||
if (comp == null) {
|
||||
@ -2615,7 +2615,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
|
||||
Intent[] specifics, String[] specificTypes, Intent intent,
|
||||
String resolvedType, int flags, int userId) {
|
||||
if (!sUserManager.exists(userId)) return null;
|
||||
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||
enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
|
||||
"query intent activity options");
|
||||
final String resultsAction = intent.getAction();
|
||||
@ -2787,7 +2787,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
|
||||
int userId) {
|
||||
if (!sUserManager.exists(userId)) return null;
|
||||
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||
ComponentName comp = intent.getComponent();
|
||||
if (comp == null) {
|
||||
if (intent.getSelector() != null) {
|
||||
@ -2838,7 +2838,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
|
||||
int userId) {
|
||||
if (!sUserManager.exists(userId)) return null;
|
||||
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||
ComponentName comp = intent.getComponent();
|
||||
if (comp == null) {
|
||||
if (intent.getSelector() != null) {
|
||||
|
@ -19,9 +19,11 @@ package com.android.server.pm;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.IStopUserCallback;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -736,21 +738,38 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
return res == ActivityManager.USER_OP_SUCCESS;
|
||||
}
|
||||
|
||||
void finishRemoveUser(int userHandle) {
|
||||
void finishRemoveUser(final int userHandle) {
|
||||
if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
|
||||
// Let other services shutdown any activity and clean up their state before completely
|
||||
// wiping the user's system directory and removing from the user list
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
|
||||
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
|
||||
mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
|
||||
android.Manifest.permission.MANAGE_USERS,
|
||||
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (DBG) {
|
||||
Slog.i(LOG_TAG,
|
||||
"USER_REMOVED broadcast sent, cleaning up user data "
|
||||
+ userHandle);
|
||||
}
|
||||
new Thread() {
|
||||
public void run() {
|
||||
synchronized (mInstallLock) {
|
||||
synchronized (mPackagesLock) {
|
||||
removeUserStateLocked(userHandle);
|
||||
}
|
||||
}
|
||||
if (DBG) Slog.i(LOG_TAG, "Removed user " + userHandle + ", sending broadcast");
|
||||
// Let other services shutdown any activity
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
|
||||
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
|
||||
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
|
||||
android.Manifest.permission.MANAGE_USERS);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
},
|
||||
|
||||
null, Activity.RESULT_OK, null, null);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@
|
||||
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_USERS" />
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
|
@ -16,23 +16,37 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Debug;
|
||||
import android.os.Environment;
|
||||
import android.os.UserManager;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Test {@link UserManager} functionality. */
|
||||
public class UserManagerTest extends AndroidTestCase {
|
||||
|
||||
UserManager mUserManager = null;
|
||||
Object mUserLock = new Object();
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
|
||||
getContext().registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
synchronized (mUserLock) {
|
||||
mUserLock.notifyAll();
|
||||
}
|
||||
}
|
||||
}, filter);
|
||||
}
|
||||
|
||||
public void testHasPrimary() throws Exception {
|
||||
@ -54,7 +68,7 @@ public class UserManagerTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
assertTrue(found);
|
||||
mUserManager.removeUser(userInfo.id);
|
||||
removeUser(userInfo.id);
|
||||
}
|
||||
|
||||
public void testAdd2Users() throws Exception {
|
||||
@ -67,14 +81,13 @@ public class UserManagerTest extends AndroidTestCase {
|
||||
assertTrue(findUser(0));
|
||||
assertTrue(findUser(user1.id));
|
||||
assertTrue(findUser(user2.id));
|
||||
mUserManager.removeUser(user1.id);
|
||||
mUserManager.removeUser(user2.id);
|
||||
removeUser(user1.id);
|
||||
removeUser(user2.id);
|
||||
}
|
||||
|
||||
public void testRemoveUser() throws Exception {
|
||||
UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
|
||||
|
||||
mUserManager.removeUser(userInfo.id);
|
||||
removeUser(userInfo.id);
|
||||
|
||||
assertFalse(findUser(userInfo.id));
|
||||
}
|
||||
@ -95,12 +108,47 @@ public class UserManagerTest extends AndroidTestCase {
|
||||
int serialNumber1 = user1.serialNumber;
|
||||
assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
|
||||
assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
|
||||
mUserManager.removeUser(user1.id);
|
||||
removeUser(user1.id);
|
||||
UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED);
|
||||
int serialNumber2 = user2.serialNumber;
|
||||
assertFalse(serialNumber1 == serialNumber2);
|
||||
assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
|
||||
assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
|
||||
mUserManager.removeUser(user2.id);
|
||||
removeUser(user2.id);
|
||||
}
|
||||
|
||||
public void testMaxUsers() {
|
||||
int N = UserManager.getMaxSupportedUsers();
|
||||
int count = mUserManager.getUsers().size();
|
||||
List<UserInfo> created = new ArrayList<UserInfo>();
|
||||
// Create as many users as permitted and make sure creation passes
|
||||
while (count < N) {
|
||||
UserInfo ui = mUserManager.createUser("User " + count, 0);
|
||||
assertNotNull(ui);
|
||||
created.add(ui);
|
||||
count++;
|
||||
}
|
||||
// Try to create one more user and make sure it fails
|
||||
UserInfo extra = null;
|
||||
assertNull(extra = mUserManager.createUser("One more", 0));
|
||||
if (extra != null) {
|
||||
removeUser(extra.id);
|
||||
}
|
||||
while (!created.isEmpty()) {
|
||||
UserInfo user = created.remove(0);
|
||||
removeUser(user.id);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeUser(int userId) {
|
||||
synchronized (mUserLock) {
|
||||
mUserManager.removeUser(userId);
|
||||
while (mUserManager.getUserInfo(userId) != null) {
|
||||
try {
|
||||
mUserLock.wait(1000);
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user