Merge mozilla-central and b2g-inbound
authorEd Morley <emorley@mozilla.com>
Fri, 01 Aug 2014 18:03:34 +0100
changeset 218933 f2acc6ff7aee6783a07bdbfac8be2e631ae8b48e
parent 218907 47a75561bc43d89213edaa5652990afab707a13e (current diff)
parent 218932 0b900c9e0940c836ac4af7299ce7f406e2d08dc8 (diff)
child 218934 db4d0d93b00525312e9678e4ced47fd4a2e2bf31
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central and b2g-inbound
configure.in
media/mtransport/third_party/nrappkit/src/util/libekr/r_bitfield.c
media/mtransport/third_party/nrappkit/src/util/libekr/r_bitfield.h
new file mode 100644
--- /dev/null
+++ b/b2g/app/B2GLoader.cpp
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 autoindent cindent expandtab: */
+/* 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 "nsXULAppAPI.h"
+#include "application.ini.h"
+#include "nsXPCOMGlue.h"
+#include "nsStringGlue.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "BinaryPath.h"
+#include "nsAutoPtr.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <dlfcn.h>
+
+#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
+
+#define ASSERT(x) if (!(x)) { MOZ_CRASH(); }
+
+
+// Functions being loaded by XPCOMGlue
+XRE_ProcLoaderServiceRunType XRE_ProcLoaderServiceRun;
+XRE_ProcLoaderClientInitType XRE_ProcLoaderClientInit;
+XRE_ProcLoaderPreloadType XRE_ProcLoaderPreload;
+extern XRE_CreateAppDataType XRE_CreateAppData;
+extern XRE_GetFileFromPathType XRE_GetFileFromPath;
+
+static const nsDynamicFunctionLoad kXULFuncs[] = {
+  { "XRE_ProcLoaderServiceRun", (NSFuncPtr*) &XRE_ProcLoaderServiceRun },
+  { "XRE_ProcLoaderClientInit", (NSFuncPtr*) &XRE_ProcLoaderClientInit },
+  { "XRE_ProcLoaderPreload", (NSFuncPtr*) &XRE_ProcLoaderPreload },
+  { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData },
+  { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath },
+  { nullptr, nullptr }
+};
+
+static int
+GetDirnameSlash(const char *aPath, char *aOutDir, int aMaxLen)
+{
+  char *lastSlash = strrchr(aPath, XPCOM_FILE_PATH_SEPARATOR[0]);
+  if (lastSlash == nullptr) {
+    return 0;
+  }
+  int cpsz = lastSlash - aPath + 1; // include slash
+  if (aMaxLen <= cpsz) {
+    return 0;
+  }
+  strncpy(aOutDir, aPath, cpsz);
+  aOutDir[cpsz] = 0;
+  return cpsz;
+}
+
+static bool
+GetXPCOMPath(const char *aProgram, char *aOutPath, int aMaxLen)
+{
+  nsAutoArrayPtr<char> progBuf(new char[aMaxLen]);
+  nsresult rv = mozilla::BinaryPath::Get(aProgram, progBuf);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  int len = GetDirnameSlash(progBuf, aOutPath, aMaxLen);
+  NS_ENSURE_TRUE(!!len, false);
+
+  NS_ENSURE_TRUE((len + sizeof(XPCOM_DLL)) < aMaxLen, false);
+  char *afterSlash = aOutPath + len;
+  strcpy(afterSlash, XPCOM_DLL);
+  return true;
+}
+
+static bool
+LoadLibxul(const char *aXPCOMPath)
+{
+  nsresult rv;
+
+  XPCOMGlueEnablePreload();
+  rv = XPCOMGlueStartup(aXPCOMPath);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+/**
+ * Return true if |arg| matches the given argument name.
+ */
+static bool
+IsArg(const char* arg, const char* s)
+{
+  if (*arg == '-') {
+    if (*++arg == '-') {
+      ++arg;
+    }
+    return !strcasecmp(arg, s);
+  }
+
+#if defined(XP_WIN)
+  if (*arg == '/') {
+    return !strcasecmp(++arg, s);
+  }
+#endif
+
+  return false;
+}
+
+static already_AddRefed<nsIFile>
+GetAppIni(int argc, const char *argv[])
+{
+  nsCOMPtr<nsIFile> appini;
+  nsresult rv;
+
+  // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
+  // Note that -app must be the *first* argument.
+  const char *appDataFile = getenv("XUL_APP_FILE");
+  if (appDataFile && *appDataFile) {
+    rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini));
+    NS_ENSURE_SUCCESS(rv, nullptr);
+  } else if (argc > 1 && IsArg(argv[1], "app")) {
+    if (argc == 2) {
+      return nullptr;
+    }
+
+    rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini));
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
+    char appEnv[MAXPATHLEN];
+    snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]);
+    if (putenv(appEnv)) {
+      return nullptr;
+    }
+  }
+
+  return appini.forget();
+}
+
+static bool
+LoadStaticData(int argc, const char *argv[])
+{
+  char xpcomPath[MAXPATHLEN];
+  bool ok = GetXPCOMPath(argv[0], xpcomPath, MAXPATHLEN);
+  NS_ENSURE_TRUE(ok, false);
+
+  ok = LoadLibxul(xpcomPath);
+  NS_ENSURE_TRUE(ok, false);
+
+  char progDir[MAXPATHLEN];
+  ok = GetDirnameSlash(xpcomPath, progDir, MAXPATHLEN);
+  NS_ENSURE_TRUE(ok, false);
+
+  nsCOMPtr<nsIFile> appini = GetAppIni(argc, argv);
+  const nsXREAppData *appData;
+  if (appini) {
+    nsresult rv =
+      XRE_CreateAppData(appini, const_cast<nsXREAppData**>(&appData));
+    NS_ENSURE_SUCCESS(rv, false);
+  } else {
+    appData = &sAppData;
+  }
+
+  XRE_ProcLoaderPreload(progDir, appData);
+
+  if (appini) {
+    XRE_FreeAppData(const_cast<nsXREAppData*>(appData));
+  }
+
+  return true;
+}
+
+/**
+ * Fork and run parent and child process.
+ *
+ * The parent is the b2g process and child for Nuwa.
+ */
+static int
+RunProcesses(int argc, const char *argv[])
+{
+  /*
+   * The original main() of the b2g process.  It is renamed to
+   * b2g_main() for the b2g loader.
+   */
+  int b2g_main(int argc, const char *argv[]);
+
+  int ipcSockets[2] = {-1, -1};
+  int r = socketpair(AF_LOCAL, SOCK_STREAM, 0, ipcSockets);
+  ASSERT(r == 0);
+  int parentSock = ipcSockets[0];
+  int childSock = ipcSockets[1];
+
+  r = fcntl(parentSock, F_SETFL, O_NONBLOCK);
+  ASSERT(r != -1);
+  r = fcntl(childSock, F_SETFL, O_NONBLOCK);
+  ASSERT(r != -1);
+
+  pid_t pid = fork();
+  ASSERT(pid >= 0);
+  bool isChildProcess = pid == 0;
+
+  close(isChildProcess ? parentSock : childSock);
+
+  if (isChildProcess) {
+    /* The Nuwa process */
+    /* This provides the IPC service of loading Nuwa at the process.
+     * The b2g process would send a IPC message of loading Nuwa
+     * as the replacement of forking and executing plugin-container.
+     */
+    return XRE_ProcLoaderServiceRun(getppid(), childSock, argc, argv);
+  }
+
+  // The b2g process
+  int childPid = pid;
+  XRE_ProcLoaderClientInit(childPid, parentSock);
+  return b2g_main(argc, argv);
+}
+
+/**
+ * B2G Loader is responsible for loading the b2g process and the
+ * Nuwa process.  It forks into the parent process, for the b2g
+ * process, and the child process, for the Nuwa process.
+ *
+ * The loader loads libxul and performs initialization of static data
+ * before forking, so relocation of libxul and static data can be
+ * shared between the b2g process, the Nuwa process, and the content
+ * processes.
+ */
+int
+main(int argc, const char* argv[])
+{
+  const char *program = argv[0];
+  /*
+   * Before fork(), libxul and static data of Gecko are loaded for
+   * sharing.
+   */
+  bool ok = LoadStaticData(argc, argv);
+  if (!ok) {
+    return 255;
+  }
+
+  return RunProcesses(argc, argv);
+}
--- a/b2g/app/moz.build
+++ b/b2g/app/moz.build
@@ -4,16 +4,21 @@
 # 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 not CONFIG['LIBXUL_SDK']:
     if CONFIG['GAIADIR']:
         PROGRAM = CONFIG['MOZ_APP_NAME'] + "-bin"
     else:
         PROGRAM = CONFIG['MOZ_APP_NAME']
+    if CONFIG['MOZ_B2G_LOADER']:
+        SOURCES += [
+            'B2GLoader.cpp',
+        ]
+
     SOURCES += [
         'nsBrowserApp.cpp',
     ]
     if CONFIG['_MSC_VER']:
         # Always enter a Windows program through wmain, whether or not we're
         # a console application.
         WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
 
--- a/b2g/app/nsBrowserApp.cpp
+++ b/b2g/app/nsBrowserApp.cpp
@@ -12,16 +12,17 @@
 #elif defined(XP_UNIX)
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <unistd.h>
 #endif
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <string.h>
 
 #include "nsCOMPtr.h"
 #include "nsIFile.h"
 #include "nsStringGlue.h"
 
 #ifdef XP_WIN
 // we want a wmain entry point
 #include "nsWindowsWMain.cpp"
@@ -158,39 +159,55 @@ static int do_main(int argc, char* argv[
     int result = XRE_main(argc, argv, appData, 0);
     XRE_FreeAppData(appData);
     return result;
   }
 
   return XRE_main(argc, argv, &sAppData, 0);
 }
 
-int main(int argc, char* argv[])
+#ifdef MOZ_B2G_LOADER
+/*
+ * The main() in B2GLoader.cpp is the new main function instead of the
+ * main() here if it is enabled.  So, rename it to b2g_man().
+ */
+#define main b2g_main
+#define _CONST const
+#else
+#define _CONST
+#endif
+
+int main(int argc, _CONST char* argv[])
 {
+#ifndef MOZ_B2G_LOADER
   char exePath[MAXPATHLEN];
+#endif
 
 #ifdef MOZ_WIDGET_GONK
   // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to
   // receive binder calls, though not necessary to send binder calls.
   // ProcessState::Self() also needs to be called once on the main thread to
   // register the main thread with the binder driver.
   android::ProcessState::self()->startThreadPool();
 #endif
 
-  nsresult rv = mozilla::BinaryPath::Get(argv[0], exePath);
+  nsresult rv;
+#ifndef MOZ_B2G_LOADER
+  rv = mozilla::BinaryPath::Get(argv[0], exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't calculate the application directory.\n");
     return 255;
   }
 
   char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]);
   if (!lastSlash || ((lastSlash - exePath) + sizeof(XPCOM_DLL) + 1 > MAXPATHLEN))
     return 255;
 
   strcpy(++lastSlash, XPCOM_DLL);
+#endif // MOZ_B2G_LOADER
 
 #if defined(XP_UNIX)
   // If the b2g app is launched from adb shell, then the shell will wind
   // up being the process group controller. This means that we can't send
   // signals to the process group (useful for profiling).
   // We ignore the return value since setsid() fails if we're already the
   // process group controller (the normal situation).
   (void)setsid();
@@ -204,26 +221,30 @@ int main(int argc, char* argv[])
   IO_COUNTERS ioCounters;
   gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
 #endif
 
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize();
 #endif
 
+  // B2G loader has already initialized Gecko so we can't initialize
+  // it again here.
+#ifndef MOZ_B2G_LOADER
   // We do this because of data in bug 771745
   XPCOMGlueEnablePreload();
 
   rv = XPCOMGlueStartup(exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't load XPCOM.\n");
     return 255;
   }
   // Reset exePath so that it is the directory name and not the xpcom dll name
   *lastSlash = 0;
+#endif // MOZ_B2G_LOADER
 
   rv = XPCOMGlueLoadXULFunctions(kXULFuncs);
   if (NS_FAILED(rv)) {
     Output("Couldn't load XRE functions.\n");
     return 255;
   }
 
   if (gotCounters) {
@@ -248,13 +269,31 @@ int main(int argc, char* argv[])
                               int(newRUsage.ru_majflt - initialRUsage.ru_majflt));
     }
 #endif
   }
 
   int result;
   {
     ScopedLogging log;
-    result = do_main(argc, argv);
+    char **_argv;
+
+    /*
+     * Duplicate argument vector to conform non-const argv of
+     * do_main() since XRE_main() is very stupid with non-const argv.
+     */
+    _argv = new char *[argc + 1];
+    for (int i = 0; i < argc; i++) {
+      _argv[i] = strdup(argv[i]);
+      MOZ_ASSERT(_argv[i] != nullptr);
+    }
+    _argv[argc] = nullptr;
+
+    result = do_main(argc, _argv);
+
+    for (int i = 0; i < argc; i++) {
+      free(_argv[i]);
+    }
+    delete[] _argv;
   }
 
   return result;
 }
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="227354333a185180b85471f2cc6abfb029e44718"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3aa6abd313f965a84aa86c6b213dc154e4875139">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="999e945b85c578c503ad445c2285940f16aacdae">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="227354333a185180b85471f2cc6abfb029e44718"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3aa6abd313f965a84aa86c6b213dc154e4875139">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "3842156466e71f41748f86777a1b8fbd379441c0", 
+    "revision": "1b7211a77c0304ac7ac3c10db8b7fbe1a1e2a7a9", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3aa6abd313f965a84aa86c6b213dc154e4875139">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9689218473b6fc4dd927ad6aa7b06c05f0843824"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="22846bf06d34bd42d124952402ab121e6ae05c27"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d61daef8fca7d6f335f659a8967bad423770e634"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="71f5a35e3bc1801847413cff1f14fc3b5cd991ca"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -54,16 +54,17 @@ MOZ_TIME_MANAGER=1
 
 MOZ_PAY=1
 MOZ_TOOLKIT_SEARCH=
 MOZ_PLACES=
 MOZ_B2G=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_NUWA_PROCESS=1
+MOZ_B2G_LOADER=1
 fi
 MOZ_FOLD_LIBS=1
 
 MOZ_JSDOWNLOADS=1
 
 MOZ_BUNDLED_FONTS=1
 
 # Enable exact rooting on b2g.
