Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ac72a29 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Improve multi-user broadcasts.

You can now use ALL and CURRENT when sending broadcasts, to specify
where the broadcast goes.

Sticky broadcasts are now correctly separated per user, and registered
receivers are filtered based on the requested target user.

New Context APIs for more kinds of sending broadcasts as users.

Updating a bunch of system code that sends broadcasts to explicitly
specify which user the broadcast goes to.

Made a single version of the code for interpreting the requested
target user ID that all entries to activity manager (start activity,
send broadcast, start service) use.

Change-Id: Ie29f02dd5242ef8c8fa56c54593a315cd2574e1c
parent e217ee4d
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -5323,15 +5323,19 @@ package android.content {
    method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
    method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
    method public abstract void removeStickyBroadcast(android.content.Intent);
    method public abstract void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public abstract void revokeUriPermission(android.net.Uri, int);
    method public abstract void sendBroadcast(android.content.Intent);
    method public abstract void sendBroadcast(android.content.Intent, java.lang.String);
    method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
    method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String);
    method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public abstract void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public abstract void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public abstract void sendStickyBroadcast(android.content.Intent);
    method public abstract void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public abstract void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public abstract void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public abstract void setTheme(int);
    method public abstract deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
    method public abstract deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
@@ -5460,15 +5464,19 @@ package android.content {
    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
    method public void removeStickyBroadcast(android.content.Intent);
    method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public void revokeUriPermission(android.net.Uri, int);
    method public void sendBroadcast(android.content.Intent);
    method public void sendBroadcast(android.content.Intent, java.lang.String);
    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendStickyBroadcast(android.content.Intent);
    method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void setTheme(int);
    method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
    method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
@@ -21264,15 +21272,19 @@ package android.test.mock {
    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
    method public void removeStickyBroadcast(android.content.Intent);
    method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public void revokeUriPermission(android.net.Uri, int);
    method public void sendBroadcast(android.content.Intent);
    method public void sendBroadcast(android.content.Intent, java.lang.String);
    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendStickyBroadcast(android.content.Intent);
    method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
    method public void setTheme(int);
    method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
    method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+2 −2
Original line number Diff line number Diff line
@@ -89,11 +89,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
     * Convenience for sending a sticky broadcast.  For internal use only.
     * If you don't care about permission, use null.
     */
    static public void broadcastStickyIntent(Intent intent, String permission) {
    static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
        try {
            getDefault().broadcastIntent(
                null, intent, null, null, Activity.RESULT_OK, null, null,
                null /*permission*/, false, true, Binder.getOrigCallingUser());
                null /*permission*/, false, true, userId);
        } catch (RemoteException ex) {
        }
    }
+76 −2
Original line number Diff line number Diff line
@@ -1071,9 +1071,23 @@ class ContextImpl extends Context {
        }
    }

    @Override
    public void sendBroadcastAsUser(Intent intent, UserHandle user,
            String receiverPermission) {
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.setAllowFds(false);
            ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, receiverPermission, false, false,
                user.getIdentifier());
        } catch (RemoteException e) {
        }
    }

    @Override
    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
            BroadcastReceiver resultReceiver, Handler scheduler,
            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
            int initialCode, String initialData, Bundle initialExtras) {
        IIntentReceiver rd = null;
        if (resultReceiver != null) {
@@ -1097,7 +1111,7 @@ class ContextImpl extends Context {
            intent.setAllowFds(false);
            ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, rd,
                initialCode, initialData, initialExtras, null,
                initialCode, initialData, initialExtras, receiverPermission,
                true, false, user.getIdentifier());
        } catch (RemoteException e) {
        }
@@ -1164,6 +1178,66 @@ class ContextImpl extends Context {
        }
    }

    @Override
    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.setAllowFds(false);
            ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, false, true, user.getIdentifier());
        } catch (RemoteException e) {
        }
    }

    @Override
    public void sendStickyOrderedBroadcastAsUser(Intent intent,
            UserHandle user, BroadcastReceiver resultReceiver,
            Handler scheduler, int initialCode, String initialData,
            Bundle initialExtras) {
        IIntentReceiver rd = null;
        if (resultReceiver != null) {
            if (mPackageInfo != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = mPackageInfo.getReceiverDispatcher(
                    resultReceiver, getOuterContext(), scheduler,
                    mMainThread.getInstrumentation(), false);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
            }
        }
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.setAllowFds(false);
            ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, rd,
                initialCode, initialData, initialExtras, null,
                true, true, user.getIdentifier());
        } catch (RemoteException e) {
        }
    }

    @Override
    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        if (resolvedType != null) {
            intent = new Intent(intent);
            intent.setDataAndType(intent.getData(), resolvedType);
        }
        try {
            intent.setAllowFds(false);
            ActivityManagerNative.getDefault().unbroadcastIntent(
                    mMainThread.getApplicationThread(), intent, user.getIdentifier());
        } catch (RemoteException e) {
        }
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
+89 −2
Original line number Diff line number Diff line
@@ -1126,6 +1126,24 @@ public abstract class Context {
     */
    public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);

    /**
     * Same as {@link #sendBroadcast(Intent, String)}, 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; all receivers matching this
     *               Intent will receive the broadcast.
     * @param user UserHandle to send the intent to.
     * @param receiverPermission (optional) String naming a permission that
     *               a receiver must hold in order to receive your broadcast.
     *               If null, no permission is required.
     *
     * @see #sendBroadcast(Intent, String)
     */
    public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
            String receiverPermission);

    /**
     * Same as
     * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)},
@@ -1139,6 +1157,9 @@ public abstract class Context {
     * @param intent The Intent to broadcast; all receivers matching this
     *               Intent will receive the broadcast.
     * @param user UserHandle to send the intent to.
     * @param receiverPermission String naming a permissions that
     *               a receiver must hold in order to receive your broadcast.
     *               If null, no permission is required.
     * @param resultReceiver Your own BroadcastReceiver to treat as the final
     *                       receiver of the broadcast.
     * @param scheduler A custom Handler with which to schedule the
@@ -1154,7 +1175,7 @@ public abstract class Context {
     * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
     */
    public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
            BroadcastReceiver resultReceiver, Handler scheduler,
            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
            int initialCode, String initialData, Bundle initialExtras);

    /**
@@ -1223,7 +1244,6 @@ public abstract class Context {
            Handler scheduler, int initialCode, String initialData,
            Bundle initialExtras);


    /**
     * Remove the data previously sent with {@link #sendStickyBroadcast},
     * so that it is as if the sticky broadcast had never happened.
@@ -1238,6 +1258,73 @@ public abstract class Context {
     */
    public abstract void removeStickyBroadcast(Intent intent);

    /**
     * Same as {@link #sendStickyBroadcast(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; all receivers matching this
     * Intent will receive the broadcast, and the Intent will be held to
     * be re-broadcast to future receivers.
     * @param user UserHandle to send the intent to.
     *
     * @see #sendBroadcast(Intent)
     */
    public abstract void sendStickyBroadcastAsUser(Intent intent, UserHandle user);

    /**
     * Same as
     * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
     * 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.
     *
     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
     *
     * @param intent The Intent to broadcast; all receivers matching this
     *               Intent will receive the broadcast.
     * @param user UserHandle to send the intent to.
     * @param resultReceiver Your own BroadcastReceiver to treat as the final
     *                       receiver of the broadcast.
     * @param scheduler A custom Handler with which to schedule the
     *                  resultReceiver callback; if null it will be
     *                  scheduled in the Context's main thread.
     * @param initialCode An initial value for the result code.  Often
     *                    Activity.RESULT_OK.
     * @param initialData An initial value for the result data.  Often
     *                    null.
     * @param initialExtras An initial value for the result extras.  Often
     *                      null.
     *
     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
     */
    public abstract void sendStickyOrderedBroadcastAsUser(Intent intent,
            UserHandle user, BroadcastReceiver resultReceiver,
            Handler scheduler, int initialCode, String initialData,
            Bundle initialExtras);

    /**
     * Same as
     * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
     * 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.
     *
     * <p>You must hold the {@link android.Manifest.permission#BROADCAST_STICKY}
     * permission in order to use this API.  If you do not hold that
     * permission, {@link SecurityException} will be thrown.
     *
     * @param intent The Intent that was previously broadcast.
     * @param user UserHandle to remove the sticky broadcast from.
     *
     * @see #sendStickyBroadcastAsUser
     */
    public abstract void removeStickyBroadcastAsUser(Intent intent, UserHandle user);

    /**
     * Register a BroadcastReceiver to be run in the main activity thread.  The
     * <var>receiver</var> will be called with any broadcast Intent that
+31 −2
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.content;

import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.LoadedApk;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -30,6 +33,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.view.CompatibilityInfoHolder;

@@ -353,11 +357,17 @@ public class ContextWrapper extends Context {
        mBase.sendBroadcastAsUser(intent, user);
    }

    @Override
    public void sendBroadcastAsUser(Intent intent, UserHandle user,
            String receiverPermission) {
        mBase.sendBroadcastAsUser(intent, user, receiverPermission);
    }

    @Override
    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
            BroadcastReceiver resultReceiver, Handler scheduler,
            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
            int initialCode, String initialData, Bundle initialExtras) {
        mBase.sendOrderedBroadcastAsUser(intent, user, resultReceiver,
        mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver,
                scheduler, initialCode, initialData, initialExtras);
    }

@@ -381,6 +391,25 @@ public class ContextWrapper extends Context {
        mBase.removeStickyBroadcast(intent);
    }

    @Override
    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
        mBase.sendStickyBroadcastAsUser(intent, user);
    }

    @Override
    public void sendStickyOrderedBroadcastAsUser(Intent intent,
            UserHandle user, BroadcastReceiver resultReceiver,
            Handler scheduler, int initialCode, String initialData,
            Bundle initialExtras) {
        mBase.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver,
                scheduler, initialCode, initialData, initialExtras);
    }

    @Override
    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
        mBase.removeStickyBroadcastAsUser(intent, user);
    }

    @Override
    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
Loading