From 1f5ac4d322d76ca76fdf5dee40fe9549aad7437e Mon Sep 17 00:00:00 2001 From: riddle_hsu Date: Sat, 3 Jan 2015 15:38:21 +0800 Subject: [PATCH] [ActivityManager] Distinguish FG or BG receiver finished Symptom: Assume a foreground broadcast FG and a background BG. If a recevier registers both FG and BG. When sending BG and FG to the receiver, and the receiver BG receiver completes first, its finishReceiver will trigger next FG receiver rather than BG, and also deliver wrong result code/data to the next. More detail and sample: https://code.google.com/p/android/issues/detail?id=92917 Root cause: Due to BroadcastQueue:getMatchingOrderedReceiver will match by receiver(IBinder), so the caller ActivityManagerService: broadcastRecordForReceiverLocked will always match the first queue(fg) if a receiver is both receiving fg and bg. Solution: Add a parameter flags to finishReceiver, then server side could know the finished receiver should belong to which queue. Another general solution but with bigger scope: I60dce4a48e20c1002a61a979e4d78b9b0a8b94a0 Change-Id: I913ca6f101ac8ec6c7a8e42754e6781f80247b7f --- core/java/android/app/ActivityManagerNative.java | 7 ++-- core/java/android/app/ActivityThread.java | 2 +- core/java/android/app/IActivityManager.java | 3 +- core/java/android/app/LoadedApk.java | 6 ++-- core/java/android/content/BroadcastReceiver.java | 10 +++--- .../android/server/am/ActivityManagerService.java | 37 ++++++---------------- 6 files changed, 26 insertions(+), 39 deletions(-) mode change 100755 => 100644 services/core/java/com/android/server/am/ActivityManagerService.java diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 4e2ff0bdb54f..20355ec9ca0d 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -466,8 +466,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String resultData = data.readString(); Bundle resultExtras = data.readBundle(); boolean resultAbort = data.readInt() != 0; + int intentFlags = data.readInt(); if (who != null) { - finishReceiver(who, resultCode, resultData, resultExtras, resultAbort); + finishReceiver(who, resultCode, resultData, resultExtras, resultAbort, intentFlags); } reply.writeNoException(); return true; @@ -2807,7 +2808,8 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException + public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, + boolean abortBroadcast, int flags) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -2817,6 +2819,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(resultData); data.writeBundle(map); data.writeInt(abortBroadcast ? 1 : 0); + data.writeInt(flags); mRemote.transact(FINISH_RECEIVER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); data.recycle(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 62336762816a..45304e111b36 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -359,7 +359,7 @@ public final class ActivityThread { public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, IBinder token, int sendingUser) { super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, - token, sendingUser); + token, sendingUser, intent.getFlags()); this.intent = intent; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index be26f3033459..d1279ad716ca 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -106,7 +106,8 @@ public interface IActivityManager extends IInterface { String resultData, Bundle map, String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) throws RemoteException; public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException; - public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException; + public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, + boolean abortBroadcast, int flags) throws RemoteException; public void attachApplication(IApplicationThread app) throws RemoteException; public void activityResumed(IBinder token) throws RemoteException; public void activityIdle(IBinder token, Configuration config, diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index aa98e973855c..973196c1f3f8 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -796,7 +796,7 @@ public final class LoadedApk { if (extras != null) { extras.setAllowFds(false); } - mgr.finishReceiver(this, resultCode, data, extras, false); + mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); } catch (RemoteException e) { Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); } @@ -821,8 +821,8 @@ public final class LoadedApk { public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, int sendingUser) { super(resultCode, resultData, resultExtras, - mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, - ordered, sticky, mIIntentReceiver.asBinder(), sendingUser); + mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered, + sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags()); mCurIntent = intent; mOrdered = ordered; } diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 9a32fdffbb9c..af74e7314f6e 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -238,6 +238,7 @@ public abstract class BroadcastReceiver { final boolean mInitialStickyHint; final IBinder mToken; final int mSendingUser; + final int mFlags; int mResultCode; String mResultData; @@ -246,8 +247,8 @@ public abstract class BroadcastReceiver { boolean mFinished; /** @hide */ - public PendingResult(int resultCode, String resultData, Bundle resultExtras, - int type, boolean ordered, boolean sticky, IBinder token, int userId) { + public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type, + boolean ordered, boolean sticky, IBinder token, int userId, int flags) { mResultCode = resultCode; mResultData = resultData; mResultExtras = resultExtras; @@ -256,6 +257,7 @@ public abstract class BroadcastReceiver { mInitialStickyHint = sticky; mToken = token; mSendingUser = userId; + mFlags = flags; } /** @@ -417,11 +419,11 @@ public abstract class BroadcastReceiver { } if (mOrderedHint) { am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras, - mAbortBroadcast); + mAbortBroadcast, mFlags); } else { // This broadcast was sent to a component; it is not ordered, // but we still need to tell the activity manager we are done. - am.finishReceiver(mToken, 0, null, null, false); + am.finishReceiver(mToken, 0, null, null, false, mFlags); } } catch (RemoteException ex) { } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java old mode 100755 new mode 100644 index e3f7fb3c9120..7112f16fc0aa --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -399,16 +399,6 @@ public final class ActivityManagerService extends ActivityManagerNative return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue; } - BroadcastRecord broadcastRecordForReceiverLocked(IBinder receiver) { - for (BroadcastQueue queue : mBroadcastQueues) { - BroadcastRecord r = queue.getMatchingOrderedReceiver(receiver); - if (r != null) { - return r; - } - } - return null; - } - /** * Activity we have told the window manager to have key focus. */ @@ -15313,11 +15303,11 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized(this) { ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl != null) { - if (rl.curBroadcast != null) { - BroadcastRecord r = rl.curBroadcast; - final boolean doNext = finishReceiverLocked( - receiver.asBinder(), r.resultCode, r.resultData, - r.resultExtras, r.resultAbort); + final BroadcastRecord r = rl.curBroadcast; + if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) { + final boolean doNext = r.queue.finishReceiverLocked( + r, r.resultCode, r.resultData, r.resultExtras, + r.resultAbort, false); if (doNext) { doTrim = true; r.queue.processNextBroadcast(false); @@ -15990,17 +15980,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final boolean finishReceiverLocked(IBinder receiver, int resultCode, - String resultData, Bundle resultExtras, boolean resultAbort) { - final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver); - if (r == null) { - Slog.w(TAG, "finishReceiver called but not found on queue"); - return false; - } - - return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false); - } - void backgroundServicesFinishedLocked(int userId) { for (BroadcastQueue queue : mBroadcastQueues) { queue.backgroundServicesFinishedLocked(userId); @@ -16008,7 +15987,7 @@ public final class ActivityManagerService extends ActivityManagerNative } public void finishReceiver(IBinder who, int resultCode, String resultData, - Bundle resultExtras, boolean resultAbort) { + Bundle resultExtras, boolean resultAbort, int flags) { if (DEBUG_BROADCAST) Slog.v(TAG, "Finish receiver: " + who); // Refuse possible leaked file descriptors @@ -16022,7 +16001,9 @@ public final class ActivityManagerService extends ActivityManagerNative BroadcastRecord r; synchronized(this) { - r = broadcastRecordForReceiverLocked(who); + BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0 + ? mFgBroadcastQueue : mBgBroadcastQueue; + r = queue.getMatchingOrderedReceiver(who); if (r != null) { doNext = r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, true); -- 2.11.0