blob: 7e24e303b2e3a32948e784ccc8b1fb9dbca7794d [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "native_client/src/shared/ppapi_proxy/browser_ppp.h"
#include <string.h>
#include "native_client/src/include/nacl_scoped_ptr.h"
#include "native_client/src/include/portability.h"
#include "native_client/src/include/portability_process.h"
#include "native_client/src/shared/ppapi_proxy/browser_globals.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_find.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_input_event.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_instance.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_mouse_lock.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_messaging.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_printing.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_selection.h"
#include "native_client/src/shared/ppapi_proxy/browser_ppp_zoom.h"
#include "native_client/src/shared/ppapi_proxy/browser_upcall.h"
#include "native_client/src/shared/ppapi_proxy/trusted/srpcgen/ppb_rpc.h"
#include "native_client/src/shared/ppapi_proxy/trusted/srpcgen/ppp_rpc.h"
#include "native_client/src/shared/ppapi_proxy/utility.h"
#include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
#include "native_client/src/trusted/plugin/plugin.h"
#include "ppapi/c/dev/ppp_find_dev.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/dev/ppp_selection_dev.h"
#include "ppapi/c/dev/ppp_zoom_dev.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_input_event.h"
#include "ppapi/c/ppp_mouse_lock.h"
#include "ppapi/c/private/ppb_nacl_private.h"
namespace ppapi_proxy {
//
// The following methods are the SRPC dispatchers for ppapi/c/ppp.h.
//
namespace {
// PPB_GetInterface must only be called on the main thread. So as we are adding
// off-the-main-thread support for various interfaces, we need to ensure that
// their pointers are available on upcall thread of the the trusted proxy.
void PPBGetInterfaces() {
PPBCoreInterface();
// TODO(all): add more interfaces here once available off the main thread.
}
} // namespace
int32_t BrowserPpp::InitializeModule(PP_Module module_id,
PPB_GetInterface get_browser_interface) {
DebugPrintf("PPP_InitializeModule: module=%"NACL_PRId32"\n", module_id);
// Ask the browser for an interface which provides missing functions
const PPB_NaCl_Private* ppb_nacl = reinterpret_cast<const PPB_NaCl_Private*>(
get_browser_interface(PPB_NACL_PRIVATE_INTERFACE));
if (ppb_nacl == NULL) {
DebugPrintf("PPP_InitializeModule: NaCl private interface missing!\n");
return PP_ERROR_FAILED;
}
SetPPBGetInterface(get_browser_interface,
plugin_->enable_dev_interfaces(),
!ppb_nacl->Are3DInterfacesDisabled());
PPBGetInterfaces();
SetBrowserPppForInstance(plugin_->pp_instance(), this);
CHECK(main_channel_ != NULL);
nacl::scoped_ptr<nacl::DescWrapper> wrapper(
BrowserUpcall::Start(&upcall_thread_, main_channel_));
if (wrapper.get() == NULL)
return PP_ERROR_FAILED;
// Set up the callbacks allowed on the main channel.
NaClSrpcService* service = reinterpret_cast<NaClSrpcService*>(
calloc(1, sizeof(*service)));
if (NULL == service) {
DebugPrintf("PPP_InitializeModule: "
"could not create callback services.\n");
return PP_ERROR_FAILED;
}
if (!NaClSrpcServiceHandlerCtor(service, PpbRpcs::srpc_methods)) {
DebugPrintf("PPP_InitializeModule: "
"could not construct callback services.\n");
free(service);
return PP_ERROR_FAILED;
}
// Export the service on the channel.
main_channel_->server = service;
char* service_string = const_cast<char*>(service->service_string);
SetModuleIdForSrpcChannel(main_channel_, module_id);
SetInstanceIdForSrpcChannel(main_channel_, plugin_->pp_instance());
// Do the RPC.
int32_t pp_error;
NaClSrpcError srpc_result =
PppRpcClient::PPP_InitializeModule(main_channel_,
module_id,
wrapper->desc(),
service_string,
&pp_error);
DebugPrintf("PPP_InitializeModule: %s\n", NaClSrpcErrorString(srpc_result));
is_nexe_alive_ = (srpc_result != NACL_SRPC_RESULT_INTERNAL);
if (srpc_result != NACL_SRPC_RESULT_OK)
return PP_ERROR_FAILED;
DebugPrintf("PPP_InitializeModule: pp_error=%"NACL_PRId32"\n", pp_error);
if (pp_error != PP_OK)
return pp_error;
const void* ppp_instance = GetPluginInterface(PPP_INSTANCE_INTERFACE);
DebugPrintf("PPP_InitializeModule: ppp_instance=%p\n", ppp_instance);
ppp_instance_interface_ = reinterpret_cast<const PPP_Instance*>(ppp_instance);
if (ppp_instance_interface_ == NULL) // PPP_Instance is required.
return PP_ERROR_NOINTERFACE;
// PPB_Messaging and PPP_InputEvent are optional, so it's OK for them to
// return NULL.
ppp_messaging_interface_ = reinterpret_cast<const PPP_Messaging*>(
GetPluginInterface(PPP_MESSAGING_INTERFACE));
ppp_input_event_interface_ = reinterpret_cast<const PPP_InputEvent*>(
GetPluginInterface(PPP_INPUT_EVENT_INTERFACE));
if (!is_valid()) // Nexe died in PPP_GetInterface.
return PP_ERROR_FAILED;
return PP_OK;
}
void BrowserPpp::ShutdownModule() {
DebugPrintf("PPP_Shutdown: main_channel=%p\n",
static_cast<void*>(main_channel_));
if (main_channel_ == NULL) {
CHECK(!is_nexe_alive_);
return; // The proxy has already been shut down.
}
if (is_nexe_alive_) {
NaClSrpcError srpc_result =
PppRpcClient::PPP_ShutdownModule(main_channel_);
DebugPrintf("PPP_ShutdownModule: %s\n", NaClSrpcErrorString(srpc_result));
}
NaClThreadJoin(&upcall_thread_);
UnsetBrowserPppForInstance(plugin_->pp_instance());
UnsetModuleIdForSrpcChannel(main_channel_);
UnsetInstanceIdForSrpcChannel(main_channel_);
main_channel_ = NULL;
is_nexe_alive_ = false;
DebugPrintf("PPP_Shutdown: main_channel=NULL\n");
}
const void* BrowserPpp::GetPluginInterface(const char* interface_name) {
DebugPrintf("PPP_GetInterface('%s')\n", interface_name);
if (!is_valid())
return NULL;
int32_t exports_interface_name;
NaClSrpcError srpc_result =
PppRpcClient::PPP_GetInterface(main_channel_,
const_cast<char*>(interface_name),
&exports_interface_name);
DebugPrintf("PPP_GetInterface('%s'): %s\n",
interface_name, NaClSrpcErrorString(srpc_result));
is_nexe_alive_ = (srpc_result != NACL_SRPC_RESULT_INTERNAL);
// Special case PPP_Instance versioning. The plugin side of the proxy
// converts Instance 1.1 to Instance 1.0 as needed, so we want to say here
// in the browser side that any time either 1.0 or 1.1 is supported, that
// we'll support 1.1.
if (srpc_result == NACL_SRPC_RESULT_OK && !exports_interface_name &&
strcmp(interface_name, PPP_INSTANCE_INTERFACE_1_1) == 0) {
srpc_result =
PppRpcClient::PPP_GetInterface(main_channel_,
const_cast<char *>(PPP_INSTANCE_INTERFACE_1_0),
&exports_interface_name);
}
const void* ppp_interface = NULL;
if (srpc_result != NACL_SRPC_RESULT_OK || !exports_interface_name) {
ppp_interface = NULL;
} else if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserInstance::GetInterface());
} else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserMessaging::GetInterface());
} else if (strcmp(interface_name, PPP_MOUSELOCK_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserMouseLock::GetInterface());
} else if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserInputEvent::GetInterface());
} else if (strcmp(interface_name, PPP_FIND_DEV_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserFind::GetInterface());
} else if (strcmp(interface_name, PPP_PRINTING_DEV_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserPrinting::GetInterface());
} else if (strcmp(interface_name, PPP_SELECTION_DEV_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserSelection::GetInterface());
} else if (strcmp(interface_name, PPP_ZOOM_DEV_INTERFACE) == 0) {
ppp_interface =
reinterpret_cast<const void*>(BrowserZoom::GetInterface());
}
// TODO(sehr): other interfaces go here.
DebugPrintf("PPP_GetInterface('%s'): %p\n", interface_name, ppp_interface);
return ppp_interface;
}
const void* BrowserPpp::GetPluginInterfaceSafe(const char* interface_name) {
const void* ppp_interface = GetPluginInterface(interface_name);
if (ppp_interface == NULL)
DebugPrintf("PPB_GetInterface: %s not found\n", interface_name);
CHECK(ppp_interface != NULL);
return ppp_interface;
}
} // namespace ppapi_proxy