Bug 959089 - Part 1: Implement a new protocol for manage shared buffers' allocation. r=vlad, r=gal
☠☠ backed out by 664f112264f4 ☠ ☠
authorchiajung hung <chung@mozilla.com>
Fri, 25 Apr 2014 02:28:00 -0400
changeset 198670 1a6ada013610f7e1983dbad1ed9b662d7e0e158a
parent 198669 4ca96570171c7e0f7fc3a458e51c7c290e889d9d
child 198671 d58403b60c77b4d8e22a9db47dc863d43381f5aa
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad, gal
bugs959089
milestone31.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 959089 - Part 1: Implement a new protocol for manage shared buffers' allocation. r=vlad, r=gal
gfx/layers/ipc/PSharedBufferManager.ipdl
gfx/layers/ipc/SharedBufferManagerChild.cpp
gfx/layers/ipc/SharedBufferManagerChild.h
gfx/layers/ipc/SharedBufferManagerParent.cpp
gfx/layers/ipc/SharedBufferManagerParent.h
gfx/thebes/gfxPlatform.cpp
hal/sandbox/PHal.ipdl
ipc/chromium/src/chrome/common/file_descriptor_set_posix.h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/PSharedBufferManager.ipdl
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 LayersSurfaces;
+include ProtocolTypes;
+
+include "mozilla/GfxMessageUtils.h";
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * This is a dedicated protocol to track/allocate/deallocate gralloc buffers.
+ */
+
+sync protocol PSharedBufferManager {
+parent:
+  sync AllocateGrallocBuffer(IntSize size, uint32_t format, uint32_t usage)
+   returns (MaybeMagicGrallocBufferHandle handle);
+both:
+  async DropGrallocBuffer(MaybeMagicGrallocBufferHandle handle);
+};
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -0,0 +1,338 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 "base/task.h"                  // for NewRunnableFunction, etc
+#include "base/thread.h"                // for Thread
+#include "base/tracked.h"               // for FROM_HERE
+#include "mozilla/layers/SharedBufferManagerChild.h"
+#include "mozilla/layers/SharedBufferManagerParent.h"
+#include "mozilla/StaticPtr.h"          // for StaticRefPtr
+#include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
+
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
+#ifdef MOZ_WIDGET_GONK
+#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "SBMChild", ## args)
+#endif
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+// Singleton
+SharedBufferManagerChild* SharedBufferManagerChild::sSharedBufferManagerChildSingleton = nullptr;
+SharedBufferManagerParent* SharedBufferManagerChild::sSharedBufferManagerParentSingleton = nullptr;
+base::Thread* SharedBufferManagerChild::sSharedBufferManagerChildThread = nullptr;
+
+SharedBufferManagerChild::SharedBufferManagerChild()
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  : mBufferMutex("BufferMonitor")
+#endif
+{
+
+}
+
+static bool
+InSharedBufferManagerChildThread()
+{
+  return SharedBufferManagerChild::sSharedBufferManagerChildThread->thread_id() == PlatformThread::CurrentId();
+}
+
+// dispatched function
+static void
+DeleteSharedBufferManagerSync(ReentrantMonitor *aBarrier, bool *aDone)
+{
+  ReentrantMonitorAutoEnter autoMon(*aBarrier);
+
+  NS_ABORT_IF_FALSE(InSharedBufferManagerChildThread(),
+                    "Should be in SharedBufferManagerChild thread.");
+  SharedBufferManagerChild::sSharedBufferManagerChildSingleton = nullptr;
+  SharedBufferManagerChild::sSharedBufferManagerParentSingleton = nullptr;
+  *aDone = true;
+  aBarrier->NotifyAll();
+}
+
+// dispatched function
+static void
+ConnectSharedBufferManager(SharedBufferManagerChild *child, SharedBufferManagerParent *parent)
+{
+  MessageLoop *parentMsgLoop = parent->GetMessageLoop();
+  ipc::MessageChannel *parentChannel = parent->GetIPCChannel();
+  child->Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
+}
+
+base::Thread*
+SharedBufferManagerChild::GetThread() const
+{
+  return sSharedBufferManagerChildThread;
+}
+
+SharedBufferManagerChild*
+SharedBufferManagerChild::GetSingleton()
+{
+  return sSharedBufferManagerChildSingleton;
+}
+
+bool
+SharedBufferManagerChild::IsCreated()
+{
+  return GetSingleton() != nullptr;
+}
+
+void
+SharedBufferManagerChild::StartUp()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+  SharedBufferManagerChild::StartUpOnThread(new base::Thread("BufferMgrChild"));
+}
+
+static void
+ConnectSharedBufferManagerInChildProcess(mozilla::ipc::Transport* aTransport,
+                                         base::ProcessHandle aOtherProcess)
+{
+  // Bind the IPC channel to the shared buffer manager thread.
+  SharedBufferManagerChild::sSharedBufferManagerChildSingleton->Open(aTransport, aOtherProcess,
+                                                                     XRE_GetIOMessageLoop(),
+                                                                     ipc::ChildSide);
+
+#ifdef MOZ_NUWA_PROCESS
+  if (IsNuwaProcess()) {
+    SharedBufferManagerChild::sSharedBufferManagerChildThread
+      ->message_loop()->PostTask(FROM_HERE,
+                                 NewRunnableFunction(NuwaMarkCurrentThread,
+                                                     (void (*)(void *))nullptr,
+                                                     (void *)nullptr));
+  }
+#endif
+}
+
+PSharedBufferManagerChild*
+SharedBufferManagerChild::StartUpInChildProcess(Transport* aTransport,
+                                                base::ProcessId aOtherProcess)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+
+  ProcessHandle processHandle;
+  if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
+    return nullptr;
+  }
+
+  sSharedBufferManagerChildThread = new base::Thread("BufferMgrChild");
+  if (!sSharedBufferManagerChildThread->Start()) {
+    return nullptr;
+  }
+
+  sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
+  sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableFunction(ConnectSharedBufferManagerInChildProcess,
+                        aTransport, processHandle));
+
+  return sSharedBufferManagerChildSingleton;
+}
+
+void
+SharedBufferManagerChild::ShutDown()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+  if (IsCreated()) {
+    SharedBufferManagerChild::DestroyManager();
+    delete sSharedBufferManagerChildThread;
+    sSharedBufferManagerChildThread = nullptr;
+  }
+}
+
+bool
+SharedBufferManagerChild::StartUpOnThread(base::Thread* aThread)
+{
+  NS_ABORT_IF_FALSE(aThread, "SharedBufferManager needs a thread.");
+  if (sSharedBufferManagerChildSingleton != nullptr)
+    return false;
+
+  sSharedBufferManagerChildThread = aThread;
+  if (!aThread->IsRunning()) {
+    aThread->Start();
+  }
+  sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
+  char thrname[128];
+  base::snprintf(thrname, 128, "BufMgrParent#%d", base::Process::Current().pid());
+  sSharedBufferManagerParentSingleton = new SharedBufferManagerParent(
+    nullptr, base::Process::Current().pid(), new base::Thread(thrname));
+  sSharedBufferManagerChildSingleton->ConnectAsync(sSharedBufferManagerParentSingleton);
+  return true;
+}
+
+void
+SharedBufferManagerChild::DestroyManager()
+{
+  NS_ABORT_IF_FALSE(!InSharedBufferManagerChildThread(),
+                    "This method must not be called in this thread.");
+  // ...because we are about to dispatch synchronous messages to the
+  // BufferManagerChild thread.
+
+  if (!IsCreated()) {
+    return;
+  }
+
+  ReentrantMonitor barrier("BufferManagerDestroyTask lock");
+  ReentrantMonitorAutoEnter autoMon(barrier);
+
+  bool done = false;
+  sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask(FROM_HERE,
+    NewRunnableFunction(&DeleteSharedBufferManagerSync, &barrier, &done));
+  while (!done) {
+    barrier.Wait();
+  }
+
+}
+
+MessageLoop *
+SharedBufferManagerChild::GetMessageLoop() const
+{
+  return sSharedBufferManagerChildThread != nullptr ?
+      sSharedBufferManagerChildThread->message_loop() :
+      nullptr;
+}
+
+void
+SharedBufferManagerChild::ConnectAsync(SharedBufferManagerParent* aParent)
+{
+  GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectSharedBufferManager,
+                                                            this, aParent));
+}
+
+// dispatched function
+void
+SharedBufferManagerChild::AllocGrallocBufferSync(const GrallocParam& aParam,
+                                                 Monitor* aBarrier,
+                                                 bool* aDone)
+{
+  MonitorAutoLock autoMon(*aBarrier);
+
+  sSharedBufferManagerChildSingleton->AllocGrallocBufferNow(aParam.size,
+                                                            aParam.format,
+                                                            aParam.usage,
+                                                            aParam.buffer);
+  *aDone = true;
+  aBarrier->NotifyAll();
+}
+
+// dispatched function
+void
+SharedBufferManagerChild::DeallocGrallocBufferSync(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer)
+{
+  SharedBufferManagerChild::sSharedBufferManagerChildSingleton->
+    DeallocGrallocBufferNow(aBuffer);
+}
+
+bool
+SharedBufferManagerChild::AllocGrallocBuffer(const gfx::IntSize& aSize,
+                                             const uint32_t& aFormat,
+                                             const uint32_t& aUsage,
+                                             mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer)
+{
+  if (InSharedBufferManagerChildThread()) {
+    return SharedBufferManagerChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aBuffer);
+  }
+
+  Monitor barrier("AllocSurfaceDescriptorGralloc Lock");
+  MonitorAutoLock autoMon(barrier);
+  bool done = false;
+
+  GetMessageLoop()->PostTask(
+    FROM_HERE,
+    NewRunnableFunction(&AllocGrallocBufferSync,
+                        GrallocParam(aSize, aFormat, aUsage, aBuffer), &barrier, &done));
+
+  while (!done) {
+    barrier.Wait();
+  }
+  return true;
+}
+
+bool
+SharedBufferManagerChild::AllocGrallocBufferNow(const IntSize& aSize,
+                                                const uint32_t& aFormat,
+                                                const uint32_t& aUsage,
+                                                mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  mozilla::layers::MaybeMagicGrallocBufferHandle handle;
+  SendAllocateGrallocBuffer(aSize, aFormat, aUsage, &handle);
+  if (handle.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle)
+    return false;
+  *aHandle = handle.get_MagicGrallocBufferHandle().mRef;
+
+  {
+    MutexAutoLock lock(mBufferMutex);
+    mBuffers[handle.get_MagicGrallocBufferHandle().mRef.mKey] = handle.get_MagicGrallocBufferHandle().mGraphicBuffer;
+  }
+  return true;
+#else
+  NS_RUNTIMEABORT("No GrallocBuffer for you");
+  return true;
+#endif
+}
+
+void
+SharedBufferManagerChild::DeallocGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer)
+{
+  if (InSharedBufferManagerChildThread()) {
+    return SharedBufferManagerChild::DeallocGrallocBufferNow(aBuffer);
+  }
+
+  GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeallocGrallocBufferSync,
+                                                            aBuffer));
+}
+
+void
+SharedBufferManagerChild::DeallocGrallocBufferNow(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  NS_ASSERTION(aBuffer.type() == mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle, "We shouldn't trying to do IPC with real buffer");
+
+  {
+    MutexAutoLock lock(mBufferMutex);
+    mBuffers.erase(aBuffer.get_GrallocBufferRef().mKey);
+  }
+  SendDropGrallocBuffer(aBuffer);
+#else
+  NS_RUNTIMEABORT("No GrallocBuffer for you");
+#endif
+}
+
+bool SharedBufferManagerChild::RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  NS_ASSERTION(handle.type() == mozilla::layers::MaybeMagicGrallocBufferHandle::TGrallocBufferRef, "shouldn't go this way");
+  int bufferKey = handle.get_GrallocBufferRef().mKey;
+
+  {
+    MutexAutoLock lock(mBufferMutex);
+    NS_ASSERTION(mBuffers.indexOfKey(bufferKey) >= 0, "Not my buffer");
+    mBuffers.erase(bufferKey);
+  }
+#endif
+  return true;
+}
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+android::sp<android::GraphicBuffer>
+SharedBufferManagerChild::GetGraphicBuffer(int key)
+{
+  MutexAutoLock lock(mBufferMutex);
+  if (mBuffers.count(key) == 0)
+    return nullptr;
+  return mBuffers[key];
+}
+#endif
+
+} /* namespace layers */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/SharedBufferManagerChild.h
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* 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 SharedBufferManagerCHILD_H_
+#define SharedBufferManagerCHILD_H_
+
+#include "mozilla/layers/PSharedBufferManagerChild.h"
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+#include "mozilla/Mutex.h"
+#endif
+
+namespace base {
+class Thread;
+}
+
+namespace mozilla {
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+class Mutex;
+#endif
+
+namespace layers {
+class SharedBufferManagerParent;
+
+struct GrallocParam {
+  gfx::IntSize size;
+  uint32_t format;
+  uint32_t usage;
+  mozilla::layers::MaybeMagicGrallocBufferHandle* buffer;
+
+  GrallocParam(const gfx::IntSize& aSize,
+               const uint32_t& aFormat,
+               const uint32_t& aUsage,
+               mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer)
+    : size(aSize)
+    , format(aFormat)
+    , usage(aUsage)
+    , buffer(aBuffer)
+  {}
+};
+
+class SharedBufferManagerChild : public PSharedBufferManagerChild {
+public:
+  SharedBufferManagerChild();
+  /**
+   * Creates the gralloc buffer manager with a dedicated thread for SharedBufferManagerChild.
+   *
+   * We may want to use a specific thread in the future. In this case, use
+   * CreateWithThread instead.
+   */
+  static void StartUp();
+
+  static PSharedBufferManagerChild*
+  StartUpInChildProcess(Transport* aTransport, ProcessId aOtherProcess);
+
+  /**
+   * Creates the SharedBufferManagerChild manager protocol.
+   */
+  static bool StartUpOnThread(base::Thread* aThread);
+
+  /**
+   * Destroys The SharedBufferManager protocol.
+   *
+   * The actual destruction happens synchronously on the SharedBufferManagerChild thread
+   * which means that if this function is called from another thread, the current
+   * thread will be paused until the destruction is done.
+   */
+  static void DestroyManager();
+
+  /**
+   * Destroys the grallob buffer manager calling DestroyManager, and destroys the
+   * SharedBufferManager's thread.
+   *
+   * If you don't want to destroy the thread, call DestroyManager directly
+   * instead.
+   */
+  static void ShutDown();
+
+  /**
+   * returns the singleton instance.
+   *
+   * can be called from any thread.
+   */
+  static SharedBufferManagerChild* GetSingleton();
+
+  /**
+   * Dispatches a task to the SharedBufferManagerChild thread to do the connection
+   */
+  void ConnectAsync(SharedBufferManagerParent* aParent);
+
+  /**
+   * Allocate GrallocBuffer remotely.
+  */
+  bool
+  AllocGrallocBuffer(const gfx::IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*);
+
+  /**
+   * Deallocate a remotely allocated gralloc buffer.
+   * As gralloc buffer life cycle controlled by sp, this just break the sharing status of the underlying buffer
+   * and decrease the reference count on both side.
+   */
+  void
+  DeallocGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aBuffer);
+
+  virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  android::sp<android::GraphicBuffer> GetGraphicBuffer(int index);
+#endif
+
+  base::Thread* GetThread() const;
+
+  MessageLoop* GetMessageLoop() const;
+
+  static bool IsCreated();
+
+  static base::Thread* sSharedBufferManagerChildThread;
+  static SharedBufferManagerChild* sSharedBufferManagerChildSingleton;
+  static SharedBufferManagerParent* sSharedBufferManagerParentSingleton; // Only available in Chrome process
+
+protected:
+  /**
+   * Part of the allocation of gralloc SurfaceDescriptor that is
+   * executed on the SharedBufferManagerChild thread after invoking
+   * AllocSurfaceDescriptorGralloc.
+   *
+   * Must be called from the SharedBufferManagerChild thread.
+   */
+  bool
+  AllocGrallocBufferNow(const gfx::IntSize& aSize,
+                        const uint32_t& aFormat,
+                        const uint32_t& aUsage,
+                        mozilla::layers::MaybeMagicGrallocBufferHandle* aBuffer);
+
+  // Dispatched function
+  static void
+  AllocGrallocBufferSync(const GrallocParam& aParam,
+                         Monitor* aBarrier,
+                         bool* aDone);
+
+  /**
+   * Part of the deallocation of gralloc SurfaceDescriptor that is
+   * executed on the SharedBufferManagerChild thread after invoking
+   * DeallocSurfaceDescriptorGralloc.
+   *
+   * Must be called from the SharedBufferManagerChild thread.
+   */
+  void
+  DeallocGrallocBufferNow(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
+
+  // dispatched function
+  static void
+  DeallocGrallocBufferSync(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  std::map<int, android::sp<android::GraphicBuffer> > mBuffers;
+  Mutex mBufferMutex;
+#endif
+};
+
+} /* namespace layers */
+} /* namespace mozilla */
+#endif /* SharedBufferManagerCHILD_H_*/
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/SharedBufferManagerParent.cpp
@@ -0,0 +1,279 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* 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 "mozilla/layers/SharedBufferManagerParent.h"
+#include "base/message_loop.h"          // for MessageLoop
+#include "base/process.h"               // for ProcessHandle
+#include "base/process_util.h"          // for OpenProcessHandle
+#include "base/task.h"                  // for CancelableTask, DeleteTask, etc
+#include "base/tracked.h"               // for FROM_HERE
+#include "base/thread.h"
+#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/Transport.h"      // for Transport
+#include "nsIMemoryReporter.h"
+#ifdef MOZ_WIDGET_GONK
+#include "ui/PixelFormat.h"
+#endif
+#include "nsThreadUtils.h"
+
+using namespace mozilla::ipc;
+#ifdef MOZ_WIDGET_GONK
+using android::sp;
+using android::GraphicBuffer;
+#endif
+using std::map;
+
+namespace mozilla {
+namespace layers {
+
+class GrallocReporter MOZ_FINAL : public nsIMemoryReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  GrallocReporter()
+  {
+#ifdef DEBUG
+    // There must be only one instance of this class, due to |sAmount|
+    // being static.  Assert this.
+    static bool hasRun = false;
+    MOZ_ASSERT(!hasRun);
+    hasRun = true;
+#endif
+  }
+
+  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
+                            nsISupports* aData)
+  {
+    return MOZ_COLLECT_REPORT(
+      "gralloc", KIND_OTHER, UNITS_BYTES, sAmount,
+"Special RAM that can be shared between processes and directly accessed by "
+"both the CPU and GPU. Gralloc memory is usually a relatively precious "
+"resource, with much less available than generic RAM. When it's exhausted, "
+"graphics performance can suffer. This value can be incorrect because of race "
+"conditions.");
+  }
+
+  static int64_t sAmount;
+};
+
+NS_IMPL_ISUPPORTS1(GrallocReporter, nsIMemoryReporter)
+
+int64_t GrallocReporter::sAmount = 0;
+
+void InitGralloc() {
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  RegisterStrongMemoryReporter(new GrallocReporter());
+}
+
+map<base::ProcessId, SharedBufferManagerParent* > SharedBufferManagerParent::sManagers;
+Monitor SharedBufferManagerParent::sManagerMonitor("Manager Monitor");
+int SharedBufferManagerParent::sBufferKey = 0;
+
+SharedBufferManagerParent::SharedBufferManagerParent(Transport* aTransport, base::ProcessId aOwner, base::Thread* aThread)
+  : mTransport(aTransport)
+  , mThread(aThread)
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  , mBuffersMutex("BuffersMonitor")
+#endif
+{
+  MonitorAutoLock lock(sManagerMonitor);
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
+  if (!aThread->IsRunning())
+    aThread->Start();
+  mOwner = aOwner;
+  sManagers[aOwner] = this;
+}
+
+SharedBufferManagerParent::~SharedBufferManagerParent()
+{
+  MonitorAutoLock lock(sManagerMonitor);
+  if (mTransport) {
+    XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                     new DeleteTask<Transport>(mTransport));
+  }
+  sManagers.erase(mOwner);
+  delete mThread;
+}
+
+void
+SharedBufferManagerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  mBuffers.clear();
+#endif
+}
+
+static void
+ConnectSharedBufferManagerInParentProcess(SharedBufferManagerParent* aManager,
+                                          Transport* aTransport,
+                                          base::ProcessHandle aOtherProcess)
+{
+  aManager->Open(aTransport, aOtherProcess, XRE_GetIOMessageLoop(), ipc::ParentSide);
+}
+
+PSharedBufferManagerParent* SharedBufferManagerParent::Create(Transport* aTransport, ProcessId aOtherProcess)
+{
+  ProcessHandle processHandle;
+  if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
+    return nullptr;
+  }
+
+  base::Thread* thread = nullptr;
+  if (sManagers.count(aOtherProcess) == 1) {
+    thread = sManagers[aOtherProcess]->mThread;
+  }
+  else {
+    char thrname[128];
+    base::snprintf(thrname, 128, "BufMgrParent#%d", aOtherProcess);
+    thread = new base::Thread(thrname);
+  }
+  SharedBufferManagerParent* manager = new SharedBufferManagerParent(aTransport, aOtherProcess, thread);
+  if (!thread->IsRunning())
+    thread->Start();
+  thread->message_loop()->PostTask(FROM_HERE,
+                                   NewRunnableFunction(ConnectSharedBufferManagerInParentProcess,
+                                                       manager, aTransport, processHandle));
+  return manager;
+}
+
+bool SharedBufferManagerParent::RecvAllocateGrallocBuffer(const IntSize& aSize, const uint32_t& aFormat, const uint32_t& aUsage, mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  sp<GraphicBuffer> outgoingBuffer = new GraphicBuffer(aSize.width, aSize.height, aFormat, aUsage);
+
+  GrallocBufferRef ref;
+  ref.mOwner = mOwner;
+  ref.mKey = ++sBufferKey;
+  *aHandle = MagicGrallocBufferHandle(outgoingBuffer, ref);
+
+  int bpp = 0;
+  bpp = android::bytesPerPixel(outgoingBuffer->getPixelFormat());
+  if (bpp > 0)
+    GrallocReporter::sAmount += outgoingBuffer->getStride() * outgoingBuffer->getHeight() * bpp;
+  else // Specical case for BSP specific formats(mainly YUV formats, count it as normal YUV buffer)
+    GrallocReporter::sAmount += outgoingBuffer->getStride() * outgoingBuffer->getHeight() * 3 / 2;
+
+  {
+    MutexAutoLock lock(mBuffersMutex);
+    mBuffers[sBufferKey] = outgoingBuffer;
+  }
+#endif
+  return true;
+}
+
+bool SharedBufferManagerParent::RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  NS_ASSERTION(handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef, "We shouldn't interact with the real buffer!");
+  int bufferKey = handle.get_GrallocBufferRef().mKey;
+  sp<GraphicBuffer> buf = GetGraphicBuffer(bufferKey);
+  MutexAutoLock lock(mBuffersMutex);
+  NS_ASSERTION(mBuffers.count(bufferKey) == 0, "How can you drop others buffer");
+  mBuffers.erase(bufferKey);
+
+  int bpp = 0;
+  bpp = android::bytesPerPixel(buf->getPixelFormat());
+  if (bpp > 0)
+    GrallocReporter::sAmount -= buf->getStride() * buf->getHeight() * bpp;
+  else // Specical case for BSP specific formats(mainly YUV formats, count it as normal YUV buffer)
+    GrallocReporter::sAmount -= buf->getStride() * buf->getHeight() * 3 / 2;
+
+#endif
+  return true;
+}
+
+void SharedBufferManagerParent::DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc)
+{
+  mgr->DropGrallocBufferImpl(aDesc);
+}
+
+void SharedBufferManagerParent::DropGrallocBuffer(mozilla::layers::SurfaceDescriptor aDesc)
+{
+  if (aDesc.type() != SurfaceDescriptor::TNewSurfaceDescriptorGralloc)
+    return;
+
+  if (PlatformThread::CurrentId() == mThread->thread_id()) {
+    DropGrallocBufferImpl(aDesc);
+  } else {
+    mThread->message_loop()->PostTask(FROM_HERE,
+                                      NewRunnableFunction(&DropGrallocBufferSync, this, aDesc));
+  }
+  return;
+}
+
+void SharedBufferManagerParent::DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  MutexAutoLock lock(mBuffersMutex);
+  int key = -1;
+  MaybeMagicGrallocBufferHandle handle;
+  if (aDesc.type() == SurfaceDescriptor::TNewSurfaceDescriptorGralloc)
+    handle = aDesc.get_NewSurfaceDescriptorGralloc().buffer();
+  else
+    return;
+
+  if (handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef)
+    key = handle.get_GrallocBufferRef().mKey;
+  else if (handle.type() == MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle)
+    key = handle.get_MagicGrallocBufferHandle().mRef.mKey;
+
+  NS_ASSERTION(key != -1, "Invalid buffer key");
+  NS_ASSERTION(mBuffers.count(key) == 0, "How can you drop others buffer");
+  mBuffers.erase(key);
+  SendDropGrallocBuffer(handle);
+#endif
+}
+
+MessageLoop* SharedBufferManagerParent::GetMessageLoop()
+{
+  return mThread->message_loop();
+}
+
+SharedBufferManagerParent* SharedBufferManagerParent::GetInstance(ProcessId id)
+{
+  MonitorAutoLock lock(sManagerMonitor);
+  NS_ASSERTION(sManagers.count(id) == 0, "No BufferManager for the process");
+  return sManagers[id];
+}
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+android::sp<android::GraphicBuffer>
+SharedBufferManagerParent::GetGraphicBuffer(int key)
+{
+  MutexAutoLock lock(mBuffersMutex);
+  NS_ASSERTION(mBuffers.count(key) == 0, "No such buffer, or the buffer is belongs to other session");
+  return mBuffers[key];
+}
+
+android::sp<android::GraphicBuffer>
+SharedBufferManagerParent::GetGraphicBuffer(GrallocBufferRef aRef)
+{
+  return GetInstance(aRef.mOwner)->GetGraphicBuffer(aRef.mKey);
+}
+#endif
+
+IToplevelProtocol*
+SharedBufferManagerParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
+                                 base::ProcessHandle aPeerProcess,
+                                 mozilla::ipc::ProtocolCloneContext* aCtx)
+{
+  for (unsigned int i = 0; i < aFds.Length(); i++) {
+    if (aFds[i].protocolId() == unsigned(GetProtocolId())) {
+      Transport* transport = OpenDescriptor(aFds[i].fd(),
+                                            Transport::MODE_SERVER);
+      PSharedBufferManagerParent* bufferManager = Create(transport, base::GetProcId(aPeerProcess));
+      bufferManager->CloneManagees(this, aCtx);
+      bufferManager->IToplevelProtocol::SetTransport(transport);
+      return bufferManager;
+    }
+  }
+  return nullptr;
+}
+
+} /* namespace layers */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/SharedBufferManagerParent.h
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* 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 SharedBufferManagerPARENT_H_
+#define SharedBufferManagerPARENT_H_
+
+#include "mozilla/layers/PSharedBufferManagerParent.h"
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/Mutex.h"            // for Mutex
+
+namespace android {
+class GraphicBuffer;
+}
+#endif
+
+namespace base {
+class Thread;
+}
+
+namespace mozilla {
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+class Mutex;
+#endif
+
+namespace layers {
+
+class SharedBufferManagerParent : public PSharedBufferManagerParent
+{
+public:
+  /**
+   * Create a SharedBufferManagerParent for child process, and link to the child side before leaving
+   */
+  static PSharedBufferManagerParent* Create(Transport* aTransport, ProcessId aOtherProcess);
+
+  /**
+   * Function for find the buffer owner, most buffer passing on IPC contains only owner/key pair.
+   * Use these function to access the real buffer.
+   */
+  static SharedBufferManagerParent* GetInstance(ProcessId id);
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  android::sp<android::GraphicBuffer> GetGraphicBuffer(int key);
+  static android::sp<android::GraphicBuffer> GetGraphicBuffer(GrallocBufferRef aRef);
+#endif
+  /**
+   * Create a SharedBufferManagerParent but do not open the link
+   */
+  SharedBufferManagerParent(Transport* aTransport, ProcessId aOwner, base::Thread* aThread);
+  virtual ~SharedBufferManagerParent();
+
+  /**
+   * When the IPC channel down or something bad make this Manager die, clear all the buffer reference!
+   */
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool RecvAllocateGrallocBuffer(const IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*);
+  virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle);
+
+  /**
+   * Break the buffer's sharing state, decrease buffer reference for both side
+   */
+  void DropGrallocBuffer(mozilla::layers::SurfaceDescriptor aDesc);
+
+  // Overriden from IToplevelProtocol
+  IToplevelProtocol*
+  CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
+                base::ProcessHandle aPeerProcess,
+                mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
+  MessageLoop* GetMessageLoop();
+
+protected:
+  /**
+   * All living SharedBufferManager instances used to find the buffer owner, and parent->child IPCs
+   */
+  static std::map<base::ProcessId, SharedBufferManagerParent*> sManagers;
+
+  /**
+   * Break the buffer's sharing state, decrease buffer reference for both side
+   *
+   * Must be called from SharedBufferManagerParent's thread
+   */
+  void DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc);
+
+  // dispatched function
+  static void DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc);
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  /**
+   * Buffers owned by this SharedBufferManager pair
+   */
+  std::map<int, android::sp<android::GraphicBuffer> > mBuffers;
+  Mutex mBuffersMutex;
+#endif
+  
+  Transport* mTransport;
+  base::ProcessId mOwner;
+  base::Thread* mThread;
+  static int sBufferKey;
+  static Monitor sManagerMonitor;
+};
+
+} /* namespace layers */
+} /* namespace mozilla */
+#endif /* SharedBufferManagerPARENT_H_ */
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -5,16 +5,17 @@
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/SharedBufferManagerChild.h"
 #include "mozilla/layers/ISurfaceAllocator.h"     // for GfxMemoryImageReporter
 
 #include "prlog.h"
 
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
 
 #ifdef XP_WIN
