Merge "Remove libhwbinder/libhidltransport deps"
diff --git a/tv/cec/1.0/default/HdmiCecMock.cpp b/tv/cec/1.0/default/HdmiCecMock.cpp
index eba8f95..219be86 100644
--- a/tv/cec/1.0/default/HdmiCecMock.cpp
+++ b/tv/cec/1.0/default/HdmiCecMock.cpp
@@ -77,6 +77,7 @@
     if (message.body.size() == 0) {
         return SendMessageResult::NACK;
     }
+    sendMessageToFifo(message);
     return SendMessageResult::SUCCESS;
 }
 
@@ -88,6 +89,11 @@
     if (callback != nullptr) {
         mCallback = callback;
         mCallback->linkToDeath(this, 0 /*cookie*/);
+
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR);
+        mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR);
+        pthread_create(&mThreadId, NULL, __threadLoop, this);
+        pthread_setname_np(mThreadId, "hdmi_cec_loop");
     }
     return Void();
 }
@@ -102,17 +108,8 @@
 }
 
 Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
-    vector<HdmiPortInfo> portInfos;
     // TODO ready port info from device specific config
-    portInfos.resize(mTotalPorts);
-    for (int i = 0; i < mTotalPorts; ++i) {
-        portInfos[i] = {.type = HdmiPortType::INPUT,
-                        .portId = static_cast<uint32_t>(i),
-                        .cecSupported = true,
-                        .arcSupported = (i == 0),
-                        .physicalAddress = static_cast<uint16_t>(i << 12)};
-    }
-    _hidl_cb(portInfos);
+    _hidl_cb(mPortInfo);
     return Void();
 }
 
@@ -140,13 +137,177 @@
     return Void();
 }
 
-Return<bool> HdmiCecMock::isConnected(int32_t portId __unused) {
+Return<bool> HdmiCecMock::isConnected(int32_t portId) {
     // maintain port connection status and update on hotplug event
+    if (portId < mTotalPorts && portId >= 0) {
+        return mPortConnectionStatus[portId];
+    }
     return false;
 }
 
+void* HdmiCecMock::__threadLoop(void* user) {
+    HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
+    self->threadLoop();
+    return 0;
+}
+
+int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+    if (msgCount <= 0 || !buf) {
+        return 0;
+    }
+
+    int ret = -1;
+    /* maybe blocked at driver */
+    ret = read(mInputFile, buf, msgCount);
+    if (ret < 0) {
+        ALOGE("[halimp] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
+        return -1;
+    }
+
+    return ret;
+}
+
+int HdmiCecMock::sendMessageToFifo(const CecMessage& message) {
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int ret = -1;
+
+    memset(msgBuf, 0, sizeof(msgBuf));
+    msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
+                (static_cast<uint8_t>(message.destination) & 0xf);
+
+    size_t length = std::min(static_cast<size_t>(message.body.size()),
+                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    for (size_t i = 0; i < length; ++i) {
+        msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
+    }
+
+    // open the output pipe for writing outgoing cec message
+    mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY);
+    if (mOutputFile < 0) {
+        ALOGD("[halimp] file open failed for writing");
+        return -1;
+    }
+
+    // write message into the output pipe
+    ret = write(mOutputFile, msgBuf, length + 1);
+    close(mOutputFile);
+    if (ret < 0) {
+        ALOGE("[halimp] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
+        return -1;
+    }
+    return ret;
+}
+
+void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
+    char buf[64] = {};
+    int i, size = 0;
+    memset(buf, 0, sizeof(buf));
+    for (i = 0; i < len; i++) {
+        size += sprintf(buf + size, " %02x", msg_buf[i]);
+    }
+    ALOGD("[halimp] %s, msg:%s", __FUNCTION__, buf);
+}
+
+void HdmiCecMock::handleHotplugMessage(unsigned char* msgBuf) {
+    HotplugEvent hotplugEvent{.connected = ((msgBuf[3]) & 0xf) > 0,
+                              .portId = static_cast<uint32_t>(msgBuf[0] & 0xf)};
+
+    if (hotplugEvent.portId >= mPortInfo.size()) {
+        ALOGD("[halimp] ignore hot plug message, id %x does not exist", hotplugEvent.portId);
+        return;
+    }
+
+    ALOGD("[halimp] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf), (msgBuf[3] & 0xf));
+    if (mPortInfo[hotplugEvent.portId].type == HdmiPortType::OUTPUT) {
+        mPhysicalAddress =
+                ((hotplugEvent.connected == 0) ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
+        mPortInfo[hotplugEvent.portId].physicalAddress = mPhysicalAddress;
+        ALOGD("[halimp] hot plug physical address %x", mPhysicalAddress);
+    }
+
+    // todo update connection status
+
+    if (mCallback != nullptr) {
+        mCallback->onHotplugEvent(hotplugEvent);
+    }
+}
+
+void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int megSize) {
+    CecMessage message;
+    size_t length = std::min(static_cast<size_t>(megSize - 1),
+                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    message.body.resize(length);
+
+    for (size_t i = 0; i < length; ++i) {
+        message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
+        ALOGD("[halimp] msg body %x", message.body[i]);
+    }
+
+    message.initiator = static_cast<CecLogicalAddress>((msgBuf[0] >> 4) & 0xf);
+    ALOGD("[halimp] msg init %x", message.initiator);
+    message.destination = static_cast<CecLogicalAddress>((msgBuf[0] >> 0) & 0xf);
+    ALOGD("[halimp] msg dest %x", message.destination);
+
+    // messageValidateAndHandle(&event);
+
+    if (mCallback != nullptr) {
+        mCallback->onCecMessage(message);
+    }
+}
+
+void HdmiCecMock::threadLoop() {
+    ALOGD("[halimp] threadLoop start.");
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int r = -1;
+
+    // open the input pipe
+    while (mInputFile < 0) {
+        usleep(1000 * 1000);
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY);
+    }
+    ALOGD("[halimp] file open ok, fd = %d.", mInputFile);
+
+    while (mCecThreadRun) {
+        if (!mOptionSystemCecControl) {
+            usleep(1000 * 1000);
+            continue;
+        }
+
+        memset(msgBuf, 0, sizeof(msgBuf));
+        // try to get a message from dev.
+        // echo -n -e '\x04\x83' >> /dev/cec
+        r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
+        if (r <= 1) {
+            // ignore received ping messages
+            continue;
+        }
+
+        printCecMsgBuf((const char*)msgBuf, r);
+
+        if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+            // the message is a hotplug event
+            handleHotplugMessage(msgBuf);
+            continue;
+        }
+
+        handleCecMessage(msgBuf, r);
+    }
+
+    ALOGD("[halimp] thread end.");
+    // mCecDevice.mExited = true;
+}
+
 HdmiCecMock::HdmiCecMock() {
-    ALOGE("Opening a virtual HAL for testing and virtual machine.");
+    ALOGE("[halimp] Opening a virtual HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mPortInfo.resize(mTotalPorts);
+    mPortConnectionStatus.resize(mTotalPorts);
+    mPortInfo[0] = {.type = HdmiPortType::OUTPUT,
+                    .portId = static_cast<uint32_t>(0),
+                    .cecSupported = true,
+                    .arcSupported = false,
+                    .physicalAddress = mPhysicalAddress};
+    mPortConnectionStatus[0] = false;
 }
 
 }  // namespace implementation
diff --git a/tv/cec/1.0/default/HdmiCecMock.h b/tv/cec/1.0/default/HdmiCecMock.h
index b2f1113..0a708fa 100644
--- a/tv/cec/1.0/default/HdmiCecMock.h
+++ b/tv/cec/1.0/default/HdmiCecMock.h
@@ -49,6 +49,9 @@
 using ::android::hardware::tv::cec::V1_0::Result;
 using ::android::hardware::tv::cec::V1_0::SendMessageResult;
 
+#define CEC_MSG_IN_FIFO "/dev/cec_in_pipe"
+#define CEC_MSG_OUT_FIFO "/dev/cec_out_pipe"
+
 struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
     HdmiCecMock();
     // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
@@ -71,21 +74,43 @@
     }
 
     void cec_set_option(int flag, int value);
