Move (some) codecs into the codec process

Encoders and secure decoders still run in the mediaserver, while
all other codecs run in a separate codec process.

Bug: 22775369

Change-Id: Ie2ac87d53edbcf7c8f46a68a15857c9940f6d00d
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 9a7dff6..b9ee91a 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -98,7 +98,9 @@
     }
 
     virtual status_t allocateNode(
-            const char *name, const sp<IOMXObserver> &observer, node_id *node) {
+            const char *name, const sp<IOMXObserver> &observer,
+            sp<IBinder> *nodeBinder,
+            node_id *node) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeCString(name);
@@ -108,6 +110,9 @@
         status_t err = reply.readInt32();
         if (err == OK) {
             *node = (node_id)reply.readInt32();
+            if (nodeBinder != NULL) {
+                *nodeBinder = remote();
+            }
         } else {
             *node = 0;
         }
@@ -656,7 +661,8 @@
 
             node_id node;
 
-            status_t err = allocateNode(name, observer, &node);
+            status_t err = allocateNode(name, observer,
+                    NULL /* nodeBinder */, &node);
             reply->writeInt32(err);
             if (err == OK) {
                 reply->writeInt32((int32_t)node);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 0dc5d4c..ee573f0 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5541,7 +5541,7 @@
     ALOGV("Now uninitialized");
 
     if (mDeathNotifier != NULL) {
-        IInterface::asBinder(mCodec->mOMX)->unlinkToDeath(mDeathNotifier);
+        mCodec->mNodeBinder->unlinkToDeath(mDeathNotifier);
         mDeathNotifier.clear();
     }
 
@@ -5638,13 +5638,6 @@
 
     sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec);
 
-    mDeathNotifier = new DeathNotifier(notify);
-    if (IInterface::asBinder(omx)->linkToDeath(mDeathNotifier) != OK) {
-        // This was a local binder, if it dies so do we, we won't care
-        // about any notifications in the afterlife.
-        mDeathNotifier.clear();
-    }
-
     Vector<AString> matchingCodecs;
 
     AString mime;
@@ -5683,7 +5676,7 @@
         pid_t tid = gettid();
         int prevPriority = androidGetThreadPriority(tid);
         androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
-        err = omx->allocateNode(componentName.c_str(), observer, &node);
+        err = omx->allocateNode(componentName.c_str(), observer, &mCodec->mNodeBinder, &node);
         androidSetThreadPriority(tid, prevPriority);
 
         if (err == OK) {
@@ -5707,6 +5700,14 @@
         return false;
     }
 
+    mDeathNotifier = new DeathNotifier(notify);
+    if (mCodec->mNodeBinder == NULL ||
+            mCodec->mNodeBinder->linkToDeath(mDeathNotifier) != OK) {
+        // This was a local binder, if it dies so do we, we won't care
+        // about any notifications in the afterlife.
+        mDeathNotifier.clear();
+    }
+
     notify = new AMessage(kWhatOMXMessageList, mCodec);
     observer->setNotificationMessage(notify);
 
@@ -7078,7 +7079,7 @@
     sp<CodecObserver> observer = new CodecObserver;
     IOMX::node_id node = 0;
 
