diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/TestUtils.java b/backtrace-library/src/androidTest/java/backtraceio/library/TestUtils.java new file mode 100644 index 000000000..7472c92fe --- /dev/null +++ b/backtrace-library/src/androidTest/java/backtraceio/library/TestUtils.java @@ -0,0 +1,16 @@ +package backtraceio.library; + +import java.io.InputStream; + +public class TestUtils { + + public static InputStream readFileAsStream(Object obj, String fileName) { + ClassLoader classLoader = obj.getClass().getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream(fileName); + + if (inputStream != null) { + return inputStream; + } + return null; + } +} diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/anr/BacktraceAppExitInfoSenderHandlerTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/anr/BacktraceAppExitInfoSenderHandlerTest.java new file mode 100644 index 000000000..422f564d4 --- /dev/null +++ b/backtrace-library/src/androidTest/java/backtraceio/library/anr/BacktraceAppExitInfoSenderHandlerTest.java @@ -0,0 +1,163 @@ +package backtraceio.library.anr; + +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.ApplicationExitInfo; +import android.content.Context; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SdkSuppress; +import androidx.test.platform.app.InstrumentationRegistry; + +import net.jodah.concurrentunit.Waiter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import backtraceio.library.BacktraceClient; +import backtraceio.library.BacktraceCredentials; +import backtraceio.library.TestUtils; +import backtraceio.library.events.RequestHandler; +import backtraceio.library.models.BacktraceApiResult; +import backtraceio.library.models.BacktraceData; +import backtraceio.library.models.BacktraceResult; + +@RunWith(AndroidJUnit4.class) +public class BacktraceAppExitInfoSenderHandlerTest { + @Mock + private Context mockContext; + + private final String PACKAGE_NAME = "backtrace.io.tests"; + + private final String ANR_APPEXIT_STACKTRACE_FILE = "anrAppExitInfoStacktrace.txt"; + + private final BacktraceCredentials credentials = new BacktraceCredentials("https://example-endpoint.com/", ""); + private BacktraceClient backtraceClient; + + @Before + public void setUp() throws Exception { + this.mockContext = InstrumentationRegistry.getInstrumentation().getContext(); + this.backtraceClient = new BacktraceClient(this.mockContext, credentials); + } + + private ExitInfo mockApplicationExitInfo(String description, Long timestamp, int reason, + int pid, int importance, long pss, long rss, InputStream stacktrace) throws IOException { + ExitInfo mockExitInfo = mock(ExitInfo.class); + when(mockExitInfo.getDescription()).thenReturn(description); + when(mockExitInfo.getTimestamp()).thenReturn(timestamp); + when(mockExitInfo.getReason()).thenReturn(reason); + when(mockExitInfo.getPid()).thenReturn(pid); + when(mockExitInfo.getImportance()).thenReturn(importance); + when(mockExitInfo.getPss()).thenReturn(pss); + when(mockExitInfo.getRss()).thenReturn(rss); + when(mockExitInfo.getTraceInputStream()).thenReturn(stacktrace); + return mockExitInfo; + } + + private ExitInfo mockApplicationExitInfo(String description, Long timestamp, int reason, InputStream stacktrace) throws IOException { + return mockApplicationExitInfo(description, timestamp, reason, 0, 0, 0L, 0L, stacktrace); + } + + private ProcessExitInfoProvider mockActivityManagerExitInfoProvider() throws IOException { + ActivityManagerExitInfoProvider mock = mock(ActivityManagerExitInfoProvider.class); + final List exitInfoList = new ArrayList<>(); + exitInfoList.add(mockApplicationExitInfo("random-text", System.currentTimeMillis(), ApplicationExitInfo.REASON_CRASH_NATIVE, null)); + exitInfoList.add(mockApplicationExitInfo("anr", System.currentTimeMillis(), ApplicationExitInfo.REASON_ANR, TestUtils.readFileAsStream(this, ANR_APPEXIT_STACKTRACE_FILE))); + exitInfoList.add(mockApplicationExitInfo("anr without stacktrace", System.currentTimeMillis(), ApplicationExitInfo.REASON_ANR, null)); + exitInfoList.add(mockApplicationExitInfo("random-description", System.currentTimeMillis(), ApplicationExitInfo.REASON_LOW_MEMORY, null)); + + when(mock.getHistoricalExitInfo(PACKAGE_NAME, 0, 0)).thenReturn(exitInfoList); + when(mock.getSupportedTypesOfExitInfo()).thenReturn(Collections.singletonList(ApplicationExitInfo.REASON_ANR)); + return mock; + } + + private AnrExitInfoState mockAnrExitInfoState() { + AnrExitInfoState mock = mock(AnrExitInfoState.class); + doNothing().when(mock).saveTimestamp(anyLong()); + when(mock.getLastTimestamp()).thenReturn(0L); + return mock; + } + + @Test + @SdkSuppress(minSdkVersion = android.os.Build.VERSION_CODES.R) + public void checkIfANRIsSentFromAppExitInfo() throws IOException { + // GIVEN + final ProcessExitInfoProvider mockProcessExitInfoProvider = mockActivityManagerExitInfoProvider(); + final AnrExitInfoState anrExitInfoState = mockAnrExitInfoState(); + final Waiter waiter = new Waiter(); + backtraceClient.setOnRequestHandler(new RequestHandler() { + @Override + public BacktraceResult onRequest(BacktraceData data) { + + Map attributes = data.getAttributes(); + Map annotations = data.getAnnotations(); + Map anrAnnotations = (Map) annotations.get("ANR annotations"); + + waiter.assertEquals(data.getReport().getException().getStackTrace().length, 33); + + waiter.assertNotNull(anrAnnotations); + waiter.assertNotNull(attributes); + waiter.assertEquals("anr", anrAnnotations.get("description")); + waiter.assertEquals(ApplicationExitInfo.REASON_ANR, anrAnnotations.get("reason-code")); + waiter.assertEquals("anr", anrAnnotations.get("reason")); + waiter.assertTrue(((Map)annotations.get("ANR parsed stacktrace")).size() > 0); + waiter.assertEquals("backtraceio.library.anr.BacktraceANRExitInfoException", attributes.get("classifier")); + waiter.assertEquals("Hang", attributes.get("error.type")); + waiter.assertTrue(attributes.get("ANR stacktrace").length() > 0); + waiter.resume(); + + return new BacktraceResult(new BacktraceApiResult("_", "ok")); + } + }); + // WHEN + new BacktraceAppExitInfoSenderHandler(this.backtraceClient, PACKAGE_NAME, anrExitInfoState, mockProcessExitInfoProvider); + + // THEN + try { + waiter.await(5, TimeUnit.SECONDS); // Check if anr is detected and event was emitted + } catch (Exception ex) { + fail(ex.getMessage()); + } + } + + @Test + @SdkSuppress(maxSdkVersion = android.os.Build.VERSION_CODES.Q) + public void checkIfANRIsNotSentOnOldSDK() throws IOException { + // GIVEN + final int THREAD_SLEEP_TIME_MS = 3000; + final ProcessExitInfoProvider mockProcessExitInfoProvider = mockActivityManagerExitInfoProvider(); + final AnrExitInfoState anrExitInfoState = mockAnrExitInfoState(); + final Waiter waiter = new Waiter(); + backtraceClient.setOnRequestHandler(new RequestHandler() { + @Override + public BacktraceResult onRequest(BacktraceData data) { + waiter.fail(); + return new BacktraceResult(new BacktraceApiResult("_", "ok")); + } + }); + // WHEN + new BacktraceAppExitInfoSenderHandler(this.backtraceClient, PACKAGE_NAME, anrExitInfoState, mockProcessExitInfoProvider); + + // THEN + try { + Thread.sleep(THREAD_SLEEP_TIME_MS); + } catch (Exception ex) { + fail(ex.getMessage()); + } + System.out.println("wat"); + } +} diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/common/SharedPreferencesManagerTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/common/SharedPreferencesManagerTest.java new file mode 100644 index 000000000..a74b8aec0 --- /dev/null +++ b/backtrace-library/src/androidTest/java/backtraceio/library/common/SharedPreferencesManagerTest.java @@ -0,0 +1,76 @@ +package backtraceio.library.common; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.SharedPreferences; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SharedPreferencesManagerTest { + + private SharedPreferencesManager sharedPreferencesManager; + + @Mock + private Context mockContext; + + @Mock + private SharedPreferences mockSharedPreferences; + + @Mock + private SharedPreferences.Editor mockEditor; + + @Before + public void setUp() { + sharedPreferencesManager = new SharedPreferencesManager(mockContext); + when(mockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mockSharedPreferences); + when(mockSharedPreferences.edit()).thenReturn(mockEditor); + when(mockEditor.putLong(anyString(), anyLong())).thenReturn(mockEditor); + } + + @Test + public void testSaveLongToSharedPreferences() { + // GIVEN + String prefName = "test_prefs"; + String key = "test_key"; + long value = 12345L; + + // WHEN + sharedPreferencesManager.saveLongToSharedPreferences(prefName, key, value); + + // THEN + verify(mockContext).getSharedPreferences(prefName, Context.MODE_PRIVATE); + verify(mockSharedPreferences).edit(); + verify(mockEditor).putLong(key, value); + verify(mockEditor).commit(); + } + + @Test + public void testReadLongFromSharedPreferences() { + // GIVEN + String prefName = "test_prefs"; + String key = "test_key"; + long defaultValue = 0L; + Long expectedValue = 12345L; + + // WHEN + when(mockSharedPreferences.getLong(key, defaultValue)).thenReturn(expectedValue); + + // THEN + Long result = sharedPreferencesManager.readLongFromSharedPreferences(prefName, key, defaultValue); + + verify(mockContext).getSharedPreferences(prefName, Context.MODE_PRIVATE); + verify(mockSharedPreferences).getLong(key, defaultValue); + assertEquals(expectedValue, result); + } +} diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/watchdog/BacktraceAnrTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/watchdog/BacktraceAnrTest.java index 7cd1ff2c1..577fe77be 100644 --- a/backtrace-library/src/androidTest/java/backtraceio/library/watchdog/BacktraceAnrTest.java +++ b/backtrace-library/src/androidTest/java/backtraceio/library/watchdog/BacktraceAnrTest.java @@ -40,7 +40,7 @@ public void setUp() { public void checkIfANRIsDetectedCorrectly() { // GIVEN final Waiter waiter = new Waiter(); - BacktraceANRWatchdog watchdog = new BacktraceANRWatchdog(this.backtraceClient, 500); + BacktraceANRHandlerWatchdog watchdog = new BacktraceANRHandlerWatchdog(this.backtraceClient, 500); watchdog.setOnApplicationNotRespondingEvent(new OnApplicationNotRespondingEvent() { @Override public void onEvent(BacktraceWatchdogTimeoutException exception) { @@ -96,7 +96,7 @@ public void checkIfANRIsNotDetected() { // GIVEN final int numberOfIterations = 5; final Waiter waiter = new Waiter(); - BacktraceANRWatchdog watchdog = new BacktraceANRWatchdog(this.backtraceClient, 5000); + BacktraceANRHandlerWatchdog watchdog = new BacktraceANRHandlerWatchdog(this.backtraceClient, 5000); watchdog.setOnApplicationNotRespondingEvent(new OnApplicationNotRespondingEvent() { @Override public void onEvent(BacktraceWatchdogTimeoutException exception) { @@ -145,4 +145,4 @@ public void onEvent(BacktraceWatchdogTimeoutException exception) { fail(e.getMessage()); } } -} \ No newline at end of file +} diff --git a/backtrace-library/src/androidTest/resources/anrAppExitInfoStacktrace.txt b/backtrace-library/src/androidTest/resources/anrAppExitInfoStacktrace.txt new file mode 100644 index 000000000..0dbdb10f1 --- /dev/null +++ b/backtrace-library/src/androidTest/resources/anrAppExitInfoStacktrace.txt @@ -0,0 +1,523 @@ + +----- pid 9207 at 2025-03-27 21:02:38 ----- +Cmd line: backtraceio.backtraceio +Build fingerprint: 'google/sdk_gphone_x86/generic_x86_arm:11/RSR1.201013.001/6903271:user/release-keys' +ABI: 'x86' +Build type: optimized +Zygote loaded classes=15747 post zygote classes=1481 +Dumping registered class loaders +#0 dalvik.system.PathClassLoader: [], parent #1 +#1 java.lang.BootClassLoader: [], no parent +#2 dalvik.system.PathClassLoader: [/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes15.dex:/data/data/backtraceio.backtraceio/code_cache/.overlay/base.apk/classes16.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes10.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes8.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes2.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes4.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes3.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes17.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes11.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes14.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes9.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes7.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes12.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes6.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes13.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes5.dex], parent #1 +Done dumping class loaders +Classes initialized: 760 in 140.777ms +Intern table: 32164 strong; 519 weak +JNI: CheckJNI is on; globals=640 (plus 60 weak) +Libraries: /data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!/lib/x86/libbacktrace-native.so /data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!/lib/x86/libnative-lib.so libandroid.so libaudioeffect_jni.so libcompiler_rt.so libicu_jni.so libjavacore.so libjavacrypto.so libjnigraphics.so libmedia_jni.so libopenjdk.so librs_jni.so libsfplugin_ccodec.so libsoundpool.so libstats_jni.so libwebviewchromium_loader.so (16) +Heap: 74% free, 6892KB/25MB; 138095 objects +Dumping cumulative Gc timings +Average major GC reclaim bytes ratio inf over 0 GC cycles +Average major GC copied live bytes ratio 0.72272 over 4 major GCs +Cumulative bytes moved 11312128 +Cumulative objects moved 212604 +Peak regions allocated 27 (6912KB) / 768 (192MB) +Start Dumping histograms for 1 iterations for young concurrent copying +GrayAllDirtyImmuneObjects: Sum: 12.004ms 99% C.I. 12.004ms-12.004ms Avg: 12.004ms Max: 12.004ms +InitializePhase: Sum: 11.934ms 99% C.I. 11.934ms-11.934ms Avg: 11.934ms Max: 11.934ms +ProcessMarkStack: Sum: 9.977ms 99% C.I. 9.977ms-9.977ms Avg: 9.977ms Max: 9.977ms +ScanImmuneSpaces: Sum: 4.691ms 99% C.I. 4.691ms-4.691ms Avg: 4.691ms Max: 4.691ms +EnqueueFinalizerReferences: Sum: 4.233ms 99% C.I. 4.233ms-4.233ms Avg: 4.233ms Max: 4.233ms +ScanCardsForSpace: Sum: 3.451ms 99% C.I. 3.451ms-3.451ms Avg: 3.451ms Max: 3.451ms +VisitConcurrentRoots: Sum: 3.005ms 99% C.I. 3.005ms-3.005ms Avg: 3.005ms Max: 3.005ms +ResetStack: Sum: 1.680ms 99% C.I. 1.680ms-1.680ms Avg: 1.680ms Max: 1.680ms +SweepSystemWeaks: Sum: 1.050ms 99% C.I. 1.050ms-1.050ms Avg: 1.050ms Max: 1.050ms +ClearFromSpace: Sum: 423us 99% C.I. 423us-423us Avg: 423us Max: 423us +FlipOtherThreads: Sum: 333us 99% C.I. 333us-333us Avg: 333us Max: 333us +ForwardSoftReferences: Sum: 289us 99% C.I. 289us-289us Avg: 289us Max: 289us +SweepArray: Sum: 202us 99% C.I. 202us-202us Avg: 202us Max: 202us +EmptyRBMarkBitStack: Sum: 121us 99% C.I. 121us-121us Avg: 121us Max: 121us +VisitNonThreadRoots: Sum: 42us 99% C.I. 42us-42us Avg: 42us Max: 42us +FlipThreadRoots: Sum: 38us 99% C.I. 38us-38us Avg: 38us Max: 38us +ProcessReferences: Sum: 26us 99% C.I. 1us-25us Avg: 13us Max: 25us +(Paused)GrayAllNewlyDirtyImmuneObjects: Sum: 25us 99% C.I. 25us-25us Avg: 25us Max: 25us +(Paused)ClearCards: Sum: 19us 99% C.I. 0.250us-13us Avg: 1.461us Max: 13us +CopyingPhase: Sum: 17us 99% C.I. 17us-17us Avg: 17us Max: 17us +MarkZygoteLargeObjects: Sum: 16us 99% C.I. 16us-16us Avg: 16us Max: 16us +ThreadListFlip: Sum: 14us 99% C.I. 14us-14us Avg: 14us Max: 14us +SwapBitmaps: Sum: 9us 99% C.I. 9us-9us Avg: 9us Max: 9us +FreeList: Sum: 6us 99% C.I. 6us-6us Avg: 6us Max: 6us +ResumeRunnableThreads: Sum: 4us 99% C.I. 4us-4us Avg: 4us Max: 4us +(Paused)FlipCallback: Sum: 2us 99% C.I. 2us-2us Avg: 2us Max: 2us +(Paused)SetFromSpace: Sum: 1us 99% C.I. 1us-1us Avg: 1us Max: 1us +Done Dumping histograms +young concurrent copying paused: Sum: 63us 99% C.I. 63us-63us Avg: 63us Max: 63us +young concurrent copying freed-bytes: Avg: 1905KB Max: 1905KB Min: 1905KB +Freed-bytes histogram: 1600:1 +young concurrent copying total time: 53.653ms mean time: 53.653ms +young concurrent copying freed: 25923 objects with total size 1905KB +young concurrent copying throughput: 489113/s / 35MB/s per cpu-time: 47582634/s / 45MB/s +Average minor GC reclaim bytes ratio 0.92539 over 1 GC cycles +Average minor GC copied live bytes ratio 0.133529 over 2 minor GCs +Cumulative bytes moved 870264 +Cumulative objects moved 16602 +Peak regions allocated 27 (6912KB) / 768 (192MB) +Total time spent in GC: 53.653ms +Mean GC size throughput: 34MB/s per cpu-time: 44MB/s +Mean GC object throughput: 483160 objects/s +Total number of allocations 164018 +Total bytes allocated 8797KB +Total bytes freed 1905KB +Free memory 19MB +Free memory until GC 19MB +Free memory until OOME 185MB +Total memory 25MB +Max memory 192MB +Zygote space size 2980KB +Total mutator paused time: 63us +Total time waiting for GC to complete: 4.459us +Total GC count: 1 +Total GC time: 53.653ms +Total blocking GC count: 0 +Total blocking GC time: 0 +Native bytes total: 15962696 registered: 108600 +Total native bytes at last GC: 4019588 +/system/framework/oat/x86/android.hidl.manager-V1.0-java.odex: quicken +/system/framework/oat/x86/android.test.base.odex: quicken +/system/framework/oat/x86/android.hidl.base-V1.0-java.odex: quicken +Current JIT code cache size (used / resident): 52KB / 60KB +Current JIT data cache size (used / resident): 61KB / 96KB +Zygote JIT code cache size (at point of fork): 42KB / 44KB +Zygote JIT data cache size (at point of fork): 31KB / 36KB +Current JIT mini-debug-info size: 50KB +Current JIT capacity: 128KB +Current number of JIT JNI stub entries: 2 +Current number of JIT code cache entries: 207 +Total number of JIT compilations: 172 +Total number of JIT compilations for on stack replacement: 7 +Total number of JIT code cache collections: 1 +Memory used for stack maps: Avg: 85B Max: 660B Min: 12B +Memory used for compiled code: Avg: 324B Max: 2604B Min: 17B +Memory used for profiling info: Avg: 74B Max: 764B Min: 20B +Start Dumping histograms for 212 iterations for JIT timings +Compiling: Sum: 540.855ms 99% C.I. 0.030ms-21.292ms Avg: 2.563ms Max: 24.444ms +TrimMaps: Sum: 77.018ms 99% C.I. 1.850us-4245us Avg: 365.014us Max: 9813us +Code cache collection: Sum: 3.847ms 99% C.I. 3.847ms-3.847ms Avg: 3.847ms Max: 3.847ms +Done Dumping histograms +Memory used for compilation: Avg: 36KB Max: 322KB Min: 0B +ProfileSaver total_bytes_written=4974 +ProfileSaver total_number_of_writes=1 +ProfileSaver total_number_of_code_cache_queries=1 +ProfileSaver total_number_of_skipped_writes=0 +ProfileSaver total_number_of_failed_writes=0 +ProfileSaver total_ms_of_sleep=45000 +ProfileSaver total_ms_of_work=10 +ProfileSaver total_number_of_hot_spikes=4 +ProfileSaver total_number_of_wake_ups=3 + +suspend all histogram: Sum: 301us 99% C.I. 0.090us-104us Avg: 11.148us Max: 104us +DALVIK THREADS (20): +"Signal Catcher" daemon prio=10 tid=4 Runnable + | group="system" sCount=0 dsCount=0 flags=0 obj=0x13040b28 self=0xe738a810 + | sysTid=9216 nice=-20 cgrp=top-app sched=0/0 handle=0xdc5da1e0 + | state=R schedstat=( 17573906 201748 7 ) utm=0 stm=1 core=0 HZ=100 + | stack=0xdc4df000-0xdc4e1000 stackSize=1008KB + | held mutexes= "mutator lock"(shared held) + native: #00 pc 00542d9e /apex/com.android.art/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+110) + native: #01 pc 006a0897 /apex/com.android.art/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream >&, bool, BacktraceMap*, bool) const+1015) + native: #02 pc 0069a171 /apex/com.android.art/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream >&, bool, BacktraceMap*, bool) const+65) + native: #03 pc 006c61b4 /apex/com.android.art/lib/libart.so (art::DumpCheckpoint::Run(art::Thread*)+1172) + native: #04 pc 006bf266 /apex/com.android.art/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+630) + native: #05 pc 006be1ce /apex/com.android.art/lib/libart.so (art::ThreadList::Dump(std::__1::basic_ostream >&, bool)+2446) + native: #06 pc 006bd70c /apex/com.android.art/lib/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream >&)+1644) + native: #07 pc 0064d654 /apex/com.android.art/lib/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream >&)+212) + native: #08 pc 00665b6a /apex/com.android.art/lib/libart.so (art::SignalCatcher::HandleSigQuit()+1818) + native: #09 pc 0066496b /apex/com.android.art/lib/libart.so (art::SignalCatcher::Run(void*)+587) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + + +//expected api request to coroner api +// java stacktrace +(String declaringClass, String methodName, String fileName, int lineNumber) + + +// native stack +{ +"funcName": "syscall", +"library": "/apex/com.android.runtime/lib/bionic/libc.so", +"address": "0005ad68" +} + + + +"main" prio=5 tid=1 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x72287300 self=0xe7380e10 + | sysTid=9207 nice=-10 cgrp=top-app sched=0/0 handle=0xf583f478 + | state=S schedstat=( 44727379364 813394028 1292 ) utm=1691 stm=2781 core=1 HZ=100 + | stack=0xff020000-0xff022000 stackSize=8192KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 007894db /apex/com.android.art/lib/libart.so (art::GoToRunnable(art::Thread*)+507) + native: #05 pc 007892a1 /apex/com.android.art/lib/libart.so (art::JniMethodEnd(unsigned int, art::Thread*)+33) + native: #06 pc 02008de3 /memfd:jit-cache (deleted) (offset 2000000) (art_jni_trampoline+163) + native: #07 pc 02008cee /memfd:jit-cache (deleted) (offset 2000000) (backtraceio.backtraceio.MainActivity.handledException+46) + native: #08 pc 00142c04 /apex/com.android.art/lib/libart.so (art_quick_osr_stub+36) + native: #09 pc 003b138f /apex/com.android.art/lib/libart.so (art::jit::Jit::MaybeDoOnStackReplacement(art::Thread*, art::ArtMethod*, unsigned int, int, art::JValue*)+415) + native: #10 pc 007b2bf9 /apex/com.android.art/lib/libart.so (MterpMaybeDoOnStackReplacement+185) + native: #11 pc 0013a2f5 /apex/com.android.art/lib/libart.so (MterpHelpers+294) + native: #12 pc 00001034 /data/data/backtraceio.backtraceio/code_cache/.overlay/base.apk/classes16.dex (backtraceio.backtraceio.MainActivity.handledException+8) + native: #13 pc 0036fb02 /apex/com.android.art/lib/libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.16375758241455872412)+370) + native: #14 pc 00379b00 /apex/com.android.art/lib/libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+176) + native: #15 pc 0078b325 /apex/com.android.art/lib/libart.so (artQuickToInterpreterBridge+1061) + native: #16 pc 0014220d /apex/com.android.art/lib/libart.so (art_quick_to_interpreter_bridge+77) + native: #17 pc 0013b922 /apex/com.android.art/lib/libart.so (art_quick_invoke_stub+338) + native: #18 pc 001d0381 /apex/com.android.art/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+241) + native: #19 pc 00630008 /apex/com.android.art/lib/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)+1464) + native: #20 pc 005886a0 /apex/com.android.art/lib/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+80) + at java.lang.Thread.yield(Native method) + at backtraceio.backtraceio.MainActivity.handledException(MainActivity.java:157) + at java.lang.reflect.Method.invoke(Native method) + at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:468) + at android.view.View.performClick(View.java:7448) + at android.view.View.performClickInternal(View.java:7425) + at android.view.View.access$3600(View.java:810) + at android.view.View$PerformClick.run(View.java:28305) + at android.os.Handler.handleCallback(Handler.java:938) + at android.os.Handler.dispatchMessage(Handler.java:99) + at android.os.Looper.loop(Looper.java:223) + at android.app.ActivityThread.main(ActivityThread.java:7656) + at java.lang.reflect.Method.invoke(Native method) + at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) + at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) + +"ADB-JDWP Connection Control Thread" daemon prio=0 tid=5 WaitingInMainDebuggerLoop + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040ba0 self=0xe738c410 + | sysTid=9218 nice=-20 cgrp=top-app sched=0/0 handle=0xdc3d81e0 + | state=S schedstat=( 4694215 13986760 9 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xdc2dd000-0xdc2df000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf496 /apex/com.android.runtime/lib/bionic/libc.so (__ppoll+38) + native: #02 pc 00083979 /apex/com.android.runtime/lib/bionic/libc.so (poll+105) + native: #03 pc 0000a493 /apex/com.android.art/lib/libadbconnection.so (adbconnection::AdbConnectionState::RunPollLoop(art::Thread*)+1171) + native: #04 pc 000086d2 /apex/com.android.art/lib/libadbconnection.so (adbconnection::CallbackFunction(void*)+1666) + native: #05 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #06 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"perfetto_hprof_listener" prio=10 tid=6 Native (still starting up) + | group="" sCount=1 dsCount=0 flags=1 obj=0x0 self=0xe7385410 + | sysTid=9217 nice=-20 cgrp=top-app sched=0/0 handle=0xdc4d91e0 + | state=S schedstat=( 6280850 9339243 10 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xdc3de000-0xdc3e0000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000ccf9c /apex/com.android.runtime/lib/bionic/libc.so (read+28) + native: #02 pc 0001aca2 /apex/com.android.art/lib/libperfetto_hprof.so (void* std::__1::__thread_proxy >, ArtPlugin_Initialize::$_29> >(void*)+306) + native: #03 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #04 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"HeapTaskDaemon" daemon prio=5 tid=7 WaitingForTaskProcessor + | group="system" sCount=1 dsCount=0 flags=1 obj=0x130410c8 self=0xe7384610 + | sysTid=9220 nice=4 cgrp=top-app sched=0/0 handle=0xc74921e0 + | state=S schedstat=( 43450902 17904055 20 ) utm=1 stm=2 core=1 HZ=100 + | stack=0xc738f000-0xc7391000 stackSize=1040KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 0034a036 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::GetTask(art::Thread*)+630) + native: #05 pc 0034aa64 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::RunAllTasks(art::Thread*)+84) + native: #06 pc 005591f5 /apex/com.android.art/lib/libart.so (art::VMRuntime_runHeapTasks(_JNIEnv*, _jobject*)+53) + at dalvik.system.VMRuntime.runHeapTasks(Native method) + at java.lang.Daemons$HeapTaskDaemon.runInternal(Daemons.java:531) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"Binder:9207_1" prio=5 tid=8 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040c18 self=0xe7380010 + | sysTid=9224 nice=0 cgrp=top-app sched=0/0 handle=0xc6f701e0 + | state=S schedstat=( 1496174 7615537 6 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc6e75000-0xc6e77000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"FinalizerWatchdogDaemon" daemon prio=5 tid=9 Waiting + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040c90 self=0xe7382a10 + | sysTid=9223 nice=4 cgrp=top-app sched=0/0 handle=0xc71771e0 + | state=S schedstat=( 398422 6565402 4 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc7074000-0xc7076000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x02d3c777> (a java.lang.Daemons$FinalizerWatchdogDaemon) + at java.lang.Object.wait(Object.java:442) + at java.lang.Object.wait(Object.java:568) + at java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:341) + - locked <0x02d3c777> (a java.lang.Daemons$FinalizerWatchdogDaemon) + at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:321) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"ReferenceQueueDaemon" daemon prio=5 tid=10 Waiting + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040d08 self=0xe7388c10 + | sysTid=9221 nice=4 cgrp=top-app sched=0/0 handle=0xc73891e0 + | state=S schedstat=( 533566 3015911 3 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc7286000-0xc7288000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x07fc5fe4> (a java.lang.Class) + at java.lang.Object.wait(Object.java:442) + at java.lang.Object.wait(Object.java:568) + at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:217) + - locked <0x07fc5fe4> (a java.lang.Class) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"Jit thread pool worker thread 0" daemon prio=5 tid=11 Native + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040d80 self=0xe7387e10 + | sysTid=9219 nice=0 cgrp=top-app sched=0/0 handle=0xc7596d60 + | state=S schedstat=( 468316720 500776964 211 ) utm=6 stm=39 core=0 HZ=100 + | stack=0xc7498000-0xc749a000 stackSize=1023KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 006c838f /apex/com.android.art/lib/libart.so (art::ThreadPool::GetTask(art::Thread*)+143) + native: #05 pc 006c73e5 /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Run()+133) + native: #06 pc 006c6e9d /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Callback(void*)+269) + native: #07 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #08 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"FinalizerDaemon" daemon prio=5 tid=12 Waiting + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040df8 self=0xe7386210 + | sysTid=9222 nice=4 cgrp=top-app sched=0/0 handle=0xc72801e0 + | state=S schedstat=( 1102483 7783564 5 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc717d000-0xc717f000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x0a047c4d> (a java.lang.Object) + at java.lang.Object.wait(Object.java:442) + at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190) + - locked <0x0a047c4d> (a java.lang.Object) + at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211) + at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:273) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"Binder:9207_2" prio=5 tid=13 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040e70 self=0xe7389a10 + | sysTid=9225 nice=0 cgrp=top-app sched=0/0 handle=0xc6e6f1e0 + | state=S schedstat=( 210561432 574003421 20 ) utm=10 stm=10 core=1 HZ=100 + | stack=0xc6d74000-0xc6d76000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"Binder:9207_3" prio=5 tid=14 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040ee8 self=0xe7391810 + | sysTid=9226 nice=0 cgrp=top-app sched=0/0 handle=0xc6d6e1e0 + | state=S schedstat=( 17000557 50151632 14 ) utm=0 stm=1 core=1 HZ=100 + | stack=0xc6c73000-0xc6c75000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"Binder:9207_4" prio=5 tid=15 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040f60 self=0xe7390a10 + | sysTid=9227 nice=0 cgrp=top-app sched=0/0 handle=0xc68411e0 + | state=S schedstat=( 8392907 55881465 12 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc6746000-0xc6748000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"Profile Saver" daemon prio=5 tid=16 Native + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040fd8 self=0xe738ee10 + | sysTid=9228 nice=9 cgrp=top-app sched=0/0 handle=0xc67401e0 + | state=S schedstat=( 14918009 13675595 16 ) utm=1 stm=0 core=1 HZ=100 + | stack=0xc6645000-0xc6647000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 003cc829 /apex/com.android.art/lib/libart.so (art::ProfileSaver::Run()+633) + native: #05 pc 003d2e8f /apex/com.android.art/lib/libart.so (art::ProfileSaver::RunProfileSaverThread(void*)+175) + native: #06 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #07 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"RenderThread" daemon prio=7 tid=17 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13041050 self=0xe7392610 + | sysTid=9229 nice=-10 cgrp=top-app sched=0/0 handle=0xc663f1e0 + | state=S schedstat=( 236695461 71606987 112 ) utm=4 stm=19 core=1 HZ=100 + | stack=0xc6544000-0xc6546000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43) + native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45) + native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259) + native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118) + native: #05 pc 002452c5 /system/lib/libhwui.so (android::uirenderer::ThreadBase::waitForWork()+149) + native: #06 pc 0026cab7 /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+119) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #09 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #10 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"BacktraceHandlerThread" prio=5 tid=18 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12cf4660 self=0xe738fc10 + | sysTid=9232 nice=0 cgrp=top-app sched=0/0 handle=0xc64281e0 + | state=S schedstat=( 313706628 570346891 185 ) utm=20 stm=11 core=0 HZ=100 + | stack=0xc6325000-0xc6327000 stackSize=1040KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43) + native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45) + native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259) + native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118) + native: #05 pc 0010ef8b /system/lib/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long long, int)+59) + at android.os.MessageQueue.nativePollOnce(Native method) + at android.os.MessageQueue.next(MessageQueue.java:335) + at android.os.Looper.loop(Looper.java:183) + at android.os.HandlerThread.run(HandlerThread.java:67) + +"Timer-0" prio=5 tid=19 TimedWaiting + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12cf5498 self=0xe738e010 + | sysTid=9233 nice=0 cgrp=top-app sched=0/0 handle=0xc62461e0 + | state=S schedstat=( 7524451 0 14 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc6143000-0xc6145000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x02569302> (a java.util.TaskQueue) + at java.lang.Object.wait(Object.java:442) + at java.util.TimerThread.mainLoop(Timer.java:559) + - locked <0x02569302> (a java.util.TaskQueue) + at java.util.TimerThread.run(Timer.java:512) + +"WifiManagerThread" prio=5 tid=20 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12cff1c0 self=0xe7399610 + | sysTid=9236 nice=0 cgrp=top-app sched=0/0 handle=0xc613d1e0 + | state=S schedstat=( 581694 0 1 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc603a000-0xc603c000 stackSize=1040KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43) + native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45) + native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259) + native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118) + native: #05 pc 0010ef8b /system/lib/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long long, int)+59) + at android.os.MessageQueue.nativePollOnce(Native method) + at android.os.MessageQueue.next(MessageQueue.java:335) + at android.os.Looper.loop(Looper.java:183) + at android.os.HandlerThread.run(HandlerThread.java:67) + +"Thread-4" prio=5 tid=21 Sleeping + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12d8a710 self=0xe7394210 + | sysTid=9237 nice=0 cgrp=top-app sched=0/0 handle=0xc60341e0 + | state=S schedstat=( 76232117 47640734 71 ) utm=5 stm=2 core=0 HZ=100 + | stack=0xc5f31000-0xc5f33000 stackSize=1040KB + | held mutexes= + at java.lang.Thread.sleep(Native method) + - sleeping on <0x05336413> (a java.lang.Object) + at java.lang.Thread.sleep(Thread.java:442) + - locked <0x05336413> (a java.lang.Object) + at java.lang.Thread.sleep(Thread.java:358) + at backtraceio.library.watchdog.BacktraceANRHandlerWatchdog.run(BacktraceANRHandlerWatchdog.java:118) + +"OkHttp ConnectionPool" daemon prio=5 tid=22 TimedWaiting + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12d39c50 self=0xe739b210 + | sysTid=9239 nice=0 cgrp=top-app sched=0/0 handle=0xc56251e0 + | state=S schedstat=( 442059 1414330 1 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc5522000-0xc5524000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x09119650> (a com.android.okhttp.ConnectionPool) + at com.android.okhttp.ConnectionPool$1.run(ConnectionPool.java:106) + - locked <0x09119650> (a com.android.okhttp.ConnectionPool) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) + at java.lang.Thread.run(Thread.java:923) + +----- end 9207 ----- + +----- Waiting Channels: pid 9207 at 2025-03-27 21:02:38 ----- +Cmd line: backtraceio.backtraceio + +sysTid=9207 0 +sysTid=9216 do_sigtimedwait +sysTid=9217 pipe_read +sysTid=9218 do_sys_poll +sysTid=9219 futex_wait_queue_me +sysTid=9220 futex_wait_queue_me +sysTid=9221 futex_wait_queue_me +sysTid=9222 futex_wait_queue_me +sysTid=9223 futex_wait_queue_me +sysTid=9224 binder_thread_read +sysTid=9225 binder_thread_read +sysTid=9226 binder_thread_read +sysTid=9227 binder_thread_read +sysTid=9228 futex_wait_queue_me +sysTid=9229 do_epoll_wait +sysTid=9232 do_epoll_wait +sysTid=9233 futex_wait_queue_me +sysTid=9236 do_epoll_wait +sysTid=9237 futex_wait_queue_me +sysTid=9239 futex_wait_queue_me + +----- end 9207 ----- + diff --git a/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java b/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java index 0426e96f9..2cb8f812f 100644 --- a/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java +++ b/backtrace-library/src/main/java/backtraceio/library/BacktraceClient.java @@ -6,12 +6,16 @@ import java.util.List; import java.util.Map; +import backtraceio.library.anr.AnrType; +import backtraceio.library.anr.BacktraceANRHandler; +import backtraceio.library.anr.BacktraceANRSettings; +import backtraceio.library.anr.BacktraceAppExitInfoSenderHandler; import backtraceio.library.base.BacktraceBase; import backtraceio.library.events.OnServerResponseEventListener; import backtraceio.library.interfaces.Database; import backtraceio.library.models.database.BacktraceDatabaseSettings; import backtraceio.library.models.json.BacktraceReport; -import backtraceio.library.watchdog.BacktraceANRWatchdog; +import backtraceio.library.watchdog.BacktraceANRHandlerWatchdog; import backtraceio.library.watchdog.OnApplicationNotRespondingEvent; /** @@ -22,7 +26,7 @@ public class BacktraceClient extends BacktraceBase { /** * Backtrace ANR watchdog instance */ - private BacktraceANRWatchdog anrWatchdog; + private BacktraceANRHandler anrHandler; /** * Initializing Backtrace client instance with BacktraceCredentials @@ -252,7 +256,10 @@ public void send(BacktraceReport report, OnServerResponseEventListener * Start monitoring if the main thread has been blocked */ public void enableAnr() { - this.anrWatchdog = new BacktraceANRWatchdog(this); + this.enableAnr(AnrType.Threshold); + } + public void enableAnr(AnrType anrType) { + this.enableAnr(anrType, new BacktraceANRSettings()); } /** @@ -292,16 +299,41 @@ public void enableAnr(int timeout, boolean debug) { * @param debug enable debug mode - errors will not be sent if the debugger is connected */ public void enableAnr(int timeout, OnApplicationNotRespondingEvent onApplicationNotRespondingEvent, boolean debug) { - this.anrWatchdog = new BacktraceANRWatchdog(this, timeout, debug); - this.anrWatchdog.setOnApplicationNotRespondingEvent(onApplicationNotRespondingEvent); + this.enableAnr(new BacktraceANRSettings(timeout, onApplicationNotRespondingEvent, debug)); + } + + public void enableAnr(BacktraceANRSettings anrSettings) { + this.enableAnr(AnrType.Threshold, anrSettings); + } + + public void enableAnr(AnrType anrType, BacktraceANRSettings anrSettings) { + this.anrHandler = initAnrHandler(anrType, anrSettings); } /** * Stop monitoring if the main thread has been blocked */ public void disableAnr() { - if (this.anrWatchdog != null && !this.anrWatchdog.isInterrupted()) { - this.anrWatchdog.stopMonitoringAnr(); + if (this.anrHandler != null) { + this.anrHandler.stopMonitoringAnr(); + } + } + + public BacktraceANRHandler initAnrHandler(AnrType anrType, BacktraceANRSettings backtraceANRSettings) { + BacktraceANRHandler handler = createBacktraceAnrHandler(anrType, backtraceANRSettings); + if (backtraceANRSettings.getOnApplicationNotRespondingEvent() != null) { + handler.setOnApplicationNotRespondingEvent(backtraceANRSettings.getOnApplicationNotRespondingEvent()); + } + return handler; + } + + public BacktraceANRHandler createBacktraceAnrHandler(AnrType anrType, BacktraceANRSettings settings) { + if (anrType == AnrType.ApplicationExit) { + return new BacktraceAppExitInfoSenderHandler(this, context); + } else if (anrType == AnrType.Threshold){ + return new BacktraceANRHandlerWatchdog(this, settings.getTimeout(), settings.isDebug()); } + throw new IllegalArgumentException("Unsupported type of ANR: " + anrType.name()); } + } diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/ActivityManagerExitInfoProvider.java b/backtrace-library/src/main/java/backtraceio/library/anr/ActivityManagerExitInfoProvider.java new file mode 100644 index 000000000..5a35a57bb --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/ActivityManagerExitInfoProvider.java @@ -0,0 +1,43 @@ +package backtraceio.library.anr; + +import android.app.ActivityManager; +import android.app.ApplicationExitInfo; +import android.content.Context; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ActivityManagerExitInfoProvider implements ProcessExitInfoProvider { + private final ActivityManager activityManager; + public ActivityManagerExitInfoProvider(Context context) { + this.activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public List getHistoricalExitInfo(String packageName, int startIndex, int maxCount) { + List systemExitInfoList = + activityManager.getHistoricalProcessExitReasons(packageName, startIndex, maxCount); + + if (systemExitInfoList.isEmpty()) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(systemExitInfoList.size()); + for (ApplicationExitInfo info : systemExitInfoList) { + result.add(new ExitInfoAdapter(info)); + } + + return result; + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public List getSupportedTypesOfExitInfo() { + return Collections.singletonList(ApplicationExitInfo.REASON_ANR); + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/AnrExitInfoState.java b/backtrace-library/src/main/java/backtraceio/library/anr/AnrExitInfoState.java new file mode 100644 index 000000000..9cad0a146 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/AnrExitInfoState.java @@ -0,0 +1,29 @@ +package backtraceio.library.anr; + +import android.content.Context; + +import backtraceio.library.common.SharedPreferencesManager; + +public class AnrExitInfoState { + + private final SharedPreferencesManager sharedPreferencesManager; + + private static final String PREFS_NAME = "ANR_APP_EXIT_INFO_STATE"; + + private static final String TIMESTAMP_PREF_KEY = "LAST_ANR_TIMESTAMP"; + private static final long TIMESTAMP_DEFAULT = 0; + + public AnrExitInfoState(Context context) { + this.sharedPreferencesManager = new SharedPreferencesManager(context); + } + + public void saveTimestamp(long value) { + this.sharedPreferencesManager.saveLongToSharedPreferences(PREFS_NAME, TIMESTAMP_PREF_KEY, value); + } + + public long getLastTimestamp() { + return this.sharedPreferencesManager.readLongFromSharedPreferences( + PREFS_NAME, TIMESTAMP_PREF_KEY, TIMESTAMP_DEFAULT); + } + +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/AnrType.java b/backtrace-library/src/main/java/backtraceio/library/anr/AnrType.java new file mode 100644 index 000000000..1ad56be1f --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/AnrType.java @@ -0,0 +1,6 @@ +package backtraceio.library.anr; + +public enum AnrType { + Threshold, + ApplicationExit +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/AppExitInfoDetailsExtractor.java b/backtrace-library/src/main/java/backtraceio/library/anr/AppExitInfoDetailsExtractor.java new file mode 100644 index 000000000..1bb65a0e8 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/AppExitInfoDetailsExtractor.java @@ -0,0 +1,90 @@ +package backtraceio.library.anr; + +import android.app.ApplicationExitInfo; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; + +import backtraceio.library.logger.BacktraceLogger; + + +public class AppExitInfoDetailsExtractor { + private final static String LOG_TAG = AppExitInfoDetailsExtractor.class.getSimpleName(); + + @RequiresApi(api = Build.VERSION_CODES.R) + public static HashMap getANRAttributes(ExitInfo appExitInfo) { + if (appExitInfo == null) { + return new HashMap<>(); + } + + final HashMap attributes = new HashMap<>(); + attributes.put("description", appExitInfo.getDescription()); + attributes.put("timestamp", getANRTimestamp(appExitInfo)); + attributes.put("reason-code", appExitInfo.getReason()); + attributes.put("reason", reasonCodeToDescription(appExitInfo.getReason())); + attributes.put("PID", appExitInfo.getPid()); + attributes.put("Importance", appExitInfo.getImportance()); + attributes.put("PSS", appExitInfo.getPss()); + attributes.put("RSS", appExitInfo.getRss()); + return attributes; + } + + @RequiresApi(api = Build.VERSION_CODES.R) + public static String getANRMessage(ExitInfo appExitInfo) { + return "Application Not Responding" + " | " + + "Description: " + appExitInfo.getDescription() + " | " + + "Timestamp: " + getANRTimestamp(appExitInfo); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private static String getANRTimestamp(ExitInfo appExitInfo) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + return dateFormat.format(new Date(appExitInfo.getTimestamp())); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + public static String getStackTraceInfo(ExitInfo exitInfo) { + InputStream traceStream = getStreamOrNull(exitInfo); + if (traceStream == null) { + BacktraceLogger.w(LOG_TAG, "Unexpected null trace stream"); + return null; + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(traceStream))) { + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append("\n"); + } + } catch (Exception exception) { + BacktraceLogger.e(LOG_TAG, "Unexpected exception on getting stacktrace from exitInfo", exception); + return ""; + } + + return builder.toString(); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private static InputStream getStreamOrNull(ExitInfo exitInfo) { + try { + return exitInfo.getTraceInputStream(); + } catch (IOException e) { + return null; + } + } + + private static String reasonCodeToDescription(int reasonCode) { + if (reasonCode == ApplicationExitInfo.REASON_ANR) { + return "anr"; + } + return "unsupported code"; + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRExitInfoException.java b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRExitInfoException.java new file mode 100644 index 000000000..97f819f52 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRExitInfoException.java @@ -0,0 +1,26 @@ +package backtraceio.library.anr; + +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +public class BacktraceANRExitInfoException extends Exception { + private final transient StackTraceElement[] anrStackTrace; + + @RequiresApi(api = Build.VERSION_CODES.R) + public BacktraceANRExitInfoException(ExitInfo exitInfo, StackTraceElement[] stackTraceElements) { + super(AppExitInfoDetailsExtractor.getANRMessage(exitInfo)); + + this.anrStackTrace = stackTraceElements; + } + + @NonNull + @Override + public StackTraceElement[] getStackTrace() { + if (anrStackTrace != null) { + return anrStackTrace; + } + return super.getStackTrace(); + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRHandler.java b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRHandler.java new file mode 100644 index 000000000..f5c6e41f1 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRHandler.java @@ -0,0 +1,9 @@ +package backtraceio.library.anr; + +import backtraceio.library.watchdog.OnApplicationNotRespondingEvent; + +public interface BacktraceANRHandler { + void setOnApplicationNotRespondingEvent(OnApplicationNotRespondingEvent onApplicationNotRespondingEvent); + + void stopMonitoringAnr(); +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRSettings.java b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRSettings.java new file mode 100644 index 000000000..ed8e40fc2 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceANRSettings.java @@ -0,0 +1,30 @@ +package backtraceio.library.anr; + +import backtraceio.library.watchdog.OnApplicationNotRespondingEvent; + +public class BacktraceANRSettings { + private int timeout = 0; + private boolean debug = false; + private OnApplicationNotRespondingEvent onApplicationNotRespondingEvent = null; + + public BacktraceANRSettings() { } + + public BacktraceANRSettings(int timeout, OnApplicationNotRespondingEvent onApplicationNotRespondingEvent, boolean debug) { + super(); + this.debug = debug; + this.onApplicationNotRespondingEvent = onApplicationNotRespondingEvent; + this.timeout = timeout; + } + + public int getTimeout() { + return timeout; + } + + public boolean isDebug() { + return debug; + } + + public OnApplicationNotRespondingEvent getOnApplicationNotRespondingEvent() { + return onApplicationNotRespondingEvent; + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceAppExitInfoSenderHandler.java b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceAppExitInfoSenderHandler.java new file mode 100644 index 000000000..046d78b9c --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/BacktraceAppExitInfoSenderHandler.java @@ -0,0 +1,168 @@ +package backtraceio.library.anr; + +import static backtraceio.library.anr.AppExitInfoDetailsExtractor.getANRAttributes; + +import android.content.Context; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import backtraceio.library.BacktraceClient; +import backtraceio.library.common.ApplicationMetadataCache; +import backtraceio.library.logger.BacktraceLogger; +import backtraceio.library.models.BacktraceAttributeConsts; +import backtraceio.library.models.json.BacktraceReport; +import backtraceio.library.models.types.BacktraceResultStatus; +import backtraceio.library.watchdog.OnApplicationNotRespondingEvent; + +public class BacktraceAppExitInfoSenderHandler extends Thread implements BacktraceANRHandler { + private final static String THREAD_NAME = "main-anr-appexit"; + private final static String LOG_TAG = BacktraceAppExitInfoSenderHandler.class.getSimpleName(); + private final static String ANR_COMPLEX_ATTR_KEY = "ANR annotations"; + private final static String ANR_STACKTRACE_PARSED_ATTR_KEY = "ANR parsed stacktrace"; + private final static String ANR_STACKTRACE_ATTR_KEY = "ANR stacktrace"; + + private final BacktraceClient backtraceClient; + private final String packageName; + + private final ProcessExitInfoProvider activityManager; + + private final AnrExitInfoState anrAppExitInfoState; + + public BacktraceAppExitInfoSenderHandler(BacktraceClient client, Context context) { + this(client, + ApplicationMetadataCache.getInstance(context).getPackageName(), + new AnrExitInfoState(context), + new ActivityManagerExitInfoProvider(context) + ); + } + + protected BacktraceAppExitInfoSenderHandler(BacktraceClient client, String packageName, AnrExitInfoState anrAppExitInfoState, ProcessExitInfoProvider activityManager) { + super(THREAD_NAME); + this.backtraceClient = client; + this.packageName = packageName; + this.anrAppExitInfoState = anrAppExitInfoState; + this.activityManager = activityManager; + + this.start(); + } + + @Override + public void run() { + send(); + } + + private void send() { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R) { + BacktraceLogger.d(LOG_TAG, "Unsupported Android version " + android.os.Build.VERSION.SDK_INT + " to send ANR based on applicationExitInfoList"); + return; + } + + final List applicationExitInfoList = this.activityManager.getHistoricalExitInfo(this.packageName, 0, 0); + + Collections.reverse(applicationExitInfoList); + for (ExitInfo appExitInfo : applicationExitInfoList) { + synchronized (this.anrAppExitInfoState) { + if (!this.shouldProcessAppExitInfo(appExitInfo)) { + continue; + } + + sendApplicationExitInfoReport(appExitInfo); + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private void sendApplicationExitInfoReport(ExitInfo appExitInfo) { + final BacktraceReport report = generateBacktraceReport(appExitInfo); + + if (report == null) { + synchronized (this.anrAppExitInfoState) { + this.anrAppExitInfoState.saveTimestamp(appExitInfo.getTimestamp()); + } + return; + } + + BacktraceLogger.d(LOG_TAG, "Sending ApplicationExitInfo ANR: " + report.message); + backtraceClient.send(report, backtraceResult -> { + synchronized (this.anrAppExitInfoState) { + if (backtraceResult.status == BacktraceResultStatus.Ok && shouldUpdateLastTimestamp(appExitInfo)) { + this.anrAppExitInfoState.saveTimestamp(appExitInfo.getTimestamp()); + } + } + }); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private BacktraceReport generateBacktraceReport(ExitInfo appExitInfo) {; + final Map anrAttributes = getANRAttributes(appExitInfo); + final String stackTrace = AppExitInfoDetailsExtractor.getStackTraceInfo(appExitInfo); + + if (stackTrace == null || stackTrace.isEmpty()) { + BacktraceLogger.w(LOG_TAG, "Empty stacktrace for ApplicationExitInfo"); + return null; + } + + final Map parsedStackTraceAttributes = this.getAttributesFromStacktrace(stackTrace); + final StackTraceElement[] anrStackTrace = ExitInfoStackTraceParser.parseMainThreadStackTrace(parsedStackTraceAttributes); + + final HashMap attributes = new HashMap(){{ + put(BacktraceAttributeConsts.ErrorType, BacktraceAttributeConsts.AnrAttributeType); + put(ANR_COMPLEX_ATTR_KEY, anrAttributes); + put(ANR_STACKTRACE_ATTR_KEY, stackTrace); + put(ANR_STACKTRACE_PARSED_ATTR_KEY, parsedStackTraceAttributes); + }}; + + return new BacktraceReport(new BacktraceANRExitInfoException(appExitInfo, anrStackTrace), attributes); + } + + private Map getAttributesFromStacktrace(String stacktrace) { + try { + return ExitInfoStackTraceParser.parseANRStackTrace(stacktrace); + } catch (Exception ex) { + BacktraceLogger.e(LOG_TAG, "Error during parsing ExitInfoStackTrace", ex); + return new HashMap<>(); + } + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private boolean isSupportedTypeOfApplicationExit(ExitInfo appExitInfo) { + final List supportedTypes = this.activityManager.getSupportedTypesOfExitInfo(); + return supportedTypes.contains(appExitInfo.getReason()); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private boolean shouldProcessAppExitInfo(ExitInfo appExitInfo) { + long lastAnrTimestamp = this.anrAppExitInfoState.getLastTimestamp(); + long anrTimestamp = appExitInfo.getTimestamp(); + + if (lastAnrTimestamp >= anrTimestamp) { + return false; + } + + return isSupportedTypeOfApplicationExit(appExitInfo); + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private boolean shouldUpdateLastTimestamp(ExitInfo appExitInfo) { + return this.anrAppExitInfoState.getLastTimestamp() < appExitInfo.getTimestamp(); + } + + @Override + public void setOnApplicationNotRespondingEvent( + OnApplicationNotRespondingEvent onApplicationNotRespondingEvent) { + } + + @Override + public void stopMonitoringAnr() { + if (!this.isInterrupted()) { + BacktraceLogger.d(LOG_TAG, "ANR thread will be interrupted."); + this.interrupt(); + } + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfo.java b/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfo.java new file mode 100644 index 000000000..ebd10ec83 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfo.java @@ -0,0 +1,24 @@ +package backtraceio.library.anr; + +import java.io.IOException; +import java.io.InputStream; + +public interface ExitInfo { + int getReason(); + + long getTimestamp(); + + String getDescription(); + + int getPid(); + + int getUid(); + + int getImportance(); + + long getPss(); + + long getRss(); + + InputStream getTraceInputStream() throws IOException; +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfoAdapter.java b/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfoAdapter.java new file mode 100644 index 000000000..61c78a9aa --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfoAdapter.java @@ -0,0 +1,71 @@ +package backtraceio.library.anr; + +import android.app.ApplicationExitInfo; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import java.io.IOException; +import java.io.InputStream; + +public class ExitInfoAdapter implements ExitInfo { + private final ApplicationExitInfo systemExitInfo; + + public ExitInfoAdapter(ApplicationExitInfo systemExitInfo) { + this.systemExitInfo = systemExitInfo; + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public int getReason() { + return systemExitInfo.getReason(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public long getTimestamp() { + return systemExitInfo.getTimestamp(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public String getDescription() { + return systemExitInfo.getDescription(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public int getPid() { + return systemExitInfo.getPid(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public int getUid() { + return systemExitInfo.getDefiningUid(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public int getImportance() { + return systemExitInfo.getImportance(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public long getPss() { + return systemExitInfo.getPss(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public long getRss() { + return systemExitInfo.getRss(); + } + + @Override + @RequiresApi(api = Build.VERSION_CODES.R) + public InputStream getTraceInputStream() throws IOException { + return systemExitInfo.getTraceInputStream(); + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfoStackTraceParser.java b/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfoStackTraceParser.java new file mode 100644 index 000000000..8002658d6 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/ExitInfoStackTraceParser.java @@ -0,0 +1,228 @@ +package backtraceio.library.anr; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ExitInfoStackTraceParser { + private static final Pattern JAVA_FRAME_PATTERN = Pattern.compile("\\s*at (.*?)\\((.*?):(\\d+)\\)"); + private static final String MAIN_THREAD_NAME = "main"; + private static final int NATIVE_STACK_ELEMENTS_NUMBER = 6; + static StackTraceElement parseFrame(String frame) { + StackTraceElement javaFrame = parseJavaFrame(frame); + if (javaFrame != null) { + return javaFrame; + } + + return parseNativeFrame(frame); + } + + static StackTraceElement parseNativeFrame(String frame) { + if (!frame.startsWith("native")) { + return null; + } + String[] parts = frame.split("\\s+", NATIVE_STACK_ELEMENTS_NUMBER); + + if (parts.length < NATIVE_STACK_ELEMENTS_NUMBER) { + return null; + } + + String address = parts[3]; + String library = parts[4]; + String funcName = parts[5]; + + return new StackTraceElement(library, funcName, "address: " + address, 0); + } + + static StackTraceElement parseJavaFrame(String frame) { + Matcher matcher = JAVA_FRAME_PATTERN.matcher(frame); + if (!matcher.find()) { + return null; + } + + String fullClassNameMethod = matcher.group(1); + String fileName = matcher.group(2); + int lineNumber = Integer.parseInt(matcher.group(3)); + + int lastDot = fullClassNameMethod.lastIndexOf('.'); + String className = (lastDot == -1) ? fullClassNameMethod : fullClassNameMethod.substring(0, lastDot); + String methodName = (lastDot == -1) ? "" : fullClassNameMethod.substring(lastDot + 1); + + return new StackTraceElement(className, methodName, fileName, lineNumber); + } + + public static StackTraceElement[] parseMainThreadStackTrace(Map parsedData) { + Map mainThreadInfo = (Map) parsedData.get("main_thread"); + + if (mainThreadInfo == null) { + return new StackTraceElement[0]; + } + + List stackFrames = (List) mainThreadInfo.get("stack_trace"); + + if (stackFrames == null) { + return new StackTraceElement[0]; + } + + List elements = new ArrayList<>(); + for (String frame : stackFrames) { + StackTraceElement element = parseFrame(frame); + if (element != null) { + elements.add(element); + } + } + return elements.toArray(new StackTraceElement[0]); + } + + public static Map parseANRStackTrace(String stackTrace) { + Map parsedData = new HashMap<>(); + + if (stackTrace == null || stackTrace.isEmpty()) { + return parsedData; + } + + // Parse timestamp + parsedData.put("timestamp", parseTimestamp(stackTrace)); + + // Parse PID + Pattern pidPattern = Pattern.compile("----- pid (\\d+) at"); + Matcher pidMatcher = pidPattern.matcher(stackTrace); + if (pidMatcher.find()) { + parsedData.put("pid", Integer.parseInt(pidMatcher.group(1))); + } + + // Parse command line + Pattern cmdLinePattern = Pattern.compile("Cmd line: (.*)"); + Matcher cmdLineMatcher = cmdLinePattern.matcher(stackTrace); + if (cmdLineMatcher.find()) { + parsedData.put("command_line", cmdLineMatcher.group(1)); + } + + // Parse build fingerprint + Pattern fingerprintPattern = Pattern.compile("Build fingerprint: '(.*?)'"); + Matcher fingerprintMatcher = fingerprintPattern.matcher(stackTrace); + if (fingerprintMatcher.find()) { + parsedData.put("build_fingerprint", fingerprintMatcher.group(1)); + } + + // Parse ABI + Pattern abiPattern = Pattern.compile("ABI: '(.*?)'"); + Matcher abiMatcher = abiPattern.matcher(stackTrace); + if (abiMatcher.find()) { + parsedData.put("abi", abiMatcher.group(1)); + } + + // Parse build type + Pattern buildTypePattern = Pattern.compile("Build type: (.*)"); + Matcher buildTypeMatcher = buildTypePattern.matcher(stackTrace); + if (buildTypeMatcher.find()) { + parsedData.put("build_type", buildTypeMatcher.group(1)); + } + + // Parse heap information + Pattern heapPattern = Pattern.compile("Heap: (.*)"); + Matcher heapMatcher = heapPattern.matcher(stackTrace); + if (heapMatcher.find()) { + parsedData.put("heap_info", heapMatcher.group(1)); + } + + List> threads = parseThreadDumps(stackTrace); + parsedData.put("threads", threads); + + // Find the main thread + Map mainThreadInfo = getMainThreadInfo(threads); + parsedData.put("main_thread", mainThreadInfo); + + return parsedData; + } + + private static Object parseTimestamp(String stackTrace) { + Pattern timestampPattern = Pattern.compile("----- pid \\d+ at (.*?) -----"); + Matcher timestampMatcher = timestampPattern.matcher(stackTrace); + if (timestampMatcher.find()) { + return timestampMatcher.group(1); + } + return null; + } + + @Nullable + private static Map getMainThreadInfo(List> threads) { + Map mainThreadInfo = null; + for (Map thread : threads) { + if (thread.get("name").equals(MAIN_THREAD_NAME)) { + mainThreadInfo = thread; + break; + } + } + return mainThreadInfo; + } + private static Map parseThreadInformation(String threadDump) { + Map result = new HashMap<>(); + + // Parse header line + Pattern headerPattern = Pattern.compile("\"([^\"]+)\"\\s*(daemon)?\\s*prio=(\\d+)\\s*tid=(\\d+)\\s*([^\\n]+)"); + Matcher headerMatcher = headerPattern.matcher(threadDump); + + if (headerMatcher.find()) { + result.put("name", headerMatcher.group(1)); + result.put("isDaemon", headerMatcher.group(2) != null); + result.put("prio", Integer.parseInt(headerMatcher.group(3))); + result.put("tid", Integer.parseInt(headerMatcher.group(4))); + result.put("status", headerMatcher.group(5).trim()); + } + + result.put("stack_trace", parseThreadStackTrace(threadDump)); + + return result; + } + + @NonNull + private static List parseThreadStackTrace(String threadDump) { + List stackTrace = new ArrayList<>(); + String[] lines = threadDump.split("\n"); + boolean isStackTrace = false; + + for (String line : lines) { + line = line.trim(); + + if (isStackTrace && (line.isEmpty() || line.startsWith("\""))) { + break; + } + + // Skip empty lines and first line (already parsed) + if (line.isEmpty() || line.startsWith("\"")) { + continue; + } + + // Check if we've reached stack trace + if (line.startsWith("at ") || line.startsWith("native:")) { + isStackTrace = true; + stackTrace.add(line); + } + } + return stackTrace; + } + + public static List> parseThreadDumps(String input) { + List> threads = new ArrayList<>(); + + String regex = "\\\"(.*?)\\\" (daemon )?prio=(\\d+) tid=(\\d+) (\\w+)(.*)\\n(?s)((.*?\\n))(?=(?:\\n\\n)|$)"; + + Pattern threadStartPattern = Pattern.compile(regex, Pattern.MULTILINE); + Matcher threadMatcher = threadStartPattern.matcher(input); + + while (threadMatcher.find()) { + String threadDump = threadMatcher.group(); + Map threadInfo = parseThreadInformation(threadDump); + threads.add(threadInfo); + } + + return threads; + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/anr/ProcessExitInfoProvider.java b/backtrace-library/src/main/java/backtraceio/library/anr/ProcessExitInfoProvider.java new file mode 100644 index 000000000..fdc383ce6 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/anr/ProcessExitInfoProvider.java @@ -0,0 +1,9 @@ +package backtraceio.library.anr; + +import java.util.List; + +public interface ProcessExitInfoProvider { + List getHistoricalExitInfo(String packageName, int startIndex, int maxCount); + + List getSupportedTypesOfExitInfo(); +} diff --git a/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java b/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java index 69a41ba24..a7d454e02 100644 --- a/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java +++ b/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java @@ -43,7 +43,7 @@ public class BacktraceBase implements Client { public static String version = backtraceio.library.BuildConfig.VERSION_NAME; static { - System.loadLibrary("backtrace-native"); + NativeLibraryLoader.load(); } /** diff --git a/backtrace-library/src/main/java/backtraceio/library/base/NativeLibraryLoader.java b/backtrace-library/src/main/java/backtraceio/library/base/NativeLibraryLoader.java new file mode 100644 index 000000000..3c8591c5b --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/base/NativeLibraryLoader.java @@ -0,0 +1,7 @@ +package backtraceio.library.base; + +public class NativeLibraryLoader { + public static void load() { + System.loadLibrary("backtrace-native"); + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/common/SharedPreferencesManager.java b/backtrace-library/src/main/java/backtraceio/library/common/SharedPreferencesManager.java new file mode 100644 index 000000000..dd1b2b6ff --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/common/SharedPreferencesManager.java @@ -0,0 +1,23 @@ +package backtraceio.library.common; + +import android.content.Context; +import android.content.SharedPreferences; + +public class SharedPreferencesManager { + private final Context context; + public SharedPreferencesManager(Context context) { + this.context = context; + } + + public void saveLongToSharedPreferences(String prefName, String key, Long value) { + SharedPreferences sharedPreferences = this.context.getSharedPreferences(prefName, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putLong(key, value); + editor.commit(); + } + + public Long readLongFromSharedPreferences(String prefName, String key, Long defaultValue) { + SharedPreferences sharedPreferences = this.context.getSharedPreferences(prefName, Context.MODE_PRIVATE); + return sharedPreferences.getLong(key, defaultValue); + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/watchdog/BacktraceANRWatchdog.java b/backtrace-library/src/main/java/backtraceio/library/watchdog/BacktraceANRHandlerWatchdog.java similarity index 86% rename from backtrace-library/src/main/java/backtraceio/library/watchdog/BacktraceANRWatchdog.java rename to backtrace-library/src/main/java/backtraceio/library/watchdog/BacktraceANRHandlerWatchdog.java index c9b3cf4e6..06c799161 100644 --- a/backtrace-library/src/main/java/backtraceio/library/watchdog/BacktraceANRWatchdog.java +++ b/backtrace-library/src/main/java/backtraceio/library/watchdog/BacktraceANRHandlerWatchdog.java @@ -7,6 +7,7 @@ import java.util.Calendar; import backtraceio.library.BacktraceClient; +import backtraceio.library.anr.BacktraceANRHandler; import backtraceio.library.logger.BacktraceLogger; @@ -14,14 +15,14 @@ * This is the class that is responsible for monitoring the * user interface thread and sending an error if it is blocked */ -public class BacktraceANRWatchdog extends Thread { +public class BacktraceANRHandlerWatchdog extends Thread implements BacktraceANRHandler { - private final static transient String LOG_TAG = BacktraceANRWatchdog.class.getSimpleName(); + private final static String LOG_TAG = BacktraceANRHandlerWatchdog.class.getSimpleName(); /** * Default timeout value in milliseconds */ - private final static transient int DEFAULT_ANR_TIMEOUT = 5000; + private final static int DEFAULT_ANR_TIMEOUT = 5000; /** * Current Backtrace client instance which will be used to send information about exception @@ -58,7 +59,7 @@ public class BacktraceANRWatchdog extends Thread { * * @param client current Backtrace client instance which will be used to send information about exception */ - public BacktraceANRWatchdog(BacktraceClient client) { + public BacktraceANRHandlerWatchdog(BacktraceClient client) { this(client, DEFAULT_ANR_TIMEOUT); } @@ -68,7 +69,7 @@ public BacktraceANRWatchdog(BacktraceClient client) { * @param client current Backtrace client instance which will be used to send information about exception * @param timeout maximum time in milliseconds after which should check if the main thread is not hanged */ - public BacktraceANRWatchdog(BacktraceClient client, int timeout) { + public BacktraceANRHandlerWatchdog(BacktraceClient client, int timeout) { this(client, timeout, false); } @@ -79,7 +80,7 @@ public BacktraceANRWatchdog(BacktraceClient client, int timeout) { * @param timeout maximum time in milliseconds after which should check if the main thread is not hanged * @param debug enable debug mode - errors will not be sent if the debugger is connected */ - public BacktraceANRWatchdog(BacktraceClient client, int timeout, boolean debug) { + public BacktraceANRHandlerWatchdog(BacktraceClient client, int timeout, boolean debug) { BacktraceLogger.d(LOG_TAG, "Start monitoring ANR"); this.backtraceClient = client; this.timeout = timeout; @@ -102,7 +103,7 @@ public void run() { return; } - Boolean reported = false; + boolean reported = false; while (!shouldStop && !isInterrupted()) { String dateTimeNow = Calendar.getInstance().getTime().toString(); BacktraceLogger.d(LOG_TAG, "ANR WATCHDOG - " + dateTimeNow); @@ -138,6 +139,10 @@ public void run() { } public void stopMonitoringAnr() { + if (this.isInterrupted()) { + BacktraceLogger.d(LOG_TAG, "ANR monitoring thread has already been interrupted."); + return; + } BacktraceLogger.d(LOG_TAG, "Stop monitoring ANR"); shouldStop = true; } diff --git a/backtrace-library/src/test/java/backtraceio/library/TestUtils.java b/backtrace-library/src/test/java/backtraceio/library/TestUtils.java index 737d7e083..944a1409c 100644 --- a/backtrace-library/src/test/java/backtraceio/library/TestUtils.java +++ b/backtrace-library/src/test/java/backtraceio/library/TestUtils.java @@ -29,6 +29,9 @@ public static String readFileAsString(Object obj, String fileName) { String line; while ((line = reader.readLine()) != null) { jsonStringBuilder.append(line); + if (reader.ready()) { + jsonStringBuilder.append("\n"); + } } return jsonStringBuilder.toString(); diff --git a/backtrace-library/src/test/java/backtraceio/library/anr/ExitInfoStackTraceParserTest.java b/backtrace-library/src/test/java/backtraceio/library/anr/ExitInfoStackTraceParserTest.java new file mode 100644 index 000000000..a5d3cba08 --- /dev/null +++ b/backtrace-library/src/test/java/backtraceio/library/anr/ExitInfoStackTraceParserTest.java @@ -0,0 +1,120 @@ +package backtraceio.library.anr; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import backtraceio.library.TestUtils; + +public class ExitInfoStackTraceParserTest { + private final String ANR_APPEXIT_STACKTRACE_FILE = "anrAppExitInfoStacktrace.txt"; + + @Test + public void parseFrameJava() { + // GIVEN + String frame = "at backtraceio.backtraceio.MainActivity.handledException(MainActivity.java:157)"; + // WHEN + StackTraceElement stackTraceElement = ExitInfoStackTraceParser.parseFrame(frame); + // THEN + assertEquals("backtraceio.backtraceio.MainActivity", stackTraceElement.getClassName()); + assertEquals("MainActivity.java", stackTraceElement.getFileName()); + assertEquals(157, stackTraceElement.getLineNumber()); + assertEquals("handledException", stackTraceElement.getMethodName()); + } + + @Test + public void parseFrameNative() { + // GIVEN + String frame = "native: #19 pc 00630008 /apex/com.android.art/lib/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)+1464)"; + // WHEN + StackTraceElement stackTraceElement = ExitInfoStackTraceParser.parseFrame(frame); + // THEN + assertEquals("/apex/com.android.art/lib/libart.so", stackTraceElement.getClassName()); + assertEquals("address: 00630008", stackTraceElement.getFileName()); + assertEquals(0, stackTraceElement.getLineNumber()); + assertEquals("(art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)+1464)", stackTraceElement.getMethodName()); + } + + @Test + public void parseAnrStackTrace() { + // GIVEN + String anrStacktraceString = TestUtils.readFileAsString(this, ANR_APPEXIT_STACKTRACE_FILE); + + // WHEN + Map anrStacktrace = ExitInfoStackTraceParser.parseANRStackTrace(anrStacktraceString); + + // THEN + assertNotNull(anrStacktrace); + assertNotNull(anrStacktrace.get("main_thread")); + assertEquals("x86", anrStacktrace.get("abi")); + assertEquals("74% free, 6892KB/25MB; 138095 objects", anrStacktrace.get("heap_info")); + assertEquals("google/sdk_gphone_x86/generic_x86_arm:11/RSR1.201013.001/6903271:user/release-keys", anrStacktrace.get("build_fingerprint")); + assertEquals("optimized", anrStacktrace.get("build_type")); + assertEquals("backtraceio.backtraceio", anrStacktrace.get("command_line")); + assertEquals("2025-03-27 21:02:38", anrStacktrace.get("timestamp")); + assertEquals(9207, anrStacktrace.get("pid")); + + // THEN THREADS + List> threads = (List>) anrStacktrace.get("threads"); + assertEquals(20, threads.size()); + + Map customThread4 = threads.get(18); + List thread4StackTrace = (List) customThread4.get("stack_trace"); + + assertEquals("Thread-4", threads.get(18).get("name")); + assertEquals("at java.lang.Thread.sleep(Native method)", thread4StackTrace.get(0)); + assertEquals("at java.lang.Thread.sleep(Thread.java:442)", thread4StackTrace.get(1)); + assertEquals("at java.lang.Thread.sleep(Thread.java:358)", thread4StackTrace.get(2)); + assertEquals("at backtraceio.library.watchdog.BacktraceANRHandlerWatchdog.run(BacktraceANRHandlerWatchdog.java:118)", thread4StackTrace.get(3)); + + // THEN MAIN THREAD + Map mainThread = (Map) anrStacktrace.get("main_thread"); + assertEquals(5, mainThread.get("prio")); + assertEquals(1, mainThread.get("tid")); + assertNull(mainThread.get("daemon")); + + ArrayList stackTrace = (ArrayList) mainThread.get("stack_trace"); + assertEquals(36, stackTrace.size()); + + assertEquals("native: #20 pc 005886a0 /apex/com.android.art/lib/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+80)", stackTrace.get(20)); + assertEquals("at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:468)", stackTrace.get(24)); + } + @Test + public void parseAnrMainThreadStackTrace() { + // GIVEN + String anrStacktraceString = TestUtils.readFileAsString(this, ANR_APPEXIT_STACKTRACE_FILE); + Map anrStacktrace = ExitInfoStackTraceParser.parseANRStackTrace(anrStacktraceString); + + // WHEN + StackTraceElement[] anrMainThreadStacktrace = ExitInfoStackTraceParser.parseMainThreadStackTrace(anrStacktrace); + + // THEN + assertEquals(33, anrMainThreadStacktrace.length); + + assertEquals("(__kernel_vsyscall+7)", anrMainThreadStacktrace[0].getMethodName()); + assertEquals(0, anrMainThreadStacktrace[0].getLineNumber()); + assertEquals("address: 00000b97", anrMainThreadStacktrace[0].getFileName()); + assertEquals("[vdso]", anrMainThreadStacktrace[0].getClassName()); + + assertEquals("(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+176)", anrMainThreadStacktrace[14].getMethodName()); + assertEquals(0, anrMainThreadStacktrace[14].getLineNumber()); + assertEquals("address: 00379b00", anrMainThreadStacktrace[14].getFileName()); + assertEquals("/apex/com.android.art/lib/libart.so", anrMainThreadStacktrace[14].getClassName()); + + assertEquals("onClick", anrMainThreadStacktrace[22].getMethodName()); + assertEquals(468, anrMainThreadStacktrace[22].getLineNumber()); + assertEquals("AppCompatViewInflater.java", anrMainThreadStacktrace[22].getFileName()); + assertEquals("androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener", anrMainThreadStacktrace[22].getClassName()); + + assertEquals("main", anrMainThreadStacktrace[32].getMethodName()); + assertEquals(947, anrMainThreadStacktrace[32].getLineNumber()); + assertEquals("ZygoteInit.java", anrMainThreadStacktrace[32].getFileName()); + assertEquals("com.android.internal.os.ZygoteInit", anrMainThreadStacktrace[32].getClassName()); + } +} diff --git a/backtrace-library/src/test/java/backtraceio/library/common/anr/AppExitInfoDetailsExtractorTest.java b/backtrace-library/src/test/java/backtraceio/library/common/anr/AppExitInfoDetailsExtractorTest.java new file mode 100644 index 000000000..d232b3158 --- /dev/null +++ b/backtrace-library/src/test/java/backtraceio/library/common/anr/AppExitInfoDetailsExtractorTest.java @@ -0,0 +1,113 @@ +package backtraceio.library.common.anr; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.ApplicationExitInfo; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Locale; + +import backtraceio.library.anr.AppExitInfoDetailsExtractor; +import backtraceio.library.anr.ExitInfo; + +@RunWith(MockitoJUnitRunner.class) +public class AppExitInfoDetailsExtractorTest { + @Mock + private ExitInfo mockAppExitInfo; + + @Before + public void setUp() { + mockAppExitInfo = mock(ExitInfo.class); + } + + @Test + public void testGetANRAttributesNullInput() { + // WHEN + HashMap result = AppExitInfoDetailsExtractor.getANRAttributes(null); + + // THEN + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + @Test + public void testGetANRAttributesValidInput() { + // GIVEN + when(mockAppExitInfo.getDescription()).thenReturn("Test ANR"); + when(mockAppExitInfo.getTimestamp()).thenReturn(System.currentTimeMillis()); + when(mockAppExitInfo.getReason()).thenReturn(ApplicationExitInfo.REASON_ANR); + when(mockAppExitInfo.getPid()).thenReturn(1234); + when(mockAppExitInfo.getImportance()).thenReturn(100); + when(mockAppExitInfo.getPss()).thenReturn(200L); + when(mockAppExitInfo.getRss()).thenReturn(300L); + + // WHEN + HashMap result = AppExitInfoDetailsExtractor.getANRAttributes(mockAppExitInfo); + + // THEN + assertNotNull(result); + assertEquals("Test ANR", result.get("description")); + assertEquals("anr", result.get("reason")); + assertEquals(1234, result.get("PID")); + assertEquals(100, result.get("Importance")); + assertEquals(200L, result.get("PSS")); + assertEquals(300L, result.get("RSS")); + } + + @Test + public void testGetANRMessage() { + // GIVEN + Long timestamp = 1745473156000L; + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + String timestampString = dateFormat.format(timestamp); + + // GIVEN + when(mockAppExitInfo.getDescription()).thenReturn("Test ANR"); + when(mockAppExitInfo.getTimestamp()).thenReturn(timestamp); + + // WHEN + String result = AppExitInfoDetailsExtractor.getANRMessage(mockAppExitInfo); + + // THEN + assertEquals("Application Not Responding | Description: Test ANR | Timestamp: " + timestampString, result); + } + + @Test + public void testGetStackTraceInfoValidStream() throws IOException { + // GIVEN + String mockStackTrace = "Exception: Test Stack Trace"; + InputStream inputStream = new ByteArrayInputStream(mockStackTrace.getBytes()); + when(mockAppExitInfo.getTraceInputStream()).thenReturn(inputStream); + + // WHEN + String stackTrace = AppExitInfoDetailsExtractor.getStackTraceInfo(mockAppExitInfo); + + // THEN + assertNotNull(stackTrace); + assertTrue(stackTrace.contains("Exception: Test Stack Trace")); + } + + @Test + public void testGetStackTraceInfoNullStream() { + // WHEN + Object stackTrace = AppExitInfoDetailsExtractor.getANRAttributes(mockAppExitInfo).get("stackTrace"); + + // THEN + assertNull(stackTrace); + } +} diff --git a/backtrace-library/src/test/resources/anrAppExitInfoStacktrace.txt b/backtrace-library/src/test/resources/anrAppExitInfoStacktrace.txt new file mode 100644 index 000000000..43b52eada --- /dev/null +++ b/backtrace-library/src/test/resources/anrAppExitInfoStacktrace.txt @@ -0,0 +1,521 @@ +----- pid 9207 at 2025-03-27 21:02:38 ----- +Cmd line: backtraceio.backtraceio +Build fingerprint: 'google/sdk_gphone_x86/generic_x86_arm:11/RSR1.201013.001/6903271:user/release-keys' +ABI: 'x86' +Build type: optimized +Zygote loaded classes=15747 post zygote classes=1481 +Dumping registered class loaders +#0 dalvik.system.PathClassLoader: [], parent #1 +#1 java.lang.BootClassLoader: [], no parent +#2 dalvik.system.PathClassLoader: [/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes15.dex:/data/data/backtraceio.backtraceio/code_cache/.overlay/base.apk/classes16.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes10.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes8.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes2.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes4.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes3.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes17.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes11.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes14.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes9.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes7.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes12.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes6.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes13.dex:/data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!classes5.dex], parent #1 +Done dumping class loaders +Classes initialized: 760 in 140.777ms +Intern table: 32164 strong; 519 weak +JNI: CheckJNI is on; globals=640 (plus 60 weak) +Libraries: /data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!/lib/x86/libbacktrace-native.so /data/app/~~lbMB2_9XcyZkiC41RLVuMg==/backtraceio.backtraceio-1XRWT_mS3AbJ9vbjbaCtkw==/base.apk!/lib/x86/libnative-lib.so libandroid.so libaudioeffect_jni.so libcompiler_rt.so libicu_jni.so libjavacore.so libjavacrypto.so libjnigraphics.so libmedia_jni.so libopenjdk.so librs_jni.so libsfplugin_ccodec.so libsoundpool.so libstats_jni.so libwebviewchromium_loader.so (16) +Heap: 74% free, 6892KB/25MB; 138095 objects +Dumping cumulative Gc timings +Average major GC reclaim bytes ratio inf over 0 GC cycles +Average major GC copied live bytes ratio 0.72272 over 4 major GCs +Cumulative bytes moved 11312128 +Cumulative objects moved 212604 +Peak regions allocated 27 (6912KB) / 768 (192MB) +Start Dumping histograms for 1 iterations for young concurrent copying +GrayAllDirtyImmuneObjects: Sum: 12.004ms 99% C.I. 12.004ms-12.004ms Avg: 12.004ms Max: 12.004ms +InitializePhase: Sum: 11.934ms 99% C.I. 11.934ms-11.934ms Avg: 11.934ms Max: 11.934ms +ProcessMarkStack: Sum: 9.977ms 99% C.I. 9.977ms-9.977ms Avg: 9.977ms Max: 9.977ms +ScanImmuneSpaces: Sum: 4.691ms 99% C.I. 4.691ms-4.691ms Avg: 4.691ms Max: 4.691ms +EnqueueFinalizerReferences: Sum: 4.233ms 99% C.I. 4.233ms-4.233ms Avg: 4.233ms Max: 4.233ms +ScanCardsForSpace: Sum: 3.451ms 99% C.I. 3.451ms-3.451ms Avg: 3.451ms Max: 3.451ms +VisitConcurrentRoots: Sum: 3.005ms 99% C.I. 3.005ms-3.005ms Avg: 3.005ms Max: 3.005ms +ResetStack: Sum: 1.680ms 99% C.I. 1.680ms-1.680ms Avg: 1.680ms Max: 1.680ms +SweepSystemWeaks: Sum: 1.050ms 99% C.I. 1.050ms-1.050ms Avg: 1.050ms Max: 1.050ms +ClearFromSpace: Sum: 423us 99% C.I. 423us-423us Avg: 423us Max: 423us +FlipOtherThreads: Sum: 333us 99% C.I. 333us-333us Avg: 333us Max: 333us +ForwardSoftReferences: Sum: 289us 99% C.I. 289us-289us Avg: 289us Max: 289us +SweepArray: Sum: 202us 99% C.I. 202us-202us Avg: 202us Max: 202us +EmptyRBMarkBitStack: Sum: 121us 99% C.I. 121us-121us Avg: 121us Max: 121us +VisitNonThreadRoots: Sum: 42us 99% C.I. 42us-42us Avg: 42us Max: 42us +FlipThreadRoots: Sum: 38us 99% C.I. 38us-38us Avg: 38us Max: 38us +ProcessReferences: Sum: 26us 99% C.I. 1us-25us Avg: 13us Max: 25us +(Paused)GrayAllNewlyDirtyImmuneObjects: Sum: 25us 99% C.I. 25us-25us Avg: 25us Max: 25us +(Paused)ClearCards: Sum: 19us 99% C.I. 0.250us-13us Avg: 1.461us Max: 13us +CopyingPhase: Sum: 17us 99% C.I. 17us-17us Avg: 17us Max: 17us +MarkZygoteLargeObjects: Sum: 16us 99% C.I. 16us-16us Avg: 16us Max: 16us +ThreadListFlip: Sum: 14us 99% C.I. 14us-14us Avg: 14us Max: 14us +SwapBitmaps: Sum: 9us 99% C.I. 9us-9us Avg: 9us Max: 9us +FreeList: Sum: 6us 99% C.I. 6us-6us Avg: 6us Max: 6us +ResumeRunnableThreads: Sum: 4us 99% C.I. 4us-4us Avg: 4us Max: 4us +(Paused)FlipCallback: Sum: 2us 99% C.I. 2us-2us Avg: 2us Max: 2us +(Paused)SetFromSpace: Sum: 1us 99% C.I. 1us-1us Avg: 1us Max: 1us +Done Dumping histograms +young concurrent copying paused: Sum: 63us 99% C.I. 63us-63us Avg: 63us Max: 63us +young concurrent copying freed-bytes: Avg: 1905KB Max: 1905KB Min: 1905KB +Freed-bytes histogram: 1600:1 +young concurrent copying total time: 53.653ms mean time: 53.653ms +young concurrent copying freed: 25923 objects with total size 1905KB +young concurrent copying throughput: 489113/s / 35MB/s per cpu-time: 47582634/s / 45MB/s +Average minor GC reclaim bytes ratio 0.92539 over 1 GC cycles +Average minor GC copied live bytes ratio 0.133529 over 2 minor GCs +Cumulative bytes moved 870264 +Cumulative objects moved 16602 +Peak regions allocated 27 (6912KB) / 768 (192MB) +Total time spent in GC: 53.653ms +Mean GC size throughput: 34MB/s per cpu-time: 44MB/s +Mean GC object throughput: 483160 objects/s +Total number of allocations 164018 +Total bytes allocated 8797KB +Total bytes freed 1905KB +Free memory 19MB +Free memory until GC 19MB +Free memory until OOME 185MB +Total memory 25MB +Max memory 192MB +Zygote space size 2980KB +Total mutator paused time: 63us +Total time waiting for GC to complete: 4.459us +Total GC count: 1 +Total GC time: 53.653ms +Total blocking GC count: 0 +Total blocking GC time: 0 +Native bytes total: 15962696 registered: 108600 +Total native bytes at last GC: 4019588 +/system/framework/oat/x86/android.hidl.manager-V1.0-java.odex: quicken +/system/framework/oat/x86/android.test.base.odex: quicken +/system/framework/oat/x86/android.hidl.base-V1.0-java.odex: quicken +Current JIT code cache size (used / resident): 52KB / 60KB +Current JIT data cache size (used / resident): 61KB / 96KB +Zygote JIT code cache size (at point of fork): 42KB / 44KB +Zygote JIT data cache size (at point of fork): 31KB / 36KB +Current JIT mini-debug-info size: 50KB +Current JIT capacity: 128KB +Current number of JIT JNI stub entries: 2 +Current number of JIT code cache entries: 207 +Total number of JIT compilations: 172 +Total number of JIT compilations for on stack replacement: 7 +Total number of JIT code cache collections: 1 +Memory used for stack maps: Avg: 85B Max: 660B Min: 12B +Memory used for compiled code: Avg: 324B Max: 2604B Min: 17B +Memory used for profiling info: Avg: 74B Max: 764B Min: 20B +Start Dumping histograms for 212 iterations for JIT timings +Compiling: Sum: 540.855ms 99% C.I. 0.030ms-21.292ms Avg: 2.563ms Max: 24.444ms +TrimMaps: Sum: 77.018ms 99% C.I. 1.850us-4245us Avg: 365.014us Max: 9813us +Code cache collection: Sum: 3.847ms 99% C.I. 3.847ms-3.847ms Avg: 3.847ms Max: 3.847ms +Done Dumping histograms +Memory used for compilation: Avg: 36KB Max: 322KB Min: 0B +ProfileSaver total_bytes_written=4974 +ProfileSaver total_number_of_writes=1 +ProfileSaver total_number_of_code_cache_queries=1 +ProfileSaver total_number_of_skipped_writes=0 +ProfileSaver total_number_of_failed_writes=0 +ProfileSaver total_ms_of_sleep=45000 +ProfileSaver total_ms_of_work=10 +ProfileSaver total_number_of_hot_spikes=4 +ProfileSaver total_number_of_wake_ups=3 + +suspend all histogram: Sum: 301us 99% C.I. 0.090us-104us Avg: 11.148us Max: 104us +DALVIK THREADS (20): +"Signal Catcher" daemon prio=10 tid=4 Runnable + | group="system" sCount=0 dsCount=0 flags=0 obj=0x13040b28 self=0xe738a810 + | sysTid=9216 nice=-20 cgrp=top-app sched=0/0 handle=0xdc5da1e0 + | state=R schedstat=( 17573906 201748 7 ) utm=0 stm=1 core=0 HZ=100 + | stack=0xdc4df000-0xdc4e1000 stackSize=1008KB + | held mutexes= "mutator lock"(shared held) + native: #00 pc 00542d9e /apex/com.android.art/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+110) + native: #01 pc 006a0897 /apex/com.android.art/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream >&, bool, BacktraceMap*, bool) const+1015) + native: #02 pc 0069a171 /apex/com.android.art/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream >&, bool, BacktraceMap*, bool) const+65) + native: #03 pc 006c61b4 /apex/com.android.art/lib/libart.so (art::DumpCheckpoint::Run(art::Thread*)+1172) + native: #04 pc 006bf266 /apex/com.android.art/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+630) + native: #05 pc 006be1ce /apex/com.android.art/lib/libart.so (art::ThreadList::Dump(std::__1::basic_ostream >&, bool)+2446) + native: #06 pc 006bd70c /apex/com.android.art/lib/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream >&)+1644) + native: #07 pc 0064d654 /apex/com.android.art/lib/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream >&)+212) + native: #08 pc 00665b6a /apex/com.android.art/lib/libart.so (art::SignalCatcher::HandleSigQuit()+1818) + native: #09 pc 0066496b /apex/com.android.art/lib/libart.so (art::SignalCatcher::Run(void*)+587) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + + +//expected api request to coroner api +// java stacktrace +(String declaringClass, String methodName, String fileName, int lineNumber) + + +// native stack +{ +"funcName": "syscall", +"library": "/apex/com.android.runtime/lib/bionic/libc.so", +"address": "0005ad68" +} + + + +"main" prio=5 tid=1 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x72287300 self=0xe7380e10 + | sysTid=9207 nice=-10 cgrp=top-app sched=0/0 handle=0xf583f478 + | state=S schedstat=( 44727379364 813394028 1292 ) utm=1691 stm=2781 core=1 HZ=100 + | stack=0xff020000-0xff022000 stackSize=8192KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 007894db /apex/com.android.art/lib/libart.so (art::GoToRunnable(art::Thread*)+507) + native: #05 pc 007892a1 /apex/com.android.art/lib/libart.so (art::JniMethodEnd(unsigned int, art::Thread*)+33) + native: #06 pc 02008de3 /memfd:jit-cache (deleted) (offset 2000000) (art_jni_trampoline+163) + native: #07 pc 02008cee /memfd:jit-cache (deleted) (offset 2000000) (backtraceio.backtraceio.MainActivity.handledException+46) + native: #08 pc 00142c04 /apex/com.android.art/lib/libart.so (art_quick_osr_stub+36) + native: #09 pc 003b138f /apex/com.android.art/lib/libart.so (art::jit::Jit::MaybeDoOnStackReplacement(art::Thread*, art::ArtMethod*, unsigned int, int, art::JValue*)+415) + native: #10 pc 007b2bf9 /apex/com.android.art/lib/libart.so (MterpMaybeDoOnStackReplacement+185) + native: #11 pc 0013a2f5 /apex/com.android.art/lib/libart.so (MterpHelpers+294) + native: #12 pc 00001034 /data/data/backtraceio.backtraceio/code_cache/.overlay/base.apk/classes16.dex (backtraceio.backtraceio.MainActivity.handledException+8) + native: #13 pc 0036fb02 /apex/com.android.art/lib/libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.16375758241455872412)+370) + native: #14 pc 00379b00 /apex/com.android.art/lib/libart.so (art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*)+176) + native: #15 pc 0078b325 /apex/com.android.art/lib/libart.so (artQuickToInterpreterBridge+1061) + native: #16 pc 0014220d /apex/com.android.art/lib/libart.so (art_quick_to_interpreter_bridge+77) + native: #17 pc 0013b922 /apex/com.android.art/lib/libart.so (art_quick_invoke_stub+338) + native: #18 pc 001d0381 /apex/com.android.art/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+241) + native: #19 pc 00630008 /apex/com.android.art/lib/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)+1464) + native: #20 pc 005886a0 /apex/com.android.art/lib/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+80) + at java.lang.Thread.yield(Native method) + at backtraceio.backtraceio.MainActivity.handledException(MainActivity.java:157) + at java.lang.reflect.Method.invoke(Native method) + at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:468) + at android.view.View.performClick(View.java:7448) + at android.view.View.performClickInternal(View.java:7425) + at android.view.View.access$3600(View.java:810) + at android.view.View$PerformClick.run(View.java:28305) + at android.os.Handler.handleCallback(Handler.java:938) + at android.os.Handler.dispatchMessage(Handler.java:99) + at android.os.Looper.loop(Looper.java:223) + at android.app.ActivityThread.main(ActivityThread.java:7656) + at java.lang.reflect.Method.invoke(Native method) + at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) + at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) + +"ADB-JDWP Connection Control Thread" daemon prio=0 tid=5 WaitingInMainDebuggerLoop + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040ba0 self=0xe738c410 + | sysTid=9218 nice=-20 cgrp=top-app sched=0/0 handle=0xdc3d81e0 + | state=S schedstat=( 4694215 13986760 9 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xdc2dd000-0xdc2df000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf496 /apex/com.android.runtime/lib/bionic/libc.so (__ppoll+38) + native: #02 pc 00083979 /apex/com.android.runtime/lib/bionic/libc.so (poll+105) + native: #03 pc 0000a493 /apex/com.android.art/lib/libadbconnection.so (adbconnection::AdbConnectionState::RunPollLoop(art::Thread*)+1171) + native: #04 pc 000086d2 /apex/com.android.art/lib/libadbconnection.so (adbconnection::CallbackFunction(void*)+1666) + native: #05 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #06 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"perfetto_hprof_listener" prio=10 tid=6 Native (still starting up) + | group="" sCount=1 dsCount=0 flags=1 obj=0x0 self=0xe7385410 + | sysTid=9217 nice=-20 cgrp=top-app sched=0/0 handle=0xdc4d91e0 + | state=S schedstat=( 6280850 9339243 10 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xdc3de000-0xdc3e0000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000ccf9c /apex/com.android.runtime/lib/bionic/libc.so (read+28) + native: #02 pc 0001aca2 /apex/com.android.art/lib/libperfetto_hprof.so (void* std::__1::__thread_proxy >, ArtPlugin_Initialize::$_29> >(void*)+306) + native: #03 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #04 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"HeapTaskDaemon" daemon prio=5 tid=7 WaitingForTaskProcessor + | group="system" sCount=1 dsCount=0 flags=1 obj=0x130410c8 self=0xe7384610 + | sysTid=9220 nice=4 cgrp=top-app sched=0/0 handle=0xc74921e0 + | state=S schedstat=( 43450902 17904055 20 ) utm=1 stm=2 core=1 HZ=100 + | stack=0xc738f000-0xc7391000 stackSize=1040KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 0034a036 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::GetTask(art::Thread*)+630) + native: #05 pc 0034aa64 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::RunAllTasks(art::Thread*)+84) + native: #06 pc 005591f5 /apex/com.android.art/lib/libart.so (art::VMRuntime_runHeapTasks(_JNIEnv*, _jobject*)+53) + at dalvik.system.VMRuntime.runHeapTasks(Native method) + at java.lang.Daemons$HeapTaskDaemon.runInternal(Daemons.java:531) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"Binder:9207_1" prio=5 tid=8 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040c18 self=0xe7380010 + | sysTid=9224 nice=0 cgrp=top-app sched=0/0 handle=0xc6f701e0 + | state=S schedstat=( 1496174 7615537 6 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc6e75000-0xc6e77000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"FinalizerWatchdogDaemon" daemon prio=5 tid=9 Waiting + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040c90 self=0xe7382a10 + | sysTid=9223 nice=4 cgrp=top-app sched=0/0 handle=0xc71771e0 + | state=S schedstat=( 398422 6565402 4 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc7074000-0xc7076000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x02d3c777> (a java.lang.Daemons$FinalizerWatchdogDaemon) + at java.lang.Object.wait(Object.java:442) + at java.lang.Object.wait(Object.java:568) + at java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:341) + - locked <0x02d3c777> (a java.lang.Daemons$FinalizerWatchdogDaemon) + at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:321) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"ReferenceQueueDaemon" daemon prio=5 tid=10 Waiting + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040d08 self=0xe7388c10 + | sysTid=9221 nice=4 cgrp=top-app sched=0/0 handle=0xc73891e0 + | state=S schedstat=( 533566 3015911 3 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc7286000-0xc7288000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x07fc5fe4> (a java.lang.Class) + at java.lang.Object.wait(Object.java:442) + at java.lang.Object.wait(Object.java:568) + at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:217) + - locked <0x07fc5fe4> (a java.lang.Class) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"Jit thread pool worker thread 0" daemon prio=5 tid=11 Native + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040d80 self=0xe7387e10 + | sysTid=9219 nice=0 cgrp=top-app sched=0/0 handle=0xc7596d60 + | state=S schedstat=( 468316720 500776964 211 ) utm=6 stm=39 core=0 HZ=100 + | stack=0xc7498000-0xc749a000 stackSize=1023KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 006c838f /apex/com.android.art/lib/libart.so (art::ThreadPool::GetTask(art::Thread*)+143) + native: #05 pc 006c73e5 /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Run()+133) + native: #06 pc 006c6e9d /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Callback(void*)+269) + native: #07 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #08 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"FinalizerDaemon" daemon prio=5 tid=12 Waiting + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040df8 self=0xe7386210 + | sysTid=9222 nice=4 cgrp=top-app sched=0/0 handle=0xc72801e0 + | state=S schedstat=( 1102483 7783564 5 ) utm=0 stm=0 core=1 HZ=100 + | stack=0xc717d000-0xc717f000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x0a047c4d> (a java.lang.Object) + at java.lang.Object.wait(Object.java:442) + at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190) + - locked <0x0a047c4d> (a java.lang.Object) + at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211) + at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:273) + at java.lang.Daemons$Daemon.run(Daemons.java:139) + at java.lang.Thread.run(Thread.java:923) + +"Binder:9207_2" prio=5 tid=13 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040e70 self=0xe7389a10 + | sysTid=9225 nice=0 cgrp=top-app sched=0/0 handle=0xc6e6f1e0 + | state=S schedstat=( 210561432 574003421 20 ) utm=10 stm=10 core=1 HZ=100 + | stack=0xc6d74000-0xc6d76000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"Binder:9207_3" prio=5 tid=14 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040ee8 self=0xe7391810 + | sysTid=9226 nice=0 cgrp=top-app sched=0/0 handle=0xc6d6e1e0 + | state=S schedstat=( 17000557 50151632 14 ) utm=0 stm=1 core=1 HZ=100 + | stack=0xc6c73000-0xc6c75000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"Binder:9207_4" prio=5 tid=15 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13040f60 self=0xe7390a10 + | sysTid=9227 nice=0 cgrp=top-app sched=0/0 handle=0xc68411e0 + | state=S schedstat=( 8392907 55881465 12 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc6746000-0xc6748000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) + native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) + native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) + native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42) + native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72) + native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174) + native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"Profile Saver" daemon prio=5 tid=16 Native + | group="system" sCount=1 dsCount=0 flags=1 obj=0x13040fd8 self=0xe738ee10 + | sysTid=9228 nice=9 cgrp=top-app sched=0/0 handle=0xc67401e0 + | state=S schedstat=( 14918009 13675595 16 ) utm=1 stm=0 core=1 HZ=100 + | stack=0xc6645000-0xc6647000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7) + native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40) + native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108) + native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35) + native: #04 pc 003cc829 /apex/com.android.art/lib/libart.so (art::ProfileSaver::Run()+633) + native: #05 pc 003d2e8f /apex/com.android.art/lib/libart.so (art::ProfileSaver::RunProfileSaverThread(void*)+175) + native: #06 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #07 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"RenderThread" daemon prio=7 tid=17 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x13041050 self=0xe7392610 + | sysTid=9229 nice=-10 cgrp=top-app sched=0/0 handle=0xc663f1e0 + | state=S schedstat=( 236695461 71606987 112 ) utm=4 stm=19 core=1 HZ=100 + | stack=0xc6544000-0xc6546000 stackSize=1008KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43) + native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45) + native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259) + native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118) + native: #05 pc 002452c5 /system/lib/libhwui.so (android::uirenderer::ThreadBase::waitForWork()+149) + native: #06 pc 0026cab7 /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+119) + native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374) + native: #08 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457) + native: #09 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100) + native: #10 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71) + (no managed stack frames) + +"BacktraceHandlerThread" prio=5 tid=18 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12cf4660 self=0xe738fc10 + | sysTid=9232 nice=0 cgrp=top-app sched=0/0 handle=0xc64281e0 + | state=S schedstat=( 313706628 570346891 185 ) utm=20 stm=11 core=0 HZ=100 + | stack=0xc6325000-0xc6327000 stackSize=1040KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43) + native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45) + native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259) + native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118) + native: #05 pc 0010ef8b /system/lib/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long long, int)+59) + at android.os.MessageQueue.nativePollOnce(Native method) + at android.os.MessageQueue.next(MessageQueue.java:335) + at android.os.Looper.loop(Looper.java:183) + at android.os.HandlerThread.run(HandlerThread.java:67) + +"Timer-0" prio=5 tid=19 TimedWaiting + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12cf5498 self=0xe738e010 + | sysTid=9233 nice=0 cgrp=top-app sched=0/0 handle=0xc62461e0 + | state=S schedstat=( 7524451 0 14 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc6143000-0xc6145000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x02569302> (a java.util.TaskQueue) + at java.lang.Object.wait(Object.java:442) + at java.util.TimerThread.mainLoop(Timer.java:559) + - locked <0x02569302> (a java.util.TaskQueue) + at java.util.TimerThread.run(Timer.java:512) + +"WifiManagerThread" prio=5 tid=20 Native + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12cff1c0 self=0xe7399610 + | sysTid=9236 nice=0 cgrp=top-app sched=0/0 handle=0xc613d1e0 + | state=S schedstat=( 581694 0 1 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc603a000-0xc603c000 stackSize=1040KB + | held mutexes= + native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9) + native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43) + native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45) + native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259) + native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118) + native: #05 pc 0010ef8b /system/lib/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long long, int)+59) + at android.os.MessageQueue.nativePollOnce(Native method) + at android.os.MessageQueue.next(MessageQueue.java:335) + at android.os.Looper.loop(Looper.java:183) + at android.os.HandlerThread.run(HandlerThread.java:67) + +"Thread-4" prio=5 tid=21 Sleeping + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12d8a710 self=0xe7394210 + | sysTid=9237 nice=0 cgrp=top-app sched=0/0 handle=0xc60341e0 + | state=S schedstat=( 76232117 47640734 71 ) utm=5 stm=2 core=0 HZ=100 + | stack=0xc5f31000-0xc5f33000 stackSize=1040KB + | held mutexes= + at java.lang.Thread.sleep(Native method) + - sleeping on <0x05336413> (a java.lang.Object) + at java.lang.Thread.sleep(Thread.java:442) + - locked <0x05336413> (a java.lang.Object) + at java.lang.Thread.sleep(Thread.java:358) + at backtraceio.library.watchdog.BacktraceANRHandlerWatchdog.run(BacktraceANRHandlerWatchdog.java:118) + +"OkHttp ConnectionPool" daemon prio=5 tid=22 TimedWaiting + | group="main" sCount=1 dsCount=0 flags=1 obj=0x12d39c50 self=0xe739b210 + | sysTid=9239 nice=0 cgrp=top-app sched=0/0 handle=0xc56251e0 + | state=S schedstat=( 442059 1414330 1 ) utm=0 stm=0 core=0 HZ=100 + | stack=0xc5522000-0xc5524000 stackSize=1040KB + | held mutexes= + at java.lang.Object.wait(Native method) + - waiting on <0x09119650> (a com.android.okhttp.ConnectionPool) + at com.android.okhttp.ConnectionPool$1.run(ConnectionPool.java:106) + - locked <0x09119650> (a com.android.okhttp.ConnectionPool) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) + at java.lang.Thread.run(Thread.java:923) + +----- end 9207 ----- + +----- Waiting Channels: pid 9207 at 2025-03-27 21:02:38 ----- +Cmd line: backtraceio.backtraceio + +sysTid=9207 0 +sysTid=9216 do_sigtimedwait +sysTid=9217 pipe_read +sysTid=9218 do_sys_poll +sysTid=9219 futex_wait_queue_me +sysTid=9220 futex_wait_queue_me +sysTid=9221 futex_wait_queue_me +sysTid=9222 futex_wait_queue_me +sysTid=9223 futex_wait_queue_me +sysTid=9224 binder_thread_read +sysTid=9225 binder_thread_read +sysTid=9226 binder_thread_read +sysTid=9227 binder_thread_read +sysTid=9228 futex_wait_queue_me +sysTid=9229 do_epoll_wait +sysTid=9232 do_epoll_wait +sysTid=9233 futex_wait_queue_me +sysTid=9236 do_epoll_wait +sysTid=9237 futex_wait_queue_me +sysTid=9239 futex_wait_queue_me + +----- end 9207 ----- diff --git a/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java b/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java index 75fc7c023..a39433b84 100644 --- a/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java +++ b/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java @@ -34,6 +34,7 @@ import backtraceio.library.models.json.BacktraceReport; public class MainActivity extends AppCompatActivity { + private BacktraceClient backtraceClient; private OnServerResponseEventListener listener; private final int anrTimeout = 3000; @@ -75,6 +76,7 @@ private void symlinkAndWriteFile() { private BacktraceClient initializeBacktrace(final String submissionUrl) { BacktraceCredentials credentials = new BacktraceCredentials(submissionUrl); + Context context = getApplicationContext(); String dbPath = context.getFilesDir().getAbsolutePath();