diff options
22 files changed, 205 insertions, 71 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 14ba537960b6..eed9254646f5 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -300,7 +300,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM = b != null ? IIntentReceiver.Stub.asInterface(b) : null; IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data); String perm = data.readString(); - Intent intent = registerReceiver(app, packageName, rec, filter, perm); + int userId = data.readInt(); + Intent intent = registerReceiver(app, packageName, rec, filter, perm, userId); reply.writeNoException(); if (intent != null) { reply.writeInt(1); @@ -1999,7 +2000,7 @@ class ActivityManagerProxy implements IActivityManager } public Intent registerReceiver(IApplicationThread caller, String packageName, IIntentReceiver receiver, - IntentFilter filter, String perm) throws RemoteException + IntentFilter filter, String perm, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -2009,6 +2010,7 @@ class ActivityManagerProxy implements IActivityManager data.writeStrongBinder(receiver != null ? receiver.asBinder() : null); filter.writeToParcel(data, 0); data.writeString(perm); + data.writeInt(userId); mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0); reply.readException(); Intent intent = null; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1b788c2a1759..97dcec0498e1 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -320,8 +320,9 @@ public final class ActivityThread { static final class ReceiverData extends BroadcastReceiver.PendingResult { public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras, - boolean ordered, boolean sticky, IBinder token) { - super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, token); + boolean ordered, boolean sticky, IBinder token, int sendingUser) { + super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, + token, sendingUser); this.intent = intent; } @@ -613,9 +614,9 @@ public final class ActivityThread { public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, - boolean sync) { + boolean sync, int sendingUser) { ReceiverData r = new ReceiverData(intent, resultCode, data, extras, - sync, false, mAppThread.asBinder()); + sync, false, mAppThread.asBinder(), sendingUser); r.info = info; r.compatInfo = compatInfo; queueOrSendMessage(H.RECEIVER, r); @@ -774,8 +775,9 @@ public final class ActivityThread { // applies transaction ordering per object for such calls. public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, - boolean sticky) throws RemoteException { - receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky); + boolean sticky, int sendingUser) throws RemoteException { + receiver.performReceive(intent, resultCode, dataStr, extras, ordered, + sticky, sendingUser); } public void scheduleLowMemory() { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 8e6278ddaa03..63aa5f9b5f34 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -193,8 +193,9 @@ public abstract class ApplicationThreadNative extends Binder String resultData = data.readString(); Bundle resultExtras = data.readBundle(); boolean sync = data.readInt() != 0; + int sendingUser = data.readInt(); scheduleReceiver(intent, info, compatInfo, resultCode, resultData, - resultExtras, sync); + resultExtras, sync, sendingUser); return true; } @@ -378,8 +379,9 @@ public abstract class ApplicationThreadNative extends Binder Bundle extras = data.readBundle(); boolean ordered = data.readInt() != 0; boolean sticky = data.readInt() != 0; + int sendingUser = data.readInt(); scheduleRegisteredReceiver(receiver, intent, - resultCode, dataStr, extras, ordered, sticky); + resultCode, dataStr, extras, ordered, sticky, sendingUser); return true; } @@ -755,7 +757,7 @@ class ApplicationThreadProxy implements IApplicationThread { public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String resultData, - Bundle map, boolean sync) throws RemoteException { + Bundle map, boolean sync, int sendingUser) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); intent.writeToParcel(data, 0); @@ -765,6 +767,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeString(resultData); data.writeBundle(map); data.writeInt(sync ? 1 : 0); + data.writeInt(sendingUser); mRemote.transact(SCHEDULE_RECEIVER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); @@ -991,8 +994,8 @@ class ApplicationThreadProxy implements IApplicationThread { } public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, - int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky) - throws RemoteException { + int resultCode, String dataStr, Bundle extras, boolean ordered, + boolean sticky, int sendingUser) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(receiver.asBinder()); @@ -1002,6 +1005,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeBundle(extras); data.writeInt(ordered ? 1 : 0); data.writeInt(sticky ? 1 : 0); + data.writeInt(sendingUser); mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 232ca0790805..65ea6a0a9ad6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -138,6 +138,17 @@ class ReceiverRestrictedContext extends ContextWrapper { } @Override + public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, + IntentFilter filter, String broadcastPermission, Handler scheduler) { + throw new ReceiverCallNotAllowedException( + "IntentReceiver components are not allowed to register to receive intents"); + //ex.fillInStackTrace(); + //Log.e("IntentReceiver", ex.getMessage(), ex); + //return mContext.registerReceiver(receiver, filter, broadcastPermission, + // scheduler); + } + + @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { throw new ReceiverCallNotAllowedException( "IntentReceiver components are not allowed to bind to services"); @@ -1252,11 +1263,18 @@ class ContextImpl extends Context { @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { - return registerReceiverInternal(receiver, filter, broadcastPermission, - scheduler, getOuterContext()); + return registerReceiverInternal(receiver, UserHandle.myUserId(), + filter, broadcastPermission, scheduler, getOuterContext()); + } + + @Override + public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, + IntentFilter filter, String broadcastPermission, Handler scheduler) { + return registerReceiverInternal(receiver, user.getIdentifier(), + filter, broadcastPermission, scheduler, getOuterContext()); } - private Intent registerReceiverInternal(BroadcastReceiver receiver, + private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; @@ -1279,7 +1297,7 @@ class ContextImpl extends Context { try { return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, - rd, filter, broadcastPermission); + rd, filter, broadcastPermission, userId); } catch (RemoteException e) { return null; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index f7c701332703..7a633ed87a22 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -80,7 +80,7 @@ public interface IActivityManager extends IInterface { public boolean willActivityBeVisible(IBinder token) throws RemoteException; public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, - String requiredPermission) throws RemoteException; + String requiredPermission, int userId) throws RemoteException; public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException; public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index f60cfd6b091e..03a26d4274c4 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -65,7 +65,8 @@ public interface IApplicationThread extends IInterface { void scheduleDestroyActivity(IBinder token, boolean finished, int configChanges) throws RemoteException; void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, - int resultCode, String data, Bundle extras, boolean sync) throws RemoteException; + int resultCode, String data, Bundle extras, boolean sync, + int sendingUser) throws RemoteException; static final int BACKUP_MODE_INCREMENTAL = 0; static final int BACKUP_MODE_FULL = 1; static final int BACKUP_MODE_RESTORE = 2; @@ -105,8 +106,8 @@ public interface IApplicationThread extends IInterface { void dumpProvider(FileDescriptor fd, IBinder servicetoken, String[] args) throws RemoteException; void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, - int resultCode, String data, Bundle extras, boolean ordered, boolean sticky) - throws RemoteException; + int resultCode, String data, Bundle extras, boolean ordered, + boolean sticky, int sendingUser) throws RemoteException; void scheduleLowMemory() throws RemoteException; void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException; void profilerControl(boolean start, String path, ParcelFileDescriptor fd, int profileType) diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 6197b1a6c2c5..0a9ed587ffd0 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -670,8 +670,8 @@ public final class LoadedApk { mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); mStrongRef = strong ? rd : null; } - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, boolean sticky) { + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky, int sendingUser) { LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); @@ -680,7 +680,7 @@ public final class LoadedApk { } if (rd != null) { rd.performReceive(intent, resultCode, data, extras, - ordered, sticky); + ordered, sticky, sendingUser); } else { // The activity manager dispatched a broadcast to a registered // receiver in this process, but before it could be delivered the @@ -716,10 +716,10 @@ public final class LoadedApk { private final boolean mOrdered; public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, - boolean ordered, boolean sticky) { + boolean ordered, boolean sticky, int sendingUser) { super(resultCode, resultData, resultExtras, mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, - ordered, sticky, mIIntentReceiver.asBinder()); + ordered, sticky, mIIntentReceiver.asBinder(), sendingUser); mCurIntent = intent; mOrdered = ordered; } @@ -830,14 +830,15 @@ public final class LoadedApk { return mUnregisterLocation; } - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, boolean sticky) { + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky, int sendingUser) { if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + " to " + mReceiver); } - Args args = new Args(intent, resultCode, data, extras, ordered, sticky); + Args args = new Args(intent, resultCode, data, extras, ordered, + sticky, sendingUser); if (!mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index bcd42ea00b0a..a3c1838c3e9f 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -147,8 +147,8 @@ public final class PendingIntent implements Parcelable { mWho = who; mHandler = handler; } - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean serialized, boolean sticky) { + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean serialized, boolean sticky, int sendingUser) { mIntent = intent; mResultCode = resultCode; mResultData = data; diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 446f1af41177..1500b009a306 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -237,16 +237,17 @@ public abstract class BroadcastReceiver { final boolean mOrderedHint; final boolean mInitialStickyHint; final IBinder mToken; + final int mSendingUser; int mResultCode; String mResultData; Bundle mResultExtras; boolean mAbortBroadcast; boolean mFinished; - + /** @hide */ public PendingResult(int resultCode, String resultData, Bundle resultExtras, - int type, boolean ordered, boolean sticky, IBinder token) { + int type, boolean ordered, boolean sticky, IBinder token, int userId) { mResultCode = resultCode; mResultData = resultData; mResultExtras = resultExtras; @@ -254,6 +255,7 @@ public abstract class BroadcastReceiver { mOrderedHint = ordered; mInitialStickyHint = sticky; mToken = token; + mSendingUser = userId; } /** @@ -425,7 +427,12 @@ public abstract class BroadcastReceiver { } } } - + + /** @hide */ + public int getSendingUserId() { + return mSendingUser; + } + void checkSynchronousHint() { // Note that we don't assert when receiving the initial sticky value, // since that may have come from an ordered broadcast. We'll catch @@ -733,6 +740,11 @@ public abstract class BroadcastReceiver { return mPendingResult; } + /** @hide */ + public int getSendingUserId() { + return mPendingResult.mSendingUser; + } + /** * Control inclusion of debugging help for mismatched * calls to {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 8a4cb4450629..7438ba8314da 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1410,9 +1410,35 @@ public abstract class Context { * @see #unregisterReceiver */ public abstract Intent registerReceiver(BroadcastReceiver receiver, - IntentFilter filter, - String broadcastPermission, - Handler scheduler); + IntentFilter filter, String broadcastPermission, Handler scheduler); + + /** + * @hide + * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) + * but for a specific user. This receiver will receiver broadcasts that + * are sent to the requested user. It + * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} + * permission. + * + * @param receiver The BroadcastReceiver to handle the broadcast. + * @param user UserHandle to send the intent to. + * @param filter Selects the Intent broadcasts to be received. + * @param broadcastPermission String naming a permissions that a + * broadcaster must hold in order to send an Intent to you. If null, + * no permission is required. + * @param scheduler Handler identifying the thread that will receive + * the Intent. If null, the main thread of the process will be used. + * + * @return The first sticky intent found that matches <var>filter</var>, + * or null if there are none. + * + * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler + * @see #sendBroadcast + * @see #unregisterReceiver + */ + public abstract Intent registerReceiverAsUser(BroadcastReceiver receiver, + UserHandle user, IntentFilter filter, String broadcastPermission, + Handler scheduler); /** * Unregister a previously registered BroadcastReceiver. <em>All</em> diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index e8c63d645ad7..6101f4eeb1d9 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -425,6 +425,15 @@ public class ContextWrapper extends Context { scheduler); } + /** @hide */ + @Override + public Intent registerReceiverAsUser( + BroadcastReceiver receiver, UserHandle user, IntentFilter filter, + String broadcastPermission, Handler scheduler) { + return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission, + scheduler); + } + @Override public void unregisterReceiver(BroadcastReceiver receiver) { mBase.unregisterReceiver(receiver); diff --git a/core/java/android/content/IIntentReceiver.aidl b/core/java/android/content/IIntentReceiver.aidl index 6f2f7c4053b4..3d9272388e03 100755 --- a/core/java/android/content/IIntentReceiver.aidl +++ b/core/java/android/content/IIntentReceiver.aidl @@ -27,7 +27,7 @@ import android.os.Bundle; * {@hide} */ oneway interface IIntentReceiver { - void performReceive(in Intent intent, int resultCode, - String data, in Bundle extras, boolean ordered, boolean sticky); + void performReceive(in Intent intent, int resultCode, String data, + in Bundle extras, boolean ordered, boolean sticky, int sendingUser); } diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index 079241aeadc9..6c3cf997d44a 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -114,8 +114,8 @@ public class IntentSender implements Parcelable { mWho = who; mHandler = handler; } - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean serialized, boolean sticky) { + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean serialized, boolean sticky, int sendingUser) { mIntent = intent; mResultCode = resultCode; mResultData = data; diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index b869abd6a989..63761cc0cca4 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -27,7 +27,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; -import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -151,7 +150,7 @@ class AppWidgetService extends IAppWidgetService.Stub // Register for the boot completed broadcast, so we can send the // ENABLE broacasts. If we try to send them now, they time out, // because the system isn't ready to handle them yet. - mContext.registerReceiver(mBroadcastReceiver, + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); // Register for configuration changes so we can update the names @@ -166,12 +165,14 @@ class AppWidgetService extends IAppWidgetService.Stub filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); - mContext.registerReceiver(mBroadcastReceiver, filter); + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + filter, null, null); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiver(mBroadcastReceiver, sdFilter); + mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, + sdFilter, null, null); IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_REMOVED); @@ -181,6 +182,15 @@ class AppWidgetService extends IAppWidgetService.Stub onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); } }, userFilter); + + IntentFilter userStopFilter = new IntentFilter(); + userStopFilter.addAction(Intent.ACTION_USER_STOPPED); + mContext.registerReceiverAsUser(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserStopped(getSendingUserId()); + } + }, UserHandle.ALL, userFilter, null, null); } @Override @@ -254,6 +264,9 @@ class AppWidgetService extends IAppWidgetService.Stub } } + public void onUserStopped(int userId) { + } + private AppWidgetServiceImpl getImplForUser(int userId) { AppWidgetServiceImpl service = mAppWidgetServices.get(userId); if (service == null) { @@ -370,9 +383,17 @@ class AppWidgetService extends IAppWidgetService.Stub service.onConfigurationChanged(); } } else { - for (int i = 0; i < mAppWidgetServices.size(); i++) { - AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); - service.onBroadcastReceived(intent); + int sendingUser = getSendingUserId(); + if (sendingUser == UserHandle.USER_ALL) { + for (int i = 0; i < mAppWidgetServices.size(); i++) { + AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); + service.onBroadcastReceived(intent); + } + } else { + AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser); + if (service != null) { + service.onBroadcastReceived(intent); + } } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 590e9d9addc5..3c379d173cd1 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -495,7 +495,8 @@ public final class ActivityManagerService extends ActivityManagerNative @Override protected BroadcastFilter newResult(BroadcastFilter filter, int match, int userId) { - if (userId == UserHandle.USER_ALL || userId == filter.owningUserId) { + if (userId == UserHandle.USER_ALL || filter.owningUserId == UserHandle.USER_ALL + || userId == filter.owningUserId) { return super.newResult(filter, match, userId); } return null; @@ -7549,7 +7550,7 @@ public final class ActivityManagerService extends ActivityManagerNative finisher = new IIntentReceiver.Stub() { public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, - boolean sticky) { + boolean sticky, int sendingUser) { // The raw IIntentReceiver interface is called // with the AM lock held, so redispatch to // execute our code without the lock. @@ -11038,9 +11039,10 @@ public final class ActivityManagerService extends ActivityManagerNative } public Intent registerReceiver(IApplicationThread caller, String callerPackage, - IIntentReceiver receiver, IntentFilter filter, String permission) { + IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { enforceNotIsolatedCaller("registerReceiver"); int callingUid; + int callingPid; synchronized(this) { ProcessRecord callerApp = null; if (caller != null) { @@ -11057,11 +11059,16 @@ public final class ActivityManagerService extends ActivityManagerNative + " is not running in process " + callerApp); } callingUid = callerApp.info.uid; + callingPid = callerApp.pid; } else { callerPackage = null; callingUid = Binder.getCallingUid(); + callingPid = Binder.getCallingPid(); } + userId = this.handleIncomingUserLocked(callingPid, callingUid, userId, + true, true, "registerReceiver", callerPackage); + List allSticky = null; // Look for any matching sticky broadcasts... @@ -11095,9 +11102,8 @@ public final class ActivityManagerService extends ActivityManagerNative ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { - rl = new ReceiverList(this, callerApp, - Binder.getCallingPid(), - Binder.getCallingUid(), receiver); + rl = new ReceiverList(this, callerApp, callingPid, callingUid, + userId, receiver); if (rl.app != null) { rl.app.receivers.add(rl); } else { @@ -11109,9 +11115,21 @@ public final class ActivityManagerService extends ActivityManagerNative rl.linkedToDeath = true; } mRegisteredReceivers.put(receiver.asBinder(), rl); + } else if (rl.uid != callingUid) { + throw new IllegalArgumentException( + "Receiver requested to register for uid " + callingUid + + " was previously registered for uid " + rl.uid); + } else if (rl.pid != callingPid) { + throw new IllegalArgumentException( + "Receiver requested to register for pid " + callingPid + + " was previously registered for pid " + rl.pid); + } else if (rl.userId != userId) { + throw new IllegalArgumentException( + "Receiver requested to register for user " + userId + + " was previously registered for user " + rl.userId); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, - permission, callingUid); + permission, callingUid, userId); rl.add(bf); if (!bf.debugCheck()) { Slog.w(TAG, "==> For Dynamic broadast"); @@ -13834,7 +13852,7 @@ public final class ActivityManagerService extends ActivityManagerNative final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, - Bundle extras, boolean ordered, boolean sticky) { + Bundle extras, boolean ordered, boolean sticky, int sendingUser) { finishUserStop(uss); } }; diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java index b0ccd8f9a07d..07440b544a1e 100644 --- a/services/java/com/android/server/am/BroadcastFilter.java +++ b/services/java/com/android/server/am/BroadcastFilter.java @@ -17,7 +17,6 @@ package com.android.server.am; import android.content.IntentFilter; -import android.os.UserHandle; import android.util.PrintWriterPrinter; import android.util.Printer; @@ -32,13 +31,13 @@ class BroadcastFilter extends IntentFilter { final int owningUserId; BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList, - String _packageName, String _requiredPermission, int _owningUid) { + String _packageName, String _requiredPermission, int _owningUid, int _userId) { super(_filter); receiverList = _receiverList; packageName = _packageName; requiredPermission = _requiredPermission; owningUid = _owningUid; - owningUserId = UserHandle.getUserId(owningUid); + owningUserId = _userId; } public void dump(PrintWriter pw, String prefix) { diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index 34dec3a8fc72..1b6ff7a48ea1 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -222,7 +222,7 @@ public class BroadcastQueue { mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo), - r.resultCode, r.resultData, r.resultExtras, r.ordered); + r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId); if (DEBUG_BROADCAST) Slog.v(TAG, "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; @@ -357,15 +357,16 @@ public class BroadcastQueue { private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, - boolean ordered, boolean sticky) throws RemoteException { + boolean ordered, boolean sticky, int sendingUser) throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null && app.thread != null) { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, - data, extras, ordered, sticky); + data, extras, ordered, sticky, sendingUser); } else { - receiver.performReceive(intent, resultCode, data, extras, ordered, sticky); + receiver.performReceive(intent, resultCode, data, extras, ordered, + sticky, sendingUser); } } @@ -428,8 +429,8 @@ public class BroadcastQueue { + " (seq=" + seq + "): " + r); } performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, - new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, r.ordered, r.initialSticky); + new Intent(r.intent), r.resultCode, r.resultData, + r.resultExtras, r.ordered, r.initialSticky, r.userId); if (ordered) { r.state = BroadcastRecord.CALL_DONE_RECEIVE; } @@ -579,7 +580,7 @@ public class BroadcastQueue { } performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, - r.resultData, r.resultExtras, false, false); + r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isnt kept in the mBroadcastHistory. r.resultTo = null; diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java index 37e90178208f..0f7240914828 100644 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ b/services/java/com/android/server/am/PendingIntentRecord.java @@ -285,7 +285,7 @@ class PendingIntentRecord extends IIntentSender.Stub { if (sendFinish) { try { finishedReceiver.performReceive(new Intent(finalIntent), 0, - null, null, false, false); + null, null, false, false, key.userId); } catch (RemoteException e) { } } diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java index 32c24c6cbf6f..9b6701e4debc 100644 --- a/services/java/com/android/server/am/ReceiverList.java +++ b/services/java/com/android/server/am/ReceiverList.java @@ -39,18 +39,20 @@ class ReceiverList extends ArrayList<BroadcastFilter> public final ProcessRecord app; public final int pid; public final int uid; + public final int userId; BroadcastRecord curBroadcast = null; boolean linkedToDeath = false; String stringName; ReceiverList(ActivityManagerService _owner, ProcessRecord _app, - int _pid, int _uid, IIntentReceiver _receiver) { + int _pid, int _uid, int _userId, IIntentReceiver _receiver) { owner = _owner; receiver = _receiver; app = _app; pid = _pid; uid = _uid; + userId = _userId; } // Want object identity, not the array identity we are inheriting. @@ -67,8 +69,9 @@ class ReceiverList extends ArrayList<BroadcastFilter> } void dumpLocal(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("app="); pw.print(app); - pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.println(uid); + pw.print(prefix); pw.print("app="); pw.print(app.toShortString()); + pw.print(" pid="); pw.print(pid); pw.print(" uid="); pw.print(uid); + pw.print(" user="); pw.println(userId); if (curBroadcast != null || linkedToDeath) { pw.print(prefix); pw.print("curBroadcast="); pw.print(curBroadcast); pw.print(" linkedToDeath="); pw.println(linkedToDeath); @@ -103,6 +106,8 @@ class ReceiverList extends ArrayList<BroadcastFilter> sb.append((app != null ? app.processName : "(unknown name)")); sb.append('/'); sb.append(uid); + sb.append("/u"); + sb.append(userId); sb.append((receiver.asBinder() instanceof Binder) ? " local:" : " remote:"); sb.append(Integer.toHexString(System.identityHashCode(receiver.asBinder()))); sb.append('}'); diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 183f8ec9b4a4..24be75fad076 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -9635,7 +9635,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (pkgList.size() > 0) { sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() { public void performReceive(Intent intent, int resultCode, String data, - Bundle extras, boolean ordered, boolean sticky) throws RemoteException { + Bundle extras, boolean ordered, boolean sticky, + int sendingUser) throws RemoteException { Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, 1, keys); mHandler.sendMessage(msg); diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 9004e10a7df9..5c9282e5e2a6 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -370,6 +370,13 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, + IntentFilter filter, String broadcastPermission, Handler scheduler) { + throw new UnsupportedOperationException(); + } + @Override public void unregisterReceiver(BroadcastReceiver receiver) { throw new UnsupportedOperationException(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index e629b7559917..428c4c2f4684 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -1164,6 +1164,13 @@ public final class BridgeContext extends Context { } @Override + public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5, + IntentFilter arg1, String arg2, Handler arg3) { + // pass + return null; + } + + @Override public void removeStickyBroadcast(Intent arg0) { // pass |