gecko/dom/ipc/ContentParent.h
Justin Lebar 73756e9464 Bug 836654 - Part 9: During app-frame creation, take the CPU wake lock only after sending down the mozapptype. r=cjones
This prevents the child process from downgrading its CPU priority when
it notices that it has the CPU wake lock but no "critical" frames.

In this patch we also reduce the scope of a race condition which occurs
when we don't launch a new process for an app.  In this case, we still
need to set the child process's priority and then check that the process
is still alive.

Because this isn't a brand-new process, it's possible that the process
will downgrade its priority (e.g. due to a timer) after we check that
it's still alive and before it notices that we've acquired the CPU wake
lock on its behalf.  This patch does not resolve that race.
2013-02-14 15:41:30 -05:00

426 lines
17 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ContentParent_h
#define mozilla_dom_ContentParent_h
#include "base/waitable_event_watcher.h"
#include "mozilla/dom/PContentParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/Attributes.h"
#include "mozilla/HalTypes.h"
#include "nsFrameMessageManager.h"
#include "nsIObserver.h"
#include "nsIThreadInternal.h"
#include "nsNetUtil.h"
#include "nsIPermissionManager.h"
#include "nsIDOMGeoPositionCallback.h"
#include "nsIMemoryReporter.h"
#include "nsCOMArray.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "PermissionMessageUtils.h"
#define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
class mozIApplication;
class nsConsoleService;
class nsIDOMBlob;
namespace mozilla {
namespace ipc {
class OptionalURIParams;
class URIParams;
class TestShellParent;
} // namespace ipc
namespace layers {
class PCompositorParent;
} // namespace layers
namespace dom {
class TabParent;
class PStorageParent;
class ClonedMessageData;
class ContentParent : public PContentParent
, public nsIObserver
, public nsIThreadObserver
, public nsIDOMGeoPositionCallback
, public mozilla::dom::ipc::MessageManagerCallback
{
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
typedef mozilla::ipc::TestShellParent TestShellParent;
typedef mozilla::ipc::URIParams URIParams;
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
/**
* Start up the content-process machinery. This might include
* scheduling pre-launch tasks.
*/
static void StartUp();
/** Shut down the content-process machinery. */
static void ShutDown();
/**
* Ensure that all subprocesses are terminated and their OS
* resources have been reaped. This is synchronous and can be
* very expensive in general. It also bypasses the normal
* shutdown process.
*/
static void JoinAllSubprocesses();
static ContentParent* GetNewOrUsed(bool aForBrowserElement = false);
/**
* Get or create a content process for the given TabContext. aFrameElement
* should be the frame/iframe element with which this process will
* associated.
*/
static TabParent*
CreateBrowserOrApp(const TabContext& aContext,
nsIDOMElement* aFrameElement);
static void GetAll(nsTArray<ContentParent*>& aArray);
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIDOMGEOPOSITIONCALLBACK
/**
* MessageManagerCallback methods that we override.
*/
virtual bool DoSendAsyncMessage(const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData);
virtual bool CheckPermission(const nsAString& aPermission);
virtual bool CheckManifestURL(const nsAString& aManifestURL);
virtual bool CheckAppHasPermission(const nsAString& aPermission);
/** Notify that a tab is beginning its destruction sequence. */
void NotifyTabDestroying(PBrowserParent* aTab);
/** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab,
bool aNotifiedDestroying);
TestShellParent* CreateTestShell();
bool DestroyTestShell(TestShellParent* aTestShell);
TestShellParent* GetTestShellSingleton();
void ReportChildAlreadyBlocked();
bool RequestRunToCompletion();
bool IsAlive();
bool IsForApp();
void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
GeckoChildProcessHost* Process() {
return mSubprocess;
}
bool NeedsPermissionsUpdate() {
return mSendPermissionUpdates;
}
BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
/**
* Kill our subprocess and make sure it dies. Should only be used
* in emergency situations since it bypasses the normal shutdown
* process.
*/
void KillHard();
uint64_t ChildID() { return mChildID; }
protected:
void OnChannelConnected(int32_t pid);
virtual void ActorDestroy(ActorDestroyReason why);
private:
static nsDataHashtable<nsStringHashKey, ContentParent*> *gAppContentParents;
static nsTArray<ContentParent*>* gNonAppContentParents;
static nsTArray<ContentParent*>* gPrivateContent;
static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
Monitor* aMonitor, bool* aDone);
static void PreallocateAppProcess();
static void DelayedPreallocateAppProcess();
static void ScheduleDelayedPreallocateAppProcess();
// Take the preallocated process and transform it into a "real" app process,
// for the specified manifest URL. If there is no preallocated process (or
// if it's dead), this returns false.
static already_AddRefed<ContentParent>
MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL,
ChildPrivileges aPrivs,
hal::ProcessPriority aInitialPriority);
static hal::ProcessPriority GetInitialProcessPriority(nsIDOMElement* aFrameElement);
static void FirstIdle();
// Hide the raw constructor methods since we don't want client code
// using them.
using PContentParent::SendPBrowserConstructor;
using PContentParent::SendPTestShellConstructor;
ContentParent(const nsAString& aAppManifestURL, bool aIsForBrowser,
ChildPrivileges aOSPrivileges = base::PRIVILEGES_DEFAULT,
hal::ProcessPriority aInitialPriority = hal::PROCESS_PRIORITY_FOREGROUND);
virtual ~ContentParent();
void Init();
// Set the child process's priority. Once the child starts up, it will
// manage its own priority via the ProcessPriorityManager.
void SetProcessPriority(hal::ProcessPriority aInitialPriority);
// If the frame element indicates that the child process is "critical" and
// has a pending system message, this function acquires the CPU wake lock on
// behalf of the child. We'll release the lock when the system message is
// handled or after a timeout, whichever comes first.
void MaybeTakeCPUWakeLock(nsIDOMElement* aFrameElement);
// Set the child process's priority and then check whether the child is
// still alive. Returns true if the process is still alive, and false
// otherwise. If you pass a FOREGROUND* priority here, it's (hopefully)
// unlikely that the process will be killed after this point.
bool SetPriorityAndCheckIsAlive(hal::ProcessPriority aPriority);
// Transform a pre-allocated app process into a "real" app
// process, for the specified manifest URL. If this returns false, the
// child process has died.
bool TransformPreallocatedIntoApp(const nsAString& aAppManifestURL,
ChildPrivileges aPrivs);
/**
* Mark this ContentParent as dead for the purposes of Get*().
* This method is idempotent.
*/
void MarkAsDead();
/**
* Exit the subprocess and vamoose. After this call IsAlive()
* will return false and this ContentParent will not be returned
* by the Get*() funtions. However, the shutdown sequence itself
* may be asynchronous.
*/
void ShutDownProcess();
PCompositorParent*
AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
PImageBridgeParent*
AllocPImageBridge(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
virtual bool RecvGetProcessAttributes(uint64_t* aId,
bool* aIsForApp,
bool* aIsForBrowser) MOZ_OVERRIDE;
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline) MOZ_OVERRIDE;
virtual PBrowserParent* AllocPBrowser(const IPCTabContext& aContext,
const uint32_t& aChromeFlags);
virtual bool DeallocPBrowser(PBrowserParent* frame);
virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);
virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestParent*);
virtual PBlobParent* AllocPBlob(const BlobConstructorParams& aParams);
virtual bool DeallocPBlob(PBlobParent*);
virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
const uint32_t& processType);
virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
virtual bool RecvPCrashReporterConstructor(PCrashReporterParent* actor,
const NativeThreadId& tid,
const uint32_t& processType);
virtual PHalParent* AllocPHal() MOZ_OVERRIDE;
virtual bool DeallocPHal(PHalParent*) MOZ_OVERRIDE;
virtual PIndexedDBParent* AllocPIndexedDB();
virtual bool DeallocPIndexedDB(PIndexedDBParent* aActor);
virtual bool
RecvPIndexedDBConstructor(PIndexedDBParent* aActor);
virtual PMemoryReportRequestParent* AllocPMemoryReportRequest();
virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
virtual PTestShellParent* AllocPTestShell();
virtual bool DeallocPTestShell(PTestShellParent* shell);
virtual PNeckoParent* AllocPNecko();
virtual bool DeallocPNecko(PNeckoParent* necko);
virtual PExternalHelperAppParent* AllocPExternalHelperApp(
const OptionalURIParams& aUri,
const nsCString& aMimeContentType,
const nsCString& aContentDisposition,
const bool& aForceSave,
const int64_t& aContentLength,
const OptionalURIParams& aReferrer);
virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
virtual PSmsParent* AllocPSms();
virtual bool DeallocPSms(PSmsParent*);
virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
virtual bool DeallocPStorage(PStorageParent* aActor);
virtual PBluetoothParent* AllocPBluetooth();
virtual bool DeallocPBluetooth(PBluetoothParent* aActor);
virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor);
virtual bool RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs);
virtual bool RecvReadFontList(InfallibleTArray<FontListEntry>* retValue);
virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions);
virtual bool RecvSetClipboardText(const nsString& text, const bool& isPrivateData, const int32_t& whichClipboard);
virtual bool RecvGetClipboardText(const int32_t& whichClipboard, nsString* text);
virtual bool RecvEmptyClipboard();
virtual bool RecvClipboardHasText(bool* hasText);
virtual bool RecvGetSystemColors(const uint32_t& colorsCount, InfallibleTArray<uint32_t>* colors);
virtual bool RecvGetIconForExtension(const nsCString& aFileExt, const uint32_t& aIconSize, InfallibleTArray<uint8_t>* bits);
virtual bool RecvGetShowPasswordSetting(bool* showPassword);
virtual bool RecvStartVisitedQuery(const URIParams& uri);
virtual bool RecvVisitURI(const URIParams& uri,
const OptionalURIParams& referrer,
const uint32_t& flags);
virtual bool RecvSetURITitle(const URIParams& uri,
const nsString& title);
virtual bool RecvShowFilePicker(const int16_t& mode,
const int16_t& selectedType,
const bool& addToRecentDocs,
const nsString& title,
const nsString& defaultFile,
const nsString& defaultExtension,
const InfallibleTArray<nsString>& filters,
const InfallibleTArray<nsString>& filterNames,
InfallibleTArray<nsString>* files,
int16_t* retValue,
nsresult* result);
virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
const nsString& aText, const bool& aTextClickable,
const nsString& aCookie, const nsString& aName);
virtual bool RecvLoadURIExternal(const URIParams& uri);
virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<nsString>* aRetvals);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData);
virtual bool RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aFilePath,
const nsCString& aReason);
virtual bool RecvAddGeolocationListener(const IPC::Principal& aPrincipal);
virtual bool RecvRemoveGeolocationListener();
virtual bool RecvSetGeolocationHigherAccuracy(const bool& aEnable);
virtual bool RecvConsoleMessage(const nsString& aMessage);
virtual bool RecvScriptError(const nsString& aMessage,
const nsString& aSourceName,
const nsString& aSourceLine,
const uint32_t& aLineNumber,
const uint32_t& aColNumber,
const uint32_t& aFlags,
const nsCString& aCategory);
virtual bool RecvPrivateDocShellsExist(const bool& aExist);
virtual bool RecvFirstIdle();
virtual bool RecvAudioChannelGetMuted(const AudioChannelType& aType,
const bool& aElementHidden,
const bool& aElementWasHidden,
bool* aValue);
virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType);
virtual bool RecvAudioChannelUnregisterType(const AudioChannelType& aType,
const bool& aElementHidden);
virtual bool RecvAudioChannelChangedNotification();
virtual bool RecvBroadcastVolume(const nsString& aVolumeName);
virtual bool RecvRecordingDeviceEvents(const nsString& aRecordingStatus);
virtual bool RecvSystemMessageHandled() MOZ_OVERRIDE;
virtual void ProcessingError(Result what) MOZ_OVERRIDE;
GeckoChildProcessHost* mSubprocess;
base::ChildPrivileges mOSPrivileges;
uint64_t mChildID;
int32_t mGeolocationWatchID;
int mRunToCompletionDepth;
bool mShouldCallUnblockChild;
// This is a cache of all of the memory reporters
// registered in the child process. To update this, one
// can broadcast the topic "child-memory-reporter-request" using
// the nsIObserverService.
nsCOMArray<nsIMemoryReporter> mMemoryReporters;
const nsString mAppManifestURL;
nsRefPtr<nsFrameMessageManager> mMessageManager;
// After we initiate shutdown, we also start a timer to ensure
// that even content processes that are 100% blocked (say from
// SIGSTOP), are still killed eventually. This task enforces that
// timer.
CancelableTask* mForceKillTask;
// How many tabs we're waiting to finish their destruction
// sequence. Precisely, how many TabParents have called
// NotifyTabDestroying() but not called NotifyTabDestroyed().
int32_t mNumDestroyingTabs;
// True only while this is ready to be used to host remote tabs.
// This must not be used for new purposes after mIsAlive goes to
// false, but some previously scheduled IPC traffic may still pass
// through.
bool mIsAlive;
// True after the OS-level shutdown sequence has been initiated.
// After going true, any use of this at all, including lingering
// IPC traffic passing through, will cause assertions to fail.
bool mIsDestroyed;
bool mSendPermissionUpdates;
bool mIsForBrowser;
friend class CrashReporterParent;
nsRefPtr<nsConsoleService> mConsoleService;
nsConsoleService* GetConsoleService();
};
} // namespace dom
} // namespace mozilla
#endif