| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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. | |
| 4 | |
| 5 #include "chrome/browser/extensions/api/log_private/log_private_api.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 #include <utility> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/command_line.h" | |
| 13 #include "base/files/file_util.h" | |
| 14 #include "base/json/json_writer.h" | |
| 15 #include "base/lazy_instance.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/memory/ptr_util.h" | |
| 18 #include "base/sequenced_task_runner.h" | |
| 19 #include "base/values.h" | |
| 20 #include "build/build_config.h" | |
| 21 #include "chrome/browser/browser_process.h" | |
| 22 #include "chrome/browser/download/download_prefs.h" | |
| 23 #include "chrome/browser/extensions/api/log_private/filter_handler.h" | |
| 24 #include "chrome/browser/extensions/api/log_private/log_parser.h" | |
| 25 #include "chrome/browser/extensions/api/log_private/syslog_parser.h" | |
| 26 #include "chrome/browser/feedback/system_logs/about_system_logs_fetcher.h" | |
| 27 #include "chrome/browser/feedback/system_logs/chrome_system_logs_fetcher.h" | |
| 28 #include "chrome/browser/io_thread.h" | |
| 29 #include "chrome/browser/profiles/profile.h" | |
| 30 #include "chrome/browser/profiles/profile_manager.h" | |
| 31 #include "chrome/common/extensions/api/log_private.h" | |
| 32 #include "chrome/common/logging_chrome.h" | |
| 33 #include "components/net_log/chrome_net_log.h" | |
| 34 #include "content/public/browser/render_frame_host.h" | |
| 35 #include "content/public/browser/render_process_host.h" | |
| 36 #include "extensions/browser/api/file_handlers/app_file_handler_util.h" | |
| 37 #include "extensions/browser/event_router.h" | |
| 38 #include "extensions/browser/extension_function.h" | |
| 39 #include "extensions/browser/extension_registry.h" | |
| 40 #include "extensions/browser/granted_file_entry.h" | |
| 41 #include "net/log/net_log_entry.h" | |
| 42 | |
| 43 #if defined(OS_CHROMEOS) | |
| 44 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" | |
| 45 #include "chrome/browser/chromeos/system_logs/debug_log_writer.h" | |
| 46 #endif | |
| 47 | |
| 48 using content::BrowserThread; | |
| 49 | |
| 50 namespace events { | |
| 51 const char kOnCapturedEvents[] = "logPrivate.onCapturedEvents"; | |
| 52 } // namespace events | |
| 53 | |
| 54 namespace extensions { | |
| 55 namespace { | |
| 56 | |
| 57 const char kAppLogsSubdir[] = "apps"; | |
| 58 const char kLogDumpsSubdir[] = "log_dumps"; | |
| 59 const char kLogFileNameBase[] = "net-internals"; | |
| 60 const int kNetLogEventDelayMilliseconds = 100; | |
| 61 | |
| 62 // Gets sequenced task runner for file specific calls within this API. | |
| 63 scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() { | |
| 64 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); | |
| 65 return pool->GetSequencedTaskRunnerWithShutdownBehavior( | |
| 66 pool->GetNamedSequenceToken(FileResource::kSequenceToken), | |
| 67 base::SequencedWorkerPool::BLOCK_SHUTDOWN); | |
| 68 } | |
| 69 | |
| 70 #if DCHECK_IS_ON() | |
| 71 base::LazyInstance<base::SequenceChecker>::Leaky | |
| 72 g_file_resource_sequence_checker = LAZY_INSTANCE_INITIALIZER; | |
| 73 #endif | |
| 74 | |
| 75 // Checks if we are running on sequenced task runner thread. | |
| 76 void AssertCurrentlyOnFileResourceSequence() { | |
| 77 #if DCHECK_IS_ON() | |
| 78 DCHECK(g_file_resource_sequence_checker.Get().CalledOnValidSequence()); | |
| 79 #endif | |
| 80 } | |
| 81 | |
| 82 std::unique_ptr<LogParser> CreateLogParser(const std::string& log_type) { | |
| 83 if (log_type == "syslog") | |
| 84 return std::unique_ptr<LogParser>(new SyslogParser()); | |
| 85 // TODO(shinfan): Add more parser here | |
| 86 | |
| 87 NOTREACHED() << "Invalid log type: " << log_type; | |
| 88 return std::unique_ptr<LogParser>(); | |
| 89 } | |
| 90 | |
| 91 void CollectLogInfo(FilterHandler* filter_handler, | |
| 92 system_logs::SystemLogsResponse* logs, | |
| 93 std::vector<api::log_private::LogEntry>* output) { | |
| 94 for (system_logs::SystemLogsResponse::const_iterator | |
| 95 request_it = logs->begin(); request_it != logs->end(); ++request_it) { | |
| 96 if (!filter_handler->IsValidSource(request_it->first)) { | |
| 97 continue; | |
| 98 } | |
| 99 std::unique_ptr<LogParser> parser(CreateLogParser(request_it->first)); | |
| 100 if (parser) { | |
| 101 parser->Parse(request_it->second, output, filter_handler); | |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 // Returns directory location of app-specific logs that are initiated with | |
| 107 // logPrivate.startEventRecorder() calls - /home/chronos/user/log/apps | |
| 108 base::FilePath GetAppLogDirectory() { | |
| 109 return logging::GetSessionLogDir(*base::CommandLine::ForCurrentProcess()) | |
| 110 .Append(kAppLogsSubdir); | |
| 111 } | |
| 112 | |
| 113 // Returns directory location where logs dumps initiated with chrome.dumpLogs | |
| 114 // will be stored - /home/chronos/<user_profile_dir>/Downloads/log_dumps | |
| 115 base::FilePath GetLogDumpDirectory(content::BrowserContext* context) { | |
| 116 const DownloadPrefs* const prefs = DownloadPrefs::FromBrowserContext(context); | |
| 117 base::FilePath path = prefs->DownloadPath(); | |
| 118 | |
| 119 #if defined(OS_CHROMEOS) | |
| 120 Profile* profile = Profile::FromBrowserContext(context); | |
| 121 if (file_manager::util::IsUnderNonNativeLocalPath(profile, path)) | |
| 122 path = prefs->GetDefaultDownloadDirectoryForProfile(); | |
| 123 #endif | |
| 124 | |
| 125 return path.Append(kLogDumpsSubdir); | |
| 126 } | |
| 127 | |
| 128 // Removes direcotry content of |logs_dumps| and |app_logs_dir| (only for the | |
| 129 // primary profile). | |
| 130 void CleanUpLeftoverLogs(bool is_primary_profile, | |
| 131 const base::FilePath& app_logs_dir, | |
| 132 const base::FilePath& logs_dumps) { | |
| 133 LOG(WARNING) << "Deleting " << app_logs_dir.value(); | |
| 134 LOG(WARNING) << "Deleting " << logs_dumps.value(); | |
| 135 | |
| 136 AssertCurrentlyOnFileResourceSequence(); | |
| 137 base::DeleteFile(logs_dumps, true); | |
| 138 | |
| 139 // App-specific logs are stored in /home/chronos/user/log/apps directory that | |
| 140 // is shared between all profiles in multi-profile case. We should not | |
| 141 // nuke it for non-primary profiles. | |
| 142 if (!is_primary_profile) | |
| 143 return; | |
| 144 | |
| 145 base::DeleteFile(app_logs_dir, true); | |
| 146 } | |
| 147 | |
| 148 } // namespace | |
| 149 | |
| 150 const char FileResource::kSequenceToken[] = "log_api_files"; | |
| 151 | |
| 152 FileResource::FileResource(const std::string& owner_extension_id, | |
| 153 const base::FilePath& path) | |
| 154 : ApiResource(owner_extension_id), path_(path) { | |
| 155 } | |
| 156 | |
| 157 FileResource::~FileResource() { | |
| 158 base::DeleteFile(path_, true); | |
| 159 } | |
| 160 | |
| 161 bool FileResource::IsPersistent() const { | |
| 162 return false; | |
| 163 } | |
| 164 | |
| 165 // static | |
| 166 LogPrivateAPI* LogPrivateAPI::Get(content::BrowserContext* context) { | |
| 167 LogPrivateAPI* api = GetFactoryInstance()->Get(context); | |
| 168 api->Initialize(); | |
| 169 return api; | |
| 170 } | |
| 171 | |
| 172 LogPrivateAPI::LogPrivateAPI(content::BrowserContext* context) | |
| 173 : browser_context_(context), | |
| 174 logging_net_internals_(false), | |
| 175 event_sink_(api::log_private::EVENT_SINK_CAPTURE), | |
| 176 extension_registry_observer_(this), | |
| 177 log_file_resources_(context), | |
| 178 initialized_(false) { | |
| 179 } | |
| 180 | |
| 181 LogPrivateAPI::~LogPrivateAPI() { | |
| 182 } | |
| 183 | |
| 184 void LogPrivateAPI::StartNetInternalsWatch( | |
| 185 const std::string& extension_id, | |
| 186 api::log_private::EventSink event_sink, | |
| 187 const base::Closure& closure) { | |
| 188 net_internal_watches_.insert(extension_id); | |
| 189 | |
| 190 // Nuke any leftover app-specific or dumped log files from previous sessions. | |
| 191 BrowserThread::PostTaskAndReply( | |
| 192 BrowserThread::IO, | |
| 193 FROM_HERE, | |
| 194 base::Bind(&LogPrivateAPI::MaybeStartNetInternalLogging, | |
| 195 base::Unretained(this), | |
| 196 extension_id, | |
| 197 g_browser_process->io_thread(), | |
| 198 event_sink), | |
| 199 closure); | |
| 200 } | |
| 201 | |
| 202 void LogPrivateAPI::StopNetInternalsWatch(const std::string& extension_id, | |
| 203 const base::Closure& closure) { | |
| 204 net_internal_watches_.erase(extension_id); | |
| 205 MaybeStopNetInternalLogging(closure); | |
| 206 } | |
| 207 | |
| 208 void LogPrivateAPI::StopAllWatches(const std::string& extension_id, | |
| 209 const base::Closure& closure) { | |
| 210 StopNetInternalsWatch(extension_id, closure); | |
| 211 } | |
| 212 | |
| 213 void LogPrivateAPI::RegisterTempFile(const std::string& owner_extension_id, | |
| 214 const base::FilePath& file_path) { | |
| 215 GetSequencedTaskRunner()->PostTask( | |
| 216 FROM_HERE, | |
| 217 base::Bind(&LogPrivateAPI::RegisterTempFileOnFileResourceSequence, | |
| 218 base::Unretained(this), owner_extension_id, file_path)); | |
| 219 } | |
| 220 | |
| 221 static base::LazyInstance< | |
| 222 BrowserContextKeyedAPIFactory<LogPrivateAPI>>::DestructorAtExit g_factory = | |
| 223 LAZY_INSTANCE_INITIALIZER; | |
| 224 | |
| 225 // static | |
| 226 BrowserContextKeyedAPIFactory<LogPrivateAPI>* | |
| 227 LogPrivateAPI::GetFactoryInstance() { | |
| 228 return g_factory.Pointer(); | |
| 229 } | |
| 230 | |
| 231 void LogPrivateAPI::OnAddEntry(const net::NetLogEntry& entry) { | |
| 232 // We could receive events on whatever thread they happen to be generated, | |
| 233 // since we are only interested in network events, we should ignore any | |
| 234 // other thread than BrowserThread::IO. | |
| 235 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
| 236 return; | |
| 237 } | |
| 238 | |
| 239 if (!pending_entries_.get()) { | |
| 240 pending_entries_.reset(new base::ListValue()); | |
| 241 BrowserThread::PostDelayedTask( | |
| 242 BrowserThread::IO, FROM_HERE, | |
| 243 base::Bind(&LogPrivateAPI::PostPendingEntries, base::Unretained(this)), | |
| 244 base::TimeDelta::FromMilliseconds(kNetLogEventDelayMilliseconds)); | |
| 245 } | |
| 246 pending_entries_->Append(entry.ToValue()); | |
| 247 } | |
| 248 | |
| 249 void LogPrivateAPI::PostPendingEntries() { | |
| 250 BrowserThread::PostTask( | |
| 251 BrowserThread::UI, FROM_HERE, | |
| 252 base::Bind(&LogPrivateAPI:: AddEntriesOnUI, | |
| 253 base::Unretained(this), | |
| 254 base::Passed(&pending_entries_))); | |
| 255 } | |
| 256 | |
| 257 void LogPrivateAPI::AddEntriesOnUI(std::unique_ptr<base::ListValue> value) { | |
| 258 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 259 | |
| 260 for (const std::string& extension_id : net_internal_watches_) { | |
| 261 // Create the event's arguments value. | |
| 262 std::unique_ptr<base::ListValue> event_args(new base::ListValue()); | |
| 263 event_args->Append(value->CreateDeepCopy()); | |
| 264 std::unique_ptr<Event> event( | |
| 265 new Event(::extensions::events::LOG_PRIVATE_ON_CAPTURED_EVENTS, | |
| 266 ::events::kOnCapturedEvents, std::move(event_args))); | |
| 267 EventRouter::Get(browser_context_) | |
| 268 ->DispatchEventToExtension(extension_id, std::move(event)); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 void LogPrivateAPI::CreateTempNetLogFile(const std::string& owner_extension_id, | |
| 273 base::ScopedFILE* file) { | |
| 274 AssertCurrentlyOnFileResourceSequence(); | |
| 275 | |
| 276 // Create app-specific subdirectory in session logs folder. | |
| 277 base::FilePath app_log_dir = GetAppLogDirectory().Append(owner_extension_id); | |
| 278 if (!base::DirectoryExists(app_log_dir)) { | |
| 279 if (!base::CreateDirectory(app_log_dir)) { | |
| 280 LOG(ERROR) << "Could not create dir " << app_log_dir.value(); | |
| 281 return; | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 base::FilePath file_path = app_log_dir.Append(kLogFileNameBase); | |
| 286 file_path = logging::GenerateTimestampedName(file_path, base::Time::Now()); | |
| 287 FILE* file_ptr = fopen(file_path.value().c_str(), "w"); | |
| 288 if (file_ptr == nullptr) { | |
| 289 LOG(ERROR) << "Could not open " << file_path.value(); | |
| 290 return; | |
| 291 } | |
| 292 | |
| 293 RegisterTempFileOnFileResourceSequence(owner_extension_id, file_path); | |
| 294 return file->reset(file_ptr); | |
| 295 } | |
| 296 | |
| 297 void LogPrivateAPI::StartObservingNetEvents( | |
| 298 IOThread* io_thread, | |
| 299 base::ScopedFILE* file) { | |
| 300 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 301 if (!file->get()) | |
| 302 return; | |
| 303 | |
| 304 write_to_file_observer_.reset(new net::WriteToFileNetLogObserver()); | |
| 305 write_to_file_observer_->set_capture_mode( | |
| 306 net::NetLogCaptureMode::IncludeCookiesAndCredentials()); | |
| 307 write_to_file_observer_->StartObserving(io_thread->net_log(), | |
| 308 std::move(*file), nullptr, nullptr); | |
| 309 } | |
| 310 | |
| 311 void LogPrivateAPI::MaybeStartNetInternalLogging( | |
| 312 const std::string& caller_extension_id, | |
| 313 IOThread* io_thread, | |
| 314 api::log_private::EventSink event_sink) { | |
| 315 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 316 if (!logging_net_internals_) { | |
| 317 logging_net_internals_ = true; | |
| 318 event_sink_ = event_sink; | |
| 319 switch (event_sink_) { | |
| 320 case api::log_private::EVENT_SINK_CAPTURE: { | |
| 321 io_thread->net_log()->DeprecatedAddObserver( | |
| 322 this, net::NetLogCaptureMode::IncludeCookiesAndCredentials()); | |
| 323 break; | |
| 324 } | |
| 325 case api::log_private::EVENT_SINK_FILE: { | |
| 326 base::ScopedFILE* file = new base::ScopedFILE(); | |
| 327 // Initialize a FILE on the blocking pool and start observing event | |
| 328 // on IO thread. | |
| 329 GetSequencedTaskRunner()->PostTaskAndReply( | |
| 330 FROM_HERE, | |
| 331 base::Bind(&LogPrivateAPI::CreateTempNetLogFile, | |
| 332 base::Unretained(this), | |
| 333 caller_extension_id, | |
| 334 file), | |
| 335 base::Bind(&LogPrivateAPI::StartObservingNetEvents, | |
| 336 base::Unretained(this), | |
| 337 io_thread, | |
| 338 base::Owned(file))); | |
| 339 break; | |
| 340 } | |
| 341 case api::log_private::EVENT_SINK_NONE: { | |
| 342 NOTREACHED(); | |
| 343 break; | |
| 344 } | |
| 345 } | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 void LogPrivateAPI::MaybeStopNetInternalLogging(const base::Closure& closure) { | |
| 350 if (net_internal_watches_.empty()) { | |
| 351 if (closure.is_null()) { | |
| 352 BrowserThread::PostTask( | |
| 353 BrowserThread::IO, | |
| 354 FROM_HERE, | |
| 355 base::Bind(&LogPrivateAPI::StopNetInternalLogging, | |
| 356 base::Unretained(this))); | |
| 357 } else { | |
| 358 BrowserThread::PostTaskAndReply( | |
| 359 BrowserThread::IO, | |
| 360 FROM_HERE, | |
| 361 base::Bind(&LogPrivateAPI::StopNetInternalLogging, | |
| 362 base::Unretained(this)), | |
| 363 closure); | |
| 364 } | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 void LogPrivateAPI::StopNetInternalLogging() { | |
| 369 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 370 if (net_log() && logging_net_internals_) { | |
| 371 logging_net_internals_ = false; | |
| 372 switch (event_sink_) { | |
| 373 case api::log_private::EVENT_SINK_CAPTURE: | |
| 374 net_log()->DeprecatedRemoveObserver(this); | |
| 375 break; | |
| 376 case api::log_private::EVENT_SINK_FILE: | |
| 377 write_to_file_observer_->StopObserving(nullptr); | |
| 378 write_to_file_observer_.reset(); | |
| 379 break; | |
| 380 case api::log_private::EVENT_SINK_NONE: | |
| 381 NOTREACHED(); | |
| 382 break; | |
| 383 } | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 void LogPrivateAPI::Initialize() { | |
| 388 if (initialized_) | |
| 389 return; | |
| 390 | |
| 391 // Clean up temp files and folders from the previous sessions. | |
| 392 initialized_ = true; | |
| 393 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | |
| 394 GetSequencedTaskRunner()->PostTask( | |
| 395 FROM_HERE, | |
| 396 base::Bind(&CleanUpLeftoverLogs, | |
| 397 Profile::FromBrowserContext(browser_context_) == | |
| 398 ProfileManager::GetPrimaryUserProfile(), | |
| 399 GetAppLogDirectory(), | |
| 400 GetLogDumpDirectory(browser_context_))); | |
| 401 } | |
| 402 | |
| 403 void LogPrivateAPI::RegisterTempFileOnFileResourceSequence( | |
| 404 const std::string& owner_extension_id, | |
| 405 const base::FilePath& file_path) { | |
| 406 AssertCurrentlyOnFileResourceSequence(); | |
| 407 log_file_resources_.Add(new FileResource(owner_extension_id, file_path)); | |
| 408 } | |
| 409 | |
| 410 void LogPrivateAPI::OnExtensionUnloaded( | |
| 411 content::BrowserContext* browser_context, | |
| 412 const Extension* extension, | |
| 413 UnloadedExtensionReason reason) { | |
| 414 StopNetInternalsWatch(extension->id(), base::Closure()); | |
| 415 } | |
| 416 | |
| 417 LogPrivateGetHistoricalFunction::LogPrivateGetHistoricalFunction() { | |
| 418 } | |
| 419 | |
| 420 LogPrivateGetHistoricalFunction::~LogPrivateGetHistoricalFunction() { | |
| 421 } | |
| 422 | |
| 423 bool LogPrivateGetHistoricalFunction::RunAsync() { | |
| 424 // Get parameters | |
| 425 std::unique_ptr<api::log_private::GetHistorical::Params> params( | |
| 426 api::log_private::GetHistorical::Params::Create(*args_)); | |
| 427 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
| 428 filter_handler_.reset(new FilterHandler(params->filter)); | |
| 429 | |
| 430 // Self-deleting object. | |
| 431 system_logs::SystemLogsFetcher* fetcher = nullptr; | |
| 432 if ((params->filter).scrub) { | |
| 433 fetcher = system_logs::BuildChromeSystemLogsFetcher(); | |
| 434 } else { | |
| 435 fetcher = system_logs::BuildAboutSystemLogsFetcher(); | |
| 436 } | |
| 437 fetcher->Fetch( | |
| 438 base::Bind(&LogPrivateGetHistoricalFunction::OnSystemLogsLoaded, this)); | |
| 439 | |
| 440 return true; | |
| 441 } | |
| 442 | |
| 443 void LogPrivateGetHistoricalFunction::OnSystemLogsLoaded( | |
| 444 std::unique_ptr<system_logs::SystemLogsResponse> sys_info) { | |
| 445 // Prepare result | |
| 446 api::log_private::Result result; | |
| 447 CollectLogInfo(filter_handler_.get(), sys_info.get(), &result.data); | |
| 448 api::log_private::Filter::Populate( | |
| 449 *((filter_handler_->GetFilter())->ToValue()), &result.filter); | |
| 450 SetResult(result.ToValue()); | |
| 451 SendResponse(true); | |
| 452 } | |
| 453 | |
| 454 LogPrivateStartEventRecorderFunction::LogPrivateStartEventRecorderFunction() { | |
| 455 } | |
| 456 | |
| 457 LogPrivateStartEventRecorderFunction::~LogPrivateStartEventRecorderFunction() { | |
| 458 } | |
| 459 | |
| 460 bool LogPrivateStartEventRecorderFunction::RunAsync() { | |
| 461 std::unique_ptr<api::log_private::StartEventRecorder::Params> params( | |
| 462 api::log_private::StartEventRecorder::Params::Create(*args_)); | |
| 463 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
| 464 switch (params->event_type) { | |
| 465 case api::log_private::EVENT_TYPE_NETWORK: | |
| 466 LogPrivateAPI::Get(Profile::FromBrowserContext(browser_context())) | |
| 467 ->StartNetInternalsWatch( | |
| 468 extension_id(), | |
| 469 params->sink, | |
| 470 base::Bind( | |
| 471 &LogPrivateStartEventRecorderFunction::OnEventRecorderStarted, | |
| 472 this)); | |
| 473 break; | |
| 474 case api::log_private::EVENT_TYPE_NONE: | |
| 475 NOTREACHED(); | |
| 476 return false; | |
| 477 } | |
| 478 | |
| 479 return true; | |
| 480 } | |
| 481 | |
| 482 void LogPrivateStartEventRecorderFunction::OnEventRecorderStarted() { | |
| 483 SendResponse(true); | |
| 484 } | |
| 485 | |
| 486 LogPrivateStopEventRecorderFunction::LogPrivateStopEventRecorderFunction() { | |
| 487 } | |
| 488 | |
| 489 LogPrivateStopEventRecorderFunction::~LogPrivateStopEventRecorderFunction() { | |
| 490 } | |
| 491 | |
| 492 bool LogPrivateStopEventRecorderFunction::RunAsync() { | |
| 493 std::unique_ptr<api::log_private::StopEventRecorder::Params> params( | |
| 494 api::log_private::StopEventRecorder::Params::Create(*args_)); | |
| 495 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
| 496 switch (params->event_type) { | |
| 497 case api::log_private::EVENT_TYPE_NETWORK: | |
| 498 LogPrivateAPI::Get(Profile::FromBrowserContext(browser_context())) | |
| 499 ->StopNetInternalsWatch( | |
| 500 extension_id(), | |
| 501 base::Bind( | |
| 502 &LogPrivateStopEventRecorderFunction::OnEventRecorderStopped, | |
| 503 this)); | |
| 504 break; | |
| 505 case api::log_private::EVENT_TYPE_NONE: | |
| 506 NOTREACHED(); | |
| 507 return false; | |
| 508 } | |
| 509 return true; | |
| 510 } | |
| 511 | |
| 512 void LogPrivateStopEventRecorderFunction::OnEventRecorderStopped() { | |
| 513 SendResponse(true); | |
| 514 } | |
| 515 | |
| 516 LogPrivateDumpLogsFunction::LogPrivateDumpLogsFunction() { | |
| 517 } | |
| 518 | |
| 519 LogPrivateDumpLogsFunction::~LogPrivateDumpLogsFunction() { | |
| 520 } | |
| 521 | |
| 522 bool LogPrivateDumpLogsFunction::RunAsync() { | |
| 523 LogPrivateAPI::Get(Profile::FromBrowserContext(browser_context())) | |
| 524 ->StopAllWatches( | |
| 525 extension_id(), | |
| 526 base::Bind(&LogPrivateDumpLogsFunction::OnStopAllWatches, this)); | |
| 527 return true; | |
| 528 } | |
| 529 | |
| 530 void LogPrivateDumpLogsFunction::OnStopAllWatches() { | |
| 531 chromeos::DebugLogWriter::StoreCombinedLogs( | |
| 532 GetLogDumpDirectory(browser_context()).Append(extension_id()), | |
| 533 FileResource::kSequenceToken, | |
| 534 base::Bind(&LogPrivateDumpLogsFunction::OnStoreLogsCompleted, this)); | |
| 535 } | |
| 536 | |
| 537 void LogPrivateDumpLogsFunction::OnStoreLogsCompleted( | |
| 538 const base::FilePath& log_path, | |
| 539 bool succeeded) { | |
| 540 if (succeeded) { | |
| 541 LogPrivateAPI::Get(Profile::FromBrowserContext(browser_context())) | |
| 542 ->RegisterTempFile(extension_id(), log_path); | |
| 543 } | |
| 544 | |
| 545 std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue()); | |
| 546 extensions::GrantedFileEntry file_entry = | |
| 547 extensions::app_file_handler_util::CreateFileEntry( | |
| 548 Profile::FromBrowserContext(browser_context()), | |
| 549 extension(), | |
| 550 render_frame_host()->GetProcess()->GetID(), | |
| 551 log_path, | |
| 552 false); | |
| 553 | |
| 554 auto entry = base::MakeUnique<base::DictionaryValue>(); | |
| 555 entry->SetString("fileSystemId", file_entry.filesystem_id); | |
| 556 entry->SetString("baseName", file_entry.registered_name); | |
| 557 entry->SetString("id", file_entry.id); | |
| 558 entry->SetBoolean("isDirectory", false); | |
| 559 auto entry_list = base::MakeUnique<base::ListValue>(); | |
| 560 entry_list->Append(std::move(entry)); | |
| 561 response->Set("entries", std::move(entry_list)); | |
| 562 response->SetBoolean("multiple", false); | |
| 563 SetResult(std::move(response)); | |
| 564 SendResponse(succeeded); | |
| 565 } | |
| 566 | |
| 567 } // namespace extensions | |
| OLD | NEW |