--- a/configure.in
+++ b/configure.in
@@ -8609,16 +8609,24 @@ AC_SUBST(MOZ_BZ2_LIBS)
 AC_SUBST(MOZ_PNG_CFLAGS)
 AC_SUBST(MOZ_PNG_LIBS)
 
 if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
     export MOZ_NUWA_PROCESS
     AC_DEFINE(MOZ_NUWA_PROCESS)
 fi
 AC_SUBST(MOZ_NUWA_PROCESS)
+if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_B2G_LOADER"; then
+    if test -z "$MOZ_NUWA_PROCESS"; then
+       AC_MSG_ERROR([B2G loader works with Nuwa]);
+    fi
+    export MOZ_B2G_LOADER
+    AC_DEFINE(MOZ_B2G_LOADER)
+fi
+AC_SUBST(MOZ_B2G_LOADER)
 
 AC_SUBST(NSPR_CFLAGS)
 AC_SUBST(NSPR_LIBS)
 AC_SUBST(MOZ_NATIVE_NSPR)
 
 AC_SUBST(NSS_CFLAGS)
 AC_SUBST(NSS_LIBS)
 AC_SUBST(MOZ_NATIVE_NSS)
--- a/dom/apps/src/OfflineCacheInstaller.jsm
+++ b/dom/apps/src/OfflineCacheInstaller.jsm
@@ -18,17 +18,19 @@ Cu.import("resource://gre/modules/NetUti
 let Namespace = CC('@mozilla.org/network/application-cache-namespace;1',
                    'nsIApplicationCacheNamespace',
                    'init');
 let makeFile = CC('@mozilla.org/file/local;1',
                 'nsIFile',
                 'initWithPath');
 let MutableArray = CC('@mozilla.org/array;1', 'nsIMutableArray');
 
-const nsICache = Ci.nsICache;
+let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
+
+const nsICacheStorage = Ci.nsICacheStorage;
 const nsIApplicationCache = Ci.nsIApplicationCache;
 const applicationCacheService =
   Cc['@mozilla.org/network/application-cache-service;1']
     .getService(Ci.nsIApplicationCacheService);
 
 
 function debug(aMsg) {
   //dump("-*-*- OfflineCacheInstaller.jsm : " + aMsg + "\n");
@@ -42,42 +44,44 @@ function enableOfflineCacheForApp(origin
                                   Ci.nsIPermissionManager.ALLOW_ACTION);
   // Prevent cache from being evicted:
   Services.perms.addFromPrincipal(principal, 'pin-app',
                                   Ci.nsIPermissionManager.ALLOW_ACTION);
 }
 
 
 function storeCache(applicationCache, url, file, itemType) {
-  let session = Services.cache.createSession(applicationCache.clientID,
-                                             nsICache.STORE_OFFLINE, true);
-  session.asyncOpenCacheEntry(url, nsICache.ACCESS_WRITE, {
-    onCacheEntryAvailable: function (cacheEntry, accessGranted, status) {
-      cacheEntry.setMetaDataElement('request-method', 'GET');
-      cacheEntry.setMetaDataElement('response-head', 'HTTP/1.1 200 OK\r\n');
+  let storage =
+    Services.cache2.appCacheStorage(LoadContextInfo.default, applicationCache);
+  let uri = Services.io.newURI(url, null, null);
+  storage.asyncOpenURI(uri, "", nsICacheStorage.OPEN_TRUNCATE, {
+    onCacheEntryAvailable:
+      function (cacheEntry, isNew, appCache, result) {
+        cacheEntry.setMetaDataElement('request-method', 'GET');
+        cacheEntry.setMetaDataElement('response-head', 'HTTP/1.1 200 OK\r\n');
 
-      let outputStream = cacheEntry.openOutputStream(0);
+        let outputStream = cacheEntry.openOutputStream(0);
 
-      // Input-Output stream machinery in order to push nsIFile content into cache
-      let inputStream = Cc['@mozilla.org/network/file-input-stream;1']
-                          .createInstance(Ci.nsIFileInputStream);
-      inputStream.init(file, 1, -1, null);
-      let bufferedOutputStream = Cc['@mozilla.org/network/buffered-output-stream;1']
-                                   .createInstance(Ci.nsIBufferedOutputStream);
-      bufferedOutputStream.init(outputStream, 1024);
-      bufferedOutputStream.writeFrom(inputStream, inputStream.available());
-      bufferedOutputStream.flush();
-      bufferedOutputStream.close();
-      inputStream.close();
+        // Input-Output stream machinery in order to push nsIFile content into cache
+        let inputStream = Cc['@mozilla.org/network/file-input-stream;1']
+                            .createInstance(Ci.nsIFileInputStream);
+        inputStream.init(file, 1, -1, null);
+        let bufferedOutputStream = Cc['@mozilla.org/network/buffered-output-stream;1']
+                                     .createInstance(Ci.nsIBufferedOutputStream);
+        bufferedOutputStream.init(outputStream, 1024);
+        bufferedOutputStream.writeFrom(inputStream, inputStream.available());
+        bufferedOutputStream.flush();
+        bufferedOutputStream.close();
+        inputStream.close();
 
-      cacheEntry.markValid();
-      debug (file.path + ' -> ' + url + ' (' + itemType + ')');
-      applicationCache.markEntry(url, itemType);
-      cacheEntry.close();
-    }
+        cacheEntry.markValid();
+        debug (file.path + ' -> ' + url + ' (' + itemType + ')');
+        applicationCache.markEntry(url, itemType);
+        cacheEntry.close();
+      }
   });
 }
 
 function readFile(aFile, aCallback) {
   let channel = NetUtil.newChannel(aFile);
   channel.contentType = "plain/text";
   NetUtil.asyncFetch(channel, function(aStream, aResult) {
     if (!Components.isSuccessCode(aResult)) {
--- a/dom/camera/GonkCameraHwMgr.cpp
+++ b/dom/camera/GonkCameraHwMgr.cpp
@@ -229,16 +229,17 @@ GonkCameraHardware::Connect(mozilla::nsG
     cameraHardware = new TestGonkCameraHardware(aTarget, aCameraId, camera);
   } else {
     cameraHardware = new GonkCameraHardware(aTarget, aCameraId, camera);
   }
 
   nsresult rv = cameraHardware->Init();
   if (NS_FAILED(rv)) {
     DOM_CAMERA_LOGE("Failed to initialize camera hardware (0x%X)\n", rv);
+    cameraHardware->Close();
     return nullptr;
   }
 
   return cameraHardware;
 }
 
 void
 GonkCameraHardware::Close()
--- a/dom/camera/test/test_camera_hardware_init_failure.html
+++ b/dom/camera/test/test_camera_hardware_init_failure.html
@@ -12,42 +12,85 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=940424">Mozilla Bug 940424</a>
   <video id="viewfinder" width="200" height="200" autoplay></video>
   <img src="#" alt="This image is going to load" id="testimage"/>
 
 <script class="testbody" type="text/javascript;version=1.7">
 
+SimpleTest.waitForExplicitFinish();
+
 var whichCamera = navigator.mozCameras.getListOfCameras()[0];
 var initialConfig = {
   mode: 'picture',
   recorderProfile: 'cif',
   previewSize: {
     width: 352,
     height: 288
   }
 };
 
-function end() {
-  CameraTest.end();
-}
+var tests = [
+  {
+    name: "init-failure",
+    key: "init-failure",
+    func: function testInitFailure(test) {
+      function onSuccess(camera, config) {
+        ok(false, "onSuccess called incorrectly");
+        camera.release();
+        test.next();
+      }
+      function onError(error) {
+        ok(true, "onError called correctly on init failure");
+        test.next();
+      }
+      info("Running test: init-failure");
+      navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError);
+    }
+  },
+  /* This test case (init-success) *must* follow the preceeding test case
+     (init-failure) in order for the desired condition to be verified */
+  {
+    name: "init-success",
+    key: "",
+    func: function(test) {
+      function onSuccess(camera, config) {
+        ok(true, "onSuccess called correctly");
+        camera.release();
+        test.next();
+      }
+      function onError(error) {
+        ok(false, "onError called incorrectly: " + error);
+        test.next();
+      }
+      info("Running test: init-success");
+      navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError)
+    }
+  }
+];
+
+var testGenerator = function() {
+  for (var i = 0; i < tests.length; ++i ) {
+    yield tests[i];
+  }
+}();
 
 CameraTest.begin("hardware", function(test) {
-  test.set("init-failure", function(type) {
-    function onSuccess(camera, config) {
-      ok(false, "onSuccess called incorrectly");
-      camera.release();
-      test.done(end);
+  CameraTest.next = function() {
+    try {
+      var t = testGenerator.next();
+      test.set(t.key, t.func.bind(undefined, CameraTest));
+    } catch(e) {
+      if (e instanceof StopIteration) {
+        CameraTest.end();
+      } else {
+        throw e;
+      }
     }
-    function onError(error) {
-      ok(true, "onError called correctly on init failure");
-      test.done(end);
-    }
-    info("Running test: " + type);
-    navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError);
-  });
+  };
+  CameraTest.next();
 });
 
 </script>
 </body>
 
 </html>
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -63,16 +63,17 @@
 #include "nsThreadUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIThread.h"
 #include "nsXULAppAPI.h"
 #include "OrientationObserver.h"
 #include "UeventPoller.h"
 #include "nsIWritablePropertyBag2.h"
 #include <algorithm>
+#include "PowerWakeLock.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
 #define NsecPerMsec  1000000LL
 #define NsecPerSec   1000000000
 
 // The header linux/oom.h is not available in bionic libc. We
 // redefine some of its constants here.
 
@@ -662,16 +663,17 @@ GetScreenEnabled()
 {
   return sScreenEnabled;
 }
 
 void
 SetScreenEnabled(bool aEnabled)
 {
   GetGonkDisplay()->SetEnabled(aEnabled);
+  gPowerWakelock = nullptr;
   sScreenEnabled = aEnabled;
 }
 
 bool
 GetKeyLightEnabled()
 {
   LightConfiguration config;
   GetLight(hal::eHalLightID_Buttons, &config);
--- a/ipc/app/Makefile.in
+++ b/ipc/app/Makefile.in
@@ -32,16 +32,20 @@ endif
 # This switches $(INSTALL) to copy mode, like $(SYSINSTALL), so things that
 # shouldn't get 755 perms need $(IFLAGS1) for either way of calling nsinstall.
 NSDISTMODE = copy
 
 include $(topsrcdir)/config/config.mk
 
 include $(topsrcdir)/config/rules.mk
 
+ifneq ($(MOZ_WIDGET_TOOLKIT),android)
+#LIBS += ../contentproc/$(LIB_PREFIX)plugin-container.$(LIB_SUFFIX)
+endif
+
 ifeq ($(OS_ARCH),WINNT) #{
 # Note the manifest file exists in the tree, so we use the explicit filename
 # here.
 EXTRA_DEPS += plugin-container.exe.manifest
 endif #}
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) #{
 
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -1,151 +1,12 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: sw=4 ts=4 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 "nsXPCOM.h"
-#include "nsXULAppAPI.h"
-
-// FIXME/cjones testing
-#if !defined(OS_WIN)
-#include <unistd.h>
-#endif
-
-#ifdef XP_WIN
-#include <windows.h>
-// we want a wmain entry point
-// but we don't want its DLL load protection, because we'll handle it here
-#define XRE_DONT_PROTECT_DLL_LOAD
-#include "nsWindowsWMain.cpp"
-#include "nsSetDllDirectory.h"
-#endif
-
-#if defined(XP_WIN)
-#include "sandbox/chromium/base/basictypes.h"
-#include "sandbox/win/src/sandbox.h"
-#include "sandbox/win/src/sandbox_factory.h"
-#include "mozilla/sandboxTarget.h"
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-# include <sys/time.h>
-# include <sys/resource.h> 
-
-# include <binder/ProcessState.h>
-
-# ifdef LOGE_IF
-#  undef LOGE_IF
-# endif
-
-# include <android/log.h>
-# define LOGE_IF(cond, ...) \
-     ( (CONDITION(cond)) \
-     ? ((void)__android_log_print(ANDROID_LOG_ERROR, \
-       "Gecko:MozillaRntimeMain", __VA_ARGS__)) \
-     : (void)0 )
-
-#endif
-
-#ifdef MOZ_NUWA_PROCESS
-#include <binder/ProcessState.h>
-#include "ipc/Nuwa.h"
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-static void
-InitializeBinder(void *aDummy) {
-    // Change thread priority to 0 only during calling ProcessState::self().
-    // The priority is registered to binder driver and used for default Binder
-    // Thread's priority. 
-    // To change the process's priority to small value need's root permission.
-    int curPrio = getpriority(PRIO_PROCESS, 0);
-    int err = setpriority(PRIO_PROCESS, 0, 0);
-    MOZ_ASSERT(!err);
-    LOGE_IF(err, "setpriority failed. Current process needs root permission.");
-    android::ProcessState::self()->startThreadPool();
-    setpriority(PRIO_PROCESS, 0, curPrio);
+#include "../contentproc/plugin-container.cpp"
+ 
+int
+main(int argc, char *argv[]) {
+    return content_process_main(argc, argv);
 }
-#endif
-
-#if defined(XP_WIN)
-static bool gIsSandboxEnabled = false;
-void StartSandboxCallback()
-{
-    if (gIsSandboxEnabled) {
-        sandbox::TargetServices* target_service =
-            sandbox::SandboxFactory::GetTargetServices();
-        target_service->LowerToken();
-    }
-}
-#endif
-
-int
-main(int argc, char* argv[])
-{
-    bool isNuwa = false;
-    for (int i = 1; i < argc; i++) {
-        isNuwa |= strcmp(argv[i], "-nuwa") == 0;
-#if defined(XP_WIN)
-        gIsSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
-#endif
-    }
-
-#ifdef MOZ_NUWA_PROCESS
-    if (isNuwa) {
-        PrepareNuwaProcess();
-    }
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-    // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to
-    // receive binder calls, though not necessary to send binder calls.
-    // ProcessState::Self() also needs to be called once on the main thread to
-    // register the main thread with the binder driver.
-
-#ifdef MOZ_NUWA_PROCESS
-    if (!isNuwa) {
-        InitializeBinder(nullptr);
-    } else {
-        NuwaAddFinalConstructor(&InitializeBinder, nullptr);
-    }
-#else
-    InitializeBinder(nullptr);
-#endif
-#endif
-
-    // Check for the absolute minimum number of args we need to move
-    // forward here. We expect the last arg to be the child process type.
-    if (argc < 1)
-      return 3;
-    GeckoProcessType proctype = XRE_StringToChildProcessType(argv[--argc]);
-
-#ifdef XP_WIN
-    // For plugins, this is done in PluginProcessChild::Init, as we need to
-    // avoid it for unsupported plugins.  See PluginProcessChild::Init for
-    // the details.
-    if (proctype != GeckoProcessType_Plugin) {
-        mozilla::SanitizeEnvironmentVariables();
-        SetDllDirectory(L"");
-    }
-
-    if (gIsSandboxEnabled) {
-        sandbox::TargetServices* target_service =
-            sandbox::SandboxFactory::GetTargetServices();
-        if (!target_service) {
-            return 1;
-        }
-
-        sandbox::ResultCode result = target_service->Init();
-        if (result != sandbox::SBOX_ALL_OK) {
-           return 2;
-        }
-        mozilla::SandboxTarget::Instance()->SetStartSandboxCallback(StartSandboxCallback);
-    }
-#endif
-
-    nsresult rv = XRE_InitChildProcess(argc, argv, proctype);
-    NS_ENSURE_SUCCESS(rv, 1);
-
-    return 0;
-}
--- a/ipc/chromium/src/base/process_util_linux.cc
+++ b/ipc/chromium/src/base/process_util_linux.cc
@@ -1,8 +1,10 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 autoindent cindent expandtab: */
 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/process_util.h"
 
 #include <ctype.h>
 #include <fcntl.h>
@@ -13,16 +15,23 @@
 #include <sys/wait.h>
 
 #include "base/debug_util.h"
 #include "base/eintr_wrapper.h"
 #include "base/file_util.h"
 #include "base/logging.h"
 #include "base/string_tokenizer.h"
 #include "base/string_util.h"
+#include "nsLiteralString.h"
+
+#ifdef MOZ_B2G_LOADER
+#include "ProcessUtils.h"
+
+using namespace mozilla::ipc;
+#endif	// MOZ_B2G_LOADER
 
 #ifdef MOZ_WIDGET_GONK
 /*
  * AID_APP is the first application UID used by Android. We're using
  * it as our unprivilegied UID.  This ensure the UID used is not
  * shared with any other processes than our own childs.
  */
 # include <private/android_filesystem_config.h>
@@ -183,22 +192,81 @@ bool LaunchApp(const std::vector<std::st
                const environment_map& env_vars_to_set,
                bool wait, ProcessHandle* process_handle,
                ProcessArchitecture arch) {
   return LaunchApp(argv, fds_to_remap, env_vars_to_set,
                    PRIVILEGES_INHERIT,
                    wait, process_handle);
 }
 
+#ifdef MOZ_B2G_LOADER
+/**
+ * Launch an app using B2g Loader.
+ */
+static bool
+LaunchAppProcLoader(const std::vector<std::string>& argv,
+                    const file_handle_mapping_vector& fds_to_remap,
+                    const environment_map& env_vars_to_set,
+                    ChildPrivileges privs,
+                    ProcessHandle* process_handle) {
+  size_t i;
+  scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
+  for (i = 0; i < argv.size(); i++) {
+    argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+  }
+  argv_cstr[argv.size()] = nullptr;
+
+  scoped_array<char*> env_cstr(new char*[env_vars_to_set.size() + 1]);
+  i = 0;
+  for (environment_map::const_iterator it = env_vars_to_set.begin();
+       it != env_vars_to_set.end(); ++it) {
+    env_cstr[i++] = strdup((it->first + "=" + it->second).c_str());
+  }
+  env_cstr[env_vars_to_set.size()] = nullptr;
+
+  bool ok = ProcLoaderLoad((const char **)argv_cstr.get(),
+                           (const char **)env_cstr.get(),
+                           fds_to_remap, privs,
+                           process_handle);
+  MOZ_ASSERT(ok, "ProcLoaderLoad() failed");
+
+  for (size_t i = 0; i < env_vars_to_set.size(); i++) {
+    free(env_cstr[i]);
+  }
+
+  return ok;
+}
+
+static bool
+IsLaunchingNuwa(const std::vector<std::string>& argv) {
+  std::vector<std::string>::const_iterator it;
+  for (it = argv.begin(); it != argv.end(); ++it) {
+    if (*it == std::string("-nuwa")) {
+      return true;
+    }
+  }
+  return false;
+}
+#endif // MOZ_B2G_LOADER
+
 bool LaunchApp(const std::vector<std::string>& argv,
                const file_handle_mapping_vector& fds_to_remap,
                const environment_map& env_vars_to_set,
                ChildPrivileges privs,
                bool wait, ProcessHandle* process_handle,
                ProcessArchitecture arch) {
+#ifdef MOZ_B2G_LOADER
+  static bool beforeFirstNuwaLaunch = true;
+  if (!wait && beforeFirstNuwaLaunch && IsLaunchingNuwa(argv)) {
+    beforeFirstNuwaLaunch = false;
+    return LaunchAppProcLoader(argv, fds_to_remap, env_vars_to_set,
+                               privs, process_handle);
+  }
+#endif // MOZ_B2G_LOADER
+
   scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
   // Illegal to allocate memory after fork and before execvp
   InjectiveMultimap fd_shuffle1, fd_shuffle2;
   fd_shuffle1.reserve(fds_to_remap.size());
   fd_shuffle2.reserve(fds_to_remap.size());
 
 #ifdef HAVE_PR_DUPLICATE_ENVIRONMENT
   Environment env;
new file mode 100644
--- /dev/null
+++ b/ipc/contentproc/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; c-basic-offset: 4; 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/.
+
+LIBRARY_NAME = 'plugin-container'
+if CONFIG['MOZ_B2G_LOADER']:
+    FINAL_LIBRARY = 'xul'
+
+SOURCES += [
+    'plugin-container.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    LOCAL_INCLUDES += [
+        '/toolkit/xre',
+        '/xpcom/base',
+    ]
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    # For sandbox includes and the include dependencies those have
+    LOCAL_INCLUDES += [
+        '/security',
+        '/security/sandbox',
+        '/security/sandbox/chromium',
+    ]
copy from ipc/app/MozillaRuntimeMain.cpp
copy to ipc/contentproc/plugin-container.cpp
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/contentproc/plugin-container.cpp
@@ -76,17 +76,17 @@ void StartSandboxCallback()
         sandbox::TargetServices* target_service =
             sandbox::SandboxFactory::GetTargetServices();
         target_service->LowerToken();
     }
 }
 #endif
 
 int
-main(int argc, char* argv[])
+content_process_main(int argc, char* argv[])
 {
     bool isNuwa = false;
     for (int i = 1; i < argc; i++) {
         isNuwa |= strcmp(argv[i], "-nuwa") == 0;
 #if defined(XP_WIN)
         gIsSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
 #endif
     }
new file mode 100644
--- /dev/null
+++ b/ipc/glue/PProcLoader.ipdl
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 autoindent cindent expandtab: */
+/* 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/. */
+
+namespace mozilla {
+namespace ipc {
+
+struct FDRemap {
+  FileDescriptor fd;
+  int mapto;
+};
+
+protocol PProcLoader
+{
+child:
+  /**
+   * Request B2G loader service to load content process.
+   *
+   * It actually calls the main() function of plugin-container.
+   */
+  async Load(nsCString[] argv, nsCString[] env,
+             FDRemap[] fdsRemap, uint32_t privs,
+             int32_t cookie);
+
+parent:
+  /**
+   * The acknowledgement of Load().
+   */
+  async LoadComplete(int32_t pid, int32_t cookie);
+};
+
+}
+}
--- a/ipc/glue/ProcessUtils.h
+++ b/ipc/glue/ProcessUtils.h
@@ -1,19 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 autoindent cindent expandtab: */
 /* 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_ipc_ProcessUtils_h
 #define mozilla_ipc_ProcessUtils_h
 
+#ifdef MOZ_B2G_LOADER
+#include "base/process_util.h"
+#endif
+
 namespace mozilla {
 namespace ipc {
 
 // You probably should call ContentChild::SetProcessName instead of calling
 // this directly.
 void SetThisProcessName(const char *aName);
 
+#ifdef MOZ_B2G_LOADER
+// see ProcessUtils_linux.cpp for explaination.
+void ProcLoaderClientGeckoInit();
+
+bool ProcLoaderLoad(const char *aArgv[],
+                    const char *aEnvp[],
+                    const base::file_handle_mapping_vector &aFdsRemap,
+                    const base::ChildPrivileges aPrivs,
+                    base::ProcessHandle *aProcessHandle);
+#endif /* MOZ_B2G_LOADER */
+
 } // namespace ipc
 } // namespace mozilla
 
 #endif // ifndef mozilla_ipc_ProcessUtils_h
 
--- a/ipc/glue/ProcessUtils_linux.cpp
+++ b/ipc/glue/ProcessUtils_linux.cpp
@@ -1,20 +1,570 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 autoindent cindent expandtab: */
 /* 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 "ProcessUtils.h"
 
 #include "nsString.h"
 
 #include <sys/prctl.h>
 
+#ifdef MOZ_B2G_LOADER
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "nsAutoPtr.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/ipc/PProcLoaderParent.h"
+#include "mozilla/ipc/PProcLoaderChild.h"
+#include "mozilla/ipc/Transport.h"
+#include "mozilla/ipc/FileDescriptorUtils.h"
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/dom/ContentProcess.h"
+#include "base/file_descriptor_shuffle.h"
+#include "mozilla/BackgroundHangMonitor.h"
+#include "mozilla/DebugOnly.h"
+#include "base/process_util.h"
+
+#include "prenv.h"
+
+#include "nsXULAppAPI.h" // export XRE_* functions
+
+#include "nsAppRunner.h"
+
+int content_process_main(int argc, char *argv[]);
+
+extern bool gDisableAndroidLog;
+
+#endif /* MOZ_B2G_LOADER */
+
 namespace mozilla {
 namespace ipc {
 
 void SetThisProcessName(const char *aName)
 {
   prctl(PR_SET_NAME, (unsigned long)aName, 0uL, 0uL, 0uL);
 }
 
+#ifdef MOZ_B2G_LOADER
+/**
+ * How does B2G Loader Work?
+ *
+ *  <<parent process>>      <<child process>>
+ *   ProcLoaderParent -----> ProcLoaderChild
+ *         ^                       |
+ *         | load()                | content_process_main()
+ *         |                       V
+ *     ProcLoaderClient      Nuwa/plugin-container
+ *         ^
+ *         | ProcLoaderLoad()
+ *        ...
+ *     ContentParent
+ *
+ *
+ * B2G loader includes an IPC protocol PProcLoader for communication
+ * between client (parent) and server (child).  The b2g process is the
+ * client.  It requests the server to load/start the Nuwa process with
+ * the given arguments, env variables, and file descriptors.
+ *
+ * ProcLoaderClientInit() is called by B2G loader to initialize the
+ * client side, the b2g process.  Then the b2g_main() is called to
+ * start b2g process.
+ *
+ * ProcLoaderClientGeckoInit() is called by XRE_main() to create the
+ * parent actor, |ProcLoaderParent|, of PProcLoader for servicing the
+ * request to run Nuwa process later once Gecko has been initialized.
+ *
+ * ProcLoaderServiceRun() is called by the server process.  It starts
+ * an IOThread and event loop to serve the |ProcLoaderChild|
+ * implmentation of PProcLoader protocol as the child actor.  Once it
+ * recieves a load() request, it stops the IOThread and event loop,
+ * then starts running the main function of the content process with
+ * the given arguments.
+ *
+ * NOTE: The server process serves at most one load() request.
+ */
+
+using namespace base;
+using namespace mozilla::dom;
+
+static bool sProcLoaderClientOnDeinit = false;
+static DebugOnly<bool> sProcLoaderClientInitialized = false;
+static DebugOnly<bool> sProcLoaderClientGeckoInitialized = false;
+static pid_t sProcLoaderPid = 0;
+static int sProcLoaderChannelFd = -1;
+static PProcLoaderParent *sProcLoaderParent = nullptr;
+static MessageLoop *sProcLoaderLoop = nullptr;
+
+static void ProcLoaderClientDeinit();
+
+
+class ProcLoaderParent : public PProcLoaderParent
+{
+private:
+  nsAutoPtr<FileDescriptor> mChannelFd; // To keep a reference.
+
+public:
+  ProcLoaderParent(FileDescriptor *aFd) : mChannelFd(aFd) {}
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool RecvLoadComplete(const int32_t &aPid,
+                                const int32_t &aCookie) MOZ_OVERRIDE;
+
+  virtual void OnChannelError() MOZ_OVERRIDE;
+};
+
+void
+ProcLoaderParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+static void
+_ProcLoaderParentDestroy(PProcLoaderParent *aLoader)
+{
+  aLoader->Close();
+  delete aLoader;
+  sProcLoaderClientOnDeinit = false;
+}
+
+bool
+ProcLoaderParent::RecvLoadComplete(const int32_t &aPid,
+                                   const int32_t &aCookie)
+{
+  ProcLoaderClientDeinit();
+  return true;
+}
+
+void
+ProcLoaderParent::OnChannelError()
+{
+  if (sProcLoaderClientOnDeinit) {
+    // Get error for closing while the channel is already error.
+    return;
+  }
+  NS_WARNING("ProcLoaderParent is in channel error");
+  ProcLoaderClientDeinit();
+}
+
+/**
+ * Initialize the client of B2G loader for loader itself.
+ *
+ * The initialization of B2G loader are divided into two stages. First
+ * stage is to collect child info passed from the main program of the
+ * loader.  Second stage is to initialize Gecko according to info from the
+ * first stage and make the client of loader service ready.
+ *
+ * \param aPeerPid is the pid of the child.
+ * \param aChannelFd is the file descriptor of the socket used for IPC.
+ */
+static void
+ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd)
+{
+  MOZ_ASSERT(!sProcLoaderClientInitialized, "call ProcLoaderClientInit() more than once");
+  MOZ_ASSERT(aPeerPid != 0 && aChannelFd != -1, "invalid argument");
+  sProcLoaderPid = aPeerPid;
+  sProcLoaderChannelFd = aChannelFd;
+  sProcLoaderClientInitialized = true;
+}
+
+/**
+ * Initialize the client of B2G loader for Gecko.
+ */
+void
+ProcLoaderClientGeckoInit()
+{
+  MOZ_ASSERT(sProcLoaderClientInitialized, "call ProcLoaderClientInit() at first");
+  MOZ_ASSERT(!sProcLoaderClientGeckoInitialized,
+             "call ProcLoaderClientGeckoInit() more than once");
+
+  sProcLoaderClientGeckoInitialized = true;
+
+  FileDescriptor *fd = new FileDescriptor(sProcLoaderChannelFd);
+  close(sProcLoaderChannelFd);
+  sProcLoaderChannelFd = -1;
+  Transport *transport = OpenDescriptor(*fd, Transport::MODE_CLIENT);
+  sProcLoaderParent = new ProcLoaderParent(fd);
+  sProcLoaderParent->Open(transport,
+                          sProcLoaderPid,
+                          XRE_GetIOMessageLoop(),
+                          ParentSide);
+  sProcLoaderLoop = MessageLoop::current();
+}
+
+/**
+ * Shutdown and destroy the client of B2G loader service.
+ */
+static void
+ProcLoaderClientDeinit()
+{
+  MOZ_ASSERT(sProcLoaderClientGeckoInitialized && sProcLoaderClientInitialized);
+  sProcLoaderClientGeckoInitialized = false;
+  sProcLoaderClientInitialized = false;
+
+  sProcLoaderClientOnDeinit = true;
+
+  MOZ_ASSERT(sProcLoaderParent != nullptr);
+  PProcLoaderParent *procLoaderParent = sProcLoaderParent;
+  sProcLoaderParent = nullptr;
+  sProcLoaderLoop = nullptr;
+
+  MessageLoop::current()->
+    PostTask(FROM_HERE,
+             NewRunnableFunction(&_ProcLoaderParentDestroy,
+                                 procLoaderParent));
+}
+
+struct AsyncSendLoadData
+{
+  nsTArray<nsCString> mArgv;
+  nsTArray<nsCString> mEnv;
+  nsTArray<FDRemap> mFdsremap;
+  ChildPrivileges mPrivs;
+  int mCookie;
+};
+
+static void
+AsyncSendLoad(AsyncSendLoadData *aLoad)
+{
+  PProcLoaderParent *loader = sProcLoaderParent;
+  DebugOnly<bool> ok =
+    loader->SendLoad(aLoad->mArgv, aLoad->mEnv, aLoad->mFdsremap,
+                     aLoad->mPrivs, aLoad->mCookie);
+  MOZ_ASSERT(ok);
+  delete aLoad;
+}
+
+/**
+ * Request the loader service, the server, to load Nuwa.
+ */
+bool
+ProcLoaderLoad(const char *aArgv[],
+               const char *aEnvp[],
+               const file_handle_mapping_vector &aFdsRemap,
+               const ChildPrivileges aPrivs,
+               ProcessHandle *aProcessHandle)
+{
+  static int cookie=0;
+  int i;
+
+  if (sProcLoaderParent == nullptr || sProcLoaderPid == 0) {
+    return false;
+  }
+
+  AsyncSendLoadData *load = new AsyncSendLoadData();
+  nsTArray<nsCString> &argv = load->mArgv;
+  for (i = 0; aArgv[i] != nullptr; i++) {
+    argv.AppendElement(nsCString(aArgv[i]));
+  }
+  nsTArray<nsCString> &env = load->mEnv;
+  for (i = 0; aEnvp[i] != nullptr; i++) {
+    env.AppendElement(nsCString(aEnvp[i]));
+  }
+  nsTArray<FDRemap> &fdsremap = load->mFdsremap;
+  for (file_handle_mapping_vector::const_iterator fdmap =
+         aFdsRemap.begin();
+       fdmap != aFdsRemap.end();
+       fdmap++) {
+    fdsremap.AppendElement(FDRemap(FileDescriptor(fdmap->first), fdmap->second));
+  }
+  load->mPrivs = aPrivs;
+  load->mCookie = cookie++;
+
+  *aProcessHandle = sProcLoaderPid;
+  sProcLoaderPid = 0;
+
+  sProcLoaderLoop->PostTask(FROM_HERE,
+                            NewRunnableFunction(AsyncSendLoad, load));
+  return true;
+}
+
+
+class ProcLoaderRunnerBase;
+
+static bool sProcLoaderServing = false;
+static ProcLoaderRunnerBase *sProcLoaderDispatchedTask = nullptr;
+
+class ProcLoaderRunnerBase
+{
+public:
+  virtual int DoWork() = 0;
+};
+
+
+class ProcLoaderNoopRunner : public ProcLoaderRunnerBase {
+public:
+  virtual int DoWork();
+};
+
+int
+ProcLoaderNoopRunner::DoWork() {
+  return 0;
+}
+
+
+/**
+ * The runner to load Nuwa at the current process.
+ */
+class ProcLoaderLoadRunner : public ProcLoaderRunnerBase {
+private:
+  const nsTArray<nsCString> mArgv;
+  const nsTArray<nsCString> mEnv;
+  const nsTArray<FDRemap> mFdsRemap;
+  const ChildPrivileges mPrivs;
+
+  void ShuffleFds();
+
+public:
+  ProcLoaderLoadRunner(const InfallibleTArray<nsCString>& aArgv,
+                       const InfallibleTArray<nsCString>& aEnv,
+                       const InfallibleTArray<FDRemap>& aFdsRemap,
+                       const ChildPrivileges aPrivs)
+    : mArgv(aArgv)
+    , mEnv(aEnv)
+    , mFdsRemap(aFdsRemap)
+    , mPrivs(aPrivs) {}
+
+  int DoWork();
+};
+
+void
+ProcLoaderLoadRunner::ShuffleFds()
+{
+  unsigned int i;
+
+  InjectiveMultimap fd_shuffle1, fd_shuffle2;
+  fd_shuffle1.reserve(mFdsRemap.Length());
+  fd_shuffle2.reserve(mFdsRemap.Length());
+  for (i = 0; i < mFdsRemap.Length(); i++) {
+    const FDRemap *map = &mFdsRemap[i];
+    int fd = map->fd().PlatformHandle();
+    int tofd = map->mapto();
+
+    fd_shuffle1.push_back(InjectionArc(fd, tofd, false));
+    fd_shuffle2.push_back(InjectionArc(fd, tofd, false));
+  }
+
+  DebugOnly<bool> ok = ShuffleFileDescriptors(&fd_shuffle1);
+  MOZ_ASSERT(ok, "ShuffleFileDescriptors failed");
+
+  CloseSuperfluousFds(fd_shuffle2);
+}
+
+int
+ProcLoaderLoadRunner::DoWork()
+{
+  unsigned int i;
+
+  ShuffleFds();
+
+  unsigned int argc = mArgv.Length();
+  char **argv = new char *[argc + 1];
+  for (i = 0; i < argc; i++) {
+    argv[i] = ::strdup(mArgv[i].get());
+  }
+  argv[argc] = nullptr;
+
+  unsigned int envc = mEnv.Length();
+  for (i = 0; i < envc; i++) {
+    PR_SetEnv(mEnv[i].get());
+  }
+
+  SetCurrentProcessPrivileges(mPrivs);
+
+  MOZ_ASSERT(content_process_main != nullptr,
+             "content_process_main not found");
+  // Start Nuwa (main function)
+  int ret = content_process_main(argc, argv);
+
+  for (i = 0; i < argc; i++) {
+    free(argv[i]);
+  }
+  delete[] argv;
+
+  return ret;
+}
+
+
+class ProcLoaderChild : public PProcLoaderChild
+{
+  pid_t mPeerPid;
+
+public:
+  ProcLoaderChild(pid_t aPeerPid) : mPeerPid(aPeerPid) {}
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool RecvLoad(const InfallibleTArray<nsCString>& aArgv,
+                        const InfallibleTArray<nsCString>& aEnv,
+                        const InfallibleTArray<FDRemap>& aFdsremap,
+                        const uint32_t& aPrivs,
+                        const int32_t& aCookie);
+
+  virtual void OnChannelError();
+};
+
+void
+ProcLoaderChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+static void
+_ProcLoaderChildDestroy(ProcLoaderChild *aChild)
+{
+  aChild->Close();
+  delete aChild;
+  MessageLoop::current()->Quit();
+}
+
+bool
+ProcLoaderChild::RecvLoad(const InfallibleTArray<nsCString>& aArgv,
+                          const InfallibleTArray<nsCString>& aEnv,
+                          const InfallibleTArray<FDRemap>& aFdsRemap,
+                          const uint32_t& aPrivs,
+                          const int32_t& aCookie) {
+  if (!sProcLoaderServing) {
+    return true;
+  }
+  sProcLoaderServing = false;
+
+  MOZ_ASSERT(sProcLoaderDispatchedTask == nullptr);
+  ChildPrivileges privs = static_cast<ChildPrivileges>(aPrivs);
+  sProcLoaderDispatchedTask =
+    new ProcLoaderLoadRunner(aArgv, aEnv, aFdsRemap, privs);
+
+  SendLoadComplete(mPeerPid, aCookie);
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   NewRunnableFunction(_ProcLoaderChildDestroy,
+                                                       this));
+  return true;
+}
+
+void
+ProcLoaderChild::OnChannelError()
+{
+  if (!sProcLoaderServing) {
+    return;
+  }
+  sProcLoaderServing = false;
+
+  PProcLoaderChild::OnChannelError();
+
+  MOZ_ASSERT(sProcLoaderDispatchedTask == nullptr);
+  sProcLoaderDispatchedTask = new ProcLoaderNoopRunner();
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   NewRunnableFunction(_ProcLoaderChildDestroy,
+                                                       this));
+}
+
+/**
+ * A helper class which calls NS_LogInit/NS_LogTerm in its scope.
+ */
+class ScopedLogging
+{
+public:
+  ScopedLogging() { NS_LogInit(); }
+  ~ScopedLogging() { NS_LogTerm(); }
+};
+
+/**
+ * Run service of ProcLoader.
+ *
+ * \param aPeerPid is the pid of the parent.
+ * \param aFd is the file descriptor of the socket for IPC.
+ *
+ * See the comment near the head of this file.
+ */
+static int
+ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
+                     int aArgc, const char *aArgv[])
+{
+  ScopedLogging logging;
+
+  char **_argv;
+  _argv = new char *[aArgc + 1];
+  for (int i = 0; i < aArgc; i++) {
+    _argv[i] = ::strdup(aArgv[i]);
+    MOZ_ASSERT(_argv[i] != nullptr);
+  }
+  _argv[aArgc] = nullptr;
+
+  gArgv = _argv;
+  gArgc = aArgc;
+
+  {
+    gDisableAndroidLog = true;
+
+    nsresult rv = XRE_InitCommandLine(aArgc, _argv);
+    if (NS_FAILED(rv)) {
+      gDisableAndroidLog = false;
+      MOZ_CRASH();
+    }
+
+    FileDescriptor fd(aFd);
+    close(aFd);
+
+    MOZ_ASSERT(!sProcLoaderServing);
+    MessageLoop loop;
+
+    nsAutoPtr<ContentProcess> process;
+    process = new ContentProcess(aPeerPid);
+    ChildThread *iothread = process->child_thread();
+
+    Transport *transport = OpenDescriptor(fd, Transport::MODE_CLIENT);
+    ProcLoaderChild *loaderChild = new ProcLoaderChild(aPeerPid);
+    // Pass a message loop to initialize (connect) the channel
+    // (connection).
+    loaderChild->Open(transport, aPeerPid, iothread->message_loop());
+
+    BackgroundHangMonitor::Prohibit();
+
+    sProcLoaderServing = true;
+    loop.Run();
+
+    BackgroundHangMonitor::Allow();
+
+    XRE_DeinitCommandLine();
+
+    gDisableAndroidLog = false;
+  }
+
+  MOZ_ASSERT(sProcLoaderDispatchedTask != nullptr);
+  ProcLoaderRunnerBase *task = sProcLoaderDispatchedTask;
+  sProcLoaderDispatchedTask = nullptr;
+  int ret = task->DoWork();
+  delete task;
+
+  for (int i = 0; i < aArgc; i++) {
+    free(_argv[i]);
+  }
+  delete[] _argv;
+
+  return ret;
+}
+
+#endif /* MOZ_B2G_LOADER */
+
 } // namespace ipc
 } // namespace mozilla
