Merge "Support for posting messages and synchronously waiting for a response."
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index c1bd4ed..2e5fd73 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -31,9 +31,14 @@
 
     void unregisterHandler(ALooper::handler_id handlerID);
 
-    void postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
+    status_t postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
     void deliverMessage(const sp<AMessage> &msg);
 
+    status_t postAndAwaitResponse(
+            const sp<AMessage> &msg, sp<AMessage> *response);
+
+    void postReply(uint32_t replyID, const sp<AMessage> &reply);
+
     sp<ALooper> findLooper(ALooper::handler_id handlerID);
 
 private:
@@ -45,6 +50,12 @@
     Mutex mLock;
     KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;
     ALooper::handler_id mNextHandlerID;
+    uint32_t mNextReplyID;
+    Condition mRepliesCondition;
+
+    KeyedVector<uint32_t, sp<AMessage> > mReplies;
+
+    status_t postMessage_l(const sp<AMessage> &msg, int64_t delayUs);
 
     DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster);
 };
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 72dc730..7ec54aa 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -72,6 +72,17 @@
 
     void post(int64_t delayUs = 0);
 
+    // Posts the message to its target and waits for a response (or error)
+    // before returning.
+    status_t postAndAwaitResponse(sp<AMessage> *response);
+
+    // If this returns true, the sender of this message is synchronously
+    // awaiting a response, the "replyID" can be used to send the response
+    // via "postReply" below.
+    bool senderAwaitsResponse(uint32_t *replyID) const;
+
+    void postReply(uint32_t replyID);
+
     // Performs a deep-copy of "this", contained messages are in turn "dup'ed".
     // Warning: RefBase items, i.e. "objects" are _not_ copied but only have
     // their refcount incremented.
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 8aa1b15..e399f2f 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -27,7 +27,8 @@
 namespace android {
 
 ALooperRoster::ALooperRoster()
-    : mNextHandlerID(1) {
+    : mNextHandlerID(1),
+      mNextReplyID(1) {
 }
 
 ALooper::handler_id ALooperRoster::registerHandler(
@@ -70,15 +71,19 @@
     mHandlers.removeItemsAt(index);
 }
 
-void ALooperRoster::postMessage(
+status_t ALooperRoster::postMessage(
         const sp<AMessage> &msg, int64_t delayUs) {
     Mutex::Autolock autoLock(mLock);
+    return postMessage_l(msg, delayUs);
+}
 
+status_t ALooperRoster::postMessage_l(
+        const sp<AMessage> &msg, int64_t delayUs) {
     ssize_t index = mHandlers.indexOfKey(msg->target());
 
     if (index < 0) {
         LOGW("failed to post message. Target handler not registered.");
-        return;
+        return -ENOENT;
     }
 
     const HandlerInfo &info = mHandlers.valueAt(index);
@@ -91,10 +96,12 @@
              msg->target());
 
         mHandlers.removeItemsAt(index);
-        return;
+        return -ENOENT;
     }
 
     looper->post(msg, delayUs);
+
+    return OK;
 }
 
 void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {
@@ -145,4 +152,38 @@
     return looper;
 }
 
+status_t ALooperRoster::postAndAwaitResponse(
+        const sp<AMessage> &msg, sp<AMessage> *response) {
+    Mutex::Autolock autoLock(mLock);
+
+    uint32_t replyID = mNextReplyID++;
+
+    msg->setInt32("replyID", replyID);
+
+    status_t err = postMessage_l(msg, 0 /* delayUs */);
+
+    if (err != OK) {
+        response->clear();
+        return err;
+    }
+
+    ssize_t index;
+    while ((index = mReplies.indexOfKey(replyID)) < 0) {
+        mRepliesCondition.wait(mLock);
+    }
+
+    *response = mReplies.valueAt(index);
+    mReplies.removeItemsAt(index);
+
+    return OK;
+}
+
+void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) {
+    Mutex::Autolock autoLock(mLock);
+
+    CHECK(mReplies.indexOfKey(replyID) < 0);
+    mReplies.add(replyID, reply);
+    mRepliesCondition.broadcast();
+}
+
 }  // namespace android
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index b592c3f..582bdba 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -27,6 +27,8 @@
 
 namespace android {
 
+extern ALooperRoster gLooperRoster;
+
 AMessage::AMessage(uint32_t what, ALooper::handler_id target)
     : mWhat(what),
       mTarget(target),
@@ -227,11 +229,30 @@
 }
 
 void AMessage::post(int64_t delayUs) {
-    extern ALooperRoster gLooperRoster;
-
     gLooperRoster.postMessage(this, delayUs);
 }
 
+status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
+    return gLooperRoster.postAndAwaitResponse(this, response);
+}
+
+void AMessage::postReply(uint32_t replyID) {
+    gLooperRoster.postReply(replyID, this);
+}
+
+bool AMessage::senderAwaitsResponse(uint32_t *replyID) const {
+    int32_t tmp;
+    bool found = findInt32("replyID", &tmp);
+
+    if (!found) {
+        return false;
+    }
+
+    *replyID = static_cast<uint32_t>(tmp);
+
+    return true;
+}
+
 sp<AMessage> AMessage::dup() const {
     sp<AMessage> msg = new AMessage(mWhat, mTarget);
     msg->mNumItems = mNumItems;