1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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/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 {
// This is true when logging redirect was tried for the first user in the
// session.
bool g_chrome_logging_redirect_tried = false;
// This should be set to true for tests that rely on log redirection.
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);
// The |log_path| is the new log file after log rotation. so it shouldn't be
// deleted even if it already exists.
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;
}
// Redirect Zygote and future children's logs.
content::ZygoteHost::GetInstance()->ReinitializeLogging(settings.logging_dest,
log_file_fd);
// Redirect child processes' logs.
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);
}
}
} // namespace
void ForceLogRedirectionForTesting() {
g_force_log_redirection = true;
}
void RedirectChromeLogging(const base::CommandLine& command_line) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Only redirect when on an actual device. To do otherwise conflicts with
// --vmodule that developers may want to use.
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;
// Redirect logs to the session log directory, if set. Otherwise
// defaults to the profile dir.
const base::FilePath log_path = logging::GetSessionLogFile(command_line);
LOG(WARNING) << "Redirecting post-login logging to " << log_path.value();
// Rotate the old log files when redirecting.
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&logging::SetUpLogFile, log_path, /*new_log=*/true),
base::BindOnce(&LogFileSetUp, command_line, log_path));
}
} // namespace ash
|