diff --git a/b2g/app/B2GLoader.cpp b/b2g/app/B2GLoader.cpp new file mode 100644 index 000000000000..7e0aa9627840 --- /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 +#include +#include +#include +#include +#include + +#include + +#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 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 +GetAppIni(int argc, const char *argv[]) +{ + nsCOMPtr appini; + nsresult rv; + + // Allow firefox.exe to launch XULRunner apps via -app + // 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 appini = GetAppIni(argc, argv); + const nsXREAppData *appData; + if (appini) { + nsresult rv = + XRE_CreateAppData(appini, const_cast(&appData)); + NS_ENSURE_SUCCESS(rv, false); + } else { + appData = &sAppData; + } + + XRE_ProcLoaderPreload(progDir, appData); + + if (appini) { + XRE_FreeAppData(const_cast(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); +} diff --git a/b2g/app/moz.build b/b2g/app/moz.build index 77879ddb4440..82b60ad6db31 100644 --- a/b2g/app/moz.build +++ b/b2g/app/moz.build @@ -9,6 +9,11 @@ if not CONFIG['LIBXUL_SDK']: PROGRAM = CONFIG['MOZ_APP_NAME'] + "-bin" else: PROGRAM = CONFIG['MOZ_APP_NAME'] + if CONFIG['MOZ_B2G_LOADER']: + SOURCES += [ + 'B2GLoader.cpp', + ] + SOURCES += [ 'nsBrowserApp.cpp', ] diff --git a/b2g/app/nsBrowserApp.cpp b/b2g/app/nsBrowserApp.cpp index bf57ef445744..f4b3e8e45a82 100644 --- a/b2g/app/nsBrowserApp.cpp +++ b/b2g/app/nsBrowserApp.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "nsCOMPtr.h" #include "nsIFile.h" @@ -163,9 +164,22 @@ static int do_main(int argc, char* argv[]) 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 @@ -175,7 +189,9 @@ int main(int argc, char* argv[]) 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; @@ -186,6 +202,7 @@ int main(int argc, char* argv[]) 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 @@ -209,6 +226,9 @@ int main(int argc, char* argv[]) 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(); @@ -219,6 +239,7 @@ int main(int argc, char* argv[]) } // 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)) { @@ -253,7 +274,25 @@ int main(int argc, char* argv[]) 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; diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index d6b7b6d01fbb..8d8ffb95e174 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index ce0428c1ac6f..1504b6198a25 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 1d13daf77890..eb69fb11e14f 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index d6b7b6d01fbb..8d8ffb95e174 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index 6fbcd6cab73b..c453c4c7783b 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index ac5025ed7543..fe961056f9f2 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -4,6 +4,6 @@ "remote": "", "branch": "" }, - "revision": "3842156466e71f41748f86777a1b8fbd379441c0", + "revision": "92b742f333b1f695de3de7c10316bc5ee652d084", "repo_path": "/integration/gaia-central" } diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml index f3c6b3be044c..64d3b9217894 100644 --- a/b2g/config/hamachi/sources.xml +++ b/b2g/config/hamachi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml index ec6f85bfb1a6..8b59a58ee4ea 100644 --- a/b2g/config/helix/sources.xml +++ b/b2g/config/helix/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index abf8f3108685..896f6c73dd15 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml index d313fc9629a2..2a8a306a1b67 100644 --- a/b2g/config/wasabi/sources.xml +++ b/b2g/config/wasabi/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/confvars.sh b/b2g/confvars.sh index f77d791fb0dd..98ef5283328a 100644 --- a/b2g/confvars.sh +++ b/b2g/confvars.sh @@ -59,6 +59,7 @@ MOZ_B2G=1 if test "$OS_TARGET" = "Android"; then MOZ_NUWA_PROCESS=1 +MOZ_B2G_LOADER=1 fi MOZ_FOLD_LIBS=1 diff --git a/configure.in b/configure.in index df2d7af316f9..40db08e510b4 100644 --- a/configure.in +++ b/configure.in @@ -8614,6 +8614,14 @@ if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then 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) diff --git a/dom/apps/src/OfflineCacheInstaller.jsm b/dom/apps/src/OfflineCacheInstaller.jsm index 16b5dd1e4198..358b38349144 100644 --- a/dom/apps/src/OfflineCacheInstaller.jsm +++ b/dom/apps/src/OfflineCacheInstaller.jsm @@ -23,7 +23,9 @@ let makeFile = CC('@mozilla.org/file/local;1', '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'] @@ -47,32 +49,34 @@ function enableOfflineCacheForApp(origin, appId) { 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(); + } }); } diff --git a/dom/camera/GonkCameraHwMgr.cpp b/dom/camera/GonkCameraHwMgr.cpp index 6d5d3564527d..e215ee750c38 100644 --- a/dom/camera/GonkCameraHwMgr.cpp +++ b/dom/camera/GonkCameraHwMgr.cpp @@ -234,6 +234,7 @@ GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCam nsresult rv = cameraHardware->Init(); if (NS_FAILED(rv)) { DOM_CAMERA_LOGE("Failed to initialize camera hardware (0x%X)\n", rv); + cameraHardware->Close(); return nullptr; } diff --git a/dom/camera/test/test_camera_hardware_init_failure.html b/dom/camera/test/test_camera_hardware_init_failure.html index d5e3ec800492..a81aa1cda7b9 100644 --- a/dom/camera/test/test_camera_hardware_init_failure.html +++ b/dom/camera/test/test_camera_hardware_init_failure.html @@ -17,6 +17,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=940424 diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 4f2e71ff1395..535126ca08a3 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -68,6 +68,7 @@ #include "UeventPoller.h" #include "nsIWritablePropertyBag2.h" #include +#include "PowerWakeLock.h" #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args) #define NsecPerMsec 1000000LL @@ -667,6 +668,7 @@ void SetScreenEnabled(bool aEnabled) { GetGonkDisplay()->SetEnabled(aEnabled); + gPowerWakelock = nullptr; sScreenEnabled = aEnabled; } diff --git a/ipc/app/Makefile.in b/ipc/app/Makefile.in index 5cc4d7a2b41c..6c18864b7029 100644 --- a/ipc/app/Makefile.in +++ b/ipc/app/Makefile.in @@ -37,6 +37,10 @@ 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. diff --git a/ipc/app/MozillaRuntimeMain.cpp b/ipc/app/MozillaRuntimeMain.cpp index 4bdb6a56dd8a..67b636333145 100644 --- a/ipc/app/MozillaRuntimeMain.cpp +++ b/ipc/app/MozillaRuntimeMain.cpp @@ -4,148 +4,9 @@ * 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 -#endif - -#ifdef XP_WIN -#include -// 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 -# include - -# include - -# ifdef LOGE_IF -# undef LOGE_IF -# endif - -# include -# 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 -#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); -} -#endif - -#if defined(XP_WIN) -static bool gIsSandboxEnabled = false; -void StartSandboxCallback() -{ - if (gIsSandboxEnabled) { - sandbox::TargetServices* target_service = - sandbox::SandboxFactory::GetTargetServices(); - target_service->LowerToken(); - } -} -#endif - +#include "../contentproc/plugin-container.cpp" + 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; +main(int argc, char *argv[]) { + return content_process_main(argc, argv); } diff --git a/ipc/chromium/src/base/process_util_linux.cc b/ipc/chromium/src/base/process_util_linux.cc index 0be1b7edd770..741e912b8d9d 100644 --- a/ipc/chromium/src/base/process_util_linux.cc +++ b/ipc/chromium/src/base/process_util_linux.cc @@ -1,3 +1,5 @@ +/* -*- 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. @@ -18,6 +20,13 @@ #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 /* @@ -188,12 +197,71 @@ bool LaunchApp(const std::vector& argv, wait, process_handle); } +#ifdef MOZ_B2G_LOADER +/** + * Launch an app using B2g Loader. + */ +static bool +LaunchAppProcLoader(const std::vector& 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 argv_cstr(new char*[argv.size() + 1]); + for (i = 0; i < argv.size(); i++) { + argv_cstr[i] = const_cast(argv[i].c_str()); + } + argv_cstr[argv.size()] = nullptr; + + scoped_array 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& argv) { + std::vector::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& 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 argv_cstr(new char*[argv.size() + 1]); // Illegal to allocate memory after fork and before execvp InjectiveMultimap fd_shuffle1, fd_shuffle2; diff --git a/ipc/contentproc/moz.build b/ipc/contentproc/moz.build new file mode 100644 index 000000000000..39b5d3273791 --- /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', + ] diff --git a/ipc/contentproc/plugin-container.cpp b/ipc/contentproc/plugin-container.cpp new file mode 100644 index 000000000000..e8fe2cc2549f --- /dev/null +++ b/ipc/contentproc/plugin-container.cpp @@ -0,0 +1,151 @@ +/* -*- 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 +#endif + +#ifdef XP_WIN +#include +// 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 +# include + +# include + +# ifdef LOGE_IF +# undef LOGE_IF +# endif + +# include +# 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 +#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); +} +#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 +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 + } + +#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; +} diff --git a/ipc/glue/PProcLoader.ipdl b/ipc/glue/PProcLoader.ipdl new file mode 100644 index 000000000000..d295d8b7221a --- /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); +}; + +} +} diff --git a/ipc/glue/ProcessUtils.h b/ipc/glue/ProcessUtils.h index fc17609dcadc..99d0f532dd8b 100644 --- a/ipc/glue/ProcessUtils.h +++ b/ipc/glue/ProcessUtils.h @@ -1,3 +1,5 @@ +/* -*- 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/. */ @@ -5,6 +7,10 @@ #ifndef mozilla_ipc_ProcessUtils_h #define mozilla_ipc_ProcessUtils_h +#ifdef MOZ_B2G_LOADER +#include "base/process_util.h" +#endif + namespace mozilla { namespace ipc { @@ -12,6 +18,17 @@ namespace ipc { // 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 diff --git a/ipc/glue/ProcessUtils_linux.cpp b/ipc/glue/ProcessUtils_linux.cpp index d5b8c092e0f3..42998991bd79 100644 --- a/ipc/glue/ProcessUtils_linux.cpp +++ b/ipc/glue/ProcessUtils_linux.cpp @@ -1,3 +1,5 @@ +/* -*- 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/. */ @@ -8,6 +10,37 @@ #include +#ifdef MOZ_B2G_LOADER + +#include +#include + +#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 { @@ -16,5 +49,522 @@ void SetThisProcessName(const char *aName) prctl(PR_SET_NAME, (unsigned long)aName, 0uL, 0uL, 0uL); } +#ifdef MOZ_B2G_LOADER +/** + * How does B2G Loader Work? + * + * <> <> + * 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 sProcLoaderClientInitialized = false; +static DebugOnly 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 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 mArgv; + nsTArray mEnv; + nsTArray mFdsremap; + ChildPrivileges mPrivs; + int mCookie; +}; + +static void +AsyncSendLoad(AsyncSendLoadData *aLoad) +{ + PProcLoaderParent *loader = sProcLoaderParent; + DebugOnly 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 &argv = load->mArgv; + for (i = 0; aArgv[i] != nullptr; i++) { + argv.AppendElement(nsCString(aArgv[i])); + } + nsTArray &env = load->mEnv; + for (i = 0; aEnvp[i] != nullptr; i++) { + env.AppendElement(nsCString(aEnvp[i])); + } + nsTArray &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 mArgv; + const nsTArray mEnv; + const nsTArray mFdsRemap; + const ChildPrivileges mPrivs; + + void ShuffleFds(); + +public: + ProcLoaderLoadRunner(const InfallibleTArray& aArgv, + const InfallibleTArray& aEnv, + const InfallibleTArray& 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 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& aArgv, + const InfallibleTArray& aEnv, + const InfallibleTArray& 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& aArgv, + const InfallibleTArray& aEnv, + const InfallibleTArray& aFdsRemap, + const uint32_t& aPrivs, + const int32_t& aCookie) { + if (!sProcLoaderServing) { + return true; + } + sProcLoaderServing = false; + + MOZ_ASSERT(sProcLoaderDispatchedTask == nullptr); + ChildPrivileges privs = static_cast(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 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 */ diff --git a/ipc/glue/moz.build b/ipc/glue/moz.build index 08e50d92cfc4..af3e146b6292 100644 --- a/ipc/glue/moz.build +++ b/ipc/glue/moz.build @@ -130,12 +130,14 @@ IPDL_SOURCES = [ 'PBackground.ipdl', 'PBackgroundSharedTypes.ipdlh', 'PBackgroundTest.ipdl', + 'PProcLoader.ipdl', 'ProtocolTypes.ipdlh', 'URIParams.ipdlh', ] LOCAL_INCLUDES += [ + '/toolkit/xre', '/xpcom/threads', ] diff --git a/ipc/moz.build b/ipc/moz.build index 00273f514f59..53433dc2365e 100644 --- a/ipc/moz.build +++ b/ipc/moz.build @@ -26,4 +26,7 @@ if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG[ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': DIRS += ['keystore', 'netd'] +if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': + DIRS += ['contentproc'] + DIRS += ['app'] diff --git a/layout/base/nsCSSColorUtils.h b/layout/base/nsCSSColorUtils.h index c89193fb1a10..f2106a7a2837 100644 --- a/layout/base/nsCSSColorUtils.h +++ b/layout/base/nsCSSColorUtils.h @@ -15,7 +15,8 @@ // 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], diff --git a/media/mtransport/third_party/moz.build b/media/mtransport/third_party/moz.build index f954024902ea..7cb5a1656f37 100644 --- a/media/mtransport/third_party/moz.build +++ b/media/mtransport/third_party/moz.build @@ -50,7 +50,6 @@ nrappkit_non_unified_sources = [ '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', diff --git a/media/mtransport/third_party/nrappkit/IMPORT_FILES b/media/mtransport/third_party/nrappkit/IMPORT_FILES index 66f9d18f8267..0f80a52e33de 100644 --- a/media/mtransport/third_party/nrappkit/IMPORT_FILES +++ b/media/mtransport/third_party/nrappkit/IMPORT_FILES @@ -10,8 +10,6 @@ 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 diff --git a/media/mtransport/third_party/nrappkit/nrappkit.gyp b/media/mtransport/third_party/nrappkit/nrappkit.gyp index b22923838f00..136f470392ef 100644 --- a/media/mtransport/third_party/nrappkit/nrappkit.gyp +++ b/media/mtransport/third_party/nrappkit/nrappkit.gyp @@ -42,8 +42,6 @@ './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', diff --git a/media/mtransport/third_party/nrappkit/src/util/libekr/r_bitfield.c b/media/mtransport/third_party/nrappkit/src/util/libekr/r_bitfield.c deleted file mode 100644 index ed01b45aa5c8..000000000000 --- 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 -#include -#include -#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(newlendata,set->len*4); - memset(tmp+set->len*4,0,(newlen-set->len)*4); - - RFREE(set->data); - set->data=tmp; - } - - set->data[word]|=1<base)/32; - int bbit=(bit-set->base)%32; - int _status; - - if(bitbase) - return(0); - - /* Resize? */ - if(word>set->len) - return(0); - - return(set->data[word]&(1<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); diff --git a/netwerk/protocol/rtsp/rtsp/APacketSource.cpp b/netwerk/protocol/rtsp/rtsp/APacketSource.cpp index e0f460d6903b..f8c18c601677 100644 --- a/netwerk/protocol/rtsp/rtsp/APacketSource.cpp +++ b/netwerk/protocol/rtsp/rtsp/APacketSource.cpp @@ -215,12 +215,21 @@ static sp MakeAVCCodecSpecificData( } sp 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 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]; @@ -476,6 +485,10 @@ APacketSource::APacketSource( sp codecSpecificData = MakeAACCodecSpecificData(params.c_str()); + if (!codecSpecificData.get()) { + mInitCheck = ERROR_UNSUPPORTED; + return; + } mFormat->setData( kKeyESDS, 0, diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index 5e8c4eddc17e..85e38b4c0da7 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -160,6 +160,8 @@ if CONFIG['MOZ_ENABLE_XREMOTE']: '/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'] diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 36e7aea2bc5e..fe8ed3c449e9 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -185,6 +185,10 @@ #include "GTestRunner.h" #endif +#ifdef MOZ_B2G_LOADER +#include "ProcessUtils.h" +#endif + #ifdef MOZ_WIDGET_ANDROID #include "AndroidBridge.h" #endif @@ -3772,6 +3776,10 @@ 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 diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 3a7f5b9780ff..4857abdf5f5c 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -81,6 +81,11 @@ 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; @@ -815,3 +820,38 @@ XRE_GetWindowsEnvironment() } #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 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 */ diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index d84ef0478c2d..a4bac142f5ed 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -878,6 +878,10 @@ void mozilla_sampler_unlock() 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 @@ -895,6 +899,10 @@ bool mozilla_sampler_register_thread(const char* aName, void* stackTop) void mozilla_sampler_unregister_thread() { + if (sInitCount == 0) { + return; + } + Sampler::UnregisterCurrentThread(); PseudoStack *stack = tlsPseudoStack.get(); @@ -906,6 +914,10 @@ void mozilla_sampler_unregister_thread() } void mozilla_sampler_sleep_start() { + if (sInitCount == 0) { + return; + } + PseudoStack *stack = tlsPseudoStack.get(); if (stack == nullptr) { return; @@ -914,6 +926,10 @@ void mozilla_sampler_sleep_start() { } void mozilla_sampler_sleep_end() { + if (sInitCount == 0) { + return; + } + PseudoStack *stack = tlsPseudoStack.get(); if (stack == nullptr) { return; diff --git a/widget/gonk/PowerWakeLock.cpp b/widget/gonk/PowerWakeLock.cpp new file mode 100644 index 000000000000..7e4d0e1a1b28 --- /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 + +const char* kPower_WAKE_LOCK_ID = "PowerKeyEvent"; + +namespace mozilla { +namespace hal_impl { +StaticRefPtr 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 diff --git a/widget/gonk/PowerWakeLock.h b/widget/gonk/PowerWakeLock.h new file mode 100644 index 000000000000..becf73969ec6 --- /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 gPowerWakelock; +} // hal_impl +} // mozilla +#endif /* __POWERWAKELOCK_H_ */ diff --git a/widget/gonk/libui/EventHub.cpp b/widget/gonk/libui/EventHub.cpp index 89581bcef014..9b318a41b438 100644 --- a/widget/gonk/libui/EventHub.cpp +++ b/widget/gonk/libui/EventHub.cpp @@ -51,6 +51,12 @@ #include #include +#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. @@ -855,6 +861,10 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz 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; } diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index 14f9d128d7c3..6fff3421b9d7 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -17,6 +17,7 @@ EXPORTS += [ 'GonkPermission.h', 'OrientationObserver.h', + 'PowerWakeLock.h', ] DIRS += ['libdisplay', 'nativewindow'] @@ -57,6 +58,7 @@ SOURCES += [ 'nsWindow.cpp', 'OrientationObserver.cpp', 'ParentProcessController.cpp', + 'PowerWakeLock.cpp', 'ProcessOrientation.cpp', 'WidgetTraceEvent.cpp' ] diff --git a/widget/gonk/nsLookAndFeel.cpp b/widget/gonk/nsLookAndFeel.cpp index a89ead051e8b..3aae4eae86e9 100644 --- a/widget/gonk/nsLookAndFeel.cpp +++ b/widget/gonk/nsLookAndFeel.cpp @@ -92,6 +92,8 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) aColor = TEXT_NORMAL_COLOR; break; case eColorID_TextSelectBackground: + aColor = NS_RGBA(0x33,0xb5,0xe5,0x66); + break; case eColorID_IMESelectedRawTextBackground: case eColorID_IMESelectedConvertedTextBackground: // still used diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index 0befeeece873..10735b25d5bd 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -101,6 +101,13 @@ Break(const char* aMsg); #include #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; @@ -392,6 +399,9 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, #endif #ifdef ANDROID +#ifdef MOZ_B2G_LOADER + if (!gDisableAndroidLog) +#endif __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", buf.buffer); #endif diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index 6f320744fd60..33329e33b23f 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -467,6 +467,16 @@ 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)) diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp index 28ac26814886..00a2d471407e 100644 --- a/xpcom/components/ManifestParser.cpp +++ b/xpcom/components/ManifestParser.cpp @@ -36,6 +36,18 @@ #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; @@ -64,36 +76,43 @@ struct ManifestDirective (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 "; @@ -126,8 +145,16 @@ struct AutoPR_smprintf_free } // 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 console = do_GetService(NS_CONSOLESERVICE_CONTRACTID); if (!console) @@ -143,6 +170,10 @@ void LogMessage(const char* aMsg, ...) 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, ...) { @@ -153,6 +184,10 @@ void LogMessageWithContext(FileLocation &aFile, if (!formatted) return; + if (!nsComponentManagerImpl::gComponentManager) { + return; + } + nsCString file; aFile.GetURIString(file); @@ -388,11 +423,23 @@ struct CachedDirective } // 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"); @@ -416,7 +463,12 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn nsAutoString osTarget; nsAutoString abi; - nsCOMPtr xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID)); + nsCOMPtr 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); @@ -516,9 +568,10 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn 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; } } @@ -577,8 +630,9 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn 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; @@ -619,6 +673,11 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn 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; @@ -636,7 +695,7 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn (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; @@ -646,6 +705,9 @@ ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOn else (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc)) (mgrcx, line, argv); + } else { + LogMessageWithContext(file, line, + "No valid manifest directive."); } } diff --git a/xpcom/components/ManifestParser.h b/xpcom/components/ManifestParser.h index 5dc98602bdf6..61f70182deef 100644 --- a/xpcom/components/ManifestParser.h +++ b/xpcom/components/ManifestParser.h @@ -13,7 +13,7 @@ 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, ...); diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index 8a5c0955ebc2..61f670636eed 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -69,6 +69,7 @@ #include "nsStringEnumerator.h" #include "mozilla/FileUtils.h" #include "nsNetUtil.h" +#include "nsDataHashtable.h" #include // for placement new @@ -104,6 +105,36 @@ NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); #define UID_STRING_LENGTH 39 +#ifdef MOZ_B2G_LOADER +typedef nsDataHashtable 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 { @@ -524,11 +555,14 @@ CutExtension(nsCString& path) 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 buf; @@ -542,7 +576,7 @@ nsComponentManagerImpl::RegisterManifest(NSLocationType aType, } 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); @@ -550,6 +584,14 @@ nsComponentManagerImpl::RegisterManifest(NSLocationType aType, } } +void +nsComponentManagerImpl::RegisterManifest(NSLocationType aType, + FileLocation &aFile, + bool aChromeOnly) +{ + DoRegisterManifest(aType, aFile, aChromeOnly, false); +} + void nsComponentManagerImpl::ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv) { @@ -587,14 +629,19 @@ nsComponentManagerImpl::ManifestBinaryComponent(ManifestProcessingContext& cx, i 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 buf; - nsresult rv = f.GetData(data); + nsresult rv = aFile.GetData(data); if (NS_SUCCEEDED(rv)) { rv = data.GetSize(&len); } @@ -604,13 +651,23 @@ nsComponentManagerImpl::ManifestXPT(ManifestProcessingContext& cx, int lineno, c } 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) { @@ -794,6 +851,10 @@ nsresult nsComponentManagerImpl::Shutdown(void) delete sStaticModules; delete sModuleLocations; +#ifdef MOZ_B2G_LOADER + delete sXPTIInfosBook; + sXPTIInfosBook = nullptr; +#endif // Unload libraries mNativeModuleLoader.UnloadLibraries(); @@ -1942,6 +2003,54 @@ nsComponentManagerImpl::GetManifestLocations(nsIArray **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) { diff --git a/xpcom/components/nsComponentManager.h b/xpcom/components/nsComponentManager.h index 7eb903f0d1eb..e0d3d159687a 100644 --- a/xpcom/components/nsComponentManager.h +++ b/xpcom/components/nsComponentManager.h @@ -38,6 +38,10 @@ #include "mozilla/Omnijar.h" #include "mozilla/Attributes.h" +#ifdef MOZ_B2G_LOADER +#include "mozilla/FileLocation.h" +#endif + struct nsFactoryEntry; class nsIServiceManager; struct PRThread; @@ -316,6 +320,30 @@ public: 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(); }; diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index 72b64dd53062..73aa25338335 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -65,6 +65,7 @@ private: public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundHangManager) static StaticRefPtr sInstance; + static bool sProhibited; // Lock for access to members of this class Monitor mLock; @@ -162,6 +163,7 @@ public: StaticRefPtr BackgroundHangManager::sInstance; +bool BackgroundHangManager::sProhibited = false; ThreadLocal BackgroundHangThread::sTlsKey; @@ -413,8 +415,16 @@ 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 @@ -440,6 +450,7 @@ void BackgroundHangMonitor::Startup() { #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR + MOZ_ASSERT(!BackgroundHangManager::sProhibited, "Prohibited"); MOZ_ASSERT(!BackgroundHangManager::sInstance, "Already initialized"); ThreadStackHelper::Startup(); BackgroundHangThread::Startup(); @@ -451,6 +462,7 @@ 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 @@ -467,7 +479,8 @@ BackgroundHangMonitor::BackgroundHangMonitor(const char* aName, : 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 @@ -477,7 +490,8 @@ 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 } @@ -489,6 +503,11 @@ 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 } @@ -497,18 +516,49 @@ 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* diff --git a/xpcom/threads/BackgroundHangMonitor.h b/xpcom/threads/BackgroundHangMonitor.h index 76d517fce4dd..059fb0a08ff9 100644 --- a/xpcom/threads/BackgroundHangMonitor.h +++ b/xpcom/threads/BackgroundHangMonitor.h @@ -107,6 +107,8 @@ class BackgroundHangThread; * } * } * + * Prohibit() and Allow() make the background hang monitor work safely + * before Startup(). */ class BackgroundHangMonitor { @@ -204,6 +206,27 @@ public: * 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