summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/ConnectivityService.java14
-rw-r--r--services/java/com/android/server/EventLogTags.logtags8
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java1
-rw-r--r--services/java/com/android/server/am/EventLogTags.logtags3
-rw-r--r--services/java/com/android/server/display/PersistentDataStore.java25
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java85
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java67
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java65
8 files changed, 189 insertions, 79 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index ad1dfb2..a7c4d73 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2686,18 +2686,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
state + "/" + info.getDetailedState());
}
- // Connectivity state changed:
- // [31-14] Reserved for future use
- // [13-10] Network subtype (for mobile network, as defined
- // by TelephonyManager)
- // [9-4] Detailed state ordinal (as defined by
- // NetworkInfo.DetailedState)
- // [3-0] Network type (as defined by ConnectivityManager)
- int eventLogParam = (info.getType() & 0xf) |
- ((info.getDetailedState().ordinal() & 0x3f) << 4) |
- (info.getSubtype() << 10);
- EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED,
- eventLogParam);
+ EventLogTags.writeConnectivityStateChanged(
+ info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
if (info.getDetailedState() ==
NetworkInfo.DetailedState.FAILED) {
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 0fe66fc..8bc2da2 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -135,12 +135,8 @@ option java_package com.android.server
# ---------------------------
# ConnectivityService.java
# ---------------------------
-# Connectivity state changed:
-# [31-14] Reserved for future use
-# [13-10] Network subtype (for mobile network, as defined by TelephonyManager)
-# [ 9- 4] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
-# [ 3- 0] Network type (as defined by ConnectivityManager)
-50020 connectivity_state_changed (custom|1|5)
+# Connectivity state changed
+50020 connectivity_state_changed (type|1),(subtype|1),(state|1)
# ---------------------------
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d2cd646..db64a9a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -14229,6 +14229,7 @@ public final class ActivityManagerService extends ActivityManagerNative
startHomeActivityLocked(userId);
}
+ EventLogTags.writeAmSwitchUser(userId);
getUserManagerLocked().userForeground(userId);
sendUserSwitchBroadcastsLocked(oldUserId, userId);
if (needStart) {
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index 6ee7507..88c0c03 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -83,3 +83,6 @@ option java_package com.android.server.am
30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
# Log.wtf() called
30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
+
+# User switched
+30041 am_switch_user (id|1|5)
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
index 3a6e1a6..105c253 100644
--- a/services/java/com/android/server/display/PersistentDataStore.java
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -81,6 +81,15 @@ final class PersistentDataStore {
}
}
+ public WifiDisplay getRememberedWifiDisplay(String deviceAddress) {
+ loadIfNeeded();
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ return mRememberedWifiDisplays.get(index);
+ }
+ return null;
+ }
+
public WifiDisplay[] getRememberedWifiDisplays() {
loadIfNeeded();
return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
@@ -137,22 +146,6 @@ final class PersistentDataStore {
return true;
}
- public boolean renameWifiDisplay(String deviceAddress, String alias) {
- int index = findRememberedWifiDisplay(deviceAddress);
- if (index >= 0) {
- WifiDisplay display = mRememberedWifiDisplays.get(index);
- if (Objects.equal(display.getDeviceAlias(), alias)) {
- return false; // already has this alias
- }
- WifiDisplay renamedDisplay = new WifiDisplay(deviceAddress,
- display.getDeviceName(), alias);
- mRememberedWifiDisplays.set(index, renamedDisplay);
- setDirty();
- return true;
- }
- return false;
- }
-
public boolean forgetWifiDisplay(String deviceAddress) {
int index = findRememberedWifiDisplay(deviceAddress);
if (index >= 0) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index 45fff30..c8a44d2 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -45,6 +45,8 @@ import android.view.Surface;
import java.io.PrintWriter;
import java.util.Arrays;
+import libcore.util.Objects;
+
/**
* Connects to Wifi displays that implement the Miracast protocol.
* <p>
@@ -224,16 +226,18 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
}
- if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
- mPersistentDataStore.saveIfNeeded();
- updateRememberedDisplaysLocked();
- scheduleStatusChangedBroadcastLocked();
+ WifiDisplay display = mPersistentDataStore.getRememberedWifiDisplay(address);
+ if (display != null && !Objects.equal(display.getDeviceAlias(), alias)) {
+ display = new WifiDisplay(address, display.getDeviceName(), alias);
+ if (mPersistentDataStore.rememberWifiDisplay(display)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
}
- if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)
- && mDisplayDevice != null) {
- mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName());
- sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
+ renameDisplayDeviceLocked(mActiveDisplay.getFriendlyDisplayName());
}
}
@@ -272,9 +276,42 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
}
- private void handleConnectLocked(WifiDisplay display,
+ private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() {
+ // It may happen that a display name has changed since it was remembered.
+ // Consult the list of available displays and update the name if needed.
+ // We don't do anything special for the active display here. The display
+ // controller will send a separate event when it needs to be updates.
+ boolean changed = false;
+ for (int i = 0; i < mRememberedDisplays.length; i++) {
+ WifiDisplay rememberedDisplay = mRememberedDisplays[i];
+ WifiDisplay availableDisplay = findAvailableDisplayLocked(
+ rememberedDisplay.getDeviceAddress());
+ if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) {
+ if (DEBUG) {
+ Slog.d(TAG, "fixRememberedDisplayNamesFromAvailableDisplaysLocked: "
+ + "updating remembered display to " + availableDisplay);
+ }
+ mRememberedDisplays[i] = availableDisplay;
+ changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay);
+ }
+ }
+ if (changed) {
+ mPersistentDataStore.saveIfNeeded();
+ }
+ }
+
+ private WifiDisplay findAvailableDisplayLocked(String address) {
+ for (WifiDisplay display : mAvailableDisplays) {
+ if (display.getDeviceAddress().equals(address)) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ private void addDisplayDeviceLocked(WifiDisplay display,
Surface surface, int width, int height, int flags) {
- handleDisconnectLocked();
+ removeDisplayDeviceLocked();
if (mPersistentDataStore.rememberWifiDisplay(display)) {
mPersistentDataStore.saveIfNeeded();
@@ -303,7 +340,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
scheduleUpdateNotificationLocked();
}
- private void handleDisconnectLocked() {
+ private void removeDisplayDeviceLocked() {
if (mDisplayDevice != null) {
mDisplayDevice.clearSurfaceLocked();
sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
@@ -313,6 +350,13 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
}
+ private void renameDisplayDeviceLocked(String name) {
+ if (mDisplayDevice != null && !mDisplayDevice.getNameLocked().equals(name)) {
+ mDisplayDevice.setNameLocked(name);
+ sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+
private void scheduleStatusChangedBroadcastLocked() {
mCurrentStatus = null;
if (!mPendingStatusChangeBroadcast) {
@@ -446,6 +490,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
|| !Arrays.equals(mAvailableDisplays, availableDisplays)) {
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
mAvailableDisplays = availableDisplays;
+ fixRememberedDisplayNamesFromAvailableDisplaysLocked();
scheduleStatusChangedBroadcastLocked();
}
}
@@ -483,7 +528,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
int width, int height, int flags) {
synchronized (getSyncRoot()) {
display = mPersistentDataStore.applyWifiDisplayAlias(display);
- handleConnectLocked(display, surface, width, height, flags);
+ addDisplayDeviceLocked(display, surface, width, height, flags);
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
|| mActiveDisplay == null
@@ -496,10 +541,24 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
+ public void onDisplayChanged(WifiDisplay display) {
+ synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
+ if (mActiveDisplay != null
+ && mActiveDisplay.hasSameAddress(display)
+ && !mActiveDisplay.equals(display)) {
+ mActiveDisplay = display;
+ renameDisplayDeviceLocked(display.getFriendlyDisplayName());
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
public void onDisplayDisconnected() {
// Stop listening.
synchronized (getSyncRoot()) {
- handleDisconnectLocked();
+ removeDisplayDeviceLocked();
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 39d042f..886e049 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -120,6 +120,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
// or are not trying to connect.
private WifiP2pDevice mConnectingDevice;
+ // The device from which we are currently disconnecting.
+ private WifiP2pDevice mDisconnectingDevice;
+
+ // The device to which we were previously trying to connect and are now canceling.
+ private WifiP2pDevice mCancelingDevice;
+
// The device to which we are currently connected, which means we have an active P2P group.
private WifiP2pDevice mConnectedDevice;
@@ -186,6 +192,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
updateWfdEnableState();
}
+ @Override
public void dump(PrintWriter pw) {
pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
@@ -196,6 +203,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
+ pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
+ pw.println("mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
pw.println("mRemoteDisplay=" + mRemoteDisplay);
@@ -384,7 +393,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
- displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
+ WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i);
+ displays[i] = createWifiDisplay(device);
+ updateDesiredDevice(device);
}
mHandler.post(new Runnable() {
@@ -395,6 +406,23 @@ final class WifiDisplayController implements DumpUtils.Dump {
});
}
+ private void updateDesiredDevice(WifiP2pDevice device) {
+ // Handle the case where the device to which we are connecting or connected
+ // may have been renamed or reported different properties in the latest scan.
+ final String address = device.deviceAddress;
+ if (mDesiredDevice != null && mDesiredDevice.deviceAddress.equals(address)) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateDesiredDevice: new information "
+ + describeWifiP2pDevice(device));
+ }
+ mDesiredDevice.update(device);
+ if (mAdvertisedDisplay != null
+ && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
+ readvertiseDisplay(createWifiDisplay(mDesiredDevice));
+ }
+ }
+ }
+
private void connect(final WifiP2pDevice device) {
if (mDesiredDevice != null
&& !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
@@ -459,12 +487,17 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
// Step 2. Before we try to connect to a new device, disconnect from the old one.
+ if (mDisconnectingDevice != null) {
+ return; // wait for asynchronous callback
+ }
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+ mDisconnectingDevice = mConnectedDevice;
+ mConnectedDevice = null;
unadvertiseDisplay();
- final WifiP2pDevice oldDevice = mConnectedDevice;
+ final WifiP2pDevice oldDevice = mDisconnectingDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
@@ -480,8 +513,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void next() {
- if (mConnectedDevice == oldDevice) {
- mConnectedDevice = null;
+ if (mDisconnectingDevice == oldDevice) {
+ mDisconnectingDevice = null;
updateConnection();
}
}
@@ -491,13 +524,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Step 3. Before we try to connect to a new device, stop trying to connect
// to the old one.
+ if (mCancelingDevice != null) {
+ return; // wait for asynchronous callback
+ }
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+ mCancelingDevice = mConnectingDevice;
+ mConnectingDevice = null;
unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
- final WifiP2pDevice oldDevice = mConnectingDevice;
+ final WifiP2pDevice oldDevice = mCancelingDevice;
mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
@Override
public void onSuccess() {
@@ -513,8 +551,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void next() {
- if (mConnectingDevice == oldDevice) {
- mConnectingDevice = null;
+ if (mCancelingDevice == oldDevice) {
+ mCancelingDevice = null;
updateConnection();
}
}
@@ -763,13 +801,17 @@ final class WifiDisplayController implements DumpUtils.Dump {
public void run() {
if (oldSurface != null && surface != oldSurface) {
mListener.onDisplayDisconnected();
- } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
+ } else if (oldDisplay != null && !oldDisplay.hasSameAddress(display)) {
mListener.onDisplayConnectionFailed();
}
if (display != null) {
- if (!Objects.equal(display, oldDisplay)) {
+ if (!display.hasSameAddress(oldDisplay)) {
mListener.onDisplayConnecting(display);
+ } else if (!display.equals(oldDisplay)) {
+ // The address is the same but some other property such as the
+ // name must have changed.
+ mListener.onDisplayChanged(display);
}
if (surface != null && surface != oldSurface) {
mListener.onDisplayConnected(display, surface, width, height, flags);
@@ -784,6 +826,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
advertiseDisplay(null, null, 0, 0, 0);
}
+ private void readvertiseDisplay(WifiDisplay display) {
+ advertiseDisplay(display, mAdvertisedDisplaySurface,
+ mAdvertisedDisplayWidth, mAdvertisedDisplayHeight,
+ mAdvertisedDisplayFlags);
+ }
+
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
NetworkInterface iface;
try {
@@ -885,6 +933,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
+ void onDisplayChanged(WifiDisplay display);
void onDisplayConnected(WifiDisplay display,
Surface surface, int width, int height, int flags);
void onDisplayDisconnected();
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index e05442b..66c3ce9 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -16,8 +16,7 @@
package com.android.server.pm;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.app.Activity;
import android.app.ActivityManager;
@@ -26,7 +25,6 @@ import android.app.IStopUserCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@@ -34,6 +32,7 @@ import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IUserManager;
import android.os.Process;
import android.os.RemoteException;
@@ -42,9 +41,17 @@ import android.os.UserManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.Xml;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -54,13 +61,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
@@ -95,19 +97,24 @@ public class UserManagerService extends IUserManager.Stub {
private final Object mInstallLock;
private final Object mPackagesLock;
+ private final Handler mHandler;
+
private final File mUsersDir;
private final File mUserListFile;
private final File mBaseUserPath;
- private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
- private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();
+ private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+
+ /**
+ * Set of user IDs being actively removed. Removed IDs linger in this set
+ * for several seconds to work around a VFS caching issue.
+ */
+ // @GuardedBy("mPackagesLock")
+ private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
- // This resets on a reboot. Otherwise it keeps incrementing so that user ids are
- // not reused in quick succession
- private int mNextUserId = MIN_USER_ID;
private int mUserVersion = 0;
private static UserManagerService sInstance;
@@ -147,6 +154,7 @@ public class UserManagerService extends IUserManager.Stub {
mPm = pm;
mInstallLock = installLock;
mPackagesLock = packagesLock;
+ mHandler = new Handler();
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
mUsersDir = new File(dataDir, USER_INFO_DIR);
@@ -190,7 +198,7 @@ public class UserManagerService extends IUserManager.Stub {
if (ui.partial) {
continue;
}
- if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
+ if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
users.add(ui);
}
}
@@ -212,7 +220,7 @@ public class UserManagerService extends IUserManager.Stub {
private UserInfo getUserInfoLocked(int userId) {
UserInfo ui = mUsers.get(userId);
// If it is partial and not in the process of being removed, return as unknown user.
- if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
+ if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
@@ -502,7 +510,7 @@ public class UserManagerService extends IUserManager.Stub {
private void fallbackToSingleUserLocked() {
// Create the primary user
- UserInfo primary = new UserInfo(0,
+ UserInfo primary = new UserInfo(0,
mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
mUsers.put(0, primary);
@@ -749,7 +757,7 @@ public class UserManagerService extends IUserManager.Stub {
if (userHandle == 0 || user == null) {
return false;
}
- mRemovingUserIds.add(userHandle);
+ mRemovingUserIds.put(userHandle, true);
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
@@ -813,13 +821,25 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private void removeUserStateLocked(int userHandle) {
+ private void removeUserStateLocked(final int userHandle) {
// Cleanup package manager settings
mPm.cleanUpUserLILPw(userHandle);
// Remove this user from the list
mUsers.remove(userHandle);
- mRemovingUserIds.remove(userHandle);
+
+ // Have user ID linger for several seconds to let external storage VFS
+ // cache entries expire. This must be greater than the 'entry_valid'
+ // timeout used by the FUSE daemon.
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mPackagesLock) {
+ mRemovingUserIds.delete(userHandle);
+ }
+ }
+ }, MINUTE_IN_MILLIS);
+
// Remove user file
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
userFile.delete();
@@ -906,14 +926,13 @@ public class UserManagerService extends IUserManager.Stub {
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
- int i = mNextUserId;
+ int i = MIN_USER_ID;
while (i < Integer.MAX_VALUE) {
- if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
+ if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
break;
}
i++;
}
- mNextUserId = i + 1;
return i;
}
}
@@ -938,7 +957,7 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
- if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
+ if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> ");
if (user.partial) pw.print(" <partial>");
pw.println();
pw.print(" Created: ");