summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java117
-rw-r--r--services/java/com/android/server/am/AppErrorDialog.java7
-rw-r--r--services/java/com/android/server/am/StrictModeViolationDialog.java7
-rw-r--r--services/java/com/android/server/am/UserStartedState.java7
-rw-r--r--services/java/com/android/server/pm/PackageSettingBase.java12
-rw-r--r--services/java/com/android/server/pm/Settings.java7
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java168
7 files changed, 242 insertions, 83 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bfefe67..2db0f97 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -912,21 +912,38 @@ public final class ActivityManagerService extends ActivityManagerNative
switch (msg.what) {
case SHOW_ERROR_MSG: {
HashMap data = (HashMap) msg.obj;
+ boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
synchronized (ActivityManagerService.this) {
ProcessRecord proc = (ProcessRecord)data.get("app");
+ AppErrorResult res = (AppErrorResult) data.get("result");
if (proc != null && proc.crashDialog != null) {
Slog.e(TAG, "App already has crash dialog: " + proc);
+ if (res != null) {
+ res.set(0);
+ }
+ return;
+ }
+ if (!showBackground && UserHandle.getAppId(proc.uid)
+ >= Process.FIRST_APPLICATION_UID && proc.userId != mCurrentUserId
+ && proc.pid != MY_PID) {
+ Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
+ if (res != null) {
+ res.set(0);
+ }
return;
}
- AppErrorResult res = (AppErrorResult) data.get("result");
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new AppErrorDialog(mContext, res, proc);
+ Dialog d = new AppErrorDialog(mContext,
+ ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
} else {
// The device is asleep, so just pretend that the user
// saw a crash dialog and hit "force quit".
- res.set(0);
+ if (res != null) {
+ res.set(0);
+ }
}
}
@@ -977,7 +994,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
AppErrorResult res = (AppErrorResult) data.get("result");
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new StrictModeViolationDialog(mContext, res, proc);
+ Dialog d = new StrictModeViolationDialog(mContext,
+ ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
} else {
@@ -3683,7 +3701,8 @@ public final class ActivityManagerService extends ActivityManagerNative
void closeSystemDialogsLocked(String reason) {
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
if (reason != null) {
intent.putExtra("reason", reason);
}
@@ -3755,7 +3774,8 @@ public final class ActivityManagerService extends ActivityManagerNative
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
Uri.fromParts("package", packageName, null));
if (!mProcessesReady) {
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
}
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
@@ -3768,7 +3788,8 @@ public final class ActivityManagerService extends ActivityManagerNative
private void forceStopUserLocked(int userId) {
forceStopPackageLocked(null, -1, false, false, true, false, userId);
Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
@@ -7363,7 +7384,14 @@ public final class ActivityManagerService extends ActivityManagerNative
return mController != null;
}
}
-
+
+ public void requestBugReport() {
+ // No permission check because this can't do anything harmful --
+ // it will just eventually cause the user to be presented with
+ // a UI to select where the bug report goes.
+ SystemProperties.set("ctl.start", "bugreport");
+ }
+
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
@@ -7698,9 +7726,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
-
+
ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-
+
final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
for (int i=0; i<ris.size(); i++) {
ActivityInfo ai = ris.get(i).activityInfo;
@@ -7874,7 +7902,8 @@ public final class ActivityManagerService extends ActivityManagerNative
long ident = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
@@ -8081,8 +8110,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
void startAppProblemLocked(ProcessRecord app) {
- app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
- mContext, app.info.packageName, app.info.flags);
+ if (app.userId == mCurrentUserId) {
+ app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+ mContext, app.info.packageName, app.info.flags);
+ } else {
+ // If this app is not running under the current user, then we
+ // can't give it a report button because that would require
+ // launching the report UI under a different user.
+ app.errorReportReceiver = null;
+ }
skipCurrentReceiverLocked(app);
}
@@ -8590,7 +8626,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (appErrorIntent != null) {
try {
- mContext.startActivity(appErrorIntent);
+ mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
} catch (ActivityNotFoundException e) {
Slog.w(TAG, "bug report receiver dissappeared", e);
}
@@ -11427,6 +11463,17 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int user : users) {
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
.queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
+ if (user != 0 && newReceivers != null) {
+ // If this is not the primary user, we need to check for
+ // any receivers that should be filtered out.
+ for (int i=0; i<newReceivers.size(); i++) {
+ ResolveInfo ri = newReceivers.get(i);
+ if ((ri.activityInfo.flags&ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
+ newReceivers.remove(i);
+ i--;
+ }
+ }
+ }
if (newReceivers != null && newReceivers.size() == 0) {
newReceivers = null;
}
@@ -12271,12 +12318,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
- broadcastIntentLocked(null, null,
- new Intent(Intent.ACTION_LOCALE_CHANGED),
+ intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
@@ -14084,7 +14133,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
@@ -14093,17 +14143,17 @@ public final class ActivityManagerService extends ActivityManagerNative
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
if (userId != 0) {
intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
- synchronized (ActivityManagerService.this) {
- getUserManagerLocked().makeInitialized(userInfo.id);
- }
+ userInitialized(uss);
}
}, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
userId);
+ uss.initializing = true;
} else {
getUserManagerLocked().makeInitialized(userInfo.id);
}
@@ -14130,7 +14180,8 @@ public final class ActivityManagerService extends ActivityManagerNative
Intent intent;
if (oldUserId >= 0) {
intent = new Intent(Intent.ACTION_USER_BACKGROUND);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, oldUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
@@ -14138,13 +14189,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (newUserId >= 0) {
intent = new Intent(Intent.ACTION_USER_FOREGROUND);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
false, false, MY_PID, Process.SYSTEM_UID, newUserId);
intent = new Intent(Intent.ACTION_USER_SWITCHED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
@@ -14175,6 +14228,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
};
synchronized (this) {
+ uss.switching = true;
mCurUserSwitchCallback = callback;
}
for (int i=0; i<N; i++) {
@@ -14206,6 +14260,14 @@ public final class ActivityManagerService extends ActivityManagerNative
oldUserId, newUserId, uss));
}
+ void userInitialized(UserStartedState uss) {
+ synchronized (ActivityManagerService.this) {
+ getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
+ uss.initializing = false;
+ completeSwitchAndInitalizeLocked(uss);
+ }
+ }
+
void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
final int N = mUserSwitchObservers.beginBroadcast();
for (int i=0; i<N; i++) {
@@ -14216,6 +14278,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mUserSwitchObservers.finishBroadcast();
synchronized (this) {
+ uss.switching = false;
+ completeSwitchAndInitalizeLocked(uss);
+ }
+ }
+
+ void completeSwitchAndInitalizeLocked(UserStartedState uss) {
+ if (!uss.switching && !uss.initializing) {
mWindowManager.stopFreezingScreen();
}
}
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 57e11cf..0ebbe3b 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -29,6 +29,7 @@ import android.view.WindowManager;
class AppErrorDialog extends BaseErrorDialog {
private final static String TAG = "AppErrorDialog";
+ private final ActivityManagerService mService;
private final AppErrorResult mResult;
private final ProcessRecord mProc;
@@ -39,11 +40,13 @@ class AppErrorDialog extends BaseErrorDialog {
// 5-minute timeout, then we automatically dismiss the crash dialog
static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
- public AppErrorDialog(Context context, AppErrorResult result, ProcessRecord app) {
+ public AppErrorDialog(Context context, ActivityManagerService service,
+ AppErrorResult result, ProcessRecord app) {
super(context);
Resources res = context.getResources();
+ mService = service;
mProc = app;
mResult = result;
CharSequence name;
@@ -86,7 +89,7 @@ class AppErrorDialog extends BaseErrorDialog {
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
- synchronized (mProc) {
+ synchronized (mService) {
if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
mProc.crashDialog = null;
}
diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/java/com/android/server/am/StrictModeViolationDialog.java
index fe76d18..35d50a1 100644
--- a/services/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/java/com/android/server/am/StrictModeViolationDialog.java
@@ -28,6 +28,7 @@ import android.util.Slog;
class StrictModeViolationDialog extends BaseErrorDialog {
private final static String TAG = "StrictModeViolationDialog";
+ private final ActivityManagerService mService;
private final AppErrorResult mResult;
private final ProcessRecord mProc;
@@ -39,11 +40,13 @@ class StrictModeViolationDialog extends BaseErrorDialog {
// dialog
static final long DISMISS_TIMEOUT = 1000 * 60 * 1;
- public StrictModeViolationDialog(Context context, AppErrorResult result, ProcessRecord app) {
+ public StrictModeViolationDialog(Context context, ActivityManagerService service,
+ AppErrorResult result, ProcessRecord app) {
super(context);
Resources res = context.getResources();
+ mService = service;
mProc = app;
mResult = result;
CharSequence name;
@@ -83,7 +86,7 @@ class StrictModeViolationDialog extends BaseErrorDialog {
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
- synchronized (mProc) {
+ synchronized (mService) {
if (mProc != null && mProc.crashDialog == StrictModeViolationDialog.this) {
mProc.crashDialog = null;
}
diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/java/com/android/server/am/UserStartedState.java
index 3f3ed85..50c8553 100644
--- a/services/java/com/android/server/am/UserStartedState.java
+++ b/services/java/com/android/server/am/UserStartedState.java
@@ -32,12 +32,17 @@ public class UserStartedState {
= new ArrayList<IStopUserCallback>();
public int mState = STATE_BOOTING;
+ public boolean switching;
+ public boolean initializing;
public UserStartedState(UserHandle handle, boolean initial) {
mHandle = handle;
}
void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mState="); pw.println(mState);
+ pw.print(prefix); pw.print("mState="); pw.print(mState);
+ if (switching) pw.print(" SWITCHING");
+ if (initializing) pw.print(" INITIALIZING");
+ pw.println();
}
}
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index d8f7345..6a363a8 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageUserState;
import android.content.pm.UserInfo;
import android.util.SparseArray;
@@ -64,7 +65,8 @@ class PackageSettingBase extends GrantedPermissions {
boolean permissionsFixed;
boolean haveGids;
- private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
+ private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState(false);
+ private static final PackageUserState DEFAULT_SYSTEM_USER_STATE = new PackageUserState(true);
// Whether this package is currently stopped, thus can not be
// started until explicitly launched by the user.
@@ -174,7 +176,7 @@ class PackageSettingBase extends GrantedPermissions {
private PackageUserState modifyUserState(int userId) {
PackageUserState state = userState.get(userId);
if (state == null) {
- state = new PackageUserState();
+ state = new PackageUserState((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0);
userState.put(userId, state);
}
return state;
@@ -182,7 +184,11 @@ class PackageSettingBase extends GrantedPermissions {
public PackageUserState readUserState(int userId) {
PackageUserState state = userState.get(userId);
- return state != null ? state : DEFAULT_USER_STATE;
+ if (state != null) {
+ return state;
+ }
+ return ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0)
+ ? DEFAULT_SYSTEM_USER_STATE : DEFAULT_USER_STATE;
}
void setEnabled(int state, int userId) {
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 2fb853a..bdf5044 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2609,10 +2609,11 @@ final class Settings {
pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
}
pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(" permissionsFixed="); pw.println(ps.permissionsFixed);
- pw.print(" haveGids="); pw.println(ps.haveGids);
+ pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
+ pw.print(" haveGids="); pw.print(ps.haveGids);
+ pw.print(" installStatus="); pw.println(ps.installStatus);
pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
- pw.print(" installStatus="); pw.println(ps.installStatus);
+ pw.println();
for (UserInfo user : users) {
pw.print(" User "); pw.print(user.id); pw.print(": ");
pw.print(" installed=");
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 2edc700..a0326c5 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -16,9 +16,6 @@
package com.android.server.pm;
-import static android.os.ParcelFileDescriptor.MODE_CREATE;
-import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
-
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -35,7 +32,6 @@ import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.IUserManager;
-import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -74,6 +70,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
private static final String ATTR_SERIAL_NO = "serialNumber";
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
+ private static final String ATTR_PARTIAL = "partial";
private static final String TAG_USERS = "users";
private static final String TAG_USER = "user";
@@ -132,24 +129,40 @@ public class UserManagerService extends IUserManager.Stub {
private UserManagerService(Context context, PackageManagerService pm,
Object installLock, Object packagesLock,
File dataDir, File baseUserPath) {
- synchronized (UserManagerService.class) {
- mContext = context;
- mPm = pm;
- mInstallLock = installLock;
- mPackagesLock = packagesLock;
- mUsersDir = new File(dataDir, USER_INFO_DIR);
- mUsersDir.mkdirs();
- // Make zeroth user directory, for services to migrate their files to that location
- File userZeroDir = new File(mUsersDir, "0");
- userZeroDir.mkdirs();
- mBaseUserPath = baseUserPath;
- FileUtils.setPermissions(mUsersDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
- readUserList();
- sInstance = this;
+ mContext = context;
+ mPm = pm;
+ mInstallLock = installLock;
+ mPackagesLock = packagesLock;
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ mUsersDir = new File(dataDir, USER_INFO_DIR);
+ mUsersDir.mkdirs();
+ // Make zeroth user directory, for services to migrate their files to that location
+ File userZeroDir = new File(mUsersDir, "0");
+ userZeroDir.mkdirs();
+ mBaseUserPath = baseUserPath;
+ FileUtils.setPermissions(mUsersDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
+ readUserListLocked();
+ // Prune out any partially created users.
+ ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo ui = mUsers.valueAt(i);
+ if (ui.partial && i != 0) {
+ partials.add(ui);
+ }
+ }
+ for (int i = 0; i < partials.size(); i++) {
+ UserInfo ui = partials.get(i);
+ Slog.w(LOG_TAG, "Removing partially created user #" + i
+ + " (name=" + ui.name + ")");
+ removeUserStateLocked(ui.id);
+ }
+ sInstance = this;
+ }
}
}
@@ -159,8 +172,12 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mPackagesLock) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
for (int i = 0; i < mUsers.size(); i++) {
- if (!excludeDying || !mRemovingUserIds.contains(mUsers.keyAt(i))) {
- users.add(mUsers.valueAt(i));
+ UserInfo ui = mUsers.valueAt(i);
+ if (ui.partial) {
+ continue;
+ }
+ if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
+ users.add(ui);
}
}
return users;
@@ -179,7 +196,12 @@ public class UserManagerService extends IUserManager.Stub {
* Should be locked on mUsers before calling this.
*/
private UserInfo getUserInfoLocked(int userId) {
- return mUsers.get(userId);
+ UserInfo ui = mUsers.get(userId);
+ if (ui != null && ui.partial) {
+ Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
+ return null;
+ }
+ return ui;
}
public boolean exists(int userId) {
@@ -191,14 +213,22 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void setUserName(int userId, String name) {
checkManageUsersPermission("rename users");
+ boolean changed = false;
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
+ if (info == null || info.partial) {
+ Slog.w(LOG_TAG, "setUserName: unknown user #" + userId);
+ return;
+ }
if (name != null && !name.equals(info.name)) {
info.name = name;
writeUserLocked(info);
+ changed = true;
}
}
- sendUserInfoChangedBroadcast(userId);
+ if (changed) {
+ sendUserInfoChangedBroadcast(userId);
+ }
}
@Override
@@ -206,7 +236,10 @@ public class UserManagerService extends IUserManager.Stub {
checkManageUsersPermission("update users");
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
- if (info == null) return;
+ if (info == null || info.partial) {
+ Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
+ return;
+ }
writeBitmapLocked(info, bitmap);
writeUserLocked(info);
}
@@ -225,7 +258,13 @@ public class UserManagerService extends IUserManager.Stub {
checkManageUsersPermission("read users");
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
- if (info == null || info.iconPath == null) return null;
+ if (info == null || info.partial) {
+ Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId);
+ return null;
+ }
+ if (info.iconPath == null) {
+ return null;
+ }
return BitmapFactory.decodeFile(info.iconPath);
}
}
@@ -239,7 +278,7 @@ public class UserManagerService extends IUserManager.Stub {
// Erase any guest user that currently exists
for (int i = 0; i < mUsers.size(); i++) {
UserInfo user = mUsers.valueAt(i);
- if (user.isGuest()) {
+ if (!user.partial && user.isGuest()) {
if (!enable) {
removeUser(user.id);
}
@@ -271,7 +310,10 @@ public class UserManagerService extends IUserManager.Stub {
checkManageUsersPermission("makeInitialized");
synchronized (mPackagesLock) {
UserInfo info = mUsers.get(userId);
- if (info != null && (info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+ if (info == null || info.partial) {
+ Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
+ }
+ if ((info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
info.flags |= UserInfo.FLAG_INITIALIZED;
writeUserLocked(info);
}
@@ -453,6 +495,9 @@ public class UserManagerService extends IUserManager.Stub {
if (userInfo.iconPath != null) {
serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
}
+ if (userInfo.partial) {
+ serializer.attribute(null, ATTR_PARTIAL, "true");
+ }
serializer.startTag(null, TAG_NAME);
serializer.text(userInfo.name);
@@ -516,6 +561,7 @@ public class UserManagerService extends IUserManager.Stub {
String iconPath = null;
long creationTime = 0L;
long lastLoggedInTime = 0L;
+ boolean partial = false;
FileInputStream fis = null;
try {
@@ -546,6 +592,10 @@ public class UserManagerService extends IUserManager.Stub {
iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
+ String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
+ if ("true".equals(valueString)) {
+ partial = true;
+ }
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
@@ -562,6 +612,7 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.serialNumber = serialNumber;
userInfo.creationTime = creationTime;
userInfo.lastLoggedInTime = lastLoggedInTime;
+ userInfo.partial = partial;
return userInfo;
} catch (IOException ioe) {
@@ -613,11 +664,14 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.serialNumber = mNextSerialNumber++;
long now = System.currentTimeMillis();
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
+ userInfo.partial = true;
mUsers.put(userId, userInfo);
writeUserListLocked();
writeUserLocked(userInfo);
- updateUserIdsLocked();
mPm.createNewUserLILPw(userId, userPath);
+ userInfo.partial = false;
+ writeUserLocked(userInfo);
+ updateUserIdsLocked();
}
}
if (userInfo != null) {
@@ -670,19 +724,7 @@ public class UserManagerService extends IUserManager.Stub {
void finishRemoveUser(int userHandle) {
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
- // Cleanup package manager settings
- mPm.cleanUpUserLILPw(userHandle);
-
- // Remove this user from the list
- mUsers.remove(userHandle);
- mRemovingUserIds.remove(userHandle);
- // Remove user file
- AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
- userFile.delete();
- // Update the user list
- writeUserListLocked();
- updateUserIdsLocked();
- removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
+ removeUserStateLocked(userHandle);
}
}
@@ -698,6 +740,22 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ private void removeUserStateLocked(int userHandle) {
+ // Cleanup package manager settings
+ mPm.cleanUpUserLILPw(userHandle);
+
+ // Remove this user from the list
+ mUsers.remove(userHandle);
+ mRemovingUserIds.remove(userHandle);
+ // Remove user file
+ AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
+ userFile.delete();
+ // Update the user list
+ writeUserListLocked();
+ updateUserIdsLocked();
+ removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
+ }
+
private void removeDirectoryRecursive(File parent) {
if (parent.isDirectory()) {
String[] files = parent.list();
@@ -732,9 +790,17 @@ public class UserManagerService extends IUserManager.Stub {
* Caches the list of user ids in an array, adjusting the array size when necessary.
*/
private void updateUserIdsLocked() {
- int[] newUsers = new int[mUsers.size()];
+ int num = 0;
+ for (int i = 0; i < mUsers.size(); i++) {
+ if (!mUsers.valueAt(i).partial) {
+ num++;
+ }
+ }
+ int[] newUsers = new int[num];
for (int i = 0; i < mUsers.size(); i++) {
- newUsers[i] = mUsers.keyAt(i);
+ if (!mUsers.valueAt(i).partial) {
+ newUsers[i] = mUsers.keyAt(i);
+ }
}
mUserIds = newUsers;
}
@@ -747,7 +813,11 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mPackagesLock) {
UserInfo user = mUsers.get(userId);
long now = System.currentTimeMillis();
- if (user != null && now > EPOCH_PLUS_30_YEARS) {
+ if (user == null || user.partial) {
+ Slog.w(LOG_TAG, "userForeground: unknown user #" + userId);
+ return;
+ }
+ if (now > EPOCH_PLUS_30_YEARS) {
user.lastLoggedInTime = now;
writeUserLocked(user);
}
@@ -793,7 +863,9 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
pw.print(" "); pw.print(user);
- pw.println(mRemovingUserIds.contains(mUsers.keyAt(i)) ? " <removing> " : "");
+ if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
+ if (user.partial) pw.print(" <partial>");
+ pw.println();
pw.print(" Created: ");
if (user.creationTime == 0) {
pw.println("<unknown>");