From 477b36acd1a661df7d056a60c77583b36a10aba1 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Wed, 16 Mar 2022 21:19:52 +0500 Subject: [PATCH] Added: Add support for `ACTION_NOTIFY_APP_CRASH` in receiver registered by `TermuxActivity` to notify users of plugin app crashes Once plugins integrate changes for `TermuxCrashUtils.onPostLogCrash()`, they will send the `ACTION_NOTIFY_APP_CRASH` broadcast when an uncaught exception is caught by `CrashHandler`. If `TermuxActivity` is in foreground, then it will receive the broadcast and notify user of the crash by reading it from the crash log file without the user having to restart termux app to be notified. --- .../java/com/termux/app/TermuxActivity.java | 13 ++-- .../termux/shared/termux/TermuxConstants.java | 13 +++- .../shared/termux/crash/TermuxCrashUtils.java | 60 ++++++++++++++++++- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index 5c8f2f72..acbe840c 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -907,8 +907,9 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo private void registerTermuxActivityBroadcastReceiver() { IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(TERMUX_ACTIVITY.ACTION_REQUEST_PERMISSIONS); + intentFilter.addAction(TERMUX_ACTIVITY.ACTION_NOTIFY_APP_CRASH); intentFilter.addAction(TERMUX_ACTIVITY.ACTION_RELOAD_STYLE); + intentFilter.addAction(TERMUX_ACTIVITY.ACTION_REQUEST_PERMISSIONS); registerReceiver(mTermuxActivityBroadcastReceiver, intentFilter); } @@ -936,14 +937,18 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo fixTermuxActivityBroadcastReceieverIntent(intent); switch (intent.getAction()) { - case TERMUX_ACTIVITY.ACTION_REQUEST_PERMISSIONS: - Logger.logDebug(LOG_TAG, "Received intent to request storage permissions"); - requestStoragePermission(false); + case TERMUX_ACTIVITY.ACTION_NOTIFY_APP_CRASH: + Logger.logDebug(LOG_TAG, "Received intent to notify app crash"); + TermuxCrashUtils.notifyAppCrashFromCrashLogFile(context, LOG_TAG); return; case TERMUX_ACTIVITY.ACTION_RELOAD_STYLE: Logger.logDebug(LOG_TAG, "Received intent to reload styling"); reloadActivityStyling(intent.getBooleanExtra(TERMUX_ACTIVITY.EXTRA_RECREATE_ACTIVITY, true)); return; + case TERMUX_ACTIVITY.ACTION_REQUEST_PERMISSIONS: + Logger.logDebug(LOG_TAG, "Received intent to request storage permissions"); + requestStoragePermission(false); + return; default: } } diff --git a/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java b/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java index b7d65411..3c5e0a8e 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/TermuxConstants.java @@ -8,7 +8,7 @@ import java.util.Formatter; import java.util.List; /* - * Version: v0.37.0 + * Version: v0.38.0 * SPDX-License-Identifier: MIT * * Changelog @@ -223,6 +223,9 @@ import java.util.List; * * - 0.37.0 (2022-03-15) * - Added `TERMUX_API_APT_*`. + * + * - 0.38.0 (2022-03-16) + * - Added `TERMUX_APP.TERMUX_ACTIVITY.ACTION_NOTIFY_APP_CRASH`. */ /** @@ -874,8 +877,9 @@ public final class TermuxConstants { public static final String EXTRA_FAILSAFE_SESSION = TermuxConstants.TERMUX_PACKAGE_NAME + ".app.failsafe_session"; // Default: "com.termux.app.failsafe_session" - /** Intent action to make termux request storage permissions */ - public static final String ACTION_REQUEST_PERMISSIONS = TermuxConstants.TERMUX_PACKAGE_NAME + ".app.request_storage_permissions"; // Default: "com.termux.app.request_storage_permissions" + /** Intent action to make termux app notify user that a crash happened. */ + public static final String ACTION_NOTIFY_APP_CRASH = TermuxConstants.TERMUX_PACKAGE_NAME + ".app.notify_app_crash"; // Default: "com.termux.app.notify_app_crash" + /** Intent action to make termux reload its termux session styling */ public static final String ACTION_RELOAD_STYLE = TermuxConstants.TERMUX_PACKAGE_NAME + ".app.reload_style"; // Default: "com.termux.app.reload_style" @@ -886,6 +890,9 @@ public final class TermuxConstants { /** Intent {@code boolean} extra for whether to recreate activity for the TERMUX_ACTIVITY.ACTION_RELOAD_STYLE intent. */ public static final String EXTRA_RECREATE_ACTIVITY = TERMUX_APP.TERMUX_ACTIVITY_NAME + ".EXTRA_RECREATE_ACTIVITY"; // Default: "com.termux.app.TermuxActivity.EXTRA_RECREATE_ACTIVITY" + + /** Intent action to make termux request storage permissions */ + public static final String ACTION_REQUEST_PERMISSIONS = TermuxConstants.TERMUX_PACKAGE_NAME + ".app.request_storage_permissions"; // Default: "com.termux.app.request_storage_permissions" } diff --git a/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java b/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java index 69b8d408..748f569a 100644 --- a/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/termux/crash/TermuxCrashUtils.java @@ -34,12 +34,70 @@ import java.nio.charset.Charset; public class TermuxCrashUtils implements CrashHandler.CrashHandlerClient { + public enum TYPE { + UNCAUGHT_EXCEPTION, + CAUGHT_EXCEPTION; + } + + private final TYPE mType; + + private static final String LOG_TAG = "TermuxCrashUtils"; + + TermuxCrashUtils(TYPE type) { + mType = type; + } + /** * Set default uncaught crash handler of current thread to {@link CrashHandler} for Termux app * and its plugin to log crashes at {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH}. */ public static void setCrashHandler(@NonNull final Context context) { - CrashHandler.setCrashHandler(context, new TermuxCrashUtils()); + CrashHandler.setCrashHandler(context, new TermuxCrashUtils(TYPE.UNCAUGHT_EXCEPTION)); + } + + /** + * Log a crash to {@link TermuxConstants#TERMUX_CRASH_LOG_FILE_PATH} and notify termux app + * by sending it the {@link TERMUX_APP.TERMUX_ACTIVITY#ACTION_NOTIFY_APP_CRASH} broadcast. + * + * @param context The {@link Context} for operations. + * @param throwable The {@link Throwable} thrown for the crash. + */ + public static void logCrash(@NonNull final Context context, final Throwable throwable) { + if (throwable == null) return; + CrashHandler.logCrash(context, new TermuxCrashUtils(TYPE.CAUGHT_EXCEPTION), Thread.currentThread(), throwable); + } + + @Override + public boolean onPreLogCrash(Context context, Thread thread, Throwable throwable) { + return false; + } + + @Override + public void onPostLogCrash(final Context currentPackageContext, Thread thread, Throwable throwable) { + if (currentPackageContext == null) return; + String currentPackageName = currentPackageContext.getPackageName(); + + // Do not notify if is a non-termux app + final Context context = TermuxUtils.getTermuxPackageContext(currentPackageContext); + if (context == null) { + Logger.logWarn(LOG_TAG, "Ignoring call to onPostLogCrash() since failed to get \"" + TermuxConstants.TERMUX_PACKAGE_NAME + "\" package context from \"" + currentPackageName + "\" context"); + return; + } + + // If an uncaught exception, then do not notify since the termux app itself would be crashing + if (TYPE.UNCAUGHT_EXCEPTION.equals(mType) && TermuxConstants.TERMUX_PACKAGE_NAME.equals(currentPackageName)) + return; + + String message = TERMUX_APP.TERMUX_ACTIVITY_NAME + " that \"" + currentPackageName + "\" app crashed"; + + try { + Logger.logInfo(LOG_TAG, "Sending broadcast to notify " + message); + Intent intent = new Intent(TERMUX_APP.TERMUX_ACTIVITY.ACTION_NOTIFY_APP_CRASH); + intent.setPackage(TermuxConstants.TERMUX_PACKAGE_NAME); + context.sendBroadcast(intent); + } catch (Exception e) { + Logger.logStackTraceWithMessage(LOG_TAG,"Failed to notify " + message, e); + } } @NonNull