Bug 1396493 - Part1 - Convert gmp-fake to use Chromium ContentDecryptionModule8 interface. r=cpearce
authorJames Cheng <jacheng@mozilla.com>
Mon, 25 Sep 2017 17:40:22 +0800
changeset 383436 4dcf9f51015d7df4a374922634378586509aa265
parent 383435 c8631efa2592d201ecad4fe61cf3a2a42cb460aa
child 383437 2dcc72594553867e363631189577fb6140045af0
push id32594
push userkwierso@gmail.com
push dateThu, 28 Sep 2017 22:49:33 +0000
treeherdermozilla-central@6dea0ee45b66 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1396493
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1396493 - Part1 - Convert gmp-fake to use Chromium ContentDecryptionModule8 interface. r=cpearce MozReview-Commit-ID: JAGAnVuEGSE
dom/media/gmp-plugin/fake.info
dom/media/gmp-plugin/fake.voucher
dom/media/gmp-plugin/gmp-fake.cpp
dom/media/gmp-plugin/gmp-test-decryptor.cpp
dom/media/gmp-plugin/gmp-test-decryptor.h
dom/media/gmp-plugin/gmp-test-storage.cpp
dom/media/gmp-plugin/gmp-test-storage.h
dom/media/gmp-plugin/manifest.json
dom/media/gmp-plugin/moz.build
dom/media/gmp/GMPParent.cpp
deleted file mode 100644
--- a/dom/media/gmp-plugin/fake.info
+++ /dev/null
@@ -1,5 +0,0 @@
-Name: fake
-Description: Fake GMP Plugin.
-Version: 1.0
-APIs: decode-video[h264:broken], eme-decrypt-v9[fake]
-Libraries: dxva2.dll
deleted file mode 100644
--- a/dom/media/gmp-plugin/fake.voucher
+++ /dev/null
@@ -1,1 +0,0 @@
-gmp-fake placeholder voucher
\ No newline at end of file
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -28,62 +28,41 @@
  *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  *     POSSIBILITY OF SUCH DAMAGE.
  *
  *
  *************************************************************************************
  */
 
-#include <stdint.h>
-#include <cstdio>
-#include <cstring>
-#include <string>
-#include <memory>
-
-#include "gmp-platform.h"
-#include "gmp-video-decode.h"
-
-#if defined(GMP_FAKE_SUPPORT_DECRYPT)
-#include "gmp-decryption.h"
+#include "stddef.h"
+#include "content_decryption_module.h"
+#include "content_decryption_module_ext.h"
 #include "gmp-test-decryptor.h"
-#include "gmp-test-storage.h"
-#endif
-
-#if defined(_MSC_VER)
-#define PUBLIC_FUNC __declspec(dllexport)
-#else
-#define PUBLIC_FUNC
-#endif
-
-GMPPlatformAPI* g_platform_api = nullptr;
 
 extern "C" {
 
-  PUBLIC_FUNC GMPErr
-  GMPInit (GMPPlatformAPI* aPlatformAPI) {
-    g_platform_api = aPlatformAPI;
-    return GMPNoErr;
-  }
+CDM_API
+void INITIALIZE_CDM_MODULE() {
+
+}
 
-  PUBLIC_FUNC GMPErr
-  GMPGetAPI (const char* aApiName, void* aHostAPI, void** aPluginApi) {
-    if (!strcmp (aApiName, GMP_API_VIDEO_DECODER)) {
-      // Note: Deliberately advertise in our .info file that we support
-      // video-decode, but we fail the "get" call here to simulate what
-      // happens when decoder init fails.
-      return GMPGenericErr;
-#if defined(GMP_FAKE_SUPPORT_DECRYPT)
-    }
-    if (!strcmp (aApiName, GMP_API_DECRYPTOR)) {
-      *aPluginApi = new FakeDecryptor();
-      return GMPNoErr;
-#endif
-    }
-    return GMPGenericErr;
-  }
+CDM_API
+void* CreateCdmInstance(int cdm_interface_version,
+                        const char* key_system,
+                        uint32_t key_system_size,
+                        GetCdmHostFunc get_cdm_host_func,
+                        void* user_data)
+{
+  cdm::Host_8* host = static_cast<cdm::Host_8*>(
+    get_cdm_host_func(cdm_interface_version, user_data));
+  return new FakeDecryptor(host);
+}
 
-  PUBLIC_FUNC void
-  GMPShutdown (void) {
-    g_platform_api = nullptr;
-  }
+
+CDM_API
+bool
+VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles)
+{
+  return true;
+}
 
 } // extern "C"
--- a/dom/media/gmp-plugin/gmp-test-decryptor.cpp
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.cpp
@@ -2,234 +2,217 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gmp-test-decryptor.h"
 #include "gmp-test-storage.h"
 #include "gmp-test-output-protection.h"
 
+#include <mutex>
 #include <string>
 #include <vector>
 #include <iostream>
 #include <istream>
 #include <iterator>
 #include <sstream>
 #include <set>
+#include <thread>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
 using namespace std;
 
 FakeDecryptor* FakeDecryptor::sInstance = nullptr;
-extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
-
-class GMPMutexAutoLock
-{
-public:
-  explicit GMPMutexAutoLock(GMPMutex* aMutex) : mMutex(aMutex) {
-    mMutex->Acquire();
-  }
-  ~GMPMutexAutoLock() {
-    mMutex->Release();
-  }
-private:
-  GMPMutex* const mMutex;
-};
 
 class TestManager {
 public:
-  TestManager() : mMutex(CreateMutex()) {}
+  TestManager() = default;
 
   // Register a test with the test manager.
   void BeginTest(const string& aTestID) {
-    GMPMutexAutoLock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
     auto found = mTestIDs.find(aTestID);
     if (found == mTestIDs.end()) {
       mTestIDs.insert(aTestID);
     } else {
       Error("FAIL BeginTest test already existed: " + aTestID);
     }
   }
 
   // Notify the test manager that the test is finished. If all tests are done,
   // test manager will send "test-storage complete" to notify the parent that
   // all tests are finished and also delete itself.
   void EndTest(const string& aTestID) {
     bool isEmpty = false;
     {
-      GMPMutexAutoLock lock(mMutex);
+      std::lock_guard<std::mutex> lock(mMutex);
       auto found = mTestIDs.find(aTestID);
       if (found != mTestIDs.end()) {
         mTestIDs.erase(aTestID);
         isEmpty = mTestIDs.empty();
       } else {
         Error("FAIL EndTest test not existed: " + aTestID);
         return;
       }
     }
     if (isEmpty) {
       Finish();
       delete this;
     }
   }
 
 private:
-  ~TestManager() {
-    mMutex->Destroy();
-  }
+  ~TestManager() = default;
 
   static void Error(const string& msg) {
     FakeDecryptor::Message(msg);
   }
 
   static void Finish() {
     FakeDecryptor::Message("test-storage complete");
   }
 
-  static GMPMutex* CreateMutex() {
-    GMPMutex* mutex = nullptr;
-    g_platform_api->createmutex(&mutex);
-    return mutex;
-  }
-
-  GMPMutex* const mMutex;
+  std::mutex mMutex;
   set<string> mTestIDs;
 };
 
