зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1465287 Part 8 - Allow spawning recording/replaying child processes and saving recordings, r=jld,mrbkap.
--HG-- extra : rebase_source : 1da4b1a7e485cfdafb38318860546ce3d0552815
This commit is contained in:
Родитель
d138090586
Коммит
3354a96d8d
|
@ -605,7 +605,8 @@ public:
|
|||
// present.
|
||||
if (!targetProcess) {
|
||||
targetProcess =
|
||||
ContentParent::GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
ContentParent::GetNewOrUsedBrowserProcess(nullptr,
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
ContentParent::GetInitialProcessPriority(nullptr),
|
||||
nullptr);
|
||||
}
|
||||
|
|
|
@ -113,4 +113,10 @@ interface nsITabParent : nsISupports
|
|||
* autoscrolled.
|
||||
*/
|
||||
void stopApzAutoscroll(in nsViewID aScrollId, in uint32_t aPresShellId);
|
||||
|
||||
/**
|
||||
* Save a recording of the associated content process' behavior to the
|
||||
* specified filename. Returns whether the process is being recorded.
|
||||
*/
|
||||
bool saveRecording(in AString aFileName);
|
||||
};
|
||||
|
|
|
@ -3828,6 +3828,13 @@ ContentChild::RecvAddDynamicScalars(nsTArray<DynamicScalarDefinition>&& aDefs)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvSaveRecording(const FileDescriptor& aFile)
|
||||
{
|
||||
recordreplay::parent::SaveRecording(aFile);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIEventTarget>
|
||||
ContentChild::GetSpecificMessageEventTarget(const Message& aMsg)
|
||||
{
|
||||
|
|
|
@ -736,6 +736,9 @@ public:
|
|||
virtual bool
|
||||
DeallocPClientOpenWindowOpChild(PClientOpenWindowOpChild* aActor) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvSaveRecording(const FileDescriptor& aFile) override;
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Fetch the current number of pending input events.
|
||||
//
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
#include "nsConsoleService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebugImpl.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsEmbedCID.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
|
@ -611,7 +612,9 @@ ContentParent::PreallocateProcess()
|
|||
{
|
||||
RefPtr<ContentParent> process =
|
||||
new ContentParent(/* aOpener = */ nullptr,
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
eNotRecordingOrReplaying,
|
||||
/* aRecordingFile = */ EmptyString());
|
||||
|
||||
PreallocatedProcessManager::AddBlocker(process);
|
||||
|
||||
|
@ -767,18 +770,55 @@ ContentParent::MinTabSelect(const nsTArray<ContentParent*>& aContentParents,
|
|||
return candidate.forget();
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateTemporaryRecordingFile(nsAString& aResult)
|
||||
{
|
||||
unsigned long elapsed = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
return !NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file)))
|
||||
&& !NS_FAILED(file->AppendNative(nsPrintfCString("Recording%lu", elapsed)))
|
||||
&& !NS_FAILED(file->GetPath(aResult));
|
||||
}
|
||||
|
||||
/*static*/ already_AddRefed<ContentParent>
|
||||
ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
|
||||
ContentParent::GetNewOrUsedBrowserProcess(Element* aFrameElement,
|
||||
const nsAString& aRemoteType,
|
||||
ProcessPriority aPriority,
|
||||
ContentParent* aOpener,
|
||||
bool aPreferUsed)
|
||||
{
|
||||
// Figure out if this process will be recording or replaying, and which file
|
||||
// to use for the recording.
|
||||
RecordReplayState recordReplayState = eNotRecordingOrReplaying;
|
||||
nsAutoString recordingFile;
|
||||
if (aFrameElement) {
|
||||
aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::ReplayExecution, recordingFile);
|
||||
if (!recordingFile.IsEmpty()) {
|
||||
recordReplayState = eReplaying;
|
||||
} else {
|
||||
aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::RecordExecution, recordingFile);
|
||||
if (recordingFile.IsEmpty() && recordreplay::parent::SaveAllRecordingsDirectory()) {
|
||||
recordingFile.AssignLiteral("*");
|
||||
}
|
||||
if (!recordingFile.IsEmpty()) {
|
||||
if (recordingFile.EqualsLiteral("*") && !CreateTemporaryRecordingFile(recordingFile)) {
|
||||
return nullptr;
|
||||
}
|
||||
recordReplayState = eRecording;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
|
||||
uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
|
||||
if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||
if (recordReplayState != eNotRecordingOrReplaying) {
|
||||
// Fall through and always create a new process when recording or replaying.
|
||||
} else if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||
// We never want to re-use Large-Allocation processes.
|
||||
if (contentParents.Length() >= maxContentParents) {
|
||||
return GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
return GetNewOrUsedBrowserProcess(aFrameElement,
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
aPriority,
|
||||
aOpener);
|
||||
}
|
||||
|
@ -836,7 +876,7 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
|
|||
}
|
||||
|
||||
// Create a new process from scratch.
|
||||
RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType);
|
||||
RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType, recordReplayState, recordingFile);
|
||||
|
||||
// Until the new process is ready let's not allow to start up any preallocated processes.
|
||||
PreallocatedProcessManager::AddBlocker(p);
|
||||
|
@ -845,7 +885,10 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
contentParents.AppendElement(p);
|
||||
if (recordReplayState == eNotRecordingOrReplaying) {
|
||||
contentParents.AppendElement(p);
|
||||
}
|
||||
|
||||
p->mActivateTS = TimeStamp::Now();
|
||||
return p.forget();
|
||||
}
|
||||
|
@ -942,7 +985,7 @@ ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
|
|||
aPriority);
|
||||
}
|
||||
else {
|
||||
cp = GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
cp = GetNewOrUsedBrowserProcess(nullptr, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
aPriority, this);
|
||||
}
|
||||
|
||||
|
@ -1163,7 +1206,7 @@ ContentParent::CreateBrowser(const TabContext& aContext,
|
|||
initialPriority);
|
||||
} else {
|
||||
constructorSender =
|
||||
GetNewOrUsedBrowserProcess(remoteType, initialPriority,
|
||||
GetNewOrUsedBrowserProcess(aFrameElement, remoteType, initialPriority,
|
||||
nullptr, isPreloadBrowser);
|
||||
}
|
||||
if (!constructorSender) {
|
||||
|
@ -1405,6 +1448,18 @@ ContentParent::ShutDownProcess(ShutDownMethod aMethod)
|
|||
// other methods. We first call Shutdown() in the child. After the child is
|
||||
// ready, it calls FinishShutdown() on us. Then we close the channel.
|
||||
if (aMethod == SEND_SHUTDOWN_MESSAGE) {
|
||||
if (const char* directory = recordreplay::parent::SaveAllRecordingsDirectory()) {
|
||||
// Save a recording for the child process before it shuts down.
|
||||
unsigned long elapsed = (TimeStamp::Now() - TimeStamp::ProcessCreation()).ToMilliseconds();
|
||||
nsCOMPtr<nsIFile> file;
|
||||
if (!NS_FAILED(NS_NewNativeLocalFile(nsDependentCString(directory), false,
|
||||
getter_AddRefs(file))) &&
|
||||
!NS_FAILED(file->AppendNative(nsPrintfCString("Recording%lu", elapsed)))) {
|
||||
bool unused;
|
||||
SaveRecording(file, &unused);
|
||||
}
|
||||
}
|
||||
|
||||
if (mIPCOpen && !mShutdownPending) {
|
||||
// Stop sending input events with input priority when shutting down.
|
||||
SetInputPriorityEventEnabled(false);
|
||||
|
@ -1794,6 +1849,14 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
DelayedDeleteSubprocess, mSubprocess));
|
||||
mSubprocess = nullptr;
|
||||
|
||||
// Delete any remaining replaying children.
|
||||
for (auto& replayingProcess : mReplayingChildren) {
|
||||
if (replayingProcess) {
|
||||
DelayedDeleteSubprocess(replayingProcess);
|
||||
replayingProcess = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// IPDL rules require actors to live on past ActorDestroy, but it
|
||||
// may be that the kungFuDeathGrip above is the last reference to
|
||||
// |this|. If so, when we go out of scope here, we're deleted and
|
||||
|
@ -1981,6 +2044,65 @@ ContentParent::NotifyTabDestroyed(const TabId& aTabId,
|
|||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvOpenRecordReplayChannel(const uint32_t& aChannelId,
|
||||
FileDescriptor* aConnection)
|
||||
{
|
||||
// We should only get this message from the child if it is recording or replaying.
|
||||
if (!recordreplay::IsRecordingOrReplaying()) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
recordreplay::parent::OpenChannel(Pid(), aChannelId, aConnection);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvCreateReplayingProcess(const uint32_t& aChannelId)
|
||||
{
|
||||
// We should only get this message from the child if it is recording or replaying.
|
||||
if (!recordreplay::IsRecordingOrReplaying()) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
while (aChannelId >= mReplayingChildren.length()) {
|
||||
if (!mReplayingChildren.append(nullptr)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
}
|
||||
if (mReplayingChildren[aChannelId]) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
std::vector<std::string> extraArgs;
|
||||
recordreplay::parent::GetArgumentsForChildProcess(Pid(), aChannelId,
|
||||
NS_ConvertUTF16toUTF8(mRecordingFile).get(),
|
||||
/* aRecording = */ false,
|
||||
extraArgs);
|
||||
|
||||
mReplayingChildren[aChannelId] = new GeckoChildProcessHost(GeckoProcessType_Content);
|
||||
if (!mReplayingChildren[aChannelId]->LaunchAndWaitForProcessHandle(extraArgs)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvTerminateReplayingProcess(const uint32_t& aChannelId)
|
||||
{
|
||||
// We should only get this message from the child if it is recording or replaying.
|
||||
if (!recordreplay::IsRecordingOrReplaying()) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
if (aChannelId < mReplayingChildren.length() && mReplayingChildren[aChannelId]) {
|
||||
DelayedDeleteSubprocess(mReplayingChildren[aChannelId]);
|
||||
mReplayingChildren[aChannelId] = nullptr;
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
jsipc::CPOWManager*
|
||||
ContentParent::GetCPOWManager()
|
||||
{
|
||||
|
@ -2101,6 +2223,18 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
|||
extraArgs.push_back("-parentBuildID");
|
||||
extraArgs.push_back(parentBuildID.get());
|
||||
|
||||
// Specify whether the process is recording or replaying an execution.
|
||||
if (mRecordReplayState != eNotRecordingOrReplaying) {
|
||||
nsPrintfCString buf("%d", mRecordReplayState == eRecording
|
||||
? (int) recordreplay::ProcessKind::MiddlemanRecording
|
||||
: (int) recordreplay::ProcessKind::MiddlemanReplaying);
|
||||
extraArgs.push_back(recordreplay::gProcessKindOption);
|
||||
extraArgs.push_back(buf.get());
|
||||
|
||||
extraArgs.push_back(recordreplay::gRecordingFileOption);
|
||||
extraArgs.push_back(NS_ConvertUTF16toUTF8(mRecordingFile).get());
|
||||
}
|
||||
|
||||
SetOtherProcessId(kInvalidProcessId, ProcessIdState::ePending);
|
||||
#ifdef ASYNC_CONTENTPROC_LAUNCH
|
||||
if (!mSubprocess->Launch(extraArgs)) {
|
||||
|
@ -2154,6 +2288,8 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
|||
|
||||
ContentParent::ContentParent(ContentParent* aOpener,
|
||||
const nsAString& aRemoteType,
|
||||
RecordReplayState aRecordReplayState,
|
||||
const nsAString& aRecordingFile,
|
||||
int32_t aJSPluginID)
|
||||
: nsIContentParent()
|
||||
, mSubprocess(nullptr)
|
||||
|
@ -2168,6 +2304,8 @@ ContentParent::ContentParent(ContentParent* aOpener,
|
|||
, mIsAvailable(true)
|
||||
, mIsAlive(true)
|
||||
, mIsForBrowser(!mRemoteType.IsEmpty())
|
||||
, mRecordReplayState(aRecordReplayState)
|
||||
, mRecordingFile(aRecordingFile)
|
||||
, mCalledClose(false)
|
||||
, mCalledKillHard(false)
|
||||
, mCreatedPairedMinidumps(false)
|
||||
|
@ -5767,6 +5905,31 @@ ContentParent::CanCommunicateWith(ContentParentId aOtherProcess)
|
|||
return parentId == aOtherProcess;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContentParent::SaveRecording(nsIFile* aFile, bool* aRetval)
|
||||
{
|
||||
if (mRecordReplayState != eRecording) {
|
||||
*aRetval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRFileDesc* prfd;
|
||||
nsresult rv = aFile->OpenNSPRFileDesc(PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE, 0644, &prfd);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
FileDescriptor::PlatformHandleType handle =
|
||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfd));
|
||||
|
||||
Unused << SendSaveRecording(FileDescriptor(handle));
|
||||
|
||||
PR_Close(prfd);
|
||||
|
||||
*aRetval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvMaybeReloadPlugins()
|
||||
{
|
||||
|
|
|
@ -174,7 +174,8 @@ public:
|
|||
* 3. normal iframe
|
||||
*/
|
||||
static already_AddRefed<ContentParent>
|
||||
GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
|
||||
GetNewOrUsedBrowserProcess(Element* aFrameElement,
|
||||
const nsAString& aRemoteType,
|
||||
hal::ProcessPriority aPriority =
|
||||
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
|
||||
ContentParent* aOpener = nullptr,
|
||||
|
@ -303,6 +304,11 @@ public:
|
|||
virtual mozilla::ipc::IPCResult RecvBridgeToChildProcess(const ContentParentId& aCpId,
|
||||
Endpoint<PContentBridgeParent>* aEndpoint) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvOpenRecordReplayChannel(const uint32_t& channelId,
|
||||
FileDescriptor* connection) override;
|
||||
virtual mozilla::ipc::IPCResult RecvCreateReplayingProcess(const uint32_t& aChannelId) override;
|
||||
virtual mozilla::ipc::IPCResult RecvTerminateReplayingProcess(const uint32_t& aChannelId) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvCreateGMPService() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv,
|
||||
|
@ -743,16 +749,28 @@ private:
|
|||
|
||||
FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
|
||||
|
||||
enum RecordReplayState
|
||||
{
|
||||
eNotRecordingOrReplaying,
|
||||
eRecording,
|
||||
eReplaying
|
||||
};
|
||||
|
||||
explicit ContentParent(int32_t aPluginID)
|
||||
: ContentParent(nullptr, EmptyString(), aPluginID)
|
||||
: ContentParent(nullptr, EmptyString(), eNotRecordingOrReplaying, EmptyString(), aPluginID)
|
||||
{}
|
||||
ContentParent(ContentParent* aOpener,
|
||||
const nsAString& aRemoteType)
|
||||
: ContentParent(aOpener, aRemoteType, nsFakePluginTag::NOT_JSPLUGIN)
|
||||
const nsAString& aRemoteType,
|
||||
RecordReplayState aRecordReplayState = eNotRecordingOrReplaying,
|
||||
const nsAString& aRecordingFile = EmptyString())
|
||||
: ContentParent(aOpener, aRemoteType, aRecordReplayState, aRecordingFile,
|
||||
nsFakePluginTag::NOT_JSPLUGIN)
|
||||
{}
|
||||
|
||||
ContentParent(ContentParent* aOpener,
|
||||
const nsAString& aRemoteType,
|
||||
RecordReplayState aRecordReplayState,
|
||||
const nsAString& aRecordingFile,
|
||||
int32_t aPluginID);
|
||||
|
||||
// Launch the subprocess and associated initialization.
|
||||
|
@ -1248,6 +1266,8 @@ public:
|
|||
|
||||
bool CanCommunicateWith(ContentParentId aOtherProcess);
|
||||
|
||||
nsresult SaveRecording(nsIFile* aFile, bool* aRetval);
|
||||
|
||||
private:
|
||||
|
||||
// If you add strong pointers to cycle collected objects here, be sure to
|
||||
|
@ -1291,6 +1311,16 @@ private:
|
|||
|
||||
bool mIsForBrowser;
|
||||
|
||||
// Whether this process is recording or replaying its execution, and any
|
||||
// associated recording file.
|
||||
RecordReplayState mRecordReplayState;
|
||||
nsString mRecordingFile;
|
||||
|
||||
// When recording or replaying, the child process is a middleman. This vector
|
||||
// stores any replaying children we have spawned on behalf of that middleman,
|
||||
// indexed by their record/replay channel ID.
|
||||
Vector<mozilla::ipc::GeckoChildProcessHost*> mReplayingChildren;
|
||||
|
||||
// These variables track whether we've called Close() and KillHard() on our
|
||||
// channel.
|
||||
bool mCalledClose;
|
||||
|
|
|
@ -726,6 +726,9 @@ child:
|
|||
*/
|
||||
async PClientOpenWindowOp(ClientOpenWindowArgs aArgs);
|
||||
|
||||
/* Save the execution up to the current point in a recording process. */
|
||||
async SaveRecording(FileDescriptor file);
|
||||
|
||||
parent:
|
||||
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
|
||||
|
||||
|
@ -737,6 +740,11 @@ parent:
|
|||
sync BridgeToChildProcess(ContentParentId cpId)
|
||||
returns (Endpoint<PContentBridgeParent> endpoint);
|
||||
|
||||
sync OpenRecordReplayChannel(uint32_t channelId)
|
||||
returns (FileDescriptor connection);
|
||||
async CreateReplayingProcess(uint32_t channelId);
|
||||
async TerminateReplayingProcess(uint32_t channelId);
|
||||
|
||||
async CreateGMPService();
|
||||
|
||||
async InitStreamFilter(uint64_t channelId, nsString addonId)
|
||||
|
|
|
@ -2964,6 +2964,17 @@ TabParent::PreserveLayers(bool aPreserveLayers)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::SaveRecording(const nsAString& aFilename, bool* aRetval)
|
||||
{
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_NewLocalFile(aFilename, false, getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return Manager()->AsContentParent()->SaveRecording(file, aRetval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::SuppressDisplayport(bool aEnabled)
|
||||
{
|
||||
|
|
|
@ -849,6 +849,8 @@ description =
|
|||
description =
|
||||
[PContent::BridgeToChildProcess]
|
||||
description =
|
||||
[PContent::OpenRecordReplayChannel]
|
||||
description = bug 1475898 this could be async
|
||||
[PContent::LoadPlugin]
|
||||
description =
|
||||
[PContent::ConnectPluginBridge]
|
||||
|
|
|
@ -951,7 +951,7 @@ nsXULAppInfo::EnsureContentProcess()
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
RefPtr<ContentParent> unused = ContentParent::GetNewOrUsedBrowserProcess(
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
nullptr, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -982,7 +982,7 @@ TestShellParent* GetOrCreateTestShellParent()
|
|||
// processes.
|
||||
RefPtr<ContentParent> parent =
|
||||
ContentParent::GetNewOrUsedBrowserProcess(
|
||||
NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
nullptr, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
parent.forget(&gContentParent);
|
||||
} else if (!gContentParent->IsAlive()) {
|
||||
return nullptr;
|
||||
|
|
|
@ -1982,6 +1982,8 @@ GK_ATOM(DisplayPortMargins, "_displayportmargins")
|
|||
GK_ATOM(DisplayPortBase, "_displayportbase")
|
||||
GK_ATOM(forcemessagemanager, "forcemessagemanager")
|
||||
GK_ATOM(preloadedState, "preloadedState")
|
||||
GK_ATOM(RecordExecution, "recordExecution")
|
||||
GK_ATOM(ReplayExecution, "replayExecution")
|
||||
|
||||
// Names for system metrics
|
||||
GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
|
||||
|
|
Загрузка…
Ссылка в новой задаче