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

Side by Side Diff: chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc

Issue 2934163002: Delete the logPrivate APIs (Closed)
Patch Set: Roll back docs changes Created 3 years, 6 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698