Skip to content

Commit b4163a6

Browse files
author
Dianne Hackborn
committed
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
1 parent b1758cf commit b4163a6

File tree

21 files changed

+275
-49
lines changed

21 files changed

+275
-49
lines changed

api/current.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ package android {
6262
field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
6363
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
6464
field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
65+
field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
6566
field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
6667
field public static final java.lang.String INTERNET = "android.permission.INTERNET";
6768
field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
@@ -893,6 +894,7 @@ package android {
893894
field public static final int shownWeekCount = 16843585; // 0x1010341
894895
field public static final int shrinkColumns = 16843082; // 0x101014a
895896
field public static final deprecated int singleLine = 16843101; // 0x101015d
897+
field public static final int singleUser = 16843711; // 0x10103bf
896898
field public static final int smallIcon = 16843422; // 0x101029e
897899
field public static final int smallScreens = 16843396; // 0x1010284
898900
field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -5317,6 +5319,7 @@ package android.content {
53175319
method public abstract void revokeUriPermission(android.net.Uri, int);
53185320
method public abstract void sendBroadcast(android.content.Intent);
53195321
method public abstract void sendBroadcast(android.content.Intent, java.lang.String);
5322+
method public void sendBroadcastToUser(android.content.Intent, int);
53205323
method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String);
53215324
method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
53225325
method public abstract void sendStickyBroadcast(android.content.Intent);
@@ -6700,6 +6703,7 @@ package android.content.pm {
67006703
method public void dump(android.util.Printer, java.lang.String);
67016704
field public static final android.os.Parcelable.Creator CREATOR;
67026705
field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
6706+
field public static final int FLAG_SINGLE_USER = 4; // 0x4
67036707
field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
67046708
field public int flags;
67056709
field public java.lang.String permission;

core/java/android/accounts/AccountManagerService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ private void setPasswordInternal(UserAccounts accounts, Account account, String
896896
private void sendAccountsChangedBroadcast(int userId) {
897897
Log.i(TAG, "the accounts changed, sending broadcast of "
898898
+ ACCOUNTS_CHANGED_INTENT.getAction());
899-
mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT, userId);
899+
mContext.sendBroadcastToUser(ACCOUNTS_CHANGED_INTENT, userId);
900900
}
901901

902902
public void clearPassword(Account account) {

core/java/android/app/ContextImpl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -966,9 +966,8 @@ public void sendBroadcast(Intent intent) {
966966
}
967967
}
968968

969-
/** @hide */
970969
@Override
971-
public void sendBroadcast(Intent intent, int userId) {
970+
public void sendBroadcastToUser(Intent intent, int userId) {
972971
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
973972
try {
974973
intent.setAllowFds(false);

core/java/android/content/Context.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -988,12 +988,14 @@ public abstract void startIntentSender(IntentSender intent,
988988
public abstract void sendBroadcast(Intent intent);
989989

990990
/**
991-
* Same as #sendBroadcast(Intent intent), but for a specific user. Used by the system only.
991+
* Same as #sendBroadcast(Intent intent), but for a specific user. This broadcast
992+
* can only be sent to receivers that are part of the calling application. It
993+
* requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
994+
* permission.
992995
* @param intent the intent to broadcast
993996
* @param userId user to send the intent to
994-
* @hide
995997
*/
996-
public void sendBroadcast(Intent intent, int userId) {
998+
public void sendBroadcastToUser(Intent intent, int userId) {
997999
throw new RuntimeException("Not implemented. Must override in a subclass.");
9981000
}
9991001

core/java/android/content/ContextWrapper.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,9 @@ public void sendBroadcast(Intent intent) {
312312
mBase.sendBroadcast(intent);
313313
}
314314

315-
/** @hide */
316315
@Override
317-
public void sendBroadcast(Intent intent, int userId) {
318-
mBase.sendBroadcast(intent, userId);
316+
public void sendBroadcastToUser(Intent intent, int userId) {
317+
mBase.sendBroadcastToUser(intent, userId);
319318
}
320319

321320
@Override

core/java/android/content/pm/PackageParser.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2703,7 +2703,7 @@ private Service parseService(Package owner, Resources res,
27032703
return null;
27042704
}
27052705

2706-
final boolean setExported = sa.hasValue(
2706+
boolean setExported = sa.hasValue(
27072707
com.android.internal.R.styleable.AndroidManifestService_exported);
27082708
if (setExported) {
27092709
s.info.exported = sa.getBoolean(
@@ -2729,6 +2729,18 @@ private Service parseService(Package owner, Resources res,
27292729
false)) {
27302730
s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
27312731
}
2732+
if (sa.getBoolean(
2733+
com.android.internal.R.styleable.AndroidManifestService_singleUser,
2734+
false)) {
2735+
s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
2736+
if (s.info.exported) {
2737+
Slog.w(TAG, "Service exported request ignored due to singleUser: "
2738+
+ s.className + " at " + mArchiveSourcePath + " "
2739+
+ parser.getPositionDescription());
2740+
s.info.exported = false;
2741+
}
2742+
setExported = true;
2743+
}
27322744

27332745
sa.recycle();
27342746

core/java/android/content/pm/ServiceInfo.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ public class ServiceInfo extends ComponentInfo
4848
*/
4949
public static final int FLAG_ISOLATED_PROCESS = 0x0002;
5050

51+
/**
52+
* Bit in {@link #flags}: If set, a single instance of the service will
53+
* run for all users on the device. Set from the
54+
* {@link android.R.attr#singleUser} attribute.
55+
*/
56+
public static final int FLAG_SINGLE_USER = 0x0004;
57+
5158
/**
5259
* Options that have been set in the service declaration in the
5360
* manifest.

core/res/AndroidManifest.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,25 @@
760760
android:label="@string/permlab_getTasks"
761761
android:description="@string/permdesc_getTasks" />
762762

763+
<!-- Allows an application to call APIs that allow it to do interactions
764+
across the users on the device, using singleton services and
765+
user-targeted broadcasts. This permission is not available to
766+
third party applications. -->
767+
<permission android:name="android.permission.INTERACT_ACROSS_USERS"
768+
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
769+
android:protectionLevel="signature|system|development"
770+
android:label="@string/permlab_interactAcrossUsers"
771+
android:description="@string/permdesc_interactAcrossUsers" />
772+
773+
<!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
774+
that removes restrictions on where broadcasts can be sent and allows other
775+
types of interactions. -->
776+
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
777+
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
778+
android:protectionLevel="signature"
779+
android:label="@string/permlab_interactAcrossUsersFull"
780+
android:description="@string/permdesc_interactAcrossUsersFull" />
781+
763782
<!-- Allows an application to get full detailed information about
764783
recently running tasks, with full fidelity to the real state.
765784
@hide -->

core/res/res/values/attrs_manifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,16 @@
12751275
that is isolated from the rest of the system. The only communication
12761276
with it is through the Service API (binding and starting). -->
12771277
<attr name="isolatedProcess" format="boolean" />
1278+
<!-- If set to true, a single instance of this service will run for
1279+
all users. That instance will run as user 0, the default/primary
1280+
user. When the app running in processes for other users interacts
1281+
with this service (by binding to it, starting it, etc) they will
1282+
always interact with the instance running for user 0. Enabling
1283+
single user mode forces "exported" of the service to be false, to
1284+
avoid introducing multi-user security bugs. You must hold the
1285+
permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS} in order
1286+
to use this feature. -->
1287+
<attr name="singleUser" format="boolean" />
12781288
</declare-styleable>
12791289

12801290
<!-- The <code>receiver</code> tag declares an

core/res/res/values/public.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3660,7 +3660,7 @@
36603660
<public type="style" name="Widget.DeviceDefault.Light.MediaRouteButton" id="0x010301d8" />
36613661

36623662
<!-- ===============================================================
3663-
Resources added in version 17 of the platform (Jelly Bean MRx?)
3663+
Resources added in version 17 of the platform (Jelly Bean MR1)
36643664
=============================================================== -->
36653665
<eat-comment />
36663666
<public type="attr" name="supportsRtl" />
@@ -3679,5 +3679,6 @@
36793679
<public type="attr" name="layout_alignParentEnd" />
36803680
<public type="attr" name="listPreferredItemPaddingStart" />
36813681
<public type="attr" name="listPreferredItemPaddingEnd" />
3682-
3682+
<public type="attr" name="singleUser" />
3683+
36833684
</resources>

0 commit comments

Comments
 (0)