diff options
Diffstat (limited to 'services/java')
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>"); |