/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=2 ts=8 et ft=cpp : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/ipc/ProcessPriorityManager.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/TabChild.h" #include "mozilla/Hal.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/HalTypes.h" #include "mozilla/TimeStamp.h" #include "AudioChannelService.h" #include "prlog.h" #include "nsPrintfCString.h" #include "nsWeakPtr.h" #include "nsXULAppAPI.h" #include "nsIInterfaceRequestorUtils.h" #include "nsITimer.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIDocument.h" #include "nsIDOMEventListener.h" #include "nsIDOMWindow.h" #include "nsIDOMEvent.h" #include "nsIDOMEventTarget.h" #include "nsIDOMDocument.h" #include "nsPIDOMWindow.h" #include "StaticPtr.h" #ifdef XP_WIN #include #define getpid _getpid #else #include #endif using namespace mozilla::hal; namespace mozilla { namespace dom { namespace ipc { namespace { static bool sInitialized = false; class ProcessPriorityManager; static StaticRefPtr sManager; // Some header defines a LOG macro, but we don't want it here. #ifdef LOG #undef LOG #endif // Enable logging by setting // // NSPR_LOG_MODULES=ProcessPriorityManager:5 // // in your environment. Or just comment out the "&& 0" below, if you're on // Android/B2G. #if defined(ANDROID) && 0 #include #define LOG(fmt, ...) \ __android_log_print(ANDROID_LOG_INFO, \ "Gecko:ProcessPriorityManager", \ fmt, ## __VA_ARGS__) #elif defined(PR_LOGGING) static PRLogModuleInfo* GetPPMLog() { static PRLogModuleInfo *sLog; if (!sLog) sLog = PR_NewLogModule("ProcessPriorityManager"); return sLog; } #define LOG(fmt, ...) \ PR_LOG(GetPPMLog(), PR_LOG_DEBUG, \ ("[%d] ProcessPriorityManager - " fmt, getpid(), ##__VA_ARGS__)) #else #define LOG(fmt, ...) #endif /** * Get the appropriate backround priority for this process. */ ProcessPriority GetBackgroundPriority() { AudioChannelService* service = AudioChannelService::GetAudioChannelService(); if (service->ContentOrNormalChannelIsActive()) { return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE; } bool isHomescreen = false; ContentChild* contentChild = ContentChild::GetSingleton(); if (contentChild) { const InfallibleTArray& browsers = contentChild->ManagedPBrowserChild(); for (uint32_t i = 0; i < browsers.Length(); i++) { nsAutoString appType; static_cast(browsers[i])->GetAppType(appType); if (appType.EqualsLiteral("homescreen")) { isHomescreen = true; break; } } } return isHomescreen ? PROCESS_PRIORITY_BACKGROUND_HOMESCREEN : PROCESS_PRIORITY_BACKGROUND; } /** * Determine if the priority is a backround priority. */ bool IsBackgroundPriority(ProcessPriority aPriority) { return (aPriority == PROCESS_PRIORITY_BACKGROUND || aPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN || aPriority == PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE); } /** * This class listens to various Gecko events and asks the hal back-end to * change this process's priority when it transitions between various states of * "importance". * * The process's priority determines its CPU priority and also how likely it is * to be killed when the system is running out of memory. * * The most basic dichotomy in the ProcessPriorityManager is between * "foreground" processes, which usually have at least one active docshell, and * "background" processes. * * An important heuristic here is that we don't always mark a process as having * "background" priority until it's met the requisite criteria for some amount * of time. * * We do this because otherwise there are cases where we'd thrash a process * between foreground and background priorities; for example, Gaia sometimes * releases and re-acquires CPU wake locks in quick succession. * * On the other hand, when the embedder of an