-    err = omx->allocateNode(name.c_str(), observer, &node);
+    err = omx->allocateNode(name.c_str(), observer, NULL, &node);
     if (err != OK) {
         client.disconnect();
         return err;
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 50f235e..8e72405 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -25,19 +25,29 @@
 
 #include <binder/IServiceManager.h>
 #include <media/IMediaPlayerService.h>
+#include <media/IMediaCodecService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/OMXClient.h>
+#include <cutils/properties.h>
 #include <utils/KeyedVector.h>
 
 #include "include/OMX.h"
 
 namespace android {
 
+static bool sCodecProcessEnabled = true;
+
 struct MuxOMX : public IOMX {
-    MuxOMX(const sp<IOMX> &remoteOMX);
+    MuxOMX(const sp<IOMX> &mediaServerOMX, const sp<IOMX> &mediaCodecOMX);
     virtual ~MuxOMX();
 
-    virtual IBinder *onAsBinder() { return IInterface::asBinder(mRemoteOMX).get(); }
+    // Nobody should be calling this. In case someone does anyway, just
+    // return the media server IOMX.
+    // TODO: return NULL
+    virtual IBinder *onAsBinder() {
+        ALOGE("MuxOMX::onAsBinder should not be called");
+        return IInterface::asBinder(mMediaServerOMX).get();
+    }
 
     virtual bool livesLocally(node_id node, pid_t pid);
 
@@ -45,6 +55,7 @@
 
     virtual status_t allocateNode(
             const char *name, const sp<IOMXObserver> &observer,
+            sp<IBinder> *nodeBinder,
             node_id *node);
 
     virtual status_t freeNode(node_id node);
@@ -148,23 +159,32 @@
 private:
     mutable Mutex mLock;
 
-    sp<IOMX> mRemoteOMX;
+    sp<IOMX> mMediaServerOMX;
+    sp<IOMX> mMediaCodecOMX;
     sp<IOMX> mLocalOMX;
 
-    KeyedVector<node_id, bool> mIsLocalNode;
+    typedef enum {
+        LOCAL,
+        MEDIAPROCESS,
+        CODECPROCESS
+    } node_location;
+
+    KeyedVector<node_id, node_location> mNodeLocation;
 
     bool isLocalNode(node_id node) const;
     bool isLocalNode_l(node_id node) const;
     const sp<IOMX> &getOMX(node_id node) const;
     const sp<IOMX> &getOMX_l(node_id node) const;
 
-    static bool CanLiveLocally(const char *name);
+    static node_location getPreferredCodecLocation(const char *name);
 
     DISALLOW_EVIL_CONSTRUCTORS(MuxOMX);
 };
 
-MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
-    : mRemoteOMX(remoteOMX) {
+MuxOMX::MuxOMX(const sp<IOMX> &mediaServerOMX, const sp<IOMX> &mediaCodecOMX)
+    : mMediaServerOMX(mediaServerOMX),
+      mMediaCodecOMX(mediaCodecOMX) {
+    ALOGI("MuxOMX ctor");
 }
 
 MuxOMX::~MuxOMX() {
@@ -177,27 +197,49 @@
 }
 
 bool MuxOMX::isLocalNode_l(node_id node) const {
-    return mIsLocalNode.indexOfKey(node) >= 0;
+    return mNodeLocation.valueFor(node) == LOCAL;
 }
 
 // static
-bool MuxOMX::CanLiveLocally(const char *name) {
+MuxOMX::node_location MuxOMX::getPreferredCodecLocation(const char *name) {
+    if (sCodecProcessEnabled) {
+        // all non-secure decoders plus OMX.google.* encoders can go in the codec process
+        if ((strcasestr(name, "decoder") && !strcasestr(name, "secure")) ||
+                !strncasecmp(name, "OMX.google.", 11)) {
+            return CODECPROCESS;
+        }
+        // everything else runs in the media server
+        return MEDIAPROCESS;
+    } else {
 #ifdef __LP64__
-    (void)name; // disable unused parameter warning
-    // 64 bit processes always run OMX remote on MediaServer
-    return false;
+        // 64 bit processes always run OMX remote on MediaServer
+        return MEDIAPROCESS;
 #else
-    // 32 bit processes run only OMX.google.* components locally
-    return !strncasecmp(name, "OMX.google.", 11);
+        // 32 bit processes run only OMX.google.* components locally
+        if (!strncasecmp(name, "OMX.google.", 11)) {
+            return LOCAL;
+        }
+        return MEDIAPROCESS;
 #endif
+    }
 }
 
 const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
-    return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
+    Mutex::Autolock autoLock(mLock);
+    return getOMX_l(node);
 }
 
 const sp<IOMX> &MuxOMX::getOMX_l(node_id node) const {
-    return isLocalNode_l(node) ? mLocalOMX : mRemoteOMX;
+    node_location loc = mNodeLocation.valueFor(node);
+    if (loc == LOCAL) {
+        return mLocalOMX;
+    } else if (loc == MEDIAPROCESS) {
+        return mMediaServerOMX;
+    } else if (loc == CODECPROCESS) {
+        return mMediaCodecOMX;
+    }
+    ALOGE("Couldn't determine node location for node %d: %d, using local", node, loc);
+    return mLocalOMX;
 }
 
 bool MuxOMX::livesLocally(node_id node, pid_t pid) {
@@ -216,29 +258,34 @@
 
 status_t MuxOMX::allocateNode(
         const char *name, const sp<IOMXObserver> &observer,
+        sp<IBinder> *nodeBinder,
         node_id *node) {
     Mutex::Autolock autoLock(mLock);
 
     sp<IOMX> omx;
 
-    if (CanLiveLocally(name)) {
+    node_location loc = getPreferredCodecLocation(name);
+    if (loc == CODECPROCESS) {
+        omx = mMediaCodecOMX;
+    } else if (loc == MEDIAPROCESS) {
+        omx = mMediaServerOMX;
+    } else {
         if (mLocalOMX == NULL) {
             mLocalOMX = new OMX;
         }
         omx = mLocalOMX;
-    } else {
-        omx = mRemoteOMX;
     }
 
-    status_t err = omx->allocateNode(name, observer, node);
+    status_t err = omx->allocateNode(name, observer, nodeBinder, node);
+    ALOGV("allocated node_id %x on %s OMX", *node, omx == mMediaCodecOMX ? "codecprocess" :
+            omx == mMediaServerOMX ? "mediaserver" : "local");
+
 
     if (err != OK) {
         return err;
     }
 
-    if (omx == mLocalOMX) {
-        mIsLocalNode.add(*node, true);
-    }
+    mNodeLocation.add(*node, loc);
 
     return OK;
 }
@@ -252,7 +299,7 @@
         return err;
     }
 
-    mIsLocalNode.removeItem(node);
+    mNodeLocation.removeItem(node);
 
     return OK;
 }
@@ -352,7 +399,7 @@
         sp<IGraphicBufferProducer> *bufferProducer,
         sp<IGraphicBufferConsumer> *bufferConsumer) {
     // TODO: local or remote? Always use remote for now
-    return mRemoteOMX->createPersistentInputSurface(
+    return mMediaServerOMX->createPersistentInputSurface(
             bufferProducer, bufferConsumer);
 }
 
@@ -415,29 +462,53 @@
 }
 
 OMXClient::OMXClient() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.codecremote", value, NULL)
+            && (!strcmp("0", value) || !strcasecmp("false", value))) {
+        sCodecProcessEnabled = false;
+    }
 }
 
 status_t OMXClient::connect() {
     sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.player"));
-    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    sp<IBinder> playerbinder = sm->getService(String16("media.player"));
+    sp<IMediaPlayerService> mediaservice = interface_cast<IMediaPlayerService>(playerbinder);
 
-    if (service.get() == NULL) {
+    if (mediaservice.get() == NULL) {
         ALOGE("Cannot obtain IMediaPlayerService");
         return NO_INIT;
     }
 
-    mOMX = service->getOMX();
-    if (mOMX.get() == NULL) {
-        ALOGE("Cannot obtain IOMX");
+    sp<IOMX> mediaServerOMX = mediaservice->getOMX();
+    if (mediaServerOMX.get() == NULL) {
+        ALOGE("Cannot obtain mediaserver IOMX");
         return NO_INIT;
     }
 
-    if (!mOMX->livesLocally(0 /* node */, getpid())) {
-        ALOGI("Using client-side OMX mux.");
-        mOMX = new MuxOMX(mOMX);
+    // If we don't want to use the codec process, and the media server OMX
+    // is local, use it directly instead of going through MuxOMX
+    if (!sCodecProcessEnabled &&
+            mediaServerOMX->livesLocally(0 /* node */, getpid())) {
+        mOMX = mediaServerOMX;
+        return OK;
     }
 
+    sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
+    sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
+
+    if (codecservice.get() == NULL) {
+        ALOGE("Cannot obtain IMediaCodecService");
+        return NO_INIT;
+    }
+
+    sp<IOMX> mediaCodecOMX = codecservice->getOMX();
+    if (mediaCodecOMX.get() == NULL) {
+        ALOGE("Cannot obtain mediacodec IOMX");
+        return NO_INIT;
+    }
+
+    mOMX = new MuxOMX(mediaServerOMX, mediaCodecOMX);
+
     return OK;
 }
 
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 4c27360..c715939 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -36,7 +36,9 @@
     virtual status_t listNodes(List<ComponentInfo> *list);
 
     virtual status_t allocateNode(
-            const char *name, const sp<IOMXObserver> &observer, node_id *node);
+            const char *name, const sp<IOMXObserver> &observer,
+            sp<IBinder> *nodeBinder,
+            node_id *node);
 
     virtual status_t freeNode(node_id node);
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index a20028b..6be289b 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -235,10 +235,14 @@
 }
 
 status_t OMX::allocateNode(
-        const char *name, const sp<IOMXObserver> &observer, node_id *node) {
+        const char *name, const sp<IOMXObserver> &observer,
+        sp<IBinder> *nodeBinder, node_id *node) {
     Mutex::Autolock autoLock(mLock);
 
     *node = 0;
+    if (nodeBinder != NULL) {
+        *nodeBinder = NULL;
+    }
 
     if (mNodeIDToInstance.size() == kMaxNodeInstances) {
         // all possible node IDs are in use
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index c0ccb35..50bb0de 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -267,7 +267,7 @@
     IOMX::node_id node;
 
     status_t err =
-        mOMX->allocateNode(componentName, this, &node);
+        mOMX->allocateNode(componentName, this, NULL, &node);
     EXPECT_SUCCESS(err, "allocateNode");
 
     NodeReaper reaper(this, node);