[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 <cinttypes>
#include "logcat.h"
#include <string_view>
#include <sys/system_properties.h>
using namespace std::string_view_literals;
@ -88,14 +87,16 @@ size_t Logcat::PrintLogLine(const AndroidLogEntry &entry, FILE *out) {
}
localtime_r(&now, &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
// to generate a new fd
return fprintf(out, "[ %s.%03ld %8d:%6d:%6d %c/%-15.*s ] %.*s\n",
int len = fprintf(out, "[ %s.%03ld %8d:%6d:%6d %c/%-15.*s ] %.*s\n",
time_buff.data(),
nsec / MS_PER_NSEC,
entry.uid, entry.pid, entry.tid,
kLogChar[entry.priority], static_cast<int>(entry.tagLen),
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) {
@ -104,15 +105,19 @@ void Logcat::RefreshFd(bool is_verbose) {
if (is_verbose) {
verbose_print_count_ = 0;
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_part_++;
fprintf(verbose_file_.get(), start, verbose_file_part_);
fflush(verbose_file_.get());
} else {
modules_print_count_ = 0;
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_part_++;
fprintf(modules_file_.get(), start, modules_file_part_);
fflush(modules_file_.get());
}
}
@ -199,9 +204,6 @@ void Logcat::Run() {
ProcessBuffer(&msg);
fflush(verbose_file_.get());
fflush(modules_file_.get());
if (verbose_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(true);
if (modules_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(false);
}

View File

@ -5,7 +5,7 @@
#include <android/log.h>
#define NS_PER_SEC 1000000000ULL
#define NS_PER_SEC 1000000000L
#define MS_PER_NSEC 1000000
#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.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -65,12 +66,19 @@ public class ConfigFileManager {
Files.createDirectories(basePath);
SELinux.setFileContext(basePath.toString(), "u:object_r:system_file:s0");
Files.createDirectories(configDirPath);
Files.createDirectories(logDirPath);
createLogDirPath();
} catch (IOException 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() {
loadRes();
return res;
@ -153,12 +161,12 @@ public class ConfigFileManager {
}
static File getNewVerboseLogPath() throws IOException {
Files.createDirectories(logDirPath);
createLogDirPath();
return logDirPath.resolve(getNewLogFileName("verbose")).toFile();
}
static File getNewModulesLogPath() throws IOException {
Files.createDirectories(logDirPath);
createLogDirPath();
return logDirPath.resolve(getNewLogFileName("modules")).toFile();
}

View File

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

View File

@ -9,6 +9,10 @@ import org.lsposed.lspd.BuildConfig;
import java.io.File;
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 {
private static final String TAG = "LSPosedLogcat";
@ -16,8 +20,8 @@ public class LogcatService implements Runnable {
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE |
ParcelFileDescriptor.MODE_APPEND;
private File modulesLog = null;
private File verboseLog = null;
private Path modulesLog = null;
private Path verboseLog = null;
private Thread thread = null;
@SuppressLint("UnsafeDynamicallyLoadedCode")
@ -43,21 +47,47 @@ public class LogcatService implements Runnable {
@SuppressWarnings("unused")
private int refreshFd(boolean isVerboseLog) {
try {
File log = isVerboseLog ? ConfigFileManager.getNewVerboseLogPath() : ConfigFileManager.getNewModulesLogPath();
Log.i(TAG, "New " + (isVerboseLog ? "verbose" : "modules") + " log file: " + 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();
var fdFile = new File("/proc/self/fd/" + fd);
var fdFile = Paths.get("/proc/self/fd", String.valueOf(fd));
if (isVerboseLog) verboseLog = fdFile;
else modulesLog = fdFile;
return fd;
} catch (IOException e) {
if (isVerboseLog) verboseLog = null;
else modulesLog = null;
Log.w(TAG, "someone chattr +i ?", e);
Log.w(TAG, "refreshFd", e);
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() {
return thread != null && thread.isAlive();
}
@ -91,10 +121,23 @@ public class LogcatService implements Runnable {
}
public File getVerboseLog() {
return verboseLog;
return verboseLog.toFile();
}
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);
}
}
}