-FakeDecryptor::FakeDecryptor()
-  : mCallback(nullptr)
+FakeDecryptor::FakeDecryptor(cdm::Host_8* aHost)
+  : mHost(aHost)
 {
   MOZ_ASSERT(!sInstance);
   sInstance = this;
 }
 
-void FakeDecryptor::DecryptingComplete()
-{
-  sInstance = nullptr;
-  delete this;
-}
-
 void
 FakeDecryptor::Message(const std::string& aMessage)
 {
   MOZ_ASSERT(sInstance);
   const static std::string sid("fake-session-id");
-  sInstance->mCallback->SessionMessage(sid.c_str(), sid.size(),
-                                       kGMPLicenseRequest,
-                                       (const uint8_t*)aMessage.c_str(), aMessage.size());
+  sInstance->mHost->OnSessionMessage(sid.c_str(),
+                                     sid.size(),
+                                     cdm::MessageType::kLicenseRequest,
+                                     aMessage.c_str(),
+                                     aMessage.size(),
+                                     nullptr,
+                                     0);
 }
 
 std::vector<std::string>
 Tokenize(const std::string& aString)
 {
   std::stringstream strstr(aString);
   std::istream_iterator<std::string> it(strstr), end;
   return std::vector<std::string>(it, end);
 }
 
 static const string TruncateRecordId = "truncate-record-id";
 static const string TruncateRecordData = "I will soon be truncated";
 
-class ReadThenTask : public GMPTask {
+template<class Continuation>
+class WriteRecordSuccessTask {
 public:
-  ReadThenTask(string aId, ReadContinuation* aThen)
+  WriteRecordSuccessTask(string aId, Continuation aThen)
     : mId(aId)
-    , mThen(aThen)
+    , mThen(move(aThen))
   {}
-  void Run() override {
-    ReadRecord(mId, mThen);
+
+  void operator()()
+  {
+    ReadRecord(FakeDecryptor::sInstance->mHost, mId, mThen);
   }
-  void Destroy() override {
-    delete this;
-  }
+
   string mId;
-  ReadContinuation* mThen;
+  Continuation mThen;
 };
 
-class SendMessageTask : public GMPTask {
+class WriteRecordFailureTask {
 public:
-  explicit SendMessageTask(const string& aMessage,
-                           TestManager* aTestManager = nullptr,
-                           const string& aTestID = "")
+  explicit WriteRecordFailureTask(const string& aMessage,
+                                  TestManager* aTestManager = nullptr,
+                                  const string& aTestID = "")
     : mMessage(aMessage), mTestmanager(aTestManager), mTestID(aTestID) {}
 
-  void Run() override {
+  void operator()()
+  {
     FakeDecryptor::Message(mMessage);
     if (mTestmanager) {
       mTestmanager->EndTest(mTestID);
     }
   }
 
-  void Destroy() override {
-    delete this;
-  }
-
 private:
   string mMessage;
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
 class TestEmptyContinuation : public ReadContinuation {
 public:
   TestEmptyContinuation(TestManager* aTestManager, const string& aTestID)
     : mTestmanager(aTestManager), mTestID(aTestID) {}
 
-  void ReadComplete(GMPErr aErr, const std::string& aData) override {
-    if (!aData.empty()) {
+  virtual void operator()(bool aSuccess,
+                          const uint8_t* aData,
+                          uint32_t aDataSize) override
+  {
+    if (aDataSize) {
       FakeDecryptor::Message("FAIL TestEmptyContinuation record was not truncated");
     }
     mTestmanager->EndTest(mTestID);
-    delete this;
   }
 
 private:
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
 class TruncateContinuation : public ReadContinuation {
 public:
   TruncateContinuation(const string& aID,
                        TestManager* aTestManager,
                        const string& aTestID)
     : mID(aID), mTestmanager(aTestManager), mTestID(aTestID) {}
 
-  void ReadComplete(GMPErr aErr, const std::string& aData) override {
-    if (aData != TruncateRecordData) {
+  virtual void operator()(bool aSuccess,
+                          const uint8_t* aData,
+                          uint32_t aDataSize) override
+  {
+    if (string(reinterpret_cast<const char*>(aData), aDataSize) != TruncateRecordData) {
       FakeDecryptor::Message("FAIL TruncateContinuation read data doesn't match written data");
     }
-    auto cont = new TestEmptyContinuation(mTestmanager, mTestID);
+    auto cont = TestEmptyContinuation(mTestmanager, mTestID);
     auto msg = "FAIL in TruncateContinuation write.";
-    auto failTask = new SendMessageTask(msg, mTestmanager, mTestID);
-    WriteRecord(mID, nullptr, 0, new ReadThenTask(mID, cont), failTask);
-    delete this;
+    WriteRecord(FakeDecryptor::sInstance->mHost, mID, nullptr, 0,
+                WriteRecordSuccessTask<TestEmptyContinuation>(mID, cont),
+                WriteRecordFailureTask(msg, mTestmanager, mTestID));
   }
 
 private:
   const string mID;
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
 class VerifyAndFinishContinuation : public ReadContinuation {
 public:
   explicit VerifyAndFinishContinuation(string aValue,
                                        TestManager* aTestManager,
                                        const string& aTestID)
   : mValue(aValue), mTestmanager(aTestManager), mTestID(aTestID) {}
 
-  void ReadComplete(GMPErr aErr, const std::string& aData) override {
-    if (aData != mValue) {
+  virtual void operator()(bool aSuccess,
+                          const uint8_t* aData,
+                          uint32_t aDataSize) override
+  {
+    if (string(reinterpret_cast<const char*>(aData), aDataSize) != mValue) {
       FakeDecryptor::Message("FAIL VerifyAndFinishContinuation read data doesn't match expected data");
     }
     mTestmanager->EndTest(mTestID);
-    delete this;
   }
 
 private:
   string mValue;
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
@@ -239,242 +222,206 @@ public:
                                  TestManager* aTestManager, const string& aTestID)
     : mId(aId)
     , mValue(aValue)
     , mOverwrite(aOverwrite)
     , mTestmanager(aTestManager)
     , mTestID(aTestID)
   {}
 
-  void ReadComplete(GMPErr aErr, const std::string& aData) override {
-    if (aData != mValue) {
+  virtual void operator()(bool aSuccess,
+                          const uint8_t* aData,
+                          uint32_t aDataSize) override
+  {
+    if (string(reinterpret_cast<const char*>(aData), aDataSize) != mValue) {
       FakeDecryptor::Message("FAIL VerifyAndOverwriteContinuation read data doesn't match expected data");
     }
-    auto cont = new VerifyAndFinishContinuation(mOverwrite, mTestmanager, mTestID);
+    auto cont = VerifyAndFinishContinuation(mOverwrite, mTestmanager, mTestID);
     auto msg = "FAIL in VerifyAndOverwriteContinuation write.";
-    auto failTask = new SendMessageTask(msg, mTestmanager, mTestID);
-    WriteRecord(mId, mOverwrite, new ReadThenTask(mId, cont), failTask);
-    delete this;
+    WriteRecord(FakeDecryptor::sInstance->mHost, mId, mOverwrite,
+                WriteRecordSuccessTask<VerifyAndFinishContinuation>(mId, cont),
+                WriteRecordFailureTask(msg, mTestmanager, mTestID));
   }
 
 private:
   string mId;
   string mValue;
   string mOverwrite;
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
 static const string OpenAgainRecordId = "open-again-record-id";
 
 class OpenedSecondTimeContinuation : public OpenContinuation {
 public:
-  explicit OpenedSecondTimeContinuation(GMPRecord* aRecord,
-                                        TestManager* aTestManager,
+  explicit OpenedSecondTimeContinuation(TestManager* aTestManager,
                                         const string& aTestID)
-    : mRecord(aRecord), mTestmanager(aTestManager), mTestID(aTestID) {
-    MOZ_ASSERT(aRecord);
+    : mTestmanager(aTestManager), mTestID(aTestID)
+  {
   }
 
-  void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) override {
-    if (GMP_SUCCEEDED(aStatus)) {
+  void operator()(bool aSuccess) override {
+    if (!aSuccess) {
       FakeDecryptor::Message("FAIL OpenSecondTimeContinuation should not be able to re-open record.");
     }
-    if (aRecord) {
-      aRecord->Close();
-    }
     // Succeeded, open should have failed.
     mTestmanager->EndTest(mTestID);
-    mRecord->Close();
   }
 
 private:
-  GMPRecord* mRecord;
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
 class OpenedFirstTimeContinuation : public OpenContinuation {
 public:
   OpenedFirstTimeContinuation(const string& aID,
                               TestManager* aTestManager,
                               const string& aTestID)
     : mID(aID), mTestmanager(aTestManager), mTestID(aTestID) {}
 
-  void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) override {
-    if (GMP_FAILED(aStatus)) {
+  void operator()(bool aSuccess) override {
+    if (!aSuccess) {
       FakeDecryptor::Message("FAIL OpenAgainContinuation to open record initially.");
       mTestmanager->EndTest(mTestID);
-      if (aRecord) {
-        aRecord->Close();
-      }
       return;
     }
 
-    auto cont = new OpenedSecondTimeContinuation(aRecord, mTestmanager, mTestID);
-    GMPOpenRecord(mID, cont);
+    auto cont = OpenedSecondTimeContinuation(mTestmanager, mTestID);
+    OpenRecord(FakeDecryptor::sInstance->mHost, mID, cont);
   }
 
 private:
   const string mID;
   TestManager* const mTestmanager;
   const string mTestID;
 };
 
 static void
 DoTestStorage(const string& aPrefix, TestManager* aTestManager)
 {
+  MOZ_ASSERT(FakeDecryptor::sInstance->mHost, "FakeDecryptor::sInstance->mHost should not be null");
   // Basic I/O tests. We run three cases concurrently. The tests, like
   // GMPStorage run asynchronously. When they've all passed, we send
   // a message back to the parent process, or a failure message if not.
 
   // Test 1: Basic I/O test, and test that writing 0 bytes in a record
   // deletes record.
   //
   // Write data to truncate record, then
   // read data, verify that we read what we wrote, then
   // write 0 bytes to truncate record, then
   // read data, verify that 0 bytes was read
   const string id1 = aPrefix + TruncateRecordId;
   const string testID1 = aPrefix + "write-test-1";
   aTestManager->BeginTest(testID1);
-  auto cont1 = new TruncateContinuation(id1, aTestManager, testID1);
+  auto cont1 = TruncateContinuation(id1, aTestManager, testID1);
   auto msg1 = "FAIL in TestStorage writing TruncateRecord.";
-  auto failTask1 = new SendMessageTask(msg1, aTestManager, testID1);
-  WriteRecord(id1, TruncateRecordData,
-              new ReadThenTask(id1, cont1), failTask1);
+  WriteRecord(FakeDecryptor::sInstance->mHost, id1, TruncateRecordData,
+              WriteRecordSuccessTask<TruncateContinuation>(id1, cont1),
+              WriteRecordFailureTask(msg1, aTestManager, testID1));
 
   // Test 2: Test that overwriting a record with a shorter record truncates
   // the record to the shorter record.
   //
   // Write record, then
   // read and verify record, then
   // write a shorter record to same record.
   // read and verify
   string id2 = aPrefix + "record1";
   string record1 = "This is the first write to a record.";
   string overwrite = "A shorter record";
   const string testID2 = aPrefix + "write-test-2";
   aTestManager->BeginTest(testID2);
-  auto task2 = new VerifyAndOverwriteContinuation(id2, record1, overwrite,
-                                                  aTestManager, testID2);
+  auto task2 = VerifyAndOverwriteContinuation(id2, record1, overwrite,
+                                              aTestManager, testID2);
   auto msg2 = "FAIL in TestStorage writing record1.";
-  auto failTask2 = new SendMessageTask(msg2, aTestManager, testID2);
-  WriteRecord(id2, record1, new ReadThenTask(id2, task2), failTask2);
+  WriteRecord(FakeDecryptor::sInstance->mHost, id2, record1,
+              WriteRecordSuccessTask<VerifyAndOverwriteContinuation>(id2, task2),
+              WriteRecordFailureTask(msg2, aTestManager, testID2));
 
   // Test 3: Test that opening a record while it's already open fails.
   //
   // Open record1, then
   // open record1, should fail.
   // close record1
   const string id3 = aPrefix + OpenAgainRecordId;
   const string testID3 = aPrefix + "open-test-1";
   aTestManager->BeginTest(testID3);
-  auto task3 = new OpenedFirstTimeContinuation(id3, aTestManager, testID3);
-  GMPOpenRecord(id3, task3);
+  auto task3 = OpenedFirstTimeContinuation(id3, aTestManager, testID3);
+  OpenRecord(FakeDecryptor::sInstance->mHost, id3, task3);
 }
 
-class TestStorageTask : public GMPTask {
-public:
-  TestStorageTask(const string& aPrefix, TestManager* aTestManager)
-    : mPrefix(aPrefix), mTestManager(aTestManager) {}
-  void Destroy() override { delete this; }
-  void Run() override {
-    DoTestStorage(mPrefix, mTestManager);
-  }
-private:
-  const string mPrefix;
-  TestManager* const mTestManager;
-};
-
 void
 FakeDecryptor::TestStorage()
 {
   auto* testManager = new TestManager();
-  GMPThread* thread1 = nullptr;
-  GMPThread* thread2 = nullptr;
-
   // Main thread tests.
   DoTestStorage("mt1-", testManager);
   DoTestStorage("mt2-", testManager);
 
-  // Off-main-thread tests.
-  if (GMP_SUCCEEDED(g_platform_api->createthread(&thread1))) {
-    thread1->Post(new TestStorageTask("thread1-", testManager));
-  } else {
-    FakeDecryptor::Message("FAIL to create thread1 for storage tests");
-  }
-
-  if (GMP_SUCCEEDED(g_platform_api->createthread(&thread2))) {
-    thread2->Post(new TestStorageTask("thread2-", testManager));
-  } else {
-    FakeDecryptor::Message("FAIL to create thread2 for storage tests");
-  }
-
-  if (thread1) {
-    thread1->Join();
-  }
-
-  if (thread2) {
-    thread2->Join();
-  }
-
   // Note: Once all tests finish, TestManager will dispatch "test-pass" message,
   // which ends the test for the parent.
 }
 
-class ReportWritten : public GMPTask {
+class ReportWritten
+{
 public:
   ReportWritten(const string& aRecordId, const string& aValue)
     : mRecordId(aRecordId)
     , mValue(aValue)
   {}
-  void Run() override {
+  void operator()() {
     FakeDecryptor::Message("stored " + mRecordId + " " + mValue);
   }
-  void Destroy() override {
-    delete this;
-  }
+
   const string mRecordId;
   const string mValue;
 };
 
 class ReportReadStatusContinuation : public ReadContinuation {
 public:
   explicit ReportReadStatusContinuation(const string& aRecordId)
     : mRecordId(aRecordId)
   {}
-  void ReadComplete(GMPErr aErr, const std::string& aData) override {
-    if (GMP_FAILED(aErr)) {
+  void operator()(bool aSuccess,
+                  const uint8_t* aData,
+                  uint32_t aDataSize) override
+  {
+    if (!aSuccess) {
       FakeDecryptor::Message("retrieve " + mRecordId + " failed");
     } else {
       stringstream ss;
-      ss << aData.size();
+      ss << aDataSize;
       string len;
       ss >> len;
       FakeDecryptor::Message("retrieve " + mRecordId + " succeeded (length " +
                              len + " bytes)");
     }
-    delete this;
   }
   string mRecordId;
 };
 
 class ReportReadRecordContinuation : public ReadContinuation {
 public:
   explicit ReportReadRecordContinuation(const string& aRecordId)
     : mRecordId(aRecordId)
   {}
-  void ReadComplete(GMPErr aErr, const std::string& aData) override {
-    if (GMP_FAILED(aErr)) {
+  void operator()(bool aSuccess,
+                  const uint8_t* aData,
+                  uint32_t aDataSize) override
+  {
+    if (!aSuccess) {
       FakeDecryptor::Message("retrieved " + mRecordId + " failed");
     } else {
-      FakeDecryptor::Message("retrieved " + mRecordId + " " + aData);
+      FakeDecryptor::Message("retrieved " + mRecordId + " " +
+                             string(reinterpret_cast<const char*>(aData),
+                                    aDataSize));
     }
-    delete this;
   }
   string mRecordId;
 };
 
 enum ShutdownMode {
   ShutdownNormal,
   ShutdownTimeout,
   ShutdownStoreToken
@@ -485,39 +432,43 @@ static string sShutdownToken = "";
 
 void
 FakeDecryptor::UpdateSession(uint32_t aPromiseId,
                              const char* aSessionId,
                              uint32_t aSessionIdLength,
                              const uint8_t* aResponse,
                              uint32_t aResponseSize)
 {
+  MOZ_ASSERT(FakeDecryptor::sInstance->mHost, "FakeDecryptor::sInstance->mHost should not be null");
   std::string response((const char*)aResponse, (const char*)(aResponse)+aResponseSize);
   std::vector<std::string> tokens = Tokenize(response);
   const string& task = tokens[0];
   if (task == "test-storage") {
     TestStorage();
   } else if (task == "store") {
       // send "stored record" message on complete.
     const string& id = tokens[1];
     const string& value = tokens[2];
-    WriteRecord(id,
+    WriteRecord(FakeDecryptor::sInstance->mHost,
+                id,
                 value,
-                new ReportWritten(id, value),
-                new SendMessageTask("FAIL in writing record."));
+                ReportWritten(id, value),
+                WriteRecordFailureTask("FAIL in writing record."));
   } else if (task == "retrieve") {
     const string& id = tokens[1];
-    ReadRecord(id, new ReportReadStatusContinuation(id));
+    ReadRecord(FakeDecryptor::sInstance->mHost, id, ReportReadStatusContinuation(id));
   } else if (task == "shutdown-mode") {
     const string& mode = tokens[1];
     if (mode == "timeout") {
       sShutdownMode = ShutdownTimeout;
     } else if (mode == "token") {
       sShutdownMode = ShutdownStoreToken;
       sShutdownToken = tokens[2];
       Message("shutdown-token received " + sShutdownToken);
     }
   } else if (task == "retrieve-shutdown-token") {
-    ReadRecord("shutdown-token", new ReportReadRecordContinuation("shutdown-token"));
+    ReadRecord(FakeDecryptor::sInstance->mHost,
+               "shutdown-token",
+               ReportReadRecordContinuation("shutdown-token"));
   } else if (task == "test-op-apis") {
     mozilla::gmptest::TestOuputProtectionAPIs();
   }
 }
--- a/dom/media/gmp-plugin/gmp-test-decryptor.h
+++ b/dom/media/gmp-plugin/gmp-test-decryptor.h
@@ -1,84 +1,138 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef FAKE_DECRYPTOR_H__
 #define FAKE_DECRYPTOR_H__
 
-#include "gmp-decryption.h"
+#include "content_decryption_module.h"
 #include <string>
 #include "mozilla/Attributes.h"
 
-class FakeDecryptor : public GMPDecryptor {
+class FakeDecryptor : public cdm::ContentDecryptionModule_8 {
 public:
-
-  explicit FakeDecryptor();
+  explicit FakeDecryptor(cdm::Host_8* aHost);
 
-  void Init(GMPDecryptorCallback* aCallback,
-            bool aDistinctiveIdentifierRequired,
-            bool aPersistentStateRequired) override
+  void Initialize(bool aAllowDistinctiveIdentifier,
+                  bool aAllowPersistentState) override
   {
-    mCallback = aCallback;
   }
 
-  void CreateSession(uint32_t aCreateSessionToken,
-                     uint32_t aPromiseId,
-                     const char* aInitDataType,
-                     uint32_t aInitDataTypeSize,
-                     const uint8_t* aInitData,
-                     uint32_t aInitDataSize,
-                     GMPSessionType aSessionType) override
+  void SetServerCertificate(uint32_t aPromiseId,
+                            const uint8_t* aServerCertificateData,
+                            uint32_t aServerCertificateDataSize)
+                            override
+  {
+  }
+
+  void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
+                                       cdm::SessionType aSessionType,
+                                       cdm::InitDataType aInitDataType,
+                                       const uint8_t* aInitData,
+                                       uint32_t aInitDataSize)
+                                       override
   {
   }
 
   void LoadSession(uint32_t aPromiseId,
+                   cdm::SessionType aSessionType,
                    const char* aSessionId,
-                   uint32_t aSessionIdLength) override
+                   uint32_t aSessionIdSize) override
   {
   }
 
   void UpdateSession(uint32_t aPromiseId,
                      const char* aSessionId,
-                     uint32_t aSessionIdLength,
+                     uint32_t aSessionIdSize,
                      const uint8_t* aResponse,
                      uint32_t aResponseSize) override;
 
   void CloseSession(uint32_t aPromiseId,
                     const char* aSessionId,
-                    uint32_t aSessionIdLength) override
+                    uint32_t aSessionIdSize) override
   {
   }
 
   void RemoveSession(uint32_t aPromiseId,
                      const char* aSessionId,
-                     uint32_t aSessionIdLength) override
+                     uint32_t aSessionIdSize) override
+  {
+  }
+
+  void TimerExpired(void* aContext) override
+  {
+  }
+
+  cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
+                      cdm::DecryptedBlock* aDecryptedBuffer) override
+  {
+    return cdm::Status::kDecodeError;
+  }
+
+  cdm::Status InitializeAudioDecoder(
+    const cdm::AudioDecoderConfig& aAudioDecoderConfig) override
+  {
+    return cdm::Status::kDecodeError;
+  }
+
+  cdm::Status InitializeVideoDecoder(
+    const cdm::VideoDecoderConfig& aVideoDecoderConfig) override
+  {
+    return cdm::Status::kDecodeError;
+  }
+
+  void DeinitializeDecoder(cdm::StreamType aDecoderType) override
+  {
+  }
+
+  void ResetDecoder(cdm::StreamType aDecoderType) override
   {
   }
 
-  void SetServerCertificate(uint32_t aPromiseId,
-                            const uint8_t* aServerCert,
-                            uint32_t aServerCertSize) override
+  cdm::Status DecryptAndDecodeFrame(
+    const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::VideoFrame* aVideoFrame) override
+  {
+    return cdm::Status::kDecodeError;
+  }
+
+  cdm::Status DecryptAndDecodeSamples(
+    const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::AudioFrames* aAudioFrame) override
+  {
+    return cdm::Status::kDecodeError;
+  }
+
+  void OnPlatformChallengeResponse(
+    const cdm::PlatformChallengeResponse& aResponse) override
   {
   }
 
-  void Decrypt(GMPBuffer* aBuffer,
-               GMPEncryptedBufferMetadata* aMetadata) override
+  void OnQueryOutputProtectionStatus(cdm::QueryResult aResult,
+                                     uint32_t aLinkMask,
+                                     uint32_t aOutputProtectionMask) override
   {
   }
 
-  void DecryptingComplete() override;
+  void Destroy() override
+  {
+    delete this;
+    sInstance = nullptr;
+  }
 
   static void Message(const std::string& aMessage);
 
+  cdm::Host_8* mHost;
+
+  static FakeDecryptor* sInstance;
+
 private:
 
   virtual ~FakeDecryptor() {}
-  static FakeDecryptor* sInstance;
 
   void TestStorage();
 
-  GMPDecryptorCallback* mCallback;
 };
 
 #endif
--- a/dom/media/gmp-plugin/gmp-test-storage.cpp
+++ b/dom/media/gmp-plugin/gmp-test-storage.cpp
@@ -4,223 +4,249 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gmp-test-storage.h"
 #include <vector>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 
-class WriteRecordClient : public GMPRecordClient {
+using namespace cdm;
+using namespace std;
+
+class WriteRecordClient : public FileIOClient
+{
 public:
-  GMPErr Init(GMPRecord* aRecord,
-              GMPTask* aOnSuccess,
-              GMPTask* aOnFailure,
-              const uint8_t* aData,
-              uint32_t aDataSize) {
-    mRecord = aRecord;
-    mOnSuccess = aOnSuccess;
-    mOnFailure = aOnFailure;
+  WriteRecordClient(function<void()>&& aOnSuccess,
+                    function<void()>&& aOnFailure,
+                    const uint8_t* aData,
+                    uint32_t aDataSize)
+    : mOnSuccess(move(aOnSuccess))
+    , mOnFailure(move(aOnFailure))
+  {
     mData.insert(mData.end(), aData, aData + aDataSize);
-    return mRecord->Open();
   }
 
-  void OpenComplete(GMPErr aStatus) override {
-    if (GMP_SUCCEEDED(aStatus)) {
-      mRecord->Write(mData.empty() ? nullptr : &mData.front(), mData.size());
-    } else {
-      GMPRunOnMainThread(mOnFailure);
-      mOnSuccess->Destroy();
+  void OnOpenComplete(Status aStatus) override
+  {
+    // If we hit an error, fail.
+    if (aStatus != Status::kSuccess) {
+      Done(aStatus);
+    } else if (mFileIO) { // Otherwise, write our data to the file.
+      mFileIO->Write(mData.empty() ? nullptr : &mData.front(), mData.size());
     }
   }
 
-  void ReadComplete(GMPErr aStatus,
-                    const uint8_t* aData,
-                    uint32_t aDataSize) override {}
+  void OnReadComplete(Status aStatus,
+                      const uint8_t* aData,
+                      uint32_t aDataSize) override
+  {
+  }
+
+  void OnWriteComplete(Status aStatus) override
+  {
+    Done(aStatus);
+  }
 
-  void WriteComplete(GMPErr aStatus) override {
+  void Do(const string& aName, Host_8* aHost)
+  {
+    // Initialize the FileIO.
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
+  }
+
+private:
+  void Done(cdm::FileIOClient::Status aStatus)
+  {
     // Note: Call Close() before running continuation, in case the
     // continuation tries to open the same record; if we call Close()
     // after running the continuation, the Close() call will arrive
     // just after the Open() call succeeds, immediately closing the
     // record we just opened.
-    mRecord->Close();
-    if (GMP_SUCCEEDED(aStatus)) {
-      GMPRunOnMainThread(mOnSuccess);
-      mOnFailure->Destroy();
+    if (mFileIO) {
+      // will delete mFileIO inside Close.
+      mFileIO->Close();
+    }
+
+    if (IO_SUCCEEDED(aStatus)) {
+      mOnSuccess();
     } else {
-      GMPRunOnMainThread(mOnFailure);
-      mOnSuccess->Destroy();
+      mOnFailure();
     }
+
     delete this;
   }
 
-private:
-  GMPRecord* mRecord;
-  GMPTask* mOnSuccess;
-  GMPTask* mOnFailure;
+  FileIO* mFileIO = nullptr;
+  function<void()> mOnSuccess;
+  function<void()> mOnFailure;
   std::vector<uint8_t> mData;
 };
 
-GMPErr
-WriteRecord(const std::string& aRecordName,
+void
+WriteRecord(Host_8* aHost,
+            const std::string& aRecordName,
             const uint8_t* aData,
             uint32_t aNumBytes,
-            GMPTask* aOnSuccess,
-            GMPTask* aOnFailure)
+            function<void()>&& aOnSuccess,
+            function<void()>&& aOnFailure)
 {
-  GMPRecord* record;
-  auto* client = new WriteRecordClient();
-  auto err = GMPOpenRecord(aRecordName.c_str(),
-                           aRecordName.size(),
-                           &record,
-                           client);
-  if (GMP_FAILED(err)) {
-    GMPRunOnMainThread(aOnFailure);
-    aOnSuccess->Destroy();
-    return err;
-  }
-  return client->Init(record, aOnSuccess, aOnFailure, aData, aNumBytes);
+  // client will be delete in WriteRecordClient::Done
+  WriteRecordClient* client = new WriteRecordClient(move(aOnSuccess),
+                                                    move(aOnFailure),
+                                                    aData,
+                                                    aNumBytes);
+  client->Do(aRecordName, aHost);
 }
 
-GMPErr
-WriteRecord(const std::string& aRecordName,
+void
+WriteRecord(Host_8* aHost,
+            const std::string& aRecordName,
             const std::string& aData,
-            GMPTask* aOnSuccess,
-            GMPTask* aOnFailure)
+            function<void()> &&aOnSuccess,
+            function<void()>&& aOnFailure)
 {
-  return WriteRecord(aRecordName,
+  return WriteRecord(aHost,
+                     aRecordName,
                      (const uint8_t*)aData.c_str(),
                      aData.size(),
-                     aOnSuccess,
-                     aOnFailure);
+                     move(aOnSuccess),
+                     move(aOnFailure));
 }
 
-class ReadRecordClient : public GMPRecordClient {
+class ReadRecordClient : public FileIOClient
+{
 public:
-  GMPErr Init(GMPRecord* aRecord,
-              ReadContinuation* aContinuation) {
-    mRecord = aRecord;
-    mContinuation = aContinuation;
-    return mRecord->Open();
+  explicit ReadRecordClient(function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete)
+    : mOnReadComplete(move(aOnReadComplete))
+  {
   }
 
-  void OpenComplete(GMPErr aStatus) override {
-    auto err = mRecord->Read();
-    if (GMP_FAILED(err)) {
-      mContinuation->ReadComplete(err, "");
-      delete this;
+  void OnOpenComplete(Status aStatus) override
+  {
+    auto err = aStatus;
+    if (aStatus != Status::kSuccess) {
+      Done(err, reinterpret_cast<const uint8_t*>(""), 0);
+    } else {
+      mFileIO->Read();
     }
   }
 
-  void ReadComplete(GMPErr aStatus,
-                    const uint8_t* aData,
-                    uint32_t aDataSize) override {
+  void OnReadComplete(Status aStatus,
+                      const uint8_t* aData,
+                      uint32_t aDataSize) override
+  {
+    Done(aStatus, aData, aDataSize);
+  }
+
+  void OnWriteComplete(Status aStatus) override
+  {
+  }
+
+  void Do(const string& aName, Host_8* aHost)
+  {
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
+  }
+
+private:
+  void Done(cdm::FileIOClient::Status aStatus,
+            const uint8_t* aData,
+            uint32_t aDataSize)
+  {
     // Note: Call Close() before running continuation, in case the
     // continuation tries to open the same record; if we call Close()
     // after running the continuation, the Close() call will arrive
     // just after the Open() call succeeds, immediately closing the
     // record we just opened.
-    mRecord->Close();
-    std::string data((const char*)aData, aDataSize);
-    mContinuation->ReadComplete(GMPNoErr, data);
+    if (mFileIO) {
+      // will delete mFileIO inside Close.
+      mFileIO->Close();
+    }
+
+    if (IO_SUCCEEDED(aStatus)) {
+      mOnReadComplete(true, aData, aDataSize);
+    } else {
+      mOnReadComplete(false, reinterpret_cast<const uint8_t*>(""), 0);
+    }
+
     delete this;
   }
 
-  void WriteComplete(GMPErr aStatus) override {
+  FileIO* mFileIO = nullptr;
+  function<void(bool, const uint8_t*, uint32_t)> mOnReadComplete;
+};
+
+void
+ReadRecord(Host_8* aHost,
+           const std::string& aRecordName,
+           function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete)
+{
+  // client will be delete in ReadRecordClient::Done
+  ReadRecordClient* client = new ReadRecordClient(move(aOnReadComplete));
+  client->Do(aRecordName, aHost);
+}
+
+class OpenRecordClient : public FileIOClient
+{
+public:
+  explicit OpenRecordClient(function<void(bool)>&& aOpenComplete)
+    : mOpenComplete(move(aOpenComplete))
+  {
+  }
+
+  void OnOpenComplete(Status aStatus) override
+  {
+    Done(aStatus);
+  }
+
+  void OnReadComplete(Status aStatus,
+                      const uint8_t* aData,
+                      uint32_t aDataSize) override
+  {
+  }
+
+  void OnWriteComplete(Status aStatus) override
+  {
+  }
+
+  void Do(const string& aName, Host_8* aHost)
+  {
+    // Initialize the FileIO.
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
   }
 
 private:
-  GMPRecord* mRecord;
-  ReadContinuation* mContinuation;
-};
-
-GMPErr
-ReadRecord(const std::string& aRecordName,
-           ReadContinuation* aContinuation)
-{
-  MOZ_ASSERT(aContinuation);
-  GMPRecord* record;
-  auto* client = new ReadRecordClient();
-  auto err = GMPOpenRecord(aRecordName.c_str(),
-                           aRecordName.size(),
-                           &record,
-                           client);
-  if (GMP_FAILED(err)) {
-    return err;
-  }
-  return client->Init(record, aContinuation);
-}
-
-extern GMPPlatformAPI* g_platform_api; // Defined in gmp-fake.cpp
-
-GMPErr
-GMPOpenRecord(const char* aName,
-              uint32_t aNameLength,
-              GMPRecord** aOutRecord,
-              GMPRecordClient* aClient)
-{
-  MOZ_ASSERT(g_platform_api);
-  return g_platform_api->createrecord(aName, aNameLength, aOutRecord, aClient);
-}
-
-GMPErr
-GMPRunOnMainThread(GMPTask* aTask)
-{
-  MOZ_ASSERT(g_platform_api);
-  return g_platform_api->runonmainthread(aTask);
-}
+  void Done(cdm::FileIOClient::Status aStatus)
+  {
+    // Note: Call Close() before running continuation, in case the
+    // continuation tries to open the same record; if we call Close()
+    // after running the continuation, the Close() call will arrive
+    // just after the Open() call succeeds, immediately closing the
+    // record we just opened.
+    if (mFileIO) {
+      // will delete mFileIO inside Close.
+      mFileIO->Close();
+    }
 
-class OpenRecordClient : public GMPRecordClient {
-public:
-  /*
-   * This function will take the memory ownership of the parameters and
-   * delete them when done.
-   */
-  static void Open(const std::string& aRecordName,
-            OpenContinuation* aContinuation) {
-    MOZ_ASSERT(aContinuation);
-    (new OpenRecordClient(aContinuation))->Do(aRecordName);
-  }
-
-  void OpenComplete(GMPErr aStatus) override {
-    Done(aStatus);
-  }
+    if (IO_SUCCEEDED(aStatus)) {
+      mOpenComplete(true);
+    } else {
+      mOpenComplete(false);
+    }
 
-  void ReadComplete(GMPErr aStatus,
-                    const uint8_t* aData,
-                    uint32_t aDataSize) override {
-    MOZ_CRASH("Should not reach here.");
-  }
-
-  void WriteComplete(GMPErr aStatus) override {
-    MOZ_CRASH("Should not reach here.");
-  }
-
-private:
-  explicit OpenRecordClient(OpenContinuation* aContinuation)
-    : mRecord(nullptr), mContinuation(aContinuation) {}
-
-  void Do(const std::string& aName) {
-    auto err = GMPOpenRecord(aName.c_str(), aName.size(), &mRecord, this);
-    if (GMP_FAILED(err) ||
-        GMP_FAILED(err = mRecord->Open())) {
-      Done(err);
-    }
-  }
-
-  void Done(GMPErr err) {
-    // mContinuation is responsible for closing mRecord.
-    mContinuation->OpenComplete(err, mRecord);
-    delete mContinuation;
     delete this;
   }
 
-  GMPRecord* mRecord;
-  OpenContinuation* mContinuation;
+  FileIO* mFileIO = nullptr;
+  function<void(bool)> mOpenComplete;;
 };
 
 void
-GMPOpenRecord(const std::string& aRecordName,
-              OpenContinuation* aContinuation)
+OpenRecord(Host_8* aHost,
+           const std::string& aRecordName,
+           function<void(bool)>&& aOpenComplete)
 {
-  OpenRecordClient::Open(aRecordName, aContinuation);
+  // client will be delete in OpenRecordClient::Done
+  OpenRecordClient* client = new OpenRecordClient(move(aOpenComplete));
+  client->Do(aRecordName, aHost);
 }
--- a/dom/media/gmp-plugin/gmp-test-storage.h
+++ b/dom/media/gmp-plugin/gmp-test-storage.h
@@ -1,59 +1,54 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TEST_GMP_STORAGE_H__
 #define TEST_GMP_STORAGE_H__
 
-#include "gmp-errors.h"
-#include "gmp-platform.h"
+#include <functional>
 #include <string>
+#include <vector>
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
+
+#define IO_SUCCEEDED(x) ((x) == cdm::FileIOClient::Status::kSuccess)
+#define IO_FAILED(x) ((x) != cdm::FileIOClient::Status::kSuccess)
 
 class ReadContinuation {
 public:
   virtual ~ReadContinuation() {}
-  virtual void ReadComplete(GMPErr aErr, const std::string& aData) = 0;
+  virtual void operator()(bool aSuccess,
+                          const uint8_t* aData,
+                          uint32_t aDataSize) = 0;
 };
 
-// Reads a record to storage using GMPRecord.
-// Calls ReadContinuation with read data.
-GMPErr
-ReadRecord(const std::string& aRecordName,
-           ReadContinuation* aContinuation);
-
-// Writes a record to storage using GMPRecord.
-// Runs continuation when data is written.
-GMPErr
-WriteRecord(const std::string& aRecordName,
-            const std::string& aData,
-            GMPTask* aOnSuccess,
-            GMPTask* aOnFailure);
+void WriteRecord(cdm::Host_8* aHost,
+                 const std::string& aRecordName,
+                 const std::string& aData,
+                 std::function<void()>&& aOnSuccess,
+                 std::function<void()>&& aOnFailure);
 
-GMPErr
-WriteRecord(const std::string& aRecordName,
-            const uint8_t* aData,
-            uint32_t aNumBytes,
-            GMPTask* aOnSuccess,
-            GMPTask* aOnFailure);
+void WriteRecord(cdm::Host_8* aHost,
+                 const std::string& aRecordName,
+                 const uint8_t* aData,
+                 uint32_t aNumBytes,
+                 std::function<void()>&& aOnSuccess,
+                 std::function<void()>&& aOnFailure);
 
-GMPErr
-GMPOpenRecord(const char* aName,
-              uint32_t aNameLength,
-              GMPRecord** aOutRecord,
-              GMPRecordClient* aClient);
-
-GMPErr
-GMPRunOnMainThread(GMPTask* aTask);
+void ReadRecord(cdm::Host_8* aHost,
+                const std::string& aRecordName,
+                std::function<void(bool, const uint8_t*, uint32_t)>&& aOnReadComplete);
 
 class OpenContinuation {
 public:
   virtual ~OpenContinuation() {}
-  virtual void OpenComplete(GMPErr aStatus, GMPRecord* aRecord) = 0;
+  virtual void operator()(bool aSuccess) = 0;
 };
 
-void
-GMPOpenRecord(const std::string& aRecordName,
-              OpenContinuation* aContinuation);
-
+void OpenRecord(cdm::Host_8* aHost,
+                const std::string& aRecordName,
+                std::function<void(bool)>&& aOpenComplete);
 #endif // TEST_GMP_STORAGE_H__
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp-plugin/manifest.json
@@ -0,0 +1,9 @@
+{
+    "name": "fake",
+    "description": "Fake GMP Plugin",
+    "version": "1",
+    "x-cdm-module-versions": "4",
+    "x-cdm-interface-versions": "8",
+    "x-cdm-host-versions": "8",
+    "x-cdm-codecs": ""
+}
\ No newline at end of file
--- a/dom/media/gmp-plugin/moz.build
+++ b/dom/media/gmp-plugin/moz.build
@@ -2,27 +2,26 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 FINAL_TARGET = 'dist/bin/gmp-fake/1.0'
 
 FINAL_TARGET_FILES += [
-    'fake.info',
-    'fake.voucher',
+    'manifest.json',
 ]
 
 SOURCES += [
         'gmp-fake.cpp',
         'gmp-test-decryptor.cpp',
         'gmp-test-storage.cpp',
 ]
 
-DEFINES['GMP_FAKE_SUPPORT_DECRYPT'] = True
+DEFINES['CDM_IMPLEMENTATION'] = True
 
 SharedLibrary("fake")
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     OS_LIBS += [
         'ole32',
     ]
 
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -785,16 +785,21 @@ GMPParent::ParseChromiumManifest(const n
 #endif
   } else if (mDisplayName.EqualsASCII("WidevineCdm")) {
     kEMEKeySystem = kEMEKeySystemWidevine;
 #if XP_WIN
     // psapi.dll added for GetMappedFileNameW, which could possibly be avoided
     // in future versions, see bug 1383611 for details.
     mLibs = NS_LITERAL_CSTRING("dxva2.dll, psapi.dll");
 #endif
+  } else if (mDisplayName.EqualsASCII("fake")) {
+    kEMEKeySystem = NS_LITERAL_CSTRING("fake");
+#if XP_WIN
+    mLibs = NS_LITERAL_CSTRING("dxva2.dll");
+#endif
   } else {
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   GMPCapability video;
 
   nsCString codecsString = NS_ConvertUTF16toUTF8(m.mX_cdm_codecs);
   nsTArray<nsCString> codecs;