OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/nacl/renderer/nexe_load_manager.h" | 5 #include "components/nacl/renderer/nexe_load_manager.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/string_tokenizer.h" | 10 #include "base/strings/string_tokenizer.h" |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 | 82 |
83 NexeLoadManager::NexeLoadManager( | 83 NexeLoadManager::NexeLoadManager( |
84 PP_Instance pp_instance) | 84 PP_Instance pp_instance) |
85 : pp_instance_(pp_instance), | 85 : pp_instance_(pp_instance), |
86 nacl_ready_state_(PP_NACL_READY_STATE_UNSENT), | 86 nacl_ready_state_(PP_NACL_READY_STATE_UNSENT), |
87 nexe_error_reported_(false), | 87 nexe_error_reported_(false), |
88 is_installed_(false), | 88 is_installed_(false), |
89 exit_status_(-1), | 89 exit_status_(-1), |
90 nexe_size_(0), | 90 nexe_size_(0), |
91 plugin_instance_(content::PepperPluginInstance::Get(pp_instance)), | 91 plugin_instance_(content::PepperPluginInstance::Get(pp_instance)), |
| 92 crash_info_shmem_handle_(base::SharedMemory::NULLHandle()), |
92 weak_factory_(this) { | 93 weak_factory_(this) { |
93 SetLastError(""); | 94 SetLastError(""); |
94 HistogramEnumerateOsArch(GetSandboxArch()); | 95 HistogramEnumerateOsArch(GetSandboxArch()); |
95 if (plugin_instance_) { | 96 if (plugin_instance_) { |
96 plugin_base_url_ = | 97 plugin_base_url_ = |
97 plugin_instance_->GetContainer()->element().document().url(); | 98 plugin_instance_->GetContainer()->element().document().url(); |
98 } | 99 } |
99 } | 100 } |
100 | 101 |
101 NexeLoadManager::~NexeLoadManager() { | 102 NexeLoadManager::~NexeLoadManager() { |
102 if (!nexe_error_reported_) { | 103 if (!nexe_error_reported_) { |
103 base::TimeDelta uptime = base::Time::Now() - ready_time_; | 104 base::TimeDelta uptime = base::Time::Now() - ready_time_; |
104 HistogramTimeLarge("NaCl.ModuleUptime.Normal", uptime.InMilliseconds()); | 105 HistogramTimeLarge("NaCl.ModuleUptime.Normal", uptime.InMilliseconds()); |
105 } | 106 } |
| 107 if (base::SharedMemory::IsHandleValid(crash_info_shmem_handle_)) |
| 108 base::SharedMemory::CloseHandle(crash_info_shmem_handle_); |
106 } | 109 } |
107 | 110 |
108 void NexeLoadManager::NexeFileDidOpen(int32_t pp_error, | 111 void NexeLoadManager::NexeFileDidOpen(int32_t pp_error, |
109 const base::File& file, | 112 const base::File& file, |
110 int32_t http_status, | 113 int32_t http_status, |
111 int64_t nexe_bytes_read, | 114 int64_t nexe_bytes_read, |
112 const std::string& url, | 115 const std::string& url, |
113 base::TimeDelta time_since_open) { | 116 base::TimeDelta time_since_open) { |
114 // Check that we are on the main renderer thread. | 117 // Check that we are on the main renderer thread. |
115 DCHECK(content::RenderThread::Get()); | 118 DCHECK(content::RenderThread::Get()); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 SetLastError(error_string); | 227 SetLastError(error_string); |
225 | 228 |
226 // Inform JavaScript that loading was aborted and is complete. | 229 // Inform JavaScript that loading was aborted and is complete. |
227 DispatchProgressEvent(pp_instance_, ProgressEvent(PP_NACL_EVENT_ABORT)); | 230 DispatchProgressEvent(pp_instance_, ProgressEvent(PP_NACL_EVENT_ABORT)); |
228 DispatchProgressEvent(pp_instance_, ProgressEvent(PP_NACL_EVENT_LOADEND)); | 231 DispatchProgressEvent(pp_instance_, ProgressEvent(PP_NACL_EVENT_LOADEND)); |
229 | 232 |
230 HistogramEnumerateLoadStatus(PP_NACL_ERROR_LOAD_ABORTED, is_installed_); | 233 HistogramEnumerateLoadStatus(PP_NACL_ERROR_LOAD_ABORTED, is_installed_); |
231 LogToConsole(error_string); | 234 LogToConsole(error_string); |
232 } | 235 } |
233 | 236 |
234 void NexeLoadManager::NexeDidCrash(const char* crash_log) { | 237 void NexeLoadManager::NexeDidCrash() { |
235 VLOG(1) << "Plugin::NexeDidCrash: crash event!"; | 238 VLOG(1) << "Plugin::NexeDidCrash: crash event!"; |
236 // The NaCl module voluntarily exited. However, this is still a | 239 // The NaCl module voluntarily exited. However, this is still a |
237 // crash from the point of view of Pepper, since PPAPI plugins are | 240 // crash from the point of view of Pepper, since PPAPI plugins are |
238 // event handlers and should never exit. | 241 // event handlers and should never exit. |
239 VLOG_IF(1, exit_status_ != -1) | 242 VLOG_IF(1, exit_status_ != -1) |
240 << "Plugin::NexeDidCrash: nexe exited with status " << exit_status_ | 243 << "Plugin::NexeDidCrash: nexe exited with status " << exit_status_ |
241 << " so this is a \"controlled crash\"."; | 244 << " so this is a \"controlled crash\"."; |
242 // If the crash occurs during load, we just want to report an error | 245 // If the crash occurs during load, we just want to report an error |
243 // that fits into our load progress event grammar. If the crash | 246 // that fits into our load progress event grammar. If the crash |
244 // occurs after loaded/loadend, then we use ReportDeadNexe to send a | 247 // occurs after loaded/loadend, then we use ReportDeadNexe to send a |
245 // "crash" event. | 248 // "crash" event. |
246 if (nexe_error_reported_) { | 249 if (nexe_error_reported_) { |
247 VLOG(1) << "Plugin::NexeDidCrash: error already reported; suppressing"; | 250 VLOG(1) << "Plugin::NexeDidCrash: error already reported; suppressing"; |
248 } else { | 251 } else { |
249 if (nacl_ready_state_ == PP_NACL_READY_STATE_DONE) { | 252 if (nacl_ready_state_ == PP_NACL_READY_STATE_DONE) { |
250 ReportDeadNexe(); | 253 ReportDeadNexe(); |
251 } else { | 254 } else { |
252 ReportLoadError(PP_NACL_ERROR_START_PROXY_CRASH, | 255 ReportLoadError(PP_NACL_ERROR_START_PROXY_CRASH, |
253 "Nexe crashed during startup"); | 256 "Nexe crashed during startup"); |
254 } | 257 } |
255 } | 258 } |
256 // In all cases, try to grab the crash log. The first error | 259 // In all cases, try to grab the crash log. The first error |
257 // reported may have come from the start_module RPC reply indicating | 260 // reported may have come from the start_module RPC reply indicating |
258 // a validation error or something similar, which wouldn't grab the | 261 // a validation error or something similar, which wouldn't grab the |
259 // crash log. In the event that this is called twice, the second | 262 // crash log. In the event that this is called twice, the second |
260 // invocation will just be a no-op, since the entire crash log will | 263 // invocation will just be a no-op, since the entire crash log will |
261 // have been received and we'll just get an EOF indication. | 264 // have been received and we'll just get an EOF indication. |
262 CopyCrashLogToJsConsole(crash_log); | 265 |
| 266 base::SharedMemory shmem(crash_info_shmem_handle_, true); |
| 267 if (shmem.Map(kNaClCrashInfoShmemSize)) { |
| 268 uint32_t crash_log_length; |
| 269 // We cast the length value to volatile here to prevent the compiler from |
| 270 // reordering instructions in a way that could introduce a TOCTTOU race. |
| 271 crash_log_length = *(static_cast<volatile uint32_t*>(shmem.memory())); |
| 272 crash_log_length = std::min<uint32_t>(crash_log_length, |
| 273 kNaClCrashInfoMaxLogSize); |
| 274 |
| 275 scoped_ptr<char[]> crash_log_data(new char[kNaClCrashInfoShmemSize]); |
| 276 memcpy(crash_log_data.get(), |
| 277 static_cast<char*>(shmem.memory()) + sizeof(uint32_t), |
| 278 crash_log_length); |
| 279 std::string crash_log(crash_log_data.get(), crash_log_length); |
| 280 CopyCrashLogToJsConsole(crash_log); |
| 281 } |
263 } | 282 } |
264 | 283 |
265 void NexeLoadManager::set_trusted_plugin_channel( | 284 void NexeLoadManager::set_trusted_plugin_channel( |
266 scoped_ptr<TrustedPluginChannel> channel) { | 285 scoped_ptr<TrustedPluginChannel> channel) { |
267 trusted_plugin_channel_ = channel.Pass(); | 286 trusted_plugin_channel_ = channel.Pass(); |
268 } | 287 } |
269 | 288 |
270 void NexeLoadManager::set_manifest_service_channel( | 289 void NexeLoadManager::set_manifest_service_channel( |
271 scoped_ptr<ManifestServiceChannel> channel) { | 290 scoped_ptr<ManifestServiceChannel> channel) { |
272 manifest_service_channel_ = channel.Pass(); | 291 manifest_service_channel_ = channel.Pass(); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 // to provide error handling. | 436 // to provide error handling. |
418 } | 437 } |
419 | 438 |
420 void NexeLoadManager::CopyCrashLogToJsConsole(const std::string& crash_log) { | 439 void NexeLoadManager::CopyCrashLogToJsConsole(const std::string& crash_log) { |
421 base::StringTokenizer t(crash_log, "\n"); | 440 base::StringTokenizer t(crash_log, "\n"); |
422 while (t.GetNext()) | 441 while (t.GetNext()) |
423 LogToConsole(t.token()); | 442 LogToConsole(t.token()); |
424 } | 443 } |
425 | 444 |
426 } // namespace nacl | 445 } // namespace nacl |
OLD | NEW |