IDrmClient: remove Parcel from interface

This is part of the effort to remove binder-related classes from libmediadrm.
This change replaces a generic listener for Parcel data with separate
listeners for each event type.

Bug: 134787536
Test: MediaDrmClearkeyTest
Test: NativeMediaDrmClearkeyTest
Test: MediaDrmMockTest
Change-Id: I90cbb75b21cc63737994a01a2171caee5cfb84ad
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 8a08a7b..40077f9 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -39,6 +39,8 @@
 #include <mediadrm/DrmSessionClientInterface.h>
 #include <mediadrm/DrmSessionManager.h>
 
+#include <vector>
+
 using drm::V1_0::KeyedVector;
 using drm::V1_0::KeyRequestType;
 using drm::V1_0::KeyType;
@@ -496,10 +498,6 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        writeByteArray(obj, data);
-
         Mutex::Autolock lock(mNotifyLock);
         DrmPlugin::EventType eventType;
         switch(hEventType) {
@@ -521,7 +519,7 @@
         default:
             return Void();
         }
-        listener->notify(eventType, 0, &obj);
+        listener->sendEvent(eventType, sessionId, data);
     }
     return Void();
 }
@@ -534,12 +532,8 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        obj.writeInt64(expiryTimeInMS);
-
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+        listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
     }
     return Void();
 }
@@ -556,21 +550,17 @@
 }
 
 Return<void> DrmHal::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
-        const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+        const hidl_vec<KeyStatus>& hKeyStatusList, bool hasNewUsableKey) {
 
     mEventLock.lock();
     sp<IDrmClient> listener = mListener;
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-
-        size_t nKeys = keyStatusList.size();
-        obj.writeInt32(nKeys);
+        std::vector<DrmKeyStatus> keyStatusList;
+        size_t nKeys = hKeyStatusList.size();
         for (size_t i = 0; i < nKeys; ++i) {
-            const KeyStatus &keyStatus = keyStatusList[i];
-            writeByteArray(obj, keyStatus.keyId);
+            const KeyStatus &keyStatus = hKeyStatusList[i];
             uint32_t type;
             switch(keyStatus.type) {
             case KeyStatusType::USABLE:
@@ -593,19 +583,18 @@
                 type = DrmPlugin::kKeyStatusType_InternalError;
                 break;
             }
-            obj.writeInt32(type);
+            keyStatusList.push_back({type, keyStatus.keyId});
             mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
         }
-        obj.writeInt32(hasNewUsableKey);
 
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+        listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
     } else {
         // There's no listener. But we still want to count the key change
         // events.
-        size_t nKeys = keyStatusList.size();
+        size_t nKeys = hKeyStatusList.size();
         for (size_t i = 0; i < nKeys; i++) {
-            mMetrics.mKeyStatusChangeCounter.Increment(keyStatusList[i].type);
+            mMetrics.mKeyStatusChangeCounter.Increment(hKeyStatusList[i].type);
         }
     }
 
@@ -620,10 +609,8 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
+        listener->sendSessionLostState(sessionId);
     }
     return Void();
 }
@@ -1585,16 +1572,6 @@
     cleanup();
 }
 
