blob: b13d93a7ee10efd65ce9852e66569d51435a3ba8 [file] [log] [blame]
Yifan Hongc80de2d2020-02-25 17:13:53 -08001//
2// Copyright (C) 2020 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include <inttypes.h>
18#include <stdio.h>
19#include <sys/stat.h>
20#include <unistd.h>
21
22#include <algorithm>
Yifan Hongf1fba652020-03-02 13:03:25 -080023#include <functional>
24#include <iomanip>
Yifan Hongc80de2d2020-02-25 17:13:53 -080025#include <string>
Yifan Hongf1fba652020-03-02 13:03:25 -080026#include <string_view>
Yifan Hongc80de2d2020-02-25 17:13:53 -080027#include <vector>
28
Yifan Hongf1fba652020-03-02 13:03:25 -080029#include <android-base/file.h>
30#include <android-base/strings.h>
31#include <android-base/unique_fd.h>
Yifan Hongc80de2d2020-02-25 17:13:53 -080032#include <base/files/dir_reader_posix.h>
33#include <base/logging.h>
34#include <base/strings/string_util.h>
35#include <base/strings/stringprintf.h>
Yifan Hongf1fba652020-03-02 13:03:25 -080036#include <log/log.h>
Yifan Hongc80de2d2020-02-25 17:13:53 -080037
38#include "update_engine/common/utils.h"
39
40using std::string;
41
42namespace chromeos_update_engine {
43namespace {
44
45constexpr char kSystemLogsRoot[] = "/data/misc/update_engine_log";
46constexpr size_t kLogCount = 5;
47
48// Keep the most recent |kLogCount| logs but remove the old ones in
49// "/data/misc/update_engine_log/".
50void DeleteOldLogs(const string& kLogsRoot) {
51 base::DirReaderPosix reader(kLogsRoot.c_str());
52 if (!reader.IsValid()) {
53 LOG(ERROR) << "Failed to read " << kLogsRoot;
54 return;
55 }
56
57 std::vector<string> old_logs;
58 while (reader.Next()) {
59 if (reader.name()[0] == '.')
60 continue;
61
62 // Log files are in format "update_engine.%Y%m%d-%H%M%S",
63 // e.g. update_engine.20090103-231425
64 uint64_t date;
65 uint64_t local_time;
66 if (sscanf(reader.name(),
67 "update_engine.%" PRIu64 "-%" PRIu64 "",
68 &date,
69 &local_time) == 2) {
70 old_logs.push_back(reader.name());
71 } else {
72 LOG(WARNING) << "Unrecognized log file " << reader.name();
73 }
74 }
75
76 std::sort(old_logs.begin(), old_logs.end(), std::greater<string>());
77 for (size_t i = kLogCount; i < old_logs.size(); i++) {
78 string log_path = kLogsRoot + "/" + old_logs[i];
79 if (unlink(log_path.c_str()) == -1) {
80 PLOG(WARNING) << "Failed to unlink " << log_path;
81 }
82 }
83}
84
85string SetupLogFile(const string& kLogsRoot) {
86 DeleteOldLogs(kLogsRoot);
87
88 return base::StringPrintf("%s/update_engine.%s",
89 kLogsRoot.c_str(),
90 utils::GetTimeAsString(::time(nullptr)).c_str());
91}
92
Yifan Hongf1fba652020-03-02 13:03:25 -080093const char* LogPriorityToCString(int priority) {
94 switch (priority) {
95 case ANDROID_LOG_VERBOSE:
96 return "VERBOSE";
97 case ANDROID_LOG_DEBUG:
98 return "DEBUG";
99 case ANDROID_LOG_INFO:
100 return "INFO";
101 case ANDROID_LOG_WARN:
102 return "WARN";
103 case ANDROID_LOG_ERROR:
104 return "ERROR";
105 case ANDROID_LOG_FATAL:
106 return "FATAL";
107 default:
108 return "UNKNOWN";
109 }
110}
111
112using LoggerFunction = std::function<void(const struct __android_logger_data*,
113 const char* message)>;
114
115class FileLogger {
116 public:
117 explicit FileLogger(const string& path) {
118 fd_.reset(TEMP_FAILURE_RETRY(
119 open(path.c_str(),
120 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC,
121 0644)));
122 if (fd_ == -1) {
123 // Use ALOGE that logs to logd before __android_log_set_logger.
124 ALOGE("Cannot open persistent log %s: %s", path.c_str(), strerror(errno));
125 return;
126 }
127 // The log file will have AID_LOG as group ID; this GID is inherited from
128 // the parent directory "/data/misc/update_engine_log" which sets the SGID
129 // bit.
130 if (fchmod(fd_.get(), 0640) == -1) {
131 // Use ALOGE that logs to logd before __android_log_set_logger.
132 ALOGE("Cannot chmod 0640 persistent log %s: %s",
133 path.c_str(),
134 strerror(errno));
135 return;
136 }
137 }
138 // Copy-constructor needed to be converted to std::function.
139 FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
140 void operator()(const struct __android_logger_data* logger_data,
141 const char* message) {
142 if (fd_ == -1) {
143 return;
144 }
145
146 // libchrome add a newline character to |message|. Strip it.
147 std::string_view message_no_newline = message != nullptr ? message : "";
148 ignore_result(android::base::ConsumeSuffix(&message_no_newline, "\n"));
149
150 WriteToFd(GetPrefix(logger_data));
151 WriteToFd(message_no_newline);
152 WriteToFd("\n");
153 }
154
155 private:
156 android::base::unique_fd fd_;
157 void WriteToFd(std::string_view message) {
158 ignore_result(
159 android::base::WriteFully(fd_, message.data(), message.size()));
160 }
161
162 string GetPrefix(const struct __android_logger_data* logger_data) {
163 std::stringstream ss;
164 timeval tv;
165 gettimeofday(&tv, nullptr);
166 time_t t = tv.tv_sec;
167 struct tm local_time;
168 localtime_r(&t, &local_time);
169 struct tm* tm_time = &local_time;
170 ss << "[" << std::setfill('0') << std::setw(2) << 1 + tm_time->tm_mon
171 << std::setw(2) << tm_time->tm_mday << '/' << std::setw(2)
172 << tm_time->tm_hour << std::setw(2) << tm_time->tm_min << std::setw(2)
173 << tm_time->tm_sec << '.' << std::setw(6) << tv.tv_usec << "] ";
174 // libchrome logs prepends |message| with severity, file and line, but
175 // leave logger_data->file as nullptr.
176 // libbase / liblog logs doesn't. Hence, add them to match the style.
177 // For liblog logs that doesn't set logger_data->file, not printing the
178 // priority is acceptable.
179 if (logger_data->file) {
180 ss << "[" << LogPriorityToCString(logger_data->priority) << ':'
181 << logger_data->file << '(' << logger_data->line << ")] ";
182 }
183 return ss.str();
184 }
185};
186
187class CombinedLogger {
188 public:
189 CombinedLogger(bool log_to_system, bool log_to_file) {
190 if (log_to_system) {
191 loggers_.push_back(__android_log_logd_logger);
192 }
193 if (log_to_file) {
194 loggers_.push_back(std::move(FileLogger(SetupLogFile(kSystemLogsRoot))));
195 }
196 }
197 void operator()(const struct __android_logger_data* logger_data,
198 const char* message) {
199 for (auto&& logger : loggers_) {
200 logger(logger_data, message != nullptr ? message : "");
201 }
202 }
203
204 private:
205 std::vector<LoggerFunction> loggers_;
206};
207
Yifan Hongc80de2d2020-02-25 17:13:53 -0800208} // namespace
209
210void SetupLogging(bool log_to_system, bool log_to_file) {
Yifan Hongf1fba652020-03-02 13:03:25 -0800211 // Note that libchrome logging uses liblog.
212 // By calling liblog's __android_log_set_logger function, all of libchrome
213 // (used by update_engine) / libbase / liblog (used by depended modules)
214 // logging eventually redirects to CombinedLogger.
215 static auto g_logger =
216 std::make_unique<CombinedLogger>(log_to_system, log_to_file);
217 __android_log_set_logger(
218 [](const struct __android_logger_data* logger_data, const char* message) {
219 (*g_logger)(logger_data, message);
220 });
221
222 // libchrome logging should not log to file.
Yifan Hongc80de2d2020-02-25 17:13:53 -0800223 logging::LoggingSettings log_settings;
224 log_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
225 log_settings.logging_dest = static_cast<logging::LoggingDestination>(
Yifan Hongf1fba652020-03-02 13:03:25 -0800226 logging::LOG_TO_SYSTEM_DEBUG_LOG);
Yifan Hongc80de2d2020-02-25 17:13:53 -0800227 log_settings.log_file = nullptr;
Yifan Hongc80de2d2020-02-25 17:13:53 -0800228 logging::InitLogging(log_settings);
Yifan Hongf1fba652020-03-02 13:03:25 -0800229 logging::SetLogItems(false /* enable_process_id */,
230 false /* enable_thread_id */,
231 false /* enable_timestamp */,
232 false /* enable_tickcount */);
Yifan Hongc80de2d2020-02-25 17:13:53 -0800233}
234
235} // namespace chromeos_update_engine