Fix log save (#1605)
This commit is contained in:
parent
a885818a4d
commit
74c55e9947
|
|
@ -63,6 +63,7 @@ import java.util.concurrent.FutureTask;
|
||||||
import okhttp3.Cache;
|
import okhttp3.Cache;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import rikka.core.os.FileUtils;
|
||||||
import rikka.material.app.DayNightDelegate;
|
import rikka.material.app.DayNightDelegate;
|
||||||
import rikka.material.app.LocaleDelegate;
|
import rikka.material.app.LocaleDelegate;
|
||||||
|
|
||||||
|
|
@ -74,10 +75,7 @@ public class App extends Application {
|
||||||
try {
|
try {
|
||||||
var input = App.getInstance().getAssets().open("webview/" + name);
|
var input = App.getInstance().getAssets().open("webview/" + name);
|
||||||
var result = new ByteArrayOutputStream(1024);
|
var result = new ByteArrayOutputStream(1024);
|
||||||
var buffer = new byte[1024];
|
FileUtils.copy(input, result);
|
||||||
for (int length; (length = input.read(buffer)) != -1; ) {
|
|
||||||
result.write(buffer, 0, length);
|
|
||||||
}
|
|
||||||
return result.toString(StandardCharsets.UTF_8.name());
|
return result.toString(StandardCharsets.UTF_8.name());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(App.TAG, "read webview HTML", e);
|
Log.e(App.TAG, "read webview HTML", e);
|
||||||
|
|
|
||||||
|
|
@ -314,15 +314,6 @@ public class ConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, ParcelFileDescriptor> getLogs() {
|
|
||||||
try {
|
|
||||||
return LSPManagerServiceHolder.getService().getLogs();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(App.TAG, Log.getStackTraceString(e));
|
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getApi() {
|
public static String getApi() {
|
||||||
try {
|
try {
|
||||||
return LSPManagerServiceHolder.getService().getApi();
|
return LSPManagerServiceHolder.getService().getApi();
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,11 @@ import org.lsposed.manager.R;
|
||||||
import org.lsposed.manager.databinding.FragmentPagerBinding;
|
import org.lsposed.manager.databinding.FragmentPagerBinding;
|
||||||
import org.lsposed.manager.databinding.ItemLogTextviewBinding;
|
import org.lsposed.manager.databinding.ItemLogTextviewBinding;
|
||||||
import org.lsposed.manager.databinding.SwiperefreshRecyclerviewBinding;
|
import org.lsposed.manager.databinding.SwiperefreshRecyclerviewBinding;
|
||||||
|
import org.lsposed.manager.receivers.LSPManagerServiceHolder;
|
||||||
import org.lsposed.manager.ui.widget.EmptyStateRecyclerView;
|
import org.lsposed.manager.ui.widget.EmptyStateRecyclerView;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
@ -62,11 +62,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import java.util.zip.Deflater;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
|
|
||||||
import rikka.core.os.FileUtils;
|
|
||||||
import rikka.material.app.LocaleDelegate;
|
import rikka.material.app.LocaleDelegate;
|
||||||
import rikka.recyclerview.RecyclerViewKt;
|
import rikka.recyclerview.RecyclerViewKt;
|
||||||
|
|
||||||
|
|
@ -89,11 +85,9 @@ public class LogsFragment extends BaseFragment {
|
||||||
runAsync(() -> {
|
runAsync(() -> {
|
||||||
var context = requireContext();
|
var context = requireContext();
|
||||||
var contentResolver = context.getContentResolver();
|
var contentResolver = context.getContentResolver();
|
||||||
try (var os = new ZipOutputStream(contentResolver.openOutputStream(uri))) {
|
try (var zipFd = contentResolver.openFileDescriptor(uri, "wt")) {
|
||||||
os.setLevel(Deflater.BEST_COMPRESSION);
|
LSPManagerServiceHolder.getService().getLogs(zipFd);
|
||||||
zipLogs(os);
|
} catch (Throwable e) {
|
||||||
os.finish();
|
|
||||||
} catch (IOException e) {
|
|
||||||
var text = context.getString(R.string.logs_save_failed2, e.getMessage());
|
var text = context.getString(R.string.logs_save_failed2, e.getMessage());
|
||||||
showHint(text, false);
|
showHint(text, false);
|
||||||
Log.w(App.TAG, "save log", e);
|
Log.w(App.TAG, "save log", e);
|
||||||
|
|
@ -171,29 +165,6 @@ public class LogsFragment extends BaseFragment {
|
||||||
saveLogsLauncher.launch(filename);
|
saveLogsLauncher.launch(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void zipLogs(ZipOutputStream os) {
|
|
||||||
var logs = ConfigManager.getLogs();
|
|
||||||
logs.forEach((name, fd) -> {
|
|
||||||
try (var is = new FileInputStream(fd.getFileDescriptor())) {
|
|
||||||
os.putNextEntry(new ZipEntry(name));
|
|
||||||
FileUtils.copy(is, os);
|
|
||||||
os.closeEntry();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(App.TAG, name, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var now = LocalDateTime.now();
|
|
||||||
var name = "app_" + now.toString() + ".log";
|
|
||||||
try (var is = new ProcessBuilder("logcat", "-d").start().getInputStream()) {
|
|
||||||
os.putNextEntry(new ZipEntry(name));
|
|
||||||
FileUtils.copy(is, os);
|
|
||||||
os.closeEntry();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w(App.TAG, name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
handler.removeCallbacksAndMessages(null);
|
handler.removeCallbacksAndMessages(null);
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,15 @@ import org.lsposed.manager.App;
|
||||||
import org.lsposed.manager.ConfigManager;
|
import org.lsposed.manager.ConfigManager;
|
||||||
import org.lsposed.manager.adapters.ScopeAdapter;
|
import org.lsposed.manager.adapters.ScopeAdapter;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
import rikka.core.os.FileUtils;
|
||||||
|
|
||||||
public class BackupUtils {
|
public class BackupUtils {
|
||||||
private static final int VERSION = 2;
|
private static final int VERSION = 2;
|
||||||
|
|
||||||
|
|
@ -79,10 +82,9 @@ public class BackupUtils {
|
||||||
public static void restore(Uri uri, String packageName) throws IOException, JSONException {
|
public static void restore(Uri uri, String packageName) throws IOException, JSONException {
|
||||||
try (GZIPInputStream gzipInputStream = new GZIPInputStream(App.getInstance().getContentResolver().openInputStream(uri), 32)) {
|
try (GZIPInputStream gzipInputStream = new GZIPInputStream(App.getInstance().getContentResolver().openInputStream(uri), 32)) {
|
||||||
StringBuilder string = new StringBuilder();
|
StringBuilder string = new StringBuilder();
|
||||||
byte[] data = new byte[32];
|
try (var os = new ByteArrayOutputStream()) {
|
||||||
int bytesRead;
|
FileUtils.copy(gzipInputStream, os);
|
||||||
while ((bytesRead = gzipInputStream.read(data)) != -1) {
|
string.append(os);
|
||||||
string.append(new String(data, 0, bytesRead));
|
|
||||||
}
|
}
|
||||||
gzipInputStream.close();
|
gzipInputStream.close();
|
||||||
JSONObject rootObject = new JSONObject(string.toString());
|
JSONObject rootObject = new JSONObject(string.toString());
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ private:
|
||||||
|
|
||||||
inline void Log(std::string_view str);
|
inline void Log(std::string_view str);
|
||||||
|
|
||||||
void OnCrash();
|
void OnCrash(int err);
|
||||||
|
|
||||||
void ProcessBuffer(struct log_msg *buf);
|
void ProcessBuffer(struct log_msg *buf);
|
||||||
|
|
||||||
|
|
@ -191,7 +191,8 @@ inline void Logcat::Log(std::string_view str) {
|
||||||
fflush(modules_file_.get());
|
fflush(modules_file_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logcat::OnCrash() {
|
void Logcat::OnCrash(int err) {
|
||||||
|
using namespace std::string_literals;
|
||||||
constexpr size_t max_restart_logd_wait = 1U << 10;
|
constexpr size_t max_restart_logd_wait = 1U << 10;
|
||||||
static size_t kLogdCrashCount = 0;
|
static size_t kLogdCrashCount = 0;
|
||||||
static size_t kLogdRestartWait = 1 << 3;
|
static size_t kLogdRestartWait = 1 << 3;
|
||||||
|
|
@ -204,7 +205,7 @@ void Logcat::OnCrash() {
|
||||||
kLogdCrashCount = 0;
|
kLogdCrashCount = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log("\nLogd maybe crashed, retrying in 1s...\n");
|
Log("\nLogd maybe crashed (err="s + strerror(err) + "), retrying in 1s...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
|
|
@ -317,7 +318,7 @@ void Logcat::Run() {
|
||||||
if (modules_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(false);
|
if (modules_print_count_ >= kMaxLogSize) [[unlikely]] RefreshFd(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnCrash();
|
OnCrash(errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.content.res.AssetManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.os.SELinux;
|
import android.os.SELinux;
|
||||||
import android.os.SharedMemory;
|
import android.os.SharedMemory;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
|
|
@ -22,8 +23,12 @@ import org.lsposed.lspd.util.Utils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
|
|
@ -45,7 +50,9 @@ import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import hidden.HiddenApiBridge;
|
import hidden.HiddenApiBridge;
|
||||||
|
|
||||||
|
|
@ -77,6 +84,15 @@ public class ConfigFileManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void transfer(InputStream in, OutputStream out) throws IOException {
|
||||||
|
int size = 8192;
|
||||||
|
var buffer = new byte[size];
|
||||||
|
int read;
|
||||||
|
while ((read = in.read(buffer, 0, size)) >= 0) {
|
||||||
|
out.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void createLogDirPath() throws IOException {
|
private static void createLogDirPath() throws IOException {
|
||||||
if (!Files.isDirectory(logDirPath, LinkOption.NOFOLLOW_LINKS)) {
|
if (!Files.isDirectory(logDirPath, LinkOption.NOFOLLOW_LINKS)) {
|
||||||
Files.deleteIfExists(logDirPath);
|
Files.deleteIfExists(logDirPath);
|
||||||
|
|
@ -194,17 +210,42 @@ public class ConfigFileManager {
|
||||||
return logDirPath.resolve("props.txt").toFile();
|
return logDirPath.resolve("props.txt").toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, ParcelFileDescriptor> getLogs() {
|
static void getLogs(ParcelFileDescriptor zipFd) throws RemoteException {
|
||||||
var map = new LinkedHashMap<String, ParcelFileDescriptor>();
|
var logs = new LinkedHashMap<String, ParcelFileDescriptor>();
|
||||||
try {
|
try (var os = new ZipOutputStream(new FileOutputStream(zipFd.getFileDescriptor()))) {
|
||||||
putFds(map, logDirPath);
|
putFds(logs, logDirPath);
|
||||||
putFds(map, oldLogDirPath);
|
putFds(logs, oldLogDirPath);
|
||||||
putFds(map, Paths.get("/data/tombstones"));
|
putFds(logs, Paths.get("/data/tombstones"));
|
||||||
putFds(map, Paths.get("/data/anr"));
|
putFds(logs, Paths.get("/data/anr"));
|
||||||
} catch (IOException e) {
|
logs.forEach((name, fd) -> {
|
||||||
Log.e(TAG, "getLogs", e);
|
try (var is = new FileInputStream(fd.getFileDescriptor())) {
|
||||||
|
os.putNextEntry(new ZipEntry(name));
|
||||||
|
transfer(is, os);
|
||||||
|
os.closeEntry();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, name, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var name = "full.log";
|
||||||
|
try (var is = new ProcessBuilder("logcat", "-d").start().getInputStream()) {
|
||||||
|
os.putNextEntry(new ZipEntry(name));
|
||||||
|
transfer(is, os);
|
||||||
|
os.closeEntry();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, name, e);
|
||||||
|
}
|
||||||
|
name = "dmesg.log";
|
||||||
|
try (var is = new ProcessBuilder("dmesg").start().getInputStream()) {
|
||||||
|
os.putNextEntry(new ZipEntry(name));
|
||||||
|
transfer(is, os);
|
||||||
|
os.closeEntry();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, name, e);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.w(TAG, "get log", e);
|
||||||
|
throw new RemoteException(Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void putFds(Map<String, ParcelFileDescriptor> map, Path path) throws IOException {
|
private static void putFds(Map<String, ParcelFileDescriptor> map, Path path) throws IOException {
|
||||||
|
|
|
||||||
|
|
@ -711,8 +711,8 @@ public class LSPManagerService extends ILSPManagerService.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, ParcelFileDescriptor> getLogs() {
|
public void getLogs(ParcelFileDescriptor zipFd) throws RemoteException {
|
||||||
return ConfigFileManager.getLogs();
|
ConfigFileManager.getLogs(zipFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ interface ILSPManagerService {
|
||||||
|
|
||||||
void setHiddenIcon(boolean hide) = 33;
|
void setHiddenIcon(boolean hide) = 33;
|
||||||
|
|
||||||
Map<String,ParcelFileDescriptor> getLogs() = 34;
|
void getLogs(in ParcelFileDescriptor zipFd) = 34;
|
||||||
|
|
||||||
void restartFor(in Intent intent) = 35;
|
void restartFor(in Intent intent) = 35;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue