Merge "Added --restricted option for create-user command"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 3f0a444..ebf5085 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -22,11 +22,13 @@
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import android.accounts.IAccountManager;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
@@ -92,6 +94,7 @@
IPackageManager mPm;
IPackageInstaller mInstaller;
IUserManager mUm;
+ IAccountManager mAm;
private WeakHashMap<String, Resources> mResourceCache
= new WeakHashMap<String, Resources>();
@@ -122,9 +125,10 @@
if (args.length < 1) {
return showUsage();
}
-
- mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
+ mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
+ mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+
if (mPm == null) {
System.err.println(PM_NOT_RUNNING_ERR);
return 1;
@@ -1381,6 +1385,8 @@
}
} else if ("--managed".equals(opt)) {
flags |= UserInfo.FLAG_MANAGED_PROFILE;
+ } else if ("--restricted".equals(opt)) {
+ flags |= UserInfo.FLAG_RESTRICTED;
} else {
System.err.println("Error: unknown option " + opt);
showUsage();
@@ -1394,12 +1400,18 @@
}
name = arg;
try {
- UserInfo info = null;
- if (userId < 0) {
+ UserInfo info;
+ if ((flags & UserInfo.FLAG_RESTRICTED) != 0) {
+ // In non-split user mode, userId can only be SYSTEM
+ int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
+ info = mUm.createRestrictedProfile(name, parentUserId);
+ mAm.addSharedAccountsFromParentUser(userId, parentUserId);
+ } else if (userId < 0) {
info = mUm.createUser(name, flags);
} else {
info = mUm.createProfileForUser(name, flags, userId);
}
+
if (info != null) {
System.out.println("Success: created user id " + info.id);
return 1;
@@ -2122,7 +2134,7 @@
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
System.err.println(" pm trim-caches DESIRED_FREE_SPACE [internal|UUID]");
- System.err.println(" pm create-user [--profileOf USER_ID] [--managed] USER_NAME");
+ System.err.println(" pm create-user [--profileOf USER_ID] [--managed] [--restricted] USER_NAME");
System.err.println(" pm remove-user USER_ID");
System.err.println(" pm get-max-users");
System.err.println("");
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index d751f96f..0a7568a 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,6 +16,7 @@
package android.accounts;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.Size;
import android.app.Activity;
@@ -423,6 +424,7 @@
* @return An array of {@link Account}, one for each account. Empty
* (never null) if no accounts have been added.
*/
+ @NonNull
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccounts() {
try {
@@ -448,6 +450,7 @@
* @return An array of {@link Account}, one for each account. Empty
* (never null) if no accounts have been added.
*/
+ @NonNull
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsAsUser(int userId) {
try {
@@ -466,6 +469,7 @@
* @param uid the uid of the calling app.
* @return the accounts that are available to this package and user.
*/
+ @NonNull
public Account[] getAccountsForPackage(String packageName, int uid) {
try {
return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
@@ -483,6 +487,7 @@
* @return An array of {@link Account}, one per matching account. Empty
* (never null) if no accounts of the specified type have been added.
*/
+ @NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName) {
try {
return mService.getAccountsByTypeForPackage(type, packageName,
@@ -515,12 +520,14 @@
* @return An array of {@link Account}, one per matching account. Empty
* (never null) if no accounts of the specified type have been added.
*/
+ @NonNull
@RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsByType(String type) {
return getAccountsByTypeAsUser(type, Process.myUserHandle());
}
/** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
+ @NonNull
public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
try {
return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
@@ -1537,23 +1544,22 @@
}.start();
}
+
/**
- * Adds a shared account from the primary user to a secondary user. Adding the shared account
+ * Adds shared accounts from a parent user to a secondary user. Adding the shared account
* doesn't take effect immediately. When the target user starts up, any pending shared accounts
* are attempted to be copied to the target user from the primary via calls to the
* authenticator.
- * @param account the account to share
- * @param user the target user
- * @return
+ * @param parentUser parent user
+ * @param user target user
* @hide
*/
- public boolean addSharedAccount(final Account account, UserHandle user) {
+ public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) {
try {
- boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier());
- return val;
+ mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
+ user.getIdentifier());
} catch (RemoteException re) {
- // won't ever happen
- throw new RuntimeException(re);
+ throw new IllegalStateException(re);
}
}
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 4378df4..0d95db1 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -74,9 +74,9 @@
String authTokenType);
/* Shared accounts */
- boolean addSharedAccountAsUser(in Account account, int userId);
Account[] getSharedAccountsAsUser(int userId);
boolean removeSharedAccountAsUser(in Account account, int userId);
+ void addSharedAccountsFromParentUser(int parentUserId, int userId);
/* Account renaming. */
void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index cfa6164..c4501ba 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -157,7 +157,7 @@
* incoming transaction, then its own UserHandle is returned.
*/
public static final UserHandle getCallingUserHandle() {
- return new UserHandle(UserHandle.getUserId(getCallingUid()));
+ return UserHandle.of(UserHandle.getUserId(getCallingUid()));
}
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index aeb5d45..7c09157 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -35,6 +35,7 @@
UserInfo createUser(in String name, int flags);
UserInfo createProfileForUser(in String name, int flags, int userHandle);
+ UserInfo createRestrictedProfile(String name, int parentUserId);
void setUserEnabled(int userHandle);
boolean removeUser(int userHandle);
void setUserName(int userHandle, String name);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7234e98..4ac361d0 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -797,8 +797,8 @@
* {@link #myUid()} in that a particular user will have multiple
* distinct apps running under it each with their own uid.
*/
- public static final UserHandle myUserHandle() {
- return new UserHandle(UserHandle.getUserId(myUid()));
+ public static UserHandle myUserHandle() {
+ return UserHandle.of(UserHandle.getUserId(myUid()));
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 213e083..796addc 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -17,7 +17,6 @@
package android.os;
import android.annotation.SystemApi;
-import android.util.SparseArray;
import java.io.PrintWriter;
@@ -83,8 +82,6 @@
final int mHandle;
- private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
-
/**
* Checks to see if the user id is the same for the two uids, i.e., they belong to the same
* user.
@@ -144,15 +141,8 @@
}
/** @hide */
- public static UserHandle getCallingUserHandle() {
- int userId = getUserId(Binder.getCallingUid());
- UserHandle userHandle = userHandles.get(userId);
- // Intentionally not synchronized to save time
- if (userHandle == null) {
- userHandle = new UserHandle(userId);
- userHandles.put(userId, userHandle);
- }
- return userHandle;
+ public static UserHandle of(int userId) {
+ return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 64e2505..f58933a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -15,6 +15,7 @@
*/
package android.os;
+import android.accounts.AccountManager;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityManager;
@@ -927,7 +928,8 @@
}
/**
- * Creates a restricted profile with the specified name.
+ * Creates a restricted profile with the specified name. This method also sets necessary
+ * restrictions and adds shared accounts.
*
* @param name profile's name
* @return UserInfo object for the created user, or null if the user could not be created.
@@ -935,13 +937,14 @@
*/
public UserInfo createRestrictedProfile(String name) {
try {
- if (isSplitSystemUser()) {
- return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
- UserHandle.getCallingUserId());
- } else {
- return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
- UserHandle.USER_SYSTEM);
+ UserHandle parentUserHandle = Process.myUserHandle();
+ UserInfo user = mService.createRestrictedProfile(name,
+ parentUserHandle.getIdentifier());
+ if (user != null) {
+ AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
+ UserHandle.of(user.id));
}
+ return user;
} catch (RemoteException e) {
Log.w(TAG, "Could not create a restricted profile", e);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index dbf1288..6b34612 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -29,6 +29,7 @@
import android.accounts.IAccountAuthenticatorResponse;
import android.accounts.IAccountManager;
import android.accounts.IAccountManagerResponse;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -2526,6 +2527,7 @@
* Returns the accounts visible to the client within the context of a specific user
* @hide
*/
+ @NonNull
public Account[] getAccounts(int userId, String opPackageName) {
int callingUid = Binder.getCallingUid();
List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
@@ -2551,6 +2553,7 @@
*
* @hide
*/
+ @NonNull
public AccountAndUser[] getRunningAccounts() {
final int[] runningUserIds;
try {
@@ -2563,6 +2566,7 @@
}
/** {@hide} */
+ @NonNull
public AccountAndUser[] getAllAccounts() {
final List<UserInfo> users = getUserManager().getUsers();
final int[] userIds = new int[users.size()];
@@ -2572,6 +2576,7 @@
return getAccounts(userIds);
}
+ @NonNull
private AccountAndUser[] getAccounts(int[] userIds) {
final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
for (int userId : userIds) {
@@ -2591,10 +2596,12 @@
}
@Override
+ @NonNull
public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
return getAccountsAsUser(type, userId, null, -1, opPackageName);
}
+ @NonNull
private Account[] getAccountsAsUser(
String type,
int userId,
@@ -2649,6 +2656,7 @@
}
}
+ @NonNull
private Account[] getAccountsInternal(
UserAccounts userAccounts,
int callingUid,
@@ -2672,7 +2680,15 @@
}
@Override
- public boolean addSharedAccountAsUser(Account account, int userId) {
+ public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
+ checkManageUsersPermission("addSharedAccountsFromParentUser");
+ Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
+ for (Account account : accounts) {
+ addSharedAccountAsUser(account, userId);
+ }
+ }
+
+ private boolean addSharedAccountAsUser(Account account, int userId) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -2764,11 +2780,13 @@
}
@Override
+ @NonNull
public Account[] getAccounts(String type, String opPackageName) {
return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
}
@Override
+ @NonNull
public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
int callingUid = Binder.getCallingUid();
if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
@@ -2780,6 +2798,7 @@
}
@Override
+ @NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName,
String opPackageName) {
int packageUid = -1;
@@ -3844,6 +3863,14 @@
return false;
}
+ private static void checkManageUsersPermission(String message) {
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("You need MANAGE_USERS permission to: " + message);
+ }
+ }
+
private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
int callerUid) {
if (callerUid == Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0c884f15..14a2cbc 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1684,7 +1684,7 @@
public boolean matchesCallFilter(Bundle extras) {
enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
return mZenModeHelper.matchesCallFilter(
- UserHandle.getCallingUserHandle(),
+ Binder.getCallingUserHandle(),
extras,
mRankingHelper.findExtractor(ValidateNotificationPeople.class),
MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1924bab..0577d59 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.accounts.Account;
import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
@@ -63,6 +64,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.accounts.AccountManagerService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1386,6 +1388,25 @@
}
/**
+ * @hide
+ */
+ public UserInfo createRestrictedProfile(String name, int parentUserId) {
+ checkManageUsersPermission("setupRestrictedProfile");
+ final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
+ if (user == null) {
+ return null;
+ }
+ setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
+ // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
+ // the putIntForUser() will fail.
+ android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ android.provider.Settings.Secure.LOCATION_MODE,
+ android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
+ setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+ return user;
+ }
+
+ /**
* Find the current guest user. If the Guest user is partial,
* then do not include it in the results as it is about to die.
*/