Mobile Development 12 min read

Implementing Java and Native Crash Monitoring on Android with the Eagle Eye System

This article explains how to capture and report both Java and native crashes on Android using the Eagle Eye monitoring system, detailing the use of Thread.UncaughtExceptionHandler, Linux signal mechanisms, sigaction registration, alternative stacks, and native stack parsing with libbacktrace to improve app stability.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Implementing Java and Native Crash Monitoring on Android with the Eagle Eye System

During mobile app development and release, crashes are common. While developers can analyze Java crashes from backend logs, online crashes lack stack traces, requiring a tool that captures crash stacks in real time and reports them to a server. The Eagle Eye monitoring system fulfills this need for iOS, Android, RN, and Flutter.

Capturing Java Crashes

The Java layer uses Thread.UncaughtExceptionHandler to intercept uncaught exceptions. By setting a default handler at application startup, all uncaught exceptions are routed to a custom MyCrashHandler which can log and upload the stack trace.

/**
 * Interface for handlers invoked when a
Thread
abruptly
 * terminates due to an uncaught exception.
 * @since 1.5
 */
@FunctionalInterface
public interface UncaughtExceptionHandler {
    /**
     * Method invoked when the given thread terminates due to the
     * given uncaught exception.
     * @param t the thread
     * @param e the exception
     */
    void uncaughtException(Thread t, Throwable e);
}
public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        MyCrashHandler handler = new MyCrashHandler();
        Thread.setDefaultUncaughtExceptionHandler(handler);
    }
}

If multiple modules set handlers, the last one wins; therefore, preserve the previous handler via getDefaultUncaughtExceptionHandler() and invoke it within the new handler.

Linux Signal Mechanism for Native Crashes

Native crashes on Android (C/C++) cannot rely on a unified Java API, so the Linux signal mechanism is used. Signals are delivered to a process, placed in a queue, and can be intercepted by registering a signal handler with sigaction() .

struct sigaction {
  unsigned int sa_flags;
  union {
    sighandler_t sa_handler;
    void (*sa_sigaction)(int, struct siginfo*, void*);
  };
  sigset_t sa_mask;
  void (*sa_restorer)(void);
};

Key fields:

sa_handler : simple handler receiving only the signal number.

sa_sigaction : extended handler receiving signal number, siginfo_t , and context.

sa_mask : signals blocked during handler execution.

sa_flags : e.g., SA_SIGINFO to receive extended info.

Example of defining and registering a handler:

static struct sigaction handler;
memset(&handler, 0, sizeof(handler));
sigemptyset(&handler.sa_mask);
handler.sa_flags = SA_SIGINFO | SA_ONSTACK;
handler.sa_sigaction = my_sigaction;
#include
int sigaction(int sig, const struct sigaction *new_action, struct sigaction *old_action);

Registration loop for common crash‑related signals:

static struct sigaction old_sa[NSIG];
static const int SIGNALS[] = {SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE};
int size = sizeof(SIGNALS) / sizeof(int);
for (int i = 0; i < size; i++) {
    int result = sigaction(SIGNALS[i], &handler, &old_sa[SIGNALS[i]]);
    if (result != 0) { /* handle error */ }
}

To avoid stack overflow when handling SIGSEGV , an alternative signal stack is created with sigaltstack() :

stack_t stack;
memset(&stack, 0, sizeof(stack));
stack.ss_size = SIGSTKSZ;
stack.ss_sp = malloc(stack.ss_size);
stack.ss_flags = 0;
int result = sigaltstack(&stack, NULL);

Parsing Native Stack Traces

The third argument of the signal handler ( void *context ) provides the CPU context. On Android 4.1.1‑4.4, libcorkscrew.so can unwind; on Android 5.0+ use libunwind or libbacktrace . Example with libbacktrace :

mFrameLines.clear();
std::unique_ptr
backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
if (!backtrace->Unwind(0, context)) {
    LOGW("Failed to unwind native stack");
}
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
    mFrameLines.push_back(String8(backtrace->FormatFrameData(i).c_str()));
}

Eagle Eye System Overview

Eagle Eye collects crash data from iOS, Android, RN, and Flutter, providing real‑time statistics, trend analysis, top‑ranking of crash causes, version‑specific views, and detailed crash records (stack, device info, logs). It has been deployed in hundreds of products, helping locate and resolve both Java and native crashes.

Conclusion

The article presented a complete solution for capturing Java and native crashes on Android, implemented in the Eagle Eye SDK, which now supports extensive crash analytics and will soon be opened to external developers.

Javamobile developmentNativeAndroidSignal HandlingCrash MonitoringEagle Eye
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.