Reland: Implement CreateInputSurface CCodec plugin

createInputSurface() will attempt to create an input surface from a list
of services, returning the first success, in the following order:
  0 - Hardware Codec2.0
  1 - Software Codec2.0

The system property debug.stagefright.c2inputsurface can be used to mask
available services. The k-th bit (counting from 0) of
debug.stagefright.c2inputsurface corresponds to enabling of the
k-indexed service.

The default value of debug.stagefright.c2inputsurface is 0, which means
createInputSurface() will not try to create an input surface from any of
the two Codec2.0 services and simply fall back to the OMX service.

Test: adb shell setprop debug.stagefright.ccodec 3
adb shell setprop debug.stagefright.c2inputsurface 2
adb shell killall mediaserver
adb shell /system/bin/screenrecord --codec-name c2.android.avc.encoder \
/sdcard/screenrecord.mp4
adb pull /sdcard/screenrecord.mp4

Test: m cts && cts-tradefed run cts -m CtsCameraTestCases \
-t android.hardware.camera2.cts.CameraDeviceTest

Bug: 64121714
Bug: 111101148
Change-Id: I8332e33444dec4f5d172bd9d8ec3a3e8cf3edb80
diff --git a/codec2/hidl/1.0/utils/ComponentStore.cpp b/codec2/hidl/1.0/utils/ComponentStore.cpp
index a42b3a1..4941ede 100644
--- a/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -28,6 +28,7 @@
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 
 #include <C2PlatformSupport.h>
+#include <util/C2InterfaceHelper.h>
 
 #include <utils/Errors.h>
 
@@ -226,11 +227,12 @@
         return nullptr;
     }
     typedef ::android::hardware::graphics::bufferqueue::V1_0::
-            IGraphicBufferProducer HGBP;
-    typedef ::android::TWGraphicBufferProducer<HGBP> B2HGBP;
+            IGraphicBufferProducer HGbp;
+    typedef ::android::TWGraphicBufferProducer<HGbp> B2HGbp;
     return new InputSurface(
             this,
-            new B2HGBP(source->getIGraphicBufferProducer()),
+            std::make_shared<C2ReflectorHelper>(),
+            new B2HGbp(source->getIGraphicBufferProducer()),
             source);
 }
 
diff --git a/codec2/hidl/1.0/utils/InputSurface.cpp b/codec2/hidl/1.0/utils/InputSurface.cpp
index 2d58183..4713af4 100644
--- a/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -287,13 +287,13 @@
 // Constructor is exclusive to ComponentStore.
 InputSurface::InputSurface(
         const sp<ComponentStore>& store,
+        const std::shared_ptr<C2ReflectorHelper>& reflector,
         const sp<HGraphicBufferProducer>& base,
         const sp<GraphicBufferSource>& source) :
     mStore(store),
     mBase(base),
     mSource(source),
