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
|
* 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
|
* 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.
|
* {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
@ -265,7 +265,9 @@ public class SyncManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doDatabaseCleanup() {
|
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);
|
Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(user.id);
|
||||||
mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
|
mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
|
||||||
}
|
}
|
||||||
|
@ -2575,7 +2575,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public List<ResolveInfo> queryIntentActivities(Intent intent,
|
public List<ResolveInfo> queryIntentActivities(Intent intent,
|
||||||
String resolvedType, int flags, int userId) {
|
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");
|
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");
|
||||||
ComponentName comp = intent.getComponent();
|
ComponentName comp = intent.getComponent();
|
||||||
if (comp == null) {
|
if (comp == null) {
|
||||||
@ -2615,7 +2615,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
|
public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
|
||||||
Intent[] specifics, String[] specificTypes, Intent intent,
|
Intent[] specifics, String[] specificTypes, Intent intent,
|
||||||
String resolvedType, int flags, int userId) {
|
String resolvedType, int flags, int userId) {
|
||||||
if (!sUserManager.exists(userId)) return null;
|
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||||
enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
|
enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
|
||||||
"query intent activity options");
|
"query intent activity options");
|
||||||
final String resultsAction = intent.getAction();
|
final String resultsAction = intent.getAction();
|
||||||
@ -2787,7 +2787,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
|
public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
|
||||||
int userId) {
|
int userId) {
|
||||||
if (!sUserManager.exists(userId)) return null;
|
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||||
ComponentName comp = intent.getComponent();
|
ComponentName comp = intent.getComponent();
|
||||||
if (comp == null) {
|
if (comp == null) {
|
||||||
if (intent.getSelector() != null) {
|
if (intent.getSelector() != null) {
|
||||||
@ -2838,7 +2838,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
@Override
|
@Override
|
||||||
public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
|
public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
|
||||||
int userId) {
|
int userId) {
|
||||||
if (!sUserManager.exists(userId)) return null;
|
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||||
ComponentName comp = intent.getComponent();
|
ComponentName comp = intent.getComponent();
|
||||||
if (comp == null) {
|
if (comp == null) {
|
||||||
if (intent.getSelector() != 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.ArrayUtils;
|
||||||
import com.android.internal.util.FastXmlSerializer;
|
import com.android.internal.util.FastXmlSerializer;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManagerNative;
|
import android.app.ActivityManagerNative;
|
||||||
import android.app.IStopUserCallback;
|
import android.app.IStopUserCallback;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@ -736,21 +738,38 @@ public class UserManagerService extends IUserManager.Stub {
|
|||||||
return res == ActivityManager.USER_OP_SUCCESS;
|
return res == ActivityManager.USER_OP_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishRemoveUser(int userHandle) {
|
void finishRemoveUser(final int userHandle) {
|
||||||
if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
|
if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
|
||||||
synchronized (mInstallLock) {
|
// Let other services shutdown any activity and clean up their state before completely
|
||||||
synchronized (mPackagesLock) {
|
// wiping the user's system directory and removing from the user list
|
||||||
removeUserStateLocked(userHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DBG) Slog.i(LOG_TAG, "Removed user " + userHandle + ", sending broadcast");
|
|
||||||
// Let other services shutdown any activity
|
|
||||||
long ident = Binder.clearCallingIdentity();
|
long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
|
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
|
||||||
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
|
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
|
||||||
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
|
mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
|
||||||
android.Manifest.permission.MANAGE_USERS);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
null, Activity.RESULT_OK, null, null);
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
|
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_USERS" />
|
<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>
|
<application>
|
||||||
<uses-library android:name="android.test.runner" />
|
<uses-library android:name="android.test.runner" />
|
||||||
|
@ -16,23 +16,37 @@
|
|||||||
|
|
||||||
package com.android.server.pm;
|
package com.android.server.pm;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** Test {@link UserManager} functionality. */
|
/** Test {@link UserManager} functionality. */
|
||||||
public class UserManagerTest extends AndroidTestCase {
|
public class UserManagerTest extends AndroidTestCase {
|
||||||
|
|
||||||
UserManager mUserManager = null;
|
UserManager mUserManager = null;
|
||||||
|
Object mUserLock = new Object();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
|
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 {
|
public void testHasPrimary() throws Exception {
|
||||||
@ -54,7 +68,7 @@ public class UserManagerTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertTrue(found);
|
assertTrue(found);
|
||||||
mUserManager.removeUser(userInfo.id);
|
removeUser(userInfo.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAdd2Users() throws Exception {
|
public void testAdd2Users() throws Exception {
|
||||||
@ -67,14 +81,13 @@ public class UserManagerTest extends AndroidTestCase {
|
|||||||
assertTrue(findUser(0));
|
assertTrue(findUser(0));
|
||||||
assertTrue(findUser(user1.id));
|
assertTrue(findUser(user1.id));
|
||||||
assertTrue(findUser(user2.id));
|
assertTrue(findUser(user2.id));
|
||||||
mUserManager.removeUser(user1.id);
|
removeUser(user1.id);
|
||||||
mUserManager.removeUser(user2.id);
|
removeUser(user2.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRemoveUser() throws Exception {
|
public void testRemoveUser() throws Exception {
|
||||||
UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
|
UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
|
||||||
|
removeUser(userInfo.id);
|
||||||
mUserManager.removeUser(userInfo.id);
|
|
||||||
|
|
||||||
assertFalse(findUser(userInfo.id));
|
assertFalse(findUser(userInfo.id));
|
||||||
}
|
}
|
||||||
@ -95,12 +108,47 @@ public class UserManagerTest extends AndroidTestCase {
|
|||||||
int serialNumber1 = user1.serialNumber;
|
int serialNumber1 = user1.serialNumber;
|
||||||
assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
|
assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
|
||||||
assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
|
assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
|
||||||
mUserManager.removeUser(user1.id);
|
removeUser(user1.id);
|
||||||
UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED);
|
UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED);
|
||||||
int serialNumber2 = user2.serialNumber;
|
int serialNumber2 = user2.serialNumber;
|
||||||
assertFalse(serialNumber1 == serialNumber2);
|
assertFalse(serialNumber1 == serialNumber2);
|
||||||
assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
|
assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
|
||||||
assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
|
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