#include "chrome/browser/ash/logging/logging.h"
#include <cstdio>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/platform_file.h"
#include "base/files/scoped_file.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/logging/logging_settings.h"
#include "base/posix/eintr_wrapper.h"
#include "base/system/sys_info.h"
#include "base/task/thread_pool.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/zygote_host/zygote_host_linux.h"
namespace ash {
namespace {
bool g_chrome_logging_redirect_tried = false;
bool g_force_log_redirection = false;
template <typename ProcessHost>
void ReinitializeLoggingForProcessHost(ProcessHost* process_host,
const logging::LoggingSettings& settings,
base::PlatformFile raw_log_file_fd) {
static_assert(std::is_same<content::ChildProcessHost, ProcessHost>() ||
std::is_same<content::RenderProcessHost, ProcessHost>());
base::ScopedFD log_file_descriptor(HANDLE_EINTR(dup(raw_log_file_fd)));
if (log_file_descriptor.get() < 0) {
DLOG(WARNING) << "Unable to duplicate log file handle";
return;
}
process_host->ReinitializeLogging(settings.logging_dest,
std::move(log_file_descriptor));
}
void LogFileSetUp(const base::CommandLine& command_line,
const base::FilePath& log_path,
const base::FilePath& target_path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
logging::LoggingSettings settings;
settings.logging_dest = logging::DetermineLoggingDestination(command_line);
settings.log_file_path = log_path.value().c_str();
if (!logging::InitLogging(settings)) {
DLOG(ERROR) << "Unable to initialize logging to " << log_path.value();
base::ThreadPool::PostTask(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&logging::RemoveSymlinkAndLog, log_path, target_path));
return;
}
base::ScopedFILE log_file(logging::DuplicateLogFILE());
base::PlatformFile log_file_fd = fileno(log_file.get());
if (log_file_fd < 0) {
DLOG(WARNING) << "Unable to duplicate log file handle";
return;
}
content::ZygoteHost::GetInstance()->ReinitializeLogging(settings.logging_dest,
log_file_fd);
for (content::BrowserChildProcessHostIterator it; !it.Done(); ++it)
ReinitializeLoggingForProcessHost(it.GetHost(), settings, log_file_fd);
for (auto it(content::RenderProcessHost::AllHostsIterator()); !it.IsAtEnd();
it.Advance()) {
ReinitializeLoggingForProcessHost(it.GetCurrentValue(), settings,
log_file_fd);
}
}
}
void ForceLogRedirectionForTesting() {
g_force_log_redirection = true;
}
void RedirectChromeLogging(const base::CommandLine& command_line) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!base::SysInfo::IsRunningOnChromeOS() && !g_force_log_redirection)
return;
if (g_chrome_logging_redirect_tried) {
LOG(WARNING) << "NOT redirecting logging for multi-profiles case.";
return;
}
g_chrome_logging_redirect_tried = true;
if (command_line.HasSwitch(switches::kDisableLoggingRedirect))
return;
const base::FilePath log_path = logging::GetSessionLogFile(command_line);
LOG(WARNING) << "Redirecting post-login logging to " << log_path.value();
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&logging::SetUpLogFile, log_path, true),
base::BindOnce(&LogFileSetUp, command_line, log_path));
}
}