+    void printCecMsgBuf(const char* msg_buf, int len);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+    int readMessageFromFifo(unsigned char* buf, int msgCount);
+    int sendMessageToFifo(const CecMessage& message);
+    void handleHotplugMessage(unsigned char* msgBuf);
+    void handleCecMessage(unsigned char* msgBuf, int length);
 
   private:
     sp<IHdmiCecCallback> mCallback;
+
     // Variables for the virtual cec hal impl
     uint16_t mPhysicalAddress = 0xFFFF;
     vector<CecLogicalAddress> mLogicalAddresses;
     int32_t mCecVersion = 0;
     uint32_t mCecVendorId = 0;
+
     // Port configuration
-    int mTotalPorts = 4;
+    int mTotalPorts = 1;
+    hidl_vec<HdmiPortInfo> mPortInfo;
+    hidl_vec<bool> mPortConnectionStatus;
+
     // CEC Option value
     int mOptionWakeUp = 0;
     int mOptionEnableCec = 0;
     int mOptionSystemCecControl = 0;
     int mOptionLanguage = 0;
+
+    // Testing variables
+    // Input file descriptor
+    int mInputFile;
+    // Output file descriptor
+    int mOutputFile;
+    bool mCecThreadRun = true;
+    pthread_t mThreadId = 0;
 };
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
index b54413d..986518b 100644
--- a/tv/tuner/1.0/Android.bp
+++ b/tv/tuner/1.0/Android.bp
@@ -8,6 +8,9 @@
     },
     srcs: [
         "types.hal",
+        "IDemux.hal",
+        "IDemuxCallback.hal",
+        "IDescrambler.hal",
         "IFrontend.hal",
         "IFrontendCallback.hal",
         "ITuner.hal",
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
new file mode 100644
index 0000000..938bc44
--- /dev/null
+++ b/tv/tuner/1.0/IDemux.hal
@@ -0,0 +1,37 @@
+package android.hardware.tv.tuner@1.0;
+
+import IDemuxCallback;
+
+/**
+ * Demultiplexer(Demux) takes a single multiplexed input and splits it into
+ * one or more output.
+ *
+ */
+interface IDemux {
+
+    /**
+     * Set a frontend resource as data input of the demux
+     *
+     * It is used by the client to specify a hardware frontend as data source of
+     * this demux instance. A demux instance can have only one data source.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setFrontendDataSource(FrontendId frontendId) generates (Result result);
+
+    /**
+     * Close the Demux instance
+     *
+     * It is used by the client to release the demux instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
+
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
new file mode 100644
index 0000000..c67c5f2
--- /dev/null
+++ b/tv/tuner/1.0/IDemuxCallback.hal
@@ -0,0 +1,11 @@
+package android.hardware.tv.tuner@1.0;
+
+interface IDemuxCallback {
+    /**
+     * Notify the client that a new filter event happened.
+     *
+     * @param filterEvent a demux filter event.
+     */
+     oneway onFilterEvent(DemuxFilterEvent filterEvent);
+};
+
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
new file mode 100644
index 0000000..4d6cf3c
--- /dev/null
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -0,0 +1,35 @@
+package android.hardware.tv.tuner@1.0;
+
+/**
+ * Descrambler is used to descramble input data.
+ *
+ */
+interface IDescrambler {
+
+    /**
+     * Set a demux as source of the descrambler
+     *
+     * It is used by the client to specify a demux as source of this
+     * descrambler. A descrambler instance can have only one source, and
+     * this method can be only called once.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setDemuxSource(DemuxId demuxId) generates (Result result);
+
+    /**
+     * Release the descrambler instance
+     *
+     * It is used by the client to release the descrambler instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+     close() generates (Result result);
+};
+
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index 5a5f547..61a9d63 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -16,6 +16,8 @@
 
 package android.hardware.tv.tuner@1.0;
 
+import IDemux;
+import IDescrambler;
 import IFrontend;
 
 /**
@@ -48,5 +50,30 @@
     openFrontendById(FrontendId frontendId)
         generates (Result result, IFrontend frontend);
 
-};
+    /**
+     * Create a new instance of Demux.
+     *
+     * It is used by the client to create a Demux instance.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return demuxId newly created demux id.
+     * @return demux the newly created demux interface.
+     */
+     openDemux()
+         generates (Result result, DemuxId demuxId, IDemux demux);
 
+    /**
+     * Create a new instance of Descrambler.
+     *
+     * It is used by the client to create a Descrambler instance.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return descrambler the newly created descrambler interface.
+     */
+     openDescrambler()
+         generates (Result result, IDescrambler descrambler);
+};
diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 67ec754..6bb7aa9 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -28,6 +28,8 @@
 namespace V1_0 {
 namespace implementation {
 
+using ::android::hardware::tv::tuner::V1_0::DemuxId;
+
 Tuner::Tuner() {
     // Static Frontends array to maintain local frontends information
     // Array index matches their FrontendId in the default impl
@@ -71,6 +73,25 @@
     return Void();
 }
 
+Return<void> Tuner::openDemux(openDemux_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<IDemux> demux;
+    DemuxId demuxId = 0;
+
+    _hidl_cb(Result::SUCCESS, demuxId, demux);
+    return Void();
+}
+
+Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<IDescrambler> descrambler;
+
+    _hidl_cb(Result::SUCCESS, descrambler);
+    return Void();
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 2152c89..1ca7671 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -37,6 +37,10 @@
     virtual Return<void> openFrontendById(uint32_t frontendId,
                                           openFrontendById_cb _hidl_cb) override;
 
+    virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
+
+    virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
   private:
     virtual ~Tuner();
     // Static mFrontends array to maintain local frontends information
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 1ca7fda..3fa9641 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -137,3 +137,53 @@
      */
     LOST_LOCK,
 };
+
+/* Demux ID is used to associate with a hardware demux resource. */
+typedef uint32_t DemuxId;
+
+/* Filter ID is used to associate with a hardware filter resource. */
+typedef uint32_t DemuxFilterId;
+
+/**
+ * Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxFilterType : uint32_t {
+    /**
+     * A filter to filter section data out from input stream.
+     */
+    SECTION,
+    /**
+     * A filter to filter PES data out from input stream.
+     */
+    PES,
+    /**
+     * A filter to filter TS payload out from input stream.
+     */
+    TS,
+    /**
+     * A filter to filter Audio Metadata out from input stream.
+     */
+    AUDIO,
+    /**
+     * A filter to filter Vidoe Metadata out from input stream.
+     */
+    VIDEO,
+    /**
+     * A filter to set PCR channel from input stream.
+     */
+    PCR,
+    /**
+     * A filter to filter data directly to output buffer for record.
+     */
+    RECORD,
+};
+
+/**
+ * Filter Event.
+ */
+struct DemuxFilterEvent {
+     DemuxFilterId filterId;
+     DemuxFilterType filterType;
+};
+
diff --git a/tv/tuner/1.0/vts/OWNERS b/tv/tuner/1.0/vts/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/vts/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com