drop the suggestions if search engine not available draft
authorNevin Chen <cnevinchen@gmail.com>
Tue, 01 Nov 2016 12:06:15 +0800
changeset 432075 20c6de9a15657795810fd98e6e680329e86a28f5
parent 430895 35bab1bf72bf023d964e505fa0510933f71f3bbe
child 535539 c187cca61317cd6e3115e18a16ed0e445889780e
push id34190
push userbmo:cnevinchen@gmail.com
push dateTue, 01 Nov 2016 07:03:43 +0000
milestone52.0a1
drop the suggestions if search engine not available MozReview-Commit-ID: 6WxT1J5bWoJ
browser/locales/searchjson.py
browser/locales/searchplugins.py
devtools/client/locales/en-US/promisedebugger.dtd
devtools/client/promisedebugger/moz.build
devtools/client/promisedebugger/promise-controller.js
devtools/client/promisedebugger/promise-debugger.xhtml
devtools/client/promisedebugger/promise-panel.js
devtools/client/promisedebugger/test/.eslintrc.js
devtools/client/promisedebugger/test/head.js
dom/ipc/nsIBrowser.idl
dom/workers/ServiceWorkerMessageEvent.cpp
dom/workers/ServiceWorkerMessageEvent.h
gfx/gl/SharedSurfaceGralloc.cpp
gfx/gl/SharedSurfaceGralloc.h
gfx/harfbuzz/harfbuzz.pc.in
gfx/layers/GrallocImages.cpp
gfx/layers/GrallocImages.h
gfx/layers/basic/GrallocTextureHostBasic.cpp
gfx/layers/basic/GrallocTextureHostBasic.h
gfx/layers/ipc/AsyncTransactionTracker.cpp
gfx/layers/ipc/AsyncTransactionTracker.h
gfx/layers/ipc/FenceUtils.cpp
gfx/layers/ipc/FenceUtils.h
gfx/layers/ipc/PSharedBufferManager.ipdl
gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
gfx/layers/ipc/ShadowLayerUtilsGralloc.h
gfx/layers/ipc/SharedBufferManagerChild.cpp
gfx/layers/ipc/SharedBufferManagerChild.h
gfx/layers/ipc/SharedBufferManagerParent.cpp
gfx/layers/ipc/SharedBufferManagerParent.h
gfx/layers/opengl/GrallocTextureClient.cpp
gfx/layers/opengl/GrallocTextureClient.h
gfx/layers/opengl/GrallocTextureHost.cpp
gfx/layers/opengl/GrallocTextureHost.h
mobile/android/base/java/org/mozilla/gecko/ChromeCast.java
mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
security/sandbox/linux/SandboxHooks.cpp
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchjson.py
@@ -0,0 +1,23 @@
+# 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/.
+
+import sys
+import json
+
+engines = []
+
+locale = sys.argv[2]
+output_file = sys.argv[3]
+
+output = open(output_file, 'w')
+
+with open(sys.argv[1]) as f:
+  searchinfo = json.load(f)
+
+if locale in searchinfo["locales"]:
+  output.write(json.dumps(searchinfo["locales"][locale]))
+else:
+  output.write(json.dumps(searchinfo["default"]))
+
+output.close();
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins.py
@@ -0,0 +1,21 @@
+# 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/.
+
+import sys
+import json
+
+engines = []
+
+locale = sys.argv[2]
+
+with open(sys.argv[1]) as f:
+  searchinfo = json.load(f)
+
+if locale in searchinfo["locales"]:
+  for region in searchinfo["locales"][locale]:
+    engines = list(set(engines)|set(searchinfo["locales"][locale][region]["visibleDefaultEngines"]))
+else:
+  engines = searchinfo["default"]["visibleDefaultEngines"]
+
+print '\n'.join(engines)
new file mode 100644
--- /dev/null
+++ b/devtools/client/locales/en-US/promisedebugger.dtd
@@ -0,0 +1,15 @@
+<!-- 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/. -->
+
+<!-- LOCALIZATION NOTE : FILE This file contains the Promise debugger panel
+     strings. The Promise debugger panel is part of the debugger -->
+<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
+
+<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
+  - keep it in English, or another language commonly spoken among web developers.
+  - You want to make that choice consistent across the developer tools.
+  - A good criteria is the language in which you'd find the best
+  - documentation on web development on the web. -->
+
+<!ENTITY title "Promise Debugger">
new file mode 100644
--- /dev/null
+++ b/devtools/client/promisedebugger/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+DevToolsModules(
+)
new file mode 100644
--- /dev/null
+++ b/devtools/client/promisedebugger/promise-controller.js
@@ -0,0 +1,102 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 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/. */
+
+/* global PromisesPanel */
+
+"use strict";
+
+var { utils: Cu } = Components;
+const { loader, require } =
+  Cu.import("resource://devtools/shared/Loader.jsm", {});
+
+const { Task } = require("devtools/shared/task");
+
+loader.lazyRequireGetter(this, "promise");
+loader.lazyRequireGetter(this, "EventEmitter",
+  "devtools/shared/event-emitter");
+loader.lazyRequireGetter(this, "DevToolsUtils",
+  "devtools/shared/DevToolsUtils");
+loader.lazyRequireGetter(this, "PromisesFront",
+  "devtools/server/actors/promises", true);
+
+// Global toolbox, set when startup is called.
+var gToolbox;
+
+/**
+ * Initialize the promise debugger controller and view upon loading the iframe.
+ */
+var startup = Task.async(function* (toolbox) {
+  gToolbox = toolbox;
+
+  yield PromisesController.initialize(toolbox);
+  yield PromisesPanel.initialize();
+});
+
+/**
+ * Destroy the promise debugger controller and view when unloading the iframe.
+ */
+var shutdown = Task.async(function* () {
+  yield PromisesController.destroy();
+  yield PromisesPanel.destroy();
+
+  gToolbox = null;
+});
+
+function setPanel(toolbox) {
+  return startup(toolbox).catch(e =>
+    DevToolsUtils.reportException("setPanel", e));
+}
+
+function destroy() {
+  return shutdown().catch(e => DevToolsUtils.reportException("destroy", e));
+}
+
+/**
+ * The promisedebugger controller's job is to retrieve PromisesFronts from the
+ * server.
+ */
+var PromisesController = {
+  initialize: Task.async(function* () {
+    if (this.initialized) {
+      return this.initialized.promise;
+    }
+
+    this.initialized = promise.defer();
+
+    let target = gToolbox.target;
+    this.promisesFront = new PromisesFront(target.client, target.form);
+    yield this.promisesFront.attach();
+
+    if (this.destroyed) {
+      console.warn("Could not fully initialize the PromisesController");
+      return null;
+    }
+
+    this.initialized.resolve();
+  }),
+
+  destroy: Task.async(function* () {
+    if (!this.initialized) {
+      return null;
+    }
+
+    if (this.destroyed) {
+      return this.destroyed.promise;
+    }
+
+    this.destroyed = promise.defer();
+
+    if (this.promisesFront) {
+      yield this.promisesFront.detach();
+      this.promisesFront.destroy();
+      this.promisesFront = null;
+    }
+
+    this.destroyed.resolve();
+  }),
+};
+
+EventEmitter.decorate(PromisesController);
new file mode 100644
--- /dev/null
+++ b/devtools/client/promisedebugger/promise-debugger.xhtml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This Source Code Form is subject to the terms of the Mkozilla 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/. -->
+
+<!DOCTYPE html [
+  <!ENTITY % promisedebuggerDTD SYSTEM "chrome://devtools/locale/promisedebugger.dtd">
+  %promisedebuggerDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>&title;</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
+  </head>
+  <body class="devtools-monospace" role="application">
+    <script type="application/javascript;version=1.8" src="promise-controller.js"></script>
+    <script type="application/javascript;version=1.8" src="promise-panel.js"></script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/promisedebugger/promise-panel.js
@@ -0,0 +1,45 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 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/. */
+
+/* global PromisesController, promise */
+/* import-globals-from promise-controller.js */
+
+"use strict";
+
+/**
+ * The main promise debugger UI.
+ */
+var PromisesPanel = {
+  PANEL_INITIALIZED: "panel-initialized",
+
+  initialize: Task.async(function* () {
+    if (PromisesController.destroyed) {
+      return null;
+    }
+    if (this.initialized) {
+      return this.initialized.promise;
+    }
+    this.initialized = promise.defer();
+
+    this.initialized.resolve();
+
+    this.emit(this.PANEL_INITIALIZED);
+  }),
+
+  destroy: Task.async(function* () {
+    if (!this.initialized) {
+      return null;
+    }
+    if (this.destroyed) {
+      return this.destroyed.promise;
+    }
+    this.destroyed = promise.defer();
+
+    this.destroyed.resolve();
+  }),
+};
+
+EventEmitter.decorate(PromisesPanel);
new file mode 100644
--- /dev/null
+++ b/devtools/client/promisedebugger/test/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../../.eslintrc.mochitests.js"
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/promisedebugger/test/head.js
@@ -0,0 +1,4 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
new file mode 100644
--- /dev/null
+++ b/dom/ipc/nsIBrowser.idl
@@ -0,0 +1,27 @@
+/* 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 "nsISupports.idl"
+
+interface nsIDOMElement;
+
+[scriptable, uuid(14e5a0cb-e223-4202-95e8-fe53275193ea)]
+interface nsIBrowser : nsISupports
+{
+  /**
+   * Gets a related browser for a given browser (if any). If this exists, then
+   * we should attempt to use the same content parent as its frameLoader
+   * for any new tab parents.
+   */
+  readonly attribute nsIDOMElement relatedBrowser;
+
+  /*
+   * Called by the child to inform the parent that links are dropped into
+   * content area.
+   *
+   * @param linksCount length of links
+   * @param links a flat array of url, name, and type for each link
+   */
+  void dropLinks(in unsigned long linksCount,
+                 [array, size_is(linksCount)] in wstring links);
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerMessageEvent.cpp
@@ -0,0 +1,166 @@
+/* vim: set ts=8 sts=2 et sw=2 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/dom/ServiceWorkerMessageEvent.h"
+#include "mozilla/dom/ServiceWorkerMessageEventBinding.h"
+#include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/MessagePortBinding.h"
+
+#include "mozilla/HoldDropJSObjects.h"
+#include "jsapi.h"
+
+#include "ServiceWorker.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ServiceWorkerMessageEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ServiceWorkerMessageEvent, Event)
+  tmp->mData.setUndefined();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorker)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServiceWorkerMessageEvent, Event)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorker)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ServiceWorkerMessageEvent, Event)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerMessageEvent)
+NS_INTERFACE_MAP_END_INHERITING(Event)
+
+NS_IMPL_ADDREF_INHERITED(ServiceWorkerMessageEvent, Event)
+NS_IMPL_RELEASE_INHERITED(ServiceWorkerMessageEvent, Event)
+
+ServiceWorkerMessageEvent::ServiceWorkerMessageEvent(EventTarget* aOwner,
+                                                     nsPresContext* aPresContext,
+                                                     WidgetEvent* aEvent)
+  : Event(aOwner, aPresContext, aEvent)
+  , mData(JS::UndefinedValue())
+{
+  mozilla::HoldJSObjects(this);
+}
+
+ServiceWorkerMessageEvent::~ServiceWorkerMessageEvent()
+{
+  mData.setUndefined();
+  DropJSObjects(this);
+}
+
+JSObject*
+ServiceWorkerMessageEvent::WrapObjectInternal(JSContext* aCx,
+                                              JS::Handle<JSObject*> aGivenProto)
+{
+  return mozilla::dom::ServiceWorkerMessageEventBinding::Wrap(aCx, this, aGivenProto);
+}
+
+
+void
+ServiceWorkerMessageEvent::GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
+                                   ErrorResult& aRv) const
+{
+  aData.set(mData);
+  if (!JS_WrapValue(aCx, aData)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+}
+
+void
+ServiceWorkerMessageEvent::GetOrigin(nsAString& aOrigin) const
+{
+  aOrigin = mOrigin;
+}
+
+void
+ServiceWorkerMessageEvent::GetLastEventId(nsAString& aLastEventId) const
+{
+  aLastEventId = mLastEventId;
+}
+
+void
+ServiceWorkerMessageEvent::GetSource(Nullable<OwningServiceWorkerOrMessagePort>& aValue) const
+{
+  if (mServiceWorker) {
+    aValue.SetValue().SetAsServiceWorker() = mServiceWorker;
+  } else if (mMessagePort) {
+    aValue.SetValue().SetAsMessagePort() = mMessagePort;
+  }
+}
+
+void
+ServiceWorkerMessageEvent::SetSource(mozilla::dom::MessagePort* aPort)
+{
+  mMessagePort = aPort;
+}
+
+void
+ServiceWorkerMessageEvent::SetSource(workers::ServiceWorker* aServiceWorker)
+{
+  mServiceWorker = aServiceWorker;
+}
+
+void
+ServiceWorkerMessageEvent::GetPorts(nsTArray<RefPtr<MessagePort>>& aPorts)
+{
+  aPorts = mPorts;
+}
+
+void
+ServiceWorkerMessageEvent::SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts)
+{
+  MOZ_ASSERT(mPorts.IsEmpty());
+  mPorts = Move(aPorts);
+}
+
+/* static */ already_AddRefed<ServiceWorkerMessageEvent>
+ServiceWorkerMessageEvent::Constructor(const GlobalObject& aGlobal,
+                                       const nsAString& aType,
+                                       const ServiceWorkerMessageEventInit& aParam,
+                                       ErrorResult& aRv)
+{
+  nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
+  return Constructor(t, aType, aParam, aRv);
+}
+
+/* static */ already_AddRefed<ServiceWorkerMessageEvent>
+ServiceWorkerMessageEvent::Constructor(EventTarget* aEventTarget,
+                                       const nsAString& aType,
+                                       const ServiceWorkerMessageEventInit& aParam,
+                                       ErrorResult& aRv)
+{
+  RefPtr<ServiceWorkerMessageEvent> event =
+    new ServiceWorkerMessageEvent(aEventTarget, nullptr, nullptr);
+
+  event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
+
+  bool trusted = event->Init(aEventTarget);
+  event->SetTrusted(trusted);
+
+  event->mData = aParam.mData;
+  event->mOrigin = aParam.mOrigin;
+  event->mLastEventId = aParam.mLastEventId;
+
+  if (!aParam.mSource.IsNull()) {
+    if (aParam.mSource.Value().IsServiceWorker()) {
+      event->mServiceWorker = aParam.mSource.Value().GetAsServiceWorker();
+    } else if (aParam.mSource.Value().IsMessagePort()) {
+      event->mMessagePort = aParam.mSource.Value().GetAsMessagePort();
+    }
+  }
+
+  event->mPorts.AppendElements(aParam.mPorts);
+
+  return event.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerMessageEvent.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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 mozilla_dom_serviceworkermessageevent_h__
+#define mozilla_dom_serviceworkermessageevent_h__
+
+#include "mozilla/dom/Event.h"
+
+namespace mozilla {
+namespace dom {
+
+struct ServiceWorkerMessageEventInit;
+class MessagePort;
+class OwningServiceWorkerOrMessagePort;
+
+namespace workers {
+
+class ServiceWorker;
+
+}
+
+class ServiceWorkerMessageEvent final : public Event
+{
+public:
+  ServiceWorkerMessageEvent(EventTarget* aOwner,
+                            nsPresContext* aPresContext,
+                            WidgetEvent* aEvent);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ServiceWorkerMessageEvent, Event)
+
+  // Forward to base class
+  NS_FORWARD_TO_EVENT
+
+  virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aData,
+               ErrorResult& aRv) const;
+
+  void GetOrigin(nsAString& aOrigin) const;
+
+  void GetLastEventId(nsAString& aLastEventId) const;
+
+  void GetSource(Nullable<OwningServiceWorkerOrMessagePort>& aValue) const;
+
+  void GetPorts(nsTArray<RefPtr<MessagePort>>& aPorts);
+
+  void SetSource(mozilla::dom::MessagePort* aPort);
+
+  void SetSource(workers::ServiceWorker* aServiceWorker);
+
+  void SetPorts(nsTArray<RefPtr<MessagePort>>&& aPorts);
+
+  static already_AddRefed<ServiceWorkerMessageEvent>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aType,
+              const ServiceWorkerMessageEventInit& aEventInit,
+              ErrorResult& aRv);
+
+  static already_AddRefed<ServiceWorkerMessageEvent>
+  Constructor(EventTarget* aEventTarget,
+              const nsAString& aType,
+              const ServiceWorkerMessageEventInit& aEventInit,
+              ErrorResult& aRv);
+
+protected:
+  ~ServiceWorkerMessageEvent();
+
+private:
+  JS::Heap<JS::Value> mData;
+  nsString mOrigin;
+  nsString mLastEventId;
+  RefPtr<workers::ServiceWorker> mServiceWorker;
+  RefPtr<MessagePort> mMessagePort;
+  nsTArray<RefPtr<MessagePort>> mPorts;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_workers_serviceworkermessageevent_h__ */
+
new file mode 100644
--- /dev/null
+++ b/gfx/gl/SharedSurfaceGralloc.cpp
@@ -0,0 +1,294 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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/Preferences.h"
+#include "mozilla/UniquePtr.h"
+
+#include "SharedSurfaceGralloc.h"
+
+#include "GLContext.h"
+#include "SharedSurface.h"
+#include "GLLibraryEGL.h"
+#include "mozilla/layers/GrallocTextureClient.h"
+#include "mozilla/layers/ShadowLayers.h"
+
+#include "ui/GraphicBuffer.h"
+#include "../layers/ipc/ShadowLayers.h"
+#include "ScopedGLHelpers.h"
+
+#include "gfxPlatform.h"
+#include "gfxPrefs.h"
+
+#define DEBUG_GRALLOC
+#ifdef DEBUG_GRALLOC
+#define DEBUG_PRINT(...) do { printf_stderr(__VA_ARGS__); } while (0)
+#else
+#define DEBUG_PRINT(...) do { } while (0)
+#endif
+
+namespace mozilla {
+namespace gl {
+
+using namespace mozilla::layers;
+using namespace android;
+
+SurfaceFactory_Gralloc::SurfaceFactory_Gralloc(GLContext* prodGL, const SurfaceCaps& caps,
+                                               const RefPtr<layers::LayersIPCChannel>& allocator,
+                                               const layers::TextureFlags& flags)
+    : SurfaceFactory(SharedSurfaceType::Gralloc, prodGL, caps, allocator, flags)
+{
+    MOZ_ASSERT(mAllocator);
+}
+
+/*static*/ UniquePtr<SharedSurface_Gralloc>
+SharedSurface_Gralloc::Create(GLContext* prodGL,
+                              const GLFormats& formats,
+                              const gfx::IntSize& size,
+                              bool hasAlpha,
+                              layers::TextureFlags flags,
+                              LayersIPCChannel* allocator)
+{
+    GLLibraryEGL* egl = &sEGLLibrary;
+    MOZ_ASSERT(egl);
+
+    UniquePtr<SharedSurface_Gralloc> ret;
+
+    DEBUG_PRINT("SharedSurface_Gralloc::Create -------\n");
+
+    if (!HasExtensions(egl, prodGL))
+        return Move(ret);
+
+    gfxContentType type = hasAlpha ? gfxContentType::COLOR_ALPHA
+                                   : gfxContentType::COLOR;
+
+    GrallocTextureData* texData = GrallocTextureData::CreateForGLRendering(
+        size, gfxPlatform::GetPlatform()->Optimal2DFormatForContent(type), allocator
+    );
+
+    if (!texData) {
+        return Move(ret);
+    }
+
+    RefPtr<TextureClient> grallocTC = new TextureClient(texData, flags, allocator);
+
+    sp<GraphicBuffer> buffer = texData->GetGraphicBuffer();
+
+    EGLDisplay display = egl->Display();
+    EGLClientBuffer clientBuffer = buffer->getNativeBuffer();
+    EGLint attrs[] = {
+        LOCAL_EGL_NONE, LOCAL_EGL_NONE
+    };
+    EGLImage image = egl->fCreateImage(display,
+                                       EGL_NO_CONTEXT,
+                                       LOCAL_EGL_NATIVE_BUFFER_ANDROID,
+                                       clientBuffer, attrs);
+    if (!image) {
+        return Move(ret);
+    }
+
+    prodGL->MakeCurrent();
+    GLuint prodTex = 0;
+    prodGL->fGenTextures(1, &prodTex);
+    ScopedBindTexture autoTex(prodGL, prodTex);
+
+    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+
+    prodGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image);
+
+    egl->fDestroyImage(display, image);
+
+    ret.reset( new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl,
+                                         allocator, grallocTC,
+                                         prodTex) );
+
+    DEBUG_PRINT("SharedSurface_Gralloc::Create: success -- surface %p,"
+                " GraphicBuffer %p.\n",
+                ret.get(), buffer.get());
+
+    return Move(ret);
+}
+
+
+SharedSurface_Gralloc::SharedSurface_Gralloc(GLContext* prodGL,
+                                             const gfx::IntSize& size,
+                                             bool hasAlpha,
+                                             GLLibraryEGL* egl,
+                                             layers::LayersIPCChannel* allocator,
+                                             layers::TextureClient* textureClient,
+                                             GLuint prodTex)
+    : SharedSurface(SharedSurfaceType::Gralloc,
+                    AttachmentType::GLTexture,
+                    prodGL,
+                    size,
+                    hasAlpha,
+                    true)
+    , mEGL(egl)
+    , mSync(0)
+    , mAllocator(allocator)
+    , mTextureClient(textureClient)
+    , mProdTex(prodTex)
+{
+}
+
+bool
+SharedSurface_Gralloc::HasExtensions(GLLibraryEGL* egl, GLContext* gl)
+{
+    return egl->HasKHRImageBase() &&
+           gl->IsExtensionSupported(GLContext::OES_EGL_image);
+}
+
+SharedSurface_Gralloc::~SharedSurface_Gralloc()
+{
+    DEBUG_PRINT("[SharedSurface_Gralloc %p] destroyed\n", this);
+
+    if (!mGL || !mGL->MakeCurrent())
+        return;
+
+    mGL->fDeleteTextures(1, &mProdTex);
+
+    if (mSync) {
+        MOZ_ALWAYS_TRUE( mEGL->fDestroySync(mEGL->Display(), mSync) );
+        mSync = 0;
+    }
+}
+
+void
+SharedSurface_Gralloc::ProducerReleaseImpl()
+{
+    if (mSync) {
+        MOZ_ALWAYS_TRUE( mEGL->fDestroySync(mEGL->Display(), mSync) );
+        mSync = 0;
+    }
+
+    bool disableSyncFence = false;
+    // Disable sync fence on AdrenoTM200.
+    // AdrenoTM200's sync fence does not work correctly. See Bug 1022205.
+    if (mGL->Renderer() == GLRenderer::AdrenoTM200) {
+        disableSyncFence = true;
+    }
+
+    // When Android native fences are available, try
+    // them first since they're more likely to work.
+    // Android native fences are also likely to perform better.
+    if (!disableSyncFence &&
+        mEGL->IsExtensionSupported(GLLibraryEGL::ANDROID_native_fence_sync))
+    {
+        mGL->MakeCurrent();
+        EGLSync sync = mEGL->fCreateSync(mEGL->Display(),
+                                         LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                         nullptr);
+        if (sync) {
+            mGL->fFlush();
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+            int fenceFd = mEGL->fDupNativeFenceFDANDROID(mEGL->Display(), sync);
+            if (fenceFd != -1) {
+                mEGL->fDestroySync(mEGL->Display(), sync);
+                mTextureClient->SetAcquireFenceHandle(FenceHandle(new FenceHandle::FdObj(fenceFd)));
+            } else {
+                mSync = sync;
+            }
+#else
+            mSync = sync;
+#endif
+            return;
+        }
+    }
+
+    if (!disableSyncFence &&
+        mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync))
+    {
+        mGL->MakeCurrent();
+        mSync = mEGL->fCreateSync(mEGL->Display(),
+                                  LOCAL_EGL_SYNC_FENCE,
+                                  nullptr);
+        if (mSync) {
+            mGL->fFlush();
+            return;
+        }
+    }
+
+    // We should be able to rely on genlock write locks/read locks.
+    // But they're broken on some configs, and even a glFinish doesn't
+    // work.  glReadPixels seems to, though.
+    if (gfxPrefs::GrallocFenceWithReadPixels()) {
+        mGL->MakeCurrent();
+        UniquePtr<char[]> buf = MakeUnique<char[]>(4);
+        mGL->fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf.get());
+    }
+}
+
+void
+SharedSurface_Gralloc::WaitForBufferOwnership()
+{
+    mTextureClient->WaitForBufferOwnership();
+}
+
+bool
+SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    mTextureClient->mWorkaroundAnnoyingSharedSurfaceOwnershipIssues = true;
+    return mTextureClient->ToSurfaceDescriptor(*out_descriptor);
+}
+
+bool
+SharedSurface_Gralloc::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
+{
+    MOZ_ASSERT(out_surface);
+    sp<GraphicBuffer> buffer = static_cast<GrallocTextureData*>(
+        mTextureClient->GetInternalData()
+    )->GetGraphicBuffer();
+
+    const uint8_t* grallocData = nullptr;
+    auto result = buffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        const_cast<void**>(reinterpret_cast<const void**>(&grallocData))
+    );
+
+    if (result == BAD_VALUE) {
+        return false;
+    }
+
+    gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
+    if (!map.IsMapped()) {
+        buffer->unlock();
+        return false;
+    }
+
+    uint32_t stride = buffer->getStride() * android::bytesPerPixel(buffer->getPixelFormat());
+    uint32_t height = buffer->getHeight();
+    uint32_t width = buffer->getWidth();
+    for (uint32_t i = 0; i < height; i++) {
+        memcpy(map.GetData() + i * map.GetStride(),
+               grallocData + i * stride, width * 4);
+    }
+
+    buffer->unlock();
+
+    android::PixelFormat srcFormat = buffer->getPixelFormat();
+    MOZ_ASSERT(srcFormat == PIXEL_FORMAT_RGBA_8888 ||
+               srcFormat == PIXEL_FORMAT_BGRA_8888 ||
+               srcFormat == PIXEL_FORMAT_RGBX_8888);
+    bool isSrcRGB = srcFormat == PIXEL_FORMAT_RGBA_8888 ||
+                    srcFormat == PIXEL_FORMAT_RGBX_8888;
+
+    gfx::SurfaceFormat destFormat = out_surface->GetFormat();
+    MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
+               destFormat == gfx::SurfaceFormat::R8G8B8A8 ||
+               destFormat == gfx::SurfaceFormat::B8G8R8X8 ||
+               destFormat == gfx::SurfaceFormat::B8G8R8A8);
+    bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
+                     destFormat == gfx::SurfaceFormat::R8G8B8A8;
+
+    if (isSrcRGB != isDestRGB) {
+        SwapRAndBComponents(out_surface);
+    }
+    return true;
+}
+
+} // namespace gl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/gl/SharedSurfaceGralloc.h
@@ -0,0 +1,104 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 SHARED_SURFACE_GRALLOC_H_
+#define SHARED_SURFACE_GRALLOC_H_
+
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/LayersSurfaces.h"
+#include "SharedSurface.h"
+
+namespace mozilla {
+namespace layers {
+class LayersIPCChannel;
+class TextureClient;
+}
+
+namespace gl {
+class GLContext;
+class GLLibraryEGL;
+
+class SharedSurface_Gralloc
+    : public SharedSurface
+{
+public:
+    static UniquePtr<SharedSurface_Gralloc> Create(GLContext* prodGL,
+                                                   const GLFormats& formats,
+                                                   const gfx::IntSize& size,
+                                                   bool hasAlpha,
+                                                   layers::TextureFlags flags,
+                                                   layers::LayersIPCChannel* allocator);
+
+    static SharedSurface_Gralloc* Cast(SharedSurface* surf) {
+        MOZ_ASSERT(surf->mType == SharedSurfaceType::Gralloc);
+
+        return (SharedSurface_Gralloc*)surf;
+    }
+
+protected:
+    GLLibraryEGL* const mEGL;
+    EGLSync mSync;
+    RefPtr<layers::LayersIPCChannel> mAllocator;
+    RefPtr<layers::TextureClient> mTextureClient;
+    const GLuint mProdTex;
+
+    SharedSurface_Gralloc(GLContext* prodGL,
+                          const gfx::IntSize& size,
+                          bool hasAlpha,
+                          GLLibraryEGL* egl,
+                          layers::LayersIPCChannel* allocator,
+                          layers::TextureClient* textureClient,
+                          GLuint prodTex);
+
+    static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl);
+
+public:
+    virtual ~SharedSurface_Gralloc();
+
+    virtual void ProducerAcquireImpl() override {}
+    virtual void ProducerReleaseImpl() override;
+
+    virtual void WaitForBufferOwnership() override;
+
+    virtual void LockProdImpl() override {}
+    virtual void UnlockProdImpl() override {}
+
+    virtual GLuint ProdTexture() override {
+        return mProdTex;
+    }
+
+    layers::TextureClient* GetTextureClient() {
+        return mTextureClient;
+    }
+
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
+
+    virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
+};
+
+class SurfaceFactory_Gralloc
+    : public SurfaceFactory
+{
+public:
+    SurfaceFactory_Gralloc(GLContext* prodGL, const SurfaceCaps& caps,
+                           const RefPtr<layers::LayersIPCChannel>& allocator,
+                           const layers::TextureFlags& flags);
+
+    virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
+        bool hasAlpha = mReadCaps.alpha;
+
+        UniquePtr<SharedSurface> ret;
+        if (mAllocator) {
+            ret = SharedSurface_Gralloc::Create(mGL, mFormats, size, hasAlpha,
+                                                mFlags, mAllocator);
+        }
+        return Move(ret);
+    }
+};
+
+} /* namespace gl */
+} /* namespace mozilla */
+
+#endif /* SHARED_SURFACE_GRALLOC_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/harfbuzz.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: harfbuzz
+Description: Text shaping library
+Version: @VERSION@
+
+Libs: -L${libdir} -lharfbuzz
+Cflags: -I${includedir}/harfbuzz
new file mode 100644
--- /dev/null
+++ b/gfx/layers/GrallocImages.cpp
@@ -0,0 +1,478 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 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 "GrallocImages.h"
+#include <stddef.h>                     // for size_t
+#include <stdint.h>                     // for int8_t, uint8_t, uint32_t, etc
+#include "nsDebug.h"                    // for NS_WARNING, NS_PRECONDITION
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/GrallocTextureClient.h"
+#include "gfx2DGlue.h"
+#include "YCbCrUtils.h"                 // for YCbCr conversions
+
+#include <ColorConverter.h>
+#include <OMX_IVCommon.h>
+
+
+using namespace mozilla::ipc;
+using namespace android;
+
+#define ALIGN(x, align) ((x + align - 1) & ~(align - 1))
+
+namespace mozilla {
+namespace layers {
+
+int32_t GrallocImage::sColorIdMap[] = {
+    HAL_PIXEL_FORMAT_YCbCr_420_P, OMX_COLOR_FormatYUV420Planar,
+    HAL_PIXEL_FORMAT_YCbCr_422_P, OMX_COLOR_FormatYUV422Planar,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP, OMX_COLOR_FormatYUV420SemiPlanar,
+    HAL_PIXEL_FORMAT_YCrCb_420_SP, -1,
+    HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO, -1,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED, HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS, HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS,
+    HAL_PIXEL_FORMAT_YV12, OMX_COLOR_FormatYUV420Planar,
+    HAL_PIXEL_FORMAT_RGBA_8888, -1,
+    0, 0
+};
+
+struct GraphicBufferAutoUnlock {
+  android::sp<GraphicBuffer> mGraphicBuffer;
+
+  GraphicBufferAutoUnlock(android::sp<GraphicBuffer>& aGraphicBuffer)
+    : mGraphicBuffer(aGraphicBuffer) { }
+
+  ~GraphicBufferAutoUnlock() { mGraphicBuffer->unlock(); }
+};
+
+GrallocImage::GrallocImage()
+  : RecyclingPlanarYCbCrImage(nullptr)
+{
+  mFormat = ImageFormat::GRALLOC_PLANAR_YCBCR;
+}
+
+GrallocImage::~GrallocImage()
+{
+}
+
+bool
+GrallocImage::SetData(const Data& aData)
+{
+  MOZ_ASSERT(!mTextureClient, "TextureClient is already set");
+  NS_PRECONDITION(aData.mYSize.width % 2 == 0, "Image should have even width");
+  NS_PRECONDITION(aData.mYSize.height % 2 == 0, "Image should have even height");
+  NS_PRECONDITION(aData.mYStride % 16 == 0, "Image should have stride of multiple of 16 pixels");
+
+  mData = aData;
+  mSize = aData.mPicSize;
+
+  if (gfxPlatform::GetPlatform()->IsInGonkEmulator()) {
+    // Emulator does not support HAL_PIXEL_FORMAT_YV12.
+    return false;
+  }
+
+  RefPtr<LayersIPCChannel> allocator = ImageBridgeChild::GetSingleton();
+  GrallocTextureData* texData = GrallocTextureData::Create(mData.mYSize, HAL_PIXEL_FORMAT_YV12,
+                                                           gfx::BackendType::NONE,
+                                                           GraphicBuffer::USAGE_SW_READ_OFTEN |
+                                                             GraphicBuffer::USAGE_SW_WRITE_OFTEN |
+                                                             GraphicBuffer::USAGE_HW_TEXTURE,
+                                                           allocator
+  );
+
+  if (!texData) {
+    return false;
+  }
+
+  mTextureClient = new TextureClient(texData, TextureFlags::DEFAULT, allocator);
+  sp<GraphicBuffer> graphicBuffer = texData->GetGraphicBuffer();
+
+  void* vaddr;
+  if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+                          &vaddr) != OK) {
+    return false;
+  }
+
+  uint8_t* yChannel = static_cast<uint8_t*>(vaddr);
+  gfx::IntSize ySize = aData.mYSize;
+  int32_t yStride = graphicBuffer->getStride();
+
+  uint8_t* vChannel = yChannel + (yStride * ySize.height);
+  gfx::IntSize uvSize = gfx::IntSize(ySize.width / 2,
+                                 ySize.height / 2);
+  // Align to 16 bytes boundary
+  int32_t uvStride = ((yStride / 2) + 15) & ~0x0F;
+  uint8_t* uChannel = vChannel + (uvStride * uvSize.height);
+
+  // Memory outside of the image width may not writable. If the stride
+  // equals to the image width then we can use only one copy.
+  if (yStride == mData.mYStride &&
+      yStride == ySize.width) {
+    memcpy(yChannel, mData.mYChannel, yStride * ySize.height);
+  } else {
+    for (int i = 0; i < ySize.height; i++) {
+      memcpy(yChannel + i * yStride,
+             mData.mYChannel + i * mData.mYStride,
+             ySize.width);
+    }
+  }
+  if (uvStride == mData.mCbCrStride &&
+      uvStride == uvSize.width) {
+    memcpy(uChannel, mData.mCbChannel, uvStride * uvSize.height);
+    memcpy(vChannel, mData.mCrChannel, uvStride * uvSize.height);
+  } else {
+    for (int i = 0; i < uvSize.height; i++) {
+      memcpy(uChannel + i * uvStride,
+             mData.mCbChannel + i * mData.mCbCrStride,
+             uvSize.width);
+      memcpy(vChannel + i * uvStride,
+             mData.mCrChannel + i * mData.mCbCrStride,
+             uvSize.width);
+    }
+  }
+  graphicBuffer->unlock();
+  // Initialze the channels' addresses.
+  // Do not cache the addresses when gralloc buffer is not locked.
+  // gralloc hal could map gralloc buffer only when the buffer is locked,
+  // though some gralloc hals implementation maps it when it is allocated.
+  mData.mYChannel     = nullptr;
+  mData.mCrChannel    = nullptr;
+  mData.mCbChannel    = nullptr;
+  return true;
+}
+
+void
+GrallocImage::AdoptData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize)
+{
+  mTextureClient = aGraphicBuffer;
+  mSize = aSize;
+}
+
+/**
+ * Converts YVU420 semi planar frames to RGB565, possibly taking different
+ * stride values.
+ * Needed because the Android ColorConverter class assumes that the Y and UV
+ * channels have equal stride.
+ */
+static void
+ConvertYVU420SPToRGB565(void *aYData, uint32_t aYStride,
+                        void *aUData, void *aVData, uint32_t aUVStride,
+                        void *aOut,
+                        uint32_t aWidth, uint32_t aHeight)
+{
+  uint8_t *y = (uint8_t*)aYData;
+  bool isCbCr;
+  int8_t *uv;
+
+  if (aUData < aVData) {
+    // The color format is YCbCr
+    isCbCr = true;
+    uv = (int8_t*)aUData;
+  } else {
+    // The color format is YCrCb
+    isCbCr = false;
+    uv = (int8_t*)aVData;
+  }
+
+  uint16_t *rgb = (uint16_t*)aOut;
+
+  for (size_t i = 0; i < aHeight; i++) {
+    for (size_t j = 0; j < aWidth; j++) {
+      int8_t d, e;
+
+      if (isCbCr) {
+        d = uv[j & ~1] - 128;
+        e = uv[j | 1] - 128;
+      } else {
+        d = uv[j | 1] - 128;
+        e = uv[j & ~1] - 128;
+      }
+
+      // Constants taken from https://en.wikipedia.org/wiki/YUV
+      int32_t r = (298 * y[j] + 409 * e + 128) >> 11;
+      int32_t g = (298 * y[j] - 100 * d - 208 * e + 128) >> 10;
+      int32_t b = (298 * y[j] + 516 * d + 128) >> 11;
+
+      r = r > 0x1f ? 0x1f : r < 0 ? 0 : r;
+      g = g > 0x3f ? 0x3f : g < 0 ? 0 : g;
+      b = b > 0x1f ? 0x1f : b < 0 ? 0 : b;
+
+      *rgb++ = (uint16_t)(r << 11 | g << 5 | b);
+    }
+
+    y += aYStride;
+    if (i % 2) {
+      uv += aUVStride;
+    }
+  }
+}
+
+/**
+ * Converts the format of vendor-specific YVU420(planar and semi-planar)
+ * with the help of GraphicBuffer::lockYCbCr. In this way, we can convert
+ * the YUV color format without awaring actual definition/enumeration
+ * of vendor formats.
+ */
+static status_t
+ConvertVendorYUVFormatToRGB565(android::sp<GraphicBuffer>& aBuffer,
+                               gfx::DataSourceSurface *aSurface,
+                               gfx::DataSourceSurface::MappedSurface *aMappedSurface)
+{
+  status_t rv = BAD_VALUE;
+
+#if ANDROID_VERSION >= 18
+  android_ycbcr ycbcr;
+
+  // Check if the vendor provides explicit addresses of Y/Cb/Cr buffer from lockYCbCr
+  rv = aBuffer->lockYCbCr(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &ycbcr);
+
+  if (rv != OK) {
+    NS_WARNING("Couldn't lock graphic buffer using lockYCbCr()");
+    return rv;
+  }
+
+  GraphicBufferAutoUnlock unlock(aBuffer);
+
+  uint32_t width = aSurface->GetSize().width;
+  uint32_t height = aSurface->GetSize().height;
+
+  if (ycbcr.chroma_step == 2) {
+    // From the system/core/include/system/graphics.h
+    // @chroma_step is the distance in bytes from one chroma pixel value to
+    // the next.  This is 2 bytes for semiplanar (because chroma values are
+    // interleaved and each chroma value is one byte) and 1 for planar.
+    ConvertYVU420SPToRGB565(ycbcr.y, ycbcr.ystride,
+                            ycbcr.cb, ycbcr.cr, ycbcr.cstride,
+                            aMappedSurface->mData,
+                            width, height);
+  } else {
+    layers::PlanarYCbCrData ycbcrData;
+    ycbcrData.mYChannel     = static_cast<uint8_t*>(ycbcr.y);
+    ycbcrData.mYStride      = ycbcr.ystride;
+    ycbcrData.mYSize        = aSurface->GetSize();
+    ycbcrData.mCbChannel    = static_cast<uint8_t*>(ycbcr.cb);
+    ycbcrData.mCrChannel    = static_cast<uint8_t*>(ycbcr.cr);
+    ycbcrData.mCbCrStride   = ycbcr.cstride;
+    ycbcrData.mCbCrSize     = aSurface->GetSize() / 2;
+    ycbcrData.mPicSize      = aSurface->GetSize();
+
+    gfx::ConvertYCbCrToRGB(ycbcrData,
+                           aSurface->GetFormat(),
+                           aSurface->GetSize(),
+                           aMappedSurface->mData,
+                           aMappedSurface->mStride);
+  }
+#endif
+
+  return rv;
+}
+
+static status_t
+ConvertOmxYUVFormatToRGB565(android::sp<GraphicBuffer>& aBuffer,
+                            gfx::DataSourceSurface *aSurface,
+                            gfx::DataSourceSurface::MappedSurface *aMappedSurface,
+                            const layers::PlanarYCbCrData& aYcbcrData)
+{
+  uint32_t omxFormat =
+    GrallocImage::GetOmxFormat(aBuffer->getPixelFormat());
+  if (!omxFormat) {
+    NS_WARNING("Unknown color format");
+    return BAD_VALUE;
+  }
+
+  status_t rv;
+  uint8_t *buffer;
+
+  rv = aBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN,
+                     reinterpret_cast<void **>(&buffer));
+  if (rv != OK) {
+    NS_WARNING("Couldn't lock graphic buffer");
+    return BAD_VALUE;
+  }
+
+  GraphicBufferAutoUnlock unlock(aBuffer);
+
+  uint32_t format = aBuffer->getPixelFormat();
+  uint32_t width = aSurface->GetSize().width;
+  uint32_t height = aSurface->GetSize().height;
+  uint32_t stride = aBuffer->getStride();
+
+  if (format == GrallocImage::HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) {
+    // The Adreno hardware decoder aligns image dimensions to a multiple of 32,
+    // so we have to account for that here
+    uint32_t alignedWidth = ALIGN(width, 32);
+    uint32_t alignedHeight = ALIGN(height, 32);
+    uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096);
+    uint32_t uvStride = 2 * ALIGN(width / 2, 32);
+    ConvertYVU420SPToRGB565(buffer, alignedWidth,
+                            buffer + uvOffset + 1,
+                            buffer + uvOffset,
+                            uvStride,
+                            aMappedSurface->mData,
+                            width, height);
+    return OK;
+  }
+
+  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+    uint32_t uvOffset = height * stride;
+    ConvertYVU420SPToRGB565(buffer, stride,
+                            buffer + uvOffset + 1,
+                            buffer + uvOffset,
+                            stride,
+                            aMappedSurface->mData,
+                            width, height);
+    return OK;
+  }
+
+  if (format == HAL_PIXEL_FORMAT_YV12) {
+    // Depend on platforms, it is possible for HW decoder to output YV12 format.
+    // It means the mData won't be configured during the SetData API because the
+    // yuv data has already stored in GraphicBuffer. Here we try to confgiure the
+    // mData if it doesn't contain valid configuration.
+    layers::PlanarYCbCrData ycbcrData = aYcbcrData;
+    if (!ycbcrData.mYChannel) {
+      ycbcrData.mYChannel     = buffer;
+      ycbcrData.mYSkip        = 0;
+      ycbcrData.mYStride      = aBuffer->getStride();
+      ycbcrData.mYSize        = aSurface->GetSize();
+      ycbcrData.mCbSkip       = 0;
+      ycbcrData.mCbCrSize     = aSurface->GetSize() / 2;
+      ycbcrData.mPicSize      = aSurface->GetSize();
+      ycbcrData.mCrChannel    = buffer + ycbcrData.mYStride * aBuffer->getHeight();
+      ycbcrData.mCrSkip       = 0;
+      // Align to 16 bytes boundary
+      ycbcrData.mCbCrStride   = ALIGN(ycbcrData.mYStride / 2, 16);
+      ycbcrData.mCbChannel    = ycbcrData.mCrChannel + (ycbcrData.mCbCrStride * aBuffer->getHeight() / 2);
+    } else {
+      // Update channels' address.
+      // Gralloc buffer could map gralloc buffer only when the buffer is locked.
+      ycbcrData.mYChannel     = buffer;
+      ycbcrData.mCrChannel    = buffer + ycbcrData.mYStride * aBuffer->getHeight();
+      ycbcrData.mCbChannel    = ycbcrData.mCrChannel + (ycbcrData.mCbCrStride * aBuffer->getHeight() / 2);
+    }
+    gfx::ConvertYCbCrToRGB(ycbcrData,
+                           aSurface->GetFormat(),
+                           aSurface->GetSize(),
+                           aMappedSurface->mData,
+                           aMappedSurface->mStride);
+    return OK;
+  }
+
+  if (format == HAL_PIXEL_FORMAT_RGBA_8888) {
+    uint32_t* src = (uint32_t*)(buffer);
+    uint16_t* dest = (uint16_t*)(aMappedSurface->mData);
+
+    // Convert RGBA8888 to RGB565
+    for (size_t i = 0; i < width * height; i++) {
+      uint32_t r = ((*src >> 0 ) & 0xFF);
+      uint32_t g = ((*src >> 8 ) & 0xFF);
+      uint32_t b = ((*src >> 16) & 0xFF);
+      *dest++ = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);
+      src++;
+    }
+    return OK;
+  }
+
+  android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)omxFormat,
+                                         OMX_COLOR_Format16bitRGB565);
+  if (!colorConverter.isValid()) {
+    NS_WARNING("Invalid color conversion");
+    return BAD_VALUE;
+  }
+
+  uint32_t pixelStride = aMappedSurface->mStride/gfx::BytesPerPixel(gfx::SurfaceFormat::R5G6B5_UINT16);
+  rv = colorConverter.convert(buffer, width, height,
+                              0, 0, width - 1, height - 1 /* source crop */,
+                              aMappedSurface->mData, pixelStride, height,
+                              0, 0, width - 1, height - 1 /* dest crop */);
+  if (rv) {
+    NS_WARNING("OMX color conversion failed");
+    return BAD_VALUE;
+  }
+
+  return OK;
+}
+
+already_AddRefed<gfx::DataSourceSurface>
+GetDataSourceSurfaceFrom(android::sp<android::GraphicBuffer>& aGraphicBuffer,
+                         gfx::IntSize aSize,
+                         const layers::PlanarYCbCrData& aYcbcrData)
+{
+  MOZ_ASSERT(aGraphicBuffer.get());
+
+  RefPtr<gfx::DataSourceSurface> surface =
+    gfx::Factory::CreateDataSourceSurface(aSize, gfx::SurfaceFormat::R5G6B5_UINT16);
+  if (NS_WARN_IF(!surface)) {
+    return nullptr;
+  }
+
+  gfx::DataSourceSurface::MappedSurface mappedSurface;
+  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
+    NS_WARNING("Could not map DataSourceSurface");
+    return nullptr;
+  }
+
+  int32_t rv;
+  rv = ConvertOmxYUVFormatToRGB565(aGraphicBuffer, surface, &mappedSurface, aYcbcrData);
+  if (rv == OK) {
+    surface->Unmap();
+    return surface.forget();
+  }
+
+  rv = ConvertVendorYUVFormatToRGB565(aGraphicBuffer, surface, &mappedSurface);
+  surface->Unmap();
+  if (rv != OK) {
+    NS_WARNING("Unknown color format");
+    return nullptr;
+  }
+
+  return surface.forget();
+}
+
+already_AddRefed<gfx::SourceSurface>
+GrallocImage::GetAsSourceSurface()
+{
+  if (!mTextureClient) {
+    return nullptr;
+  }
+
+  android::sp<GraphicBuffer> graphicBuffer = GetGraphicBuffer();
+
+  RefPtr<gfx::DataSourceSurface> surface =
+    GetDataSourceSurfaceFrom(graphicBuffer, mSize, mData);
+
+  return surface.forget();
+}
+
+android::sp<android::GraphicBuffer>
+GrallocImage::GetGraphicBuffer() const
+{
+  if (!mTextureClient) {
+    return nullptr;
+  }
+  return static_cast<GrallocTextureData*>(mTextureClient->GetInternalData())->GetGraphicBuffer();
+}
+
+void*
+GrallocImage::GetNativeBuffer()
+{
+  if (!mTextureClient) {
+    return nullptr;
+  }
+  android::sp<android::GraphicBuffer> graphicBuffer = GetGraphicBuffer();
+  if (!graphicBuffer.get()) {
+    return nullptr;
+  }
+  return graphicBuffer->getNativeBuffer();
+}
+
+TextureClient*
+GrallocImage::GetTextureClient(KnowsCompositor* aForwarder)
+{
+  return mTextureClient;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/GrallocImages.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 20; 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 GRALLOCIMAGES_H
+#define GRALLOCIMAGES_H
+
+#ifdef MOZ_WIDGET_GONK
+
+#include "ImageLayers.h"
+#include "ImageContainer.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
+#include "mozilla/layers/FenceUtils.h"
+#include "mozilla/layers/LayersSurfaces.h"
+
+#include <ui/GraphicBuffer.h>
+
+namespace mozilla {
+namespace layers {
+
+class TextureClient;
+
+already_AddRefed<gfx::DataSourceSurface>
+GetDataSourceSurfaceFrom(android::sp<android::GraphicBuffer>& aGraphicBuffer,
+                         gfx::IntSize aSize,
+                         const layers::PlanarYCbCrData& aYcbcrData);
+
+/**
+ * The YUV format supported by Android HAL
+ *
+ * 4:2:0 - CbCr width and height is half that of Y.
+ *
+ * This format assumes
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ * - a vertical stride equal to the height
+ *
+ * y_size = stride * height
+ * c_size = ALIGN(stride/2, 16) * height/2
+ * size = y_size + c_size * 2
+ * cr_offset = y_size
+ * cb_offset = y_size + c_size
+ *
+ * The Image that is rendered is the picture region defined by
+ * mPicX, mPicY and mPicSize. The size of the rendered image is
+ * mPicSize, not mYSize or mCbCrSize.
+ */
+class GrallocImage : public RecyclingPlanarYCbCrImage
+{
+  typedef PlanarYCbCrData Data;
+  static int32_t sColorIdMap[];
+public:
+  GrallocImage();
+
+  virtual ~GrallocImage();
+
+  /**
+   * This makes a copy of the data buffers, in order to support functioning
+   * in all different layer managers.
+   */
+  virtual bool SetData(const Data& aData);
+
+  using RecyclingPlanarYCbCrImage::AdoptData;
+  /**
+   *  Share the SurfaceDescriptor without making the copy, in order
+   *  to support functioning in all different layer managers.
+   */
+  void AdoptData(TextureClient* aGraphicBuffer, const gfx::IntSize& aSize);
+
+  // From [android 4.0.4]/hardware/msm7k/libgralloc-qsd8k/gralloc_priv.h
+  enum {
+    /* OEM specific HAL formats */
+    HAL_PIXEL_FORMAT_YCbCr_422_P            = 0x102,
+    HAL_PIXEL_FORMAT_YCbCr_420_P            = 0x103,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP           = 0x109,
+    HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO    = 0x10A,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED     = 0x7FA30C03,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS     = 0x7FA30C04,
+  };
+
+  enum {
+    GRALLOC_SW_UAGE = android::GraphicBuffer::USAGE_SOFTWARE_MASK,
+  };
+
+  virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
+
+  android::sp<android::GraphicBuffer> GetGraphicBuffer() const;
+
+  void* GetNativeBuffer();
+
+  virtual bool IsValid() { return !!mTextureClient; }
+
+  virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
+
+  virtual GrallocImage* AsGrallocImage() override
+  {
+    return this;
+  }
+
+  virtual uint8_t* GetBuffer()
+  {
+    return static_cast<uint8_t*>(GetNativeBuffer());
+  }
+
+  int GetUsage()
+  {
+    return (static_cast<ANativeWindowBuffer*>(GetNativeBuffer()))->usage;
+  }
+
+  static int GetOmxFormat(int aFormat)
+  {
+    uint32_t omxFormat = 0;
+
+    for (int i = 0; sColorIdMap[i]; i += 2) {
+      if (sColorIdMap[i] == aFormat) {
+        omxFormat = sColorIdMap[i + 1];
+        break;
+      }
+    }
+
+    return omxFormat;
+  }
+
+private:
+  RefPtr<TextureClient> mTextureClient;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
+
+#endif /* GRALLOCIMAGES_H */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/GrallocTextureHostBasic.cpp
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 20; 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/. */
+
+#include "GrallocTextureHostBasic.h"
+#include "GrallocImages.h"  // for GetDataSourceSurfaceFrom()
+#include "mozilla/layers/SharedBufferManagerParent.h"
+
+#if ANDROID_VERSION >= 17
+#include <ui/Fence.h>
+#endif
+
+namespace mozilla {
+namespace layers {
+
+static gfx::SurfaceFormat
+HalFormatToSurfaceFormat(int aHalFormat, TextureFlags aFlags)
+{
+  bool swapRB = bool(aFlags & TextureFlags::RB_SWAPPED);
+  switch (aHalFormat) {
+  case android::PIXEL_FORMAT_BGRA_8888:
+    return swapRB ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8A8;
+  case android::PIXEL_FORMAT_RGBA_8888:
+    return swapRB ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::R8G8B8A8;
+  case android::PIXEL_FORMAT_RGBX_8888:
+    return swapRB ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::R8G8B8X8;
+  case android::PIXEL_FORMAT_RGB_565:
+    return gfx::SurfaceFormat::R5G6B5_UINT16;
+  case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+  case HAL_PIXEL_FORMAT_YCbCr_422_I:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+  case HAL_PIXEL_FORMAT_YV12:
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+#endif
+      // Needs convert to RGB565
+      return gfx::SurfaceFormat::R5G6B5_UINT16;
+  default:
+    if (aHalFormat >= 0x100 && aHalFormat <= 0x1FF) {
+      // Reserved range for HAL specific formats.
+      // Needs convert to RGB565
+      return gfx::SurfaceFormat::R5G6B5_UINT16;
+    } else {
+      MOZ_CRASH("GFX: Unhandled HAL pixel format");
+      return gfx::SurfaceFormat::UNKNOWN; // not reached
+    }
+  }
+}
+
+static bool
+NeedsConvertFromYUVtoRGB565(int aHalFormat)
+{
+  switch (aHalFormat) {
+  case android::PIXEL_FORMAT_BGRA_8888:
+  case android::PIXEL_FORMAT_RGBA_8888:
+  case android::PIXEL_FORMAT_RGBX_8888:
+  case android::PIXEL_FORMAT_RGB_565:
+    return false;
+  case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+  case HAL_PIXEL_FORMAT_YCbCr_422_I:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+  case HAL_PIXEL_FORMAT_YV12:
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+#endif
+      return true;
+  default:
+    if (aHalFormat >= 0x100 && aHalFormat <= 0x1FF) {
+      // Reserved range for HAL specific formats.
+      return true;
+    } else {
+      MOZ_CRASH("GFX: Unhandled HAL pixel format YUV");
+      return false; // not reached
+    }
+  }
+}
+
+GrallocTextureHostBasic::GrallocTextureHostBasic(
+  TextureFlags aFlags,
+  const SurfaceDescriptorGralloc& aDescriptor)
+  : TextureHost(aFlags)
+  , mGrallocHandle(aDescriptor)
+  , mSize(0, 0)
+  , mCropSize(0, 0)
+  , mFormat(gfx::SurfaceFormat::UNKNOWN)
+  , mIsOpaque(aDescriptor.isOpaque())
+{
+  android::GraphicBuffer* grallocBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+  MOZ_ASSERT(grallocBuffer);
+
+  if (grallocBuffer) {
+    mFormat =
+      HalFormatToSurfaceFormat(grallocBuffer->getPixelFormat(),
+                               aFlags & TextureFlags::RB_SWAPPED);
+    mSize = gfx::IntSize(grallocBuffer->getWidth(), grallocBuffer->getHeight());
+    mCropSize = mSize;
+  } else {
+    printf_stderr("gralloc buffer is nullptr\n");
+  }
+}
+
+bool
+GrallocTextureHostBasic::Lock()
+{
+  if (!mCompositor || !IsValid()) {
+    return false;
+  }
+
+  if (mTextureSource) {
+    return true;
+  }
+
+  android::sp<android::GraphicBuffer> graphicBuffer =
+    GetGraphicBufferFromDesc(mGrallocHandle);
+  MOZ_ASSERT(graphicBuffer.get());
+
+  RefPtr<gfx::DataSourceSurface> surf;
+  if (NeedsConvertFromYUVtoRGB565(graphicBuffer->getPixelFormat())) {
+    PlanarYCbCrData ycbcrData;
+    surf = GetDataSourceSurfaceFrom(graphicBuffer,
+                                    mCropSize,
+                                    ycbcrData);
+  } else {
+    uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
+    int32_t rv = graphicBuffer->lock(usage,
+                                     reinterpret_cast<void**>(&mMappedBuffer));
+    if (rv) {
+      mMappedBuffer = nullptr;
+      NS_WARNING("Couldn't lock graphic buffer");
+      return false;
+    }
+    surf = gfx::Factory::CreateWrappingDataSourceSurface(
+             mMappedBuffer,
+             graphicBuffer->getStride() * gfx::BytesPerPixel(mFormat),
+             mCropSize,
+             mFormat);
+  }
+  if (surf) {
+    mTextureSource = mCompositor->CreateDataTextureSource(mFlags);
+    mTextureSource->Update(surf, nullptr);
+    return true;
+  }
+  mMappedBuffer = nullptr;
+  return false;
+}
+
+bool
+GrallocTextureHostBasic::IsValid() const
+{
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+  return graphicBuffer != nullptr;
+}
+
+bool
+GrallocTextureHostBasic::BindTextureSource(CompositableTextureSourceRef& aTexture)
+{
+  aTexture = mTextureSource;
+  return !!aTexture;
+}
+
+void
+GrallocTextureHostBasic::UnbindTextureSource()
+{
+  TextureHost::UnbindTextureSource();
+  ClearTextureSource();
+}
+
+void
+GrallocTextureHostBasic::ClearTextureSource()
+{
+  mTextureSource = nullptr;
+  if (mMappedBuffer) {
+    android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+    MOZ_ASSERT(graphicBuffer);
+    mMappedBuffer = nullptr;
+    graphicBuffer->unlock();
+  }
+}
+
+void
+GrallocTextureHostBasic::SetCompositor(Compositor* aCompositor)
+{
+  BasicCompositor* compositor = AssertBasicCompositor(aCompositor);
+  if (!compositor) {
+    return;
+  }
+
+  mCompositor = compositor;
+  if (mTextureSource) {
+    mTextureSource->SetCompositor(compositor);
+  }
+}
+
+Compositor*
+GrallocTextureHostBasic::GetCompositor()
+{
+  return mCompositor;
+}
+
+gfx::SurfaceFormat
+GrallocTextureHostBasic::GetFormat() const {
+  return mFormat;
+}
+
+void
+GrallocTextureHostBasic::WaitAcquireFenceHandleSyncComplete()
+{
+  if (!mAcquireFenceHandle.IsValid()) {
+    return;
+  }
+
+#if ANDROID_VERSION >= 17
+  RefPtr<FenceHandle::FdObj> fdObj = mAcquireFenceHandle.GetAndResetFdObj();
+  android::sp<android::Fence> fence(
+    new android::Fence(fdObj->GetAndResetFd()));
+
+  // Wait fece complete with timeout.
+  // If a source of the fence becomes invalid because of error,
+  // fene complete is not signaled. See Bug 1061435.
+  int rv = fence->wait(400 /*400 msec*/);
+  if (rv != android::OK) {
+    NS_ERROR("failed to wait fence complete");
+  }
+#endif
+}
+
+void
+GrallocTextureHostBasic::SetCropRect(nsIntRect aCropRect)
+{
+  MOZ_ASSERT(aCropRect.TopLeft() == gfx::IntPoint(0, 0));
+  MOZ_ASSERT(!aCropRect.IsEmpty());
+  MOZ_ASSERT(aCropRect.width <= mSize.width);
+  MOZ_ASSERT(aCropRect.height <= mSize.height);
+
+  gfx::IntSize cropSize(aCropRect.width, aCropRect.height);
+  if (mCropSize == cropSize) {
+    return;
+  }
+
+  mCropSize = cropSize;
+  ClearTextureSource();
+}
+
+void
+GrallocTextureHostBasic::DeallocateSharedData()
+{
+  ClearTextureSource();
+
+  if (mGrallocHandle.buffer().type() != MaybeMagicGrallocBufferHandle::Tnull_t) {
+    MaybeMagicGrallocBufferHandle handle = mGrallocHandle.buffer();
+    base::ProcessId owner;
+    if (handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
+      owner = handle.get_GrallocBufferRef().mOwner;
+    }
+    else {
+      owner = handle.get_MagicGrallocBufferHandle().mRef.mOwner;
+    }
+
+    SharedBufferManagerParent::DropGrallocBuffer(owner, mGrallocHandle);
+  }
+}
+
+void
+GrallocTextureHostBasic::ForgetSharedData()
+{
+  ClearTextureSource();
+}
+
+void
+GrallocTextureHostBasic::DeallocateDeviceData()
+{
+  ClearTextureSource();
+}
+
+LayerRenderState
+GrallocTextureHostBasic::GetRenderState()
+{
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+
+  if (graphicBuffer) {
+    LayerRenderStateFlags flags = LayerRenderStateFlags::LAYER_RENDER_STATE_DEFAULT;
+    if (mIsOpaque) {
+      flags |= LayerRenderStateFlags::OPAQUE;
+    }
+    if (mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
+      flags |= LayerRenderStateFlags::ORIGIN_BOTTOM_LEFT;
+    }
+    if (mFlags & TextureFlags::RB_SWAPPED) {
+      flags |= LayerRenderStateFlags::FORMAT_RB_SWAP;
+    }
+    return LayerRenderState(graphicBuffer,
+                            mCropSize,
+                            flags,
+                            this);
+  }
+
+  return LayerRenderState();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/GrallocTextureHostBasic.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 20; 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 MOZILLA_GFX_GRALLOCTEXTUREHOST_BASIC_H
+#define MOZILLA_GFX_GRALLOCTEXTUREHOST_BASIC_H
+
+#include "mozilla/layers/BasicCompositor.h"
+#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include "mozilla/layers/TextureHostBasic.h"
+
+namespace mozilla {
+namespace layers {
+
+class BasicCompositor;
+
+/**
+ * A TextureHost for shared gralloc
+ *
+ * Most of the logic actually happens in GrallocTextureSourceBasic.
+ */
+class GrallocTextureHostBasic : public TextureHost
+{
+public:
+  GrallocTextureHostBasic(TextureFlags aFlags,
+                          const SurfaceDescriptorGralloc& aDescriptor);
+
+  virtual void SetCompositor(Compositor* aCompositor) override;
+
+  virtual Compositor* GetCompositor() override;
+
+  virtual bool Lock() override;
+
+  virtual gfx::SurfaceFormat GetFormat() const override;
+
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
+
+  virtual void UnbindTextureSource() override;
+
+  virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
+  {
+    return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
+  }
+
+  virtual void WaitAcquireFenceHandleSyncComplete() override;
+
+  virtual gfx::IntSize GetSize() const override { return mCropSize; }
+
+  virtual void SetCropRect(nsIntRect aCropRect) override;
+
+  virtual void DeallocateSharedData() override;
+
+  virtual void ForgetSharedData() override;
+
+  virtual void DeallocateDeviceData() override;
+
+  virtual LayerRenderState GetRenderState() override;
+
+  bool IsValid() const;
+
+  void ClearTextureSource();
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() override { return "GrallocTextureHostBasic"; }
+#endif
+
+protected:
+  RefPtr<BasicCompositor> mCompositor;
+  RefPtr<DataTextureSource> mTextureSource;
+  SurfaceDescriptorGralloc mGrallocHandle;
+  // gralloc buffer size.
+  gfx::IntSize mSize;
+  // Size reported by TextureClient, can be different in some cases (video?),
+  // used by LayerRenderState.
+  gfx::IntSize mCropSize;
+  gfx::SurfaceFormat mFormat;
+  bool mIsOpaque;
+  /**
+   * Points to a mapped gralloc buffer when TextureSource is valid.
+   */
+  uint8_t* mMappedBuffer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_GRALLOCTEXTUREHOST_BASIC_H
new file mode 100755
--- /dev/null
+++ b/gfx/layers/ipc/AsyncTransactionTracker.cpp
@@ -0,0 +1,169 @@
+/* -*- 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 "AsyncTransactionTracker.h"
+
+#include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
+#include "mozilla/gfx/Logging.h"
+
+namespace mozilla {
+namespace layers {
+
+void
+AsyncTransactionWaiter::WaitComplete()
+{
+  MOZ_ASSERT(!InImageBridgeChildThread());
+
+  MonitorAutoLock mon(mCompletedMonitor);
+  int count = 0;
+  const int maxCount = 5;
+  while (mWaitCount > 0 && (count < maxCount)) {
+    if (!NS_SUCCEEDED(mCompletedMonitor.Wait(PR_MillisecondsToInterval(10000)))) {
+      NS_WARNING("Failed to wait Monitor");
+      return;
+    }
+    if (count > 1) {
+      printf_stderr("Waiting async transaction complete.\n");
+    }
+    count++;
+  }
+
+  if (mWaitCount > 0) {
+    printf_stderr("Timeout of waiting transaction complete.");
+  }
+
+  if (count == maxCount) {
+    gfxDevCrash(gfx::LogReason::AsyncTransactionTimeout) << "Bug 1244883: AsyncTransactionWaiter timed out.";
+  }
+}
+
+Atomic<uint64_t> AsyncTransactionTracker::sSerialCounter(0);
+
+AsyncTransactionTracker::AsyncTransactionTracker(AsyncTransactionWaiter* aWaiter)
+    : mSerial(GetNextSerial())
+    , mWaiter(aWaiter)
+#ifdef DEBUG
+    , mCompleted(false)
+#endif
+{
+  if (mWaiter) {
+    mWaiter->IncrementWaitCount();
+  }
+}
+
+AsyncTransactionTracker::~AsyncTransactionTracker()
+{
+}
+
+void
+AsyncTransactionTracker::NotifyComplete()
+{
+  MOZ_ASSERT(!mCompleted);
+#ifdef DEBUG
+  mCompleted = true;
+#endif
+  Complete();
+  if (mWaiter) {
+    mWaiter->DecrementWaitCount();
+  }
+}
+
+void
+AsyncTransactionTracker::NotifyCancel()
+{
+  MOZ_ASSERT(!mCompleted);
+#ifdef DEBUG
+  mCompleted = true;
+#endif
+  Cancel();
+  if (mWaiter) {
+    mWaiter->DecrementWaitCount();
+  }
+}
+
+Atomic<uint64_t> AsyncTransactionTrackersHolder::sSerialCounter(0);
+
+AsyncTransactionTrackersHolder::AsyncTransactionTrackersHolder()
+  : mSerial(GetNextSerial())
+  , mIsTrackersHolderDestroyed(false)
+{
+  MOZ_COUNT_CTOR(AsyncTransactionTrackersHolder);
+}
+
+AsyncTransactionTrackersHolder::~AsyncTransactionTrackersHolder()
+{
+  if (!mIsTrackersHolderDestroyed) {
+    DestroyAsyncTransactionTrackersHolder();
+  }
+  MOZ_COUNT_DTOR(AsyncTransactionTrackersHolder);
+}
+
+void
+AsyncTransactionTrackersHolder::HoldUntilComplete(AsyncTransactionTracker* aTransactionTracker)
+{
+  if (!aTransactionTracker) {
+    return;
+  }
+
+  if (mIsTrackersHolderDestroyed && aTransactionTracker) {
+    aTransactionTracker->NotifyComplete();
+    return;
+  }
+
+  if (aTransactionTracker) {
+    mAsyncTransactionTrackers[aTransactionTracker->GetId()] = aTransactionTracker;
+  }
+}
+
+void
+AsyncTransactionTrackersHolder::TransactionCompleteted(uint64_t aTransactionId)
+{
+  TransactionCompletetedInternal(aTransactionId);
+}
+
+void
+AsyncTransactionTrackersHolder::TransactionCompletetedInternal(uint64_t aTransactionId)
+{
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> >::iterator it
+    = mAsyncTransactionTrackers.find(aTransactionId);
+  if (it != mAsyncTransactionTrackers.end()) {
+    it->second->NotifyComplete();
+    mAsyncTransactionTrackers.erase(it);
+  }
+}
+
+void
+AsyncTransactionTrackersHolder::SetReleaseFenceHandle(FenceHandle& aReleaseFenceHandle,
+                                                      uint64_t aTransactionId)
+{
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> >::iterator it
+    = mAsyncTransactionTrackers.find(aTransactionId);
+  if (it != mAsyncTransactionTrackers.end()) {
+    it->second->SetReleaseFenceHandle(aReleaseFenceHandle);
+  }
+}
+
+void
+AsyncTransactionTrackersHolder::ClearAllAsyncTransactionTrackers()
+{
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> >::iterator it;
+  for (it = mAsyncTransactionTrackers.begin();
+       it != mAsyncTransactionTrackers.end(); it++) {
+    it->second->NotifyCancel();
+  }
+  mAsyncTransactionTrackers.clear();
+}
+
+void
+AsyncTransactionTrackersHolder::DestroyAsyncTransactionTrackersHolder() {
+  mIsTrackersHolderDestroyed = true;
+  ClearAllAsyncTransactionTrackers();
+}
+
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/AsyncTransactionTracker.h
@@ -0,0 +1,172 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_AsyncTransactionTracker_h
+#define mozilla_layers_AsyncTransactionTracker_h
+
+#include <map>
+
+#include "mozilla/Atomics.h"
+#include "mozilla/layers/FenceUtils.h"  // for FenceHandle
+#include "mozilla/Monitor.h"      // for Monitor
+#include "mozilla/RefPtr.h"       // for AtomicRefCounted
+
+namespace mozilla {
+namespace layers {
+
+class TextureClient;
+class AsyncTransactionTrackersHolder;
+
+/**
+ * Object that lets you wait for one or more async transactions to complete.
+ */
+class AsyncTransactionWaiter
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncTransactionWaiter)
+
+  AsyncTransactionWaiter()
+    : mCompletedMonitor("AsyncTransactionWaiter")
+    , mWaitCount(0)
+  {}
+
+  void IncrementWaitCount()
+  {
+    MonitorAutoLock lock(mCompletedMonitor);
+    ++mWaitCount;
+  }
+  void DecrementWaitCount()
+  {
+    MonitorAutoLock lock(mCompletedMonitor);
+    MOZ_ASSERT(mWaitCount > 0);
+    --mWaitCount;
+    if (mWaitCount == 0) {
+      mCompletedMonitor.Notify();
+    }
+  }
+
+  /**
+   * Wait until asynchronous transactions complete.
+   */
+  void WaitComplete();
+
+  uint32_t GetWaitCount() { return mWaitCount; }
+
+private:
+  ~AsyncTransactionWaiter() {}
+
+  Monitor mCompletedMonitor;
+  uint32_t mWaitCount;
+};
+
+/**
+ * AsyncTransactionTracker tracks asynchronous transaction.
+ * It is typically used for asynchronous layer transaction handling.
+ */
+class AsyncTransactionTracker
+{
+  friend class AsyncTransactionTrackersHolder;
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncTransactionTracker)
+
+  explicit AsyncTransactionTracker(AsyncTransactionWaiter* aWaiter = nullptr);
+
+  /**
+   * Notify async transaction complete.
+   */
+  void NotifyComplete();
+
+  /**
+   * Notify async transaction cancel.
+   */
+  void NotifyCancel();
+
+  uint64_t GetId()
+  {
+    return mSerial;
+  }
+
+  /**
+   * Called when asynchronous transaction complete.
+   */
+  virtual void Complete()= 0;
+
+  /**
+   * Called when asynchronous transaction is cancelled.
+   * The cancel typically happens when IPC is disconnected
+   */
+  virtual void Cancel()= 0;
+
+  virtual void SetTextureClient(TextureClient* aTextureClient) {}
+
+  virtual void SetReleaseFenceHandle(FenceHandle& aReleaseFenceHandle) {}
+
+protected:
+  virtual ~AsyncTransactionTracker();
+
+  static uint64_t GetNextSerial()
+  {
+    return ++sSerialCounter;
+  }
+
+  uint64_t mSerial;
+  RefPtr<AsyncTransactionWaiter> mWaiter;
+#ifdef DEBUG
+  bool mCompleted;
+#endif
+
+  static Atomic<uint64_t> sSerialCounter;
+};
+
+class AsyncTransactionTrackersHolder
+{
+public:
+  AsyncTransactionTrackersHolder();
+  virtual ~AsyncTransactionTrackersHolder();
+
+  void HoldUntilComplete(AsyncTransactionTracker* aTransactionTracker);
+
+  void TransactionCompleteted(uint64_t aTransactionId);
+
+  static void TransactionCompleteted(uint64_t aHolderId, uint64_t aTransactionId);
+
+  static void SetReleaseFenceHandle(FenceHandle& aReleaseFenceHandle,
+                                    uint64_t aHolderId,
+                                    uint64_t aTransactionId);
+
+  uint64_t GetId()
+  {
+    return mSerial;
+  }
+
+  void DestroyAsyncTransactionTrackersHolder();
+
+protected:
+
+  static uint64_t GetNextSerial()
+  {
+    return ++sSerialCounter;
+  }
+
+  void TransactionCompletetedInternal(uint64_t aTransactionId);
+
+  void SetReleaseFenceHandle(FenceHandle& aReleaseFenceHandle, uint64_t aTransactionId);
+
+  void ClearAllAsyncTransactionTrackers();
+
+  const uint64_t mSerial;
+
+  bool mIsTrackersHolderDestroyed;
+  std::map<uint64_t, RefPtr<AsyncTransactionTracker> > mAsyncTransactionTrackers;
+
+  static Atomic<uint64_t> sSerialCounter;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif  // mozilla_layers_AsyncTransactionTracker_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/FenceUtils.cpp
@@ -0,0 +1,111 @@
+/* -*- 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/. */
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+#pragma GCC visibility push(default)
+#include "sync/sync.h"       // for sync_merge
+#pragma GCC visibility pop
+#endif
+
+#include "FenceUtils.h"
+
+using namespace mozilla::layers;
+
+namespace IPC {
+
+void
+ParamTraits<FenceHandle>::Write(Message* aMsg,
+                                const paramType& aParam)
+{
+  FenceHandle handle = aParam;
+
+  MOZ_ASSERT(handle.IsValid());
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  RefPtr<FenceHandle::FdObj> fence = handle.GetAndResetFdObj();
+  aMsg->WriteFileDescriptor(base::FileDescriptor(fence->GetAndResetFd(), true));
+#endif
+}
+
+bool
+ParamTraits<FenceHandle>::Read(const Message* aMsg,
+                               PickleIterator* aIter, paramType* aResult)
+{
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  base::FileDescriptor fd;
+  if (aMsg->ReadFileDescriptor(aIter, &fd)) {
+    aResult->Merge(FenceHandle(new FenceHandle::FdObj(fd.fd)));
+  }
+#endif
+  return true;
+}
+
+} // namespace IPC
+
+namespace mozilla {
+namespace layers {
+
+FenceHandle::FenceHandle()
+  : mFence(new FdObj())
+{
+}
+
+FenceHandle::FenceHandle(FdObj* aFdObj)
+  : mFence(aFdObj)
+{
+  MOZ_ASSERT(aFdObj);
+}
+
+void
+FenceHandle::Merge(const FenceHandle& aFenceHandle)
+{
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  if (!aFenceHandle.IsValid()) {
+    return;
+  }
+
+  if (!IsValid()) {
+    mFence = aFenceHandle.mFence;
+  } else {
+    int result = sync_merge("FenceHandle", mFence->mFd, aFenceHandle.mFence->mFd);
+    if (result == -1) {
+      mFence = aFenceHandle.mFence;
+    } else {
+      mFence = new FdObj(result);
+    }
+  }
+#endif
+}
+
+void
+FenceHandle::TransferToAnotherFenceHandle(FenceHandle& aFenceHandle)
+{
+  aFenceHandle.mFence = this->GetAndResetFdObj();
+}
+
+already_AddRefed<FenceHandle::FdObj>
+FenceHandle::GetAndResetFdObj()
+{
+  RefPtr<FdObj> fence = mFence;
+  mFence = new FdObj();
+  return fence.forget();
+}
+
+already_AddRefed<FenceHandle::FdObj>
+FenceHandle::GetDupFdObj()
+{
+  RefPtr<FdObj> fdObj;
+  if (IsValid()) {
+    fdObj = new FenceHandle::FdObj(dup(mFence->mFd));
+  } else {
+    fdObj = new FenceHandle::FdObj();
+  }
+  return fdObj.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/FenceUtils.h
@@ -0,0 +1,84 @@
+/* -*- 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/. */
+
+#ifndef IPC_FencerUtils_h
+#define IPC_FencerUtils_h
+
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/RefPtr.h"             // for nsRefPtr
+
+namespace mozilla {
+namespace layers {
+
+class FenceHandle {
+public:
+  class FdObj {
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FdObj)
+    friend class FenceHandle;
+  public:
+    FdObj()
+      : mFd(-1) {}
+    explicit FdObj(int aFd)
+      : mFd(aFd) {}
+    int GetAndResetFd()
+    {
+      int fd = mFd;
+      mFd = -1;
+      return fd;
+    }
+
+  private:
+    virtual ~FdObj() {
+      if (mFd != -1) {
+        close(mFd);
+      }
+    }
+
+    int mFd;
+  };
+
+  FenceHandle();
+
+  explicit FenceHandle(FdObj* aFdObj);
+
+  bool operator==(const FenceHandle& aOther) const {
+    return mFence.get() == aOther.mFence.get();
+  }
+
+  bool IsValid() const
+  {
+    return (mFence->mFd != -1);
+  }
+
+  void Merge(const FenceHandle& aFenceHandle);
+
+  void TransferToAnotherFenceHandle(FenceHandle& aFenceHandle);
+
+  already_AddRefed<FdObj> GetAndResetFdObj();
+
+  already_AddRefed<FdObj> GetDupFdObj();
+
+private:
+  RefPtr<FdObj> mFence;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::layers::FenceHandle> {
+  typedef mozilla::layers::FenceHandle paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
+};
+
+} // namespace IPC
+
+#endif // IPC_FencerUtils_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/ShadowLayerUtilsGralloc.cpp
@@ -0,0 +1,253 @@
+/* -*- 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 "mozilla/DebugOnly.h"
+
+#include "mozilla/gfx/Point.h"
+#include "mozilla/layers/LayerTransactionChild.h"
+#include "mozilla/layers/ShadowLayers.h"
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/layers/SharedBufferManagerChild.h"
+#include "mozilla/layers/SharedBufferManagerParent.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
+#include "nsXULAppAPI.h"
+
+#include "ShadowLayerUtilsGralloc.h"
+
+#include "nsIMemoryReporter.h"
+
+#include "gfxPlatform.h"
+#include "gfx2DGlue.h"
+#include "GLContext.h"
+
+#include "GeckoProfiler.h"
+
+#include "cutils/properties.h"
+
+#include "MainThreadUtils.h"
+
+using namespace android;
+using namespace mozilla::layers;
+using namespace mozilla::gl;
+
+using base::FileDescriptor;
+
+namespace IPC {
+
+void
+ParamTraits<GrallocBufferRef>::Write(Message* aMsg,
+                                     const paramType& aParam)
+{
+  aMsg->WriteInt(aParam.mOwner);
+  aMsg->WriteInt64(aParam.mKey);
+}
+
+bool
+ParamTraits<GrallocBufferRef>::Read(const Message* aMsg, PickleIterator* aIter,
+                                    paramType* aParam)
+{
+  int owner;
+  int64_t index;
+  if (!aMsg->ReadInt(aIter, &owner) ||
+      !aMsg->ReadInt64(aIter, &index)) {
+    printf_stderr("ParamTraits<GrallocBufferRef>::Read() failed to read a message\n");
+    return false;
+  }
+  aParam->mOwner = owner;
+  aParam->mKey = index;
+  return true;
+}
+
+void
+ParamTraits<MagicGrallocBufferHandle>::Write(Message* aMsg,
+                                             const paramType& aParam)
+{
+#if ANDROID_VERSION >= 19
+  sp<GraphicBuffer> flattenable = aParam.mGraphicBuffer;
+#else
+  Flattenable *flattenable = aParam.mGraphicBuffer.get();
+#endif
+  size_t nbytes = flattenable->getFlattenedSize();
+  size_t nfds = flattenable->getFdCount();
+
+  char data[nbytes];
+  int fds[nfds];
+
+#if ANDROID_VERSION >= 19
+  // Make a copy of "data" and "fds" for flatten() to avoid casting problem
+  void *pdata = (void *)data;
+  int *pfds = fds;
+
+  flattenable->flatten(pdata, nbytes, pfds, nfds);
+
+  // In Kitkat, flatten() will change the value of nbytes and nfds, which dues
+  // to multiple parcelable object consumption. The actual size and fd count
+  // which returned by getFlattenedSize() and getFdCount() are not changed.
+  // So we change nbytes and nfds back by call corresponding calls.
+  nbytes = flattenable->getFlattenedSize();
+  nfds = flattenable->getFdCount();
+#else
+  flattenable->flatten(data, nbytes, fds, nfds);
+#endif
+  aMsg->WriteInt(aParam.mRef.mOwner);
+  aMsg->WriteInt64(aParam.mRef.mKey);
+  aMsg->WriteSize(nbytes);
+  aMsg->WriteBytes(data, nbytes);
+  for (size_t n = 0; n < nfds; ++n) {
+    // These buffers can't die in transit because they're created
+    // synchonously and the parent-side buffer can only be dropped if
+    // there's a crash.
+    aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
+  }
+}
+
+bool
+ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg,
+                                            PickleIterator* aIter, paramType* aResult)
+{
+  MOZ_ASSERT(!aResult->mGraphicBuffer.get());
+  MOZ_ASSERT(aResult->mRef.mOwner == 0);
+  MOZ_ASSERT(aResult->mRef.mKey == -1);
+
+  size_t nbytes;
+  int owner;
+  int64_t index;
+
+  if (!aMsg->ReadInt(aIter, &owner) ||
+      !aMsg->ReadInt64(aIter, &index) ||
+      !aMsg->ReadSize(aIter, &nbytes)) {
+    printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to read a message\n");
+    return false;
+  }
+
+  auto data = mozilla::MakeUnique<char[]>(nbytes);
+
+  if (!aMsg->ReadBytesInto(aIter, data.get(), nbytes)) {
+    printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to read a message\n");
+    return false;
+  }
+
+  size_t nfds = aMsg->num_fds();
+  int fds[nfds];
+
+  for (size_t n = 0; n < nfds; ++n) {
+    FileDescriptor fd;
+    if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
+      printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to read file descriptors\n");
+      return false;
+    }
+    // If the GraphicBuffer was shared cross-process, SCM_RIGHTS does
+    // the right thing and dup's the fd. If it's shared cross-thread,
+    // SCM_RIGHTS doesn't dup the fd.
+    // But in shared cross-thread, dup fd is not necessary because we get
+    // a pointer to the GraphicBuffer directly from SharedBufferManagerParent
+    // and don't create a new GraphicBuffer around the fd.
+    fds[n] = fd.fd;
+  }
+
+  aResult->mRef.mOwner = owner;
+  aResult->mRef.mKey = index;
+  if (XRE_IsParentProcess()) {
+    // If we are in chrome process, we can just get GraphicBuffer directly from
+    // SharedBufferManagerParent.
+    aResult->mGraphicBuffer = SharedBufferManagerParent::GetGraphicBuffer(aResult->mRef);
+  } else {
+    // Deserialize GraphicBuffer
+#if ANDROID_VERSION >= 19
+    sp<GraphicBuffer> buffer(new GraphicBuffer());
+    const void* datap = (const void*)data.get();
+    const int* fdsp = &fds[0];
+    if (NO_ERROR != buffer->unflatten(datap, nbytes, fdsp, nfds)) {
+      buffer = nullptr;
+    }
+#else
+    sp<GraphicBuffer> buffer(new GraphicBuffer());
+    Flattenable *flattenable = buffer.get();
+    if (NO_ERROR != flattenable->unflatten(data.get(), nbytes, fds, nfds)) {
+      buffer = nullptr;
+    }
+#endif
+    if (buffer.get()) {
+      aResult->mGraphicBuffer = buffer;
+    }
+  }
+
+  if (!aResult->mGraphicBuffer.get()) {
+    printf_stderr("ParamTraits<MagicGrallocBufferHandle>::Read() failed to get gralloc buffer\n");
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace IPC
+
+namespace mozilla {
+namespace layers {
+
+MagicGrallocBufferHandle::MagicGrallocBufferHandle(const sp<GraphicBuffer>& aGraphicBuffer, GrallocBufferRef ref)
+  : mGraphicBuffer(aGraphicBuffer)
+  , mRef(ref)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Parent process
+
+/*static*/ bool
+LayerManagerComposite::SupportsDirectTexturing()
+{
+  return true;
+}
+
+/*static*/ void
+LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
+{
+  // Nothing to be done for gralloc.
+}
+
+//-----------------------------------------------------------------------------
+// Both processes
+
+/*static*/ sp<GraphicBuffer>
+GetGraphicBufferFrom(MaybeMagicGrallocBufferHandle aHandle)
+{
+  if (aHandle.type() != MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle) {
+    if (aHandle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
+      if (XRE_IsParentProcess()) {
+        return SharedBufferManagerParent::GetGraphicBuffer(aHandle.get_GrallocBufferRef());
+      }
+      return SharedBufferManagerChild::GetSingleton()->GetGraphicBuffer(aHandle.get_GrallocBufferRef().mKey);
+    }
+  } else {
+    MagicGrallocBufferHandle realHandle = aHandle.get_MagicGrallocBufferHandle();
+    return realHandle.mGraphicBuffer;
+  }
+  return nullptr;
+}
+
+android::sp<android::GraphicBuffer>
+GetGraphicBufferFromDesc(SurfaceDescriptor aDesc)
+{
+  MaybeMagicGrallocBufferHandle handle;
+  if (aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc) {
+    handle = aDesc.get_SurfaceDescriptorGralloc().buffer();
+  }
+  return GetGraphicBufferFrom(handle);
+}
+
+/*static*/ void
+ShadowLayerForwarder::PlatformSyncBeforeUpdate()
+{
+  // Nothing to be done for gralloc.
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.h
@@ -0,0 +1,95 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_ShadowLayerUtilsGralloc_h
+#define mozilla_layers_ShadowLayerUtilsGralloc_h
+
+#include <unistd.h>
+#include <ui/GraphicBuffer.h>
+
+#include "base/process.h"
+#include "ipc/IPCMessageUtils.h"
+
+#define MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+#define MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
+
+namespace mozilla {
+namespace layers {
+
+class MaybeMagicGrallocBufferHandle;
+class SurfaceDescriptor;
+
+struct GrallocBufferRef {
+  base::ProcessId mOwner;
+  int64_t mKey;
+
+  GrallocBufferRef()
+    : mOwner(0)
+    , mKey(-1)
+  {
+
+  }
+
+  bool operator== (const GrallocBufferRef rhs) const{
+    return mOwner == rhs.mOwner && mKey == rhs.mKey;
+  }
+};
+/**
+ * This class exists to share the underlying GraphicBuffer resources
+ * from one thread context to another.  This requires going through
+ * slow paths in the kernel so can be somewhat expensive.
+ *
+ * This is not just platform-specific, but also
+ * gralloc-implementation-specific.
+ */
+struct MagicGrallocBufferHandle {
+  typedef android::GraphicBuffer GraphicBuffer;
+  MagicGrallocBufferHandle() {}
+
+  MagicGrallocBufferHandle(const android::sp<GraphicBuffer>& aGraphicBuffer, GrallocBufferRef ref);
+
+  // Default copy ctor and operator= are OK
+
+  bool operator==(const MagicGrallocBufferHandle& aOther) const {
+    return mGraphicBuffer == aOther.mGraphicBuffer;
+  }
+
+  android::sp<GraphicBuffer> mGraphicBuffer;
+  GrallocBufferRef mRef;
+};
+
+/**
+ * Util function to find GraphicBuffer from SurfaceDescriptor, caller of this function should check origin
+ * to make sure not corrupt others buffer
+ */
+android::sp<android::GraphicBuffer> GetGraphicBufferFrom(MaybeMagicGrallocBufferHandle aHandle);
+android::sp<android::GraphicBuffer> GetGraphicBufferFromDesc(SurfaceDescriptor aDesc);
+
+} // namespace layers
+} // namespace mozilla
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::layers::MagicGrallocBufferHandle> {
+  typedef mozilla::layers::MagicGrallocBufferHandle paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
+};
+
+template<>
+struct ParamTraits<mozilla::layers::GrallocBufferRef> {
+  typedef mozilla::layers::GrallocBufferRef paramType;
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
+};
+
+
+} // namespace IPC
+
+#endif  // mozilla_layers_ShadowLayerUtilsGralloc_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -0,0 +1,352 @@
+/* -*- 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 "mozilla/gfx/Logging.h"        // for gfxDebug
+#include "mozilla/layers/SharedBufferManagerChild.h"
+#include "mozilla/layers/SharedBufferManagerParent.h"
+#include "mozilla/Sprintf.h"            // for SprintfLiteral
+#include "mozilla/StaticPtr.h"          // for StaticRefPtr
+#include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
+#include "nsThreadUtils.h"              // for NS_IsMainThread
+
+#ifdef MOZ_WIDGET_GONK
+#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "SBMChild", ## args)
+#endif
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+// 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);
+
+  MOZ_ASSERT(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::ProcessId aOtherPid)
+{
+  // Bind the IPC channel to the shared buffer manager thread.
+  SharedBufferManagerChild::sSharedBufferManagerChildSingleton->Open(aTransport,
+                                                                     aOtherPid,
+                                                                     XRE_GetIOMessageLoop(),
+                                                                     ipc::ChildSide);
+
+}
+
+PSharedBufferManagerChild*
+SharedBufferManagerChild::StartUpInChildProcess(Transport* aTransport,
+                                                base::ProcessId aOtherPid)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+
+  sSharedBufferManagerChildThread = new base::Thread("BufferMgrChild");
+  if (!sSharedBufferManagerChildThread->Start()) {
+    return nullptr;
+  }
+
+  sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
+  sSharedBufferManagerChildSingleton->GetMessageLoop()->PostTask(
+    NewRunnableFunction(ConnectSharedBufferManagerInChildProcess,
+                        aTransport, aOtherPid));
+
+  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)
+{
+  MOZ_ASSERT(aThread, "SharedBufferManager needs a thread.");
+  if (sSharedBufferManagerChildSingleton != nullptr) {
+    return false;
+  }
+
+  sSharedBufferManagerChildThread = aThread;
+  if (!aThread->IsRunning()) {
+    aThread->Start();
+  }
+  sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
+  char thrname[128];
+  SprintfLiteral(thrname, "BufMgrParent#%d", base::Process::Current().pid());
+  sSharedBufferManagerParentSingleton = new SharedBufferManagerParent(
+    base::Process::Current().pid(), new base::Thread(thrname));
+  sSharedBufferManagerChildSingleton->ConnectAsync(sSharedBufferManagerParentSingleton);
+  return true;
+}
+
+void
+SharedBufferManagerChild::DestroyManager()
+{
+  MOZ_ASSERT(!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(
+    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(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 (aSize.width <= 0 || aSize.height <= 0) {
+    gfxDebug() << "Asking for gralloc of invalid size " << aSize.width << "x" << aSize.height;
+    return false;
+  }
+
+  if (InSharedBufferManagerChildThread()) {
+    return SharedBufferManagerChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aBuffer);
+  }
+
+  Monitor barrier("AllocSurfaceDescriptorGralloc Lock");
+  MonitorAutoLock autoMon(barrier);
+  bool done = false;
+
+  GetMessageLoop()->PostTask(
+    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)
+{
+  // These are protected functions, we can just assert and ask the caller to test
+  MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0);
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  mozilla::layers::MaybeMagicGrallocBufferHandle handle;
+  if (!SendAllocateGrallocBuffer(aSize, aFormat, aUsage, &handle)) {
+    return false;
+  }
+  if (handle.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle) {
+    return false;
+  }
+  *aHandle = handle.get_MagicGrallocBufferHandle().mRef;
+
+  {
+    MutexAutoLock lock(mBufferMutex);
+    MOZ_ASSERT(mBuffers.count(handle.get_MagicGrallocBufferHandle().mRef.mKey)==0);
+    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)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  NS_ASSERTION(aBuffer.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle, "We shouldn't try to do IPC with real buffer");
+  if (aBuffer.type() != mozilla::layers::MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
+    return;
+  }
+#endif
+
+  if (InSharedBufferManagerChildThread()) {
+    return SharedBufferManagerChild::DeallocGrallocBufferNow(aBuffer);
+  }
+
+  GetMessageLoop()->PostTask(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 try 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
+}
+
+void
+SharedBufferManagerChild::DropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aHandle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  int64_t bufferKey = -1;
+  if (aHandle.type() == mozilla::layers::MaybeMagicGrallocBufferHandle::TMagicGrallocBufferHandle) {
+    bufferKey = aHandle.get_MagicGrallocBufferHandle().mRef.mKey;
+  } else if (aHandle.type() == mozilla::layers::MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
+    bufferKey = aHandle.get_GrallocBufferRef().mKey;
+  } else {
+    return;
+  }
+
+  {
+    MutexAutoLock lock(mBufferMutex);
+    mBuffers.erase(bufferKey);
+  }
+#endif
+}
+
+bool SharedBufferManagerChild::RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aHandle)
+{
+  DropGrallocBuffer(aHandle);
+  return true;
+}
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+android::sp<android::GraphicBuffer>
+SharedBufferManagerChild::GetGraphicBuffer(int64_t key)
+{
+  MutexAutoLock lock(mBufferMutex);
+  if (mBuffers.count(key) == 0) {
+    printf_stderr("SharedBufferManagerChild::GetGraphicBuffer -- invalid key");
+    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,168 @@
+/* -*- 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 base
+
+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);
+
+  void
+  DropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aHandle);
+
+  virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& aHandle);
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
+#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<int64_t, 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,364 @@
+/* -*- 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 ProcessId
+#include "base/task.h"                  // for CancelableTask, DeleteTask, etc
+#include "base/thread.h"
+#include "mozilla/Sprintf.h"            // for SprintfLiteral
+#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/Transport.h"      // for Transport
+#include "mozilla/Sprintf.h"
+#include "mozilla/UniquePtr.h"          // for UniquePtr
+#include "mozilla/Unused.h"
+#include "nsIMemoryReporter.h"
+#ifdef MOZ_WIDGET_GONK
+#include "mozilla/LinuxUtils.h"
+#include "ui/PixelFormat.h"
+#endif
+#include "nsPrintfCString.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla::ipc;
+#ifdef MOZ_WIDGET_GONK
+using namespace android;
+#endif
+using std::map;
+
+namespace mozilla {
+namespace layers {
+
+map<base::ProcessId, SharedBufferManagerParent* > SharedBufferManagerParent::sManagers;
+StaticAutoPtr<Monitor> SharedBufferManagerParent::sManagerMonitor;
+uint64_t SharedBufferManagerParent::sBufferKey(0);
+
+#ifdef MOZ_WIDGET_GONK
+class GrallocReporter final : public nsIMemoryReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
+                            nsISupports* aData, bool aAnonymize) override
+  {
+    if (SharedBufferManagerParent::sManagerMonitor) {
+      SharedBufferManagerParent::sManagerMonitor->Lock();
+    }
+    map<base::ProcessId, SharedBufferManagerParent*>::iterator it;
+    for (it = SharedBufferManagerParent::sManagers.begin(); it != SharedBufferManagerParent::sManagers.end(); it++) {
+      base::ProcessId pid = it->first;
+      SharedBufferManagerParent *mgr = it->second;
+      if (!mgr) {
+        printf_stderr("GrallocReporter::CollectReports(): mgr is nullptr");
+        continue;
+      }
+
+      nsAutoCString pidName;
+      LinuxUtils::GetThreadName(pid, pidName);
+
+      MutexAutoLock lock(mgr->mLock);
+      std::map<int64_t, android::sp<android::GraphicBuffer> >::iterator buf_it;
+      for (buf_it = mgr->mBuffers.begin(); buf_it != mgr->mBuffers.end(); buf_it++) {
+        android::sp<android::GraphicBuffer> gb = buf_it->second;
+        int bpp = android::bytesPerPixel(gb->getPixelFormat());
+        int stride = gb->getStride();
+        int height = gb->getHeight();
+        int amount = bpp > 0
+          ? (stride * height * bpp)
+          // Special case for BSP specific formats (mainly YUV formats, count it as normal YUV buffer).
+          : (stride * height * 3 / 2);
+
+        nsPrintfCString gpath("gralloc/%s (pid=%d)/buffer(width=%d, height=%d, bpp=%d, stride=%d)",
+            pidName.get(), pid, gb->getWidth(), height, bpp, stride);
+
+        aHandleReport->Callback(
+          EmptyCString(), gpath, KIND_OTHER, UNITS_BYTES, amount,
+          NS_LITERAL_CSTRING(
+"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."),
+          aData);
+      }
+    }
+    if (SharedBufferManagerParent::sManagerMonitor) {
+      SharedBufferManagerParent::sManagerMonitor->Unlock();
+    }
+    return NS_OK;
+  }
+
+protected:
+  ~GrallocReporter() {}
+};
+
+NS_IMPL_ISUPPORTS(GrallocReporter, nsIMemoryReporter)
+#endif
+
+void InitGralloc() {
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+#ifdef MOZ_WIDGET_GONK
+  RegisterStrongMemoryReporter(new GrallocReporter());
+#endif
+}
+
+/**
+ * Task that deletes SharedBufferManagerParent on a specified thread.
+ */
+class DeleteSharedBufferManagerParentTask : public Runnable
+{
+public:
+    explicit DeleteSharedBufferManagerParentTask(UniquePtr<SharedBufferManagerParent> aSharedBufferManager)
+        : mSharedBufferManager(Move(aSharedBufferManager)) {
+    }
+    NS_IMETHOD Run() override { return NS_OK; }
+private:
+    UniquePtr<SharedBufferManagerParent> mSharedBufferManager;
+};
+
+SharedBufferManagerParent::SharedBufferManagerParent(base::ProcessId aOwner, base::Thread* aThread)
+  : mThread(aThread)
+  , mDestroyed(false)
+  , mLock("SharedBufferManagerParent.mLock")
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!sManagerMonitor) {
+    sManagerMonitor = new Monitor("Manager Monitor");
+  }
+
+  MonitorAutoLock lock(*sManagerMonitor.get());
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread");
+  if (!aThread->IsRunning()) {
+    aThread->Start();
+  }
+
+  if (sManagers.count(aOwner) != 0) {
+    printf_stderr("SharedBufferManagerParent already exists.");
+  }
+  mOwner = aOwner;
+  sManagers[aOwner] = this;
+}
+
+SharedBufferManagerParent::~SharedBufferManagerParent()
+{
+  MonitorAutoLock lock(*sManagerMonitor.get());
+  sManagers.erase(mOwner);
+  delete mThread;
+}
+
+void
+SharedBufferManagerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MutexAutoLock lock(mLock);
+  mDestroyed = true;
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  mBuffers.clear();
+#endif
+  RefPtr<DeleteSharedBufferManagerParentTask> task =
+    new DeleteSharedBufferManagerParentTask(UniquePtr<SharedBufferManagerParent>(this));
+  NS_DispatchToMainThread(task.forget());
+}
+
+static void
+ConnectSharedBufferManagerInParentProcess(SharedBufferManagerParent* aManager,
+                                          Transport* aTransport,
+                                          base::ProcessId aOtherPid)
+{
+  aManager->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ParentSide);
+}
+
+PSharedBufferManagerParent* SharedBufferManagerParent::Create(Transport* aTransport,
+                                                              ProcessId aOtherPid)
+{
+  base::Thread* thread = nullptr;
+  char thrname[128];
+  SprintfLiteral(thrname, "BufMgrParent#%d", aOtherPid);
+  thread = new base::Thread(thrname);
+
+  SharedBufferManagerParent* manager = new SharedBufferManagerParent(aOtherPid, thread);
+  if (!thread->IsRunning()) {
+    thread->Start();
+  }
+  thread->message_loop()->PostTask(NewRunnableFunction(ConnectSharedBufferManagerInParentProcess,
+                                                       manager, aTransport, aOtherPid));
+  return manager;
+}
+
+bool SharedBufferManagerParent::RecvAllocateGrallocBuffer(const IntSize& aSize, const uint32_t& aFormat, const uint32_t& aUsage, mozilla::layers::MaybeMagicGrallocBufferHandle* aHandle)
+{
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+
+  *aHandle = null_t();
+
+  if (aFormat == 0 || aUsage == 0) {
+    printf_stderr("SharedBufferManagerParent::RecvAllocateGrallocBuffer -- format and usage must be non-zero");
+    return false;
+  }
+
+  if (aSize.width <= 0 || aSize.height <= 0) {
+    printf_stderr("SharedBufferManagerParent::RecvAllocateGrallocBuffer -- requested gralloc buffer size is invalid");
+    return false;
+  }
+
+  // If the requested size is too big (i.e. exceeds the commonly used max GL texture size)
+  // then we risk OOMing the parent process. It's better to just deny the allocation and
+  // kill the child process, which is what the following code does.
+  // TODO: actually use GL_MAX_TEXTURE_SIZE instead of hardcoding 4096
+  if (aSize.width > 4096 || aSize.height > 4096) {
+    printf_stderr("SharedBufferManagerParent::RecvAllocateGrallocBuffer -- requested gralloc buffer is too big.");
+    return false;
+  }
+
+  sp<GraphicBuffer> outgoingBuffer = new GraphicBuffer(aSize.width, aSize.height, aFormat, aUsage);
+  if (!outgoingBuffer.get() || outgoingBuffer->initCheck() != NO_ERROR) {
+    printf_stderr("SharedBufferManagerParent::RecvAllocateGrallocBuffer -- gralloc buffer allocation failed");
+    return true;
+  }
+
+  int64_t bufferKey;
+  {
+    MonitorAutoLock lock(*sManagerMonitor.get());
+    bufferKey = ++sBufferKey; 
+  }
+  GrallocBufferRef ref;
+  ref.mOwner = mOwner;
+  ref.mKey = bufferKey;
+  *aHandle = MagicGrallocBufferHandle(outgoingBuffer, ref);
+
+  {
+    MutexAutoLock lock(mLock);
+    mBuffers[bufferKey] = 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!");
+  int64_t bufferKey = handle.get_GrallocBufferRef().mKey;
+  sp<GraphicBuffer> buf = GetGraphicBuffer(bufferKey);
+  MOZ_ASSERT(buf.get());
+  MutexAutoLock lock(mLock);
+  NS_ASSERTION(mBuffers.count(bufferKey) == 1, "No such buffer");
+  mBuffers.erase(bufferKey);
+
+  if(!buf.get()) {
+    printf_stderr("SharedBufferManagerParent::RecvDropGrallocBuffer -- invalid buffer key.");
+    return true;
+  }
+
+#endif
+  return true;
+}
+
+/*static*/
+void SharedBufferManagerParent::DropGrallocBufferSync(SharedBufferManagerParent* mgr, mozilla::layers::SurfaceDescriptor aDesc)
+{
+  mgr->DropGrallocBufferImpl(aDesc);
+}
+
+/*static*/
+void SharedBufferManagerParent::DropGrallocBuffer(ProcessId id, mozilla::layers::SurfaceDescriptor aDesc)
+{
+  if (aDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
+    return;
+  }
+
+  MonitorAutoLock lock(*sManagerMonitor.get());
+  SharedBufferManagerParent* mgr = SharedBufferManagerParent::GetInstance(id);
+  if (!mgr) {
+    return;
+  }
+
+  MutexAutoLock mgrlock(mgr->mLock);
+  if (mgr->mDestroyed) {
+    return;
+  }
+
+  if (PlatformThread::CurrentId() == mgr->mThread->thread_id()) {
+    MOZ_CRASH("GFX: SharedBufferManagerParent::DropGrallocBuffer should not be called on SharedBufferManagerParent thread");
+  } else {
+    mgr->mThread->message_loop()->PostTask(
+                                      NewRunnableFunction(&DropGrallocBufferSync, mgr, aDesc));
+  }
+  return;
+}
+
+void SharedBufferManagerParent::DropGrallocBufferImpl(mozilla::layers::SurfaceDescriptor aDesc)
+{
+  MutexAutoLock lock(mLock);
+  if (mDestroyed) {
+    return;
+  }
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  int64_t key = -1;
+  MaybeMagicGrallocBufferHandle handle;
+  if (aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc) {
+    handle = aDesc.get_SurfaceDescriptorGralloc().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) == 1, "No such buffer");
+  mBuffers.erase(key);
+  mozilla::Unused << SendDropGrallocBuffer(handle);
+#endif
+}
+
+MessageLoop* SharedBufferManagerParent::GetMessageLoop()
+{
+  return mThread->message_loop();
+}
+
+SharedBufferManagerParent* SharedBufferManagerParent::GetInstance(ProcessId id)
+{
+  NS_ASSERTION(sManagers.count(id) == 1, "No BufferManager for the process");
+  if (sManagers.count(id) == 1) {
+    return sManagers[id];
+  } else {
+    return nullptr;
+  }
+}
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+android::sp<android::GraphicBuffer>
+SharedBufferManagerParent::GetGraphicBuffer(int64_t key)
+{
+  MutexAutoLock lock(mLock);
+  if (mBuffers.count(key) == 1) {
+    return mBuffers[key];
+  } else {
+    // The buffer can be dropped, or invalid
+    printf_stderr("SharedBufferManagerParent::GetGraphicBuffer -- invalid key");
+    return nullptr;
+  }
+}
+
+android::sp<android::GraphicBuffer>
+SharedBufferManagerParent::GetGraphicBuffer(GrallocBufferRef aRef)
+{
+  MonitorAutoLock lock(*sManagerMonitor.get());
+  SharedBufferManagerParent* parent = GetInstance(aRef.mOwner);
+  if (!parent) {
+    return nullptr;
+  }
+  return parent->GetGraphicBuffer(aRef.mKey);
+}
+#endif
+
+} /* namespace layers */
+} /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/SharedBufferManagerParent.h
@@ -0,0 +1,110 @@
+/* -*- 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/Atomics.h"          // for Atomic
+#include "mozilla/layers/PSharedBufferManagerParent.h"
+#include "mozilla/StaticPtr.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 base
+
+namespace mozilla {
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+class Mutex;
+#endif
+
+namespace layers {
+
+class SharedBufferManagerParent : public PSharedBufferManagerParent
+{
+friend class GrallocReporter;
+public:
+  /**
+   * Create a SharedBufferManagerParent for child process, and link to the child side before leaving
+   */
+  static PSharedBufferManagerParent* Create(Transport* aTransport, ProcessId aOtherProcess);
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
+  static android::sp<android::GraphicBuffer> GetGraphicBuffer(GrallocBufferRef aRef);
+#endif
+  /**
+   * Create a SharedBufferManagerParent but do not open the link
+   */
+  SharedBufferManagerParent(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) override;
+
+  virtual bool RecvAllocateGrallocBuffer(const IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*) override;
+  virtual bool RecvDropGrallocBuffer(const mozilla::layers::MaybeMagicGrallocBufferHandle& handle) override;
+
+  /**
+   * Break the buffer's sharing state, decrease buffer reference for both side
+   */
+  static void DropGrallocBuffer(ProcessId id, mozilla::layers::SurfaceDescriptor aDesc);
+
+  MessageLoop* GetMessageLoop();
+
+protected:
+
+  /**
+   * 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);
+
+  /**
+   * Function for find the buffer owner, most buffer passing on IPC contains only owner/key pair.
+   * Use these function to access the real buffer.
+   * Caller needs to hold sManagerMonitor.
+   */
+  static SharedBufferManagerParent* GetInstance(ProcessId id);
+
+  /**
+   * All living SharedBufferManager instances used to find the buffer owner, and parent->child IPCs
+   */
+  static std::map<base::ProcessId, SharedBufferManagerParent*> sManagers;
+
+#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
+  /**
+   * Buffers owned by this SharedBufferManager pair
+   */
+  std::map<int64_t, android::sp<android::GraphicBuffer> > mBuffers;
+#endif
+  
+  base::ProcessId mOwner;
+  base::Thread* mThread;
+  bool mDestroyed;
+  Mutex mLock;
+
+  static uint64_t sBufferKey;
+  static StaticAutoPtr<Monitor> sManagerMonitor;
+};
+
+} /* namespace layers */
+} /* namespace mozilla */
+#endif /* SharedBufferManagerPARENT_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -0,0 +1,460 @@
+/* -*- Mode: C++; tab-width: 20; 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/. */
+
+#ifdef MOZ_WIDGET_GONK
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker
+#include "mozilla/layers/GrallocTextureClient.h"
+#include "mozilla/layers/TextureForwarder.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include "mozilla/layers/SharedBufferManagerChild.h"
+#include "gfx2DGlue.h"
+#include "gfxPrefs.h" // for gfxPrefs
+#include "SharedSurfaceGralloc.h"
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+#include <ui/Fence.h>
+#endif
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+using namespace android;
+
+static bool
+DisableGralloc(SurfaceFormat aFormat, const gfx::IntSize& aSizeHint)
+{
+  if (gfxPrefs::DisableGralloc()) {
+    return true;
+  }
+  if (aFormat == gfx::SurfaceFormat::A8) {
+    return true;
+  }
+
+  return false;
+}
+
+gfx::SurfaceFormat
+SurfaceFormatForPixelFormat(android::PixelFormat aFormat)
+{
+  switch (aFormat) {
+  case PIXEL_FORMAT_RGBA_8888:
+    return gfx::SurfaceFormat::R8G8B8A8;
+  case PIXEL_FORMAT_BGRA_8888:
+    return gfx::SurfaceFormat::B8G8R8A8;
+  case PIXEL_FORMAT_RGBX_8888:
+    return gfx::SurfaceFormat::R8G8B8X8;
+  case PIXEL_FORMAT_RGB_565:
+    return gfx::SurfaceFormat::R5G6B5_UINT16;
+  case HAL_PIXEL_FORMAT_YV12:
+    return gfx::SurfaceFormat::YUV;
+  default:
+    return gfx::SurfaceFormat::UNKNOWN;
+  }
+}
+
+bool
+IsGrallocRBSwapped(gfx::SurfaceFormat aFormat) {
+  switch (aFormat) {
+  case gfx::SurfaceFormat::B8G8R8A8:
+  case gfx::SurfaceFormat::B8G8R8X8:
+    return true;
+  default:
+    return false;
+  }
+}
+
+uint32_t GetAndroidFormat(gfx::SurfaceFormat aFormat)
+{
+  switch (aFormat) {
+  case gfx::SurfaceFormat::R8G8B8A8:
+  case gfx::SurfaceFormat::B8G8R8A8:
+    return android::PIXEL_FORMAT_RGBA_8888;
+  case gfx::SurfaceFormat::R8G8B8X8:
+  case gfx::SurfaceFormat::B8G8R8X8:
+    return android::PIXEL_FORMAT_RGBX_8888;
+  case gfx::SurfaceFormat::R5G6B5_UINT16:
+    return android::PIXEL_FORMAT_RGB_565;
+  case gfx::SurfaceFormat::YUV:
+    return HAL_PIXEL_FORMAT_YV12;
+  case gfx::SurfaceFormat::A8:
+    NS_WARNING("gralloc does not support SurfaceFormat::A8");
+  default:
+    NS_WARNING("Unsupported surface format");
+    return android::PIXEL_FORMAT_UNKNOWN;
+  }
+}
+
+GrallocTextureData::GrallocTextureData(MaybeMagicGrallocBufferHandle aGrallocHandle,
+                                       gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+                                       gfx::BackendType aMoz2DBackend)
+: mSize(aSize)
+, mFormat(aFormat)
+, mMoz2DBackend(aMoz2DBackend)
+, mGrallocHandle(aGrallocHandle)
+, mMappedBuffer(nullptr)
+, mMediaBuffer(nullptr)
+{
+  mGraphicBuffer = GetGraphicBufferFrom(aGrallocHandle);
+  MOZ_COUNT_CTOR(GrallocTextureData);
+}
+
+GrallocTextureData::~GrallocTextureData()
+{
+  MOZ_COUNT_DTOR(GrallocTextureData);
+}
+
+void
+GrallocTextureData::Deallocate(LayersIPCChannel* aAllocator)
+{
+  MOZ_ASSERT(aAllocator);
+  if (aAllocator && aAllocator->IPCOpen()) {
+    SharedBufferManagerChild::GetSingleton()->DeallocGrallocBuffer(mGrallocHandle);
+  }
+
+  mGrallocHandle = null_t();
+  mGraphicBuffer = nullptr;
+}
+
+void
+GrallocTextureData::Forget(LayersIPCChannel* aAllocator)
+{
+  MOZ_ASSERT(aAllocator);
+  if (aAllocator && aAllocator->IPCOpen()) {
+    SharedBufferManagerChild::GetSingleton()->DropGrallocBuffer(mGrallocHandle);
+  }
+
+  mGrallocHandle = null_t();
+  mGraphicBuffer = nullptr;
+}
+
+void
+GrallocTextureData::FillInfo(TextureData::Info& aInfo) const
+{
+  aInfo.size = mSize;
+  aInfo.format = mFormat;
+  aInfo.hasIntermediateBuffer = false;
+  aInfo.hasSynchronization = true;
+  aInfo.supportsMoz2D = true;
+  aInfo.canExposeMappedData = true;
+}
+
+bool
+GrallocTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
+{
+  aOutDescriptor = SurfaceDescriptorGralloc(mGrallocHandle, gfx::IsOpaque(mFormat));
+  return true;
+}
+
+void
+GrallocTextureData::WaitForFence(FenceHandle* aFence)
+{
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21 && ANDROID_VERSION >= 17
+   if (aFence && aFence->IsValid()) {
+     RefPtr<FenceHandle::FdObj> fdObj = aFence->GetAndResetFdObj();
+     android::sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
+#if ANDROID_VERSION == 17
+     fence->waitForever(1000, "GrallocTextureData::Lock");
+     // 1000 is what Android uses. It is a warning timeout in ms.
+     // This timeout was removed in ANDROID_VERSION 18.
+#else
+     fence->waitForever("GrallocTextureData::Lock");
+#endif
+   }
+#endif
+}
+
+bool
+GrallocTextureData::Lock(OpenMode aMode, FenceHandle* aReleaseFence)
+{
+  MOZ_ASSERT(!mMappedBuffer);
+
+  uint32_t usage = 0;
+  if (aMode & OpenMode::OPEN_READ) {
+    usage |= GRALLOC_USAGE_SW_READ_OFTEN;
+  }
+  if (aMode & OpenMode::OPEN_WRITE) {
+    usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+  }
+
+  void** mappedBufferPtr = reinterpret_cast<void**>(&mMappedBuffer);
+
+  int32_t rv = 0;
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+  if (aReleaseFence) {
+    RefPtr<FenceHandle::FdObj> fdObj = aReleaseFence->GetAndResetFdObj();
+    rv = mGraphicBuffer->lockAsync(usage, mappedBufferPtr,
+                                   fdObj->GetAndResetFd());
+  } else {
+    rv = mGraphicBuffer->lock(usage, mappedBufferPtr);
+  }
+#else
+  // older versions of android don't have lockAsync
+  WaitForFence(aReleaseFence);
+  rv = mGraphicBuffer->lock(usage, mappedBufferPtr);
+#endif
+
+  if (rv) {
+    mMappedBuffer = nullptr;
+    NS_WARNING("Couldn't lock graphic buffer");
+    return false;
+  }
+
+  return true;
+}
+
+void
+GrallocTextureData::Unlock()
+{
+  MOZ_ASSERT(mMappedBuffer);
+  mMappedBuffer = nullptr;
+  mGraphicBuffer->unlock();
+}
+
+already_AddRefed<gfx::DrawTarget>
+GrallocTextureData::BorrowDrawTarget()
+{
+  MOZ_ASSERT(mMappedBuffer);
+  if (!mMappedBuffer) {
+    return nullptr;
+  }
+  long byteStride = mGraphicBuffer->getStride() * BytesPerPixel(mFormat);
+  return gfxPlatform::CreateDrawTargetForData(mMappedBuffer, mSize,
+                                              byteStride, mFormat);
+}
+
+bool
+GrallocTextureData::BorrowMappedData(MappedTextureData& aMap)
+{
+  if (mFormat == gfx::SurfaceFormat::YUV || !mMappedBuffer) {
+    return false;
+  }
+
+  aMap.data = mMappedBuffer;
+  aMap.size = mSize;
+  aMap.stride = mGraphicBuffer->getStride() * BytesPerPixel(mFormat);
+  aMap.format = mFormat;
+
+  return true;
+}
+
+bool
+GrallocTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
+{
+  MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :(");
+
+  if (!mMappedBuffer) {
+    return false;
+  }
+
+  RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
+
+  if (!srcSurf) {
+    gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (GTC).";
+    return false;
+  }
+
+  gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat());
+  if (mSize != srcSurf->GetSize() || mFormat != srcSurf->GetFormat()) {
+    gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << format << " Other: " << srcSurf->GetSize() << " " << srcSurf->GetFormat();
+    return false;
+  }
+
+  long pixelStride = mGraphicBuffer->getStride();
+  long byteStride = pixelStride * BytesPerPixel(format);
+
+  DataSourceSurface::MappedSurface sourceMap;
+
+  if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
+    gfxCriticalError() << "Failed to map source surface for UpdateFromSurface (GTC).";
+    return false;
+  }
+
+  for (int y = 0; y < srcSurf->GetSize().height; y++) {
+    memcpy(mMappedBuffer + byteStride * y,
+           sourceMap.mData + sourceMap.mStride * y,
+           srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
+  }
+
+  srcSurf->Unmap();
+
+  return true;
+}
+
+// static
+GrallocTextureData*
+GrallocTextureData::Create(gfx::IntSize aSize, AndroidFormat aAndroidFormat,
+                           gfx::BackendType aMoz2dBackend, uint32_t aUsage,
+                           LayersIPCChannel* aAllocator)
+{
+  if (!aAllocator || !aAllocator->IPCOpen()) {
+    return nullptr;
+  }
+  gfx::SurfaceFormat format;
+  switch (aAndroidFormat) {
+  case android::PIXEL_FORMAT_RGBA_8888:
+    format = gfx::SurfaceFormat::B8G8R8A8;
+    break;
+  case android::PIXEL_FORMAT_BGRA_8888:
+    format = gfx::SurfaceFormat::B8G8R8A8;
+    break;
+  case android::PIXEL_FORMAT_RGBX_8888:
+    format = gfx::SurfaceFormat::B8G8R8X8;
+    break;
+  case android::PIXEL_FORMAT_RGB_565:
+    format = gfx::SurfaceFormat::R5G6B5_UINT16;
+    break;
+  case HAL_PIXEL_FORMAT_YV12:
+    format = gfx::SurfaceFormat::YUV;
+    break;
+  default:
+    format = gfx::SurfaceFormat::UNKNOWN;
+  }
+
+  if (DisableGralloc(format, aSize)) {
+    return nullptr;
+  }
+
+  MaybeMagicGrallocBufferHandle handle;
+  if (!SharedBufferManagerChild::GetSingleton()->AllocGrallocBuffer(aSize, aAndroidFormat, aUsage, &handle)) {
+    return nullptr;
+  }
+
+  sp<GraphicBuffer> graphicBuffer = GetGraphicBufferFrom(handle);
+  if (!graphicBuffer.get()) {
+    return nullptr;
+  }
+
+  if (graphicBuffer->initCheck() != NO_ERROR) {
+    return nullptr;
+  }
+
+  return new GrallocTextureData(handle, aSize, format, aMoz2dBackend);
+}
+
+// static
+GrallocTextureData*
+GrallocTextureData::CreateForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+                                     gfx::BackendType aMoz2dBackend,
+                                     LayersIPCChannel* aAllocator)
+{
+  if (DisableGralloc(aFormat, aSize)) {
+    return nullptr;
+  }
+
+#if ANDROID_VERSION <= 15
+  // Adreno 200 has a problem of drawing gralloc buffer width less than 64 and
+  // drawing gralloc buffer with a height 9px-16px.
+  // See Bug 983971.
+  // We only have this restriction in TextureClients that we'll use for drawing
+  // (not with WebGL for instance). Not sure why that's OK, but we have tests that
+  // rely on being able to create 32x32 webgl canvases with gralloc, so moving
+  // this check in DisableGralloc will break them.
+  if (aSize.width < 64 || aSize.height < 32) {
+    return nullptr;
+  }
+#endif
+
+  uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN |
+                   android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
+                   android::GraphicBuffer::USAGE_HW_TEXTURE;
+  auto data =  GrallocTextureData::Create(aSize, GetAndroidFormat(aFormat),
+                                          aMoz2dBackend, usage, aAllocator);
+
+  if (!data) {
+    return nullptr;
+  }
+
+  DebugOnly<gfx::SurfaceFormat> grallocFormat =
+    SurfaceFormatForPixelFormat(data->mGraphicBuffer->getPixelFormat());
+  // mFormat may be different from the format the graphic buffer reports if we
+  // swap the R and B channels but we should always have at least the same bytes
+  // per pixel!
+  MOZ_ASSERT(BytesPerPixel(data->mFormat) == BytesPerPixel(grallocFormat));
+
+  return data;
+}
+
+TextureFlags
+GrallocTextureData::GetTextureFlags() const
+{
+  if (IsGrallocRBSwapped(mFormat)) {
+    return TextureFlags::RB_SWAPPED;
+  }
+  return TextureFlags::NO_FLAGS;
+}
+
+
+// static
+GrallocTextureData*
+GrallocTextureData::CreateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize,
+                                   LayersIPCChannel* aAllocator)
+{
+  MOZ_ASSERT(aYSize.width == aCbCrSize.width * 2);
+  MOZ_ASSERT(aYSize.height == aCbCrSize.height * 2);
+  return GrallocTextureData::Create(aYSize, HAL_PIXEL_FORMAT_YV12,
+                                    gfx::BackendType::NONE,
+                                    android::GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                    aAllocator);
+}
+
+// static
+GrallocTextureData*
+GrallocTextureData::CreateForGLRendering(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+                                         LayersIPCChannel* aAllocator)
+{
+  if (aFormat == gfx::SurfaceFormat::YUV) {
+    return nullptr;
+  }
+  uint32_t usage = android::GraphicBuffer::USAGE_HW_RENDER |
+                   android::GraphicBuffer::USAGE_HW_TEXTURE;
+  return GrallocTextureData::Create(aSize, GetAndroidFormat(aFormat),
+                                    gfx::BackendType::NONE, usage, aAllocator);
+}
+
+// static
+already_AddRefed<TextureClient>
+GrallocTextureData::TextureClientFromSharedSurface(gl::SharedSurface* abstractSurf,
+                                                   TextureFlags flags)
+{
+  auto surf = gl::SharedSurface_Gralloc::Cast(abstractSurf);
+
+  RefPtr<TextureClient> ret = surf->GetTextureClient();
+
+  TextureFlags mask = TextureFlags::ORIGIN_BOTTOM_LEFT |
+                      TextureFlags::RB_SWAPPED |
+                      TextureFlags::NON_PREMULTIPLIED;
+  TextureFlags required = flags & mask;
+  TextureFlags present = ret->GetFlags() & mask;
+
+  if (present != required) {
+    printf_stderr("Present flags: 0x%x. Required: 0x%x.\n",
+                  (uint32_t)present,
+                  (uint32_t)required);
+    MOZ_CRASH("Flag requirement mismatch.");
+  }
+  return ret.forget();
+}
+
+TextureData*
+GrallocTextureData::CreateSimilar(LayersIPCChannel* aAllocator,
+                                  LayersBackend aLayersBackend,
+                                  TextureFlags aFlags,
+                                  TextureAllocationFlags aAllocFlags) const
+{
+  if (mFormat == gfx::SurfaceFormat::YUV) {
+    return GrallocTextureData::CreateForYCbCr(mSize, mSize*2, aAllocator);
+  } else {
+    return GrallocTextureData::CreateForDrawing(mSize, mFormat, mMoz2DBackend, aAllocator);
+  }
+}
+
+} // namesapace layers
+} // namesapace mozilla
+
+#endif // MOZ_WIDGET_GONK
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 20; 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 MOZILLA_GFX_GRALLOCTEXTURECLIENT_H
+#define MOZILLA_GFX_GRALLOCTEXTURECLIENT_H
+#ifdef MOZ_WIDGET_GONK
+
+#include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/FenceUtils.h" // for FenceHandle
+#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include <ui/GraphicBuffer.h>
+
+
+namespace android {
+class MediaBuffer;
+};
+
+namespace mozilla {
+namespace gl {
+class SharedSurface;
+}
+
+namespace layers {
+
+/// A TextureData implementation based on android::GraphicBuffer (also referred to
+/// as "gralloc").
+///
+/// Gralloc lets us map texture data in memory (accessible through pointers)
+/// and also use it directly as an OpenGL texture without the cost of texture
+/// uploads.
+/// Gralloc buffers can also be shared accros processes.
+///
+/// More info about Gralloc here: https://wiki.mozilla.org/Platform/GFX/Gralloc
+///
+/// This is only used in Firefox OS
+class GrallocTextureData : public TextureData {
+public:
+  typedef uint32_t AndroidFormat;
+
+  virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
+
+  virtual bool Lock(OpenMode aMode, FenceHandle* aFence) override;
+
+  virtual void Unlock() override;
+
+  virtual void FillInfo(TextureData::Info& aInfo) const override;
+
+  virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
+
+  virtual bool BorrowMappedData(MappedTextureData& aMap) override;
+
+  virtual void Deallocate(LayersIPCChannel*) override;
+
+  virtual void Forget(LayersIPCChannel*) override;
+
+  static GrallocTextureData* CreateForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+                                              gfx::BackendType aMoz2dBackend,
+                                              LayersIPCChannel* aAllocator);
+
+  static GrallocTextureData* CreateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize,
+                                            LayersIPCChannel* aAllocator);
+
+  static GrallocTextureData* CreateForGLRendering(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+                                                  LayersIPCChannel* aAllocator);
+
+  static GrallocTextureData* Create(gfx::IntSize aSize, AndroidFormat aFormat,
+                                    gfx::BackendType aMoz2DBackend, uint32_t aUsage,
+                                    LayersIPCChannel* aAllocator);
+
+
+  static already_AddRefed<TextureClient>
+  TextureClientFromSharedSurface(gl::SharedSurface* abstractSurf, TextureFlags flags);
+
+  virtual TextureData*
+  CreateSimilar(LayersIPCChannel* aAllocator,
+                LayersBackend aLayersBackend,
+                TextureFlags aFlags = TextureFlags::DEFAULT,
+                TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
+
+  // use TextureClient's default implementation
+  virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
+
+  /// Hold android::MediaBuffer.
+  /// MediaBuffer needs to be add refed to keep MediaBuffer alive while the texture
+  /// is in use.
+  ///
+  /// TODO - ideally we should be able to put the MediaBuffer in the texture's
+  /// constructor and not expose these methods.
+  void SetMediaBuffer(android::MediaBuffer* aMediaBuffer) { mMediaBuffer = aMediaBuffer; }
+  android::MediaBuffer* GetMediaBuffer() { return mMediaBuffer; }
+
+  android::sp<android::GraphicBuffer> GetGraphicBuffer() { return mGraphicBuffer; }
+
+  virtual void WaitForFence(FenceHandle* aFence) override;
+
+  ~GrallocTextureData();
+
+  virtual TextureFlags GetTextureFlags() const override;
+
+  virtual GrallocTextureData* AsGrallocTextureData() { return this; }
+
+protected:
+  GrallocTextureData(MaybeMagicGrallocBufferHandle aGrallocHandle,
+                     gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
+                     gfx::BackendType aMoz2DBackend);
+
+  gfx::IntSize mSize;
+  gfx::SurfaceFormat mFormat;
+  gfx::BackendType mMoz2DBackend;
+
+  MaybeMagicGrallocBufferHandle mGrallocHandle;
+  android::sp<android::GraphicBuffer> mGraphicBuffer;
+
+  // Points to a mapped gralloc buffer between calls to lock and unlock.
+  // Should be null outside of the lock-unlock pair.
+  uint8_t* mMappedBuffer;
+
+  android::MediaBuffer* mMediaBuffer;
+};
+
+gfx::SurfaceFormat SurfaceFormatForPixelFormat(android::PixelFormat aFormat);
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZ_WIDGET_GONK
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -0,0 +1,480 @@
+/* -*- Mode: C++; tab-width: 20; 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/. */
+
+#include "base/process.h"
+#include "GLContext.h"
+#include "gfx2DGlue.h"
+#include <ui/GraphicBuffer.h>
+#include "GrallocImages.h"  // for GrallocImage
+#include "GLLibraryEGL.h"   // for GLLibraryEGL
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/DataSurfaceHelpers.h"
+#include "mozilla/layers/GrallocTextureHost.h"
+#include "mozilla/layers/SharedBufferManagerParent.h"
+#include "EGLImageHelpers.h"
+#include "GLReadTexImageHelper.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace android;
+using namespace mozilla::gl;
+
+static gfx::SurfaceFormat
+SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
+                                   TextureFlags aFlags)
+{
+  bool swapRB = bool(aFlags & TextureFlags::RB_SWAPPED);
+  switch (aFormat) {
+  case android::PIXEL_FORMAT_BGRA_8888:
+    return swapRB ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8A8;
+  case android::PIXEL_FORMAT_RGBA_8888:
+    return swapRB ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::R8G8B8A8;
+  case android::PIXEL_FORMAT_RGBX_8888:
+    return swapRB ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::R8G8B8X8;
+  case android::PIXEL_FORMAT_RGB_565:
+    return gfx::SurfaceFormat::R5G6B5_UINT16;
+  case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+  case HAL_PIXEL_FORMAT_YCbCr_422_I:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+  case HAL_PIXEL_FORMAT_YV12:
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+#endif
+    return gfx::SurfaceFormat::R8G8B8A8; // yup, use SurfaceFormat::R8G8B8A8 even though it's a YUV texture. This is an external texture.
+  default:
+    if (aFormat >= 0x100 && aFormat <= 0x1FF) {
+      // Reserved range for HAL specific formats.
+      return gfx::SurfaceFormat::R8G8B8A8;
+    } else {
+      // This is not super-unreachable, there's a bunch of hypothetical pixel
+      // formats we don't deal with.
+      // We only want to abort in debug builds here, since if we crash here
+      // we'll take down the compositor process and thus the phone. This seems
+      // like undesirable behaviour. We'd rather have a subtle artifact.
+      printf_stderr(" xxxxx unknow android format %i\n", (int)aFormat);
+      MOZ_ASSERT(false, "Unknown Android pixel format.");
+      return gfx::SurfaceFormat::UNKNOWN;
+    }
+  }
+}
+
+static GLenum
+TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat)
+{
+  switch (aFormat) {
+  case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+  case HAL_PIXEL_FORMAT_YCbCr_422_I:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+  case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+  case HAL_PIXEL_FORMAT_YV12:
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+#endif
+    return LOCAL_GL_TEXTURE_EXTERNAL;
+  case android::PIXEL_FORMAT_BGRA_8888:
+  case android::PIXEL_FORMAT_RGBA_8888:
+  case android::PIXEL_FORMAT_RGBX_8888:
+  case android::PIXEL_FORMAT_RGB_565:
+    return LOCAL_GL_TEXTURE_2D;
+  default:
+    if (aFormat >= 0x100 && aFormat <= 0x1FF) {
+      // Reserved range for HAL specific formats.
+      return LOCAL_GL_TEXTURE_EXTERNAL;
+    } else {
+      // This is not super-unreachable, there's a bunch of hypothetical pixel
+      // formats we don't deal with.
+      // We only want to abort in debug builds here, since if we crash here
+      // we'll take down the compositor process and thus the phone. This seems
+      // like undesirable behaviour. We'd rather have a subtle artifact.
+      MOZ_ASSERT(false, "Unknown Android pixel format.");
+      return LOCAL_GL_TEXTURE_EXTERNAL;
+    }
+  }
+}
+
+GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags,
+                                             const SurfaceDescriptorGralloc& aDescriptor)
+  : TextureHost(aFlags)
+  , mGrallocHandle(aDescriptor)
+  , mSize(0, 0)
+  , mCropSize(0, 0)
+  , mFormat(gfx::SurfaceFormat::UNKNOWN)
+  , mEGLImage(EGL_NO_IMAGE)
+  , mIsOpaque(aDescriptor.isOpaque())
+{
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+  MOZ_ASSERT(graphicBuffer);
+
+  if (graphicBuffer) {
+    mFormat =
+      SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(),
+                                         aFlags & TextureFlags::RB_SWAPPED);
+    mSize = gfx::IntSize(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+    mCropSize = mSize;
+  } else {
+    printf_stderr("gralloc buffer is nullptr\n");
+  }
+}
+
+GrallocTextureHostOGL::~GrallocTextureHostOGL()
+{
+  DestroyEGLImage();
+}
+
+void
+GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
+{
+  mCompositor = AssertGLCompositor(aCompositor);
+  if (mGLTextureSource) {
+    mGLTextureSource->SetCompositor(mCompositor);
+  }
+
+  if (mCompositor && aCompositor != mCompositor) {
+    DestroyEGLImage();
+  }
+}
+
+bool
+GrallocTextureHostOGL::Lock()
+{
+  return IsValid();
+}
+
+void
+GrallocTextureHostOGL::Unlock()
+{
+  // Unlock is done internally by binding the texture to another gralloc buffer
+}
+
+bool
+GrallocTextureHostOGL::IsValid() const
+{
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+  return graphicBuffer != nullptr;
+}
+
+gfx::SurfaceFormat
+GrallocTextureHostOGL::GetFormat() const
+{
+  return mFormat;
+}
+
+void
+GrallocTextureHostOGL::DeallocateSharedData()
+{
+  if (mGLTextureSource) {
+    mGLTextureSource = nullptr;
+  }
+
+  DestroyEGLImage();
+
+  if (mGrallocHandle.buffer().type() != MaybeMagicGrallocBufferHandle::Tnull_t) {
+    MaybeMagicGrallocBufferHandle handle = mGrallocHandle.buffer();
+    base::ProcessId owner;
+    if (handle.type() == MaybeMagicGrallocBufferHandle::TGrallocBufferRef) {
+      owner = handle.get_GrallocBufferRef().mOwner;
+    }
+    else {
+      owner = handle.get_MagicGrallocBufferHandle().mRef.mOwner;
+    }
+
+    SharedBufferManagerParent::DropGrallocBuffer(owner, mGrallocHandle);
+  }
+}
+
+void
+GrallocTextureHostOGL::ForgetSharedData()
+{
+  if (mGLTextureSource) {
+    mGLTextureSource = nullptr;
+  }
+}
+
+void
+GrallocTextureHostOGL::DeallocateDeviceData()
+{
+  if (mGLTextureSource) {
+    mGLTextureSource = nullptr;
+  }
+  DestroyEGLImage();
+}
+
+LayerRenderState
+GrallocTextureHostOGL::GetRenderState()
+{
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+
+  if (graphicBuffer) {
+    LayerRenderStateFlags flags = LayerRenderStateFlags::LAYER_RENDER_STATE_DEFAULT;
+    if (mIsOpaque) {
+      flags |= LayerRenderStateFlags::OPAQUE;
+    }
+    if (mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
+      flags |= LayerRenderStateFlags::ORIGIN_BOTTOM_LEFT;
+    }
+    if (mFlags & TextureFlags::RB_SWAPPED) {
+      flags |= LayerRenderStateFlags::FORMAT_RB_SWAP;
+    }
+    return LayerRenderState(graphicBuffer,
+                            mCropSize,
+                            flags,
+                            this);
+  }
+
+  return LayerRenderState();
+}
+
+already_AddRefed<gfx::DataSourceSurface>
+GrallocTextureHostOGL::GetAsSurface() {
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+  if (!graphicBuffer) {
+    return nullptr;
+  }
+  uint8_t* grallocData;
+  int32_t rv = graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
+  if (rv) {
+    return nullptr;
+  }
+  RefPtr<gfx::DataSourceSurface> grallocTempSurf =
+    gfx::Factory::CreateWrappingDataSourceSurface(grallocData,
+                                                  graphicBuffer->getStride() * android::bytesPerPixel(graphicBuffer->getPixelFormat()),
+                                                  GetSize(), GetFormat());
+  if (!grallocTempSurf) {
+    graphicBuffer->unlock();
+    return nullptr;
+  }
+  RefPtr<gfx::DataSourceSurface> surf = CreateDataSourceSurfaceByCloning(grallocTempSurf);
+
+  graphicBuffer->unlock();
+
+  return surf.forget();
+}
+
+void
+GrallocTextureHostOGL::UnbindTextureSource()
+{
+  TextureHost::UnbindTextureSource();
+  // Clear the reference to the TextureSource (if any), because we know that
+  // another TextureHost is being bound to the TextureSource. This means that
+  // we will have to re-do gl->fEGLImageTargetTexture2D next time we go through
+  // BindTextureSource (otherwise we would have skipped it).
+  // Note that this doesn't "unlock" the gralloc buffer or force it to be
+  // detached, Although decreasing the refcount of the TextureSource may lead
+  // to the gl handle being destroyed, which would unlock the gralloc buffer.
+  // That said, this method is called before another TextureHost attaches to the
+  // TextureSource, which has the effect of unlocking the gralloc buffer. So when
+  // this is called we know we are going to be unlocked soon.
+  mGLTextureSource = nullptr;
+}
+
+GLenum GetTextureTarget(gl::GLContext* aGL, android::PixelFormat aFormat) {
+  MOZ_ASSERT(aGL);
+  if (aGL->Renderer() == gl::GLRenderer::SGX530 ||
+      aGL->Renderer() == gl::GLRenderer::SGX540) {
+    // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will
+    // result in black pixels when trying to draw from bound textures.
+    // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on
+    // performance.
+    // See Bug 950050.
+    return LOCAL_GL_TEXTURE_EXTERNAL;
+  } else {
+    return TextureTargetForAndroidPixelFormat(aFormat);
+  }
+}
+
+void
+GrallocTextureHostOGL::DestroyEGLImage()
+{
+  // Only called when we want to get rid of the gralloc buffer, usually
+  // around the end of life of the TextureHost.
+  if (mEGLImage != EGL_NO_IMAGE && GetGLContext()) {
+    EGLImageDestroy(GetGLContext(), mEGLImage);
+    mEGLImage = EGL_NO_IMAGE;
+  }
+}
+
+void
+GrallocTextureHostOGL::PrepareTextureSource(CompositableTextureSourceRef& aTextureSource)
+{
+  // This happens during the layers transaction.
+  // All of the gralloc magic goes here. The only thing that happens externally
+  // and that is good to keep in mind is that when the TextureSource is deleted,
+  // it destroys its gl texture handle which is important for genlock.
+
+  // If this TextureHost's mGLTextureSource member is non-null, it means we are
+  // still bound to the TextureSource, in which case we can skip the driver
+  // overhead of binding the texture again (fEGLImageTargetTexture2D)
+  // As a result, if the TextureHost is used with several CompositableHosts,
+  // it will be bound to only one TextureSource, and we'll do the driver work
+  // only once, which is great. This means that all of the compositables that
+  // use this TextureHost will keep a reference to this TextureSource at least
+  // for the duration of this frame.
+
+  // If the compositable already has a TextureSource (the aTextureSource parameter),
+  // that is compatible and is not in use by several compositable, we try to
+  // attach to it. This has the effect of unlocking the previous TextureHost that
+  // we attached to the TextureSource (the previous frame)
+
+  // If the TextureSource used by the compositable is also used by other
+  // compositables (see NumCompositableRefs), we have to create a new TextureSource,
+  // because otherwise we would be modifying the content of every layer that uses
+  // the TextureSource in question, even thoug they don't use this TextureHost.
+
+  android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
+
+  MOZ_ASSERT(graphicBuffer);
+  if (!graphicBuffer) {
+    mGLTextureSource = nullptr;
+    return;
+  }
+
+  if (mGLTextureSource && !mGLTextureSource->IsValid()) {
+    mGLTextureSource = nullptr;
+  }
+
+  if (mGLTextureSource) {
+    // We are already attached to a TextureSource, nothing to do except tell
+    // the compositable to use it.
+    aTextureSource = mGLTextureSource.get();
+    return;
+  }
+
+  gl::GLContext* gl = GetGLContext();
+  if (!gl || !gl->MakeCurrent()) {
+    mGLTextureSource = nullptr;
+    return;
+  }
+
+  if (mEGLImage == EGL_NO_IMAGE) {
+    gfx::IntSize cropSize(0, 0);
+    if (mCropSize != mSize) {
+      cropSize = mCropSize;
+    }
+    // Should only happen the first time.
+    mEGLImage = EGLImageCreateFromNativeBuffer(gl, graphicBuffer->getNativeBuffer(), cropSize);
+  }
+
+  GLenum textureTarget = GetTextureTarget(gl, graphicBuffer->getPixelFormat());
+
+  GLTextureSource* glSource = aTextureSource.get() ?
+    aTextureSource->AsSourceOGL()->AsGLTextureSource() : nullptr;
+
+  bool shouldCreateTextureSource = !glSource  || !glSource->IsValid()
+                                 || glSource->NumCompositableRefs() > 1
+                                 || glSource->GetTextureTarget() != textureTarget;
+
+  if (shouldCreateTextureSource) {
+    GLuint textureHandle;
+    gl->fGenTextures(1, &textureHandle);
+    gl->fBindTexture(textureTarget, textureHandle);
+    gl->fTexParameteri(textureTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+    gl->fTexParameteri(textureTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+    gl->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
+
+    mGLTextureSource = new GLTextureSource(mCompositor, textureHandle, textureTarget,
+                                           mSize, mFormat);
+    aTextureSource = mGLTextureSource.get();
+  } else {
+    gl->fBindTexture(textureTarget, glSource->GetTextureHandle());
+
+    gl->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
+    glSource->SetSize(mSize);
+    glSource->SetFormat(mFormat);
+    mGLTextureSource = glSource;
+  }
+}
+
+void
+GrallocTextureHostOGL::WaitAcquireFenceHandleSyncComplete()
+{
+  if (!mAcquireFenceHandle.IsValid()) {
+    return;
+  }
+
+  RefPtr<FenceHandle::FdObj> fence = mAcquireFenceHandle.GetAndResetFdObj();
+  int fenceFd = fence->GetAndResetFd();
+
+  EGLint attribs[] = {
+              LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+              LOCAL_EGL_NONE
+          };
+
+  EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(),
+                                         LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                         attribs);
+  if (!sync) {
+    NS_WARNING("failed to create native fence sync");
+    return;
+  }
+
+  // Wait sync complete with timeout.
+  // If a source of the fence becomes invalid because of error,
+  // fene complete is not signaled. See Bug 1061435.
+  EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(),
+                                              sync,
+                                              0,
+                                              400000000 /*400 msec*/);
+  if (status != LOCAL_EGL_CONDITION_SATISFIED) {
+    NS_ERROR("failed to wait native fence sync");
+  }
+  MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) );
+}
+
+void
+GrallocTextureHostOGL::SetCropRect(nsIntRect aCropRect)
+{
+  MOZ_ASSERT(aCropRect.TopLeft() == gfx::IntPoint(0, 0));
+  MOZ_ASSERT(!aCropRect.IsEmpty());
+  MOZ_ASSERT(aCropRect.width <= mSize.width);
+  MOZ_ASSERT(aCropRect.height <= mSize.height);
+
+  gfx::IntSize cropSize(aCropRect.width, aCropRect.height);
+  if (mCropSize == cropSize) {
+    return;
+  }
+
+  mCropSize = cropSize;
+  mGLTextureSource = nullptr;
+}
+
+bool
+GrallocTextureHostOGL::BindTextureSource(CompositableTextureSourceRef& aTextureSource)
+{
+  // This happens at composition time.
+
+  // If mGLTextureSource is null it means PrepareTextureSource failed.
+  if (!mGLTextureSource) {
+    return false;
+  }
+
+  // If Prepare didn't fail, we expect our TextureSource to be the same as aTextureSource,
+  // otherwise it means something has fiddled with the TextureSource between Prepare and
+  // now.
+  MOZ_ASSERT(mGLTextureSource == aTextureSource);
+  aTextureSource = mGLTextureSource.get();
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+  // Wait until it's ready.
+  WaitAcquireFenceHandleSyncComplete();
+#endif
+  return true;
+}
+
+FenceHandle
+GrallocTextureHostOGL::GetCompositorReleaseFence()
+{
+  if (!mCompositor) {
+    return FenceHandle();
+  }
+  return mCompositor->GetReleaseFence();
+}
+
+
+} // namepsace layers
+} // namepsace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/GrallocTextureHost.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 20; 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 MOZILLA_GFX_GRALLOCTEXTUREHOST_H
+#define MOZILLA_GFX_GRALLOCTEXTUREHOST_H
+#ifdef MOZ_WIDGET_GONK
+
+#include "mozilla/layers/CompositorOGL.h"
+#include "mozilla/layers/TextureHostOGL.h"
+#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include <ui/GraphicBuffer.h>
+
+namespace mozilla {
+namespace layers {
+
+class GrallocTextureHostOGL : public TextureHost
+{
+  friend class GrallocBufferActor;
+public:
+  GrallocTextureHostOGL(TextureFlags aFlags,
+                        const SurfaceDescriptorGralloc& aDescriptor);
+
+  virtual ~GrallocTextureHostOGL();
+
+  virtual bool Lock() override;
+
+  virtual void Unlock() override;
+
+  virtual void SetCompositor(Compositor* aCompositor) override;
+
+  virtual Compositor* GetCompositor() override { return mCompositor; }
+
+  virtual void DeallocateSharedData() override;
+
+  virtual void ForgetSharedData() override;
+
+  virtual void DeallocateDeviceData() override;
+
+  virtual gfx::SurfaceFormat GetFormat() const;
+
+  virtual gfx::IntSize GetSize() const override { return mCropSize; }
+
+  virtual LayerRenderState GetRenderState() override;
+
+  virtual void PrepareTextureSource(CompositableTextureSourceRef& aTextureSource) override;
+
+  virtual bool BindTextureSource(CompositableTextureSourceRef& aTextureSource) override;
+
+  virtual void UnbindTextureSource() override;
+
+  virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
+
+  virtual void WaitAcquireFenceHandleSyncComplete() override;
+
+  virtual void SetCropRect(nsIntRect aCropRect) override;
+
+  bool IsValid() const;
+
+  virtual const char* Name() override { return "GrallocTextureHostOGL"; }
+
+  gl::GLContext* GetGLContext() const { return mCompositor ? mCompositor->gl() : nullptr; }
+
+  virtual bool NeedsFenceHandle() override
+  {
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+    return true;
+#else
+    return false;
+#endif
+  }
+
+  virtual FenceHandle GetCompositorReleaseFence() override;
+
+  virtual GrallocTextureHostOGL* AsGrallocTextureHostOGL() override { return this; }
+
+private:
+  void DestroyEGLImage();
+
+  SurfaceDescriptorGralloc mGrallocHandle;
+  RefPtr<GLTextureSource> mGLTextureSource;
+  RefPtr<CompositorOGL> mCompositor;
+  // Size reported by the GraphicBuffer
+  gfx::IntSize mSize;
+  // Size reported by TextureClient, can be different in some cases (video?),
+  // used by LayerRenderState.
+  gfx::IntSize mCropSize;
+  gfx::SurfaceFormat mFormat;
+  EGLImage mEGLImage;
+  bool mIsOpaque;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
+#endif
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/ChromeCast.java
@@ -0,0 +1,509 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko;
+
+import java.io.IOException;
+
+import org.mozilla.gecko.util.EventCallback;
+import org.json.JSONObject;
+import org.json.JSONException;
+
+import com.google.android.gms.cast.Cast.MessageReceivedCallback;
+import com.google.android.gms.cast.ApplicationMetadata;
+import com.google.android.gms.cast.Cast;
+import com.google.android.gms.cast.Cast.ApplicationConnectionResult;
+import com.google.android.gms.cast.CastDevice;
+import com.google.android.gms.cast.CastMediaControlIntent;
+import com.google.android.gms.cast.MediaInfo;
+import com.google.android.gms.cast.MediaMetadata;
+import com.google.android.gms.cast.MediaStatus;
+import com.google.android.gms.cast.RemoteMediaPlayer;
+import com.google.android.gms.cast.RemoteMediaPlayer.MediaChannelResult;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.common.api.ResultCallback;
+import com.google.android.gms.common.api.Status;
+import com.google.android.gms.common.GooglePlayServicesUtil;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
+
+/* Implementation of GeckoMediaPlayer for talking to ChromeCast devices */
+class ChromeCast implements GeckoMediaPlayer {
+    private static final boolean SHOW_DEBUG = false;
+
+    static final String MIRROR_RECEIVER_APP_ID = "08FF1091";
+
+    private final Context context;
+    private final RouteInfo route;
+    private GoogleApiClient apiClient;
+    private RemoteMediaPlayer remoteMediaPlayer;
+    private final boolean canMirror;
+    private String mSessionId;
+    private MirrorChannel mMirrorChannel;
+    private boolean mApplicationStarted = false;
+
+    // EventCallback which is actually a GeckoEventCallback is sometimes being invoked more
+    // than once. That causes the IllegalStateException to be thrown. To prevent a crash,
+    // catch the exception and report it as an error to the log.
+    private static void sendSuccess(final EventCallback callback, final String msg) {
+        try {
+            callback.sendSuccess(msg);
+        } catch (final IllegalStateException e) {
+            Log.e(LOGTAG, "Attempting to invoke callback.sendSuccess more than once.", e);
+        }
+    }
+
+    private static void sendError(final EventCallback callback, final String msg) {
+        try {
+            callback.sendError(msg);
+        } catch (final IllegalStateException e) {
+            Log.e(LOGTAG, "Attempting to invoke callback.sendError more than once.", e);
+        }
+    }
+
+    // Callback to start playback of a url on a remote device
+    private class VideoPlayCallback implements ResultCallback<ApplicationConnectionResult>,
+                                               RemoteMediaPlayer.OnStatusUpdatedListener,
+                                               RemoteMediaPlayer.OnMetadataUpdatedListener {
+        private final String url;
+        private final String type;
+        private final String title;
+        private final EventCallback callback;
+
+        public VideoPlayCallback(String url, String type, String title, EventCallback callback) {
+            this.url = url;
+            this.type = type;
+            this.title = title;
+            this.callback = callback;
+        }
+
+        @Override
+        public void onStatusUpdated() {
+            MediaStatus mediaStatus = remoteMediaPlayer.getMediaStatus();
+
+            switch (mediaStatus.getPlayerState()) {
+            case MediaStatus.PLAYER_STATE_PLAYING:
+                GeckoAppShell.notifyObservers("MediaPlayer:Playing", null);
+                break;
+            case MediaStatus.PLAYER_STATE_PAUSED:
+                GeckoAppShell.notifyObservers("MediaPlayer:Paused", null);
+                break;
+            case MediaStatus.PLAYER_STATE_IDLE:
+                // TODO: Do we want to shutdown when there are errors?
+                if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED) {
+                    GeckoAppShell.notifyObservers("Casting:Stop", null);
+                }
+                break;
+            default:
+                // TODO: Do we need to handle other status such as buffering / unknown?
+                break;
+            }
+        }
+
+        @Override
+        public void onMetadataUpdated() { }
+
+        @Override
+        public void onResult(ApplicationConnectionResult result) {
+            Status status = result.getStatus();
+            debug("ApplicationConnectionResultCallback.onResult: statusCode" + status.getStatusCode());
+            if (status.isSuccess()) {
+                remoteMediaPlayer = new RemoteMediaPlayer();
+                remoteMediaPlayer.setOnStatusUpdatedListener(this);
+                remoteMediaPlayer.setOnMetadataUpdatedListener(this);
+                mSessionId = result.getSessionId();
+                if (!verifySession(callback)) {
+                    return;
+                }
+
+                try {
+                    Cast.CastApi.setMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace(), remoteMediaPlayer);
+                } catch (IOException e) {
+                    debug("Exception while creating media channel", e);
+                }
+
+                startPlayback();
+            } else {
+                sendError(callback, status.toString());
+            }
+        }
+
+        private void startPlayback() {
+            MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
+            mediaMetadata.putString(MediaMetadata.KEY_TITLE, title);
+            MediaInfo mediaInfo = new MediaInfo.Builder(url)
+                                               .setContentType(type)
+                                               .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
+                                               .setMetadata(mediaMetadata)
+                                               .build();
+            try {
+                remoteMediaPlayer.load(apiClient, mediaInfo, true).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
+                    @Override
+                    public void onResult(MediaChannelResult result) {
+                        if (result.getStatus().isSuccess()) {
+                            sendSuccess(callback, null);
+                            debug("Media loaded successfully");
+                            return;
+                        }
+
+                        debug("Media load failed " + result.getStatus());
+                        sendError(callback, result.getStatus().toString());
+                    }
+                });
+
+                return;
+            } catch (IllegalStateException e) {
+                debug("Problem occurred with media during loading", e);
+            } catch (Exception e) {
+                debug("Problem opening media during loading", e);
+            }
+
+            sendError(callback, "");
+        }
+    }
+
+    public ChromeCast(Context context, RouteInfo route) {
+        int status =  GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
+        if (status != ConnectionResult.SUCCESS) {
+            throw new IllegalStateException("Play services are required for Chromecast support (got status code " + status + ")");
+        }
+
+        this.context = context;
+        this.route = route;
+        this.canMirror = route.supportsControlCategory(CastMediaControlIntent.categoryForCast(MIRROR_RECEIVER_APP_ID));
+    }
+
+    /**
+     *  This dumps everything we can find about the device into JSON. This will hopefully make it
+     *  easier to filter out duplicate devices from different sources in JS.
+     *  Returns null if the device can't be found.
+     */
+    @Override
+    public JSONObject toJSON() {
+        final JSONObject obj = new JSONObject();
+        try {
+            final CastDevice device = CastDevice.getFromBundle(route.getExtras());
+            if (device == null) {
+                return null;
+            }
+
+            obj.put("uuid", route.getId());
+            obj.put("version", device.getDeviceVersion());
+            obj.put("friendlyName", device.getFriendlyName());
+            obj.put("location", device.getIpAddress().toString());
+            obj.put("modelName", device.getModelName());
+            obj.put("mirror", canMirror);
+            // For now we just assume all of these are Google devices
+            obj.put("manufacturer", "Google Inc.");
+        } catch (JSONException ex) {
+            debug("Error building route", ex);
+        }
+
+        return obj;
+    }
+
+    @Override
+    public void load(final String title, final String url, final String type, final EventCallback callback) {
+        final CastDevice device = CastDevice.getFromBundle(route.getExtras());
+        Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(device, new Cast.Listener() {
+            @Override
+            public void onApplicationStatusChanged() { }
+
+            @Override
+            public void onVolumeChanged() { }
+
+            @Override
+            public void onApplicationDisconnected(int errorCode) { }
+        });
+
+        apiClient = new GoogleApiClient.Builder(context)
+            .addApi(Cast.API, apiOptionsBuilder.build())
+            .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
+                @Override
+                public void onConnected(Bundle connectionHint) {
+                    // Sometimes apiClient is null here. See bug 1061032
+                    if (apiClient != null && !apiClient.isConnected()) {
+                        debug("Connection failed");
+                        sendError(callback, "Not connected");
+                        return;
+                    }
+
+                    // Launch the media player app and launch this url once its loaded
+                    try {
+                        Cast.CastApi.launchApplication(apiClient, CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID, true)
+                                    .setResultCallback(new VideoPlayCallback(url, type, title, callback));
+                    } catch (Exception e) {
+                        debug("Failed to launch application", e);
+                    }
+                }
+
+                @Override
+                public void onConnectionSuspended(int cause) {
+                    debug("suspended");
+                }
+        }).build();
+
+        apiClient.connect();
+    }
+
+    @Override
+    public void start(final EventCallback callback) {
+        // Nothing to be done here
+        sendSuccess(callback, null);
+    }
+
+    @Override
+    public void stop(final EventCallback callback) {
+        // Nothing to be done here
+        sendSuccess(callback, null);
+    }
+
+    public boolean verifySession(final EventCallback callback) {
+        String msg = null;
+        if (apiClient == null || !apiClient.isConnected()) {
+            msg = "Not connected";
+        }
+
+        if (mSessionId == null) {
+            msg = "No session";
+        }
+
+        if (msg != null) {
+            debug(msg);
+            if (callback != null) {
+                sendError(callback, msg);
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void play(final EventCallback callback) {
+        if (!verifySession(callback)) {
+            return;
+        }
+
+        try {
+            remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
+                @Override
+                public void onResult(MediaChannelResult result) {
+                    Status status = result.getStatus();
+                    if (!status.isSuccess()) {
+                        debug("Unable to play: " + status.getStatusCode());
+                        sendError(callback, status.toString());
+                    } else {
+                        sendSuccess(callback, null);
+                    }
+                }
+            });
+        } catch (IllegalStateException ex) {
+            // The media player may throw if the session has been killed. For now, we're just catching this here.
+            sendError(callback, "Error playing");
+        }
+    }
+
+    @Override
+    public void pause(final EventCallback callback) {
+        if (!verifySession(callback)) {
+            return;
+        }
+
+        try {
+            remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
+                @Override
+                public void onResult(MediaChannelResult result) {
+                    Status status = result.getStatus();
+                    if (!status.isSuccess()) {
+                        debug("Unable to pause: " + status.getStatusCode());
+                        sendError(callback, status.toString());
+                    } else {
+                        sendSuccess(callback, null);
+                    }
+                }
+            });
+        } catch (IllegalStateException ex) {
+            // The media player may throw if the session has been killed. For now, we're just catching this here.
+            sendError(callback, "Error pausing");
+        }
+    }
+
+    @Override
+    public void end(final EventCallback callback) {
+        if (!verifySession(callback)) {
+            return;
+        }
+
+        try {
+            Cast.CastApi.stopApplication(apiClient).setResultCallback(new ResultCallback<Status>() {
+                @Override
+                public void onResult(Status result) {
+                    if (result.isSuccess()) {
+                        try {
+                            Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
+                            remoteMediaPlayer = null;
+                            mSessionId = null;
+                            apiClient.disconnect();
+                            apiClient = null;
+
+                            if (callback != null) {
+                                sendSuccess(callback, null);
+                            }
+
+                            return;
+                        } catch (Exception ex) {
+                            debug("Error ending", ex);
+                        }
+                    }
+
+                    if (callback != null) {
+                        sendError(callback, result.getStatus().toString());
+                    }
+                }
+            });
+        } catch (IllegalStateException ex) {
+            // The media player may throw if the session has been killed. For now, we're just catching this here.
+            sendError(callback, "Error stopping");
+        }
+    }
+
+    class MirrorChannel implements MessageReceivedCallback {
+        /**
+         * @return custom namespace
+         */
+        public String getNamespace() {
+            return "urn:x-cast:org.mozilla.mirror";
+        }
+
+        /*
+         * Receive message from the receiver app
+         */
+        @Override
+        public void onMessageReceived(CastDevice castDevice, String namespace,
+                                      String message) {
+            GeckoAppShell.notifyObservers("MediaPlayer:Response", message);
+        }
+
+        public void sendMessage(String message) {
+            if (apiClient != null && mMirrorChannel != null) {
+                try {
+                    Cast.CastApi.sendMessage(apiClient, mMirrorChannel.getNamespace(), message)
+                        .setResultCallback(
+                                           new ResultCallback<Status>() {
+                                               @Override
+                                                   public void onResult(Status result) {
+                                               }
+                                           });
+                } catch (Exception e) {
+                    Log.e(LOGTAG, "Exception while sending message", e);
+                }
+            }
+        }
+    }
+    private class MirrorCallback implements ResultCallback<ApplicationConnectionResult> {
+        final EventCallback callback;
+        MirrorCallback(final EventCallback callback) {
+            this.callback = callback;
+        }
+
+
+        @Override
+        public void onResult(ApplicationConnectionResult result) {
+            Status status = result.getStatus();
+            if (status.isSuccess()) {
+                ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
+                mSessionId = result.getSessionId();
+                String applicationStatus = result.getApplicationStatus();
+                boolean wasLaunched = result.getWasLaunched();
+                mApplicationStarted = true;
+
+                // Create the custom message
+                // channel
+                mMirrorChannel = new MirrorChannel();
+                try {
+                    Cast.CastApi.setMessageReceivedCallbacks(apiClient,
+                                                             mMirrorChannel
+                                                             .getNamespace(),
+                                                             mMirrorChannel);
+                    sendSuccess(callback, null);
+                } catch (IOException e) {
+                    Log.e(LOGTAG, "Exception while creating channel", e);
+                }
+
+                GeckoAppShell.notifyObservers("Casting:Mirror", route.getId());
+            } else {
+                sendError(callback, status.toString());
+            }
+        }
+    }
+
+    @Override
+    public void message(String msg, final EventCallback callback) {
+        if (mMirrorChannel != null) {
+            mMirrorChannel.sendMessage(msg);
+        }
+    }
+
+    @Override
+    public void mirror(final EventCallback callback) {
+        final CastDevice device = CastDevice.getFromBundle(route.getExtras());
+        Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(device, new Cast.Listener() {
+                @Override
+                public void onApplicationStatusChanged() { }
+
+                @Override
+                public void onVolumeChanged() { }
+
+                @Override
+                public void onApplicationDisconnected(int errorCode) { }
+            });
+
+        apiClient = new GoogleApiClient.Builder(context)
+            .addApi(Cast.API, apiOptionsBuilder.build())
+            .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
+                    @Override
+                    public void onConnected(Bundle connectionHint) {
+                        // Sometimes apiClient is null here. See bug 1061032
+                        if (apiClient == null || !apiClient.isConnected()) {
+                            return;
+                        }
+
+                        // Launch the media player app and launch this url once its loaded
+                        try {
+                            Cast.CastApi.launchApplication(apiClient, MIRROR_RECEIVER_APP_ID, true)
+                                .setResultCallback(new MirrorCallback(callback));
+                        } catch (Exception e) {
+                            debug("Failed to launch application", e);
+                        }
+                    }
+
+                    @Override
+                    public void onConnectionSuspended(int cause) {
+                        debug("suspended");
+                    }
+                }).build();
+
+        apiClient.connect();
+    }
+
+    private static final String LOGTAG = "GeckoChromeCast";
+    private void debug(String msg, Exception e) {
+        if (SHOW_DEBUG) {
+            Log.e(LOGTAG, msg, e);
+        }
+    }
+
+    private void debug(String msg) {
+        if (SHOW_DEBUG) {
+            Log.d(LOGTAG, msg);
+        }
+    }
+
+}
--- a/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/BrowserSearch.java
@@ -244,16 +244,18 @@ public class BrowserSearch extends HomeF
 
         mSearchEngines = new ArrayList<SearchEngine>();
         mSearchHistorySuggestions = new ArrayList<>();
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
+
+        mSearchEngines = null;
     }
 
     @Override
     public void onHiddenChanged(boolean hidden) {
         if (!hidden) {
             final Tab tab = Tabs.getInstance().getSelectedTab();
             final boolean isPrivate = (tab != null && tab.isPrivate());
 
@@ -680,18 +682,23 @@ public class BrowserSearch extends HomeF
             mSearchHistorySuggestionLoaderCallback = new SearchHistorySuggestionLoaderCallbacks();
         }
         getLoaderManager().restartLoader(LOADER_ID_SAVED_SUGGESTION, null, mSearchHistorySuggestionLoaderCallback);
     }
 
     private void setSuggestions(ArrayList<String> suggestions) {
         ThreadUtils.assertOnUiThread();
 
-        mSearchEngines.get(0).setSuggestions(suggestions);
-        mAdapter.notifyDataSetChanged();
+        // mSearchEngines may be null if the setSuggestions calls after onDestroy (bug 1310621).
+        // So drop the suggestions if search engines are not available
+        if (mSearchEngines != null && !mSearchEngines.isEmpty()) {
+            mSearchEngines.get(0).setSuggestions(suggestions);
+            mAdapter.notifyDataSetChanged();
+        }
+
     }
 
     private void setSavedSuggestions(ArrayList<String> savedSuggestions) {
         ThreadUtils.assertOnUiThread();
 
         mSearchHistorySuggestions = savedSuggestions;
         mAdapter.notifyDataSetChanged();
     }
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxHooks.cpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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 <dlfcn.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "mozilla/Types.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Signal number used to enable seccomp on each thread.
+extern int gSeccompTsyncBroadcastSignum;
+
+// This file defines a hook for sigprocmask() and pthread_sigmask().
+// Bug 1176099: some threads block SIGSYS signal which breaks our seccomp-bpf
+// sandbox. To avoid this, we intercept the call and remove SIGSYS.
+//
+// ENOSYS indicates an error within the hook function itself.
+static int HandleSigset(int (*aRealFunc)(int, const sigset_t*, sigset_t*),
+                        int aHow, const sigset_t* aSet,
+                        sigset_t* aOldSet, bool aUseErrno)
+{
+  if (!aRealFunc) {
+    if (aUseErrno) {
+      errno = ENOSYS;
+      return -1;
+    }
+
+    return ENOSYS;
+  }
+
+  // Avoid unnecessary work
+  if (aSet == NULL || aHow == SIG_UNBLOCK) {
+    return aRealFunc(aHow, aSet, aOldSet);
+  }
+
+  sigset_t newSet = *aSet;
+  if (sigdelset(&newSet, SIGSYS) != 0 ||
+     (gSeccompTsyncBroadcastSignum &&
+      sigdelset(&newSet, gSeccompTsyncBroadcastSignum) != 0)) {
+    if (aUseErrno) {
+      errno = ENOSYS;
+      return -1;
+    }
+
+    return ENOSYS;
+  }
+
+  return aRealFunc(aHow, &newSet, aOldSet);
+}
+
+extern "C" MOZ_EXPORT int
+sigprocmask(int how, const sigset_t* set, sigset_t* oldset)
+{
+  static auto sRealFunc = (int (*)(int, const sigset_t*, sigset_t*))
+    dlsym(RTLD_NEXT, "sigprocmask");
+
+  return HandleSigset(sRealFunc, how, set, oldset, true);
+}
+
+extern "C" MOZ_EXPORT int
+pthread_sigmask(int how, const sigset_t* set, sigset_t* oldset)
+{
+  static auto sRealFunc = (int (*)(int, const sigset_t*, sigset_t*))
+    dlsym(RTLD_NEXT, "pthread_sigmask");
+
+  return HandleSigset(sRealFunc, how, set, oldset, false);
+}