[core] Dump fd if log file deleted (#1337)
This commit is contained in:
parent
e58db90d72
commit
330747aca1
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -591,6 +591,7 @@ public class LSPManagerService extends ILSPManagerService.Stub {
|
|||
|
||||
@Override
|
||||
public ParcelFileDescriptor getModulesLog() {
|
||||
workerHandler.post(() -> ServiceManager.getLogcatService().checkLogFile());
|
||||
return ConfigManager.getInstance().getModulesLog();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue