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)) {