+
+#ifdef MOZ_B2G_LOADER
+void
+XRE_ProcLoaderClientInit(pid_t aPeerPid, int aChannelFd)
+{
+  mozilla::ipc::ProcLoaderClientInit(aPeerPid, aChannelFd);
+}
+
+int
+XRE_ProcLoaderServiceRun(pid_t aPeerPid, int aFd,
+                         int aArgc, const char *aArgv[])
+{
+  return mozilla::ipc::ProcLoaderServiceRun(aPeerPid, aFd,
+                                            aArgc, aArgv);
+}
+#endif /* MOZ_B2G_LOADER */
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -125,22 +125,24 @@ LOCAL_INCLUDES += [
     '/xpcom/build',
 ]
 
 IPDL_SOURCES = [
     'InputStreamParams.ipdlh',
     'PBackground.ipdl',
     'PBackgroundSharedTypes.ipdlh',
     'PBackgroundTest.ipdl',
+    'PProcLoader.ipdl',
     'ProtocolTypes.ipdlh',
     'URIParams.ipdlh',
 ]
 
 
 LOCAL_INCLUDES += [
+    '/toolkit/xre',
     '/xpcom/threads',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 for var in ('MOZ_CHILD_PROCESS_NAME', 'MOZ_CHILD_PROCESS_BUNDLE',
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -21,9 +21,12 @@ if CONFIG['MOZ_NFC']:
     DIRS += ['nfc']
 
 if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['unixfd', 'unixsocket']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DIRS += ['keystore', 'netd']
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
+    DIRS += ['contentproc']
+
 DIRS += ['app']
--- a/layout/base/nsCSSColorUtils.h
+++ b/layout/base/nsCSSColorUtils.h
@@ -10,17 +10,18 @@
 
 #include "nsColor.h"
 
 // "Sufficient contrast" is determined by
 // "Techniques For Accessibility Evalution And Repair Tools".
 // See http://www.w3.org/TR/AERT#color-contrast
 #define NS_SUFFICIENT_LUMINOSITY_DIFFERENCE 125000
 #define NS_LUMINOSITY_DIFFERENCE(a, b) \
-          int32_t(mozilla::Abs(NS_GetLuminosity(a) - NS_GetLuminosity(b)))
+          int32_t(mozilla::Abs( \
+            NS_GetLuminosity(a | 0xff000000) - NS_GetLuminosity(b | 0xff000000)))
 
 // To determine colors based on the background brightness and border color
 void NS_GetSpecial3DColors(nscolor aResult[2],
                            nscolor aBackgroundColor,
                            nscolor aBorderColor);
 
 // Determins brightness for a specific color
 int NS_GetBrightness(uint8_t aRed, uint8_t aGreen, uint8_t aBlue);
--- a/media/mtransport/third_party/moz.build
+++ b/media/mtransport/third_party/moz.build
@@ -45,17 +45,16 @@ nICEr_non_unified_sources += [
     'nICEr/src/util/mbslen.c',
 ]
 nrappkit_non_unified_sources = [
     'nrappkit/src/log/r_log.c',
     'nrappkit/src/util/byteorder.c',
     'nrappkit/src/util/hex.c',
     'nrappkit/src/util/libekr/debug.c',
     'nrappkit/src/util/libekr/r_assoc.c',
-    'nrappkit/src/util/libekr/r_bitfield.c',
     'nrappkit/src/util/libekr/r_crc32.c',
     'nrappkit/src/util/libekr/r_data.c',
     'nrappkit/src/util/libekr/r_errors.c',
     'nrappkit/src/util/libekr/r_list.c',
     'nrappkit/src/util/libekr/r_memory.c',
     'nrappkit/src/util/libekr/r_replace.c',
     'nrappkit/src/util/libekr/r_time.c',
     'nrappkit/src/util/p_buf.c',
--- a/media/mtransport/third_party/nrappkit/IMPORT_FILES
+++ b/media/mtransport/third_party/nrappkit/IMPORT_FILES
@@ -5,18 +5,16 @@
               src/share/nr_reg_keys.h
 
               # libekr
               src/util/libekr/assoc.h
               src/util/libekr/debug.c
               src/util/libekr/debug.h
               src/util/libekr/r_assoc.c
               src/util/libekr/r_assoc.h
-              src/util/libekr/r_bitfield.c
-              src/util/libekr/r_bitfield.h
               src/util/libekr/r_common.h
               src/util/libekr/r_crc32.c
               src/util/libekr/r_crc32.h
               src/util/libekr/r_data.c
               src/util/libekr/r_data.h
               src/util/libekr/r_defaults.h
               src/util/libekr/r_errors.c
               src/util/libekr/r_errors.h
--- a/media/mtransport/third_party/nrappkit/nrappkit.gyp
+++ b/media/mtransport/third_party/nrappkit/nrappkit.gyp
@@ -37,18 +37,16 @@
 
               # libekr
               './src/util/libekr/assoc.h',
               './src/util/libekr/debug.c',
               './src/util/libekr/debug.h',
               './src/util/libekr/r_assoc.c',
               './src/util/libekr/r_assoc.h',
 #              './src/util/libekr/r_assoc_test.c',
-              './src/util/libekr/r_bitfield.c',
-              './src/util/libekr/r_bitfield.h',
               './src/util/libekr/r_common.h',
               './src/util/libekr/r_crc32.c',
               './src/util/libekr/r_crc32.h',
               './src/util/libekr/r_data.c',
               './src/util/libekr/r_data.h',
               './src/util/libekr/r_defaults.h',
               './src/util/libekr/r_errors.c',
               './src/util/libekr/r_errors.h',
deleted file mode 100644
--- a/media/mtransport/third_party/nrappkit/src/util/libekr/r_bitfield.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
-   r_bitfield.c
-
-
-   Copyright (C) 2002-2003, Network Resonance, Inc.
-   Copyright (C) 2006, Network Resonance, Inc.
-   All Rights Reserved
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions
-   are met:
-
-   1. Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-   2. Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-   3. Neither the name of Network Resonance, Inc. nor the name of any
-      contributors to this software may be used to endorse or promote
-      products derived from this software without specific prior written
-      permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
-   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-   POSSIBILITY OF SUCH DAMAGE.
-
-
- */
-
-/**
-   r_bitfield.c
-
-   Copyright (C) 2001 RTFM, Inc.
-   All Rights Reserved.
-
-   ekr@rtfm.com  Wed Oct  3 11:15:23 2001
- */
-
-
-static char *RCSSTRING __UNUSED__ ="$Id: r_bitfield.c,v 1.2 2006/08/16 19:39:17 adamcain Exp $";
-
-#include <string.h>
-#include <r_common.h>
-#include <string.h>
-#include "r_bitfield.h"
-
-int r_bitfield_create(setp,size)
-  r_bitfield **setp;
-  UINT4 size;
-  {
-    r_bitfield *set=0;
-    int _status;
-    int num_words=size/32+!!(size%32);
-
-    if(!(set=(r_bitfield *)RMALLOC(sizeof(r_bitfield))))
-      ABORT(R_NO_MEMORY);
-
-    if(!(set->data=(UINT4 *)RMALLOC(num_words*4)))
-      ABORT(R_NO_MEMORY);
-    memset(set->data,0,4*num_words);
-
-    set->base=0;
-    set->len=num_words;
-
-    *setp=set;
-
-    _status=0;
-  abort:
-    if(_status){
-      r_bitfield_destroy(&set);
-    }
-    return(_status);
-  }
-
-int r_bitfield_destroy(setp)
-  r_bitfield **setp;
-  {
-    r_bitfield *set;
-
-    if(!setp || !*setp)
-      return(0);
-
-    set=*setp;
-
-    RFREE(set->data);
-    RFREE(set);
-
-    *setp=0;
-    return(0);
-  }
-
-int r_bitfield_set(set,bit)
-  r_bitfield *set;
-  int bit;
-  {
-    int word=(bit-set->base)/32;
-    int bbit=(bit-set->base)%32;
-    int _status;
-
-    /* Resize? */
-    if(word>set->len){
-      UINT4 newlen=set->len;
-      UINT4 *tmp;
-
-      while(newlen<word)
-	newlen*=2;
-
-      if(!(tmp=(UINT4 *)RMALLOC(newlen)))
-	ABORT(R_NO_MEMORY);
-
-      memcpy(tmp,set->data,set->len*4);
-      memset(tmp+set->len*4,0,(newlen-set->len)*4);
-
-      RFREE(set->data);
-      set->data=tmp;
-    }
-
-    set->data[word]|=1<<bbit;
-
-    _status=0;
-  abort:
-    return(_status);
-  }
-
-int r_bitfield_isset(set,bit)
-  r_bitfield *set;
-  int bit;
-  {
-    int word=(bit-set->base)/32;
-    int bbit=(bit-set->base)%32;
-    int _status;
-
-    if(bit<set->base)
-      return(0);
-
-    /* Resize? */
-    if(word>set->len)
-      return(0);
-
-    return(set->data[word]&(1<<bbit));
-
-    _status=0;
-    return(_status);
-  }
deleted file mode 100644
--- a/media/mtransport/third_party/nrappkit/src/util/libekr/r_bitfield.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
-   r_bitfield.h
-
-
-   Copyright (C) 2002-2003, Network Resonance, Inc.
-   Copyright (C) 2006, Network Resonance, Inc.
-   All Rights Reserved
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions
-   are met:
-
-   1. Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-   2. Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-   3. Neither the name of Network Resonance, Inc. nor the name of any
-      contributors to this software may be used to endorse or promote
-      products derived from this software without specific prior written
-      permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
-   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-   POSSIBILITY OF SUCH DAMAGE.
-
-
- */
-
-/**
-   r_bitfield.h
-
-   Copyright (C) 2001 RTFM, Inc.
-   All Rights Reserved.
-
-   ekr@rtfm.com  Wed Oct  3 10:43:50 2001
- */
-
-
-#ifndef _r_bitfield_h
-#define _r_bitfield_h
-
-typedef struct r_bitfield_ {
-     UINT4 *data;
-     UINT4 len;
-     UINT4 base;
-} r_bitfield;
-
-int r_bitfield_set(r_bitfield *,int bit);
-int r_bitfield_isset(r_bitfield *,int bit);
-int r_bitfield_create(r_bitfield **setp,UINT4 size);
-int r_bitfield_destroy(r_bitfield **setp);
-
-#endif
-
--- a/netwerk/protocol/rtsp/rtsp/AH263Assembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/AH263Assembler.cpp
@@ -94,28 +94,80 @@ ARTPAssembler::AssemblyStatus AH263Assem
 
     if (buffer->size() < 2) {
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
 
         return MALFORMED_PACKET;
     }
 
+    // RFC 4629, Sec. 5.1 General H.263+ Payload Header.
+    // The H.263+ payload header is structured as follows:
+    //  0                   1
+    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    // |   RR    |P|V|   PLEN    |PEBIT|
+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //
+    // RR: 5 bits
+    //     Reserved bits. It SHALL be zero and MUST be ignored by receivers.
+    // P: 1 bit
+    //     Indicates the picture start or a picture segment (GOB/Slice) start or
+    //     a video sequence end (EOS or EOSBS). Two bytes of zero bits then have
+    //     to be prefixed to the payload of such a packet to compose a complete
+    //     picture/GOB/slice/EOS/EOSBS start code. This bit allows the omission
+    //     of the two first bytes of the start code, thus improving the
+    //     compression ratio.
+    // V: 1 bit
+    //     Indicates the presence of an 8-bit field containing information for
+    //     Video Redundancy Coding (VRC), which follows immediately after the
+    //     initial 16 bits of the payload header.
+    // PLEN: 6 bits
+    //     Length, in bytes, of the extra picture header. If no extra picture
+    //     header is attached, PLEN is 0. If PLEN>0, the extra picture header is
+    //     attached immediately following the rest of the payload header. Note
+    //     that the length reflects the omission of the first two bytes of the
+    //     picture start code (PSC).
+    // PEBIT: 3 bits
+    //     Indicates the number of bits that shall be ignored in the last byte
+    //     of the picture header. If PLEN is not zero, the ignored bits shall be
+    //     the least significant bits of the byte. If PLEN is zero, then PEBIT
+    //     shall also be zero.
+
     unsigned payloadHeader = U16_AT(buffer->data());
-    CHECK_EQ(payloadHeader >> 11, 0u);  // RR=0
     unsigned P = (payloadHeader >> 10) & 1;
-    CHECK_EQ((payloadHeader >> 9) & 1, 0u);  // V=0
-    CHECK_EQ((payloadHeader >> 3) & 0x3f, 0u);  // PLEN=0
-    CHECK_EQ(payloadHeader & 7, 0u);  // PEBIT=0
+    unsigned V = (payloadHeader >> 9) & 1;
+    unsigned PLEN = (payloadHeader >> 3) & 0x3f;
+    unsigned PEBIT = payloadHeader & 7;
+
+    // V = 0
+    // We do not support VRC header extension for now, so just discard it if
+    // present.
+    if (V != 0u) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+        ALOGW("Packet discarded due to VRC (V != 0)");
+        return MALFORMED_PACKET;
+    }
+
+    // If PLEN is zero, then PEBIT shall also be zero.
+    if (PLEN == 0u && PEBIT != 0u) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+        ALOGW("Packet discarded (PEBIT != 0)");
+        return MALFORMED_PACKET;
+    }
+
+    size_t skip = PLEN + (P ? 0: 2);
+
+    buffer->setRange(buffer->offset() + skip, buffer->size() - skip);
 
     if (P) {
         buffer->data()[0] = 0x00;
         buffer->data()[1] = 0x00;
-    } else {
-        buffer->setRange(buffer->offset() + 2, buffer->size() - 2);
     }
 
     mPackets.push_back(buffer);
 
     queue->erase(queue->begin());
     ++mNextExpectedSeqNo;
 
     return OK;
--- a/netwerk/protocol/rtsp/rtsp/APacketSource.cpp
+++ b/netwerk/protocol/rtsp/rtsp/APacketSource.cpp
@@ -210,22 +210,31 @@ static sp<ABuffer> MakeAVCCodecSpecificD
     }
 
     // hexdump(csd->data(), csd->size());
 
     return csd;
 }
 
 sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