-    mHelper(std::make_shared<ConfigurableImpl>(
-            std::static_pointer_cast<C2ReflectorHelper>(store->mParamReflector))),
+    mHelper(std::make_shared<ConfigurableImpl>(reflector)),
     mConfigurable(new CachedConfigurable(
             std::make_unique<ConfigurableWrapper>(mHelper, source))) {
 
diff --git a/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index ee82a24..0e86d63 100644
--- a/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -33,6 +33,8 @@
 #include <hidl/HidlSupport.h>
 #include <hidl/Status.h>
 
+class C2ReflectorHelper;
+
 namespace hardware {
 namespace google {
 namespace media {
@@ -178,6 +180,7 @@
 
     InputSurface(
             const sp<ComponentStore>& store,
+            const std::shared_ptr<C2ReflectorHelper>& reflector,
             const sp<HGraphicBufferProducer>& base,
             const sp<GraphicBufferSource>& source);
 
diff --git a/codec2/hidl/client/client.cpp b/codec2/hidl/client/client.cpp
index 76a3196..48a9d5d 100644
--- a/codec2/hidl/client/client.cpp
+++ b/codec2/hidl/client/client.cpp
@@ -26,8 +26,9 @@
 #include <type_traits>
 #include <vector>
 
+#include <android-base/properties.h>
 #include <bufferpool/ClientManager.h>
-#include <cutils/properties.h>
+#include <cutils/native_handle.h>
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <hidl/HidlSupport.h>
 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
@@ -62,22 +63,18 @@
 // c2_status_t value that corresponds to hwbinder transaction failure.
 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
 
-// List of known IComponentStore services.
+// List of known IComponentStore services in the decreasing order of preference.
 constexpr const char* kClientNames[] = {
         "default",
         "software",
     };
 
-typedef std::array<
-        std::shared_ptr<Codec2Client>,
-        std::extent<decltype(kClientNames)>::value> ClientList;
+// Number of known IComponentStore services.
+constexpr size_t kNumClients = std::extent<decltype(kClientNames)>::value;
+
+typedef std::array<std::shared_ptr<Codec2Client>, kNumClients> ClientList;
 
 // Convenience methods to obtain known clients.
-size_t getClientCount() {
-    // TODO: this may not work if there is no default service
-    return std::extent<decltype(kClientNames)>::value;
-}
-
 std::shared_ptr<Codec2Client> getClient(size_t index) {
     return Codec2Client::CreateFromService(kClientNames[index]);
 }
@@ -508,10 +505,14 @@
         ALOGE("createInputSurface -- failed transaction.");
         return C2_TRANSACTION_FAILED;
     }
-    *inputSurface = std::make_shared<InputSurface>(
-            static_cast<sp<IInputSurface>>(transResult));
+    sp<IInputSurface> result = static_cast<sp<IInputSurface>>(transResult);
+    if (!result) {
+        *inputSurface = nullptr;
+        return C2_OK;
+    }
+    *inputSurface = std::make_shared<InputSurface>(result);
     if (!*inputSurface) {
-        ALOGE("createInputSurface -- failed to create client.");
+        ALOGE("createInputSurface -- unknown error.");
         return C2_CORRUPTED;
     }
     return C2_OK;
@@ -631,7 +632,7 @@
     // client fails, retry once. We do this by pushing the last known client in front of the
     // list of all clients.
     std::deque<size_t> indices;
-    for (size_t index = getClientCount(); index > 0; ) {
+    for (size_t index = kNumClients; index > 0; ) {
         indices.push_front(--index);
     }
 
@@ -715,6 +716,24 @@
     return interface;
 }
 
+std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface() {
+    uint32_t serviceMask = ::android::base::GetUintProperty(
+            "debug.stagefright.c2inputsurface", uint32_t(0));
+    for (size_t i = 0; i < kNumClients; ++i) {
+        if ((1 << i) & serviceMask) {
+            std::shared_ptr<Codec2Client> client = getClient(i);
+            std::shared_ptr<Codec2Client::InputSurface> inputSurface;
+            if (client &&
+                    client->createInputSurface(&inputSurface) == C2_OK &&
+                    inputSurface) {
+                return inputSurface;
+            }
+        }
+    }
+    ALOGW("Could not create an input surface from any Codec2.0 services.");
+    return nullptr;
+}
+
 const std::vector<C2Component::Traits>& Codec2Client::ListComponents() {
     static std::vector<C2Component::Traits> traitsList = [](){
         std::vector<C2Component::Traits> list;
@@ -1256,6 +1275,10 @@
     return mGraphicBufferProducer;
 }
 
+const sp<IInputSurface>& Codec2Client::InputSurface::getHalInterface() const {
+    return mBase;
+}
+
 // Codec2Client::InputSurfaceConnection
 
 Codec2Client::InputSurfaceConnection::Base*
diff --git a/codec2/hidl/client/include/codec2/hidl/client.h b/codec2/hidl/client/include/codec2/hidl/client.h
index 24b6f7e..3f38a9a 100644
--- a/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/codec2/hidl/client/include/codec2/hidl/client.h
@@ -214,6 +214,9 @@
     // List traits from all known IComponentStore services.
     static const std::vector<C2Component::Traits>& ListComponents();
 
+    // Create an input surface.
+    static std::shared_ptr<InputSurface> CreateInputSurface();
+
     // base cannot be null.
     Codec2Client(const sp<Base>& base, std::string instanceName);
 
@@ -393,6 +396,9 @@
 
     const sp<IGraphicBufferProducer>& getGraphicBufferProducer() const;
 
+    // Return the underlying IInputSurface.
+    const sp<Base>& getHalInterface() const;
+
     // base cannot be null.
     InputSurface(const sp<Base>& base);
 
diff --git a/media/sfplugin/Android.bp b/media/sfplugin/Android.bp
index 9843162..5c48cc6 100644
--- a/media/sfplugin/Android.bp
+++ b/media/sfplugin/Android.bp
@@ -26,6 +26,7 @@
         "android.hardware.cas.native@1.0",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.media.omx@1.0",
+        "hardware.google.media.c2@1.0",
         "libbase",
         "libbinder",
         "libcodec2_hidl_client",
diff --git a/media/sfplugin/CCodec.cpp b/media/sfplugin/CCodec.cpp
index a030e68..b7797dd 100644
--- a/media/sfplugin/CCodec.cpp
+++ b/media/sfplugin/CCodec.cpp
@@ -27,30 +27,35 @@
 #include <C2PlatformSupport.h>
 #include <C2V4l2Support.h>
 
-#include <android/IOMXBufferSource.h>
 #include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
-#include <media/omx/1.0/WOmx.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <media/omx/1.0/WGraphicBufferSource.h>
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
 
 #include "C2OMXNode.h"
 #include "CCodec.h"
 #include "CCodecBufferChannel.h"
 #include "InputSurfaceWrapper.h"
 
+extern "C" android::PersistentSurface *CreateInputSurface();
+
 namespace android {
 
 using namespace std::chrono_literals;
 using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
 using android::base::StringPrintf;
 using BGraphicBufferSource = ::android::IGraphicBufferSource;
+using ::hardware::google::media::c2::V1_0::IInputSurface;
 
 namespace {
 
@@ -862,48 +867,56 @@
         outputFormat = config->mOutputFormat;
     }
 
-    // TODO: Remove this property check and assume it's always true.
-    if (property_get_bool("debug.stagefright.c2inputsurface", false)) {
-        std::shared_ptr<Codec2Client::InputSurface> surface;
-
-        err = toStatusT(mClient->createInputSurface(&surface),
-                        C2_OPERATION_ComponentStore_createInputSurface);
-        if (err != OK) {
-            ALOGE("Failed to create input surface: %d", static_cast<int>(err));
-            mCallback->onInputSurfaceCreationFailed(err);
-            return;
+    std::shared_ptr<PersistentSurface> persistentSurface(CreateInputSurface());
+    if (!persistentSurface) {
+        using namespace android::hardware::media::omx::V1_0;
+        using namespace android::hardware::media::omx::V1_0::utils;
+        using namespace android::hardware::graphics::bufferqueue::V1_0::utils;
+        typedef android::hardware::media::omx::V1_0::Status OmxStatus;
+        android::sp<IOmx> omx = IOmx::getService();
+        typedef android::hardware::graphics::bufferqueue::V1_0::
+                IGraphicBufferProducer HGraphicBufferProducer;
+        typedef android::hardware::media::omx::V1_0::
+                IGraphicBufferSource HGraphicBufferSource;
+        OmxStatus s;
+        android::sp<HGraphicBufferProducer> gbp;
+        android::sp<HGraphicBufferSource> gbs;
+        android::Return<void> transStatus = omx->createInputSurface(
+                [&s, &gbp, &gbs](
+                        OmxStatus status,
+                        const android::sp<HGraphicBufferProducer>& producer,
+                        const android::sp<HGraphicBufferSource>& source) {
+                    s = status;
+                    gbp = producer;
+                    gbs = source;
+                });
+        if (transStatus.isOk() && s == OmxStatus::OK) {
+            persistentSurface = std::make_shared<android::PersistentSurface>(
+                    new H2BGraphicBufferProducer(gbp),
+                    sp<::android::IGraphicBufferSource>(
+                        new LWGraphicBufferSource(gbs)));
         }
-        if (!surface) {
-            ALOGE("Failed to create input surface: null input surface");
+    }
+
+    if (persistentSurface->getHidlTarget()) {
+        sp<IInputSurface> inputSurface = IInputSurface::castFrom(
+                persistentSurface->getHidlTarget());
+        if (!inputSurface) {
+            ALOGE("Corrupted input surface");
             mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
             return;
         }
-        bufferProducer = surface->getGraphicBufferProducer();
-        err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(surface));
-    } else { // TODO: Remove this block.
-        using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmx> tOmx = IOmx::getService("default");
-        if (tOmx == nullptr) {
-            ALOGE("Failed to create input surface");
-            mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
-            return;
-        }
-        sp<IOMX> omx = new utils::LWOmx(tOmx);
-
-        sp<BGraphicBufferSource> bufferSource;
-        err = omx->createInputSurface(&bufferProducer, &bufferSource);
-
-        if (err != OK) {
-            ALOGE("Failed to create input surface: %d", err);
-            mCallback->onInputSurfaceCreationFailed(err);
-            return;
-        }
+        err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
+                std::make_shared<Codec2Client::InputSurface>(inputSurface)));
+        bufferProducer = new H2BGraphicBufferProducer(inputSurface);
+    } else {
         int32_t width = 0;
         (void)outputFormat->findInt32("width", &width);
         int32_t height = 0;
         (void)outputFormat->findInt32("height", &height);
         err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
-                bufferSource, width, height));
+                persistentSurface->getBufferSource(), width, height));
+        bufferProducer = persistentSurface->getBufferProducer();
     }
 
     if (err != OK) {
@@ -911,6 +924,7 @@
         mCallback->onInputSurfaceCreationFailed(err);
         return;
     }
+
     mCallback->onInputSurfaceCreated(
             inputFormat,
             outputFormat,
@@ -949,16 +963,34 @@
         inputFormat = config->mInputFormat;
         outputFormat = config->mOutputFormat;
     }
-    int32_t width = 0;
-    (void)outputFormat->findInt32("width", &width);
-    int32_t height = 0;
-    (void)outputFormat->findInt32("height", &height);
-    status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
-            surface->getBufferSource(), width, height));
-    if (err != OK) {
-        ALOGE("Failed to set up input surface: %d", err);
-        mCallback->onInputSurfaceDeclined(err);
-        return;
+    auto hidlTarget = surface->getHidlTarget();
+    if (hidlTarget) {
+        sp<IInputSurface> inputSurface =
+                IInputSurface::castFrom(hidlTarget);
+        if (!inputSurface) {
+            ALOGE("Failed to set input surface: Corrupted surface.");
+            mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
+            return;
+        }
+        status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
+                std::make_shared<Codec2Client::InputSurface>(inputSurface)));
+        if (err != OK) {
+            ALOGE("Failed to set up input surface: %d", err);
+            mCallback->onInputSurfaceDeclined(err);
+            return;
+        }
+    } else {
+        int32_t width = 0;
+        (void)outputFormat->findInt32("width", &width);
+        int32_t height = 0;
+        (void)outputFormat->findInt32("height", &height);
+        status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
+                surface->getBufferSource(), width, height));
+        if (err != OK) {
+            ALOGE("Failed to set up input surface: %d", err);
+            mCallback->onInputSurfaceDeclined(err);
+            return;
+        }
     }
     mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
 }
@@ -1546,3 +1578,15 @@
     return new android::CCodec;
 }
 
+extern "C" android::PersistentSurface *CreateInputSurface() {
+    std::shared_ptr<android::Codec2Client::InputSurface> inputSurface =
+            android::Codec2Client::CreateInputSurface();
+    if (inputSurface) {
+        return new android::PersistentSurface(
+                inputSurface->getGraphicBufferProducer(),
+                static_cast<android::sp<android::hidl::base::V1_0::IBase>>(
+                inputSurface->getHalInterface()));
+    }
+    return nullptr;
+}
+