mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +00:00
bcff2dd108
In order to enable asynchronous launch, destruction of GeckoChildProcessHost (and its subclasses) has to be delayed until after launching (or anything else that might be made asynchronous in the future) has completed, to prevent use-after-free. However, there are other dependencies on process hosts always being destroyed on the I/O thread, so refcounting would be difficult to use. Instead, GeckoChildProcessHost now may not be destroyed directly, but must go through a method that handles the scheduling. There are also some minor cleanups to the affected headers (removed duplicate access modifiers, and made PluginProcessParent final). Depends on D18010 Differential Revision: https://phabricator.services.mozilla.com/D18011 --HG-- extra : moz-landing-system : lando
191 lines
5.4 KiB
C++
191 lines
5.4 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vim: sw=2 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 "mozilla/plugins/PluginProcessParent.h"
|
|
|
|
#include "base/string_util.h"
|
|
#include "base/process_util.h"
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
#include "nsDirectoryServiceDefs.h"
|
|
#include "nsIProperties.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "mozilla/ipc/BrowserProcessSubThread.h"
|
|
#include "mozilla/plugins/PluginMessageUtils.h"
|
|
#include "mozilla/Telemetry.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
|
|
using mozilla::ipc::BrowserProcessSubThread;
|
|
using mozilla::ipc::GeckoChildProcessHost;
|
|
using mozilla::plugins::LaunchCompleteTask;
|
|
using mozilla::plugins::PluginProcessParent;
|
|
|
|
#ifdef XP_WIN
|
|
PluginProcessParent::PidSet* PluginProcessParent::sPidSet = nullptr;
|
|
#endif
|
|
|
|
PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath)
|
|
: GeckoChildProcessHost(GeckoProcessType_Plugin),
|
|
mPluginFilePath(aPluginFilePath),
|
|
mTaskFactory(this),
|
|
mMainMsgLoop(MessageLoop::current())
|
|
#ifdef XP_WIN
|
|
,
|
|
mChildPid(0)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
PluginProcessParent::~PluginProcessParent() {
|
|
#ifdef XP_WIN
|
|
if (sPidSet && mChildPid) {
|
|
sPidSet->RemoveEntry(mChildPid);
|
|
if (sPidSet->IsEmpty()) {
|
|
delete sPidSet;
|
|
sPidSet = nullptr;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool PluginProcessParent::Launch(
|
|
mozilla::UniquePtr<LaunchCompleteTask> aLaunchCompleteTask,
|
|
int32_t aSandboxLevel, bool aIsSandboxLoggingEnabled) {
|
|
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_SANDBOX)
|
|
// At present, the Mac Flash plugin sandbox does not support different
|
|
// levels and is enabled via a boolean pref or environment variable.
|
|
// On Mac, when |aSandboxLevel| is positive, we enable the sandbox.
|
|
# if defined(XP_WIN)
|
|
mSandboxLevel = aSandboxLevel;
|
|
|
|
// The sandbox process sometimes needs read access to the plugin file.
|
|
if (aSandboxLevel >= 3) {
|
|
std::wstring pluginFile(
|
|
NS_ConvertUTF8toUTF16(mPluginFilePath.c_str()).get());
|
|
mAllowedFilesRead.push_back(pluginFile);
|
|
}
|
|
# endif // XP_WIN
|
|
#else
|
|
if (aSandboxLevel != 0) {
|
|
MOZ_ASSERT(false,
|
|
"Can't enable an NPAPI process sandbox for platform/build.");
|
|
}
|
|
#endif
|
|
|
|
mLaunchCompleteTask = std::move(aLaunchCompleteTask);
|
|
|
|
vector<string> args;
|
|
args.push_back(MungePluginDsoPath(mPluginFilePath));
|
|
|
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
|
if (aSandboxLevel > 0) {
|
|
args.push_back("-flashSandboxLevel");
|
|
args.push_back(std::to_string(aSandboxLevel));
|
|
if (aIsSandboxLoggingEnabled) {
|
|
args.push_back("-flashSandboxLogging");
|
|
}
|
|
}
|
|
#elif defined(XP_WIN) && defined(MOZ_SANDBOX)
|
|
nsresult rv;
|
|
nsCOMPtr<nsIProperties> dirSvc =
|
|
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
|
|
if (NS_FAILED(rv)) {
|
|
MOZ_ASSERT(false, "Failed to get directory service.");
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsIFile> dir;
|
|
rv = dirSvc->Get(NS_APP_PLUGIN_PROCESS_TEMP_DIR, NS_GET_IID(nsIFile),
|
|
getter_AddRefs(dir));
|
|
if (NS_FAILED(rv)) {
|
|
NS_WARNING("Failed to get plugin process temp directory.");
|
|
return false;
|
|
}
|
|
|
|
nsAutoString tempDir;
|
|
MOZ_ALWAYS_SUCCEEDS(dir->GetPath(tempDir));
|
|
args.push_back(NS_ConvertUTF16toUTF8(tempDir).get());
|
|
|
|
rv =
|
|
dirSvc->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsIFile), getter_AddRefs(dir));
|
|
if (NS_FAILED(rv)) {
|
|
NS_WARNING("Failed to get appdata directory.");
|
|
return false;
|
|
}
|
|
|
|
nsAutoString appdataDir;
|
|
MOZ_ALWAYS_SUCCEEDS(dir->GetPath(appdataDir));
|
|
appdataDir.Append(L"\\Adobe\\");
|
|
args.push_back(NS_ConvertUTF16toUTF8(appdataDir).get());
|
|
#endif
|
|
|
|
bool result = AsyncLaunch(args);
|
|
if (!result) {
|
|
mLaunchCompleteTask = nullptr;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This function exists so that we may provide an additional level of
|
|
* indirection between the task being posted to main event loop (a
|
|
* RunnableMethod) and the launch complete task itself. This is needed
|
|
* for cases when both WaitUntilConnected or OnChannel* race to invoke the
|
|
* task.
|
|
*/
|
|
void PluginProcessParent::RunLaunchCompleteTask() {
|
|
if (mLaunchCompleteTask) {
|
|
mLaunchCompleteTask->Run();
|
|
mLaunchCompleteTask = nullptr;
|
|
}
|
|
}
|
|
|
|
bool PluginProcessParent::WaitUntilConnected(int32_t aTimeoutMs) {
|
|
bool result = GeckoChildProcessHost::WaitUntilConnected(aTimeoutMs);
|
|
if (mLaunchCompleteTask) {
|
|
if (result) {
|
|
mLaunchCompleteTask->SetLaunchSucceeded();
|
|
}
|
|
RunLaunchCompleteTask();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void PluginProcessParent::OnChannelConnected(int32_t peer_pid) {
|
|
#ifdef XP_WIN
|
|
mChildPid = static_cast<uint32_t>(peer_pid);
|
|
if (!sPidSet) {
|
|
sPidSet = new PluginProcessParent::PidSet();
|
|
}
|
|
sPidSet->PutEntry(mChildPid);
|
|
#endif
|
|
|
|
GeckoChildProcessHost::OnChannelConnected(peer_pid);
|
|
}
|
|
|
|
void PluginProcessParent::OnChannelError() {
|
|
GeckoChildProcessHost::OnChannelError();
|
|
}
|
|
|
|
bool PluginProcessParent::IsConnected() {
|
|
mozilla::MonitorAutoLock lock(mMonitor);
|
|
return mProcessState == PROCESS_CONNECTED;
|
|
}
|
|
|
|
bool PluginProcessParent::IsPluginProcessId(base::ProcessId procId) {
|
|
#ifdef XP_WIN
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
return sPidSet && sPidSet->Contains(static_cast<uint32_t>(procId));
|
|
#else
|
|
NS_ERROR("IsPluginProcessId not available on this platform.");
|
|
return false;
|
|
#endif
|
|
}
|