Import debug-tools, to unify them

This commit is contained in:
roynatech2544
2023-11-26 14:16:33 +09:00
parent e6b0047868
commit f6d0886107
8 changed files with 345 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
//
// Copyright (C) 2021 Soo Hwan Na "Royna"
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
cc_binary {
name: "logger",
srcs: [
"Logger.cpp",
],
init_rc: ["logger.rc"],
whole_static_libs: ["libbase"],
shared_libs: ["liblog"],
system_ext_specific: true,
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright 2021 Soo Hwan Na "Royna"
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "bootlogger"
#include <android-base/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <log/log.h>
#include <unistd.h>
#include <atomic>
#include <fstream>
#include <functional>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
using android::base::WaitForProperty;
#define PLOGE(fmt, ...) ALOGE(fmt ": %s", ##__VA_ARGS__, strerror(errno))
struct LoggerContext;
// Base context for outputs with file
struct OutputContext {
// Fetch out file name of this context.
// Note that .txt suffix is auto appended.
virtual std::string getFileName(void) const = 0;
/**
* Returns absolute path of output
* Basically a wrapper of [getFileName]
*
* @return absolute path of out
*/
std::string getOutFilePath(void) const {
static std::string kLogDir = "/data/debug/";
return kLogDir + getFileName() + ".txt";
}
/**
* Open outfilestream.
*/
bool openOutput(void) {
auto out = getOutFilePath();
ALOGI("%s: Open %s", __func__, out.c_str());
std::remove(out.c_str());
ofs = std::ofstream(out);
valid = ofs.good();
if (!valid) PLOGE("%s: Failed to open %s", __func__, out.c_str());
return valid;
}
/**
* Writes the string to this context's file
*
* @param string data
*/
void writeStringToOutput(const std::string &data) {
ofs << data << std::endl;
}
operator bool() const { return valid; }
virtual ~OutputContext() {}
private:
std::ofstream ofs;
bool valid = false;
};
/**
* Filter support to LoggerContext's stream and outputting to a file.
*/
struct LogFilterContext : OutputContext {
// Function to be invoked to filter
virtual bool filter(const std::string &line) const = 0;
virtual std::string getFilterName(void) const = 0;
std::string getFileName(void) const override;
void setParent(LoggerContext *_parent) { parent = _parent; }
~LogFilterContext() override = default;
private:
LoggerContext *parent = nullptr;
};
struct LoggerContext : OutputContext {
/**
* Opens the log file stream handle
*
* @return FILE* handle
*/
virtual FILE *openSource(void) = 0;
/**
* Closes log file stream handle and does cleanup
*
* @param fp The file stream to close and cleanup. NonNull.
*/
virtual void closeSource(FILE *fp) = 0;
/**
* Register a LogFilterContext to this stream.
*
* @param ctx The context to register
*/
void registerLogFilter(LogFilterContext *ctx) {
if (ctx) {
filters.emplace_back(ctx);
ctx->setParent(this);
}
}
/**
* Start the associated logger
*
* @param run Pointer to run/stop control variable
*/
void startLogger(std::atomic_bool *run) {
char buf[1024] = {0};
auto fp = openSource();
if (fp) {
int fd = fileno(fp);
int flags = fcntl(fd, F_GETFL);
if (!(flags & O_NONBLOCK)) {
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
}
bool ret = openOutput();
if (ret) {
for (auto &f : filters) {
f->openOutput();
}
while (*run) {
auto ret = fgets(buf, sizeof(buf), fp);
std::istringstream ss(buf);
std::string line;
if (ret) {
while (getline(ss, line)) {
for (auto &f : filters) {
if (*f && f->filter(line)) f->writeStringToOutput(line);
}
writeStringToOutput(line);
}
}
}
// ofstream will auto close
} else {
PLOGE("[Context %s] Open output '%s'", getFileName().c_str(),
getOutFilePath().c_str());
}
closeSource(fp);
} else {
PLOGE("[Context %s] Open source", getFileName().c_str());
}
}
virtual ~LoggerContext(){};
private:
std::vector<LogFilterContext *> filters;
};
// Due to referencing LoggerContext::getFileName()
std::string LogFilterContext::getFileName(void) const {
return getFilterName() +
(parent ? std::string(".") + parent->getFileName() : "");
}
// DMESG
struct DmesgContext : LoggerContext {
FILE *openSource(void) override { return fopen("/proc/kmsg", "r"); }
void closeSource(FILE *fp) override { fclose(fp); }
std::string getFileName() const override { return "kmsg"; }
~DmesgContext() override = default;
};
// Logcat
struct LogcatContext : LoggerContext {
FILE *openSource(void) override { return popen("/system/bin/logcat", "r"); }
void closeSource(FILE *fp) override { pclose(fp); }
std::string getFileName() const override { return "logcat"; }
~LogcatContext() override = default;
};
// Filters - AVC
struct AvcFilterContext : LogFilterContext {
bool filter(const std::string &line) const override {
return std::regex_search(line, std::regex(R"(avc:\s+denied\s+\{\s\w+\s\})"));
}
std::string getFilterName(void) const override { return "avc"; }
~AvcFilterContext() override = default;
};
int main(void) {
std::vector<std::thread> threads;
std::atomic_bool run;
DmesgContext kDmesgCtx;
LogcatContext kLogcatCtx;
AvcFilterContext kDmesgAvcFilter, kLogcatAvcFilter;
kDmesgCtx.registerLogFilter(&kDmesgAvcFilter);
kLogcatCtx.registerLogFilter(&kLogcatAvcFilter);
run = true;
threads.emplace_back(std::thread([&] { kDmesgCtx.startLogger(&run); }));
threads.emplace_back(std::thread([&] { kLogcatCtx.startLogger(&run); }));
WaitForProperty("sys.boot_completed", "1");
run = false;
for (auto &i : threads) i.join();
return 0;
}

View File

@@ -0,0 +1,9 @@
service logdump /system/system_ext/bin/logger
user root
group system
oneshot
disabled
on post-fs-data
mkdir /data/debug 0755 root system encryption=None
start logdump

22
debug-tools/debug.mk Normal file
View File

@@ -0,0 +1,22 @@
## logger: Dump tool that automatically dumps logcat/kmsg while booting.
# It is common to miss boot time logs, since there is a lot of logs there on boot.
# So this dumps logs while boot, starts at post-fs-data, stops at sys.boot_completed=1
#
# This is selinux-safe (Enforcing OK) neverallow-safe (Passes neverallow)
# And user-build safe (Works)
#
PRODUCT_PACKAGES += logger
## dlopener: Tool for command-line to test dlopen, aka opening shared object files (.so)
# Provides dlerror string if failed to open (resolve dependencies, symbols etc)
# Else returns success.
#
# Has vendor varient and system varient as from Android R, namespace is sperated with
# /vendor and /system so /system/bin/dlopener cant open vendor libs and vice versa
PRODUCT_PACKAGES += dlopener dlopener.vendor
# System calls - ptrace
PRODUCT_PACKAGES += strace

View File

@@ -0,0 +1,11 @@
cc_binary {
name: "dlopener",
compile_multilib: "both",
multilib: {
lib32: {
suffix: "32",
},
},
srcs: ["dlopener.c"],
vendor_available: true,
}

View File

@@ -0,0 +1,26 @@
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
const char *path;
void *handle = NULL;
int ret = EXIT_FAILURE;
if (argc <= 1) {
printf("Please specify a module to load!\n");
return ret;
}
path = argv[1];
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
const char *err_str = dlerror();
printf("load: module=%s\n%s\n", path, err_str ? err_str : "unknown");
} else {
printf("load: module=%s %s\n", path, "Success!");
ret = EXIT_SUCCESS;
}
return ret;
}

