Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/extensions/api/log_private/log_private_api.h" | 5 #include "chrome/browser/extensions/api/log_private/log_private_api.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/command_line.h" | |
| 10 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
| 11 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 12 #include "base/logging.h" | 13 #include "base/logging.h" |
| 13 #include "base/memory/linked_ptr.h" | 14 #include "base/memory/linked_ptr.h" |
| 14 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
| 15 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/download/download_prefs.h" | |
| 18 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" | |
| 16 #include "chrome/browser/extensions/api/log_private/filter_handler.h" | 19 #include "chrome/browser/extensions/api/log_private/filter_handler.h" |
| 17 #include "chrome/browser/extensions/api/log_private/log_parser.h" | 20 #include "chrome/browser/extensions/api/log_private/log_parser.h" |
| 18 #include "chrome/browser/extensions/api/log_private/syslog_parser.h" | 21 #include "chrome/browser/extensions/api/log_private/syslog_parser.h" |
| 19 #include "chrome/browser/feedback/system_logs/scrubbed_system_logs_fetcher.h" | 22 #include "chrome/browser/feedback/system_logs/scrubbed_system_logs_fetcher.h" |
| 20 #include "chrome/browser/io_thread.h" | 23 #include "chrome/browser/io_thread.h" |
| 21 #include "chrome/browser/net/chrome_net_log.h" | 24 #include "chrome/browser/net/chrome_net_log.h" |
| 22 #include "chrome/browser/profiles/profile.h" | 25 #include "chrome/browser/profiles/profile.h" |
| 23 #include "chrome/common/extensions/api/log_private.h" | 26 #include "chrome/common/extensions/api/log_private.h" |
| 27 #include "chrome/common/logging_chrome.h" | |
| 28 #include "content/public/browser/render_process_host.h" | |
| 24 #include "extensions/browser/event_router.h" | 29 #include "extensions/browser/event_router.h" |
| 25 #include "extensions/browser/extension_function.h" | 30 #include "extensions/browser/extension_function.h" |
| 26 #include "extensions/browser/extension_registry.h" | 31 #include "extensions/browser/extension_registry.h" |
| 32 #include "extensions/browser/granted_file_entry.h" | |
| 33 | |
| 34 #if defined(OS_CHROMEOS) | |
| 35 #include "chrome/browser/chromeos/system_logs/debug_log_writer.h" | |
| 36 #endif | |
| 27 | 37 |
| 28 using content::BrowserThread; | 38 using content::BrowserThread; |
| 29 | 39 |
| 30 namespace events { | 40 namespace events { |
| 31 const char kOnAddNetInternalsEntries[] = "logPrivate.onAddNetInternalsEntries"; | 41 const char kOnAddNetInternalsEntries[] = "logPrivate.onAddNetInternalsEntries"; |
| 32 } // namespace events | 42 } // namespace events |
| 33 | 43 |
| 34 namespace extensions { | 44 namespace extensions { |
| 35 namespace { | 45 namespace { |
| 36 | 46 |
| 47 const char kLogFileNameBase[] = "net-internals"; | |
| 37 const int kNetLogEventDelayMilliseconds = 100; | 48 const int kNetLogEventDelayMilliseconds = 100; |
| 38 | 49 |
| 39 scoped_ptr<LogParser> CreateLogParser(const std::string& log_type) { | 50 scoped_ptr<LogParser> CreateLogParser(const std::string& log_type) { |
| 40 if (log_type == "syslog") | 51 if (log_type == "syslog") |
| 41 return scoped_ptr<LogParser>(new SyslogParser()); | 52 return scoped_ptr<LogParser>(new SyslogParser()); |
| 42 // TODO(shinfan): Add more parser here | 53 // TODO(shinfan): Add more parser here |
| 43 | 54 |
| 44 NOTREACHED() << "Invalid log type: " << log_type; | 55 NOTREACHED() << "Invalid log type: " << log_type; |
| 45 return scoped_ptr<LogParser>(); | 56 return scoped_ptr<LogParser>(); |
| 46 } | 57 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 64 } // namespace | 75 } // namespace |
| 65 | 76 |
| 66 // static | 77 // static |
| 67 LogPrivateAPI* LogPrivateAPI::Get(content::BrowserContext* context) { | 78 LogPrivateAPI* LogPrivateAPI::Get(content::BrowserContext* context) { |
| 68 return GetFactoryInstance()->Get(context); | 79 return GetFactoryInstance()->Get(context); |
| 69 } | 80 } |
| 70 | 81 |
| 71 LogPrivateAPI::LogPrivateAPI(content::BrowserContext* context) | 82 LogPrivateAPI::LogPrivateAPI(content::BrowserContext* context) |
| 72 : browser_context_(context), | 83 : browser_context_(context), |
| 73 logging_net_internals_(false), | 84 logging_net_internals_(false), |
| 85 event_sink_(LogPrivateAPI::REPORT_EVENTS_TO_EXTENSION), | |
| 74 extension_registry_observer_(this) { | 86 extension_registry_observer_(this) { |
| 75 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | 87 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); |
| 76 } | 88 } |
| 77 | 89 |
| 78 LogPrivateAPI::~LogPrivateAPI() { | 90 LogPrivateAPI::~LogPrivateAPI() { |
| 79 } | 91 } |
| 80 | 92 |
| 81 void LogPrivateAPI::StartNetInternalsWatch(const std::string& extension_id) { | 93 void LogPrivateAPI::StartNetInternalsWatch( |
| 94 const std::string& extension_id, | |
| 95 LogPrivateAPI::CapturedEventsSink event_sink) { | |
| 82 net_internal_watches_.insert(extension_id); | 96 net_internal_watches_.insert(extension_id); |
| 83 BrowserThread::PostTask( | 97 BrowserThread::PostTask( |
| 84 BrowserThread::IO, FROM_HERE, | 98 BrowserThread::IO, FROM_HERE, |
| 85 base::Bind(&LogPrivateAPI::MaybeStartNetInternalLogging, | 99 base::Bind(&LogPrivateAPI::MaybeStartNetInternalLogging, |
| 86 base::Unretained(this))); | 100 base::Unretained(this), |
| 101 event_sink)); | |
| 87 } | 102 } |
| 88 | 103 |
| 89 void LogPrivateAPI::StopNetInternalsWatch(const std::string& extension_id) { | 104 void LogPrivateAPI::StopNetInternalsWatch(const std::string& extension_id, |
| 105 const base::Closure& closure) { | |
| 90 net_internal_watches_.erase(extension_id); | 106 net_internal_watches_.erase(extension_id); |
| 91 MaybeStopNetInternalLogging(); | 107 MaybeStopNetInternalLogging(closure); |
| 108 } | |
| 109 | |
| 110 void LogPrivateAPI::StopAllWatches(const std::string& extension_id, | |
| 111 const base::Closure& closure) { | |
| 112 StopNetInternalsWatch(extension_id, closure); | |
| 92 } | 113 } |
| 93 | 114 |
| 94 static base::LazyInstance<BrowserContextKeyedAPIFactory<LogPrivateAPI> > | 115 static base::LazyInstance<BrowserContextKeyedAPIFactory<LogPrivateAPI> > |
| 95 g_factory = LAZY_INSTANCE_INITIALIZER; | 116 g_factory = LAZY_INSTANCE_INITIALIZER; |
| 96 | 117 |
| 97 // static | 118 // static |
| 98 BrowserContextKeyedAPIFactory<LogPrivateAPI>* | 119 BrowserContextKeyedAPIFactory<LogPrivateAPI>* |
| 99 LogPrivateAPI::GetFactoryInstance() { | 120 LogPrivateAPI::GetFactoryInstance() { |
| 100 return g_factory.Pointer(); | 121 return g_factory.Pointer(); |
| 101 } | 122 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 128 // Create the event's arguments value. | 149 // Create the event's arguments value. |
| 129 scoped_ptr<base::ListValue> event_args(new base::ListValue()); | 150 scoped_ptr<base::ListValue> event_args(new base::ListValue()); |
| 130 event_args->Append(value->DeepCopy()); | 151 event_args->Append(value->DeepCopy()); |
| 131 scoped_ptr<Event> event(new Event(events::kOnAddNetInternalsEntries, | 152 scoped_ptr<Event> event(new Event(events::kOnAddNetInternalsEntries, |
| 132 event_args.Pass())); | 153 event_args.Pass())); |
| 133 EventRouter::Get(browser_context_) | 154 EventRouter::Get(browser_context_) |
| 134 ->DispatchEventToExtension(*ix, event.Pass()); | 155 ->DispatchEventToExtension(*ix, event.Pass()); |
| 135 } | 156 } |
| 136 } | 157 } |
| 137 | 158 |
| 138 void LogPrivateAPI::MaybeStartNetInternalLogging() { | 159 void LogPrivateAPI::MaybeStartNetInternalLogging( |
| 160 LogPrivateAPI::CapturedEventsSink event_sink) { | |
| 139 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 161 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 140 if (!logging_net_internals_) { | 162 if (!logging_net_internals_) { |
| 141 g_browser_process->io_thread()->net_log()->AddThreadSafeObserver( | |
| 142 this, net::NetLog::LOG_ALL_BUT_BYTES); | |
| 143 logging_net_internals_ = true; | 163 logging_net_internals_ = true; |
| 164 event_sink_ = event_sink; | |
| 165 switch (event_sink_) { | |
| 166 case REPORT_EVENTS_TO_EXTENSION: { | |
| 167 g_browser_process->io_thread()->net_log()->AddThreadSafeObserver( | |
| 168 this, net::NetLog::LOG_ALL_BUT_BYTES); | |
| 169 break; | |
| 170 } | |
| 171 case RECORD_EVENTS_TO_FILE: { | |
| 172 base::FilePath file_path = | |
| 173 logging::GetSessionLogDir( | |
| 174 *CommandLine::ForCurrentProcess()).Append(kLogFileNameBase); | |
| 175 file_path = logging::GenerateTimestampedName(file_path, | |
| 176 base::Time::Now()); | |
| 177 FILE* file = NULL; | |
| 178 file = fopen(file_path.value().c_str(), "w"); | |
| 179 if (file == NULL) { | |
| 180 LOG(ERROR) << "Could not open file " << file_path.value() | |
|
xiaowenx
2014/06/25 05:30:44
Does zork's comment earlier about VLOG(1) also app
zel
2014/06/27 19:31:01
same answer
| |
| 181 << " for net logging"; | |
| 182 } else { | |
| 183 scoped_ptr<base::Value> constants(net::NetLogLogger::GetConstants()); | |
| 184 net_log_logger_.reset(new net::NetLogLogger(file, *constants)); | |
| 185 net_log_logger_->set_log_level(net::NetLog::LOG_ALL_BUT_BYTES); | |
| 186 net_log_logger_->StartObserving( | |
| 187 g_browser_process->io_thread()->net_log()); | |
| 188 } | |
| 189 break; | |
| 190 } | |
|
xiaowenx
2014/06/25 05:30:44
Do you want to add in: "default: NOTREACHED()" to
Zachary Kuznia
2014/06/25 18:39:03
Switches with enums generate a compile error if ca
zel
2014/06/27 19:31:01
Yep. We prefer failing in compile time vs. runtime
| |
| 191 } | |
| 144 } | 192 } |
| 145 } | 193 } |
| 146 | 194 |
| 147 void LogPrivateAPI::MaybeStopNetInternalLogging() { | 195 void LogPrivateAPI::MaybeStopNetInternalLogging(const base::Closure& closure) { |
| 148 if (net_internal_watches_.empty()) { | 196 if (net_internal_watches_.empty()) { |
| 149 BrowserThread::PostTask( | 197 BrowserThread::PostTaskAndReply( |
| 150 BrowserThread::IO, FROM_HERE, | 198 BrowserThread::IO, FROM_HERE, |
| 151 base::Bind(&LogPrivateAPI:: StopNetInternalLogging, | 199 base::Bind(&LogPrivateAPI:: StopNetInternalLogging, |
| 152 base::Unretained(this))); | 200 base::Unretained(this)), |
| 201 closure); | |
| 153 } | 202 } |
| 154 } | 203 } |
| 155 | 204 |
| 156 void LogPrivateAPI::StopNetInternalLogging() { | 205 void LogPrivateAPI::StopNetInternalLogging() { |
| 157 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 206 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 158 if (net_log() && logging_net_internals_) { | 207 if (net_log() && logging_net_internals_) { |
| 159 net_log()->RemoveThreadSafeObserver(this); | |
| 160 logging_net_internals_ = false; | 208 logging_net_internals_ = false; |
| 209 switch (event_sink_) { | |
| 210 case REPORT_EVENTS_TO_EXTENSION: | |
| 211 net_log()->RemoveThreadSafeObserver(this); | |
| 212 break; | |
| 213 case RECORD_EVENTS_TO_FILE: | |
| 214 net_log_logger_->StopObserving(); | |
| 215 net_log_logger_.reset(); | |
| 216 break; | |
|
xiaowenx
2014/06/25 05:30:44
Same as above, do you want to add a default case?
zel
2014/06/27 19:31:01
same as above
| |
| 217 } | |
| 161 } | 218 } |
| 162 } | 219 } |
| 163 | 220 |
| 164 void LogPrivateAPI::OnExtensionUnloaded( | 221 void LogPrivateAPI::OnExtensionUnloaded( |
| 165 content::BrowserContext* browser_context, | 222 content::BrowserContext* browser_context, |
| 166 const Extension* extension, | 223 const Extension* extension, |
| 167 UnloadedExtensionInfo::Reason reason) { | 224 UnloadedExtensionInfo::Reason reason) { |
| 168 StopNetInternalsWatch(extension->id()); | 225 StopNetInternalsWatch(extension->id(), base::Closure()); |
| 169 } | 226 } |
| 170 | 227 |
| 171 LogPrivateGetHistoricalFunction::LogPrivateGetHistoricalFunction() { | 228 LogPrivateGetHistoricalFunction::LogPrivateGetHistoricalFunction() { |
| 172 } | 229 } |
| 173 | 230 |
| 174 LogPrivateGetHistoricalFunction::~LogPrivateGetHistoricalFunction() { | 231 LogPrivateGetHistoricalFunction::~LogPrivateGetHistoricalFunction() { |
| 175 } | 232 } |
| 176 | 233 |
| 177 bool LogPrivateGetHistoricalFunction::RunAsync() { | 234 bool LogPrivateGetHistoricalFunction::RunAsync() { |
| 178 // Get parameters | 235 // Get parameters |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 | 267 |
| 211 LogPrivateStartNetInternalsWatchFunction:: | 268 LogPrivateStartNetInternalsWatchFunction:: |
| 212 LogPrivateStartNetInternalsWatchFunction() { | 269 LogPrivateStartNetInternalsWatchFunction() { |
| 213 } | 270 } |
| 214 | 271 |
| 215 LogPrivateStartNetInternalsWatchFunction:: | 272 LogPrivateStartNetInternalsWatchFunction:: |
| 216 ~LogPrivateStartNetInternalsWatchFunction() { | 273 ~LogPrivateStartNetInternalsWatchFunction() { |
| 217 } | 274 } |
| 218 | 275 |
| 219 bool LogPrivateStartNetInternalsWatchFunction::RunSync() { | 276 bool LogPrivateStartNetInternalsWatchFunction::RunSync() { |
| 220 LogPrivateAPI::Get(GetProfile())->StartNetInternalsWatch(extension_id()); | 277 LogPrivateAPI::Get(GetProfile())->StartNetInternalsWatch( |
| 278 extension_id(), | |
| 279 LogPrivateAPI::REPORT_EVENTS_TO_EXTENSION); | |
| 221 return true; | 280 return true; |
| 222 } | 281 } |
| 223 | 282 |
| 224 LogPrivateStopNetInternalsWatchFunction:: | 283 LogPrivateStopNetInternalsWatchFunction:: |
| 225 LogPrivateStopNetInternalsWatchFunction() { | 284 LogPrivateStopNetInternalsWatchFunction() { |
| 226 } | 285 } |
| 227 | 286 |
| 228 LogPrivateStopNetInternalsWatchFunction:: | 287 LogPrivateStopNetInternalsWatchFunction:: |
| 229 ~LogPrivateStopNetInternalsWatchFunction() { | 288 ~LogPrivateStopNetInternalsWatchFunction() { |
| 230 } | 289 } |
| 231 | 290 |
| 232 bool LogPrivateStopNetInternalsWatchFunction::RunSync() { | 291 bool LogPrivateStopNetInternalsWatchFunction::RunSync() { |
| 233 LogPrivateAPI::Get(GetProfile())->StopNetInternalsWatch(extension_id()); | 292 LogPrivateAPI::Get(GetProfile())->StopNetInternalsWatch(extension_id(), |
| 293 base::Closure()); | |
| 234 return true; | 294 return true; |
| 235 } | 295 } |
| 236 | 296 |
| 297 LogPrivateStartEventRecorderFunction::LogPrivateStartEventRecorderFunction() { | |
| 298 } | |
| 299 | |
| 300 LogPrivateStartEventRecorderFunction::~LogPrivateStartEventRecorderFunction() { | |
| 301 } | |
| 302 | |
| 303 bool LogPrivateStartEventRecorderFunction::RunSync() { | |
| 304 scoped_ptr<api::log_private::StartEventRecorder::Params> params( | |
| 305 api::log_private::StartEventRecorder::Params::Create(*args_)); | |
| 306 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
| 307 if (params->type == api::log_private::EVENT_TYPE_NETWORK) { | |
|
Zachary Kuznia
2014/06/25 00:05:53
params->type should be generated as an enum, so if
| |
| 308 LogPrivateAPI::Get(GetProfile())->StartNetInternalsWatch( | |
| 309 extension_id(), | |
| 310 LogPrivateAPI::RECORD_EVENTS_TO_FILE); | |
|
xiaowenx
2014/06/25 05:30:44
We always want network events to be saved to a fil
zel
2014/06/27 19:31:01
For this API call - yes. Those files are aggregate
| |
| 311 } else { | |
| 312 NOTREACHED(); | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 return true; | |
| 317 } | |
| 318 | |
| 319 LogPrivateStopEventRecorderFunction::LogPrivateStopEventRecorderFunction() { | |
| 320 } | |
| 321 | |
| 322 LogPrivateStopEventRecorderFunction::~LogPrivateStopEventRecorderFunction() { | |
| 323 } | |
| 324 | |
| 325 bool LogPrivateStopEventRecorderFunction::RunSync() { | |
| 326 scoped_ptr<api::log_private::StartEventRecorder::Params> params( | |
|
xiaowenx
2014/06/25 05:30:44
Should this say "StopEventRecorder::Params" instea
zel
2014/06/27 19:31:01
Good catch. They happen to be the same by accident
| |
| 327 api::log_private::StartEventRecorder::Params::Create(*args_)); | |
| 328 EXTENSION_FUNCTION_VALIDATE(params.get()); | |
| 329 if (params->type == api::log_private::EVENT_TYPE_NETWORK) { | |
| 330 LogPrivateAPI::Get(GetProfile())->StopNetInternalsWatch(extension_id(), | |
| 331 base::Closure()); | |
| 332 } else { | |
| 333 NOTREACHED(); | |
| 334 return false; | |
| 335 } | |
| 336 return true; | |
| 337 } | |
| 338 | |
| 339 LogPrivateDumpLogsFunction::LogPrivateDumpLogsFunction() { | |
| 340 } | |
| 341 | |
| 342 LogPrivateDumpLogsFunction::~LogPrivateDumpLogsFunction() { | |
| 343 } | |
| 344 | |
| 345 bool LogPrivateDumpLogsFunction::RunAsync() { | |
| 346 LogPrivateAPI::Get(Profile::FromBrowserContext(browser_context()))-> | |
| 347 StopAllWatches( | |
| 348 extension_id(), | |
| 349 base::Bind(&LogPrivateDumpLogsFunction::OnStopAllWatches, this)); | |
| 350 return true; | |
| 351 } | |
| 352 | |
| 353 void LogPrivateDumpLogsFunction::OnStopAllWatches() { | |
| 354 const DownloadPrefs* const prefs = | |
| 355 DownloadPrefs::FromBrowserContext(browser_context()); | |
| 356 chromeos::DebugLogWriter::StoreLogs( | |
| 357 prefs->DownloadPath(), | |
| 358 base::Bind(&LogPrivateDumpLogsFunction::OnStoreLogsCompleted, | |
| 359 this)); | |
| 360 } | |
| 361 | |
| 362 void LogPrivateDumpLogsFunction::OnStoreLogsCompleted( | |
| 363 const base::FilePath& log_path, bool succeeded) { | |
| 364 | |
| 365 scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue()); | |
| 366 extensions::GrantedFileEntry file_entry = | |
| 367 extensions::app_file_handler_util::CreateFileEntry( | |
| 368 Profile::FromBrowserContext(browser_context()), | |
| 369 GetExtension(), | |
| 370 render_view_host_->GetProcess()->GetID(), | |
| 371 log_path, | |
| 372 false); | |
| 373 | |
| 374 base::DictionaryValue* entry = new base::DictionaryValue(); | |
| 375 entry->SetString("fileSystemId", file_entry.filesystem_id); | |
| 376 entry->SetString("baseName", file_entry.registered_name); | |
| 377 entry->SetString("id", file_entry.id); | |
| 378 entry->SetBoolean("isDirectory", false); | |
| 379 response->Set("entry", entry); | |
| 380 SetResult(response.release()); | |
| 381 SendResponse(succeeded); | |
| 382 } | |
| 383 | |
| 384 | |
| 237 } // namespace extensions | 385 } // namespace extensions |
| OLD | NEW |