[Android] Added UMA for search by image context menu.
[chromium-blink-merge.git] / chrome / renderer / pepper / ppb_nacl_private_impl.cc
blobce95b628647439531600a98a35969db8426fa5f4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/pepper/ppb_nacl_private_impl.h"
7 #ifndef DISABLE_NACL
9 #include "base/command_line.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/rand_util.h"
13 #include "chrome/common/chrome_switches.h"
14 #include "chrome/renderer/chrome_render_process_observer.h"
15 #include "chrome/renderer/pepper/pnacl_translation_resource_host.h"
16 #include "components/nacl/common/nacl_host_messages.h"
17 #include "components/nacl/common/nacl_types.h"
18 #include "content/public/common/content_client.h"
19 #include "content/public/common/content_switches.h"
20 #include "content/public/common/sandbox_init.h"
21 #include "content/public/renderer/pepper_plugin_instance.h"
22 #include "content/public/renderer/renderer_ppapi_host.h"
23 #include "content/public/renderer/render_thread.h"
24 #include "content/public/renderer/render_view.h"
25 #include "ppapi/c/pp_bool.h"
26 #include "ppapi/c/private/pp_file_handle.h"
27 #include "ppapi/native_client/src/trusted/plugin/nacl_entry_points.h"
28 #include "ppapi/shared_impl/ppapi_permissions.h"
29 #include "ppapi/shared_impl/ppapi_preferences.h"
30 #include "ppapi/shared_impl/var.h"
31 #include "ppapi/thunk/enter.h"
32 #include "third_party/WebKit/public/web/WebDocument.h"
33 #include "third_party/WebKit/public/web/WebElement.h"
34 #include "third_party/WebKit/public/web/WebFrame.h"
35 #include "third_party/WebKit/public/web/WebPluginContainer.h"
36 #include "third_party/WebKit/public/web/WebView.h"
38 namespace {
40 base::LazyInstance<scoped_refptr<PnaclTranslationResourceHost> >
41 g_pnacl_resource_host = LAZY_INSTANCE_INITIALIZER;
43 static bool InitializePnaclResourceHost() {
44 // Must run on the main thread.
45 content::RenderThread* render_thread = content::RenderThread::Get();
46 if (!render_thread)
47 return false;
48 if (!g_pnacl_resource_host.Get()) {
49 g_pnacl_resource_host.Get() = new PnaclTranslationResourceHost(
50 render_thread->GetIOMessageLoopProxy());
51 render_thread->AddFilter(g_pnacl_resource_host.Get());
53 return true;
56 struct InstanceInfo {
57 InstanceInfo() : plugin_pid(base::kNullProcessId), plugin_child_id(0) {}
58 GURL url;
59 ppapi::PpapiPermissions permissions;
60 base::ProcessId plugin_pid;
61 int plugin_child_id;
62 IPC::ChannelHandle channel_handle;
65 typedef std::map<PP_Instance, InstanceInfo> InstanceInfoMap;
67 base::LazyInstance<InstanceInfoMap> g_instance_info =
68 LAZY_INSTANCE_INITIALIZER;
70 static int GetRoutingID(PP_Instance instance) {
71 // Check that we are on the main renderer thread.
72 DCHECK(content::RenderThread::Get());
73 content::RendererPpapiHost *host =
74 content::RendererPpapiHost::GetForPPInstance(instance);
75 if (!host)
76 return 0;
77 return host->GetRoutingIDForWidget(instance);
80 // Launch NaCl's sel_ldr process.
81 PP_ExternalPluginResult LaunchSelLdr(PP_Instance instance,
82 const char* alleged_url,
83 PP_Bool uses_irt,
84 PP_Bool uses_ppapi,
85 PP_Bool enable_ppapi_dev,
86 PP_Bool enable_dyncode_syscalls,
87 PP_Bool enable_exception_handling,
88 void* imc_handle,
89 struct PP_Var* error_message) {
90 nacl::FileDescriptor result_socket;
91 IPC::Sender* sender = content::RenderThread::Get();
92 DCHECK(sender);
93 *error_message = PP_MakeUndefined();
94 int routing_id = 0;
95 // If the nexe uses ppapi APIs, we need a routing ID.
96 // To get the routing ID, we must be on the main thread.
97 // Some nexes do not use ppapi and launch from the background thread,
98 // so those nexes can skip finding a routing_id.
99 if (uses_ppapi) {
100 routing_id = GetRoutingID(instance);
101 if (!routing_id)
102 return PP_EXTERNAL_PLUGIN_FAILED;
105 InstanceInfo instance_info;
106 instance_info.url = GURL(alleged_url);
108 uint32_t perm_bits = ppapi::PERMISSION_NONE;
109 // Conditionally block 'Dev' interfaces. We do this for the NaCl process, so
110 // it's clearer to developers when they are using 'Dev' inappropriately. We
111 // must also check on the trusted side of the proxy.
112 if (enable_ppapi_dev)
113 perm_bits |= ppapi::PERMISSION_DEV;
114 instance_info.permissions =
115 ppapi::PpapiPermissions::GetForCommandLine(perm_bits);
116 std::string error_message_string;
117 nacl::NaClLaunchResult launch_result;
119 if (!sender->Send(new NaClHostMsg_LaunchNaCl(
120 nacl::NaClLaunchParams(instance_info.url.spec(),
121 routing_id,
122 perm_bits,
123 PP_ToBool(uses_irt),
124 PP_ToBool(enable_dyncode_syscalls),
125 PP_ToBool(enable_exception_handling)),
126 &launch_result,
127 &error_message_string))) {
128 return PP_EXTERNAL_PLUGIN_FAILED;
130 if (!error_message_string.empty()) {
131 *error_message = ppapi::StringVar::StringToPPVar(error_message_string);
132 return PP_EXTERNAL_PLUGIN_FAILED;
134 result_socket = launch_result.imc_channel_handle;
135 instance_info.channel_handle = launch_result.ipc_channel_handle;
136 instance_info.plugin_pid = launch_result.plugin_pid;
137 instance_info.plugin_child_id = launch_result.plugin_child_id;
138 // Don't save instance_info if channel handle is invalid.
139 bool invalid_handle = instance_info.channel_handle.name.empty();
140 #if defined(OS_POSIX)
141 if (!invalid_handle)
142 invalid_handle = (instance_info.channel_handle.socket.fd == -1);
143 #endif
144 if (!invalid_handle)
145 g_instance_info.Get()[instance] = instance_info;
147 *(static_cast<NaClHandle*>(imc_handle)) =
148 nacl::ToNativeHandle(result_socket);
150 return PP_EXTERNAL_PLUGIN_OK;
153 PP_ExternalPluginResult StartPpapiProxy(PP_Instance instance) {
154 InstanceInfoMap& map = g_instance_info.Get();
155 InstanceInfoMap::iterator it = map.find(instance);
156 if (it == map.end()) {
157 DLOG(ERROR) << "Could not find instance ID";
158 return PP_EXTERNAL_PLUGIN_FAILED;
160 InstanceInfo instance_info = it->second;
161 map.erase(it);
163 content::PepperPluginInstance* plugin_instance =
164 content::PepperPluginInstance::Get(instance);
165 if (!plugin_instance) {
166 DLOG(ERROR) << "GetInstance() failed";
167 return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
170 return plugin_instance->SwitchToOutOfProcessProxy(
171 base::FilePath().AppendASCII(instance_info.url.spec()),
172 instance_info.permissions,
173 instance_info.channel_handle,
174 instance_info.plugin_pid,
175 instance_info.plugin_child_id);
178 int UrandomFD(void) {
179 #if defined(OS_POSIX)
180 return base::GetUrandomFD();
181 #else
182 return -1;
183 #endif
186 PP_Bool Are3DInterfacesDisabled() {
187 return PP_FromBool(CommandLine::ForCurrentProcess()->HasSwitch(
188 switches::kDisable3DAPIs));
191 int32_t BrokerDuplicateHandle(PP_FileHandle source_handle,
192 uint32_t process_id,
193 PP_FileHandle* target_handle,
194 uint32_t desired_access,
195 uint32_t options) {
196 #if defined(OS_WIN)
197 return content::BrokerDuplicateHandle(source_handle, process_id,
198 target_handle, desired_access,
199 options);
200 #else
201 return 0;
202 #endif
205 int32_t EnsurePnaclInstalled(PP_Instance instance,
206 PP_CompletionCallback callback) {
207 ppapi::thunk::EnterInstance enter(instance, callback);
208 if (enter.failed())
209 return enter.retval();
210 if (!InitializePnaclResourceHost())
211 return enter.SetResult(PP_ERROR_FAILED);
212 g_pnacl_resource_host.Get()->EnsurePnaclInstalled(
213 instance,
214 enter.callback());
215 return enter.SetResult(PP_OK_COMPLETIONPENDING);
218 PP_FileHandle GetReadonlyPnaclFD(const char* filename) {
219 IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
220 IPC::Sender* sender = content::RenderThread::Get();
221 DCHECK(sender);
222 if (!sender->Send(new NaClHostMsg_GetReadonlyPnaclFD(
223 std::string(filename),
224 &out_fd))) {
225 return base::kInvalidPlatformFileValue;
227 if (out_fd == IPC::InvalidPlatformFileForTransit()) {
228 return base::kInvalidPlatformFileValue;
230 base::PlatformFile handle =
231 IPC::PlatformFileForTransitToPlatformFile(out_fd);
232 return handle;
235 PP_FileHandle CreateTemporaryFile(PP_Instance instance) {
236 IPC::PlatformFileForTransit transit_fd = IPC::InvalidPlatformFileForTransit();
237 IPC::Sender* sender = content::RenderThread::Get();
238 DCHECK(sender);
239 if (!sender->Send(new NaClHostMsg_NaClCreateTemporaryFile(
240 &transit_fd))) {
241 return base::kInvalidPlatformFileValue;
244 if (transit_fd == IPC::InvalidPlatformFileForTransit()) {
245 return base::kInvalidPlatformFileValue;
248 base::PlatformFile handle = IPC::PlatformFileForTransitToPlatformFile(
249 transit_fd);
250 return handle;
253 int32_t GetNexeFd(PP_Instance instance,
254 const char* pexe_url,
255 uint32_t abi_version,
256 uint32_t opt_level,
257 const char* last_modified,
258 const char* etag,
259 PP_Bool* is_hit,
260 PP_FileHandle* handle,
261 struct PP_CompletionCallback callback) {
262 ppapi::thunk::EnterInstance enter(instance, callback);
263 if (enter.failed())
264 return enter.retval();
265 if (!pexe_url || !last_modified || !etag || !is_hit || !handle)
266 return enter.SetResult(PP_ERROR_BADARGUMENT);
267 if (!InitializePnaclResourceHost())
268 return enter.SetResult(PP_ERROR_FAILED);
270 base::Time last_modified_time;
271 // If FromString fails, it doesn't touch last_modified_time and we just send
272 // the default-constructed null value.
273 base::Time::FromString(last_modified, &last_modified_time);
275 nacl::PnaclCacheInfo cache_info;
276 cache_info.pexe_url = GURL(pexe_url);
277 cache_info.abi_version = abi_version;
278 cache_info.opt_level = opt_level;
279 cache_info.last_modified = last_modified_time;
280 cache_info.etag = std::string(etag);
282 g_pnacl_resource_host.Get()->RequestNexeFd(
283 GetRoutingID(instance),
284 instance,
285 cache_info,
286 is_hit,
287 handle,
288 enter.callback());
290 return enter.SetResult(PP_OK_COMPLETIONPENDING);
293 void ReportTranslationFinished(PP_Instance instance, PP_Bool success) {
294 // If the resource host isn't initialized, don't try to do that here.
295 // Just return because something is already very wrong.
296 if (g_pnacl_resource_host.Get() == NULL)
297 return;
298 g_pnacl_resource_host.Get()->ReportTranslationFinished(instance, success);
301 PP_Bool IsOffTheRecord() {
302 return PP_FromBool(ChromeRenderProcessObserver::is_incognito_process());
305 PP_Bool IsPnaclEnabled() {
306 return PP_FromBool(
307 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisablePnacl));
310 PP_ExternalPluginResult ReportNaClError(PP_Instance instance,
311 PP_NaClError error_id) {
312 IPC::Sender* sender = content::RenderThread::Get();
314 if (!sender->Send(
315 new NaClHostMsg_NaClErrorStatus(
316 // TODO(dschuff): does this enum need to be sent as an int,
317 // or is it safe to include the appropriate headers in
318 // render_messages.h?
319 GetRoutingID(instance), static_cast<int>(error_id)))) {
320 return PP_EXTERNAL_PLUGIN_FAILED;
322 return PP_EXTERNAL_PLUGIN_OK;
325 PP_FileHandle OpenNaClExecutable(PP_Instance instance,
326 const char* file_url,
327 uint64_t* nonce_lo,
328 uint64_t* nonce_hi) {
329 IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
330 IPC::Sender* sender = content::RenderThread::Get();
331 DCHECK(sender);
332 *nonce_lo = 0;
333 *nonce_hi = 0;
334 base::FilePath file_path;
335 if (!sender->Send(
336 new NaClHostMsg_OpenNaClExecutable(GetRoutingID(instance),
337 GURL(file_url),
338 &out_fd,
339 nonce_lo,
340 nonce_hi))) {
341 return base::kInvalidPlatformFileValue;
344 if (out_fd == IPC::InvalidPlatformFileForTransit()) {
345 return base::kInvalidPlatformFileValue;
348 base::PlatformFile handle =
349 IPC::PlatformFileForTransitToPlatformFile(out_fd);
350 return handle;
353 const PPB_NaCl_Private nacl_interface = {
354 &LaunchSelLdr,
355 &StartPpapiProxy,
356 &UrandomFD,
357 &Are3DInterfacesDisabled,
358 &BrokerDuplicateHandle,
359 &EnsurePnaclInstalled,
360 &GetReadonlyPnaclFD,
361 &CreateTemporaryFile,
362 &GetNexeFd,
363 &ReportTranslationFinished,
364 &IsOffTheRecord,
365 &IsPnaclEnabled,
366 &ReportNaClError,
367 &OpenNaClExecutable
370 } // namespace
372 const PPB_NaCl_Private* PPB_NaCl_Private_Impl::GetInterface() {
373 return &nacl_interface;
376 #endif // DISABLE_NACL