diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp index 1bc03574c..a0d0c033f 100644 --- a/fs_mgr/libsnapshot/snapshotctl.cpp +++ b/fs_mgr/libsnapshot/snapshotctl.cpp @@ -19,9 +19,13 @@ #include #include #include +#include +#include #include +#include #include +#include "utility.h" using namespace std::string_literals; @@ -31,9 +35,11 @@ int Usage() { "Actions:\n" " dump\n" " Print snapshot states.\n" - " merge [--logcat]\n" + " merge [--logcat] [--log-to-file]\n" " Initialize merge and wait for it to be completed.\n" - " If --logcat is specified, log to logcat. Otherwise, log to stdout.\n"; + " If --logcat is specified, log to logcat.\n" + " If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n" + " If both specified, log to both. If none specified, log to stdout.\n"; return EX_USAGE; } @@ -45,20 +51,62 @@ bool DumpCmdHandler(int /*argc*/, char** argv) { return SnapshotManager::New()->Dump(std::cout); } +class FileLogger { + public: + FileLogger() { + static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/"; + std::stringstream ss; + ss << kLogFilePath << "snapshotctl." << Now() << ".log"; + fd_.reset(TEMP_FAILURE_RETRY( + open(ss.str().c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660))); + } + // Copy-contuctor needed to be converted to std::function. + FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); } + void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/, + const char* /*file*/, unsigned int /*line*/, const char* message) { + if (fd_ == -1) return; + std::stringstream ss; + ss << Now() << ":" << message << "\n"; + (void)android::base::WriteStringToFd(ss.str(), fd_); + } + + private: + android::base::unique_fd fd_; +}; + +class MergeCmdLogger { + public: + MergeCmdLogger(int argc, char** argv) { + for (int i = 0; i < argc; ++i) { + if (argv[i] == "--logcat"s) { + loggers_.push_back(android::base::LogdLogger()); + } + if (argv[i] == "--log-to-file"s) { + loggers_.push_back(std::move(FileLogger())); + } + } + if (loggers_.empty()) { + loggers_.push_back(&android::base::StdioLogger); + } + } + void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag, + const char* file, unsigned int line, const char* message) { + for (auto&& logger : loggers_) { + logger(id, severity, tag, file, line, message); + } + } + + private: + std::vector loggers_; +}; + bool MergeCmdHandler(int argc, char** argv) { auto begin = std::chrono::steady_clock::now(); - bool log_to_logcat = false; - for (int i = 2; i < argc; ++i) { - if (argv[i] == "--logcat"s) { - log_to_logcat = true; - } - } - if (log_to_logcat) { - android::base::InitLogging(argv); - } else { - android::base::InitLogging(argv, &android::base::StdioLogger); - } + // 'snapshotctl merge' is stripped away from arguments to + // Logger. + android::base::InitLogging(argv, MergeCmdLogger(argc - 2, argv + 2)); auto state = SnapshotManager::New()->InitiateMergeAndWait(); diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc index 3ab0645db..5dbe35255 100644 --- a/fs_mgr/libsnapshot/snapshotctl.rc +++ b/fs_mgr/libsnapshot/snapshotctl.rc @@ -1,2 +1,2 @@ on property:sys.boot_completed=1 - exec_background - root root -- /system/bin/snapshotctl merge --logcat + exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp index 3a64448b8..3318b331e 100644 --- a/fs_mgr/libsnapshot/utility.cpp +++ b/fs_mgr/libsnapshot/utility.cpp @@ -15,6 +15,10 @@ #include "utility.h" #include +#include + +#include +#include #include #include @@ -155,5 +159,12 @@ bool WriteStringToFileAtomic(const std::string& content, const std::string& path return true; } +std::ostream& operator<<(std::ostream& os, const Now&) { + struct tm now; + time_t t = time(nullptr); + localtime_r(&t, &now); + return os << std::put_time(&now, "%Y%m%d-%H%M%S"); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h index ad46090b9..90ad0fec7 100644 --- a/fs_mgr/libsnapshot/utility.h +++ b/fs_mgr/libsnapshot/utility.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include #include @@ -120,5 +121,9 @@ Return InitializeCow(const std::string& device); // is an open fd to |path|, because that fd has an old view of the file. bool WriteStringToFileAtomic(const std::string& content, const std::string& path); +// Writes current time to a given stream. +struct Now {}; +std::ostream& operator<<(std::ostream& os, const Now&); + } // namespace snapshot } // namespace android diff --git a/rootdir/init.rc b/rootdir/init.rc index 731aba34b..c6fcafa5d 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -613,6 +613,7 @@ on post-fs-data mkdir /data/misc/installd 0700 root root mkdir /data/misc/apexdata 0711 root root mkdir /data/misc/apexrollback 0700 root root + mkdir /data/misc/snapshotctl_log 0770 root root mkdir /data/preloads 0775 system system encryption=None