-void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
-{
-    if (vec.size()) {
-        obj.writeInt32(vec.size());
-        obj.write(vec.data(), vec.size());
-    } else {
-        obj.writeInt32(0);
-    }
-}
-
 void DrmHal::reportFrameworkMetrics() const
 {
     std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
diff --git a/drm/libmediadrm/IDrmClient.cpp b/drm/libmediadrm/IDrmClient.cpp
index 357de9d..2e05093 100644
--- a/drm/libmediadrm/IDrmClient.cpp
+++ b/drm/libmediadrm/IDrmClient.cpp
@@ -17,39 +17,104 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "IDrmClient"
-#include <utils/Log.h>
 
+#include <utils/Errors.h>
+#include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
+#include <hidl/HidlSupport.h>
 
 #include <media/IMediaPlayerClient.h>
+#include <mediadrm/DrmUtils.h>
 #include <mediadrm/IDrmClient.h>
 
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
 namespace android {
 
 enum {
-    NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+    SEND_EVENT = IBinder::FIRST_CALL_TRANSACTION,
+    SEND_EXPIRATION_UPDATE,
+    SEND_KEYS_CHANGE,
+    SEND_SESSION_LOST_STATE,
 };
 
+namespace {
+
+hardware::hidl_vec<uint8_t> ReadByteArray(const Parcel &obj, status_t *err)
+{
+    int32_t len = obj.readInt32();
+    hardware::hidl_vec<uint8_t> ret;
+    if (len < 0) {
+        ALOGE("Invalid array len");
+        *err = BAD_VALUE;
+        return ret;
+    }
+    ret.resize(static_cast<size_t>(len));
+    *err = obj.read(ret.data(), ret.size());
+    return ret;
+}
+
+}
+
 class BpDrmClient: public BpInterface<IDrmClient>
 {
+    template <typename F>
+    void notify(uint32_t code, F fillParcel) {
+        Parcel obj, reply;
+        obj.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
+        fillParcel(obj);
+        remote()->transact(code, obj, &reply, IBinder::FLAG_ONEWAY);
+    }
+
 public:
     explicit BpDrmClient(const sp<IBinder>& impl)
         : BpInterface<IDrmClient>(impl)
     {
     }
 
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj)
+    virtual void sendEvent(
+            DrmPlugin::EventType eventType,
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const hardware::hidl_vec<uint8_t> &data)
     {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
-        data.writeInt32((int)eventType);
-        data.writeInt32(extra);
-        if (obj && obj->dataSize() > 0) {
-            data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
-        }
-        remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteEventToParcel(p, eventType, sessionId, data);
+        };
+        notify(SEND_EVENT, fillParcel);
+    }
+
+    virtual void sendExpirationUpdate(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            int64_t expiryTimeInMS)
+    {
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteExpirationUpdateToParcel(p, sessionId, expiryTimeInMS);
+        };
+        notify(SEND_EXPIRATION_UPDATE, fillParcel);
+    }
+
+    virtual void sendKeysChange(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const std::vector<DrmKeyStatus> &keyStatusList,
+            bool hasNewUsableKey)
+    {
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteKeysChange(p, sessionId, keyStatusList, hasNewUsableKey);
+        };
+        notify(SEND_KEYS_CHANGE, fillParcel);
+    }
+
+    virtual void sendSessionLostState(
+            const hardware::hidl_vec<uint8_t> &sessionId)
+    {
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteByteArray(p, sessionId);
+        };
+        notify(SEND_SESSION_LOST_STATE, fillParcel);
     }
 };
 
