Add APIs for interacting across users.

- Expose the existing Context.sendBroadcast() as
  Context.sendBroadcastAsUser().
- Add new android:singleUser attribute for services.
- Add new INTERACT_ACROSS_USERS_FULL permission for full
  system-level access to cross-user interface (allows
  sendBroadcastAsUser() to send to any receiver).
- Add new INTERACT_ACROSS_USERS_FULL permission for
  more restricted cross-user interaction: this is required
  for android:singleUser, and allows you to use
  sendBroadcastAsUser() but only to send to your own
  receivers.

Change-Id: I0de88f6718e9505f4de72e3f45d29c0f503b76e9
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 22e454f..ba05ee7 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -896,7 +896,7 @@
     private void sendAccountsChangedBroadcast(int userId) {
         Log.i(TAG, "the accounts changed, sending broadcast of "
                 + ACCOUNTS_CHANGED_INTENT.getAction());
-        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT, userId);
+        mContext.sendBroadcastToUser(ACCOUNTS_CHANGED_INTENT, userId);
     }
 
     public void clearPassword(Account account) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 74fce62..3c8a290 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -966,9 +966,8 @@
         }
     }
 
-    /** @hide */
     @Override
-    public void sendBroadcast(Intent intent, int userId) {
+    public void sendBroadcastToUser(Intent intent, int userId) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
             intent.setAllowFds(false);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8597993..af8b213 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -988,12 +988,14 @@
     public abstract void sendBroadcast(Intent intent);
 
     /**
-     * Same as #sendBroadcast(Intent intent), but for a specific user. Used by the system only.
+     * Same as #sendBroadcast(Intent intent), but for a specific user.  This broadcast
+     * can only be sent to receivers that are part of the calling application.  It
+     * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+     * permission.
      * @param intent the intent to broadcast
      * @param userId user to send the intent to
-     * @hide
      */
-    public void sendBroadcast(Intent intent, int userId) {
+    public void sendBroadcastToUser(Intent intent, int userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 6b950e0..7738132 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -312,10 +312,9 @@
         mBase.sendBroadcast(intent);
     }
 
-    /** @hide */
     @Override
-    public void sendBroadcast(Intent intent, int userId) {
-        mBase.sendBroadcast(intent, userId);
+    public void sendBroadcastToUser(Intent intent, int userId) {
+        mBase.sendBroadcastToUser(intent, userId);
     }
 
     @Override
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f8898c1..3ce7c78 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2703,7 +2703,7 @@
             return null;
         }
 
-        final boolean setExported = sa.hasValue(
+        boolean setExported = sa.hasValue(
                 com.android.internal.R.styleable.AndroidManifestService_exported);
         if (setExported) {
             s.info.exported = sa.getBoolean(
@@ -2729,6 +2729,18 @@
                 false)) {
             s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
         }
+        if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestService_singleUser,
+                false)) {
+            s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
+            if (s.info.exported) {
+                Slog.w(TAG, "Service exported request ignored due to singleUser: "
+                        + s.className + " at " + mArchiveSourcePath + " "
+                        + parser.getPositionDescription());
+                s.info.exported = false;
+            }
+            setExported = true;
+        }
 
         sa.recycle();
 
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 7ee84ab..1aaceb4 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -49,6 +49,13 @@
     public static final int FLAG_ISOLATED_PROCESS = 0x0002;
 
     /**
+     * Bit in {@link #flags}: If set, a single instance of the service will
+     * run for all users on the device.  Set from the
+     * {@link android.R.attr#singleUser} attribute.
+     */
+    public static final int FLAG_SINGLE_USER = 0x0004;
+
+    /**
      * Options that have been set in the service declaration in the
      * manifest.
      * These include:
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9253f24..d636713 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -760,6 +760,25 @@
         android:label="@string/permlab_getTasks"
         android:description="@string/permdesc_getTasks" />
 
+    <!-- Allows an application to call APIs that allow it to do interactions
+         across the users on the device, using singleton services and
+         user-targeted broadcasts.  This permission is not available to
+         third party applications. -->
+    <permission android:name="android.permission.INTERACT_ACROSS_USERS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature|system|development"
+        android:label="@string/permlab_interactAcrossUsers"
+        android:description="@string/permdesc_interactAcrossUsers" />
+
+    <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+         that removes restrictions on where broadcasts can be sent and allows other
+         types of interactions. -->
+    <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_interactAcrossUsersFull"
+        android:description="@string/permdesc_interactAcrossUsersFull" />
+
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index f971d39..8bc1e79 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1275,6 +1275,16 @@
              that is isolated from the rest of the system.  The only communication
              with it is through the Service API (binding and starting). -->
         <attr name="isolatedProcess" format="boolean" />
+        <!-- If set to true, a single instance of this service will run for
+             all users.  That instance will run as user 0, the default/primary
+             user.  When the app running in processes for other users interacts
+             with this service (by binding to it, starting it, etc) they will
+             always interact with the instance running for user 0.  Enabling
+             single user mode forces "exported" of the service to be false, to
+             avoid introducing multi-user security bugs.  You must hold the
+             permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS} in order
+             to use this feature. -->
+        <attr name="singleUser" format="boolean" />
     </declare-styleable>
     
     <!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b9b8a1b..4881a94 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3660,7 +3660,7 @@
   <public type="style" name="Widget.DeviceDefault.Light.MediaRouteButton" id="0x010301d8" />
 
 <!-- ===============================================================
-     Resources added in version 17 of the platform (Jelly Bean MRx?)
+     Resources added in version 17 of the platform (Jelly Bean MR1)
      =============================================================== -->
   <eat-comment />
   <public type="attr" name="supportsRtl" />
@@ -3679,5 +3679,6 @@
   <public type="attr" name="layout_alignParentEnd" />
   <public type="attr" name="listPreferredItemPaddingStart" />
   <public type="attr" name="listPreferredItemPaddingEnd" />
-
+  <public type="attr" name="singleUser" />
+  
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b757fe8..b369744 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -543,6 +543,19 @@
        about currently and recently running tasks.  This may allow the app to
        discover information about which applications are used on the device.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permlab_interactAcrossUsers">interact across users</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_interactAcrossUsers">Allows the app to perform actions
+        across different users on the device.  Malicious apps may use this to violate
+        the protection between users.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permlab_interactAcrossUsersFull">full license to interact across users</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_interactAcrossUsersFull">Allows all possible interactions across
+        users.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50] -->
     <string name="permlab_getDetailedTasks">retrieve details of running apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->