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.
This commit is contained in:
agnostic-apollo
2022-03-16 21:19:52 +05:00
parent 5f00531381
commit 477b36acd1
3 changed files with 78 additions and 8 deletions

View File

@@ -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:
}
}

View File

@@ -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"
}

View File

@@ -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