diff options
author | 2012-08-11 21:37:08 -0700 | |
---|---|---|
committer | 2012-08-11 21:37:08 -0700 | |
commit | f83d2d6f6b4a23011226a7b9fee20dabf94820cb (patch) | |
tree | ab3454bef71ac17fb53f3a740ded92f6f5feb3e5 | |
parent | f7178d3cadfeb0101491eeea7d7f3b0d7c26dbe6 (diff) | |
parent | 258848d2ae04f447ff1c18023fa76b139fcc0862 (diff) |
Merge "User Manager service to manage users and query user details" into jb-mr1-dev
30 files changed, 588 insertions, 377 deletions
diff --git a/Android.mk b/Android.mk index 381989c097cd..c2331f2f0406 100644 --- a/Android.mk +++ b/Android.mk @@ -139,6 +139,7 @@ LOCAL_SRC_FILES += \ core/java/android/os/IRemoteCallback.aidl \ core/java/android/os/ISchedulingPolicyService.aidl \ core/java/android/os/IUpdateLock.aidl \ + core/java/android/os/IUserManager.aidl \ core/java/android/os/IVibratorService.aidl \ core/java/android/service/dreams/IDreamManager.aidl \ core/java/android/service/dreams/IDreamService.aidl \ diff --git a/api/current.txt b/api/current.txt index d2f1e4ec8b50..9c6c437b09cb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5386,6 +5386,7 @@ package android.content { field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices"; field public static final java.lang.String UI_MODE_SERVICE = "uimode"; field public static final java.lang.String USB_SERVICE = "usb"; + field public static final java.lang.String USER_SERVICE = "user"; field public static final java.lang.String VIBRATOR_SERVICE = "vibrator"; field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper"; field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p"; @@ -16448,6 +16449,11 @@ package android.os { ctor public TransactionTooLargeException(); } + public class UserManager { + method public java.lang.String getUserName(); + method public boolean supportsMultipleUsers(); + } + public abstract class Vibrator { method public abstract void cancel(); method public abstract boolean hasVibrator(); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 4cb52705d83f..eb1f9a27ecec 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -20,6 +20,7 @@ import com.android.internal.content.PackageHelper; import android.app.ActivityManagerNative; import android.content.ComponentName; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ContainerEncryptionParams; import android.content.pm.FeatureInfo; @@ -39,9 +40,11 @@ import android.content.res.AssetManager; import android.content.res.Resources; import android.net.Uri; import android.os.Binder; +import android.os.IUserManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserManager; import java.io.File; import java.lang.reflect.Field; @@ -59,6 +62,7 @@ import javax.crypto.spec.SecretKeySpec; public final class Pm { IPackageManager mPm; + IUserManager mUm; private WeakHashMap<String, Resources> mResourceCache = new WeakHashMap<String, Resources>(); @@ -82,6 +86,7 @@ public final class Pm { return; } + mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (mPm == null) { System.err.println(PM_NOT_RUNNING_ERR); @@ -985,7 +990,7 @@ public final class Pm { } name = arg; try { - if (mPm.createUser(name, 0) == null) { + if (mUm.createUser(name, 0) == null) { System.err.println("Error: couldn't create User."); showUsage(); } @@ -1017,7 +1022,7 @@ public final class Pm { return; } try { - if (!mPm.removeUser(userId)) { + if (!mUm.removeUser(userId)) { System.err.println("Error: couldn't remove user."); showUsage(); } @@ -1034,7 +1039,7 @@ public final class Pm { return; } try { - List<UserInfo> users = mPm.getUsers(); + List<UserInfo> users = mUm.getUsers(); if (users == null) { System.err.println("Error: couldn't get users"); } else { diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index ba05ee7c927d..935d647d435f 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -51,6 +51,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserId; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -92,6 +93,7 @@ public class AccountManagerService private final Context mContext; private final PackageManager mPackageManager; + private UserManager mUserManager; private HandlerThread mMessageThread; private final MessageHandler mMessageHandler; @@ -245,6 +247,13 @@ public class AccountManagerService initUser(0); } + private UserManager getUserManager() { + if (mUserManager == null) { + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + return mUserManager; + } + private UserAccounts initUser(int userId) { synchronized (mUsers) { UserAccounts accounts = mUsers.get(userId); @@ -382,12 +391,7 @@ public class AccountManagerService } private List<UserInfo> getAllUsers() { - try { - return AppGlobals.getPackageManager().getUsers(); - } catch (RemoteException re) { - // Local to system process, shouldn't happen - } - return null; + return getUserManager().getUsers(); } public void onServiceChanged(AuthenticatorDescription desc, boolean removed) { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 9a50a41b4f27..2face4c22c2c 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -41,8 +41,8 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.UserInfo; import android.content.pm.ManifestDigest; +import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -1182,80 +1182,6 @@ final class ApplicationPackageManager extends PackageManager { return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; } - // Multi-user support - - /** - * @hide - */ - @Override - public UserInfo createUser(String name, int flags) { - try { - return mPM.createUser(name, flags); - } catch (RemoteException e) { - // Should never happen! - } - return null; - } - - /** - * @hide - */ - @Override - public List<UserInfo> getUsers() { - try { - return mPM.getUsers(); - } catch (RemoteException re) { - ArrayList<UserInfo> users = new ArrayList<UserInfo>(); - UserInfo primary = new UserInfo(0, "Root!", null, - UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); - users.add(primary); - return users; - } - } - - /** - * @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); - } catch (RemoteException e) { - return false; - } - } - - /** - * @hide - */ - @Override - public void setUserName(int id, String name) { - try { - mPM.setUserName(id, name); - } catch (RemoteException re) { - } - } - - /** - * @hide - */ - @Override - public void updateUserFlags(int id, int flags) { - // TODO: - } - /** * @hide */ diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d88627871729..4496ce81484a 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -80,6 +80,7 @@ import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; import android.os.IPowerManager; +import android.os.IUserManager; import android.os.Looper; import android.os.PowerManager; import android.os.Process; @@ -87,6 +88,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserId; import android.os.SystemVibrator; +import android.os.UserManager; import android.os.storage.StorageManager; import android.telephony.TelephonyManager; import android.content.ClipboardManager; @@ -498,6 +500,13 @@ class ContextImpl extends Context { return WindowManagerImpl.getDefault().makeCompatible( ctx.mPackageInfo.mCompatibilityInfo); }}); + + registerService(USER_SERVICE, new ServiceFetcher() { + public Object getService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(USER_SERVICE); + IUserManager service = IUserManager.Stub.asInterface(b); + return new UserManager(ctx, service); + }}); } static ContextImpl getImpl(Context context) { @@ -918,6 +927,18 @@ class ContextImpl extends Context { (Activity)null, intent, -1, options); } + /** @hide */ + @Override + public void startActivityAsUser(Intent intent, Bundle options, int userId) { + try { + ActivityManagerNative.getDefault().startActivityAsUser( + mMainThread.getApplicationThread(), intent, + intent.resolveTypeIfNeeded(getContentResolver()), + null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, options, userId); + } catch (RemoteException re) { + } + } + @Override public void startActivities(Intent[] intents) { startActivities(intents, null); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5a7a9896075d..bf60a96ea071 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -890,6 +890,22 @@ public abstract class Context { public abstract void startActivity(Intent intent, Bundle options); /** + * Same as {@link #startActivity(Intent, Bundle)}, but for a specific user. It requires holding + * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission. + * @param intent The description of the activity to start. + * @param options Additional options for how the Activity should be started. + * May be null if there are no options. See {@link android.app.ActivityOptions} + * for how to build the Bundle supplied here; there are no supported definitions + * for building it manually. + * @param userId The user id of the user to start this activity for. + * @throws ActivityNotFoundException + * @hide + */ + public void startActivityAsUser(Intent intent, Bundle options, int userId) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * Same as {@link #startActivities(Intent[], Bundle)} with no options * specified. * @@ -2018,6 +2034,15 @@ public abstract class Context { public static final String SCHEDULING_POLICY_SERVICE = "scheduling_policy"; /** + * Use with {@link #getSystemService} to retrieve a + * {@link android.os.UserManager} for managing users on devices that support multiple users. + * + * @see #getSystemService + * @see android.os.UserManager + */ + public static final String USER_SERVICE = "user"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index f0077203c659..ff4c9a100123 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -287,6 +287,12 @@ public class ContextWrapper extends Context { mBase.startActivity(intent, options); } + /** @hide */ + @Override + public void startActivityAsUser(Intent intent, Bundle options, int userId) { + mBase.startActivityAsUser(intent, options, userId); + } + @Override public void startActivities(Intent[] intents) { mBase.startActivities(intents); diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index badcb03a0e4a..e6303b9544db 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -53,6 +53,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserId; +import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; import android.text.format.DateUtils; @@ -206,16 +207,20 @@ public class SyncManager implements OnAccountsUpdateListener { // Use this as a random offset to seed all periodic syncs private int mSyncRandomOffsetMillis; + private UserManager mUserManager; + private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours - private List<UserInfo> getAllUsers() { - try { - return AppGlobals.getPackageManager().getUsers(); - } catch (RemoteException re) { - // Local to system process, shouldn't happen + private UserManager getUserManager() { + if (mUserManager == null) { + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); } - return null; + return mUserManager; + } + + private List<UserInfo> getAllUsers() { + return getUserManager().getUsers(); } private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 0d87df552347..22807a4c58fc 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -358,11 +358,6 @@ interface IPackageManager { boolean setInstallLocation(int loc); int getInstallLocation(); - UserInfo createUser(in String name, int flags); - boolean removeUser(int userId); - void setUserName(int userId, String name); - ParcelFileDescriptor setUserIcon(int userId); - void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer, int flags, in String installerPackageName, in Uri verificationURI, in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams); @@ -373,9 +368,6 @@ interface IPackageManager { boolean isFirstBoot(); - List<UserInfo> getUsers(); - UserInfo getUser(int userId); - void setPermissionEnforced(String permission, boolean enforced); boolean isPermissionEnforced(String permission); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index cd7ef0e8160e..f287ca51fea1 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2616,56 +2616,6 @@ public abstract class PackageManager { String packageName, IPackageMoveObserver observer, int flags); /** - * Creates a user with the specified name and options. - * - * @param name the user's name - * @param flags flags that identify the type of user and other properties. - * @see UserInfo - * - * @return the UserInfo object for the created user, or null if the user could not be created. - * @hide - */ - public abstract UserInfo createUser(String name, int flags); - - /** - * @return the list of users that were created - * @hide - */ - public abstract List<UserInfo> getUsers(); - - /** - * @param id the ID of the user, where 0 is the primary user. - * @hide - */ - public abstract boolean removeUser(int id); - - /** - * Updates the user's name. - * - * @param id the user's id - * @param name the new name for the user - * @hide - */ - public abstract void setUserName(int id, String name); - - /** - * Changes the user's properties specified by the flags. - * - * @param id the user's id - * @param flags the new flags for the user - * @hide - */ - public abstract void updateUserFlags(int id, int flags); - - /** - * 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. * diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 68a7257012eb..638e273cb915 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -18,12 +18,17 @@ package android.content.pm; import android.os.Parcel; import android.os.Parcelable; +import android.os.Parcelable.Creator; /** * Per-user information. * @hide */ public class UserInfo implements Parcelable { + + /** 6 bits for user type */ + public static final int FLAG_MASK_USER_TYPE = 0x0000003F; + /** * Primary user. Only one user can have this flag set. Meaning of this * flag TBD. @@ -41,6 +46,12 @@ public class UserInfo implements Parcelable { */ public static final int FLAG_GUEST = 0x00000004; + /** + * Indicates the user has restrictions in privileges, in addition to those for normal users. + * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts. + */ + public static final int FLAG_RESTRICTED = 0x00000008; + public int id; public String name; public String iconPath; diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl new file mode 100644 index 000000000000..cb1b9626c60e --- /dev/null +++ b/core/java/android/os/IUserManager.aidl @@ -0,0 +1,36 @@ +/* +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.os; + +import android.os.ParcelFileDescriptor; +import android.content.pm.UserInfo; + +/** + * {@hide} + */ +interface IUserManager { + UserInfo createUser(in String name, int flags); + boolean removeUser(int userHandle); + void setUserName(int userHandle, String name); + ParcelFileDescriptor setUserIcon(int userHandle); + List<UserInfo> getUsers(); + UserInfo getUserInfo(int userHandle); + void setGuestEnabled(boolean enable); + boolean isGuestEnabled(); + void wipeUser(int userHandle); +} diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java new file mode 100644 index 000000000000..9c73392a2412 --- /dev/null +++ b/core/java/android/os/UserManager.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +import com.android.internal.R; +import android.content.Context; +import android.content.pm.UserInfo; +import android.util.Log; + +import java.util.List; + +/** + * Manages users and user details on a multi-user system. + */ +public class UserManager { + + private static String TAG = "UserManager"; + private final IUserManager mService; + private final Context mContext; + + /** @hide */ + public UserManager(Context context, IUserManager service) { + mService = service; + mContext = context; + } + + /** + * Returns whether the system supports multiple users. + * @return true if multiple users can be created, false if it is a single user device. + */ + public boolean supportsMultipleUsers() { + return getMaxSupportedUsers() > 1; + } + + /** + * Returns the user handle for the user that this application is running for. + * @return the user handle of the user making this call. + * @hide + * */ + public int getUserHandle() { + return Process.myUserHandle(); + } + + /** + * Returns the user name of the user making this call. + * @return the user name + */ + public String getUserName() { + try { + return mService.getUserInfo(getUserHandle()).name; + } catch (RemoteException re) { + Log.w(TAG, "Could not get user name", re); + return ""; + } + } + + /** + * Returns the UserInfo object describing a specific user. + * @param userHandle the user handle of the user whose information is being requested. + * @return the UserInfo object for a specific user. + * @hide + * */ + public UserInfo getUserInfo(int userHandle) { + try { + return mService.getUserInfo(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not get user info", re); + return null; + } + } + + /** + * Creates a user with the specified name and options. + * + * @param name the user's name + * @param flags flags that identify the type of user and other properties. + * @see UserInfo + * + * @return the UserInfo object for the created user, or null if the user could not be created. + * @hide + */ + public UserInfo createUser(String name, int flags) { + try { + return mService.createUser(name, flags); + } catch (RemoteException re) { + Log.w(TAG, "Could not create a user", re); + return null; + } + } + + /** + * Returns information for all users on this device. + * @return the list of users that were created. + * @hide + */ + public List<UserInfo> getUsers() { + try { + return mService.getUsers(); + } catch (RemoteException re) { + Log.w(TAG, "Could not get user list", re); + return null; + } + } + + /** + * Removes a user and all associated data. + * @param userHandle the integer handle of the user, where 0 is the primary user. + * @hide + */ + public boolean removeUser(int userHandle) { + try { + return mService.removeUser(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not remove user ", re); + return false; + } + } + + /** + * Updates the user's name. + * + * @param userHandle the user's integer handle + * @param name the new name for the user + * @hide + */ + public void setUserName(int userHandle, String name) { + try { + mService.setUserName(userHandle, name); + } catch (RemoteException re) { + Log.w(TAG, "Could not set the user name ", re); + } + } + + /** + * Returns a file descriptor for the user's photo. PNG data can be written into this file. + * @param userHandle the user for whom to change the photo. + * @return a {@link ParcelFileDescriptor} to which to write the photo. + * @hide + */ + public ParcelFileDescriptor setUserIcon(int userHandle) { + try { + return mService.setUserIcon(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not set the user icon ", re); + return null; + } + } + + /** + * Enable or disable the use of a guest account. If disabled, the existing guest account + * will be wiped. + * @param enable whether to enable a guest account. + * @hide + */ + public void setGuestEnabled(boolean enable) { + try { + mService.setGuestEnabled(enable); + } catch (RemoteException re) { + Log.w(TAG, "Could not change guest account availability to " + enable); + } + } + + /** + * Checks if a guest user is enabled for this device. + * @return whether a guest user is enabled + * @hide + */ + public boolean isGuestEnabled() { + try { + return mService.isGuestEnabled(); + } catch (RemoteException re) { + Log.w(TAG, "Could not retrieve guest enabled state"); + return false; + } + } + + /** + * Wipes all the data for a user, but doesn't remove the user. + * @param userHandle + * @hide + */ + public void wipeUser(int userHandle) { + try { + mService.wipeUser(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not wipe user " + userHandle); + } + } + + /** + * Returns the maximum number of users that can be created on this device. A return value + * of 1 means that it is a single user device. + * @hide + * @return a value greater than or equal to 1 + */ + public int getMaxSupportedUsers() { + return mContext.getResources().getInteger(R.integer.config_multiuserMaximumUsers); + } +} diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index 2411cec0ea31..a1f6735db34e 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -32,6 +32,7 @@ import android.database.ContentObserver; import android.os.Binder; import android.os.Process; import android.os.UserId; +import android.os.UserManager; import android.provider.Settings; import android.util.Log; import android.util.SparseArray; @@ -77,7 +78,8 @@ public class SearchManagerService extends ISearchManager.Stub { Searchables searchables = mSearchables.get(userId); long origId = Binder.clearCallingIdentity(); - boolean userExists = mContext.getPackageManager().getUser(userId) != null; + boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) + .getUserInfo(userId) != null; Binder.restoreCallingIdentity(origId); if (searchables == null && userExists) { diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 6ab323e41f6a..ee0ff8ed0450 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -890,4 +890,7 @@ <!-- Set to true to add links to Cell Broadcast app from Settings and MMS app. --> <bool name="config_cellBroadcastAppLinks">false</bool> + + <!-- Maximum number of supported users --> + <integer name="config_multiuserMaximumUsers">10</integer> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5b86db550b4a..38a431fa0feb 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -280,6 +280,7 @@ <java-symbol type="integer" name="config_wifi_driver_stop_delay" /> <java-symbol type="integer" name="config_soundEffectVolumeDb" /> <java-symbol type="integer" name="config_lockSoundVolumeDb" /> + <java-symbol type="integer" name="config_multiuserMaximumUsers" /> <java-symbol type="color" name="tab_indicator_text_v4" /> diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index cb69660cb729..bb647c3146a7 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -36,6 +36,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserId; import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; @@ -789,7 +790,7 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener | Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_TASK); if (DEBUG) Log.v(TAG, "Starting activity " + intent); - context.startActivity(intent, opts.toBundle()); + context.startActivityAsUser(intent, opts.toBundle(), UserId.USER_CURRENT); } if (usingDrawingCache) { holder.thumbnailViewImage.setDrawingCacheEnabled(false); diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 6c50f1cedb1d..a0e3e3c8d36e 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -38,6 +38,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; +import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; import android.telephony.PhoneStateListener; @@ -278,7 +279,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mItems.add(mSilentModeAction); } - List<UserInfo> users = mContext.getPackageManager().getUsers(); + List<UserInfo> users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) + .getUsers(); if (users.size() > 1) { UserInfo currentUser; try { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 96cf3d3bd807..e8350c182513 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -55,6 +55,7 @@ import com.android.server.input.InputManagerService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; import com.android.server.pm.PackageManagerService; +import com.android.server.pm.UserManagerService; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; import com.android.server.usb.UsbService; @@ -192,6 +193,11 @@ class ServerThread extends Thread { } ActivityManagerService.setSystemProcess(); + + Slog.i(TAG, "User Service"); + ServiceManager.addService(Context.USER_SERVICE, + UserManagerService.getInstance(context)); + mContentResolver = context.getContentResolver(); diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index df6c51eba2f4..533c2cd7af8c 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -1835,7 +1835,7 @@ public class ActiveServices { pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)"); try { - List<UserInfo> users = AppGlobals.getPackageManager().getUsers(); + List<UserInfo> users = mAm.getUserManager().getUsers(); for (UserInfo user : users) { if (mServiceMap.getAllServices(user.id).size() > 0) { boolean printed = false; @@ -1913,8 +1913,8 @@ public class ActiveServices { needSep = printed; } } - } catch (RemoteException re) { - + } catch (Exception e) { + Log.w(TAG, "Exception in dumpServicesLocked: " + e); } if (mPendingServices.size() > 0) { @@ -2028,16 +2028,13 @@ public class ActiveServices { int opti, boolean dumpAll) { ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); + List<UserInfo> users = mAm.getUserManager().getUsers(); if ("all".equals(name)) { synchronized (this) { - try { - List<UserInfo> users = AppGlobals.getPackageManager().getUsers(); - for (UserInfo user : users) { - for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) { - services.add(r1); - } + for (UserInfo user : users) { + for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) { + services.add(r1); } - } catch (RemoteException re) { } } } else { @@ -2055,24 +2052,20 @@ public class ActiveServices { } synchronized (this) { - try { - List<UserInfo> users = AppGlobals.getPackageManager().getUsers(); - for (UserInfo user : users) { - for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) { - if (componentName != null) { - if (r1.name.equals(componentName)) { - services.add(r1); - } - } else if (name != null) { - if (r1.name.flattenToString().contains(name)) { - services.add(r1); - } - } else if (System.identityHashCode(r1) == objectId) { + for (UserInfo user : users) { + for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) { + if (componentName != null) { + if (r1.name.equals(componentName)) { services.add(r1); } + } else if (name != null) { + if (r1.name.flattenToString().contains(name)) { + services.add(r1); + } + } else if (System.identityHashCode(r1) == objectId) { + services.add(r1); } } - } catch (RemoteException re) { } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 5bed0158af2d..d3ec9f7b8b3d 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -27,6 +27,7 @@ import com.android.server.ProcessMap; import com.android.server.SystemServer; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.pm.UserManagerService; import com.android.server.wm.WindowManagerService; import dalvik.system.Zygote; @@ -76,12 +77,12 @@ import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.UserInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -111,6 +112,7 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserId; +import android.os.UserManager; import android.provider.Settings; import android.text.format.Time; import android.util.EventLog; @@ -778,6 +780,10 @@ public final class ActivityManagerService extends ActivityManagerNative static ActivityManagerService mSelf; static ActivityThread mSystemThread; + private int mCurrentUserId; + private SparseIntArray mLoggedInUsers = new SparseIntArray(5); + private UserManager mUserManager; + private final class AppDeathRecipient implements IBinder.DeathRecipient { final ProcessRecord mApp; final int mPid; @@ -4197,19 +4203,14 @@ public final class ActivityManagerService extends ActivityManagerNative // Tell anyone interested that we are done booting! SystemProperties.set("sys.boot_completed", "1"); SystemProperties.set("dev.bootcomplete", "1"); - try { - List<UserInfo> users = AppGlobals.getPackageManager().getUsers(); - for (UserInfo user : users) { - broadcastIntentLocked(null, null, - new Intent(Intent.ACTION_BOOT_COMPLETED, null), - null, null, 0, null, null, - android.Manifest.permission.RECEIVE_BOOT_COMPLETED, - false, false, MY_PID, Process.SYSTEM_UID, user.id); - } - } catch (RemoteException re) { - // Won't happen, in same process + List<UserInfo> users = getUserManager().getUsers(); + for (UserInfo user : users) { + broadcastIntentLocked(null, null, + new Intent(Intent.ACTION_BOOT_COMPLETED, null), + null, null, 0, null, null, + android.Manifest.permission.RECEIVE_BOOT_COMPLETED, + false, false, MY_PID, Process.SYSTEM_UID, user.id); } - } } } @@ -13358,9 +13359,6 @@ public final class ActivityManagerService extends ActivityManagerNative // Multi-user methods - private int mCurrentUserId; - private SparseIntArray mLoggedInUsers = new SparseIntArray(5); - public boolean switchUser(int userId) { final int callingUid = Binder.getCallingUid(); if (callingUid != 0 && callingUid != Process.myUid()) { @@ -13403,7 +13401,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.e(TAG, "Trying to get user from unauthorized app"); return null; } - return AppGlobals.getPackageManager().getUser(mCurrentUserId); + return getUserManager().getUserInfo(mCurrentUserId); } private void onUserRemoved(Intent intent) { @@ -13431,14 +13429,15 @@ public final class ActivityManagerService extends ActivityManagerNative } private boolean userExists(int userId) { - try { - UserInfo user = AppGlobals.getPackageManager().getUser(userId); - return user != null; - } catch (RemoteException re) { - // Won't happen, in same process - } + UserInfo user = getUserManager().getUserInfo(userId); + return user != null; + } - return false; + UserManager getUserManager() { + if (mUserManager == null) { + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + return mUserManager; } private void checkValidCaller(int uid, int userId) { diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 7e5f8cff7182..46c24b0baa55 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -113,6 +113,7 @@ import android.os.MessageQueue.IdleHandler; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserId; +import android.os.UserManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.format.Formatter; @@ -1707,7 +1708,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void updateRulesForAppLocked(int appId) { - for (UserInfo user : mContext.getPackageManager().getUsers()) { + UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + for (UserInfo user : um.getUsers()) { final int uid = UserId.getUid(user.id, appId); updateRulesForUidLocked(uid); } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 180081b26ebb..f257203c278c 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -68,6 +68,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; +import android.content.pm.UserInfo; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageStats; import android.content.pm.ParceledListSlice; @@ -77,7 +78,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; -import android.content.pm.UserInfo; import android.content.pm.ManifestDigest; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; @@ -101,6 +101,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserId; +import android.os.UserManager; import android.provider.Settings.Secure; import android.security.SystemKeyStore; import android.util.DisplayMetrics; @@ -420,7 +421,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; - static UserManager sUserManager; + static UserManagerService sUserManager; // Stores a list of users whose package restrictions file needs to be updated private HashSet<Integer> mDirtyUsers = new HashSet<Integer>(); @@ -899,7 +900,7 @@ public class PackageManagerService extends IPackageManager.Stub { mOnlyCore = onlyCore; mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); mMetrics = new DisplayMetrics(); - mSettings = new Settings(); + mSettings = new Settings(context); mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM); @@ -942,11 +943,12 @@ public class PackageManagerService extends IPackageManager.Stub { mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); - sUserManager = new UserManager(mInstaller, mUserAppDataDir); + sUserManager = UserManagerService.getInstance(context); + sUserManager.setInstaller(this, mInstaller); readPermissions(); - mRestoredSettings = mSettings.readLPw(getUsers()); + mRestoredSettings = mSettings.readLPw(sUserManager.getUsers()); long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, @@ -9459,48 +9461,16 @@ public class PackageManagerService extends IPackageManager.Stub { PackageHelper.APP_INSTALL_AUTO); } - public UserInfo createUser(String name, int flags) { - // TODO(kroot): Add a real permission for creating users - enforceSystemOrRoot("Only the system can create users"); - - 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; - } - - public boolean removeUser(int userId) { - // TODO(kroot): Add a real permission for removing users - enforceSystemOrRoot("Only the system can remove users"); - - if (userId == 0 || !sUserManager.exists(userId)) { - return false; - } - - 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) { + /** Called by UserManagerService */ + void cleanUpUser(int userHandle) { // 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); + entry.getValue().removeUser(userHandle); } - if (mDirtyUsers.remove(userId)); - mSettings.removeUserLPr(userId); + if (mDirtyUsers.remove(userHandle)); + mSettings.removeUserLPr(userHandle); } } @@ -9516,30 +9486,6 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public List<UserInfo> getUsers() { - enforceSystemOrRoot("Only the system can query users"); - return sUserManager.getUsers(); - } - - @Override - public UserInfo getUser(int userId) { - enforceSystemOrRoot("Only the system can query user"); - return sUserManager.getUser(userId); - } - - @Override - public void setUserName(int userId, String name) { - enforceSystemOrRoot("Only the system can rename users"); - sUserManager.setUserName(userId, name); - } - - @Override - public ParcelFileDescriptor setUserIcon(int userId) { - enforceSystemOrRoot("Only the system can update users"); - return sUserManager.setUserIcon(userId); - } - - @Override public void setPermissionEnforced(String permission, boolean enforced) { mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null); if (READ_EXTERNAL_STORAGE.equals(permission)) { diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index def1696dddef..add91d3a62bf 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -34,6 +34,7 @@ import org.xmlpull.v1.XmlSerializer; import android.app.AppGlobals; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; @@ -79,6 +80,7 @@ final class Settings { private static final String TAG = "PackageSettings"; private static final boolean DEBUG_STOPPED = false; + private static final boolean DEBUG_MU = false; private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage"; private static final String ATTR_ENFORCEMENT = "enforcement"; @@ -173,12 +175,15 @@ final class Settings { */ private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>(); + private final Context mContext; + private final File mSystemDir; - Settings() { - this(Environment.getDataDirectory()); + Settings(Context context) { + this(context, Environment.getDataDirectory()); } - Settings(File dataDir) { + Settings(Context context, File dataDir) { + mContext = context; mSystemDir = new File(dataDir, "system"); mSystemDir.mkdirs(); FileUtils.setPermissions(mSystemDir.toString(), @@ -739,6 +744,9 @@ final class Settings { } void readPackageRestrictionsLPr(int userId) { + if (DEBUG_MU) { + Log.i(TAG, "Reading package restrictions for user=" + userId); + } FileInputStream str = null; File userPackagesStateFile = getUserPackagesStateFile(userId); File backupFile = getUserPackagesStateBackupFile(userId); @@ -891,6 +899,9 @@ final class Settings { } void writePackageRestrictionsLPr(int userId) { + if (DEBUG_MU) { + Log.i(TAG, "Writing package restrictions for user=" + userId); + } // Keep the old stopped packages around until we know the new ones have // been successfully written. File userPackagesStateFile = getUserPackagesStateFile(userId); @@ -935,6 +946,7 @@ final class Settings { boolean stopped = pkg.getStopped(userId); boolean notLaunched = pkg.getNotLaunched(userId); int enabled = pkg.getEnabled(userId); + if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + enabled); HashSet<String> enabledComponents = pkg.getEnabledComponents(userId); HashSet<String> disabledComponents = pkg.getDisabledComponents(userId); @@ -1584,7 +1596,24 @@ final class Settings { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); + } + if (mBackupStoppedPackagesFilename.exists() + || mStoppedPackagesFilename.exists()) { + // Read old file + readStoppedLPw(); + mBackupStoppedPackagesFilename.delete(); + mStoppedPackagesFilename.delete(); + // Migrate to new file format + writePackageRestrictionsLPr(0); + } else { + if (users == null) { + readPackageRestrictionsLPr(0); + } else { + for (UserInfo user : users) { + readPackageRestrictionsLPr(user.id); + } + } } final int N = mPendingPackages.size(); @@ -1628,23 +1657,6 @@ final class Settings { } } - if (mBackupStoppedPackagesFilename.exists() - || mStoppedPackagesFilename.exists()) { - // Read old file - readStoppedLPw(); - mBackupStoppedPackagesFilename.delete(); - mStoppedPackagesFilename.delete(); - // Migrate to new file format - writePackageRestrictionsLPr(0); - } else { - if (users == null) { - readPackageRestrictionsLPr(0); - } else { - for (UserInfo user : users) { - readPackageRestrictionsLPr(user.id); - } - } - } mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, " + mSharedUsers.size() + " shared uids\n"); @@ -2378,9 +2390,7 @@ final class Settings { private List<UserInfo> getAllUsers() { long id = Binder.clearCallingIdentity(); try { - return AppGlobals.getPackageManager().getUsers(); - } catch (RemoteException re) { - // Local to system process, shouldn't happen + return UserManagerService.getInstance(mContext).getUsers(); } catch (NullPointerException npe) { // packagemanager not yet initialized } finally { diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManagerService.java index 738ab089bdd5..b55dd247ce21 100644 --- a/services/java/com/android/server/pm/UserManager.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -22,12 +22,17 @@ import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; +import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +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.SystemClock; import android.os.UserId; import android.util.Log; @@ -48,9 +53,9 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; -public class UserManager { +public class UserManagerService extends IUserManager.Stub { - private static final String TAG = "UserManager"; + private static final String TAG = "UserManagerService"; private static final String TAG_NAME = "name"; @@ -75,14 +80,25 @@ public class UserManager { private final File mUsersDir; private final File mUserListFile; private int[] mUserIds; + private boolean mGuestEnabled; private Installer mInstaller; private File mBaseUserPath; + private Context mContext; + private static UserManagerService sInstance; + private PackageManagerService mPm; + + public synchronized static UserManagerService getInstance(Context context) { + if (sInstance == null) { + sInstance = new UserManagerService(context); + } + return sInstance; + } /** * Available for testing purposes. */ - UserManager(File dataDir, File baseUserPath) { + UserManagerService(File dataDir, File baseUserPath) { mUsersDir = new File(dataDir, USER_INFO_DIR); mUsersDir.mkdirs(); // Make zeroth user directory, for services to migrate their files to that location @@ -97,12 +113,19 @@ public class UserManager { readUserList(); } - public UserManager(Installer installer, File baseUserPath) { - this(Environment.getDataDirectory(), baseUserPath); + public UserManagerService(Context context) { + this(Environment.getDataDirectory(), new File(Environment.getDataDirectory(), "user")); + mContext = context; + } + + void setInstaller(PackageManagerService pm, Installer installer) { mInstaller = installer; + mPm = pm; } + @Override public List<UserInfo> getUsers() { + enforceSystemOrRoot("Only the system can query users"); synchronized (mUsers) { ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); for (int i = 0; i < mUsers.size(); i++) { @@ -112,7 +135,9 @@ public class UserManager { } } - public UserInfo getUser(int userId) { + @Override + public UserInfo getUserInfo(int userId) { + enforceSystemOrRoot("Only the system can query user"); synchronized (mUsers) { UserInfo info = mUsers.get(userId); return info; @@ -125,7 +150,9 @@ public class UserManager { } } + @Override public void setUserName(int userId, String name) { + enforceSystemOrRoot("Only the system can rename users"); synchronized (mUsers) { UserInfo info = mUsers.get(userId); if (name != null && !name.equals(info.name)) { @@ -135,7 +162,9 @@ public class UserManager { } } + @Override public ParcelFileDescriptor setUserIcon(int userId) { + enforceSystemOrRoot("Only the system can update users"); synchronized (mUsers) { UserInfo info = mUsers.get(userId); if (info == null) return null; @@ -147,6 +176,57 @@ public class UserManager { } } + @Override + public void setGuestEnabled(boolean enable) { + enforceSystemOrRoot("Only the system can enable guest users"); + synchronized (mUsers) { + if (mGuestEnabled != enable) { + mGuestEnabled = enable; + // Erase any guest user that currently exists + for (int i = 0; i < mUsers.size(); i++) { + UserInfo user = mUsers.valueAt(i); + if (user.isGuest()) { + if (!enable) { + removeUser(user.id); + } + return; + } + } + // No guest was found + if (enable) { + createUser("Guest", UserInfo.FLAG_GUEST); + } + } + } + } + + @Override + public boolean isGuestEnabled() { + synchronized (mUsers) { + return mGuestEnabled; + } + } + + @Override + public void wipeUser(int userHandle) { + enforceSystemOrRoot("Only the system can wipe users"); + // TODO: + } + + /** + * Enforces that only the system UID or root's UID can call a method exposed + * via Binder. + * + * @param message used as message if SecurityException is thrown + * @throws SecurityException if the caller is not system or root + */ + private static final void enforceSystemOrRoot(String message) { + final int uid = Binder.getCallingUid(); + if (uid != Process.SYSTEM_UID && uid != 0) { + throw new SecurityException(message); + } + } + private ParcelFileDescriptor updateIconBitmapLocked(UserInfo info) { try { File dir = new File(mUsersDir, Integer.toString(info.id)); @@ -184,6 +264,7 @@ public class UserManager { } private void readUserListLocked() { + mGuestEnabled = false; if (!mUserListFile.exists()) { fallbackToSingleUserLocked(); return; @@ -212,6 +293,9 @@ public class UserManager { if (user != null) { mUsers.put(user.id, user); } + if (user.isGuest()) { + mGuestEnabled = true; + } } } updateUserIdsLocked(); @@ -389,7 +473,9 @@ public class UserManager { return null; } + @Override public UserInfo createUser(String name, int flags) { + enforceSystemOrRoot("Only the system can create users"); int userId = getNextAvailableId(); UserInfo userInfo = new UserInfo(userId, name, null, flags); File userPath = new File(mBaseUserPath, Integer.toString(userId)); @@ -402,6 +488,11 @@ public class UserManager { writeUserLocked(userInfo); updateUserIdsLocked(); } + 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; } @@ -410,27 +501,37 @@ public class UserManager { * after the user's processes have been terminated. * @param id the user's id */ - public boolean removeUser(int id) { + public boolean removeUser(int userHandle) { + enforceSystemOrRoot("Only the system can remove users"); synchronized (mUsers) { - return removeUserLocked(id); + return removeUserLocked(userHandle); } } - private boolean removeUserLocked(int id) { - // Remove from the list - UserInfo userInfo = mUsers.get(id); - if (userInfo != null) { - // Remove this user from the list - mUsers.remove(id); - // Remove user file - File userFile = new File(mUsersDir, id + ".xml"); - userFile.delete(); - // Update the user list - writeUserListLocked(); - updateUserIdsLocked(); - return true; + private boolean removeUserLocked(int userHandle) { + final UserInfo user = mUsers.get(userHandle); + if (userHandle == 0 || user == null) { + return false; } - return false; + + mPm.cleanUpUser(userHandle); + + // Remove this user from the list + mUsers.remove(userHandle); + // Remove user file + File userFile = new File(mUsersDir, userHandle + ".xml"); + userFile.delete(); + // Update the user list + writeUserListLocked(); + updateUserIdsLocked(); + + // Let other services shutdown any activity + Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED); + addedIntent.putExtra(Intent.EXTRA_USERID, userHandle); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + + removePackageFolders(userHandle); + return true; } public void installPackageForAllUsers(String packageName, int uid) { diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 416900f87140..f6f9aa0e7f27 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -176,13 +176,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { return info; } - @Override - public List<UserInfo> getUsers() { - final ArrayList<UserInfo> users = new ArrayList<UserInfo>(); - users.add(new UserInfo(USER_ID, "Primary", null, UserInfo.FLAG_PRIMARY)); - users.add(new UserInfo(USER_ID_GUEST, "Guest", 0)); - return users; - } }; } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 796372d1ebaa..5f93e6f17a49 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -138,7 +138,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); - Settings settings = new Settings(getContext().getFilesDir()); + Settings settings = new Settings(getContext(), getContext().getFilesDir()); assertEquals(true, settings.readLPw(null)); assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3)); assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1)); @@ -156,11 +156,11 @@ public class PackageManagerSettingsTests extends AndroidTestCase { public void testNewPackageRestrictionsFile() { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); - Settings settings = new Settings(getContext().getFilesDir()); + Settings settings = new Settings(getContext(), getContext().getFilesDir()); assertEquals(true, settings.readLPw(null)); // Create Settings again to make it read from the new files - settings = new Settings(getContext().getFilesDir()); + settings = new Settings(getContext(), getContext().getFilesDir()); assertEquals(true, settings.readLPw(null)); PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2); @@ -171,7 +171,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase { public void testEnableDisable() { // Write the package files and make sure they're parsed properly the first time writeOldFiles(); - Settings settings = new Settings(getContext().getFilesDir()); + Settings settings = new Settings(getContext(), getContext().getFilesDir()); assertEquals(true, settings.readLPw(null)); // Enable/Disable a package 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 d736ac157e29..bc3649c6b1f8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -16,7 +16,7 @@ package com.android.server.pm; -import com.android.server.pm.UserManager; +import com.android.server.pm.UserManagerService; import android.content.pm.UserInfo; import android.os.Debug; @@ -25,14 +25,14 @@ import android.test.AndroidTestCase; import java.util.List; -/** Test {@link UserManager} functionality. */ +/** Test {@link UserManagerService} functionality. */ public class UserManagerTest extends AndroidTestCase { - UserManager mUserManager = null; + UserManagerService mUserManager = null; @Override public void setUp() throws Exception { - mUserManager = new UserManager(Environment.getExternalStorageDirectory(), + mUserManager = new UserManagerService(Environment.getExternalStorageDirectory(), Environment.getExternalStorageDirectory()); } @@ -52,7 +52,7 @@ public class UserManagerTest extends AndroidTestCase { } public void testAddUser() throws Exception { - final UserManager details = mUserManager; + final UserManagerService details = mUserManager; UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST); assertTrue(userInfo != null); @@ -71,7 +71,7 @@ public class UserManagerTest extends AndroidTestCase { } public void testAdd2Users() throws Exception { - final UserManager details = mUserManager; + final UserManagerService details = mUserManager; UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST); UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN); @@ -85,7 +85,7 @@ public class UserManagerTest extends AndroidTestCase { } public void testRemoveUser() throws Exception { - final UserManager details = mUserManager; + final UserManagerService details = mUserManager; UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 0399b3be232c..ef144040562b 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -513,54 +513,6 @@ public class MockPackageManager extends PackageManager { * @hide */ @Override - public UserInfo createUser(String name, int flags) { - throw new UnsupportedOperationException(); - } - - /** - * @hide - */ - @Override - public List<UserInfo> getUsers() { - throw new UnsupportedOperationException(); - } - - /** - * @hide - */ - @Override - public UserInfo getUser(int userId) { - throw new UnsupportedOperationException(); - } - - /** - * @hide - */ - @Override - public boolean removeUser(int id) { - throw new UnsupportedOperationException(); - } - - /** - * @hide - */ - @Override - public void setUserName(int id, String name) { - throw new UnsupportedOperationException(); - } - - /** - * @hide - */ - @Override - public void updateUserFlags(int id, int flags) { - throw new UnsupportedOperationException(); - } - - /** - * @hide - */ - @Override public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { |