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.
      */