diff options
22 files changed, 682 insertions, 274 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 27c9c8b..197c1bd 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -231,6 +231,14 @@ public class AccountManagerService } }, intentFilter); + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent); + } + }, userFilter); } private UserAccounts initUser(int userId) { @@ -347,6 +355,28 @@ public class AccountManagerService } } + private void onUserRemoved(Intent intent) { + int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + if (userId < 1) return; + + UserAccounts accounts; + synchronized (mUsers) { + accounts = mUsers.get(userId); + mUsers.remove(userId); + } + if (accounts == null) { + File dbFile = new File(getDatabaseName(userId)); + dbFile.delete(); + return; + } + + synchronized (accounts.cacheLock) { + accounts.openHelper.close(); + File dbFile = new File(getDatabaseName(userId)); + dbFile.delete(); + } + } + private List<UserInfo> getAllUsers() { try { return AppGlobals.getPackageManager().getUsers(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index f38540c..0510de1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1215,6 +1215,18 @@ final class ApplicationPackageManager extends PackageManager { * @hide */ @Override + public UserInfo getUser(int userId) { + try { + return mPM.getUser(userId); + } catch (RemoteException re) { + return null; + } + } + + /** + * @hide + */ + @Override public boolean removeUser(int id) { try { return mPM.removeUser(id); @@ -1228,7 +1240,10 @@ final class ApplicationPackageManager extends PackageManager { */ @Override public void updateUserName(int id, String name) { - // TODO: + try { + mPM.updateUserName(id, name); + } catch (RemoteException re) { + } } /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 1c9ef38..24c2461 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2141,6 +2141,30 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED"; + /** + * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USERID that has the + * userid of the new user. + * @hide + */ + public static final String ACTION_USER_ADDED = + "android.intent.action.USER_ADDED"; + + /** + * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USERID that has + * the userid of the user. + * @hide + */ + public static final String ACTION_USER_REMOVED = + "android.intent.action.USER_REMOVED"; + + /** + * Broadcast sent to the system when the user switches. Carries an extra EXTRA_USERID that has + * the userid of the user to become the current one. + * @hide + */ + public static final String ACTION_USER_SWITCHED = + "android.intent.action.USER_SWITCHED"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). @@ -2682,6 +2706,13 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY"; + /** + * The userid carried with broadcast intents related to addition, removal and switching of users + * - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}. + * @hide + */ + public static final String EXTRA_USERID = + "android.intent.extra.user_id"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index b7dfe92..06dfe90 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -326,6 +326,13 @@ public class SyncManager implements OnAccountsUpdateListener { } }; + private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent); + } + }; + private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM"; private final SyncHandler mSyncHandler; @@ -420,6 +427,10 @@ public class SyncManager implements OnAccountsUpdateListener { intentFilter.setPriority(100); context.registerReceiver(mShutdownIntentReceiver, intentFilter); + intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(mUserIntentReceiver, intentFilter); + if (!factoryTest) { mNotificationMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); @@ -905,6 +916,18 @@ public class SyncManager implements OnAccountsUpdateListener { } } + private void onUserRemoved(Intent intent) { + int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + if (userId == -1) return; + + // Clean up the storage engine database + mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId); + onAccountsUpdated(null); + synchronized (mSyncQueue) { + mSyncQueue.removeUser(userId); + } + } + /** * @hide */ diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java index 06da6fa..c18c86b 100644 --- a/core/java/android/content/SyncQueue.java +++ b/core/java/android/content/SyncQueue.java @@ -117,6 +117,19 @@ public class SyncQueue { return true; } + public void removeUser(int userId) { + ArrayList<SyncOperation> opsToRemove = new ArrayList<SyncOperation>(); + for (SyncOperation op : mOperationsMap.values()) { + if (op.userId == userId) { + opsToRemove.add(op); + } + } + + for (SyncOperation op : opsToRemove) { + remove(op); + } + } + /** * Remove the specified operation if it is in the queue. * @param operation the operation to remove diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index d89d2de..56fd5f8 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -358,6 +358,7 @@ interface IPackageManager { UserInfo createUser(in String name, int flags); boolean removeUser(int userId); + void updateUserName(int userId, String name); void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer, int flags, in String installerPackageName, in Uri verificationURI, @@ -370,6 +371,7 @@ interface IPackageManager { boolean isFirstBoot(); List<UserInfo> getUsers(); + UserInfo getUser(int userId); void setPermissionEnforcement(String permission, int enforcement); int getPermissionEnforcement(String permission); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 55426b8..b06b4a5 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2153,7 +2153,8 @@ public abstract class PackageManager { if ((flags & GET_SIGNATURES) != 0) { packageParser.collectCertificates(pkg, 0); } - return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null); + return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, false, + COMPONENT_ENABLED_STATE_DEFAULT); } /** @@ -2637,10 +2638,17 @@ public abstract class PackageManager { public abstract void updateUserFlags(int id, int flags); /** - * Returns the device identity that verifiers can use to associate their - * scheme to a particular device. This should not be used by anything other - * than a package verifier. - * + * Returns the details for the user specified by userId. + * @param userId the user id of the user + * @return UserInfo for the specified user, or null if no such user exists. + * @hide + */ + public abstract UserInfo getUser(int userId); + + /** + * Returns the device identity that verifiers can use to associate their scheme to a particular + * device. This should not be used by anything other than a package verifier. + * * @return identity that uniquely identifies current device * @hide */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 07d231a..eb8536f 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -230,6 +230,15 @@ public class PackageParser { return name.endsWith(".apk"); } + public static PackageInfo generatePackageInfo(PackageParser.Package p, + int gids[], int flags, long firstInstallTime, long lastUpdateTime, + HashSet<String> grantedPermissions) { + + return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, + grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, + UserId.getCallingUserId()); + } + /** * Generate and return the {@link PackageInfo} for a parsed package. * @@ -238,15 +247,15 @@ public class PackageParser { */ public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions) { + HashSet<String> grantedPermissions, boolean stopped, int enabledState) { return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, - grantedPermissions, UserId.getCallingUserId()); + grantedPermissions, stopped, enabledState, UserId.getCallingUserId()); } - static PackageInfo generatePackageInfo(PackageParser.Package p, + public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions, int userId) { + HashSet<String> grantedPermissions, boolean stopped, int enabledState, int userId) { PackageInfo pi = new PackageInfo(); pi.packageName = p.packageName; @@ -254,7 +263,7 @@ public class PackageParser { pi.versionName = p.mVersionName; pi.sharedUserId = p.mSharedUserId; pi.sharedUserLabel = p.mSharedUserLabel; - pi.applicationInfo = generateApplicationInfo(p, flags); + pi.applicationInfo = generateApplicationInfo(p, flags, stopped, enabledState, userId); pi.installLocation = p.installLocation; pi.firstInstallTime = firstInstallTime; pi.lastUpdateTime = lastUpdateTime; @@ -290,7 +299,7 @@ public class PackageParser { if (activity.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags, - userId); + stopped, enabledState, userId); } } } @@ -311,7 +320,8 @@ public class PackageParser { final Activity activity = p.receivers.get(i); if (activity.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, userId); + pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, + stopped, enabledState, userId); } } } @@ -332,7 +342,8 @@ public class PackageParser { final Service service = p.services.get(i); if (service.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.services[j++] = generateServiceInfo(p.services.get(i), flags, userId); + pi.services[j++] = generateServiceInfo(p.services.get(i), flags, stopped, + enabledState, userId); } } } @@ -353,7 +364,8 @@ public class PackageParser { final Provider provider = p.providers.get(i); if (provider.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, userId); + pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, stopped, + enabledState, userId); } } } @@ -3068,11 +3080,11 @@ public class PackageParser { // For use by package manager to keep track of where it has done dexopt. public boolean mDidDexOpt; - // User set enabled state. - public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - - // Whether the package has been stopped. - public boolean mSetStopped = false; + // // User set enabled state. + // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + // + // // Whether the package has been stopped. + // public boolean mSetStopped = false; // Additional data supplied by callers. public Object mExtras; @@ -3337,9 +3349,9 @@ public class PackageParser { } } - private static boolean copyNeeded(int flags, Package p, Bundle metaData) { - if (p.mSetEnabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { - boolean enabled = p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + private static boolean copyNeeded(int flags, Package p, int enabledState, Bundle metaData) { + if (enabledState != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + boolean enabled = enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; if (p.applicationInfo.enabled != enabled) { return true; } @@ -3355,30 +3367,32 @@ public class PackageParser { return false; } - public static ApplicationInfo generateApplicationInfo(Package p, int flags) { - return generateApplicationInfo(p, flags, UserId.getCallingUserId()); + public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped, + int enabledState) { + return generateApplicationInfo(p, flags, stopped, enabledState, UserId.getCallingUserId()); } - public static ApplicationInfo generateApplicationInfo(Package p, int flags, int userId) { + public static ApplicationInfo generateApplicationInfo(Package p, int flags, + boolean stopped, int enabledState, int userId) { if (p == null) return null; - if (!copyNeeded(flags, p, null) && userId == 0) { + if (!copyNeeded(flags, p, enabledState, null) && userId == 0) { // CompatibilityMode is global state. It's safe to modify the instance // of the package. if (!sCompatibilityModeEnabled) { p.applicationInfo.disableCompatibilityMode(); } - if (p.mSetStopped) { + if (stopped) { p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; } else { p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; } - if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { p.applicationInfo.enabled = true; - } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { p.applicationInfo.enabled = false; } - p.applicationInfo.enabledSetting = p.mSetEnabled; + p.applicationInfo.enabledSetting = enabledState; return p.applicationInfo; } @@ -3397,18 +3411,18 @@ public class PackageParser { if (!sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } - if (p.mSetStopped) { + if (stopped) { p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; } else { p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; } - if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { ai.enabled = true; - } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { ai.enabled = false; } - ai.enabledSetting = p.mSetEnabled; + ai.enabledSetting = enabledState; return ai; } @@ -3455,15 +3469,16 @@ public class PackageParser { } } - public static final ActivityInfo generateActivityInfo(Activity a, int flags, int userId) { + public static final ActivityInfo generateActivityInfo(Activity a, int flags, boolean stopped, + int enabledState, int userId) { if (a == null) return null; - if (!copyNeeded(flags, a.owner, a.metaData) && userId == 0) { + if (!copyNeeded(flags, a.owner, enabledState, a.metaData) && userId == 0) { return a.info; } // Make shallow copies so we can store the metadata safely ActivityInfo ai = new ActivityInfo(a.info); ai.metaData = a.metaData; - ai.applicationInfo = generateApplicationInfo(a.owner, flags, userId); + ai.applicationInfo = generateApplicationInfo(a.owner, flags, stopped, enabledState, userId); return ai; } @@ -3488,16 +3503,17 @@ public class PackageParser { } } - public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) { + public static final ServiceInfo generateServiceInfo(Service s, int flags, boolean stopped, + int enabledState, int userId) { if (s == null) return null; - if (!copyNeeded(flags, s.owner, s.metaData) + if (!copyNeeded(flags, s.owner, enabledState, s.metaData) && userId == UserId.getUserId(s.info.applicationInfo.uid)) { return s.info; } // Make shallow copies so we can store the metadata safely ServiceInfo si = new ServiceInfo(s.info); si.metaData = s.metaData; - si.applicationInfo = generateApplicationInfo(s.owner, flags, userId); + si.applicationInfo = generateApplicationInfo(s.owner, flags, stopped, enabledState, userId); return si; } @@ -3530,9 +3546,10 @@ public class PackageParser { } } - public static final ProviderInfo generateProviderInfo(Provider p, int flags, int userId) { + public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped, + int enabledState, int userId) { if (p == null) return null; - if (!copyNeeded(flags, p.owner, p.metaData) + if (!copyNeeded(flags, p.owner, enabledState, p.metaData) && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 || p.info.uriPermissionPatterns == null) && userId == 0) { @@ -3544,7 +3561,7 @@ public class PackageParser { if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { pi.uriPermissionPatterns = null; } - pi.applicationInfo = generateApplicationInfo(p.owner, flags, userId); + pi.applicationInfo = generateApplicationInfo(p.owner, flags, stopped, enabledState, userId); return pi; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d1e3642..3e57212 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -60,6 +60,9 @@ <protected-broadcast android:name="android.intent.action.REBOOT" /> <protected-broadcast android:name="android.intent.action.DOCK_EVENT" /> <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" /> + <protected-broadcast android:name="android.intent.action.USER_ADDED" /> + <protected-broadcast android:name="android.intent.action.USER_REMOVED" /> + <protected-broadcast android:name="android.intent.action.USER_SWITCHED" /> <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" /> <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" /> diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index bcba3c2..4ebabd3 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -23,6 +23,7 @@ import com.android.internal.R; import android.app.ActivityManagerNative; import android.app.AlertDialog; +import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -31,14 +32,18 @@ import android.content.IntentFilter; import android.content.pm.UserInfo; import android.media.AudioManager; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemProperties; +import android.os.Vibrator; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.Log; +import android.view.IWindowManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -77,6 +82,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private ToggleAction.State mAirplaneState = ToggleAction.State.Off; private boolean mIsWaitingForEcmExit = false; + private IWindowManager mIWindowManager; + /** * @param context everything needs a context :( */ @@ -119,7 +126,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac * @return A new dialog. */ private AlertDialog createDialog() { - mSilentModeAction = new SilentModeAction(mAudioManager, mHandler); + mSilentModeAction = new SilentModeAction(mContext, mAudioManager, mHandler); mAirplaneModeOn = new ToggleAction( R.drawable.ic_lock_airplane_mode, @@ -200,6 +207,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public void onPress() { try { ActivityManagerNative.getDefault().switchUser(user.id); + getWindowManager().lockNow(); } catch (RemoteException re) { Log.e(TAG, "Couldn't switch user " + re); } @@ -540,10 +548,15 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private final AudioManager mAudioManager; private final Handler mHandler; + private final boolean mHasVibrator; + private final Context mContext; - SilentModeAction(AudioManager audioManager, Handler handler) { + SilentModeAction(Context context, AudioManager audioManager, Handler handler) { mAudioManager = audioManager; mHandler = handler; + mContext = context; + Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + mHasVibrator = vibrator != null && vibrator.hasVibrator(); } private int ringerModeToIndex(int ringerMode) { @@ -567,6 +580,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac // Set up click handler itemView.setTag(i); itemView.setOnClickListener(this); + if (itemView.getId() == R.id.option2 && !mHasVibrator) { + itemView.setVisibility(View.GONE); + } } return v; } @@ -667,4 +683,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac intent.putExtra("state", on); mContext.sendBroadcast(intent); } + + private IWindowManager getWindowManager() { + if (mIWindowManager == null) { + IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE); + mIWindowManager = IWindowManager.Stub.asInterface(b); + } + return mIWindowManager; + } } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index a85b605..eb024e9 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -170,6 +170,15 @@ class AppWidgetService extends IAppWidgetService.Stub sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); + + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1)); + } + }, userFilter); } @Override @@ -192,19 +201,6 @@ class AppWidgetService extends IAppWidgetService.Stub getImplForUser().deleteAllHosts(); } - void cancelBroadcasts(Provider p) { - if (p.broadcast != null) { - mAlarmManager.cancel(p.broadcast); - long token = Binder.clearCallingIdentity(); - try { - p.broadcast.cancel(); - } finally { - Binder.restoreCallingIdentity(token); - } - p.broadcast = null; - } - } - @Override public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException { getImplForUser().bindAppWidgetId(appWidgetId, provider); @@ -222,8 +218,15 @@ class AppWidgetService extends IAppWidgetService.Stub return getImplForUser().startListening(host, packageName, hostId, updatedViews); } - // TODO: Call this from PackageManagerService when a user is removed - public void removeUser(int userId) { + public void onUserRemoved(int userId) { + AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); + if (userId < 1) return; + + if (impl == null) { + AppWidgetServiceImpl.getSettingsFile(userId).delete(); + } else { + impl.onUserRemoved(); + } } private AppWidgetServiceImpl getImplForUser() { diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 182a884..b24823e 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -1484,9 +1484,13 @@ class AppWidgetServiceImpl { } } + static File getSettingsFile(int userId) { + return new File("/data/system/users/" + userId + "/" + SETTINGS_FILENAME); + } + AtomicFile savedStateFile() { File dir = new File("/data/system/users/" + mUserId); - File settingsFile = new File(dir, SETTINGS_FILENAME); + File settingsFile = getSettingsFile(mUserId); if (!dir.exists()) { dir.mkdirs(); if (mUserId == 0) { @@ -1500,6 +1504,16 @@ class AppWidgetServiceImpl { return new AtomicFile(settingsFile); } + void onUserRemoved() { + // prune the ones we don't want to keep + int N = mInstalledProviders.size(); + for (int i = N - 1; i >= 0; i--) { + Provider p = mInstalledProviders.get(i); + cancelBroadcasts(p); + } + getSettingsFile(mUserId).delete(); + } + void addProvidersForPackageLocked(String pkgName) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.setPackage(pkgName); diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java index 062ab74..2e2a278 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/java/com/android/server/ClipboardService.java @@ -34,6 +34,7 @@ import android.os.Parcel; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.UserId; import android.util.Pair; import android.util.Slog; @@ -204,7 +205,7 @@ public class ClipboardService extends IClipboard.Stub { PackageInfo pi; try { pi = mPm.getPackageInfo(pkg, 0); - if (pi.applicationInfo.uid != uid) { + if (!UserId.isSameApp(pi.applicationInfo.uid, uid)) { throw new SecurityException("Calling uid " + uid + " does not own package " + pkg); } diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 8ee12bc..6d83f30 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -25,9 +25,11 @@ import android.app.PendingIntent; import android.app.WallpaperInfo; import android.app.backup.BackupManager; import android.app.backup.WallpaperBackupHelper; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -36,6 +38,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.os.Binder; import android.os.Bundle; +import android.os.Environment; import android.os.FileUtils; import android.os.IBinder; import android.os.RemoteException; @@ -401,41 +404,48 @@ class WallpaperManagerService extends IWallpaperManager.Stub { wallpaper.wallpaperObserver.stopWatching(); } } - + public void systemReady() { if (DEBUG) Slog.v(TAG, "systemReady"); WallpaperData wallpaper = mWallpaperMap.get(0); switchWallpaper(wallpaper); wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper); wallpaper.wallpaperObserver.startWatching(); - ActivityManagerService ams = (ActivityManagerService) ServiceManager - .getService(Context.ACTIVITY_SERVICE); - ams.addUserListener(new ActivityManagerService.UserListener() { - - @Override - public void onUserChanged(int userId) { - switchUser(userId); - } + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_SWITCHED); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { @Override - public void onUserAdded(int userId) { - } - - @Override - public void onUserRemoved(int userId) { - } - - @Override - public void onUserLoggedOut(int userId) { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + switchUser(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + } } - - }); + }, userFilter); } String getName() { return mWallpaperMap.get(0).name; } + void removeUser(int userId) { + synchronized (mLock) { + WallpaperData wallpaper = mWallpaperMap.get(userId); + if (wallpaper != null) { + wallpaper.wallpaperObserver.stopWatching(); + mWallpaperMap.remove(userId); + } + File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); + wallpaperFile.delete(); + File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO); + wallpaperInfoFile.delete(); + } + } + void switchUser(int userId) { synchronized (mLock) { mCurrentUserId = userId; @@ -861,7 +871,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } private static JournaledFile makeJournaledFile(int userId) { - final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO; + final String base = getWallpaperDir(userId) + "/" + WALLPAPER_INFO; return new JournaledFile(new File(base), new File(base + ".tmp")); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 60749b3..467297b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -152,6 +152,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -3582,9 +3583,14 @@ public final class ActivityManagerService extends ActivityManagerNative if (doit) { procs.add(app); } - } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid) - || app.processName.equals(packageName) - || app.processName.startsWith(procNamePrefix)) { + // If uid is specified and the uid and process name match + // Or, the uid is not specified and the process name matches + } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid) + && (app.processName.equals(packageName) + || app.processName.startsWith(procNamePrefix))) + || (uid < 0 + && (app.processName.equals(packageName) + || app.processName.startsWith(procNamePrefix)))) { if (app.setAdj >= minOomAdj) { if (!doit) { return true; @@ -3635,7 +3641,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (i=0; i<mMainStack.mHistory.size(); i++) { ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); final boolean samePackage = r.packageName.equals(name); - if ((samePackage || r.task == lastTask) + if (r.userId == userId + && (samePackage || r.task == lastTask) && (r.app == null || evenPersistent || !r.app.persistent)) { if (!doit) { if (r.finishing) { @@ -3685,7 +3692,7 @@ public final class ActivityManagerService extends ActivityManagerNative } ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>(); - for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) { + for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(userId).values()) { if (provider.info.packageName.equals(name) && (provider.proc == null || evenPersistent || !provider.proc.persistent)) { if (!doit) { @@ -4118,7 +4125,16 @@ public final class ActivityManagerService extends ActivityManagerNative } } }, pkgFilter); - + + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent); + } + }, userFilter); + synchronized (this) { // Ensure that any processes we had put on hold are now started // up. @@ -12469,7 +12485,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST_LIGHT) Slog.v( TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent - + " ordered=" + ordered); + + " ordered=" + ordered + " userid=" + userId); if ((resultTo != null) && !ordered) { Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); } @@ -14593,25 +14609,6 @@ public final class ActivityManagerService extends ActivityManagerNative private int mCurrentUserId; private SparseIntArray mLoggedInUsers = new SparseIntArray(5); - private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3); - - public interface UserListener { - public void onUserChanged(int userId); - - public void onUserAdded(int userId); - - public void onUserRemoved(int userId); - - public void onUserLoggedOut(int userId); - } - - public void addUserListener(UserListener listener) { - synchronized (this) { - if (!mUserListeners.contains(listener)) { - mUserListeners.add(listener); - } - } - } public boolean switchUser(int userId) { final int callingUid = Binder.getCallingUid(); @@ -14622,8 +14619,6 @@ public final class ActivityManagerService extends ActivityManagerNative if (mCurrentUserId == userId) return true; - ArrayList<UserListener> listeners; - synchronized (this) { // Check if user is already logged in, otherwise check if user exists first before // adding to the list of logged in users. @@ -14640,23 +14635,44 @@ public final class ActivityManagerService extends ActivityManagerNative startHomeActivityLocked(userId); } - listeners = (ArrayList<UserListener>) mUserListeners.clone(); - } - // Inform the listeners - for (UserListener listener : listeners) { - listener.onUserChanged(userId); } + + // Inform of user switch + Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED); + addedIntent.putExtra(Intent.EXTRA_USERID, userId); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + return true; } - private boolean userExists(int userId) { - try { - List<UserInfo> users = AppGlobals.getPackageManager().getUsers(); - for (UserInfo user : users) { - if (user.id == userId) { - return true; + private void onUserRemoved(Intent intent) { + int extraUserId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + if (extraUserId < 1) return; + + // Kill all the processes for the user + ArrayList<Pair<String, Integer>> pkgAndUids = new ArrayList<Pair<String,Integer>>(); + synchronized (this) { + HashMap<String,SparseArray<ProcessRecord>> map = mProcessNames.getMap(); + for (Entry<String, SparseArray<ProcessRecord>> uidMap : map.entrySet()) { + SparseArray<ProcessRecord> uids = uidMap.getValue(); + for (int i = 0; i < uids.size(); i++) { + if (UserId.getUserId(uids.keyAt(i)) == extraUserId) { + pkgAndUids.add(new Pair<String,Integer>(uidMap.getKey(), uids.keyAt(i))); + } } } + + for (Pair<String,Integer> pkgAndUid : pkgAndUids) { + forceStopPackageLocked(pkgAndUid.first, pkgAndUid.second, + false, false, true, true, extraUserId); + } + } + } + + private boolean userExists(int userId) { + try { + UserInfo user = AppGlobals.getPackageManager().getUser(userId); + return user != null; } catch (RemoteException re) { // Won't happen, in same process } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 067bf28..1593707 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -134,6 +134,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -404,7 +405,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; - final UserManager mUserManager; + static UserManager sUserManager; // Stores a list of users whose package restrictions file needs to be updated private HashSet<Integer> mDirtyUsers = new HashSet<Integer>(); @@ -632,7 +633,7 @@ public class PackageManagerService extends IPackageManager.Stub { packages[i] = ent.getKey(); components[i] = ent.getValue(); PackageSetting ps = mSettings.mPackages.get(ent.getKey()); - uids[i] = (ps != null) ? ps.uid : -1; + uids[i] = (ps != null) ? ps.appId : -1; i++; } size = i; @@ -676,14 +677,15 @@ public class PackageManagerService extends IPackageManager.Stub { } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, res.pkg.applicationInfo.packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, res.pkg.applicationInfo.packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, - res.pkg.applicationInfo.packageName, null); + res.pkg.applicationInfo.packageName, null, + UserId.USER_ALL); } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now @@ -820,6 +822,7 @@ public class PackageManagerService extends IPackageManager.Stub { } void scheduleWritePackageRestrictionsLocked(int userId) { + if (!sUserManager.exists(userId)) return; mDirtyUsers.add(userId); if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY); @@ -920,7 +923,7 @@ public class PackageManagerService extends IPackageManager.Stub { mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); - mUserManager = new UserManager(mInstaller, mUserAppDataDir); + sUserManager = new UserManager(mInstaller, mUserAppDataDir); readPermissions(); @@ -1086,7 +1089,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " no longer exists; wiping its data"; reportSettingsProblem(Log.WARN, msg); mInstaller.remove(ps.name, 0); - mUserManager.removePackageForAllUsers(ps.name); + sUserManager.removePackageForAllUsers(ps.name); } } } @@ -1242,7 +1245,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Couldn't remove app data directory for package: " + ps.name + ", retcode=" + retCode); } else { - mUserManager.removePackageForAllUsers(ps.name); + sUserManager.removePackageForAllUsers(ps.name); } if (ps.codePath != null) { if (!ps.codePath.delete()) { @@ -1506,29 +1509,39 @@ public class PackageManagerService extends IPackageManager.Stub { return cur; } - PackageInfo generatePackageInfo(PackageParser.Package p, int flags) { + PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + PackageInfo pi; if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { // The package has been uninstalled but has retained data and resources. - return PackageParser.generatePackageInfo(p, null, flags, 0, 0, null); - } - final PackageSetting ps = (PackageSetting)p.mExtras; - if (ps == null) { - return null; + pi = PackageParser.generatePackageInfo(p, null, flags, 0, 0, null, false, 0, userId); + } else { + final PackageSetting ps = (PackageSetting) p.mExtras; + if (ps == null) { + return null; + } + final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + pi = PackageParser.generatePackageInfo(p, gp.gids, flags, + ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions, + ps.getStopped(userId), ps.getEnabled(userId), userId); + pi.applicationInfo.enabledSetting = ps.getEnabled(userId); + pi.applicationInfo.enabled = + pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT + || pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED; } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - return PackageParser.generatePackageInfo(p, gp.gids, flags, - ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions); + return pi; } @Override public PackageInfo getPackageInfo(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { - return generatePackageInfo(p, flags); + return generatePackageInfo(p, flags, userId); } if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { return generatePackageInfoFromSettingsLPw(packageName, flags, userId); @@ -1563,6 +1576,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getPackageUid(String packageName, int userId) { + if (!sUserManager.exists(userId)) return -1; // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1673,6 +1687,7 @@ public class PackageManagerService extends IPackageManager.Stub { private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { if (ps.pkg == null) { @@ -1682,15 +1697,18 @@ public class PackageManagerService extends IPackageManager.Stub { } return null; } - return PackageParser.generateApplicationInfo(ps.pkg, flags); + return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } return null; } private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { + PackageParser.Package pkg = new PackageParser.Package(packageName); if (ps.pkg == null) { ps.pkg = new PackageParser.Package(packageName); ps.pkg.applicationInfo.packageName = packageName; @@ -1701,15 +1719,16 @@ public class PackageManagerService extends IPackageManager.Stub { getDataPathForPackage(ps.pkg.packageName, 0).getPath(); ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; } - ps.pkg.mSetEnabled = ps.getEnabled(userId); - ps.pkg.mSetStopped = ps.getStopped(userId); - return generatePackageInfo(ps.pkg, flags); + // ps.pkg.mSetEnabled = ps.getEnabled(userId); + // ps.pkg.mSetStopped = ps.getStopped(userId); + return generatePackageInfo(ps.pkg, flags, userId); } return null; } @Override public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1717,8 +1736,11 @@ public class PackageManagerService extends IPackageManager.Stub { TAG, "getApplicationInfo " + packageName + ": " + p); if (p != null) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) return null; // Note: isEnabledLP() does not apply here - always return info - return PackageParser.generateApplicationInfo(p, flags); + return PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId), + ps.getEnabled(userId)); } if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; @@ -1782,12 +1804,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Activity a = mActivities.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { - return PackageParser.generateActivityInfo(a, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } if (mResolveComponentName.equals(component)) { return mResolveActivity; @@ -1798,12 +1824,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Activity a = mReceivers.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { - return PackageParser.generateActivityInfo(a, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } return null; @@ -1811,12 +1841,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Service s = mServices.mServices.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getServiceInfo " + component + ": " + s); if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) { - return PackageParser.generateServiceInfo(s, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateServiceInfo(s, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } return null; @@ -1824,12 +1858,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Provider p = mProvidersByComponent.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getProviderInfo " + component + ": " + p); if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) { - return PackageParser.generateProviderInfo(p, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateProviderInfo(p, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } return null; @@ -2253,6 +2291,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId); return chooseBestActivity(intent, resolvedType, flags, query, userId); } @@ -2294,6 +2333,7 @@ public class PackageManagerService extends IPackageManager.Stub { ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int priority, int userId) { + if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { if (intent.getSelector() != null) { @@ -2389,6 +2429,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2427,6 +2468,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; final String resultsAction = intent.getAction(); List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags @@ -2596,6 +2638,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2632,6 +2675,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) { List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId); + if (!sUserManager.exists(userId)) return null; if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, @@ -2645,6 +2689,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2723,7 +2768,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { final PackageParser.Package p = mPackages.get(packageName); if (p != null) { - pi = generatePackageInfo(p, flags); + pi = generatePackageInfo(p, flags, userId); } } @@ -2743,6 +2788,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, String lastRead, int userId) { + if (!sUserManager.exists(userId)) return null; final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>(); final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; final String[] keys; @@ -2763,15 +2809,16 @@ public class PackageManagerService extends IPackageManager.Stub { final String packageName = keys[i++]; ApplicationInfo ai = null; + final PackageSetting ps = mSettings.mPackages.get(packageName); if (listUninstalled) { - final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId); } } else { final PackageParser.Package p = mPackages.get(packageName); - if (p != null) { - ai = PackageParser.generateApplicationInfo(p, flags, userId); + if (p != null && ps != null) { + ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } @@ -2794,13 +2841,17 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { final Iterator<PackageParser.Package> i = mPackages.values().iterator(); - final int userId = UserId.getUserId(Binder.getCallingUid()); + final int userId = UserId.getCallingUserId(); while (i.hasNext()) { final PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p))) { - finalList.add(PackageParser.generateApplicationInfo(p, flags, userId)); + PackageSetting ps = mSettings.mPackages.get(p.packageName); + finalList.add(PackageParser.generateApplicationInfo(p, flags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId)); } } } @@ -2810,14 +2861,21 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ProviderInfo resolveContentProvider(String name, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; // reader synchronized (mPackages) { final PackageParser.Provider provider = mProviders.get(name); + PackageSetting ps = provider != null + ? mSettings.mPackages.get(provider.owner.packageName) + : null; return provider != null && mSettings.isEnabledLPr(provider.info, flags, userId) && (!mSafeMode || (provider.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0) - ? PackageParser.generateProviderInfo(provider, flags, userId) + ? PackageParser.generateProviderInfo(provider, flags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId) : null; } } @@ -2831,16 +2889,20 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet() .iterator(); - final int userId = UserId.getUserId(Binder.getCallingUid()); + final int userId = UserId.getCallingUserId(); while (i.hasNext()) { Map.Entry<String, PackageParser.Provider> entry = i.next(); PackageParser.Provider p = entry.getValue(); + PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); if (p.syncable && (!mSafeMode || (p.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0)) { outNames.add(entry.getKey()); - outInfo.add(PackageParser.generateProviderInfo(p, 0, userId)); + outInfo.add(PackageParser.generateProviderInfo(p, 0, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId)); } } } @@ -2857,6 +2919,7 @@ public class PackageManagerService extends IPackageManager.Stub { UserId.getUserId(uid) : UserId.getCallingUserId(); while (i.hasNext()) { final PackageParser.Provider p = i.next(); + PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); if (p.info.authority != null && (processName == null || (p.info.processName.equals(processName) @@ -2867,7 +2930,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (finalList == null) { finalList = new ArrayList<ProviderInfo>(3); } - finalList.add(PackageParser.generateProviderInfo(p, flags, userId)); + finalList.add(PackageParser.generateProviderInfo(p, flags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId)); } } } @@ -3511,7 +3577,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } - pkg.applicationInfo.uid = pkgSetting.uid; + pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting; if (!verifySignaturesLP(pkgSetting, pkg)) { @@ -3618,7 +3684,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (ret >= 0) { // TODO: Kill the processes first // Remove the data directories for all users - mUserManager.removePackageForAllUsers(pkgName); + sUserManager.removePackageForAllUsers(pkgName); // Old data gone! String msg = "System package " + pkg.packageName + " has changed from uid: " @@ -3639,7 +3705,7 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } // Create data directories for all users - mUserManager.installPackageForAllUsers(pkgName, + sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid); } if (!recovered) { @@ -3681,7 +3747,7 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } // Create data directories for all users - mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid); + sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid); if (dataPath.exists()) { pkg.applicationInfo.dataDir = dataPath.getPath(); @@ -4510,12 +4576,14 @@ public class PackageManagerService extends IPackageManager.Stub { extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; return super.queryIntent(intent, resolvedType, defaultOnly, userId); } public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = flags; return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); @@ -4523,6 +4591,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) { + if (!sUserManager.exists(userId)) return null; if (packageActivities == null) { return null; } @@ -4605,6 +4674,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) return true; PackageParser.Package p = filter.activity.owner; if (p != null) { PackageSetting ps = (PackageSetting)p.mExtras; @@ -4626,6 +4696,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, int match, int userId) { + if (!sUserManager.exists(userId)) return null; if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) { return null; } @@ -4635,7 +4706,11 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final ResolveInfo res = new ResolveInfo(); - res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, userId); + PackageSetting ps = (PackageSetting) activity.owner.mExtras; + res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId); if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = info; } @@ -4696,6 +4771,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = flags; return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); @@ -4703,6 +4779,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags, ArrayList<PackageParser.Service> packageServices, int userId) { + if (!sUserManager.exists(userId)) return null; if (packageServices == null) { return null; } @@ -4780,6 +4857,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) return true; PackageParser.Package p = filter.service.owner; if (p != null) { PackageSetting ps = (PackageSetting)p.mExtras; @@ -4802,6 +4880,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, int match, int userId) { + if (!sUserManager.exists(userId)) return null; final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) { return null; @@ -4812,7 +4891,11 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final ResolveInfo res = new ResolveInfo(); - res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, userId); + PackageSetting ps = (PackageSetting) service.owner.mExtras; + res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId); if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } @@ -4903,23 +4986,32 @@ public class PackageManagerService extends IPackageManager.Stub { }; static final void sendPackageBroadcast(String action, String pkg, - Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) { + Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { - final Intent intent = new Intent(action, - pkg != null ? Uri.fromParts("package", pkg, null) : null); - if (extras != null) { - intent.putExtras(extras); - } - if (targetPkg != null) { - intent.setPackage(targetPkg); - } - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - // TODO: Fix the userId argument - am.broadcastIntent(null, intent, null, finishedReceiver, - 0, null, null, null, finishedReceiver != null, false, - Binder.getOrigCallingUser()); + int[] userIds = userId == UserId.USER_ALL + ? sUserManager.getUserIds() + : new int[] {userId}; + for (int id : userIds) { + final Intent intent = new Intent(action, + pkg != null ? Uri.fromParts("package", pkg, null) : null); + if (extras != null) { + intent.putExtras(extras); + } + if (targetPkg != null) { + intent.setPackage(targetPkg); + } + // Modify the UID when posting to other users + int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + if (uid > 0 && id > 0) { + uid = UserId.getUid(id, UserId.getAppId(uid)); + intent.putExtra(Intent.EXTRA_UID, uid); + } + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + am.broadcastIntent(null, intent, null, finishedReceiver, + 0, null, null, null, finishedReceiver != null, false, id); + } } catch (RemoteException ex) { } } @@ -5062,13 +5154,13 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); } } @@ -7092,11 +7184,11 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putBoolean(Intent.EXTRA_REPLACING, true); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, - null, packageName, null); + null, packageName, null, UserId.USER_ALL); } } // Force a gc here. @@ -7129,14 +7221,15 @@ public class PackageManagerService extends IPackageManager.Stub { } if (removedPackage != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); if (fullRemove && !replacing) { sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); } } if (removedUid >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null); + sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null, + UserId.getUserId(removedUid)); } } } @@ -7168,7 +7261,7 @@ public class PackageManagerService extends IPackageManager.Stub { // we don't consider this to be a failure of the core package deletion } else { // TODO: Kill the processes first - mUserManager.removePackageForAllUsers(packageName); + sUserManager.removePackageForAllUsers(packageName); } schedulePackageCleaning(packageName); } @@ -7732,12 +7825,14 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId) { + if (!sUserManager.exists(userId)) return; setEnabledSetting(appPackageName, null, newState, flags, userId); } @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { + if (!sUserManager.exists(userId)) return; setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags, userId); } @@ -7776,11 +7871,11 @@ public class PackageManagerService extends IPackageManager.Stub { + "/" + className); } // Allow root and verify that userId is not being specified by a different user - if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.uid)) { + if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.appId)) { throw new SecurityException( "Permission Denial: attempt to change component state from pid=" + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.uid); + + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } if (className == null) { // We're dealing with an application/package level state change @@ -7789,7 +7884,7 @@ public class PackageManagerService extends IPackageManager.Stub { return; } pkgSetting.setEnabled(newState, userId); - pkgSetting.pkg.mSetEnabled = newState; + // pkgSetting.pkg.mSetEnabled = newState; } else { // We're dealing with a component level state change // First, verify that this is a valid class name. @@ -7825,7 +7920,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } mSettings.writePackageRestrictionsLPr(userId); - packageUid = pkgSetting.uid; + packageUid = UserId.getUid(userId, pkgSetting.appId); components = mPendingBroadcasts.get(packageName); final boolean newPackage = components == null; if (newPackage) { @@ -7873,10 +7968,12 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag); extras.putInt(Intent.EXTRA_UID, packageUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null, + UserId.getUserId(packageUid)); } public void setPackageStoppedState(String packageName, boolean stopped, int userId) { + if (!sUserManager.exists(userId)) return; final int uid = Binder.getCallingUid(); final int permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); @@ -7900,6 +7997,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getApplicationEnabledSetting(String packageName, int userId) { + if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int uid = Binder.getCallingUid(); checkValidCaller(uid, userId); // reader @@ -7910,6 +8008,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getComponentEnabledSetting(ComponentName componentName, int userId) { + if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int uid = Binder.getCallingUid(); checkValidCaller(uid, userId); // reader @@ -8383,7 +8482,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " at code path: " + ps.codePathString); // We do have a valid package installed on sdcard processCids.put(args, ps.codePathString); - int uid = ps.uid; + int uid = ps.appId; if (uid != -1) { uidList[num++] = uid; } @@ -8436,7 +8535,7 @@ public class PackageManagerService extends IPackageManager.Stub { } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, null, finishedReceiver); + sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserId.USER_ALL); } } @@ -8860,8 +8959,12 @@ public class PackageManagerService extends IPackageManager.Stub { // TODO(kroot): Add a real permission for creating users enforceSystemOrRoot("Only the system can create users"); - // TODO(kroot): fix this API - UserInfo userInfo = mUserManager.createUser(name, flags, new ArrayList<ApplicationInfo>()); + UserInfo userInfo = sUserManager.createUser(name, flags); + if (userInfo != null) { + Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); + addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + } return userInfo; } @@ -8869,13 +8972,34 @@ public class PackageManagerService extends IPackageManager.Stub { // TODO(kroot): Add a real permission for removing users enforceSystemOrRoot("Only the system can remove users"); - if (userId == 0) { + if (userId == 0 || !sUserManager.exists(userId)) { return false; } - mUserManager.removeUser(userId); + + cleanUpUser(userId); + + if (sUserManager.removeUser(userId)) { + // Let other services shutdown any activity + Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED); + addedIntent.putExtra(Intent.EXTRA_USERID, userId); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + } + sUserManager.removePackageFolders(userId); return true; } + private void cleanUpUser(int userId) { + // Disable all the packages for the user first + synchronized (mPackages) { + Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet(); + for (Entry<String, PackageSetting> entry : entries) { + entry.getValue().removeUser(userId); + } + if (mDirtyUsers.remove(userId)); + mSettings.removeUserLPr(userId); + } + } + @Override public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { mContext.enforceCallingOrSelfPermission( @@ -8887,8 +9011,22 @@ public class PackageManagerService extends IPackageManager.Stub { } } + @Override public List<UserInfo> getUsers() { - return mUserManager.getUsers(); + enforceSystemOrRoot("Only the system can query users"); + return sUserManager.getUsers(); + } + + @Override + public UserInfo getUser(int userId) { + enforceSystemOrRoot("Only the system can remove users"); + return sUserManager.getUser(userId); + } + + @Override + public void updateUserName(int userId, String name) { + enforceSystemOrRoot("Only the system can rename users"); + sUserManager.updateUserName(userId, name); } @Override diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java index 48ed9bf..f7f0870 100644 --- a/services/java/com/android/server/pm/PackageSetting.java +++ b/services/java/com/android/server/pm/PackageSetting.java @@ -24,7 +24,7 @@ import java.io.File; * Settings data for a particular package we know about. */ final class PackageSetting extends PackageSettingBase { - int uid; + int appId; PackageParser.Package pkg; SharedUserSetting sharedUser; @@ -41,7 +41,7 @@ final class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig) { super(orig); - uid = orig.uid; + appId = orig.appId; pkg = orig.pkg; sharedUser = orig.sharedUser; } @@ -50,6 +50,6 @@ final class PackageSetting extends PackageSettingBase { public String toString() { return "PackageSetting{" + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "/" + uid + "}"; + + " " + name + "/" + appId + "}"; } }
\ No newline at end of file diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java index b7cf8d6..56f2166 100644 --- a/services/java/com/android/server/pm/PackageSettingBase.java +++ b/services/java/com/android/server/pm/PackageSettingBase.java @@ -273,4 +273,13 @@ class PackageSettingBase extends GrantedPermissions { return COMPONENT_ENABLED_STATE_DEFAULT; } } + + void removeUser(int userId) { + enabled.delete(userId); + stopped.delete(userId); + enabledComponents.delete(userId); + disabledComponents.delete(userId); + notLaunched.delete(userId); + } + } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index b541c8c..bb7f4fc 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -275,7 +275,7 @@ final class Settings { p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, - p.nativeLibraryPathString, p.uid, p.versionCode, p.pkgFlags); + p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags); mDisabledSysPackages.remove(name); return ret; } @@ -284,7 +284,7 @@ final class Settings { String nativeLibraryPathString, int uid, int vc, int pkgFlags) { PackageSetting p = mPackages.get(name); if (p != null) { - if (p.uid == uid) { + if (p.appId == uid) { return p; } PackageManagerService.reportSettingsProblem(Log.ERROR, @@ -293,7 +293,7 @@ final class Settings { } p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, vc, pkgFlags); - p.uid = uid; + p.appId = uid; if (addUserIdLPw(uid, p, name)) { mPackages.put(name, p); return p; @@ -407,7 +407,7 @@ final class Settings { p.copyFrom(origPackage); p.signatures = s; p.sharedUser = origPackage.sharedUser; - p.uid = origPackage.uid; + p.appId = origPackage.appId; p.origPackage = origPackage; mRenamedPackages.put(name, origPackage.name); name = origPackage.name; @@ -435,7 +435,7 @@ final class Settings { } } if (sharedUser != null) { - p.uid = sharedUser.userId; + p.appId = sharedUser.userId; } else { // Clone the setting here for disabled system packages PackageSetting dis = mDisabledSysPackages.get(name); @@ -447,7 +447,7 @@ final class Settings { if (dis.signatures.mSignatures != null) { p.signatures.mSignatures = dis.signatures.mSignatures.clone(); } - p.uid = dis.uid; + p.appId = dis.appId; // Clone permissions p.grantedPermissions = new HashSet<String>(dis.grantedPermissions); // Clone component info @@ -464,14 +464,14 @@ final class Settings { } } // Add new setting to list of user ids - addUserIdLPw(p.uid, p, name); + addUserIdLPw(p.appId, p, name); } else { // Assign new user id - p.uid = newUserIdLPw(p); + p.appId = newUserIdLPw(p); } } } - if (p.uid < 0) { + if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, "Package " + name + " could not be assigned a valid uid"); return null; @@ -539,9 +539,9 @@ final class Settings { + p.sharedUser + " but is now " + sharedUser + "; I am not changing its files so it will probably fail!"); p.sharedUser.packages.remove(p); - } else if (p.uid != sharedUser.userId) { + } else if (p.appId != sharedUser.userId) { PackageManagerService.reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user id " + p.uid + "Package " + p.name + " was user id " + p.appId + " but is now user " + sharedUser + " with id " + sharedUser.userId + "; I am not changing its files so it will probably fail!"); @@ -549,7 +549,7 @@ final class Settings { sharedUser.packages.add(p); p.sharedUser = sharedUser; - p.uid = sharedUser.userId; + p.appId = sharedUser.userId; } } @@ -614,8 +614,8 @@ final class Settings { return p.sharedUser.userId; } } else { - removeUserIdLPw(p.uid); - return p.uid; + removeUserIdLPw(p.appId); + return p.appId; } } return -1; @@ -628,7 +628,7 @@ final class Settings { p.sharedUser.packages.remove(p); p.sharedUser.packages.add(newp); } else { - replaceUserIdLPw(p.uid, newp); + replaceUserIdLPw(p.appId, newp); } } mPackages.put(name, newp); @@ -1317,9 +1317,9 @@ final class Settings { serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); } if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", Integer.toString(pkg.uid)); + serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { - serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid)); + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } serializer.startTag(null, "perms"); if (pkg.sharedUser == null) { @@ -1364,9 +1364,9 @@ final class Settings { serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", Integer.toString(pkg.uid)); + serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { - serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid)); + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } if (pkg.uidError) { serializer.attribute(null, "uidError", "true"); @@ -1607,7 +1607,7 @@ final class Settings { final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator(); while (disabledIt.hasNext()) { final PackageSetting disabledPs = disabledIt.next(); - final Object id = getUserIdLPr(disabledPs.uid); + final Object id = getUserIdLPr(disabledPs.appId); if (id != null && id instanceof SharedUserSetting) { disabledPs.sharedUser = (SharedUserSetting) id; } @@ -1753,10 +1753,10 @@ final class Settings { } } String idStr = parser.getAttributeValue(null, "userId"); - ps.uid = idStr != null ? Integer.parseInt(idStr) : 0; - if (ps.uid <= 0) { + ps.appId = idStr != null ? Integer.parseInt(idStr) : 0; + if (ps.appId <= 0) { String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - ps.uid = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; } int outerDepth = parser.getDepth(); int type; @@ -2164,6 +2164,13 @@ final class Settings { } } + void removeUserLPr(int userId) { + File file = getUserPackagesStateFile(userId); + file.delete(); + file = getUserPackagesStateBackupFile(userId); + file.delete(); + } + // Returns -1 if we could not find an available UserId to assign private int newUserIdLPw(Object obj) { // Let's be stupidly inefficient for now... @@ -2265,11 +2272,11 @@ final class Settings { if (pkgSetting == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } - if (!allowedByPermission && (appId != pkgSetting.uid)) { + if (!allowedByPermission && (appId != pkgSetting.appId)) { throw new SecurityException( "Permission Denial: attempt to change stopped state from pid=" + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.uid); + + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } if (DEBUG_STOPPED) { if (stopped) { @@ -2285,7 +2292,7 @@ final class Settings { if (pkgSetting.installerPackageName != null) { PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgSetting.name, null, - pkgSetting.installerPackageName, null); + pkgSetting.installerPackageName, null, userId); } pkgSetting.setNotLaunched(false, userId); } @@ -2369,7 +2376,7 @@ final class Settings { pw.println(ps.name); } - pw.print(" userId="); pw.print(ps.uid); + pw.print(" userId="); pw.print(ps.appId); pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids)); pw.print(" sharedUser="); pw.println(ps.sharedUser); pw.print(" pkg="); pw.println(ps.pkg); @@ -2513,7 +2520,7 @@ final class Settings { pw.println(ps.name); } pw.print(" userId="); - pw.println(ps.uid); + pw.println(ps.appId); pw.print(" sharedUser="); pw.println(ps.sharedUser); pw.print(" codePath="); diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java index 959e570..4e9e666 100644 --- a/services/java/com/android/server/pm/UserManager.java +++ b/services/java/com/android/server/pm/UserManager.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import android.content.pm.ApplicationInfo; @@ -58,7 +59,7 @@ public class UserManager { private static final String USER_INFO_DIR = "system" + File.separator + "users"; private static final String USER_LIST_FILENAME = "userlist.xml"; - private SparseArray<UserInfo> mUsers; + private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); private final File mUsersDir; private final File mUserListFile; @@ -91,11 +92,36 @@ public class UserManager { } public List<UserInfo> getUsers() { - ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); - for (int i = 0; i < mUsers.size(); i++) { - users.add(mUsers.valueAt(i)); + synchronized (mUsers) { + ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); + for (int i = 0; i < mUsers.size(); i++) { + users.add(mUsers.valueAt(i)); + } + return users; + } + } + + public UserInfo getUser(int userId) { + synchronized (mUsers) { + UserInfo info = mUsers.get(userId); + return info; + } + } + + public boolean exists(int userId) { + synchronized (mUsers) { + return ArrayUtils.contains(mUserIds, userId); + } + } + + public void updateUserName(int userId, String name) { + synchronized (mUsers) { + UserInfo info = mUsers.get(userId); + if (name != null && !name.equals(info.name)) { + info.name = name; + writeUserLocked(info); + } } - return users; } /** @@ -108,9 +134,14 @@ public class UserManager { } private void readUserList() { - mUsers = new SparseArray<UserInfo>(); + synchronized (mUsers) { + readUserListLocked(); + } + } + + private void readUserListLocked() { if (!mUserListFile.exists()) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); return; } FileInputStream fis = null; @@ -126,7 +157,7 @@ public class UserManager { if (type != XmlPullParser.START_TAG) { Slog.e(LOG_TAG, "Unable to read user list"); - fallbackToSingleUser(); + fallbackToSingleUserLocked(); return; } @@ -139,11 +170,11 @@ public class UserManager { } } } - updateUserIds(); + updateUserIdsLocked(); } catch (IOException ioe) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); } catch (XmlPullParserException pe) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); } finally { if (fis != null) { try { @@ -154,15 +185,15 @@ public class UserManager { } } - private void fallbackToSingleUser() { + private void fallbackToSingleUserLocked() { // Create the primary user UserInfo primary = new UserInfo(0, "Primary", UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); mUsers.put(0, primary); - updateUserIds(); + updateUserIdsLocked(); - writeUserList(); - writeUser(primary); + writeUserListLocked(); + writeUserLocked(primary); } /* @@ -172,7 +203,7 @@ public class UserManager { * <name>Primary</name> * </user> */ - private void writeUser(UserInfo userInfo) { + private void writeUserLocked(UserInfo userInfo) { FileOutputStream fos = null; try { final File mUserFile = new File(mUsersDir, userInfo.id + ".xml"); @@ -216,7 +247,7 @@ public class UserManager { * <user id="2"></user> * </users> */ - private void writeUserList() { + private void writeUserListLocked() { FileOutputStream fos = null; try { fos = new FileOutputStream(mUserListFile); @@ -309,17 +340,19 @@ public class UserManager { return null; } - public UserInfo createUser(String name, int flags, List<ApplicationInfo> apps) { + public UserInfo createUser(String name, int flags) { int userId = getNextAvailableId(); UserInfo userInfo = new UserInfo(userId, name, flags); File userPath = new File(mBaseUserPath, Integer.toString(userId)); - if (!createPackageFolders(userId, userPath, apps)) { + if (!createPackageFolders(userId, userPath)) { return null; } - mUsers.put(userId, userInfo); - writeUserList(); - writeUser(userInfo); - updateUserIds(); + synchronized (mUsers) { + mUsers.put(userId, userInfo); + writeUserListLocked(); + writeUserLocked(userInfo); + updateUserIdsLocked(); + } return userInfo; } @@ -328,7 +361,13 @@ public class UserManager { * after the user's processes have been terminated. * @param id the user's id */ - public void removeUser(int id) { + public boolean removeUser(int id) { + synchronized (mUsers) { + return removeUserLocked(id); + } + } + + private boolean removeUserLocked(int id) { // Remove from the list UserInfo userInfo = mUsers.get(id); if (userInfo != null) { @@ -338,11 +377,11 @@ public class UserManager { File userFile = new File(mUsersDir, id + ".xml"); userFile.delete(); // Update the user list - writeUserList(); - // Remove the data directories for all packages for this user - removePackageFolders(id); - updateUserIds(); + writeUserListLocked(); + updateUserIdsLocked(); + return true; } + return false; } public void installPackageForAllUsers(String packageName, int uid) { @@ -376,7 +415,7 @@ public class UserManager { /** * Caches the list of user ids in an array, adjusting the array size when necessary. */ - private void updateUserIds() { + private void updateUserIdsLocked() { if (mUserIds == null || mUserIds.length != mUsers.size()) { mUserIds = new int[mUsers.size()]; } @@ -402,11 +441,10 @@ public class UserManager { return i; } - private boolean createPackageFolders(int id, File userPath, final List<ApplicationInfo> apps) { + private boolean createPackageFolders(int id, File userPath) { // mInstaller may not be available for unit-tests. - if (mInstaller == null || apps == null) return true; + if (mInstaller == null) return true; - final long startTime = SystemClock.elapsedRealtime(); // Create the user path userPath.mkdir(); FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG @@ -414,13 +452,10 @@ public class UserManager { mInstaller.cloneUserData(0, id, false); - final long stopTime = SystemClock.elapsedRealtime(); - Log.i(LOG_TAG, - "Time to create " + apps.size() + " packages = " + (stopTime - startTime) + "ms"); return true; } - private boolean removePackageFolders(int id) { + boolean removePackageFolders(int id) { // mInstaller may not be available for unit-tests. if (mInstaller == null) return true; diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index e8188e7..d736ac1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -54,7 +54,7 @@ public class UserManagerTest extends AndroidTestCase { public void testAddUser() throws Exception { final UserManager details = mUserManager; - UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null); + UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST); assertTrue(userInfo != null); List<UserInfo> list = details.getUsers(); @@ -73,8 +73,8 @@ public class UserManagerTest extends AndroidTestCase { public void testAdd2Users() throws Exception { final UserManager details = mUserManager; - UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null); - UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN, null); + UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST); + UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN); assertTrue(user1 != null); assertTrue(user2 != null); @@ -87,7 +87,7 @@ public class UserManagerTest extends AndroidTestCase { public void testRemoveUser() throws Exception { final UserManager details = mUserManager; - UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null); + UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST); details.removeUser(userInfo.id); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 351c771..5610134 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -45,6 +45,7 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.RemoteException; import java.util.List; @@ -530,6 +531,14 @@ public class MockPackageManager extends PackageManager { * @hide */ @Override + public UserInfo getUser(int userId) { + throw new UnsupportedOperationException(); + } + + /** + * @hide + */ + @Override public boolean removeUser(int id) { throw new UnsupportedOperationException(); } |