@@ -58,23 +123,58 @@
 // ----------------------------------------------------------------------
 
 status_t BnDrmClient::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+    uint32_t code, const Parcel& obj, Parcel* reply, uint32_t flags)
 {
-    switch (code) {
-        case NOTIFY: {
-            CHECK_INTERFACE(IDrmClient, data, reply);
-            int eventType = data.readInt32();
-            int extra = data.readInt32();
-            Parcel obj;
-            if (data.dataAvail() > 0) {
-                obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
-            }
+    CHECK_INTERFACE(IDrmClient, obj, reply);
+    status_t err = NO_ERROR;
+    hardware::hidl_vec<uint8_t> sessionId(ReadByteArray(obj, &err));
+    if (err != NO_ERROR) {
+        ALOGE("Failed to read session id, error=%d", err);
+        return err;
+    }
 
-            notify((DrmPlugin::EventType)eventType, extra, &obj);
+    switch (code) {
+        case SEND_EVENT: {
+            hardware::hidl_vec<uint8_t> data(ReadByteArray(obj, &err));
+            int eventType = obj.readInt32();
+            if (err == NO_ERROR) {
+                sendEvent(static_cast<DrmPlugin::EventType>(eventType), sessionId, data);
+            }
+            return err;
+        } break;
+        case SEND_EXPIRATION_UPDATE: {
+            int64_t expiryTimeInMS = obj.readInt64();
+            sendExpirationUpdate(sessionId, expiryTimeInMS);
+            return NO_ERROR;
+        } break;
+        case SEND_KEYS_CHANGE: {
+            // ...
+            int32_t n = obj.readInt32();
+            if (n < 0) {
+                return BAD_VALUE;
+            }
+            std::vector<DrmKeyStatus> keyStatusList;
+            for (int32_t i = 0; i < n; ++i) {
+                hardware::hidl_vec<uint8_t> keyId(ReadByteArray(obj, &err));
+                if (err != NO_ERROR) {
+                    return err;
+                }
+                int32_t type = obj.readInt32();
+                if (type < 0) {
+                    return BAD_VALUE;
+                }
+                keyStatusList.push_back({static_cast<uint32_t>(type), keyId});
+            }
+            int32_t hasNewUsableKey = obj.readInt32();
+            sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+            return NO_ERROR;
+        } break;
+        case SEND_SESSION_LOST_STATE: {
+            sendSessionLostState(sessionId);
             return NO_ERROR;
         } break;
         default:
-            return BBinder::onTransact(code, data, reply, flags);
+            return BBinder::onTransact(code, obj, reply, flags);
     }
 }
 
diff --git a/drm/libmediadrm/include/mediadrm/IDrmClient.h b/drm/libmediadrm/include/mediadrm/IDrmClient.h
index 3b2fc7c..f8f2b25 100644
--- a/drm/libmediadrm/include/mediadrm/IDrmClient.h
+++ b/drm/libmediadrm/include/mediadrm/IDrmClient.h
@@ -22,14 +22,41 @@
 #include <binder/Parcel.h>
 #include <media/drm/DrmAPI.h>
 
+#include <android/hardware/drm/1.2/types.h>
+#include <hidl/HidlSupport.h>
+
+#include <cstdint>
+#include <vector>
+
 namespace android {
 
+struct DrmKeyStatus {
+    const uint32_t type;
+    const hardware::hidl_vec<uint8_t> keyId;
+};
+
 class IDrmClient: public IInterface
 {
 public:
     DECLARE_META_INTERFACE(DrmClient);
 
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) = 0;
+    virtual void sendEvent(
+            DrmPlugin::EventType eventType,
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const hardware::hidl_vec<uint8_t> &data) = 0;
+
+    virtual void sendExpirationUpdate(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            int64_t expiryTimeInMS) = 0;
+
+    virtual void sendKeysChange(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const std::vector<DrmKeyStatus> &keyStatusList,
+            bool hasNewUsableKey) = 0;
+
+    virtual void sendSessionLostState(
+            const hardware::hidl_vec<uint8_t> &sessionId) = 0;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index 2cd3e6d..a5bc09b 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -19,6 +19,7 @@
 
 #include <utils/Errors.h>  // for status_t
 #include <utils/StrongPointer.h>
+#include <binder/Parcel.h>
 
 namespace android {
 
@@ -33,6 +34,49 @@
 
 sp<ICrypto> MakeCrypto(status_t *pstatus = nullptr);
 
+template<typename BA>
+void WriteByteArray(Parcel &obj, const BA &vec) {
+    obj.writeInt32(vec.size());
+    if (vec.size()) {
+        obj.write(vec.data(), vec.size());
+    }
+}
+
+template<typename ET, typename BA>
+void WriteEventToParcel(
+        Parcel &obj,
+        ET eventType,
+        const BA &sessionId,
+        const BA &data) {
+    WriteByteArray(obj, sessionId);
+    WriteByteArray(obj, data);
+    obj.writeInt32(eventType);
+}
+
+template<typename BA>
+void WriteExpirationUpdateToParcel(
+        Parcel &obj,
+        const BA &sessionId,
+        int64_t expiryTimeInMS) {
+    WriteByteArray(obj, sessionId);
+    obj.writeInt64(expiryTimeInMS);
+}
+
+template<typename BA, typename KSL>
+void WriteKeysChange(
+        Parcel &obj,
+        const BA &sessionId,
+        const KSL &keyStatusList,
+        bool hasNewUsableKey) {
+    WriteByteArray(obj, sessionId);
+    obj.writeInt32(keyStatusList.size());
+    for (const auto &keyStatus : keyStatusList) {
+        WriteByteArray(obj, keyStatus.keyId);
+        obj.writeInt32(keyStatus.type);
+    }
+    obj.writeInt32(hasNewUsableKey);
+}
+
 } // namespace DrmUtils
 
 } // namespace android