+    if (!params || !strlen(params)) {
+      return NULL;
+    }
     AString val;
-    CHECK(GetAttribute(params, "config", &val));
+    if (!GetAttribute(params, "config", &val)) {
+        return NULL;
+    }
 
     sp<ABuffer> config = decodeHex(val);
-    CHECK(config != NULL);
-    CHECK_GE(config->size(), 4u);
+    if (!config.get()) {
+      return NULL;
+    }
+    if (config->size() < 4u) {
+      return NULL;
+    }
 
     const uint8_t *data = config->data();
     uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
     x = (x >> 1) & 0xffff;
 
     static const uint8_t kStaticESDS[] = {
         0x03, 22,
         0x00, 0x00,     // ES_ID
@@ -471,16 +480,20 @@ APacketSource::APacketSource(
         ASessionDescription::ParseFormatDesc(
                 desc.c_str(), &sampleRate, &numChannels);
 
         mFormat->setInt32(kKeySampleRate, sampleRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
 
         sp<ABuffer> codecSpecificData =
             MakeAACCodecSpecificData(params.c_str());
+        if (!codecSpecificData.get()) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
 
         mFormat->setData(
                 kKeyESDS, 0,
                 codecSpecificData->data(), codecSpecificData->size());
     } else if (!strncmp(desc.c_str(), "AMR/", 4)) {
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
 
         int32_t sampleRate, numChannels;
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -155,14 +155,16 @@ LOCAL_INCLUDES += [
     '/xpcom/build',
 ]
 
 if CONFIG['MOZ_ENABLE_XREMOTE']:
     LOCAL_INCLUDES += [
         '/widget/xremoteclient',
     ]
 
+if CONFIG['MOZ_B2G_LOADER']:
+    DEFINES['OMNIJAR_NAME'] = CONFIG['OMNIJAR_NAME']
 CXXFLAGS += CONFIG['TK_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
 
 if CONFIG['MOZ_WIDGET_GTK']:
     CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -180,16 +180,20 @@
 #include "nsIPrefService.h"
 #endif
 
 #include "base/command_line.h"
 #ifdef MOZ_ENABLE_TESTS
 #include "GTestRunner.h"
 #endif
 
+#ifdef MOZ_B2G_LOADER
+#include "ProcessUtils.h"
+#endif
+
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
 extern uint32_t gRestartMode;
 extern void InstallSignalHandlers(const char *ProgramName);
 
 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
@@ -3767,16 +3771,20 @@ XREMain::XRE_mainStartup(bool* aExitFlag
  * the calling of appStartup->Run().
  */
 nsresult
 XREMain::XRE_mainRun()
 {
   nsresult rv = NS_OK;
   NS_ASSERTION(mScopedXPCom, "Scoped xpcom not initialized.");
 
+#ifdef MOZ_B2G_LOADER
+  mozilla::ipc::ProcLoaderClientGeckoInit();
+#endif
+
 #ifdef NS_FUNCTION_TIMER
   // initialize some common services, so we don't pay the cost for these at odd times later on;
   // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs
   {
     nsCOMPtr<nsISupports> comp;
 
     comp = do_GetService("@mozilla.org/preferences-service;1");
 
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -76,16 +76,21 @@
 
 #ifdef MOZ_IPDL_TESTS
 #include "mozilla/_ipdltest/IPDLUnitTests.h"
 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
 
 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
 #endif  // ifdef MOZ_IPDL_TESTS
 
+#ifdef MOZ_B2G_LOADER
+#include "nsLocalFile.h"
+#include "nsXREAppData.h"
+#endif
+
 using namespace mozilla;
 
 using mozilla::ipc::BrowserProcessSubThread;
 using mozilla::ipc::GeckoChildProcessHost;
 using mozilla::ipc::IOThreadChild;
 using mozilla::ipc::ProcessChild;
 using mozilla::ipc::ScopedXREEmbed;
 
@@ -810,8 +815,43 @@ SetWindowsEnvironment(WindowsEnvironment
 
 WindowsEnvironmentType
 XRE_GetWindowsEnvironment()
 {
   return sWindowsEnvironmentType;
 }
 #endif // XP_WIN
 
+#ifdef MOZ_B2G_LOADER
+extern const nsXREAppData* gAppData;
+
+/**
+ * Preload static data of Gecko for B2G loader.
+ *
+ * This function is supposed to be called before XPCOM is initialized.
+ * For now, this function preloads
+ *  - XPT interface Information
+ */
+void
+XRE_ProcLoaderPreload(const char* aProgramDir, const nsXREAppData* aAppData)
+{
+    void PreloadXPT(nsIFile *);
+
+    nsresult rv;
+    nsCOMPtr<nsIFile> omnijarFile;
+    rv = NS_NewNativeLocalFile(nsCString(aProgramDir),
+			       true,
+			       getter_AddRefs(omnijarFile));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    rv = omnijarFile->AppendNative(NS_LITERAL_CSTRING(NS_STRINGIFY(OMNIJAR_NAME)));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+    /*
+     * gAppData is required by nsXULAppInfo.  The manifest parser
+     * evaluate flags with the information from nsXULAppInfo.
+     */
+    gAppData = aAppData;
+
+    PreloadXPT(omnijarFile);
+
+    gAppData = nullptr;
+}
+#endif /* MOZ_B2G_LOADER */
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -873,16 +873,20 @@ void mozilla_sampler_unlock()
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os)
     os->NotifyObservers(nullptr, "profiler-unlocked", nullptr);
 }
 
 bool mozilla_sampler_register_thread(const char* aName, void* stackTop)
 {
+  if (sInitCount == 0) {
+    return false;
+  }
+
 #if defined(MOZ_WIDGET_GONK) && !defined(MOZ_PROFILING)
   // The only way to profile secondary threads on b2g
   // is to build with profiling OR have the profiler
   // running on startup.
   if (!profiler_is_active()) {
     return false;
   }
 #endif
@@ -890,35 +894,47 @@ bool mozilla_sampler_register_thread(con
   PseudoStack* stack = new PseudoStack();
   tlsPseudoStack.set(stack);
   bool isMainThread = is_main_thread_name(aName);
   return Sampler::RegisterCurrentThread(aName, stack, isMainThread, stackTop);
 }
 
 void mozilla_sampler_unregister_thread()
 {
+  if (sInitCount == 0) {
+    return;
+  }
+
   Sampler::UnregisterCurrentThread();
 
   PseudoStack *stack = tlsPseudoStack.get();
   if (!stack) {
     return;
   }
   delete stack;
   tlsPseudoStack.set(nullptr);
 }
 
 void mozilla_sampler_sleep_start() {
+    if (sInitCount == 0) {
+	return;
+    }
+
     PseudoStack *stack = tlsPseudoStack.get();
     if (stack == nullptr) {
       return;
     }
     stack->setSleeping(1);
 }
 
 void mozilla_sampler_sleep_end() {
+    if (sInitCount == 0) {
+	return;
+    }
+
     PseudoStack *stack = tlsPseudoStack.get();
     if (stack == nullptr) {
       return;
     }
     stack->setSleeping(0);
 }
 
 double mozilla_sampler_time(const mozilla::TimeStamp& aTime)
new file mode 100644
--- /dev/null
+++ b/widget/gonk/PowerWakeLock.cpp
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 40; 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 "PowerWakeLock.h"
+#include <hardware_legacy/power.h>
+
+const char* kPower_WAKE_LOCK_ID = "PowerKeyEvent";
+
+namespace mozilla {
+namespace hal_impl {
+StaticRefPtr <PowerWakelock> gPowerWakelock;
+PowerWakelock::PowerWakelock()
+{
+  acquire_wake_lock(PARTIAL_WAKE_LOCK, kPower_WAKE_LOCK_ID);
+}
+
+PowerWakelock::~PowerWakelock()
+{
+  release_wake_lock(kPower_WAKE_LOCK_ID);
+}
+} // hal_impl
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gonk/PowerWakeLock.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 40; 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 __POWERWAKELOCK_H_
+#define __POWERWAKELOCK_H_
+
+#include "mozilla/StaticPtr.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace hal_impl {
+class PowerWakelock
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(PowerWakelock);
+  PowerWakelock();
+private:
+  ~PowerWakelock();
+};
+extern StaticRefPtr <PowerWakelock> gPowerWakelock;
+} // hal_impl
+} // mozilla
+#endif /* __POWERWAKELOCK_H_ */
--- a/widget/gonk/libui/EventHub.cpp
+++ b/widget/gonk/libui/EventHub.cpp
@@ -46,16 +46,22 @@
 #include <dirent.h>
 
 #include <sys/inotify.h>
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
 #include <sys/limits.h>
 #include <sha1.h>
 
+#include "PowerWakeLock.h"
+#include "mozilla/Hal.h"
+using namespace mozilla;
+using namespace mozilla::hal;
+using namespace mozilla::hal_impl;
+
 /* this macro is used to tell if "bit" is set in "array"
  * it selects a byte from the array, and does a boolean AND
  * operation with a byte that only has the relevant bit set.
  * eg. to check for the 12th bit, we do (array[1] & 1<<4)
  */
 #define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))
 
 /* this macro computes the number of bytes needed to represent a bit array of the specified size */
@@ -850,16 +856,20 @@ size_t EventHub::getEvents(int timeoutMi
                         }
 #else
                         event->when = now;
 #endif
                         event->deviceId = deviceId;
                         event->type = iev.type;
                         event->code = iev.code;
                         event->value = iev.value;
+			if (event->code == KEY_POWER && event->value
+                          && !hal::GetScreenEnabled()) {
+                          gPowerWakelock = new PowerWakelock();
+                        }
                         event += 1;
                         capacity -= 1;
                     }
                     if (capacity == 0) {
                         // The result buffer is full.  Reset the pending event index
                         // so we will try to read the device again on the next iteration.
                         mPendingEventIndex -= 1;
                         break;
--- a/widget/gonk/moz.build
+++ b/widget/gonk/moz.build
@@ -12,16 +12,17 @@
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 EXPORTS += [
     'GonkPermission.h',
     'OrientationObserver.h',
+    'PowerWakeLock.h',
 ]
 
 DIRS += ['libdisplay', 'nativewindow']
 
 # libui files
 SOURCES += ['libui/' + src for src in [
     'EventHub.cpp',
     'Input.cpp',
@@ -52,16 +53,17 @@ SOURCES += [
     'nsAppShell.cpp',
     'nsClipboard.cpp',
     'nsIdleServiceGonk.cpp',
     'nsLookAndFeel.cpp',
     'nsWidgetFactory.cpp',
     'nsWindow.cpp',
     'OrientationObserver.cpp',
     'ParentProcessController.cpp',
+    'PowerWakeLock.cpp',
     'ProcessOrientation.cpp',
     'WidgetTraceEvent.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
--- a/widget/gonk/nsLookAndFeel.cpp
+++ b/widget/gonk/nsLookAndFeel.cpp
@@ -87,16 +87,18 @@ nsLookAndFeel::NativeGetColor(ColorID aI
         // not used?
         aColor = BASE_NORMAL_COLOR;
         break;
     case eColorID_TextForeground:
         // not used?
         aColor = TEXT_NORMAL_COLOR;
         break;
     case eColorID_TextSelectBackground:
+        aColor = NS_RGBA(0x33,0xb5,0xe5,0x66);
+        break;
     case eColorID_IMESelectedRawTextBackground:
     case eColorID_IMESelectedConvertedTextBackground:
         // still used
         aColor = BASE_SELECTED_COLOR;
         break;
     case eColorID_TextSelectForegroundCustom:
         aColor = NS_RGB(0x4d,0x4d,0x4d);
         break;
--- a/xpcom/base/nsDebugImpl.cpp
+++ b/xpcom/base/nsDebugImpl.cpp
@@ -96,16 +96,23 @@ Break(const char* aMsg);
 #if defined(_WIN32)
 #include <windows.h>
 #include <signal.h>
 #include <malloc.h> // for _alloca
 #elif defined(XP_UNIX)
 #include <stdlib.h>
 #endif
 
+#ifdef MOZ_B2G_LOADER
+/* Avoid calling Android logger/logd temporarily while running
+ * B2GLoader to start the child process.
+ */
+bool gDisableAndroidLog = false;
+#endif
+
 using namespace mozilla;
 
 static const char* sMultiprocessDescription = nullptr;
 
 static Atomic<int32_t> gAssertionCount;
 
 NS_IMPL_QUERY_INTERFACE(nsDebugImpl, nsIDebug, nsIDebug2)
 
@@ -387,16 +394,19 @@ NS_DebugBreak(uint32_t aSeverity, const 
   // errors on platforms without a debugdlg ring a bell on stderr
 #if !defined(XP_WIN)
   if (ll != PR_LOG_WARNING) {
     fprintf(stderr, "\07");
   }
 #endif
 
 #ifdef ANDROID
+#ifdef MOZ_B2G_LOADER
+  if (!gDisableAndroidLog)
+#endif
   __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", buf.buffer);
 #endif
 
   // Write the message to stderr unless it's a warning and MOZ_IGNORE_WARNINGS
   // is set.
   if (!(PR_GetEnv("MOZ_IGNORE_WARNINGS") && aSeverity == NS_DEBUG_WARNING)) {
     fprintf(stderr, "%s\n", buf.buffer);
     fflush(stderr);
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -462,12 +462,22 @@ enum WindowsEnvironmentType {
 /**
  * Retrieve the Windows desktop environment libXUL is running
  * under. Valid after a call to XRE_main.
  */
 XRE_API(WindowsEnvironmentType,
         XRE_GetWindowsEnvironment, ())
 #endif // XP_WIN
 
+#ifdef MOZ_B2G_LOADER
+XRE_API(int,
+        XRE_ProcLoaderServiceRun, (pid_t, int, int argc, const char *argv[]));
+XRE_API(void,
+        XRE_ProcLoaderClientInit, (pid_t, int));
+XRE_API(void,
+        XRE_ProcLoaderPreload, (const char* aProgramDir,
+                                const nsXREAppData* aAppData));
+#endif // MOZ_B2G_LOADER
+
 XRE_API(int,
         XRE_XPCShellMain, (int argc, char** argv, char** envp))
 
 #endif // _nsXULAppAPI_h__
--- a/xpcom/components/ManifestParser.cpp
+++ b/xpcom/components/ManifestParser.cpp
@@ -31,16 +31,28 @@
 #include "nsTextFormatter.h"
 #include "nsVersionComparator.h"
 #include "nsXPCOMCIDInternal.h"
 
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIXULAppInfo.h"
 #include "nsIXULRuntime.h"
+#ifdef MOZ_B2G_LOADER
+#include "mozilla/XPTInterfaceInfoManager.h"
+#endif
+
+#ifdef MOZ_B2G_LOADER
+#define XPTONLY_MANIFEST &nsComponentManagerImpl::XPTOnlyManifestManifest
+#define XPTONLY_XPT &nsComponentManagerImpl::XPTOnlyManifestXPT
+#else
+#define XPTONLY_MANIFEST nullptr
+#define XPTONLY_XPT nullptr
+#endif
+
 
 using namespace mozilla;
 
 struct ManifestDirective
 {
   const char* directive;
   int argc;
 
@@ -59,46 +71,53 @@ struct ManifestDirective
   // hasn't learned how to initialize unions in a sane way.
   void (nsComponentManagerImpl::*mgrfunc)
     (nsComponentManagerImpl::ManifestProcessingContext& cx,
      int lineno, char *const * argv);
   void (nsChromeRegistry::*regfunc)
     (nsChromeRegistry::ManifestProcessingContext& cx,
      int lineno, char *const *argv,
      bool platform, bool contentaccessible);
+#ifdef MOZ_B2G_LOADER
+  // The function to handle the directive for XPT Only parsing.
+  void (*xptonlyfunc)(nsComponentManagerImpl::XPTOnlyManifestProcessingContext& cx,
+                      int lineno, char *const * argv);
+#else
+  void *xptonlyfunc;
+#endif
 
   bool isContract;
 };
 static const ManifestDirective kParsingTable[] = {
   { "manifest",         1, false, true, true, false,
-    &nsComponentManagerImpl::ManifestManifest, nullptr },
+    &nsComponentManagerImpl::ManifestManifest, nullptr, XPTONLY_MANIFEST },
   { "binary-component", 1, true, false, false, false,
-    &nsComponentManagerImpl::ManifestBinaryComponent, nullptr },
+    &nsComponentManagerImpl::ManifestBinaryComponent, nullptr, nullptr },
   { "interfaces",       1, true, false, false, false,
-    &nsComponentManagerImpl::ManifestXPT, nullptr },
+    &nsComponentManagerImpl::ManifestXPT, nullptr, XPTONLY_XPT },
   { "component",        2, true, false, false, false,
-    &nsComponentManagerImpl::ManifestComponent, nullptr },
+    &nsComponentManagerImpl::ManifestComponent, nullptr, nullptr },
   { "contract",         2, true, false, false, false,
-    &nsComponentManagerImpl::ManifestContract, nullptr, true},
+    &nsComponentManagerImpl::ManifestContract, nullptr, nullptr, true},
   { "category",         3, true, false, false, false,
-    &nsComponentManagerImpl::ManifestCategory, nullptr },
+    &nsComponentManagerImpl::ManifestCategory, nullptr, nullptr },
   { "content",          2, true, true, true,  true,
-    nullptr, &nsChromeRegistry::ManifestContent },
+    nullptr, &nsChromeRegistry::ManifestContent, nullptr },
   { "locale",           3, true, true, true,  false,
-    nullptr, &nsChromeRegistry::ManifestLocale },
+    nullptr, &nsChromeRegistry::ManifestLocale, nullptr },
   { "skin",             3, false, true, true,  false,
-    nullptr, &nsChromeRegistry::ManifestSkin },
+    nullptr, &nsChromeRegistry::ManifestSkin, nullptr },
   { "overlay",          2, true, true, false,  false,
-    nullptr, &nsChromeRegistry::ManifestOverlay },
+    nullptr, &nsChromeRegistry::ManifestOverlay, nullptr },
   { "style",            2, false, true, false,  false,
-    nullptr, &nsChromeRegistry::ManifestStyle },
+    nullptr, &nsChromeRegistry::ManifestStyle, nullptr },
   { "override",         2, true, true, true,  false,
-    nullptr, &nsChromeRegistry::ManifestOverride },
+    nullptr, &nsChromeRegistry::ManifestOverride, nullptr },
   { "resource",         2, true, true, false,  false,
-    nullptr, &nsChromeRegistry::ManifestResource }
+    nullptr, &nsChromeRegistry::ManifestResource, nullptr }
 };
 
 static const char kWhitespace[] = "\t ";
 
 static bool IsNewline(char c)
 {
   return c == '\n' || c == '\r';
 }
