diff --git a/debug-tools/bootlogger/Logger.cpp b/debug-tools/bootlogger/Logger.cpp index da0477d..7cf58f9 100644 --- a/debug-tools/bootlogger/Logger.cpp +++ b/debug-tools/bootlogger/Logger.cpp @@ -48,9 +48,6 @@ using std::chrono_literals::operator""s; // NOLINT (misc-unused-using-decls) namespace fs = std::filesystem; -// TODO is there anything better than global variable? -static fs::path kLogDir; - // Base context for outputs with file struct OutputContext { // File path (absolute) of this context. @@ -60,14 +57,13 @@ struct OutputContext { std::string kFileName; // Takes one argument 'filename' without file extension - OutputContext(const std::string &filename) : kFileName(filename) { - auto localLogDir = kLogDir; // Copy-construct - kFilePath = localLogDir.append(kFileName + ".txt").string(); + OutputContext(fs::path logDir, const std::string &filename) : kFileName(filename) { + kFilePath = logDir.append(kFileName + ".txt").string(); } // Takes two arguments 'filename' and is_filter - OutputContext(const std::string &filename, const bool isFilter) - : OutputContext(filename) { + OutputContext(const fs::path logDir, const std::string &filename, const bool isFilter) + : OutputContext(logDir, filename) { is_filter = isFilter; } @@ -103,9 +99,9 @@ struct OutputContext { operator bool() const { return fd >= 0; } /** - * To be called on ~OutputContext Sub-classes + * Cleanup */ - void cleanupOutputCtx() { + ~OutputContext() { struct stat buf {}; int rc = fstat(fd, &buf); if (rc == 0 && buf.st_size == 0) { @@ -116,8 +112,6 @@ struct OutputContext { fd = -1; } - virtual ~OutputContext() {} - private: int fd = -1; int len = 0; @@ -129,7 +123,6 @@ private: */ struct LogFilterContext { // Function to be invoked to filter - // Note: The line passed to this function is modifiable. virtual bool filter(const std::string &line) const = 0; // Filter name, must be a vaild file name itself. std::string kFilterName; @@ -150,27 +143,25 @@ struct LoggerContext : OutputContext { * * @return FILE* handle */ - virtual FILE *openSource(void) = 0; + FILE *(*openSource)(void) = nullptr; /** * Closes log file stream handle and does cleanup * * @param fp The file stream to close and cleanup. NonNull. */ - virtual void closeSource(FILE *fp) = 0; + void (*closeSource)(FILE *fp) = nullptr; /** * Register a LogFilterContext to this stream. * * @param ctx The context to register */ - void registerLogFilter(std::shared_ptr ctx) { + void registerLogFilter(const fs::path logDir, std::shared_ptr ctx) { if (ctx) { ALOGD("%s: registered filter '%s' to '%s' logger", __func__, ctx->kFilterName.c_str(), name.c_str()); - filters.emplace( - ctx, std::make_unique(ctx->kFilterName + '.' + name, - /*isFilter*/ true)); + filters.emplace(ctx, OutputContext(logDir, ctx->kFilterName + '.' + name,/*isFilter*/ true)); } } @@ -185,11 +176,11 @@ struct LoggerContext : OutputContext { if (fp) { if (openOutput()) { for (auto &f : filters) { - f.second->openOutput(); + f.second.openOutput(); } // Erase failed-to-open contexts for (auto it = filters.begin(), last = filters.end(); it != last;) { - if (!it->second.get()) + if (!it->second) it = filters.erase(it); else ++it; @@ -204,15 +195,12 @@ struct LoggerContext : OutputContext { std::string fline = line; fline.shrink_to_fit(); if (f.first->filter(fline)) - f.second->writeToOutput(fline); + f.second.writeToOutput(fline); } writeToOutput(line); } } } - for (auto &f : filters) { - f.second->cleanupOutputCtx(); - } // ofstream will auto close } else { PLOGE("[Context %s] Opening output '%s'", name.c_str(), @@ -223,33 +211,34 @@ struct LoggerContext : OutputContext { PLOGE("[Context %s] Opening source", name.c_str()); } } - LoggerContext(const std::string &fname) : OutputContext(fname), name(fname) { - ALOGD("%s: Logger context '%s' created", __func__, fname.c_str()); - } - virtual ~LoggerContext(){}; -private: + LoggerContext(decltype(openSource) op, decltype(closeSource) cl, const fs::path logDir, + const std::string& name) + : OutputContext(logDir, name), openSource(op), closeSource(cl), name(name) { + ALOGD("%s: Logger context '%s' created", __func__, name.c_str()); + } + + private: std::string name; - std::unordered_map, - std::unique_ptr> + std::unordered_map, OutputContext> filters; }; // DMESG -struct DmesgContext : LoggerContext { - FILE *openSource(void) override { return fopen("/proc/kmsg", "r"); } - void closeSource(FILE *fp) override { fclose(fp); } - DmesgContext() : LoggerContext("kmsg") {} - ~DmesgContext() override { cleanupOutputCtx(); } -}; +static FILE* DmesgContext_openSource() { + return fopen("/proc/kmsg", "r"); +} +static void DmesgContext_closeSource(FILE *fp) { + fclose(fp); +} // Logcat -struct LogcatContext : LoggerContext { - FILE *openSource(void) override { return popen("/system/bin/logcat", "r"); } - void closeSource(FILE *fp) override { pclose(fp); } - LogcatContext() : LoggerContext("logcat") {} - ~LogcatContext() override { cleanupOutputCtx(); } -}; +static FILE* LogcatContext_openSource() { + return popen("/system/bin/logcat", "r"); +} +static void LogcatContext_closeSource(FILE *fp) { + fclose(fp); +} // Filters - AVC struct AvcFilterContext : LogFilterContext { @@ -342,7 +331,7 @@ int main(int argc, const char** argv) { fprintf(stderr, "%s: Invaild empty string for log directory\n", argv[0]); return EXIT_FAILURE; } - kLogDir = fs::path(kLogRoot); + auto kLogDir = fs::path(kLogRoot); if (GetProperty("sys.boot_completed", "") == "1") { ALOGI("Running in system log mode"); @@ -353,8 +342,18 @@ int main(int argc, const char** argv) { else kLogDir.append("boot"); - DmesgContext kDmesgCtx; - LogcatContext kLogcatCtx; + LoggerContext kDmesgCtx = { + DmesgContext_openSource, + DmesgContext_closeSource, + kLogDir, + "dmesg" + }; + LoggerContext kLogcatCtx = { + LogcatContext_openSource, + LogcatContext_closeSource, + kLogDir, + "logcat" + }; auto kAvcCtx = std::make_shared>(); auto kAvcFilter = std::make_shared(kAvcCtx, lock); auto kLibcPropsFilter = std::make_shared(); @@ -406,11 +405,11 @@ int main(int argc, const char** argv) { // If this prop is true, logd logs kernel message to logcat // Don't make duplicate (Also it will race against kernel logs) if (!GetBoolProperty("ro.logd.kernel", false)) { - kDmesgCtx.registerLogFilter(kAvcFilter); + kDmesgCtx.registerLogFilter(kLogDir, kAvcFilter); threads.emplace_back(std::thread([&] { kDmesgCtx.startLogger(&run); })); } - kLogcatCtx.registerLogFilter(kAvcFilter); - kLogcatCtx.registerLogFilter(kLibcPropsFilter); + kLogcatCtx.registerLogFilter(kLogDir, kAvcFilter); + kLogcatCtx.registerLogFilter(kLogDir, kLibcPropsFilter); threads.emplace_back(std::thread([&] { kLogcatCtx.startLogger(&run); })); if (system_log) {