[core] Dump fd if log file deleted (#1337)

This commit is contained in:
南宫雪珊 2021-10-29 10:13:08 +08:00 committed by GitHub
parent e58db90d72
commit 330747aca1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 24 deletions

View File

@ -5,7 +5,6 @@
#include <array> #include <array>
#include <cinttypes> #include <cinttypes>
#include "logcat.h" #include "logcat.h"
#include <string_view>
#include <sys/system_properties.h> #include <sys/system_properties.h>
using namespace std::string_view_literals; using namespace std::string_view_literals;
@ -88,14 +87,16 @@ size_t Logcat::PrintLogLine(const AndroidLogEntry &entry, FILE *out) {
} }
localtime_r(&now, &tm); localtime_r(&now, &tm);
strftime(time_buff.data(), time_buff.size(), "%Y-%m-%dT%H:%M:%S", &tm); strftime(time_buff.data(), time_buff.size(), "%Y-%m-%dT%H:%M:%S", &tm);
// implicitly convert to size_t and intentionally trigger overflow when failed int len = fprintf(out, "[ %s.%03ld %8d:%6d:%6d %c/%-15.*s ] %.*s\n",
// to generate a new fd
return fprintf(out, "[ %s.%03ld %8d:%6d:%6d %c/%-15.*s ] %.*s\n",
time_buff.data(), time_buff.data(),
nsec / MS_PER_NSEC, nsec / MS_PER_NSEC,
entry.uid, entry.pid, entry.tid, entry.uid, entry.pid, entry.tid,
kLogChar[entry.priority], static_cast<int>(entry.tagLen), kLogChar[entry.priority], static_cast<int>(entry.tagLen),
entry.tag, static_cast<int>(message_len), message); entry.tag, static_cast<int>(message_len), message);
fflush(out);
// trigger overflow when failed to generate a new fd
if (len <= 0) len = kMaxLogSize;
return static_cast<size_t>(len);
} }
void Logcat::RefreshFd(bool is_verbose) { void Logcat::RefreshFd(bool is_verbose) {
@ -104,15 +105,19 @@ void Logcat::RefreshFd(bool is_verbose) {
if (is_verbose) { if (is_verbose) {
verbose_print_count_ = 0; verbose_print_count_ = 0;
fprintf(verbose_file_.get(), end, verbose_file_part_); fprintf(verbose_file_.get(), end, verbose_file_part_);
fflush(verbose_file_.get());
verbose_file_ = UniqueFile(env_->CallIntMethod(thiz_, refresh_fd_method_, JNI_TRUE), "a"); verbose_file_ = UniqueFile(env_->CallIntMethod(thiz_, refresh_fd_method_, JNI_TRUE), "a");
verbose_file_part_++; verbose_file_part_++;
fprintf(verbose_file_.get(), start, verbose_file_part_); fprintf(verbose_file_.get(), start, verbose_file_part_);
fflush(verbose_file_.get());
} else { } else {
modules_print_count_ = 0; modules_print_count_ = 0;
fprintf(modules_file_.get(), end, modules_file_part_); fprintf(modules_file_.get(), end, modules_file_part_);
fflush(modules_file_.get());
modules_file_ = UniqueFile(env_->CallIntMethod(thiz_, refresh_fd_method_, JNI_FALSE), "a"); modules_file_ = UniqueFile(env_->CallIntMethod(thiz_, refresh_fd_method_, JNI_FALSE), "a");
modules_file_part_++; modules_file_part_++;
fprintf(modules_file_.get(), start, modules_file_part_); fprintf(modules_file_.get(), start, modules_file_part_);
fflush(modules_file_.get());
} }
} }
@ -199,9 +204,6 @@ void Logcat::Run() {
ProcessBuffer(&msg); ProcessBuffer(&msg);
fflush(verbose_file_.get());
fflush(modules_file_.get());
if (verbose_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(true); if (verbose_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(true);
if (modules_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(false); if (modules_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(false);
} }

View File

@ -5,7 +5,7 @@
#include <android/log.h> #include <android/log.h>
#define NS_PER_SEC 1000000000ULL #define NS_PER_SEC 1000000000L
#define MS_PER_NSEC 1000000 #define MS_PER_NSEC 1000000
#define LOGGER_ENTRY_MAX_LEN (5 * 1024) #define LOGGER_ENTRY_MAX_LEN (5 * 1024)

View File

@ -28,6 +28,7 @@ import java.nio.channels.FileChannel;
import java.nio.channels.FileLock; import java.nio.channels.FileLock;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -65,12 +66,19 @@ public class ConfigFileManager {
Files.createDirectories(basePath); Files.createDirectories(basePath);
SELinux.setFileContext(basePath.toString(), "u:object_r:system_file:s0"); SELinux.setFileContext(basePath.toString(), "u:object_r:system_file:s0");
Files.createDirectories(configDirPath); Files.createDirectories(configDirPath);
Files.createDirectories(logDirPath); createLogDirPath();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e)); Log.e(TAG, Log.getStackTraceString(e));
} }
} }
private static void createLogDirPath() throws IOException {
if (!Files.isDirectory(logDirPath, LinkOption.NOFOLLOW_LINKS)) {
Files.deleteIfExists(logDirPath);
}
Files.createDirectories(logDirPath);
}
public static Resources getResources() { public static Resources getResources() {
loadRes(); loadRes();
return res; return res;
@ -153,12 +161,12 @@ public class ConfigFileManager {
} }
static File getNewVerboseLogPath() throws IOException { static File getNewVerboseLogPath() throws IOException {
Files.createDirectories(logDirPath); createLogDirPath();
return logDirPath.resolve(getNewLogFileName("verbose")).toFile(); return logDirPath.resolve(getNewLogFileName("verbose")).toFile();
} }
static File getNewModulesLogPath() throws IOException { static File getNewModulesLogPath() throws IOException {
Files.createDirectories(logDirPath); createLogDirPath();
return logDirPath.resolve(getNewLogFileName("modules")).toFile(); return logDirPath.resolve(getNewLogFileName("modules")).toFile();
} }

View File

@ -591,6 +591,7 @@ public class LSPManagerService extends ILSPManagerService.Stub {
@Override @Override
public ParcelFileDescriptor getModulesLog() { public ParcelFileDescriptor getModulesLog() {
workerHandler.post(() -> ServiceManager.getLogcatService().checkLogFile());
return ConfigManager.getInstance().getModulesLog(); return ConfigManager.getInstance().getModulesLog();
} }

View File

@ -9,6 +9,10 @@ import org.lsposed.lspd.BuildConfig;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class LogcatService implements Runnable { public class LogcatService implements Runnable {
private static final String TAG = "LSPosedLogcat"; private static final String TAG = "LSPosedLogcat";
@ -16,8 +20,8 @@ public class LogcatService implements Runnable {
ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_TRUNCATE |
ParcelFileDescriptor.MODE_APPEND; ParcelFileDescriptor.MODE_APPEND;
private File modulesLog = null; private Path modulesLog = null;
private File verboseLog = null; private Path verboseLog = null;
private Thread thread = null; private Thread thread = null;
@SuppressLint("UnsafeDynamicallyLoadedCode") @SuppressLint("UnsafeDynamicallyLoadedCode")
@ -43,21 +47,47 @@ public class LogcatService implements Runnable {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private int refreshFd(boolean isVerboseLog) { private int refreshFd(boolean isVerboseLog) {
try { try {
File log = isVerboseLog ? ConfigFileManager.getNewVerboseLogPath() : ConfigFileManager.getNewModulesLogPath(); File log;
Log.i(TAG, "New " + (isVerboseLog ? "verbose" : "modules") + " log file: " + log); if (isVerboseLog) {
checkFdFile(verboseLog);
log = ConfigFileManager.getNewVerboseLogPath();
} else {
checkFdFile(modulesLog);
log = ConfigFileManager.getNewModulesLogPath();
}
Log.i(TAG, "New log file: " + log);
int fd = ParcelFileDescriptor.open(log, mode).detachFd(); int fd = ParcelFileDescriptor.open(log, mode).detachFd();
var fdFile = new File("/proc/self/fd/" + fd); var fdFile = Paths.get("/proc/self/fd", String.valueOf(fd));
if (isVerboseLog) verboseLog = fdFile; if (isVerboseLog) verboseLog = fdFile;
else modulesLog = fdFile; else modulesLog = fdFile;
return fd; return fd;
} catch (IOException e) { } catch (IOException e) {
if (isVerboseLog) verboseLog = null; if (isVerboseLog) verboseLog = null;
else modulesLog = null; else modulesLog = null;
Log.w(TAG, "someone chattr +i ?", e); Log.w(TAG, "refreshFd", e);
return -1; return -1;
} }
} }
private static void checkFdFile(Path fdFile) {
if (fdFile == null) return;
try {
var file = Files.readSymbolicLink(fdFile);
if (!Files.exists(file)) {
var parent = file.getParent();
if (!Files.isDirectory(parent, LinkOption.NOFOLLOW_LINKS)) {
Files.deleteIfExists(parent);
}
Files.createDirectories(parent);
var name = file.getFileName().toString();
var originName = name.substring(0, name.lastIndexOf(' '));
Files.copy(fdFile, parent.resolve(originName));
}
} catch (IOException e) {
Log.w(TAG, "checkFd " + fdFile, e);
}
}
public boolean isRunning() { public boolean isRunning() {
return thread != null && thread.isAlive(); return thread != null && thread.isAlive();
} }
@ -91,10 +121,23 @@ public class LogcatService implements Runnable {
} }
public File getVerboseLog() { public File getVerboseLog() {
return verboseLog; return verboseLog.toFile();
} }
public File getModulesLog() { public File getModulesLog() {
return modulesLog; return modulesLog.toFile();
}
public void checkLogFile() {
try {
modulesLog.toRealPath();
} catch (IOException e) {
refresh(false);
}
try {
verboseLog.toRealPath();
} catch (IOException e) {
refresh(true);
}
} }
} }