@@ -121,43 +140,59 @@ struct AutoPR_smprintf_free
     return mBuf;
   }
 
   char* mBuf;
 };
 
 } // anonymous namespace
 
+/**
+ * If we are pre-loading XPTs, this method may do nothing because the
+ * console service is not initialized.
+ */
 void LogMessage(const char* aMsg, ...)
 {
+  if (!nsComponentManagerImpl::gComponentManager) {
+    return;
+  }
+
   nsCOMPtr<nsIConsoleService> console =
     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   if (!console)
     return;
 
   va_list args;
   va_start(args, aMsg);
   AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args));
   va_end(args);
 
   nsCOMPtr<nsIConsoleMessage> error =
     new nsConsoleMessage(NS_ConvertUTF8toUTF16(formatted).get());
   console->LogMessage(error);
 }
 
+/**
+ * If we are pre-loading XPTs, this method may do nothing because the
+ * console service is not initialized.
+ */
 void LogMessageWithContext(FileLocation &aFile,
                            uint32_t aLineNumber, const char* aMsg, ...)
 {
   va_list args;
   va_start(args, aMsg);
   AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args));
   va_end(args);
   if (!formatted)
     return;
 
+  if (!nsComponentManagerImpl::gComponentManager) {
+    return;
+  }
+
   nsCString file;
   aFile.GetURIString(file);
 
   nsCOMPtr<nsIScriptError> error =
     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
   if (!error) {
     // This can happen early in component registration. Fall back to a
     // generic console message.
@@ -383,21 +418,33 @@ struct CachedDirective
 {
   int lineno;
   char* argv[4];
 };
 
 } // anonymous namespace
 
 
