Add log configuration ensure watchdog (#1535)
This commit is contained in:
parent
7190a27d70
commit
47d88050d3
|
|
@ -1,28 +1,91 @@
|
||||||
|
#include "logcat.h"
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include "logcat.h"
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
|
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
constexpr size_t kMaxLogSize = 4 * 1024 * 1024;
|
constexpr size_t kMaxLogSize = 4 * 1024 * 1024;
|
||||||
|
#ifdef NDEBUG
|
||||||
constexpr size_t kLogBufferSize = 256 * 1024;
|
constexpr size_t kLogBufferSize = 256 * 1024;
|
||||||
|
#else
|
||||||
|
constexpr size_t kLogBufferSize = 4 * 1024 * 1024;
|
||||||
|
#endif
|
||||||
|
|
||||||
constexpr std::array<char, ANDROID_LOG_SILENT + 1> kLogChar = {
|
namespace {
|
||||||
/*ANDROID_LOG_UNKNOWN*/'?',
|
constexpr std::array<char, ANDROID_LOG_SILENT + 1> kLogChar = {
|
||||||
/*ANDROID_LOG_DEFAULT*/ '?',
|
/*ANDROID_LOG_UNKNOWN*/'?',
|
||||||
/*ANDROID_LOG_VERBOSE*/ 'V',
|
/*ANDROID_LOG_DEFAULT*/ '?',
|
||||||
/*ANDROID_LOG_DEBUG*/ 'D',
|
/*ANDROID_LOG_VERBOSE*/ 'V',
|
||||||
/*ANDROID_LOG_INFO*/'I',
|
/*ANDROID_LOG_DEBUG*/ 'D',
|
||||||
/*ANDROID_LOG_WARN*/'W',
|
/*ANDROID_LOG_INFO*/'I',
|
||||||
/*ANDROID_LOG_ERROR*/ 'E',
|
/*ANDROID_LOG_WARN*/'W',
|
||||||
/*ANDROID_LOG_FATAL*/ 'F',
|
/*ANDROID_LOG_ERROR*/ 'E',
|
||||||
/*ANDROID_LOG_SILENT*/ 'S',
|
/*ANDROID_LOG_FATAL*/ 'F',
|
||||||
};
|
/*ANDROID_LOG_SILENT*/ 'S',
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t ParseUint(const char *s) {
|
||||||
|
if (s[0] == '\0') return -1;
|
||||||
|
|
||||||
|
while (isspace(*s)) {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s[0] == '-') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
|
||||||
|
char *end;
|
||||||
|
auto result = strtoull(s, &end, base);
|
||||||
|
if (end == s) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*end != '\0') {
|
||||||
|
const char *suffixes = "bkmgtpe";
|
||||||
|
const char *suffix;
|
||||||
|
if ((suffix = strchr(suffixes, tolower(*end))) == nullptr ||
|
||||||
|
__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (std::numeric_limits<size_t>::max() < result) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return static_cast<size_t>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t GetByteProp(std::string_view prop, size_t def = -1) {
|
||||||
|
std::array<char, PROP_VALUE_MAX> buf{};
|
||||||
|
if (__system_property_get(prop.data(), buf.data()) < 0) return def;
|
||||||
|
return ParseUint(buf.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string GetStrProp(std::string_view prop, std::string def = {}) {
|
||||||
|
std::array<char, PROP_VALUE_MAX> buf{};
|
||||||
|
if (__system_property_get(prop.data(), buf.data()) < 0) return def;
|
||||||
|
return {buf.data()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SetIntProp(std::string_view prop, int val) {
|
||||||
|
auto buf = std::to_string(val);
|
||||||
|
return __system_property_set(prop.data(), buf.data()) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool SetStrProp(std::string_view prop, std::string_view val) {
|
||||||
|
return __system_property_set(prop.data(), val.data()) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
class UniqueFile : public std::unique_ptr<FILE, std::function<void(FILE *)>> {
|
class UniqueFile : public std::unique_ptr<FILE, std::function<void(FILE *)>> {
|
||||||
inline static deleter_type deleter = [](auto f) { f && f != stdout && fclose(f); };
|
inline static deleter_type deleter = [](auto f) { f && f != stdout && fclose(f); };
|
||||||
|
|
@ -52,6 +115,8 @@ private:
|
||||||
|
|
||||||
static size_t PrintLogLine(const AndroidLogEntry &entry, FILE *out);
|
static size_t PrintLogLine(const AndroidLogEntry &entry, FILE *out);
|
||||||
|
|
||||||
|
void EnsureLogWatchDog();
|
||||||
|
|
||||||
JNIEnv *env_;
|
JNIEnv *env_;
|
||||||
jobject thiz_;
|
jobject thiz_;
|
||||||
jmethodID refresh_fd_method_;
|
jmethodID refresh_fd_method_;
|
||||||
|
|
@ -73,7 +138,7 @@ size_t Logcat::PrintLogLine(const AndroidLogEntry &entry, FILE *out) {
|
||||||
if (!out) return 0;
|
if (!out) return 0;
|
||||||
constexpr static size_t kMaxTimeBuff = 64;
|
constexpr static size_t kMaxTimeBuff = 64;
|
||||||
struct tm tm{};
|
struct tm tm{};
|
||||||
std::array<char, kMaxTimeBuff> time_buff;
|
std::array<char, kMaxTimeBuff> time_buff{};
|
||||||
|
|
||||||
auto now = entry.tv_sec;
|
auto now = entry.tv_sec;
|
||||||
auto nsec = entry.tv_nsec;
|
auto nsec = entry.tv_nsec;
|
||||||
|
|
@ -122,8 +187,12 @@ void Logcat::RefreshFd(bool is_verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Logcat::Log(std::string_view str) {
|
inline void Logcat::Log(std::string_view str) {
|
||||||
if (verbose_) fprintf(verbose_file_.get(), "%.*s", static_cast<int>(str.size()), str.data());
|
if (verbose_) {
|
||||||
|
fprintf(verbose_file_.get(), "%.*s", static_cast<int>(str.size()), str.data());
|
||||||
|
fflush(verbose_file_.get());
|
||||||
|
}
|
||||||
fprintf(modules_file_.get(), "%.*s", static_cast<int>(str.size()), str.data());
|
fprintf(modules_file_.get(), "%.*s", static_cast<int>(str.size()), str.data());
|
||||||
|
fflush(modules_file_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logcat::OnCrash() {
|
void Logcat::OnCrash() {
|
||||||
|
|
@ -142,7 +211,7 @@ void Logcat::OnCrash() {
|
||||||
Log("\nLogd maybe crashed, retrying in 1s...\n");
|
Log("\nLogd maybe crashed, retrying in 1s...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(1);
|
std::this_thread::sleep_for(1s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logcat::ProcessBuffer(struct log_msg *buf) {
|
void Logcat::ProcessBuffer(struct log_msg *buf) {
|
||||||
|
|
@ -178,11 +247,46 @@ void Logcat::ProcessBuffer(struct log_msg *buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logcat::EnsureLogWatchDog() {
|
||||||
|
constexpr static auto kLogdSizeProp = "persist.logd.size"sv;
|
||||||
|
constexpr static auto kLogdTagProp = "persist.log.tag"sv;
|
||||||
|
constexpr static auto kLogdMainSizeProp = "persist.logd.size.main"sv;
|
||||||
|
constexpr static auto kLogdCrashSizeProp = "persist.logd.size.crash"sv;
|
||||||
|
constexpr static size_t kErr = -1;
|
||||||
|
std::thread([this] {
|
||||||
|
while (true) {
|
||||||
|
auto logd_size = GetByteProp(kLogdSizeProp);
|
||||||
|
auto logd_tag = GetStrProp(kLogdTagProp);
|
||||||
|
auto logd_main_size = GetByteProp(kLogdMainSizeProp);
|
||||||
|
auto logd_crash_size = GetByteProp(kLogdCrashSizeProp);
|
||||||
|
if (!logd_tag.empty() ||
|
||||||
|
!((logd_main_size == kErr && logd_crash_size == kErr && logd_size != kErr &&
|
||||||
|
logd_size >= kLogBufferSize) ||
|
||||||
|
(logd_main_size != kErr && logd_main_size >= kLogBufferSize &&
|
||||||
|
logd_crash_size != kErr &&
|
||||||
|
logd_crash_size >= kLogBufferSize))) {
|
||||||
|
SetIntProp(kLogdSizeProp, kLogBufferSize);
|
||||||
|
SetIntProp(kLogdMainSizeProp, kLogBufferSize);
|
||||||
|
SetIntProp(kLogdCrashSizeProp, kLogBufferSize);
|
||||||
|
SetStrProp(kLogdTagProp, "");
|
||||||
|
SetStrProp("ctl.start", "logd-reinit");
|
||||||
|
Log("Reset log settings\n");
|
||||||
|
}
|
||||||
|
const auto *pi = __system_property_find(kLogdTagProp.data());
|
||||||
|
uint32_t serial;
|
||||||
|
if (!__system_property_wait(pi, 0, &serial, nullptr)) break;
|
||||||
|
}
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
void Logcat::Run() {
|
void Logcat::Run() {
|
||||||
constexpr size_t tail_after_crash = 10U;
|
constexpr size_t tail_after_crash = 10U;
|
||||||
size_t tail = 0;
|
size_t tail = 0;
|
||||||
RefreshFd(true);
|
RefreshFd(true);
|
||||||
RefreshFd(false);
|
RefreshFd(false);
|
||||||
|
|
||||||
|
EnsureLogWatchDog();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
|
std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
|
||||||
android_logger_list_alloc(0, tail, 0), &android_logger_list_free};
|
android_logger_list_alloc(0, tail, 0), &android_logger_list_free};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue