Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(616)

Side by Side Diff: ppapi/native_client/src/trusted/plugin/service_runtime.cc

Issue 249183004: Implement open_resource in non-SFI mode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "ppapi/native_client/src/trusted/plugin/service_runtime.h" 9 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
10 10
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 #include "ppapi/native_client/src/trusted/plugin/manifest.h" 50 #include "ppapi/native_client/src/trusted/plugin/manifest.h"
51 #include "ppapi/native_client/src/trusted/plugin/plugin.h" 51 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
52 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h" 52 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
53 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h" 53 #include "ppapi/native_client/src/trusted/plugin/pnacl_resources.h"
54 #include "ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h" 54 #include "ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h"
55 #include "ppapi/native_client/src/trusted/plugin/srpc_client.h" 55 #include "ppapi/native_client/src/trusted/plugin/srpc_client.h"
56 #include "ppapi/native_client/src/trusted/weak_ref/call_on_main_thread.h" 56 #include "ppapi/native_client/src/trusted/weak_ref/call_on_main_thread.h"
57 57
58 namespace plugin { 58 namespace plugin {
59
60 class OpenManifestEntryAsyncCallback {
61 public:
62 OpenManifestEntryAsyncCallback(PP_OpenResourceCompletionCallback callback,
63 void* callback_user_data)
64 : callback_(callback), callback_user_data_(callback_user_data) {
65 }
66
67 ~OpenManifestEntryAsyncCallback() {
68 if (callback_)
69 callback_(callback_user_data_, PP_kInvalidFileHandle);
70 }
71
72 void Run(int32_t pp_error) {
73 #if defined(OS_WIN)
74 // Currently, this is used only for non-SFI mode, and now the mode is not
75 // supported on windows.
76 // TODO(hidehiko): Support it on Windows when we switch to use
77 // ManifestService also in SFI-mode.
78 NACL_NOTREACHED();
79 #elif defined(OS_POSIX)
80 // On posix, PlatformFile is the file descriptor.
81 callback_(callback_user_data_, (pp_error == PP_OK) ? info_.desc : -1);
82 callback_ = NULL;
83 #endif
84 }
85
86 NaClFileInfo* mutable_info() { return &info_; }
87
88 private:
89 NaClFileInfo info_;
90 PP_OpenResourceCompletionCallback callback_;
91 void* callback_user_data_;
92 DISALLOW_COPY_AND_ASSIGN(OpenManifestEntryAsyncCallback);
93 };
94
59 namespace { 95 namespace {
60 96
61 // For doing crude quota enforcement on writes to temp files. 97 // For doing crude quota enforcement on writes to temp files.
62 // We do not allow a temp file bigger than 128 MB for now. 98 // We do not allow a temp file bigger than 128 MB for now.
63 // There is currently a limit of 32M for nexe text size, so 128M 99 // There is currently a limit of 32M for nexe text size, so 128M
64 // should be plenty for static data 100 // should be plenty for static data
65 const int64_t kMaxTempQuota = 0x8000000; 101 const int64_t kMaxTempQuota = 0x8000000;
66 102
67 class ManifestService { 103 class ManifestService {
68 public: 104 public:
(...skipping 16 matching lines...) Expand all
85 // Release this instance if the ServiceRuntime is already destructed. 121 // Release this instance if the ServiceRuntime is already destructed.
86 if (anchor_->is_abandoned()) { 122 if (anchor_->is_abandoned()) {
87 delete this; 123 delete this;
88 return false; 124 return false;
89 } 125 }
90 126
91 plugin_reverse_->StartupInitializationComplete(); 127 plugin_reverse_->StartupInitializationComplete();
92 return true; 128 return true;
93 } 129 }
94 130
131 bool OpenResource(const char* entry_key,
132 PP_OpenResourceCompletionCallback callback,
133 void* callback_user_data) {
134 // Release this instance if the ServiceRuntime is already destructed.
135 if (anchor_->is_abandoned()) {
136 callback(callback_user_data, PP_kInvalidFileHandle);
137 delete this;
138 return false;
139 }
140
141 OpenManifestEntryAsyncCallback* open_manifest_callback =
142 new OpenManifestEntryAsyncCallback(callback, callback_user_data);
143 plugin_reverse_->OpenManifestEntryAsync(
144 entry_key,
145 open_manifest_callback->mutable_info(),
146 open_manifest_callback);
147 return true;
148 }
149
95 static PP_Bool QuitTrampoline(void* user_data) { 150 static PP_Bool QuitTrampoline(void* user_data) {
96 return PP_FromBool(static_cast<ManifestService*>(user_data)->Quit()); 151 return PP_FromBool(static_cast<ManifestService*>(user_data)->Quit());
97 } 152 }
98 153
99 static PP_Bool StartupInitializationCompleteTrampoline(void* user_data) { 154 static PP_Bool StartupInitializationCompleteTrampoline(void* user_data) {
100 return PP_FromBool(static_cast<ManifestService*>(user_data)-> 155 return PP_FromBool(static_cast<ManifestService*>(user_data)->
101 StartupInitializationComplete()); 156 StartupInitializationComplete());
102 } 157 }
103 158
159 static PP_Bool OpenResourceTrampoline(
160 void* user_data,
161 const char* entry_key,
162 PP_OpenResourceCompletionCallback callback,
163 void* callback_user_data) {
164 return PP_FromBool(static_cast<ManifestService*>(user_data)->OpenResource(
165 entry_key, callback, callback_user_data));
166 }
167
104 private: 168 private:
105 // Weak reference to check if plugin_reverse is legally accessible or not. 169 // Weak reference to check if plugin_reverse is legally accessible or not.
106 nacl::WeakRefAnchor* anchor_; 170 nacl::WeakRefAnchor* anchor_;
107 PluginReverseInterface* plugin_reverse_; 171 PluginReverseInterface* plugin_reverse_;
108 172
109 DISALLOW_COPY_AND_ASSIGN(ManifestService); 173 DISALLOW_COPY_AND_ASSIGN(ManifestService);
110 }; 174 };
111 175
112 // Vtable to pass functions to LaunchSelLdr. 176 // Vtable to pass functions to LaunchSelLdr.
113 const PP_ManifestService kManifestServiceVTable = { 177 const PPP_ManifestService kManifestServiceVTable = {
114 &ManifestService::QuitTrampoline, 178 &ManifestService::QuitTrampoline,
115 &ManifestService::StartupInitializationCompleteTrampoline, 179 &ManifestService::StartupInitializationCompleteTrampoline,
180 &ManifestService::OpenResourceTrampoline,
116 }; 181 };
117 182
118 } // namespace 183 } // namespace
119 184
185 OpenManifestEntryResource::~OpenManifestEntryResource() {
186 MaybeRunCallback(PP_ERROR_ABORTED);
187 }
188
189 void OpenManifestEntryResource::MaybeRunCallback(int32_t pp_error) {
190 if (!callback)
191 return;
192
193 callback->Run(pp_error);
194 delete callback;
195 callback = NULL;
196 }
197
120 PluginReverseInterface::PluginReverseInterface( 198 PluginReverseInterface::PluginReverseInterface(
121 nacl::WeakRefAnchor* anchor, 199 nacl::WeakRefAnchor* anchor,
122 Plugin* plugin, 200 Plugin* plugin,
123 const Manifest* manifest, 201 const Manifest* manifest,
124 ServiceRuntime* service_runtime, 202 ServiceRuntime* service_runtime,
125 pp::CompletionCallback init_done_cb, 203 pp::CompletionCallback init_done_cb,
126 pp::CompletionCallback crash_cb) 204 pp::CompletionCallback crash_cb)
127 : anchor_(anchor), 205 : anchor_(anchor),
128 plugin_(plugin), 206 plugin_(plugin),
129 manifest_(manifest), 207 manifest_(manifest),
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 // and invoke StreamAsFile with a completion callback that invokes 266 // and invoke StreamAsFile with a completion callback that invokes
189 // GetPOSIXFileDesc. 267 // GetPOSIXFileDesc.
190 bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key, 268 bool PluginReverseInterface::OpenManifestEntry(nacl::string url_key,
191 struct NaClFileInfo* info) { 269 struct NaClFileInfo* info) {
192 bool op_complete = false; // NB: mu_ and cv_ also controls access to this! 270 bool op_complete = false; // NB: mu_ and cv_ also controls access to this!
193 // The to_open object is owned by the weak ref callback. Because this function 271 // The to_open object is owned by the weak ref callback. Because this function
194 // waits for the callback to finish, the to_open object will be deallocated on 272 // waits for the callback to finish, the to_open object will be deallocated on
195 // the main thread before this function can return. The pointers it contains 273 // the main thread before this function can return. The pointers it contains
196 // to stack variables will not leak. 274 // to stack variables will not leak.
197 OpenManifestEntryResource* to_open = 275 OpenManifestEntryResource* to_open =
198 new OpenManifestEntryResource(url_key, info, &op_complete); 276 new OpenManifestEntryResource(url_key, info, &op_complete, NULL);
199 CHECK(to_open != NULL); 277 CHECK(to_open != NULL);
200 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n", 278 NaClLog(4, "PluginReverseInterface::OpenManifestEntry: %s\n",
201 url_key.c_str()); 279 url_key.c_str());
202 // This assumes we are not on the main thread. If false, we deadlock. 280 // This assumes we are not on the main thread. If false, we deadlock.
203 plugin::WeakRefCallOnMainThread( 281 plugin::WeakRefCallOnMainThread(
204 anchor_, 282 anchor_,
205 0, 283 0,
206 this, 284 this,
207 &plugin::PluginReverseInterface::OpenManifestEntry_MainThreadContinuation, 285 &plugin::PluginReverseInterface::OpenManifestEntry_MainThreadContinuation,
208 to_open); 286 to_open);
(...skipping 29 matching lines...) Expand all
238 if (info->desc == -1) { 316 if (info->desc == -1) {
239 // TODO(bsy,ncbray): what else should we do with the error? This 317 // TODO(bsy,ncbray): what else should we do with the error? This
240 // is a runtime error that may simply be a programming error in 318 // is a runtime error that may simply be a programming error in
241 // the untrusted code, or it may be something else wrong w/ the 319 // the untrusted code, or it may be something else wrong w/ the
242 // manifest. 320 // manifest.
243 NaClLog(4, "OpenManifestEntry: failed for key %s", url_key.c_str()); 321 NaClLog(4, "OpenManifestEntry: failed for key %s", url_key.c_str());
244 } 322 }
245 return true; 323 return true;
246 } 324 }
247 325
326 void PluginReverseInterface::OpenManifestEntryAsync(
327 const nacl::string& entry_key,
328 struct NaClFileInfo* info,
329 OpenManifestEntryAsyncCallback* callback) {
330 bool op_complete = false;
331 OpenManifestEntryResource to_open(
332 entry_key, info, &op_complete, callback);
333 OpenManifestEntry_MainThreadContinuation(&to_open, PP_OK);
334 }
335
248 // Transfer point from OpenManifestEntry() which runs on the main thread 336 // Transfer point from OpenManifestEntry() which runs on the main thread
249 // (Some PPAPI actions -- like StreamAsFile -- can only run on the main thread). 337 // (Some PPAPI actions -- like StreamAsFile -- can only run on the main thread).
250 // OpenManifestEntry() is waiting on a condvar for this continuation to 338 // OpenManifestEntry() is waiting on a condvar for this continuation to
251 // complete. We Broadcast and awaken OpenManifestEntry() whenever we are done 339 // complete. We Broadcast and awaken OpenManifestEntry() whenever we are done
252 // either here, or in a later MainThreadContinuation step, if there are 340 // either here, or in a later MainThreadContinuation step, if there are
253 // multiple steps. 341 // multiple steps.
254 void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation( 342 void PluginReverseInterface::OpenManifestEntry_MainThreadContinuation(
255 OpenManifestEntryResource* p, 343 OpenManifestEntryResource* p,
256 int32_t err) { 344 int32_t err) {
257 UNREFERENCED_PARAMETER(err); 345 UNREFERENCED_PARAMETER(err);
258 // CallOnMainThread continuations always called with err == PP_OK. 346 // CallOnMainThread continuations always called with err == PP_OK.
259 347
260 NaClLog(4, "Entered OpenManifestEntry_MainThreadContinuation\n"); 348 NaClLog(4, "Entered OpenManifestEntry_MainThreadContinuation\n");
261 349
262 std::string mapped_url; 350 std::string mapped_url;
263 PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, 2}; 351 PP_PNaClOptions pnacl_options = {PP_FALSE, PP_FALSE, 2};
264 ErrorInfo error_info; 352 ErrorInfo error_info;
265 if (!manifest_->ResolveKey(p->url, &mapped_url, 353 if (!manifest_->ResolveKey(p->url, &mapped_url,
266 &pnacl_options, &error_info)) { 354 &pnacl_options, &error_info)) {
267 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: ResolveKey failed\n"); 355 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: ResolveKey failed\n");
268 NaClLog(4, 356 NaClLog(4,
269 "Error code %d, string %s\n", 357 "Error code %d, string %s\n",
270 error_info.error_code(), 358 error_info.error_code(),
271 error_info.message().c_str()); 359 error_info.message().c_str());
272 // Failed, and error_info has the details on what happened. Wake 360 // Failed, and error_info has the details on what happened. Wake
273 // up requesting thread -- we are done. 361 // up requesting thread -- we are done.
274 nacl::MutexLocker take(&mu_); 362 {
275 *p->op_complete_ptr = true; // done... 363 nacl::MutexLocker take(&mu_);
276 p->file_info->desc = -1; // but failed. 364 *p->op_complete_ptr = true; // done...
277 NaClXCondVarBroadcast(&cv_); 365 p->file_info->desc = -1; // but failed.
366 NaClXCondVarBroadcast(&cv_);
367 }
368 p->MaybeRunCallback(PP_OK);
278 return; 369 return;
279 } 370 }
280 NaClLog(4, 371 NaClLog(4,
281 "OpenManifestEntry_MainThreadContinuation: " 372 "OpenManifestEntry_MainThreadContinuation: "
282 "ResolveKey: %s -> %s (pnacl_translate(%d))\n", 373 "ResolveKey: %s -> %s (pnacl_translate(%d))\n",
283 p->url.c_str(), mapped_url.c_str(), pnacl_options.translate); 374 p->url.c_str(), mapped_url.c_str(), pnacl_options.translate);
284 375
285 if (pnacl_options.translate) { 376 if (pnacl_options.translate) {
286 // Requires PNaCl translation, but that's not supported. 377 // Requires PNaCl translation, but that's not supported.
287 NaClLog(4, 378 NaClLog(4,
288 "OpenManifestEntry_MainThreadContinuation: " 379 "OpenManifestEntry_MainThreadContinuation: "
289 "Requires PNaCl translation -- not supported\n"); 380 "Requires PNaCl translation -- not supported\n");
290 nacl::MutexLocker take(&mu_); 381 {
291 *p->op_complete_ptr = true; // done... 382 nacl::MutexLocker take(&mu_);
292 p->file_info->desc = -1; // but failed. 383 *p->op_complete_ptr = true; // done...
293 NaClXCondVarBroadcast(&cv_); 384 p->file_info->desc = -1; // but failed.
385 NaClXCondVarBroadcast(&cv_);
386 }
387 p->MaybeRunCallback(PP_OK);
294 return; 388 return;
295 } 389 }
296 390
297 if (PnaclUrls::IsPnaclComponent(mapped_url)) { 391 if (PnaclUrls::IsPnaclComponent(mapped_url)) {
298 // Special PNaCl support files, that are installed on the 392 // Special PNaCl support files, that are installed on the
299 // user machine. 393 // user machine.
300 int32_t fd = PnaclResources::GetPnaclFD( 394 int32_t fd = PnaclResources::GetPnaclFD(
301 plugin_, 395 plugin_,
302 PnaclUrls::PnaclComponentURLToFilename(mapped_url).c_str()); 396 PnaclUrls::PnaclComponentURLToFilename(mapped_url).c_str());
303 if (fd < 0) { 397 if (fd < 0) {
304 // We checked earlier if the pnacl component wasn't installed 398 // We checked earlier if the pnacl component wasn't installed
305 // yet, so this shouldn't happen. At this point, we can't do much 399 // yet, so this shouldn't happen. At this point, we can't do much
306 // anymore, so just continue with an invalid fd. 400 // anymore, so just continue with an invalid fd.
307 NaClLog(4, 401 NaClLog(4,
308 "OpenManifestEntry_MainThreadContinuation: " 402 "OpenManifestEntry_MainThreadContinuation: "
309 "GetReadonlyPnaclFd failed\n"); 403 "GetReadonlyPnaclFd failed\n");
310 } 404 }
311 nacl::MutexLocker take(&mu_); 405 {
312 *p->op_complete_ptr = true; // done! 406 nacl::MutexLocker take(&mu_);
313 // TODO(ncbray): enable the fast loading and validation paths for this 407 *p->op_complete_ptr = true; // done!
314 // type of file. 408 // TODO(ncbray): enable the fast loading and validation paths for this
315 p->file_info->desc = fd; 409 // type of file.
316 NaClXCondVarBroadcast(&cv_); 410 p->file_info->desc = fd;
411 NaClXCondVarBroadcast(&cv_);
412 }
317 NaClLog(4, 413 NaClLog(4,
318 "OpenManifestEntry_MainThreadContinuation: GetPnaclFd okay\n"); 414 "OpenManifestEntry_MainThreadContinuation: GetPnaclFd okay\n");
415 p->MaybeRunCallback(PP_OK);
319 return; 416 return;
320 } 417 }
321 418
322 // Hereafter, normal files. 419 // Hereafter, normal files.
323 420
324 // Because p is owned by the callback of this invocation, so it is necessary 421 // Because p is owned by the callback of this invocation, so it is necessary
325 // to create another instance. 422 // to create another instance.
326 OpenManifestEntryResource* open_cont = new OpenManifestEntryResource(*p); 423 OpenManifestEntryResource* open_cont = new OpenManifestEntryResource(*p);
327 open_cont->url = mapped_url; 424 open_cont->url = mapped_url;
425 // Callback is now delegated from p to open_cont. So, here we manually clear
426 // complete callback.
427 p->callback = NULL;
328 pp::CompletionCallback stream_cc = WeakRefNewCallback( 428 pp::CompletionCallback stream_cc = WeakRefNewCallback(
329 anchor_, 429 anchor_,
330 this, 430 this,
331 &PluginReverseInterface::StreamAsFile_MainThreadContinuation, 431 &PluginReverseInterface::StreamAsFile_MainThreadContinuation,
332 open_cont); 432 open_cont);
333 433
334 if (!plugin_->StreamAsFile(mapped_url, stream_cc)) { 434 if (!plugin_->StreamAsFile(mapped_url, stream_cc)) {
335 NaClLog(4, 435 NaClLog(4,
336 "OpenManifestEntry_MainThreadContinuation: " 436 "OpenManifestEntry_MainThreadContinuation: "
337 "StreamAsFile failed\n"); 437 "StreamAsFile failed\n");
338 // Here, StreamAsFile is failed and stream_cc is not called. 438 // Here, StreamAsFile is failed and stream_cc is not called.
339 // However, open_cont will be released only by the invocation. 439 // However, open_cont will be released only by the invocation.
340 // So, we manually call it here with error. 440 // So, we manually call it here with error.
341 stream_cc.Run(PP_ERROR_FAILED); 441 stream_cc.Run(PP_ERROR_FAILED);
342 return; 442 return;
343 } 443 }
344 444
345 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n"); 445 NaClLog(4, "OpenManifestEntry_MainThreadContinuation: StreamAsFile okay\n");
346 // p is deleted automatically 446 // p is deleted automatically
347 } 447 }
348 448
349 void PluginReverseInterface::StreamAsFile_MainThreadContinuation( 449 void PluginReverseInterface::StreamAsFile_MainThreadContinuation(
350 OpenManifestEntryResource* p, 450 OpenManifestEntryResource* p,
351 int32_t result) { 451 int32_t result) {
352 NaClLog(4, 452 NaClLog(4,
353 "Entered StreamAsFile_MainThreadContinuation\n"); 453 "Entered StreamAsFile_MainThreadContinuation\n");
354 454
355 nacl::MutexLocker take(&mu_); 455 {
356 if (result == PP_OK) { 456 nacl::MutexLocker take(&mu_);
357 NaClLog(4, "StreamAsFile_MainThreadContinuation: GetFileInfo(%s)\n", 457 if (result == PP_OK) {
358 p->url.c_str()); 458 NaClLog(4, "StreamAsFile_MainThreadContinuation: GetFileInfo(%s)\n",
359 *p->file_info = plugin_->GetFileInfo(p->url); 459 p->url.c_str());
460 *p->file_info = plugin_->GetFileInfo(p->url);
360 461
361 NaClLog(4, 462 NaClLog(4,
362 "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n", 463 "StreamAsFile_MainThreadContinuation: PP_OK, desc %d\n",
363 p->file_info->desc); 464 p->file_info->desc);
364 } else { 465 } else {
365 NaClLog(4, 466 NaClLog(
366 "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n"); 467 4,
367 p->file_info->desc = -1; 468 "StreamAsFile_MainThreadContinuation: !PP_OK, setting desc -1\n");
469 p->file_info->desc = -1;
470 }
471 *p->op_complete_ptr = true;
472 NaClXCondVarBroadcast(&cv_);
368 } 473 }
369 *p->op_complete_ptr = true; 474 p->MaybeRunCallback(PP_OK);
370 NaClXCondVarBroadcast(&cv_);
371 } 475 }
372 476
373 bool PluginReverseInterface::CloseManifestEntry(int32_t desc) { 477 bool PluginReverseInterface::CloseManifestEntry(int32_t desc) {
374 bool op_complete = false; 478 bool op_complete = false;
375 bool op_result; 479 bool op_result;
376 CloseManifestEntryResource* to_close = 480 CloseManifestEntryResource* to_close =
377 new CloseManifestEntryResource(desc, &op_complete, &op_result); 481 new CloseManifestEntryResource(desc, &op_complete, &op_result);
378 482
379 plugin::WeakRefCallOnMainThread( 483 plugin::WeakRefCallOnMainThread(
380 anchor_, 484 anchor_,
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 900
797 nacl::string ServiceRuntime::GetCrashLogOutput() { 901 nacl::string ServiceRuntime::GetCrashLogOutput() {
798 if (NULL != subprocess_.get()) { 902 if (NULL != subprocess_.get()) {
799 return subprocess_->GetCrashLogOutput(); 903 return subprocess_->GetCrashLogOutput();
800 } else { 904 } else {
801 return std::string(); 905 return std::string();
802 } 906 }
803 } 907 }
804 908
805 } // namespace plugin 909 } // namespace plugin
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698