+/**
+ * For XPT-Only mode, the parser handles only directives of "manifest"
+ * and "interfaces", and always call the function given by |xptonlyfunc|
+ * variable of struct |ManifestDirective|.
+ *
+ * This function is safe to be called before the component manager is
+ * ready if aXPTOnly is true for it don't invoke any component during
+ * parsing.
+ */
 void
-ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOnly)
+ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOnly, bool aXPTOnly)
 {
   nsComponentManagerImpl::ManifestProcessingContext mgrcx(type, file, aChromeOnly);
   nsChromeRegistry::ManifestProcessingContext chromecx(type, file);
+#ifdef MOZ_B2G_LOADER
+  nsComponentManagerImpl::XPTOnlyManifestProcessingContext xptonlycx(file);
+#endif
   nsresult rv;
 
   NS_NAMED_LITERAL_STRING(kPlatform, "platform");
   NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
   NS_NAMED_LITERAL_STRING(kApplication, "application");
   NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
   NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
   NS_NAMED_LITERAL_STRING(kOs, "os");
@@ -411,17 +458,22 @@ ParseManifest(NSLocationType type, FileL
   NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
 
   nsAutoString appID;
   nsAutoString appVersion;
   nsAutoString geckoVersion;
   nsAutoString osTarget;
   nsAutoString abi;
 
-  nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
+  nsCOMPtr<nsIXULAppInfo> xapp;
+  if (!aXPTOnly) {
+    // Avoid to create any component for XPT only mode.
+    // No xapp means no ID, version, ..., modifiers checking.
+    xapp = do_GetService(XULAPPINFO_SERVICE_CONTRACTID);
+  }
   if (xapp) {
     nsAutoCString s;
     rv = xapp->GetID(s);
     if (NS_SUCCEEDED(rv))
       CopyUTF8toUTF16(s, appID);
 
     rv = xapp->GetVersion(s);
     if (NS_SUCCEEDED(rv))
@@ -511,19 +563,20 @@ ParseManifest(NSLocationType type, FileL
     char *whitespace = token;
     token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
     if (!token) continue;
 
     const ManifestDirective* directive = nullptr;
     for (const ManifestDirective* d = kParsingTable;
 	 d < ArrayEnd(kParsingTable);
 	 ++d) {
-      if (!strcmp(d->directive, token)) {
-	directive = d;
-	break;
+      if (!strcmp(d->directive, token) &&
+          (!aXPTOnly || d->xptonlyfunc)) {
+        directive = d;
+        break;
       }
     }
 
     if (!directive) {
       LogMessageWithContext(file, line,
                             "Ignoring unrecognized chrome manifest directive '%s'.",
                             token);
       continue;
@@ -572,18 +625,19 @@ ParseManifest(NSLocationType type, FileL
       ToLowerCase(token);
       NS_ConvertASCIItoUTF16 wtoken(token);
 
       if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
           CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
           CheckStringFlag(kABI, wtoken, abi, stABI) ||
           CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
           CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
-          CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion))
+          CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
         continue;
+      }
 
 #if defined(MOZ_WIDGET_ANDROID)
       bool tablet = false;
       if (CheckFlag(kTablet, wtoken, tablet)) {
         stTablet = (tablet == isTablet) ? eOK : eBad;
         continue;
       }
 #endif
@@ -614,16 +668,21 @@ ParseManifest(NSLocationType type, FileL
         stOs == eBad ||
         stOsVersion == eBad ||
 #ifdef MOZ_WIDGET_ANDROID
         stTablet == eBad ||
 #endif
         stABI == eBad)
       continue;
 
+#ifdef MOZ_B2G_LOADER
+    if (aXPTOnly) {
+      directive->xptonlyfunc(xptonlycx, line, argv);
+    } else
+#endif /* MOZ_B2G_LOADER */
     if (directive->regfunc) {
       if (GeckoProcessType_Default != XRE_GetProcessType())
         continue;
 
       if (!nsChromeRegistry::gChromeRegistry) {
         nsCOMPtr<nsIChromeRegistry> cr =
           mozilla::services::GetChromeRegistryService();
         if (!nsChromeRegistry::gChromeRegistry) {
@@ -631,26 +690,29 @@ ParseManifest(NSLocationType type, FileL
                                 "Chrome registry isn't available yet.");
           continue;
         }
       }
 
       (nsChromeRegistry::gChromeRegistry->*(directive->regfunc))
 	(chromecx, line, argv, platform, contentAccessible);
     }
-    else if (directive->ischrome || !aChromeOnly) {
+    else if (directive->mgrfunc && (directive->ischrome || !aChromeOnly)) {
       if (directive->isContract) {
         CachedDirective* cd = contracts.AppendElement();
         cd->lineno = line;
         cd->argv[0] = argv[0];
         cd->argv[1] = argv[1];
       }
       else
         (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))
           (mgrcx, line, argv);
+    } else {
+      LogMessageWithContext(file, line,
+                            "No valid manifest directive.");
     }
   }
 
   for (uint32_t i = 0; i < contracts.Length(); ++i) {
     CachedDirective& d = contracts[i];
     nsComponentManagerImpl::gComponentManager->ManifestContract
       (mgrcx, d.lineno, d.argv);
   }
--- a/xpcom/components/ManifestParser.h
+++ b/xpcom/components/ManifestParser.h
@@ -8,16 +8,16 @@
 
 #include "nsComponentManager.h"
 #include "nsChromeRegistry.h"
 #include "mozilla/FileLocation.h"
 
 class nsIFile;
 
 void ParseManifest(NSLocationType type, mozilla::FileLocation &file,
-                   char* buf, bool aChromeOnly);
+                   char* buf, bool aChromeOnly, bool aXPTOnly=false);
 
 void LogMessage(const char* aMsg, ...);
 
 void LogMessageWithContext(mozilla::FileLocation &aFile,
                            uint32_t aLineNumber, const char* aMsg, ...);
 
 #endif // ManifestParser_h
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -64,16 +64,17 @@
 #include "mozilla/GenericFactory.h"
 #include "nsSupportsPrimitives.h"
 #include "nsArray.h"
 #include "nsIMutableArray.h"
 #include "nsArrayEnumerator.h"
 #include "nsStringEnumerator.h"
 #include "mozilla/FileUtils.h"
 #include "nsNetUtil.h"
+#include "nsDataHashtable.h"
 
 #include <new>     // for placement new
 
 #include "mozilla/Omnijar.h"
 
 #include "prlog.h"
 
 using namespace mozilla;
@@ -99,16 +100,46 @@ const char fileSizeValueName[]="FileSize
 const char lastModValueName[]="LastModTimeStamp";
 const char nativeComponentType[]="application/x-mozilla-native";
 const char staticComponentType[]="application/x-mozilla-static";
 
 NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
 
 #define UID_STRING_LENGTH 39
 
+#ifdef MOZ_B2G_LOADER
+typedef nsDataHashtable<nsCStringHashKey, bool> XPTIInfosBookType;
+static XPTIInfosBookType *sXPTIInfosBook = nullptr;
+
+static XPTIInfosBookType *
+GetXPTIInfosBook()
+{
+    if (sXPTIInfosBook == nullptr) {
+        sXPTIInfosBook = new XPTIInfosBookType;
+    }
+    return sXPTIInfosBook;
+}
+
+static bool
+IsRegisteredXPTIInfo(FileLocation &aFile)
+{
+    nsAutoCString uri;
+    aFile.GetURIString(uri);
+    return GetXPTIInfosBook()->Get(uri);
+}
+
+static void
+MarkRegisteredXPTIInfo(FileLocation &aFile)
+{
+    nsAutoCString uri;
+    aFile.GetURIString(uri);
+    GetXPTIInfosBook()->Put(uri, true);
+}
+#endif /* MOZ_B2G_LOADER */
+
 nsresult
 nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
 {
     nsresult rv;
     nsXPIDLCString value;
     nsCOMPtr<nsICategoryManager> catman;
     nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager;
     if (!compMgr) {
@@ -519,43 +550,54 @@ CutExtension(nsCString& path)
 {
     int32_t dotPos = path.RFindChar('.');
     if (kNotFound == dotPos)
         path.Truncate();
     else
         path.Cut(0, dotPos + 1);
 }
 
-void
-nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
-                                         FileLocation &aFile,
-                                         bool aChromeOnly)
+static void
+DoRegisterManifest(NSLocationType aType,
+                   FileLocation &aFile,
+                   bool aChromeOnly,
+                   bool aXPTOnly)
 {
+    MOZ_ASSERT(!aXPTOnly ||
+               nsComponentManagerImpl::gComponentManager == nullptr);
     uint32_t len;
     FileLocation::Data data;
     nsAutoArrayPtr<char> buf;
     nsresult rv = aFile.GetData(data);
     if (NS_SUCCEEDED(rv)) {
         rv = data.GetSize(&len);
     }
     if (NS_SUCCEEDED(rv)) {
         buf = new char[len + 1];
         rv = data.Copy(buf, len);
     }
     if (NS_SUCCEEDED(rv)) {
         buf[len] = '\0';
-        ParseManifest(aType, aFile, buf, aChromeOnly);
+        ParseManifest(aType, aFile, buf, aChromeOnly, aXPTOnly);
     } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
         nsCString uri;
         aFile.GetURIString(uri);
         LogMessage("Could not read chrome manifest '%s'.", uri.get());
     }
 }
 
 void
+nsComponentManagerImpl::RegisterManifest(NSLocationType aType,
+                                         FileLocation &aFile,
+                                         bool aChromeOnly)
+{
+    DoRegisterManifest(aType, aFile, aChromeOnly, false);
+}
+
+void
 nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv)
 {
     char* file = argv[0];
     FileLocation f(cx.mFile, file);
     RegisterManifest(cx.mType, f, cx.mChromeOnly);
 }
 
 void
@@ -582,41 +624,56 @@ nsComponentManagerImpl::ManifestBinaryCo
     const mozilla::Module* m = mNativeModuleLoader.LoadModule(f);
     // The native module loader should report an error here, we don't have to
     if (!m)
         return;
 
     RegisterModule(m, &f);
 }
 
