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