diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 13a79243..c4de2927 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -56,9 +56,6 @@
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
-
AppHelper.getAppLabel(i, pm));
+ AppHelper.getDenyList(false);
+ ModuleUtil.getInstance();
+ RepoLoader.getInstance();
});
- return false;
- });
-
- Looper.myQueue().addIdleHandler(() -> {
- if (App.getInstance() == null || App.getExecutorService() == null) return true;
- App.getExecutorService().submit(() -> AppHelper.getDenyList(false));
- return false;
- });
- Looper.myQueue().addIdleHandler(() -> {
- if (App.getInstance() == null || App.getExecutorService() == null) return true;
- App.getExecutorService().submit(ModuleUtil::getInstance);
- return false;
- });
- Looper.myQueue().addIdleHandler(() -> {
- if (App.getInstance() == null || App.getExecutorService() == null) return true;
- App.getExecutorService().submit(RepoLoader::getInstance);
+ App.getExecutorService().submit(HTML_TEMPLATE);
+ App.getExecutorService().submit(HTML_TEMPLATE_DARK);
return false;
});
}
@@ -169,41 +160,47 @@ public class App extends Application {
}
}
- @SuppressLint("WrongConstant")
private void setCrashReport() {
+ var handler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
-
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- throwable.printStackTrace(pw);
- String stackTraceString = sw.toString();
-
- //Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.
- //The limit is 1MB on Android but some devices seem to have it lower.
- //See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
- //And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171
- if (stackTraceString.length() > 131071) {
- String disclaimer = " [stack trace too large]";
- stackTraceString = stackTraceString.substring(0, 131071 - disclaimer.length()) + disclaimer;
+ var time = OffsetDateTime.now();
+ var dir = new File(getCacheDir(), "crash");
+ //noinspection ResultOfMethodCallIgnored
+ dir.mkdir();
+ var file = new File(dir, time.toEpochSecond() + ".log");
+ try (var pw = new PrintWriter(file)) {
+ pw.println(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")");
+ pw.println(time);
+ pw.println("pid: " + Os.getpid() + " uid: " + Os.getuid());
+ throwable.printStackTrace(pw);
+ } catch (IOException ignored) {
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ var table = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ var values = new ContentValues();
+ values.put(MediaStore.Downloads.DISPLAY_NAME, "LSPosed_crash_report" + time.toEpochSecond() + ".zip");
+ values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS);
+ var cr = getContentResolver();
+ var uri = cr.insert(table, values);
+ if (uri == null) return;
+ try (var zipFd = cr.openFileDescriptor(uri, "wt")) {
+ LSPManagerServiceHolder.getService().getLogs(zipFd);
+ } catch (Exception ignored) {
+ cr.delete(uri, null, null);
+ }
+ }
+ if (handler != null) {
+ handler.uncaughtException(thread, throwable);
}
- Intent intent = new Intent(App.this, CrashReportActivity.class);
- intent.putExtra(BuildConfig.APPLICATION_ID + ".EXTRA_STACK_TRACE", stackTraceString);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- App.this.startActivity(intent);
- System.exit(10);
- Process.killProcess(Os.getpid());
});
}
@Override
public void onCreate() {
super.onCreate();
- if (!BuildConfig.DEBUG && !isParasitic) {
- setCrashReport();
- }
-
instance = this;
+ setCrashReport();
pref = PreferenceManager.getDefaultSharedPreferences(this);
if (!pref.contains("doh")) {
var name = "private_dns_mode";
@@ -256,17 +253,14 @@ public class App extends Application {
}, intentFilter, Context.RECEIVER_NOT_EXPORTED);
UpdateUtil.loadRemoteVersion();
-
- executorService.submit(HTML_TEMPLATE);
- executorService.submit(HTML_TEMPLATE_DARK);
}
@NonNull
public static OkHttpClient getOkHttpClient() {
if (okHttpClient != null) return okHttpClient;
var builder = new OkHttpClient.Builder()
- .cache(getOkHttpCache())
- .dns(new CloudflareDNS());
+ .cache(getOkHttpCache())
+ .dns(new CloudflareDNS());
if (BuildConfig.DEBUG) {
var log = new HttpLoggingInterceptor();
log.setLevel(HttpLoggingInterceptor.Level.HEADERS);
diff --git a/app/src/main/java/org/lsposed/manager/ui/activity/CrashReportActivity.java b/app/src/main/java/org/lsposed/manager/ui/activity/CrashReportActivity.java
deleted file mode 100644
index e77c1cb6..00000000
--- a/app/src/main/java/org/lsposed/manager/ui/activity/CrashReportActivity.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * This file is part of LSPosed.
- *
- * LSPosed is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LSPosed is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with LSPosed. If not, see .
- *
- * Copyright (C) 2020 EdXposed Contributors
- * Copyright (C) 2021 LSPosed Contributors
- */
-
-package org.lsposed.manager.ui.activity;
-
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.Bundle;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.android.material.color.DynamicColors;
-
-import org.lsposed.manager.BuildConfig;
-import org.lsposed.manager.R;
-import org.lsposed.manager.databinding.ActivityCrashReportBinding;
-import org.lsposed.manager.util.NavUtil;
-
-import java.time.LocalDateTime;
-
-import rikka.material.app.LocaleDelegate;
-import rikka.material.app.MaterialActivity;
-
-public class CrashReportActivity extends MaterialActivity {
- ActivityCrashReportBinding binding;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(R.style.AppTheme);
- super.onCreate(savedInstanceState);
- binding = ActivityCrashReportBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
- binding.sendLogs.setOnClickListener(view -> {
- Intent sendIntent = new Intent();
- sendIntent.setAction(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_TEXT, getAllErrorDetailsFromIntent(getIntent()));
- sendIntent.setType("text/plain");
- startActivity(Intent.createChooser(sendIntent, null));
- });
- binding.reportIssue.setOnClickListener(view -> {
- var clipboard = getSystemService(ClipboardManager.class);
- //Are there any devices without clipboard...?
- if (clipboard != null) {
- ClipData clip = ClipData.newPlainText("LSPManagerCrashInfo",
- getAllErrorDetailsFromIntent(getIntent()));
- clipboard.setPrimaryClip(clip);
- Toast.makeText(this, R.string.crash_info_copied, Toast.LENGTH_LONG).show();
- }
- NavUtil.startURL(this, "https://github.com/LSPosed/LSPosed/issues");
- });
-
- }
-
- @Override
- public void onApplyUserThemeResource(@NonNull Resources.Theme theme, boolean isDecorView) {
- if (!DynamicColors.isDynamicColorAvailable())
- theme.applyStyle(R.style.ThemeOverlay_MaterialBlue, true);
- }
-
- public String getAllErrorDetailsFromIntent(@NonNull Intent intent) {
- String versionName = String.format(LocaleDelegate.getDefaultLocale(), "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE);
-
- return "Build version: " + versionName + " \n" +
- "Current date: " + LocalDateTime.now() + " \n" +
- "Device: " + getDeviceModelName() + " \n" +
- "Fingerprint: " + getFingerprint() + " \n \n" +
- "SDK: " + Build.VERSION.SDK_INT + " \n \n" +
- "Stack trace: \n" +
- getStackTraceFromIntent(intent);
- }
-
- private String getFingerprint() {
- return Build.BRAND + '/' +
- Build.PRODUCT + '/' +
- Build.DEVICE + ':' +
- Build.VERSION.RELEASE + '/' +
- Build.ID + '/' +
- Build.VERSION.INCREMENTAL + ':' +
- Build.TYPE + '/' +
- Build.TAGS;
- }
-
- private String getDeviceModelName() {
- String manufacturer = Build.MANUFACTURER;
- String model = Build.MODEL;
- if (model.startsWith(manufacturer)) {
- return capitalize(model);
- } else {
- return capitalize(manufacturer) + " " + model;
- }
- }
-
- private String capitalize(@Nullable String s) {
- if (s == null || s.length() == 0) {
- return "";
- }
- char first = s.charAt(0);
- if (Character.isUpperCase(first)) {
- return s;
- } else {
- return Character.toUpperCase(first) + s.substring(1);
- }
- }
-
- public String getStackTraceFromIntent(@NonNull Intent intent) {
- return intent.getStringExtra(BuildConfig.APPLICATION_ID + ".EXTRA_STACK_TRACE");
- }
-
-}
diff --git a/app/src/main/res/layout/activity_crash_report.xml b/app/src/main/res/layout/activity_crash_report.xml
deleted file mode 100644
index 2ce43e42..00000000
--- a/app/src/main/res/layout/activity_crash_report.xml
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java
index 3ed4783e..bf91567a 100644
--- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java
+++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java
@@ -24,6 +24,7 @@ import static org.lsposed.lspd.service.ServiceManager.toGlobalNamespace;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
@@ -69,6 +70,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.stream.Collectors;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -248,6 +250,11 @@ public class ConfigFileManager {
zipAddDir(os, oldLogDirPath);
zipAddDir(os, Paths.get("/data/tombstones"));
zipAddDir(os, Paths.get("/data/anr"));
+ var data = Paths.get("/data/data");
+ var app1 = data.resolve(BuildConfig.MANAGER_INJECTED_PKG_NAME + "/cache/crash");
+ var app2 = data.resolve(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME + "/cache/crash");
+ zipAddDir(os, app1);
+ zipAddDir(os, app2);
zipAddProcOutput(os, "full.log", "logcat", "-b", "all", "-d");
zipAddProcOutput(os, "dmesg.log", "dmesg");
var magiskDataDir = Paths.get("/data/adb");
@@ -261,6 +268,14 @@ public class ConfigFileManager {
zipAddFile(os, p.resolve("sepolicy.rule"), magiskDataDir);
});
}
+ var proc = Paths.get("/proc");
+ for (var pid : new String[]{"self", String.valueOf(Binder.getCallingPid())}) {
+ var pidPath = proc.resolve(pid);
+ zipAddFile(os, pidPath.resolve("maps"), proc);
+ zipAddFile(os, pidPath.resolve("mountinfo"), proc);
+ zipAddFile(os, pidPath.resolve("status"), proc);
+ }
+ zipAddFile(os, dbPath.toPath(), configDirPath);
ConfigManager.getInstance().exportScopes(os);
} catch (Throwable e) {
Log.w(TAG, "get log", e);
@@ -299,6 +314,7 @@ public class ConfigFileManager {
}
private static void zipAddDir(ZipOutputStream os, Path path) throws IOException {
+ if (!Files.isDirectory(path)) return;
Files.walkFileTree(path, new SimpleFileVisitor<>() {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (Files.isRegularFile(file)) {