Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #define NACL_LOG_MODULE_NAME "Plugin::ServiceRuntime" | 7 #define NACL_LOG_MODULE_NAME "Plugin::ServiceRuntime" |
| 8 | 8 |
| 9 #include "native_client/src/trusted/plugin/service_runtime.h" | 9 #include "native_client/src/trusted/plugin/service_runtime.h" |
| 10 | 10 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 // PostMessage method, so this undef must appear before any of those. | 39 // PostMessage method, so this undef must appear before any of those. |
| 40 #ifdef PostMessage | 40 #ifdef PostMessage |
| 41 #undef PostMessage | 41 #undef PostMessage |
| 42 #endif | 42 #endif |
| 43 #include "native_client/src/trusted/plugin/plugin.h" | 43 #include "native_client/src/trusted/plugin/plugin.h" |
| 44 #include "native_client/src/trusted/plugin/plugin_error.h" | 44 #include "native_client/src/trusted/plugin/plugin_error.h" |
| 45 #include "native_client/src/trusted/plugin/pnacl_coordinator.h" | 45 #include "native_client/src/trusted/plugin/pnacl_coordinator.h" |
| 46 #include "native_client/src/trusted/plugin/pnacl_resources.h" | 46 #include "native_client/src/trusted/plugin/pnacl_resources.h" |
| 47 #include "native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h" | 47 #include "native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h" |
| 48 #include "native_client/src/trusted/plugin/srpc_client.h" | 48 #include "native_client/src/trusted/plugin/srpc_client.h" |
| 49 | |
| 50 #include "native_client/src/trusted/weak_ref/call_on_main_thread.h" | |
| 51 | |
| 52 #include "native_client/src/trusted/service_runtime/nacl_error_code.h" | 49 #include "native_client/src/trusted/service_runtime/nacl_error_code.h" |
| 53 #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h" | 50 #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h" |
| 51 #include "native_client/src/trusted/validator/nacl_file_info.h" | |
| 52 #include "native_client/src/trusted/weak_ref/call_on_main_thread.h" | |
| 54 | 53 |
| 55 #include "ppapi/c/pp_errors.h" | 54 #include "ppapi/c/pp_errors.h" |
| 56 #include "ppapi/c/trusted/ppb_file_io_trusted.h" | 55 #include "ppapi/c/trusted/ppb_file_io_trusted.h" |
| 57 #include "ppapi/cpp/core.h" | 56 #include "ppapi/cpp/core.h" |
| 58 #include "ppapi/cpp/completion_callback.h" | 57 #include "ppapi/cpp/completion_callback.h" |
| 59 #include "ppapi/cpp/file_io.h" | 58 #include "ppapi/cpp/file_io.h" |
| 60 | 59 |
| 61 namespace { | 60 namespace { |
| 62 | 61 |
| 63 // For doing crude quota enforcement on writes to temp files. | 62 // For doing crude quota enforcement on writes to temp files. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 return false; | 164 return false; |
| 166 } | 165 } |
| 167 | 166 |
| 168 return true; | 167 return true; |
| 169 } | 168 } |
| 170 | 169 |
| 171 // TODO(bsy): OpenManifestEntry should use the manifest to ResolveKey | 170 // TODO(bsy): OpenManifestEntry should use the manifest to ResolveKey |
| 172 // and invoke StreamAsFile with a completion callback that invokes | 171 // and invoke StreamAsFile with a completion callback that invokes |
| 173 // GetPOSIXFileDesc. | 172 // GetPOSIXFileDesc. |
| 174 bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key, | 173 bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key, |
| 175 int32_t* out_desc) { | 174 struct NaClFileInfo *info) { |
|
Mark Seaborn
2013/05/24 20:21:58
Fix "*" spacing style
Nick Bray (chromium)
2013/05/24 21:35:24
Done.
| |
| 176 ErrorInfo error_info; | 175 ErrorInfo error_info; |
| 177 bool op_complete = false; // NB: mu_ and cv_ also controls access to this! | 176 bool op_complete = false; // NB: mu_ and cv_ also controls access to this! |
| 177 // The to_open object is owned by the weak ref callback. Because this function | |
| 178 // waits for the callback to finish, the to_open object will be deallocated on | |
| 179 // the main thread before this function can return. The pointers it contains | |
| 180 // to stack variables will not leak. | |
| 178 OpenManifestEntryResource* to_open = | 181 OpenManifestEntryResource* to_open = |
| 179 new OpenManifestEntryResource(url_key, out_desc, | 182 new OpenManifestEntryResource(url_key, info, |
| 180 &error_info, &op_complete); | 183 &error_info, &op_complete); |
| 181 CHECK(to_open != NULL); | 184 CHECK(to_open != NULL); |
| 182 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n", | 185 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n", |
| 183 url_key.c_str()); | 186 url_key.c_str()); |
| 184 // This assumes we are not on the main thread. If false, we deadlock. | 187 // This assumes we are not on the main thread. If false, we deadlock. |
| 185 plugin::WeakRefCallOnMainThread( | 188 plugin::WeakRefCallOnMainThread( |
| 186 anchor_, | 189 anchor_, |
| 187 0, | 190 0, |
| 188 this, | 191 this, |
| 189 &plugin::PluginReverseInterface::OpenManifestEntry_MainThreadContinuation, | 192 &plugin::PluginReverseInterface::OpenManifestEntry_MainThreadContinuation, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 221 // The caller is responsible for not closing *out_desc. If it is | 224 // The caller is responsible for not closing *out_desc. If it is |
| 222 // closed prematurely, then another open could re-use the OS | 225 // closed prematurely, then another open could re-use the OS |
| 223 // descriptor, confusing the opened_ map. If the caller is going to | 226 // descriptor, confusing the opened_ map. If the caller is going to |
| 224 // want to make a NaClDesc object and transfer it etc., then the | 227 // want to make a NaClDesc object and transfer it etc., then the |
| 225 // caller should DUP the descriptor (but remember the original | 228 // caller should DUP the descriptor (but remember the original |
| 226 // value) for use by the NaClDesc object, which closes when the | 229 // value) for use by the NaClDesc object, which closes when the |
| 227 // object is destroyed. | 230 // object is destroyed. |
| 228 NaClLog(4, | 231 NaClLog(4, |
| 229 "PluginReverseInterface::OpenManifestEntry:" | 232 "PluginReverseInterface::OpenManifestEntry:" |
| 230 " *out_desc = %d\n", | 233 " *out_desc = %d\n", |
| 231 *out_desc); | 234 info->desc); |
| 232 if (*out_desc == -1) { | 235 if (info->desc == -1) { |
| 233 // TODO(bsy,ncbray): what else should we do with the error? This | 236 // TODO(bsy,ncbray): what else should we do with the error? This |
| 234 // is a runtime error that may simply be a programming error in | 237 // is a runtime error that may simply be a programming error in |
| 235 // the untrusted code, or it may be something else wrong w/ the | 238 // the untrusted code, or it may be something else wrong w/ the |
| 236 // manifest. | 239 // manifest. |
| 237 NaClLog(4, | 240 NaClLog(4, |
| 238 "OpenManifestEntry: failed for key %s, code %d (%s)\n", | 241 "OpenManifestEntry: failed for key %s, code %d (%s)\n", |
| 239 url_key.c_str(), | 242 url_key.c_str(), |
| 240 error_info.error_code(), | 243 error_info.error_code(), |
| 241 error_info.message().c_str()); | 244 error_info.message().c_str()); |
| 242 } | 245 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 260 | 263 |
| 261 std::string mapped_url; | 264 std::string mapped_url; |
| 262 PnaclOptions pnacl_options; | 265 PnaclOptions pnacl_options; |
| 263 if (!manifest_->ResolveKey(p->url, &mapped_url, | 266 if (!manifest_->ResolveKey(p->url, &mapped_url, |
| 264 &pnacl_options, p->error_info)) { | 267 &pnacl_options, p->error_info)) { |
| 265 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: ResolveKey failed\n"); | 268 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: ResolveKey failed\n"); |
| 266 // Failed, and error_info has the details on what happened. Wake | 269 // Failed, and error_info has the details on what happened. Wake |
| 267 // up requesting thread -- we are done. | 270 // up requesting thread -- we are done. |
| 268 nacl::MutexLocker take(&mu_); | 271 nacl::MutexLocker take(&mu_); |
| 269 *p->op_complete_ptr = true; // done... | 272 *p->op_complete_ptr = true; // done... |
| 270 *p->out_desc = -1; // but failed. | 273 p->file_info->desc = -1; // but failed. |
| 271 NaClXCondVarBroadcast(&cv_); | 274 NaClXCondVarBroadcast(&cv_); |
| 272 return; | 275 return; |
| 273 } | 276 } |
| 274 NaClLog(4, | 277 NaClLog(4, |
| 275 "OpenManifestEntry_MainThreadContinuation: " | 278 "OpenManifestEntry_MainThreadContinuation: " |
| 276 "ResolveKey: %s -> %s (pnacl_translate(%d))\n", | 279 "ResolveKey: %s -> %s (pnacl_translate(%d))\n", |
| 277 p->url.c_str(), mapped_url.c_str(), pnacl_options.translate()); | 280 p->url.c_str(), mapped_url.c_str(), pnacl_options.translate()); |
| 278 | 281 |
| 279 open_cont = new OpenManifestEntryResource(*p); // copy ctor! | 282 open_cont = new OpenManifestEntryResource(*p); // copy ctor! |
| 280 CHECK(open_cont != NULL); | 283 CHECK(open_cont != NULL); |
| 281 open_cont->url = mapped_url; | 284 open_cont->url = mapped_url; |
| 282 if (!pnacl_options.translate()) { | 285 if (!pnacl_options.translate()) { |
| 283 pp::CompletionCallback stream_cc = WeakRefNewCallback( | 286 pp::CompletionCallback stream_cc = WeakRefNewCallback( |
| 284 anchor_, | 287 anchor_, |
| 285 this, | 288 this, |
| 286 &PluginReverseInterface::StreamAsFile_MainThreadContinuation, | 289 &PluginReverseInterface::StreamAsFile_MainThreadContinuation, |
| 287 open_cont); | 290 open_cont); |
| 288 // Normal files. | 291 // Normal files. |
| 289 if (!PnaclUrls::IsPnaclComponent(mapped_url)) { | 292 if (!PnaclUrls::IsPnaclComponent(mapped_url)) { |
| 290 if (!plugin_->StreamAsFile(mapped_url, | 293 if (!plugin_->StreamAsFile(mapped_url, |
| 291 stream_cc.pp_completion_callback())) { | 294 stream_cc.pp_completion_callback())) { |
| 292 NaClLog(4, | 295 NaClLog(4, |
| 293 "OpenManifestEntry_MainThreadContinuation: " | 296 "OpenManifestEntry_MainThreadContinuation: " |
| 294 "StreamAsFile failed\n"); | 297 "StreamAsFile failed\n"); |
| 295 nacl::MutexLocker take(&mu_); | 298 nacl::MutexLocker take(&mu_); |
| 296 *p->op_complete_ptr = true; // done... | 299 *p->op_complete_ptr = true; // done... |
| 297 *p->out_desc = -1; // but failed. | 300 p->file_info->desc = -1; // but failed. |
| 298 p->error_info->SetReport(ERROR_MANIFEST_OPEN, | 301 p->error_info->SetReport(ERROR_MANIFEST_OPEN, |
| 299 "ServiceRuntime: StreamAsFile failed"); | 302 "ServiceRuntime: StreamAsFile failed"); |
| 300 NaClXCondVarBroadcast(&cv_); | 303 NaClXCondVarBroadcast(&cv_); |
| 301 return; | 304 return; |
| 302 } | 305 } |
| 303 NaClLog(4, | 306 NaClLog(4, |
| 304 "OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n"); | 307 "OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n"); |
| 305 } else { | 308 } else { |
| 306 // Special PNaCl support files, that are installed on the | 309 // Special PNaCl support files, that are installed on the |
| 307 // user machine. | 310 // user machine. |
| 308 int32_t fd = PnaclResources::GetPnaclFD( | 311 int32_t fd = PnaclResources::GetPnaclFD( |
| 309 plugin_, | 312 plugin_, |
| 310 PnaclUrls::PnaclComponentURLToFilename(mapped_url).c_str()); | 313 PnaclUrls::PnaclComponentURLToFilename(mapped_url).c_str()); |
| 311 if (fd < 0) { | 314 if (fd < 0) { |
| 312 // We should check earlier if the pnacl component wasn't installed | 315 // We should check earlier if the pnacl component wasn't installed |
| 313 // yet. At this point, we can't do much anymore, so just continue | 316 // yet. At this point, we can't do much anymore, so just continue |
| 314 // with an invalid fd. | 317 // with an invalid fd. |
| 315 NaClLog(4, | 318 NaClLog(4, |
| 316 "OpenManifestEntry_MainThreadContinuation: " | 319 "OpenManifestEntry_MainThreadContinuation: " |
| 317 "GetReadonlyPnaclFd failed\n"); | 320 "GetReadonlyPnaclFd failed\n"); |
| 318 // TODO(jvoung): Separate the error codes? | 321 // TODO(jvoung): Separate the error codes? |
| 319 p->error_info->SetReport(ERROR_MANIFEST_OPEN, | 322 p->error_info->SetReport(ERROR_MANIFEST_OPEN, |
| 320 "ServiceRuntime: GetPnaclFd failed"); | 323 "ServiceRuntime: GetPnaclFd failed"); |
| 321 } | 324 } |
| 322 nacl::MutexLocker take(&mu_); | 325 nacl::MutexLocker take(&mu_); |
| 323 *p->op_complete_ptr = true; // done! | 326 *p->op_complete_ptr = true; // done! |
| 324 *p->out_desc = fd; | 327 // TODO(ncbray): enable the fast loading and validation paths for this |
| 328 // type of file. | |
| 329 p->file_info->desc = fd; | |
| 325 NaClXCondVarBroadcast(&cv_); | 330 NaClXCondVarBroadcast(&cv_); |
| 326 NaClLog(4, | 331 NaClLog(4, |
| 327 "OpenManifestEntry_MainThreadContinuation: GetPnaclFd okay\n"); | 332 "OpenManifestEntry_MainThreadContinuation: GetPnaclFd okay\n"); |
| 328 } | 333 } |
| 329 } else { | 334 } else { |
| 330 // Requires PNaCl translation. | 335 // Requires PNaCl translation. |
| 331 NaClLog(4, | 336 NaClLog(4, |
| 332 "OpenManifestEntry_MainThreadContinuation: " | 337 "OpenManifestEntry_MainThreadContinuation: " |
| 333 "pulling down and translating.\n"); | 338 "pulling down and translating.\n"); |
| 334 if (plugin_->nacl_interface()->IsPnaclEnabled()) { | 339 if (plugin_->nacl_interface()->IsPnaclEnabled()) { |
| 335 pp::CompletionCallback translate_callback = | 340 pp::CompletionCallback translate_callback = |
| 336 WeakRefNewCallback( | 341 WeakRefNewCallback( |
| 337 anchor_, | 342 anchor_, |
| 338 this, | 343 this, |
| 339 &PluginReverseInterface::BitcodeTranslate_MainThreadContinuation, | 344 &PluginReverseInterface::BitcodeTranslate_MainThreadContinuation, |
| 340 open_cont); | 345 open_cont); |
| 341 // Will always call the callback on success or failure. | 346 // Will always call the callback on success or failure. |
| 342 pnacl_coordinator_.reset( | 347 pnacl_coordinator_.reset( |
| 343 PnaclCoordinator::BitcodeToNative(plugin_, | 348 PnaclCoordinator::BitcodeToNative(plugin_, |
| 344 mapped_url, | 349 mapped_url, |
| 345 pnacl_options, | 350 pnacl_options, |
| 346 translate_callback)); | 351 translate_callback)); |
| 347 } else { | 352 } else { |
| 348 nacl::MutexLocker take(&mu_); | 353 nacl::MutexLocker take(&mu_); |
| 349 *p->op_complete_ptr = true; // done... | 354 *p->op_complete_ptr = true; // done... |
| 350 *p->out_desc = -1; // but failed. | 355 p->file_info->desc = -1; // but failed. |
| 351 p->error_info->SetReport(ERROR_PNACL_NOT_ENABLED, | 356 p->error_info->SetReport(ERROR_PNACL_NOT_ENABLED, |
| 352 "ServiceRuntime: GetPnaclFd failed -- pnacl not " | 357 "ServiceRuntime: GetPnaclFd failed -- pnacl not " |
| 353 "enabled with --enable-pnacl."); | 358 "enabled with --enable-pnacl."); |
| 354 NaClXCondVarBroadcast(&cv_); | 359 NaClXCondVarBroadcast(&cv_); |
| 355 return; | 360 return; |
| 356 } | 361 } |
| 357 } | 362 } |
| 358 // p is deleted automatically | 363 // p is deleted automatically |
| 359 } | 364 } |
| 360 | 365 |
| 361 void PluginReverseInterface::StreamAsFile_MainThreadContinuation( | 366 void PluginReverseInterface::StreamAsFile_MainThreadContinuation( |
| 362 OpenManifestEntryResource* p, | 367 OpenManifestEntryResource* p, |
| 363 int32_t result) { | 368 int32_t result) { |
| 364 NaClLog(4, | 369 NaClLog(4, |
| 365 "Entered StreamAsFile_MainThreadContinuation\n"); | 370 "Entered StreamAsFile_MainThreadContinuation\n"); |
| 366 | 371 |
| 367 nacl::MutexLocker take(&mu_); | 372 nacl::MutexLocker take(&mu_); |
| 368 if (result == PP_OK) { | 373 if (result == PP_OK) { |
| 369 NaClLog(4, "StreamAsFile_MainThreadContinuation: GetPOSIXFileDesc(%s)\n", | 374 NaClLog(4, "StreamAsFile_MainThreadContinuation: GetFileInfo(%s)\n", |
| 370 p->url.c_str()); | 375 p->url.c_str()); |
| 371 *p->out_desc = plugin_->GetPOSIXFileDesc(p->url); | 376 *p->file_info = plugin_->GetFileInfo(p->url); |
| 377 | |
| 372 NaClLog(4, | 378 NaClLog(4, |
| 373 "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n", | 379 "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n", |
| 374 *p->out_desc); | 380 p->file_info->desc); |
| 375 } else { | 381 } else { |
| 376 NaClLog(4, | 382 NaClLog(4, |
| 377 "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n"); | 383 "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n"); |
| 378 *p->out_desc = -1; | 384 p->file_info->desc = -1; |
| 379 p->error_info->SetReport(ERROR_MANIFEST_OPEN, | 385 p->error_info->SetReport(ERROR_MANIFEST_OPEN, |
| 380 "Plugin StreamAsFile failed at callback"); | 386 "Plugin StreamAsFile failed at callback"); |
| 381 } | 387 } |
| 382 *p->op_complete_ptr = true; | 388 *p->op_complete_ptr = true; |
| 383 NaClXCondVarBroadcast(&cv_); | 389 NaClXCondVarBroadcast(&cv_); |
| 384 } | 390 } |
| 385 | 391 |
| 386 | 392 |
| 387 void PluginReverseInterface::BitcodeTranslate_MainThreadContinuation( | 393 void PluginReverseInterface::BitcodeTranslate_MainThreadContinuation( |
| 388 OpenManifestEntryResource* p, | 394 OpenManifestEntryResource* p, |
| 389 int32_t result) { | 395 int32_t result) { |
| 390 NaClLog(4, | 396 NaClLog(4, |
| 391 "Entered BitcodeTranslate_MainThreadContinuation\n"); | 397 "Entered BitcodeTranslate_MainThreadContinuation\n"); |
| 392 | 398 |
| 393 nacl::MutexLocker take(&mu_); | 399 nacl::MutexLocker take(&mu_); |
| 394 if (result == PP_OK) { | 400 if (result == PP_OK) { |
| 395 // TODO(jvoung): clean this up. We are assuming that the NaClDesc is | 401 // TODO(jvoung): clean this up. We are assuming that the NaClDesc is |
| 396 // a host IO desc and doing a downcast. Once the ReverseInterface | 402 // a host IO desc and doing a downcast. Once the ReverseInterface |
| 397 // accepts NaClDescs we can avoid this downcast. | 403 // accepts NaClDescs we can avoid this downcast. |
| 398 NaClDesc* desc = pnacl_coordinator_->ReleaseTranslatedFD()->desc(); | 404 NaClDesc* desc = pnacl_coordinator_->ReleaseTranslatedFD()->desc(); |
| 399 struct NaClDescIoDesc* ndiodp = (struct NaClDescIoDesc*)desc; | 405 struct NaClDescIoDesc* ndiodp = (struct NaClDescIoDesc*)desc; |
| 400 *p->out_desc = ndiodp->hd->d; | 406 p->file_info->desc = ndiodp->hd->d; |
| 401 pnacl_coordinator_.reset(NULL); | 407 pnacl_coordinator_.reset(NULL); |
| 402 NaClLog(4, | 408 NaClLog(4, |
| 403 "BitcodeTranslate_MainThreadContinuation: PP_OK, desc %d\n", | 409 "BitcodeTranslate_MainThreadContinuation: PP_OK, desc %d\n", |
| 404 *p->out_desc); | 410 p->file_info->desc); |
| 405 } else { | 411 } else { |
| 406 NaClLog(4, | 412 NaClLog(4, |
| 407 "BitcodeTranslate_MainThreadContinuation: !PP_OK, " | 413 "BitcodeTranslate_MainThreadContinuation: !PP_OK, " |
| 408 "setting desc -1\n"); | 414 "setting desc -1\n"); |
| 409 *p->out_desc = -1; | 415 p->file_info->desc = -1; |
| 410 // Error should have been reported by pnacl coordinator. | 416 // Error should have been reported by pnacl coordinator. |
| 411 NaClLog(LOG_ERROR, "PluginReverseInterface::BitcodeTranslate error.\n"); | 417 NaClLog(LOG_ERROR, "PluginReverseInterface::BitcodeTranslate error.\n"); |
| 412 } | 418 } |
| 413 *p->op_complete_ptr = true; | 419 *p->op_complete_ptr = true; |
| 414 NaClXCondVarBroadcast(&cv_); | 420 NaClXCondVarBroadcast(&cv_); |
| 415 } | 421 } |
| 416 | 422 |
| 417 | 423 |
| 418 bool PluginReverseInterface::CloseManifestEntry(int32_t desc) { | 424 bool PluginReverseInterface::CloseManifestEntry(int32_t desc) { |
| 419 bool op_complete = false; | 425 bool op_complete = false; |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 846 | 852 |
| 847 nacl::string ServiceRuntime::GetCrashLogOutput() { | 853 nacl::string ServiceRuntime::GetCrashLogOutput() { |
| 848 if (NULL != subprocess_.get()) { | 854 if (NULL != subprocess_.get()) { |
| 849 return subprocess_->GetCrashLogOutput(); | 855 return subprocess_->GetCrashLogOutput(); |
| 850 } else { | 856 } else { |
| 851 return std::string(); | 857 return std::string(); |
| 852 } | 858 } |
| 853 } | 859 } |
| 854 | 860 |
| 855 } // namespace plugin | 861 } // namespace plugin |
| OLD | NEW |