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

Unified Diff: components/net_log/net_log_file_writer.cc

Issue 2603523002: Move net-export thread-hopping code into NetLogFileWriter and add IO polled data. (Closed)
Patch Set: Fixed tommycli's nits from patchset 13 Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/net_log/net_log_file_writer.h ('k') | components/net_log/net_log_file_writer_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/net_log/net_log_file_writer.cc
diff --git a/components/net_log/net_log_file_writer.cc b/components/net_log/net_log_file_writer.cc
index db51ca7d2df294065553ee94c372e6bc0723a7e3..344edf03d16602644fdbb9d280ddd544b5eed5aa 100644
--- a/components/net_log/net_log_file_writer.cc
+++ b/components/net_log/net_log_file_writer.cc
@@ -6,20 +6,28 @@
#include <utility>
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/net_log/chrome_net_log.h"
-#include "net/log/write_to_file_net_log_observer.h"
+#include "net/log/file_net_log_observer.h"
+#include "net/log/net_log_util.h"
+#include "net/url_request/url_request_context_getter.h"
namespace net_log {
-// Path of logs if relative to default temporary directory of
+// Path of logs relative to default temporary directory given by
// base::GetTempDir(). Must be kept in sync with
-// chrome/android/java/res/xml/file_paths.xml. Only used if
-// not saving log file to a custom path.
+// chrome/android/java/res/xml/file_paths.xml. Only used if not saving log file
+// to a custom path.
base::FilePath::CharType kLogRelativePath[] =
FILE_PATH_LITERAL("net-export/chrome-net-export-log.json");
@@ -28,219 +36,349 @@ base::FilePath::CharType kLogRelativePath[] =
base::FilePath::CharType kOldLogRelativePath[] =
FILE_PATH_LITERAL("chrome-net-export-log.json");
+// Adds net info from net::GetNetInfo() to |polled_data|. Must run on the
+// |net_task_runner_| of NetLogFileWriter.
+std::unique_ptr<base::DictionaryValue> AddNetInfo(
+ scoped_refptr<net::URLRequestContextGetter> context_getter,
+ std::unique_ptr<base::DictionaryValue> polled_data) {
+ DCHECK(context_getter);
+ std::unique_ptr<base::DictionaryValue> net_info = net::GetNetInfo(
+ context_getter->GetURLRequestContext(), net::NET_INFO_ALL_SOURCES);
+ if (polled_data)
+ net_info->MergeDictionary(polled_data.get());
+ return net_info;
+}
+
+// If running on a POSIX OS, this will attempt to set all the permission flags
+// of the file at |path| to 1. Will return |path| on success and the empty path
+// on failure.
+base::FilePath GetPathWithAllPermissions(const base::FilePath& path) {
+ if (!base::PathExists(path))
+ return base::FilePath();
+#if defined(OS_POSIX)
+ return base::SetPosixFilePermissions(path, base::FILE_PERMISSION_MASK)
+ ? path
+ : base::FilePath();
+#else
+ return path;
+#endif
+}
+
+NetLogFileWriter::NetLogFileWriter(
+ ChromeNetLog* chrome_net_log,
+ const base::CommandLine::StringType& command_line_string,
+ const std::string& channel_string)
+ : state_(STATE_UNINITIALIZED),
+ log_exists_(false),
+ log_capture_mode_known_(false),
+ log_capture_mode_(net::NetLogCaptureMode::Default()),
+ chrome_net_log_(chrome_net_log),
+ command_line_string_(command_line_string),
+ channel_string_(channel_string),
+ default_log_base_directory_getter_(base::Bind(&base::GetTempDir)),
+ weak_ptr_factory_(this) {}
+
NetLogFileWriter::~NetLogFileWriter() {
if (write_to_file_observer_)
- write_to_file_observer_->StopObserving(nullptr);
+ write_to_file_observer_->StopObserving(nullptr, base::Bind([] {}));
}
-void NetLogFileWriter::ProcessCommand(Command command) {
+void NetLogFileWriter::StartNetLog(const base::FilePath& log_path,
+ net::NetLogCaptureMode capture_mode,
+ const StateCallback& state_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (!EnsureInit())
- return;
- switch (command) {
- case DO_START_LOG_BYTES:
- StartNetLog(LOG_TYPE_LOG_BYTES);
- break;
- case DO_START:
- StartNetLog(LOG_TYPE_NORMAL);
- break;
- case DO_START_STRIP_PRIVATE_DATA:
- StartNetLog(LOG_TYPE_STRIP_PRIVATE_DATA);
- break;
- case DO_STOP:
- StopNetLog();
- break;
- default:
- NOTREACHED();
- break;
+ EnsureInitThenRun(
+ base::Bind(&NetLogFileWriter::StartNetLogAfterInitialized,
+ weak_ptr_factory_.GetWeakPtr(), log_path, capture_mode),
+ state_callback);
+}
+
+void NetLogFileWriter::StopNetLog(
+ std::unique_ptr<base::DictionaryValue> polled_data,
+ scoped_refptr<net::URLRequestContextGetter> context_getter,
+ const StateCallback& state_callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(net_task_runner_);
+ if (state_ == STATE_LOGGING) {
+ // Stopping the log requires first grabbing the net info on the net thread.
+ // Before posting that task to the net thread, change the state to
+ // STATE_STOP_LOGGING so that if the NetLogFileWriter receives a command
+ // while the net info is being retrieved on the net thread, the state can be
+ // checked and the command can be ignored. It's the responsibility of the
+ // commands (StartNetLog(), StopNetLog(), GetState()) to check the state
+ // before performing their actions.
+ state_ = STATE_STOPPING_LOG;
+
+ // StopLogging() will always execute its state callback asynchronously,
+ // which means |state_callback| will always be executed asynchronously
+ // relative to the StopNetLog() call regardless of how StopLogging() is
+ // called here.
+
+ if (context_getter) {
+ base::PostTaskAndReplyWithResult(
+ net_task_runner_.get(), FROM_HERE,
+ base::Bind(&AddNetInfo, context_getter, base::Passed(&polled_data)),
+ base::Bind(&NetLogFileWriter::StopNetLogAfterAddNetInfo,
+ weak_ptr_factory_.GetWeakPtr(), state_callback));
+ } else {
+ StopNetLogAfterAddNetInfo(state_callback, std::move(polled_data));
+ }
+ } else {
+ // No-op; just run |state_callback| asynchronously.
+ RunStateCallbackAsync(state_callback);
}
}
-bool NetLogFileWriter::GetFilePath(base::FilePath* path) {
+void NetLogFileWriter::GetState(const StateCallback& state_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (log_type_ == LOG_TYPE_NONE || state_ == STATE_LOGGING)
- return false;
+ EnsureInitThenRun(base::Bind([] {}), state_callback);
+}
- if (!NetExportLogExists())
- return false;
+void NetLogFileWriter::GetFilePathToCompletedLog(
+ const FilePathCallback& path_callback) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!log_exists_ || state_ == STATE_LOGGING) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(path_callback, base::FilePath()));
+ return;
+ }
+ DCHECK(file_task_runner_);
DCHECK(!log_path_.empty());
-#if defined(OS_POSIX)
- // Users, group and others can read, write and traverse.
- int mode = base::FILE_PERMISSION_MASK;
- base::SetPosixFilePermissions(log_path_, mode);
-#endif // defined(OS_POSIX)
- *path = log_path_;
- return true;
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE,
+ base::Bind(&GetPathWithAllPermissions, log_path_), path_callback);
}
-base::DictionaryValue* NetLogFileWriter::GetState() {
+void NetLogFileWriter::SetTaskRunners(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> net_task_runner) {
DCHECK(thread_checker_.CalledOnValidThread());
- base::DictionaryValue* dict = new base::DictionaryValue;
+ if (file_task_runner_)
+ DCHECK_EQ(file_task_runner, file_task_runner_);
+ file_task_runner_ = file_task_runner;
- EnsureInit();
-
-#ifndef NDEBUG
- dict->SetString("file", log_path_.LossyDisplayName());
-#endif // NDEBUG
+ if (net_task_runner_)
+ DCHECK_EQ(net_task_runner, net_task_runner_);
+ net_task_runner_ = net_task_runner;
+}
- switch (state_) {
- case STATE_NOT_LOGGING:
- dict->SetString("state", "NOT_LOGGING");
- break;
- case STATE_LOGGING:
- dict->SetString("state", "LOGGING");
- break;
- case STATE_UNINITIALIZED:
- dict->SetString("state", "UNINITIALIZED");
- break;
+std::string NetLogFileWriter::CaptureModeToString(
+ net::NetLogCaptureMode capture_mode) {
+ if (capture_mode == net::NetLogCaptureMode::Default()) {
+ return "STRIP_PRIVATE_DATA";
+ } else if (capture_mode ==
+ net::NetLogCaptureMode::IncludeCookiesAndCredentials()) {
+ return "NORMAL";
+ } else if (capture_mode == net::NetLogCaptureMode::IncludeSocketBytes()) {
+ return "LOG_BYTES";
+ } else {
+ NOTREACHED();
+ return "STRIP_PRIVATE_DATA";
}
+}
- switch (log_type_) {
- case LOG_TYPE_NONE:
- dict->SetString("logType", "NONE");
- break;
- case LOG_TYPE_UNKNOWN:
- dict->SetString("logType", "UNKNOWN");
- break;
- case LOG_TYPE_LOG_BYTES:
- dict->SetString("logType", "LOG_BYTES");
- break;
- case LOG_TYPE_NORMAL:
- dict->SetString("logType", "NORMAL");
- break;
- case LOG_TYPE_STRIP_PRIVATE_DATA:
- dict->SetString("logType", "STRIP_PRIVATE_DATA");
- break;
+net::NetLogCaptureMode NetLogFileWriter::CaptureModeFromString(
+ const std::string& capture_mode_string) {
+ if (capture_mode_string == "STRIP_PRIVATE_DATA") {
+ return net::NetLogCaptureMode::Default();
+ } else if (capture_mode_string == "NORMAL") {
+ return net::NetLogCaptureMode::IncludeCookiesAndCredentials();
+ } else if (capture_mode_string == "LOG_BYTES") {
+ return net::NetLogCaptureMode::IncludeSocketBytes();
+ } else {
+ NOTREACHED();
+ return net::NetLogCaptureMode::Default();
}
-
- return dict;
}
-NetLogFileWriter::NetLogFileWriter(
- ChromeNetLog* chrome_net_log,
- const base::CommandLine::StringType& command_line_string,
- const std::string& channel_string)
- : state_(STATE_UNINITIALIZED),
- log_type_(LOG_TYPE_NONE),
- chrome_net_log_(chrome_net_log),
- command_line_string_(command_line_string),
- channel_string_(channel_string) {
- // NetLogFileWriter can be created on one thread and used on another.
- thread_checker_.DetachFromThread();
+void NetLogFileWriter::SetDefaultLogBaseDirectoryGetterForTest(
+ const DirectoryGetter& getter) {
+ default_log_base_directory_getter_ = getter;
}
-bool NetLogFileWriter::GetNetExportLogBaseDirectory(
- base::FilePath* path) const {
+void NetLogFileWriter::EnsureInitThenRun(
+ const base::Closure& after_successful_init_callback,
+ const StateCallback& state_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- return base::GetTempDir(path);
-}
-
-net::NetLogCaptureMode NetLogFileWriter::GetCaptureModeForLogType(
- LogType log_type) {
- switch (log_type) {
- case LOG_TYPE_LOG_BYTES:
- return net::NetLogCaptureMode::IncludeSocketBytes();
- case LOG_TYPE_NORMAL:
- return net::NetLogCaptureMode::IncludeCookiesAndCredentials();
- case LOG_TYPE_STRIP_PRIVATE_DATA:
- return net::NetLogCaptureMode::Default();
- case LOG_TYPE_NONE:
- case LOG_TYPE_UNKNOWN:
- NOTREACHED();
+
+ if (state_ == STATE_UNINITIALIZED) {
+ state_ = STATE_INITIALIZING;
+ // Run initialization tasks on the file thread, then the main thread. Once
+ // finished, run |after_successful_init_callback| and |state_callback| on
+ // the main thread.
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE,
+ base::Bind(&NetLogFileWriter::SetUpDefaultLogPath,
+ default_log_base_directory_getter_),
+ base::Bind(&NetLogFileWriter::SetStateAfterSetUpDefaultLogPathThenRun,
+ weak_ptr_factory_.GetWeakPtr(),
+ after_successful_init_callback, state_callback));
+ } else if (state_ == STATE_INITIALIZING) {
+ // If NetLogFileWriter is already in the process of initializing due to a
+ // previous call to EnsureInitThenRun(), commands received by
+ // NetLogFileWriter should be ignored, so only |state_callback| will be
+ // executed.
+ // Wait for the in-progress initialization to finish before calling
+ // |state_callback|. To do this, post a dummy task to the file thread
+ // (which is guaranteed to run after the tasks belonging to the
+ // in-progress initialization have finished), and have that dummy task
+ // post |state_callback| as a reply on the main thread.
+ file_task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind([] {}),
+ base::Bind(&NetLogFileWriter::RunStateCallback,
+ weak_ptr_factory_.GetWeakPtr(), state_callback));
+
+ } else {
+ // NetLogFileWriter is already fully initialized. Run
+ // |after_successful_init_callback| synchronously and |state_callback|
+ // asynchronously.
+ after_successful_init_callback.Run();
+ RunStateCallbackAsync(state_callback);
}
- return net::NetLogCaptureMode::Default();
}
-bool NetLogFileWriter::EnsureInit() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != STATE_UNINITIALIZED)
- return true;
+NetLogFileWriter::DefaultLogPathResults NetLogFileWriter::SetUpDefaultLogPath(
+ const DirectoryGetter& default_log_base_directory_getter) {
+ DefaultLogPathResults results;
+ results.default_log_path_success = false;
+ results.log_exists = false;
- if (log_path_.empty() && !SetUpDefaultNetExportLogPath())
- return false;
+ base::FilePath default_base_dir;
+ if (!default_log_base_directory_getter.Run(&default_base_dir))
+ return results;
- state_ = STATE_NOT_LOGGING;
- if (NetExportLogExists())
- log_type_ = LOG_TYPE_UNKNOWN;
- else
- log_type_ = LOG_TYPE_NONE;
+ // Delete log file at old location, if present.
+ base::DeleteFile(default_base_dir.Append(kOldLogRelativePath), false);
+
+ results.default_log_path = default_base_dir.Append(kLogRelativePath);
+ if (!base::CreateDirectoryAndGetError(results.default_log_path.DirName(),
+ nullptr))
+ return results;
- return true;
+ results.log_exists = base::PathExists(results.default_log_path);
+ results.default_log_path_success = true;
+ return results;
}
-void NetLogFileWriter::StartNetLog(LogType log_type) {
+void NetLogFileWriter::SetStateAfterSetUpDefaultLogPathThenRun(
+ const base::Closure& after_successful_init_callback,
+ const StateCallback& state_callback,
+ const DefaultLogPathResults& set_up_default_log_path_results) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ == STATE_LOGGING)
- return;
+ DCHECK_EQ(state_, STATE_INITIALIZING);
- DCHECK_NE(STATE_UNINITIALIZED, state_);
- DCHECK(!log_path_.empty());
+ if (set_up_default_log_path_results.default_log_path_success) {
+ state_ = STATE_NOT_LOGGING;
+ log_path_ = set_up_default_log_path_results.default_log_path;
+ log_exists_ = set_up_default_log_path_results.log_exists;
+ DCHECK(!log_capture_mode_known_);
- // Try to make sure we can create the file.
- // TODO(rtenneti): Find a better for doing the following. Surface some error
- // to the user if we couldn't create the file.
- base::ScopedFILE file(base::OpenFile(log_path_, "w"));
- if (!file)
- return;
+ after_successful_init_callback.Run();
+ } else {
+ state_ = STATE_UNINITIALIZED;
+ }
- log_type_ = log_type;
- state_ = STATE_LOGGING;
+ RunStateCallback(state_callback);
+}
- std::unique_ptr<base::Value> constants(
- ChromeNetLog::GetConstants(command_line_string_, channel_string_));
- write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
- write_to_file_observer_->set_capture_mode(GetCaptureModeForLogType(log_type));
- write_to_file_observer_->StartObserving(chrome_net_log_, std::move(file),
- constants.get(), nullptr);
+void NetLogFileWriter::RunStateCallback(
+ const StateCallback& state_callback) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ state_callback.Run(GetState());
}
-void NetLogFileWriter::StopNetLog() {
+void NetLogFileWriter::RunStateCallbackAsync(
+ const StateCallback& state_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (state_ != STATE_LOGGING)
- return;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&NetLogFileWriter::RunStateCallback,
+ weak_ptr_factory_.GetWeakPtr(), state_callback));
+}
- write_to_file_observer_->StopObserving(nullptr);
- write_to_file_observer_.reset();
- state_ = STATE_NOT_LOGGING;
+void NetLogFileWriter::StartNetLogAfterInitialized(
+ const base::FilePath& log_path,
+ net::NetLogCaptureMode capture_mode) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(state_ != STATE_UNINITIALIZED && state_ != STATE_INITIALIZING);
+ DCHECK(file_task_runner_);
+
+ if (state_ == STATE_NOT_LOGGING) {
+ if (!log_path.empty())
+ log_path_ = log_path;
+
+ DCHECK(!log_path_.empty());
+
+ state_ = STATE_LOGGING;
+ log_exists_ = true;
+ log_capture_mode_known_ = true;
+ log_capture_mode_ = capture_mode;
+
+ std::unique_ptr<base::Value> constants(
+ ChromeNetLog::GetConstants(command_line_string_, channel_string_));
+ write_to_file_observer_ =
+ base::MakeUnique<net::FileNetLogObserver>(file_task_runner_);
+ write_to_file_observer_->StartObservingUnbounded(
+ chrome_net_log_, capture_mode, log_path_, std::move(constants),
+ nullptr);
+ }
}
-void NetLogFileWriter::SetUpNetExportLogPath(
- const base::FilePath& custom_path) {
+void NetLogFileWriter::StopNetLogAfterAddNetInfo(
+ const StateCallback& state_callback,
+ std::unique_ptr<base::DictionaryValue> polled_data) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(state_, STATE_STOPPING_LOG);
- // The directory should always exist because the custom path
- // is taken from a file selector dialog window.
- DCHECK(base::PathExists(custom_path.DirName()));
+ write_to_file_observer_->StopObserving(
+ std::move(polled_data),
+ base::Bind(&NetLogFileWriter::ResetObserverThenSetStateNotLogging,
+ weak_ptr_factory_.GetWeakPtr(), state_callback));
+}
- log_path_ = custom_path;
+void NetLogFileWriter::ResetObserverThenSetStateNotLogging(
+ const StateCallback& state_callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ write_to_file_observer_.reset();
+ state_ = STATE_NOT_LOGGING;
+
+ RunStateCallback(state_callback);
}
-bool NetLogFileWriter::SetUpDefaultNetExportLogPath() {
+std::unique_ptr<base::DictionaryValue> NetLogFileWriter::GetState() const {
DCHECK(thread_checker_.CalledOnValidThread());
- base::FilePath temp_dir;
- if (!GetNetExportLogBaseDirectory(&temp_dir))
- return false;
- // Delete log file at old location, if present.
- DeleteFile(temp_dir.Append(kOldLogRelativePath), false);
+ auto dict = base::MakeUnique<base::DictionaryValue>();
- base::FilePath log_path = temp_dir.Append(kLogRelativePath);
+#ifndef NDEBUG
+ dict->SetString("file", log_path_.LossyDisplayName());
+#endif // NDEBUG
- if (!base::CreateDirectoryAndGetError(log_path.DirName(), nullptr)) {
- return false;
+ switch (state_) {
+ case STATE_UNINITIALIZED:
+ dict->SetString("state", "UNINITIALIZED");
+ break;
+ case STATE_INITIALIZING:
+ dict->SetString("state", "INITIALIZING");
+ break;
+ case STATE_NOT_LOGGING:
+ dict->SetString("state", "NOT_LOGGING");
+ break;
+ case STATE_LOGGING:
+ dict->SetString("state", "LOGGING");
+ break;
+ case STATE_STOPPING_LOG:
+ dict->SetString("state", "STOPPING_LOG");
+ break;
}
- log_path_ = log_path;
- return true;
-}
+ dict->SetBoolean("logExists", log_exists_);
+ dict->SetBoolean("logCaptureModeKnown", log_capture_mode_known_);
+ dict->SetString("captureMode", CaptureModeToString(log_capture_mode_));
-bool NetLogFileWriter::NetExportLogExists() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!log_path_.empty());
- return base::PathExists(log_path_);
+ return dict;
}
} // namespace net_log
« no previous file with comments | « components/net_log/net_log_file_writer.h ('k') | components/net_log/net_log_file_writer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698