@@ -370,16 +371,19 @@ gfxPlatform::Init()
       useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
     }
 
     if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
         CompositorParent::StartUp();
         if (gfxPrefs::AsyncVideoEnabled()) {
             ImageBridgeChild::StartUp();
         }
+#ifdef MOZ_WIDGET_GONK
+        SharedBufferManagerChild::StartUp();
+#endif
     }
 
     nsresult rv;
 
 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
     rv = gfxPlatformFontList::Init();
     if (NS_FAILED(rv)) {
         NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
@@ -488,16 +492,20 @@ gfxPlatform::Shutdown()
     // most platforms.  Windows is a "special snowflake", though, and has three
     // context providers available, so we have to shut all of them down.
     // We should only support the default GL provider on Windows; then, this
     // could go away. Unfortunately, we currently support WGL (the default) for
     // WebGL on Optimus.
     mozilla::gl::GLContextProviderEGL::Shutdown();
 #endif
 
+#ifdef MOZ_WIDGET_GONK
+    SharedBufferManagerChild::ShutDown();
+#endif
+
     delete gGfxPlatformPrefsLock;
 
     gfxPrefs::DestroySingleton();
     gfxFont::DestroySingletons();
 
     delete gPlatform;
     gPlatform = nullptr;
 }
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -2,16 +2,18 @@
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 protocol PContent;
 include protocol PBrowser;
 
