| // 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 |