-void
-nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv)
+static void
+DoRegisterXPT(FileLocation &aFile)
 {
-    FileLocation f(cx.mFile, argv[0]);
+#ifdef MOZ_B2G_LOADER
+    if (IsRegisteredXPTIInfo(aFile)) {
+        return;
+    }
+#endif
+
     uint32_t len;
     FileLocation::Data data;
     nsAutoArrayPtr<char> buf;
-    nsresult rv = f.GetData(data);
+    nsresult rv = aFile.GetData(data);
     if (NS_SUCCEEDED(rv)) {
         rv = data.GetSize(&len);
     }
     if (NS_SUCCEEDED(rv)) {
         buf = new char[len];
         rv = data.Copy(buf, len);
     }
     if (NS_SUCCEEDED(rv)) {
         XPTInterfaceInfoManager::GetSingleton()->RegisterBuffer(buf, len);
+#ifdef MOZ_B2G_LOADER
+        MarkRegisteredXPTIInfo(aFile);
+#endif
     } else {
         nsCString uri;
-        f.GetURIString(uri);
+        aFile.GetURIString(uri);
         LogMessage("Could not read '%s'.", uri.get());
     }
 }
 
 void
+nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv)
+{
+    FileLocation f(cx.mFile, argv[0]);
+    DoRegisterXPT(f);
+}
+
+void
 nsComponentManagerImpl::ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv)
 {
     mLock.AssertNotCurrentThreadOwns();
 
     char* id = argv[0];
     char* file = argv[1];
 
     nsID cid;
@@ -789,16 +846,20 @@ nsresult nsComponentManagerImpl::Shutdow
     mContractIDs.Clear();
     mFactories.Clear(); // XXX release the objects, don't just clear
     mLoaderMap.Clear();
     mKnownModules.Clear();
     mKnownStaticModules.Clear();
 
     delete sStaticModules;
     delete sModuleLocations;
+#ifdef MOZ_B2G_LOADER
+    delete sXPTIInfosBook;
+    sXPTIInfosBook = nullptr;
+#endif
 
     // Unload libraries
     mNativeModuleLoader.UnloadLibraries();
 
     // delete arena for strings and small objects
     PL_FinishArenaPool(&mArena);
 
     mStatus = SHUTDOWN_COMPLETE;
@@ -1937,16 +1998,64 @@ nsComponentManagerImpl::GetManifestLocat
     if (NS_SUCCEEDED(rv))
       locations->AppendElement(uri, false);
   }
 
   locations.forget(aLocations);
   return NS_OK;
 }
 