View File

@@ -1,2 +1,6 @@
# Samsung Ext
(/system)?/system_ext/bin/hw/vendor\.samsung_ext\.hardware\.camera\.flashlight-service u:object_r:hal_samsung_camera_flashlight_default_exec:s0
(/system)?/system_ext/bin/hw/vendor\.samsung_ext\.framework\.battery-service u:object_r:hal_samsung_battery_default_exec:s0
# Logger
(/system)?/system_ext/bin/logger u:object_r:logger_exec:s0
/data/debug(/.*)? u:object_r:logger_data_file:s0

View File

@@ -0,0 +1,18 @@
type logger, domain, coredomain;
type logger_exec, exec_type, file_type, system_file_type;
init_daemon_domain(logger)
type logger_data_file, file_type, data_file_type, core_data_file_type;
allow logger logger_data_file:dir rw_dir_perms;
allow logger logger_data_file:file rw_file_perms;
allow logger proc_kmsg:file r_file_perms;
allow logger logcat_exec:file rx_file_perms;
allow logger self:capability2 syslog;
allow logger kernel:system syslog_mod;
allow logger logger_data_file:file create_file_perms;
allow logger shell_exec:file rx_file_perms;
allow logger self:capability sys_nice;
allow logger logdr_socket:sock_file write;
allow logger logd:unix_stream_socket connectto;
get_prop(logger, boot_status_prop)