204 lines
7.8 KiB
C++
204 lines
7.8 KiB
C++
|
|
// Copyright 2012 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#include "components/nacl/renderer/plugin/plugin.h"
|
||
|
|
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/types.h>
|
||
|
|
|
||
|
|
#include <string>
|
||
|
|
|
||
|
|
#include "base/check.h"
|
||
|
|
#include "components/nacl/renderer/plugin/nacl_subprocess.h"
|
||
|
|
#include "components/nacl/renderer/plugin/plugin_error.h"
|
||
|
|
#include "components/nacl/renderer/plugin/service_runtime.h"
|
||
|
|
#include "components/nacl/renderer/ppb_nacl_private.h"
|
||
|
|
#include "ppapi/c/pp_errors.h"
|
||
|
|
#include "ppapi/cpp/module.h"
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
void NoOpCallback(void* user_data, int32_t result) {
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
namespace plugin {
|
||
|
|
|
||
|
|
void Plugin::ShutDownSubprocesses() {
|
||
|
|
// Shut down service runtime. This must be done before all other calls so
|
||
|
|
// they don't block forever when waiting for the upcall thread to exit.
|
||
|
|
main_subprocess_.Shutdown();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Plugin::LoadNaClModule(PP_NaClFileInfo file_info,
|
||
|
|
PP_NaClAppProcessType process_type) {
|
||
|
|
CHECK(pp::Module::Get()->core()->IsMainThread());
|
||
|
|
// Before forking a new sel_ldr process, ensure that we do not leak
|
||
|
|
// the ServiceRuntime object for an existing subprocess, and that any
|
||
|
|
// associated listener threads do not go unjoined because if they
|
||
|
|
// outlive the Plugin object, they will not be memory safe.
|
||
|
|
ShutDownSubprocesses();
|
||
|
|
pp::Var manifest_base_url =
|
||
|
|
pp::Var(pp::PASS_REF,
|
||
|
|
nacl::PPBNaClPrivate::GetManifestBaseURL(pp_instance()));
|
||
|
|
std::string manifest_base_url_str = manifest_base_url.AsString();
|
||
|
|
|
||
|
|
SelLdrStartParams params(manifest_base_url_str,
|
||
|
|
file_info,
|
||
|
|
process_type);
|
||
|
|
ErrorInfo error_info;
|
||
|
|
ServiceRuntime* service_runtime =
|
||
|
|
new ServiceRuntime(this, pp_instance(), /*main_service_runtime=*/true);
|
||
|
|
main_subprocess_.set_service_runtime(service_runtime);
|
||
|
|
|
||
|
|
service_runtime->StartSelLdr(params,
|
||
|
|
pp::CompletionCallback(NoOpCallback, NULL));
|
||
|
|
}
|
||
|
|
|
||
|
|
void Plugin::LoadHelperNaClModule(const std::string& helper_url,
|
||
|
|
PP_NaClFileInfo file_info,
|
||
|
|
NaClSubprocess* subprocess_to_init,
|
||
|
|
pp::CompletionCallback callback) {
|
||
|
|
CHECK(pp::Module::Get()->core()->IsMainThread());
|
||
|
|
// Do not report UMA stats for translator-related nexes.
|
||
|
|
// TODO(sehr): define new UMA stats for translator related nexe events.
|
||
|
|
SelLdrStartParams params(helper_url,
|
||
|
|
file_info,
|
||
|
|
PP_PNACL_TRANSLATOR_PROCESS_TYPE);
|
||
|
|
ServiceRuntime* service_runtime =
|
||
|
|
new ServiceRuntime(this, pp_instance(),
|
||
|
|
/*main_service_runtime=*/false);
|
||
|
|
|
||
|
|
subprocess_to_init->set_service_runtime(service_runtime);
|
||
|
|
service_runtime->StartSelLdr(params, callback);
|
||
|
|
}
|
||
|
|
|
||
|
|
// All failures of this function will show up as "Missing Plugin-in", so
|
||
|
|
// there is no need to log to JS console that there was an initialization
|
||
|
|
// failure. Note that module loading functions will log their own errors.
|
||
|
|
bool Plugin::Init(uint32_t argc, const char* argn[], const char* argv[]) {
|
||
|
|
nacl::PPBNaClPrivate::InitializePlugin(pp_instance(), argc, argn, argv);
|
||
|
|
pp::CompletionCallback open_cb =
|
||
|
|
callback_factory_.NewCallback(&Plugin::NaClManifestFileDidOpen);
|
||
|
|
nacl::PPBNaClPrivate::RequestNaClManifest(pp_instance(),
|
||
|
|
open_cb.pp_completion_callback());
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
Plugin::Plugin(PP_Instance pp_instance)
|
||
|
|
: pp::Instance(pp_instance), uma_interface_(this) {
|
||
|
|
callback_factory_.Initialize(this);
|
||
|
|
|
||
|
|
// Notify PPBNaClPrivate that the instance is created before altering any
|
||
|
|
// state that it tracks.
|
||
|
|
nacl::PPBNaClPrivate::InstanceCreated(pp_instance);
|
||
|
|
nexe_file_info_ = kInvalidNaClFileInfo;
|
||
|
|
}
|
||
|
|
|
||
|
|
Plugin::~Plugin() {
|
||
|
|
// Destroy the coordinator while the rest of the data is still there
|
||
|
|
pnacl_coordinator_.reset(NULL);
|
||
|
|
|
||
|
|
nacl::PPBNaClPrivate::InstanceDestroyed(pp_instance());
|
||
|
|
|
||
|
|
// ShutDownSubprocesses shuts down the main subprocess, which shuts
|
||
|
|
// down the main ServiceRuntime object, which kills the subprocess.
|
||
|
|
// As a side effect of the subprocess being killed, the reverse
|
||
|
|
// services thread(s) will get EOF on the reverse channel(s), and
|
||
|
|
// the thread(s) will exit. In ServiceRuntime::Shutdown, we invoke
|
||
|
|
// ReverseService::WaitForServiceThreadsToExit(), so that there will
|
||
|
|
// not be an extent thread(s) hanging around. This means that the
|
||
|
|
// ~Plugin will block until this happens. This is a requirement,
|
||
|
|
// since the renderer should be free to unload the plugin code, and
|
||
|
|
// we cannot have threads running code that gets unloaded before
|
||
|
|
// they exit.
|
||
|
|
//
|
||
|
|
// By waiting for the threads here, we also ensure that the Plugin
|
||
|
|
// object and the subprocess and ServiceRuntime objects is not
|
||
|
|
// (fully) destroyed while the threads are running, so resources
|
||
|
|
// that are destroyed after ShutDownSubprocesses (below) are
|
||
|
|
// guaranteed to be live and valid for access from the service
|
||
|
|
// threads.
|
||
|
|
//
|
||
|
|
// The main_subprocess object, which wraps the main service_runtime
|
||
|
|
// object, is dtor'd implicitly after the explicit code below runs,
|
||
|
|
// so the main service runtime object will not have been dtor'd,
|
||
|
|
// though the Shutdown method may have been called, during the
|
||
|
|
// lifetime of the service threads.
|
||
|
|
ShutDownSubprocesses();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Plugin::HandleDocumentLoad(const pp::URLLoader& url_loader) {
|
||
|
|
// We don't know if the plugin will handle the document load, but return
|
||
|
|
// true in order to give it a chance to respond once the proxy is started.
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Plugin::NexeFileDidOpen(int32_t pp_error) {
|
||
|
|
if (pp_error != PP_OK)
|
||
|
|
return;
|
||
|
|
LoadNaClModule(nexe_file_info_, PP_NATIVE_NACL_PROCESS_TYPE);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Plugin::BitcodeDidTranslate(int32_t pp_error) {
|
||
|
|
if (pp_error != PP_OK) {
|
||
|
|
// Error should have been reported by pnacl. Just return.
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Inform JavaScript that we successfully translated the bitcode to a nexe.
|
||
|
|
PP_FileHandle handle = pnacl_coordinator_->TakeTranslatedFileHandle();
|
||
|
|
|
||
|
|
PP_NaClFileInfo info;
|
||
|
|
info.handle = handle;
|
||
|
|
info.token_lo = 0;
|
||
|
|
info.token_hi = 0;
|
||
|
|
LoadNaClModule(info, PP_PNACL_PROCESS_TYPE);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Plugin::NaClManifestFileDidOpen(int32_t pp_error) {
|
||
|
|
if (pp_error != PP_OK)
|
||
|
|
return;
|
||
|
|
|
||
|
|
PP_Var pp_program_url;
|
||
|
|
PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, PP_FALSE, 2};
|
||
|
|
if (nacl::PPBNaClPrivate::GetManifestProgramURL(
|
||
|
|
pp_instance(), &pp_program_url, &pnacl_options)) {
|
||
|
|
std::string program_url = pp::Var(pp::PASS_REF, pp_program_url).AsString();
|
||
|
|
// TODO(teravest): Make ProcessNaClManifest take responsibility for more of
|
||
|
|
// this function.
|
||
|
|
nacl::PPBNaClPrivate::ProcessNaClManifest(pp_instance(),
|
||
|
|
program_url.c_str());
|
||
|
|
if (pnacl_options.translate) {
|
||
|
|
pp::CompletionCallback translate_callback =
|
||
|
|
callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
|
||
|
|
pnacl_coordinator_.reset(
|
||
|
|
PnaclCoordinator::BitcodeToNative(this,
|
||
|
|
program_url,
|
||
|
|
pnacl_options,
|
||
|
|
translate_callback));
|
||
|
|
return;
|
||
|
|
} else {
|
||
|
|
pp::CompletionCallback open_callback =
|
||
|
|
callback_factory_.NewCallback(&Plugin::NexeFileDidOpen);
|
||
|
|
// Will always call the callback on success or failure.
|
||
|
|
nacl::PPBNaClPrivate::DownloadNexe(
|
||
|
|
pp_instance(),
|
||
|
|
program_url.c_str(),
|
||
|
|
&nexe_file_info_,
|
||
|
|
open_callback.pp_completion_callback());
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Plugin::ReportLoadError(const ErrorInfo& error_info) {
|
||
|
|
nacl::PPBNaClPrivate::ReportLoadError(pp_instance(),
|
||
|
|
error_info.error_code(),
|
||
|
|
error_info.message().c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace plugin
|