+#ifdef MOZ_B2G_LOADER
+
+/* static */
+void
+nsComponentManagerImpl::XPTOnlyManifestManifest(XPTOnlyManifestProcessingContext &aCx,
+                                                int aLineno,
+                                                char * const * aArgv)
+{
+    char* file = aArgv[0];
+    FileLocation f(aCx.mFile, file);
+
+    DoRegisterManifest(NS_COMPONENT_LOCATION, f, false, true);
+}
+
+/* static */
+void
+nsComponentManagerImpl::XPTOnlyManifestXPT(XPTOnlyManifestProcessingContext &aCx,
+                                           int aLineno,
+                                           char * const * aArgv)
+{
+    FileLocation f(aCx.mFile, aArgv[0]);
+    DoRegisterXPT(f);
+}
+
+/**
+ * To load XPT Interface Information before the component manager is ready.
+ *
+ * With this function, B2G loader could XPT interface info. as earier
+ * as possible to gain benefit of shared memory model of the kernel.
+ */
+/* static */ void
+nsComponentManagerImpl::PreloadXPT(nsIFile *aFile)
+{
+    MOZ_ASSERT(nsComponentManagerImpl::gComponentManager == nullptr);
+    FileLocation location(aFile, "chrome.manifest");
+
+    DoRegisterManifest(NS_COMPONENT_LOCATION, location,
+                       false, true /* aXPTOnly */);
+}
+
+void
+PreloadXPT(nsIFile *aOmnijarFile)
+{
+    nsComponentManagerImpl::PreloadXPT(aOmnijarFile);
+}
+
+#endif /* MOZ_B2G_LOADER */
+
 EXPORT_XPCOM_API(nsresult)
 XRE_AddManifestLocation(NSLocationType aType, nsIFile* aLocation)
 {
     nsComponentManagerImpl::InitializeModuleLocations();
     nsComponentManagerImpl::ComponentLocation* c = 
         nsComponentManagerImpl::sModuleLocations->AppendElement();
     c->type = aType;
     c->location.Init(aLocation);
--- a/xpcom/components/nsComponentManager.h
+++ b/xpcom/components/nsComponentManager.h
@@ -33,16 +33,20 @@
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsTArray.h"
 
 #include "mozilla/Omnijar.h"
 #include "mozilla/Attributes.h"
 
+#ifdef MOZ_B2G_LOADER
+#include "mozilla/FileLocation.h"
+#endif
+
 struct nsFactoryEntry;
 class nsIServiceManager;
 struct PRThread;
 
 #define NS_COMPONENTMANAGER_CID                      \
 { /* 91775d60-d5dc-11d2-92fb-00e09805570f */         \
     0x91775d60,                                      \
     0xd5dc,                                          \
@@ -311,16 +315,40 @@ public:
                                                  PRThread* aThread);
     inline void RemovePendingService(const nsCID& aServiceCID);
     inline PRThread* GetPendingServiceThread(const nsCID& aServiceCID) const;
 
     nsTArray<PendingServiceInfo> mPendingServices;
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
+#ifdef MOZ_B2G_LOADER
+    // Preload XPT interface info for B2G loader.
+    // This function is called before XPCOM has been initialized.
+    static void PreloadXPT(nsIFile *aFile);
+#endif
+
+#ifdef MOZ_B2G_LOADER
+    // Parsing functions of directives of manifest for XPT only parsing.
+    struct XPTOnlyManifestProcessingContext
+    {
+        XPTOnlyManifestProcessingContext(mozilla::FileLocation &aFile)
+            : mFile(aFile)
+        { }
+
+        ~XPTOnlyManifestProcessingContext() { }
+
+        mozilla::FileLocation mFile;
+    };
+    static void XPTOnlyManifestManifest(XPTOnlyManifestProcessingContext& aCx,
+                                        int aLineno, char * const *aArgv);
+    static void XPTOnlyManifestXPT(XPTOnlyManifestProcessingContext& aCx,
+                                   int aLineno, char * const *aArgv);
+#endif
+
 private:
     ~nsComponentManagerImpl();
 };
 
 
 #define NS_MAX_FILENAME_LEN     1024
 
 #define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24)
--- a/xpcom/threads/BackgroundHangMonitor.cpp
+++ b/xpcom/threads/BackgroundHangMonitor.cpp
@@ -60,16 +60,17 @@ private:
 
   BackgroundHangManager(const BackgroundHangManager&);
   BackgroundHangManager& operator=(const BackgroundHangManager&);
   void RunMonitorThread();
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundHangManager)
   static StaticRefPtr<BackgroundHangManager> sInstance;
+  static bool sProhibited;
 
   // Lock for access to members of this class
   Monitor mLock;
   // Current time as seen by hang monitors
   PRIntervalTime mIntervalNow;
   // List of BackgroundHangThread instances associated with each thread
   LinkedList<BackgroundHangThread> mHangThreads;
 
@@ -157,16 +158,17 @@ public:
   {
     NotifyActivity();
     mWaiting = true;
   }
 };
 
 
 StaticRefPtr<BackgroundHangManager> BackgroundHangManager::sInstance;
+bool BackgroundHangManager::sProhibited = false;
 
 ThreadLocal<BackgroundHangThread*> BackgroundHangThread::sTlsKey;
 
 
 BackgroundHangManager::BackgroundHangManager()
   : mShutdown(false)
   , mLock("BackgroundHangManager")
   , mIntervalNow(0)
@@ -408,18 +410,26 @@ BackgroundHangThread::NotifyActivity()
     mInterval = intervalNow;
   }
 }
 
 BackgroundHangThread*
 BackgroundHangThread::FindThread()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  if (BackgroundHangManager::sInstance == nullptr) {
+    MOZ_ASSERT(BackgroundHangManager::sProhibited,
+               "BackgroundHandleManager is not initialized");
+    return nullptr;
+  }
+
   if (sTlsKey.initialized()) {
     // Use TLS if available
+    MOZ_ASSERT(!BackgroundHangManager::sProhibited,
+               "BackgroundHandleManager is not initialized");
     return sTlsKey.get();
   }
   // If TLS is unavailable, we can search through the thread list
   RefPtr<BackgroundHangManager> manager(BackgroundHangManager::sInstance);
   MOZ_ASSERT(manager, "Creating BackgroundHangMonitor after shutdown");
 
   PRThread* threadID = PR_GetCurrentThread();
   // Lock thread list for traversal
@@ -435,85 +445,125 @@ BackgroundHangThread::FindThread()
   return nullptr;
 }
 
 
 void
 BackgroundHangMonitor::Startup()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  MOZ_ASSERT(!BackgroundHangManager::sProhibited, "Prohibited");
   MOZ_ASSERT(!BackgroundHangManager::sInstance, "Already initialized");
   ThreadStackHelper::Startup();
   BackgroundHangThread::Startup();
   BackgroundHangManager::sInstance = new BackgroundHangManager();
 #endif
 }
 
 void
 BackgroundHangMonitor::Shutdown()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  MOZ_ASSERT(!BackgroundHangManager::sProhibited, "Prohibited");
   MOZ_ASSERT(BackgroundHangManager::sInstance, "Not initialized");
   /* Scope our lock inside Shutdown() because the sInstance object can
      be destroyed as soon as we set sInstance to nullptr below, and
      we don't want to hold the lock when it's being destroyed. */
   BackgroundHangManager::sInstance->Shutdown();
   BackgroundHangManager::sInstance = nullptr;
   ThreadStackHelper::Shutdown();
 #endif
 }
 
 BackgroundHangMonitor::BackgroundHangMonitor(const char* aName,
                                              uint32_t aTimeoutMs,
                                              uint32_t aMaxTimeoutMs)
   : mThread(BackgroundHangThread::FindThread())
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
-  if (!mThread) {
+  if (!BackgroundHangManager::sProhibited && !mThread) {
+    // If sProhibit is true, mThread would be null, and no monitoring.
     mThread = new BackgroundHangThread(aName, aTimeoutMs, aMaxTimeoutMs);
   }
 #endif
 }
 
 BackgroundHangMonitor::BackgroundHangMonitor()
   : mThread(BackgroundHangThread::FindThread())
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
-  MOZ_ASSERT(mThread, "Thread not initialized for hang monitoring");
+  MOZ_ASSERT(!BackgroundHangManager::sProhibited || mThread,
+             "This thread is not initialized for hang monitoring");
 #endif
 }
 
 BackgroundHangMonitor::~BackgroundHangMonitor()
 {
 }
 
 void
 BackgroundHangMonitor::NotifyActivity()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  if (mThread == nullptr) {
+    MOZ_ASSERT(BackgroundHangManager::sProhibited,
+               "This thread is not initialized for hang monitoring");
+    return;
+  }
   mThread->NotifyActivity();
 #endif
 }
 
 void
 BackgroundHangMonitor::NotifyWait()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  if (mThread == nullptr) {
+    MOZ_ASSERT(BackgroundHangManager::sProhibited,
+               "This thread is not initialized for hang monitoring");
+    return;
+  }
   mThread->NotifyWait();
 #endif
 }
 
+void
+BackgroundHangMonitor::Prohibit()
+{
+#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  MOZ_ASSERT(BackgroundHangManager::sInstance == nullptr,
+             "The background hang monitor is already initialized");
+  BackgroundHangManager::sProhibited = true;
+#endif
+}
+
+void
+BackgroundHangMonitor::Allow()
+{
+#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  MOZ_ASSERT(BackgroundHangManager::sInstance == nullptr,
+             "The background hang monitor is already initialized");
+  BackgroundHangManager::sProhibited = false;
+#endif
+}
+
 
 /* Because we are iterating through the BackgroundHangThread linked list,
    we need to take a lock. Using MonitorAutoLock as a base class makes
    sure all of that is taken care of for us. */
 BackgroundHangMonitor::ThreadHangStatsIterator::ThreadHangStatsIterator()
   : MonitorAutoLock(BackgroundHangManager::sInstance->mLock)
-  , mThread(BackgroundHangManager::sInstance->mHangThreads.getFirst())
+  , mThread(BackgroundHangManager::sInstance ?
+            BackgroundHangManager::sInstance->mHangThreads.getFirst() :
+            nullptr)
 {
+#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
+  MOZ_ASSERT(BackgroundHangManager::sInstance || BackgroundHangManager::sProhibited,
+             "Inconsistent state");
+#endif
 }
 
 Telemetry::ThreadHangStats*
 BackgroundHangMonitor::ThreadHangStatsIterator::GetNext()
 {
   if (!mThread) {
     return nullptr;
   }
--- a/xpcom/threads/BackgroundHangMonitor.h
+++ b/xpcom/threads/BackgroundHangMonitor.h
@@ -102,16 +102,18 @@ class BackgroundHangThread;
  *        hangMonitor.NotifyWait();
  *        wait_for_next_event();
  *      }
  *    } else {
  *      process_nonsync_event();
  *    }
  *  }
  *
+ * Prohibit() and Allow() make the background hang monitor work safely
+ * before Startup().
  */
 class BackgroundHangMonitor
 {
 private:
   RefPtr<BackgroundHangThread> mThread;
 
 public:
   static const uint32_t kNoTimeout = 0;
@@ -199,13 +201,34 @@ public:
   void NotifyActivity();
 
   /**
    * Notify the hang monitor of current thread wait.
    * Call this method before entering a wait state; call
    * NotifyActivity when subsequently exiting the wait state.
    */
   void NotifyWait();
+
+  /**
+   * Prohibit the hang monitor from activating.
+   *
+   * Startup() should not be called between Prohibit() and Allow().
+   * This function makes the background hang monitor stop monitoring
+   * threads.
+   *
+   * Prohibit() and Allow() can be called before XPCOM is ready.  If
+   * we don't stop monitoring threads it could case errors.
+   */
+  static void Prohibit();
+
+  /**
+   * Allow the hang monitor to run.
+   *
+   * Allow() and Prohibit() should be called in pair.
+   *
+   * \see Prohibit()
+   */
+  static void Allow();
 };
 
 } // namespace mozilla
 
 #endif // mozilla_BackgroundHangMonitor_h