+include "mozilla/GfxMessageUtils.h";
+
 using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
 using mozilla::hal::FlashMode from "mozilla/HalTypes.h";
 using mozilla::hal::LightType from "mozilla/HalTypes.h";
 using mozilla::hal::LightMode from "mozilla/HalTypes.h";
 using mozilla::hal::SensorType from "mozilla/HalSensor.h";
 using mozilla::hal::SensorAccuracyType from "mozilla/HalSensor.h";
 using mozilla::hal::WakeLockControl from "mozilla/HalTypes.h";
 using mozilla::hal::SwitchState from "mozilla/HalTypes.h";
--- a/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h
+++ b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.h
@@ -25,17 +25,17 @@ class FileDescriptorSet : public base::R
   // because the control message kernel interface has to be given a buffer which
   // is large enough to store all the descriptor numbers. Otherwise the kernel
   // tells us that it truncated the control data and the extra descriptors are
   // lost.
   //
   // In debugging mode, it's a fatal error to try and add more than this number
   // of descriptors to a FileDescriptorSet.
   enum {
-    MAX_DESCRIPTORS_PER_MESSAGE = 4
+    MAX_DESCRIPTORS_PER_MESSAGE = 7
   };
 
   // ---------------------------------------------------------------------------
   // Interfaces for building during message serialisation...
 
   // Add a descriptor to the end of the set. Returns false iff the set is full.
   bool Add(int fd);
   // Add a descriptor to the end of the set and automatically close it after