Skip to content

Commit 886d06e

Browse files
committed
Merge branch 'release/5.200.0'
2 parents 85266ae + d34f33f commit 886d06e

File tree

63 files changed

+1620
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1620
-79
lines changed

.maestro/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ appStartup:
22
enabled: false
33
appSize:
44
enabled: false
5-
disableRetries: true
5+
disableRetries: false
66

77
flows:
88
- "**"

anrs/anrs-impl/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
project(crash-ndk)
2+
cmake_minimum_required(VERSION 3.4.1)
3+
4+
add_library( # Sets the name of the library.
5+
crash-ndk
6+
7+
# Sets the library as a shared library.
8+
SHARED
9+
10+
# Provides a relative path to your source file(s).
11+
src/main/cpp/ndk-crash.cpp
12+
src/main/cpp/jni.cpp
13+
src/main/cpp/pixel.cpp
14+
)
15+
16+
find_library( # Sets the name of the path variable.
17+
log-lib
18+
19+
# Specifies the name of the NDK library that
20+
# you want CMake to locate.
21+
log)
22+
23+
target_link_libraries(
24+
# Specifies the target library.
25+
crash-ndk
26+
27+
# Links the target library to the log library
28+
# included in the NDK.
29+
${log-lib} )

anrs/anrs-impl/build.gradle

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ plugins {
2323
apply from: "$rootProject.projectDir/gradle/android-library.gradle"
2424

2525
dependencies {
26+
anvil project(':anvil-compiler')
27+
implementation project(':anvil-annotations')
28+
2629
implementation project(':app-build-config-api')
2730
implementation project(':anrs-api')
2831
implementation project(':anrs-store')
@@ -31,6 +34,8 @@ dependencies {
3134
implementation project(':browser-api')
3235
implementation project(':statistics')
3336
implementation project(':verified-installation-api')
37+
implementation project(':library-loader-api')
38+
implementation project(':feature-toggles-api')
3439

3540
implementation AndroidX.core.ktx
3641
implementation KotlinX.coroutines.core
@@ -56,8 +61,16 @@ android {
5661
anvil {
5762
generateDaggerFactories = true // default is false
5863
}
59-
namespace 'com.duckduckgo.app.anr'
64+
65+
ndkVersion '21.4.7075529'
66+
namespace 'com.duckduckgo.app.anr'
6067
compileOptions {
6168
coreLibraryDesugaringEnabled = true
6269
}
70+
71+
externalNativeBuild {
72+
cmake {
73+
path "CMakeLists.txt"
74+
}
75+
}
6376
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef ANDROID_JNI_H
2+
#define ANDROID_JNI_H
3+
4+
#include <cstdio>
5+
#include <android/log.h>
6+
7+
void __platform_log_print(int prio, const char *tag, const char *fmt, ...);
8+
9+
// loglevel will be assigned during library initialisation, it always has a default value
10+
extern int loglevel;
11+
extern char pname[256];
12+
extern char appVersion[256];
13+
extern bool isCustomTab;
14+
15+
// Use this method to print log messages into the console
16+
#define log_print(prio, format, ...) do { if (prio >= loglevel) __platform_log_print(prio, "ndk-crash", format, ##__VA_ARGS__); } while (0)
17+
18+
#endif // ANDROID_JNI_H
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#include <jni.h>
2+
#include <android/log.h>
3+
#include <exception>
4+
#include <string.h> // strncpy
5+
6+
#include "android.h"
7+
#include "ndk-crash.h"
8+
#include "pixel.h"
9+
10+
///////////////////////////////////////////////////////////////////////////
11+
12+
static JavaVM *JVM = NULL;
13+
jclass clsCrash;
14+
jobject CLASS_JVM_CRASH = NULL;
15+
16+
17+
static jobject jniGlobalRef(JNIEnv *env, jobject cls);
18+
static jclass jniFindClass(JNIEnv *env, const char *name);
19+
static jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature);
20+
21+
int loglevel = 0;
22+
char appVersion[256];
23+
char pname[256];
24+
bool isCustomTab = false;
25+
26+
///////////////////////////////////////////////////////////////////////////
27+
28+
29+
void __platform_log_print(int prio, const char *tag, const char *fmt, ...) {
30+
char line[1024];
31+
va_list argptr;
32+
va_start(argptr, fmt);
33+
vsprintf(line, fmt, argptr);
34+
__android_log_print(prio, tag, "%s", line);
35+
va_end(argptr);
36+
}
37+
38+
///////////////////////////////////////////////////////////////////////////
39+
// JNI utils
40+
///////////////////////////////////////////////////////////////////////////
41+
42+
static jobject jniGlobalRef(JNIEnv *env, jobject cls) {
43+
jobject gcls = env->NewGlobalRef(cls);
44+
if (gcls == NULL)
45+
log_print(ANDROID_LOG_ERROR, "Global ref failed (out of memory?)");
46+
return gcls;
47+
}
48+
49+
static jclass jniFindClass(JNIEnv *env, const char *name) {
50+
jclass cls = env->FindClass(name);
51+
if (cls == NULL)
52+
log_print(ANDROID_LOG_ERROR, "Class %s not found", name);
53+
return cls;
54+
}
55+
56+
static jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature) {
57+
jmethodID method = env->GetMethodID(cls, name, signature);
58+
if (method == NULL) {
59+
log_print(ANDROID_LOG_ERROR, "Method %s %s not found", name, signature);
60+
}
61+
return method;
62+
}
63+
64+
///////////////////////////////////////////////////////////////////////////
65+
// JNI lifecycle
66+
///////////////////////////////////////////////////////////////////////////
67+
68+
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
69+
JNIEnv *env;
70+
if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
71+
log_print(ANDROID_LOG_INFO, "JNI load GetEnv failed");
72+
return -1;
73+
}
74+
75+
jint rs = env->GetJavaVM(&JVM);
76+
if (rs != JNI_OK) {
77+
log_print(ANDROID_LOG_ERROR, "Could not get JVM");
78+
return -1;
79+
}
80+
81+
return JNI_VERSION_1_6;
82+
}
83+
84+
void JNI_OnUnload(JavaVM *vm, void *reserved) {
85+
log_print(ANDROID_LOG_INFO, "JNI unload");
86+
87+
JNIEnv *env;
88+
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK)
89+
log_print(ANDROID_LOG_INFO, "JNI load GetEnv failed");
90+
else {
91+
env->DeleteGlobalRef(clsCrash);
92+
}
93+
}
94+
95+
///////////////////////////////////////////////////////////////////////////
96+
// native<>JVM interface
97+
///////////////////////////////////////////////////////////////////////////
98+
99+
extern "C" JNIEXPORT void JNICALL
100+
Java_com_duckduckgo_app_anr_ndk_NativeCrashInit_jni_1register_1sighandler(
101+
JNIEnv* env,
102+
jobject instance,
103+
jint loglevel_,
104+
jstring version_,
105+
jstring pname_,
106+
jboolean customtab_
107+
) {
108+
109+
if (!native_crash_handler_init()) {
110+
log_print(ANDROID_LOG_ERROR, "Error initialising crash handler.");
111+
return;
112+
}
113+
114+
// get and set loglevel
115+
loglevel = loglevel_;
116+
117+
// get and set app vesrion
118+
const char *versionChars = env->GetStringUTFChars(version_, nullptr);
119+
strncpy(appVersion, versionChars, sizeof(appVersion) - 1);
120+
appVersion[sizeof(appVersion) - 1] = '\0'; // Ensure null-termination
121+
env->ReleaseStringUTFChars(version_, versionChars);
122+
123+
// get and set process name
124+
const char *pnameChars = env->GetStringUTFChars(pname_, nullptr);
125+
strncpy(pname, pnameChars, sizeof(pname) - 1);
126+
pname[sizeof(pname) - 1] = '\0'; // Ensure null-termination
127+
env->ReleaseStringUTFChars(pname_, pnameChars);
128+
129+
// get and set isCustomTabs
130+
isCustomTab = customtab_;
131+
132+
clsCrash = env->GetObjectClass(instance);
133+
const char *emptyParamVoidSig = "()V";
134+
CLASS_JVM_CRASH = env->NewGlobalRef(instance);
135+
136+
send_crash_handle_init_pixel();
137+
138+
log_print(ANDROID_LOG_ERROR, "Native crash handler successfully initialized.");
139+
}
140+
141+
extern "C" JNIEXPORT void JNICALL
142+
Java_com_duckduckgo_app_anr_ndk_NativeCrashInit_jni_1unregister_sighandler(
143+
JNIEnv* env,
144+
jobject /* this */) {
145+
native_crash_handler_fini();
146+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include "jni.h"
2+
#include "android.h"
3+
#include "pixel.h"
4+
5+
#include <csignal>
6+
#include <cstdio>
7+
#include <cstring>
8+
#include <memory>
9+
#include <cxxabi.h>
10+
#include <unistd.h>
11+
12+
#define sizeofa(array) sizeof(array) / sizeof(array[0])
13+
14+
// sometimes signal handlers inlinux consume crashes entirely. For those cases we trigger a signal so that we ultimately
15+
// crash properly
16+
#define __NR_tgkill 270
17+
18+
// Caught signals
19+
static const int SIGNALS_TO_CATCH[] = {
20+
SIGABRT,
21+
SIGBUS,
22+
SIGFPE,
23+
SIGSEGV,
24+
SIGILL,
25+
SIGSTKFLT,
26+
SIGTRAP,
27+
};
28+
29+
// Signal handler context
30+
struct CrashInContext {
31+
// Old handlers of signals that we restore on de-initialization. Keep values for all possible
32+
// signals, for unused signals nullptr value is stored.
33+
struct sigaction old_handlers[NSIG];
34+
};
35+
36+
// Crash handler function signature
37+
typedef void (*CrashSignalHandler)(int, siginfo*, void*);
38+
39+
// Global instance of context. As the app can only crash once per process lifetime, this can be global
40+
static CrashInContext* crashInContext = nullptr;
41+
42+
43+
// Main signal handling function.
44+
static void native_crash_sig_handler(int signo, siginfo* siginfo, void* ctxvoid) {
45+
// Restoring an old handler to make built-in Android crash mechanism work.
46+
sigaction(signo, &crashInContext->old_handlers[signo], nullptr);
47+
48+
// Log crash message
49+
__android_log_print(ANDROID_LOG_ERROR, "ndk-crash", "Terminating with uncaught exception of type %d", signo);
50+
send_crash_pixel();
51+
52+
// sometimes signal handlers inlinux consume crashes entirely. For those cases we trigger a signal so that we ultimately
53+
// crash properly, ie. to run standard bionic handler
54+
if (siginfo->si_code <= 0 || signo == SIGABRT) {
55+
if (syscall(__NR_tgkill, getpid(), gettid(), signo) < 0) {
56+
_exit(1);
57+
}
58+
}
59+
}
60+
61+
// Register signal handler for crashes
62+
static bool register_sig_handler(CrashSignalHandler handler, struct sigaction old_handlers[NSIG]) {
63+
struct sigaction sigactionstruct;
64+
memset(&sigactionstruct, 0, sizeof(sigactionstruct));
65+
sigactionstruct.sa_flags = SA_SIGINFO;
66+
sigactionstruct.sa_sigaction = handler;
67+
68+
// Register new handlers for all signals
69+
for (int index = 0; index < sizeofa(SIGNALS_TO_CATCH); ++index) {
70+
const int signo = SIGNALS_TO_CATCH[index];
71+
72+
if (sigaction(signo, &sigactionstruct, &old_handlers[signo])) {
73+
return false;
74+
}
75+
}
76+
77+
return true;
78+
}
79+
80+
// Unregister already register signal handler
81+
static void unregister_sig_handler(struct sigaction old_handlers[NSIG]) {
82+
// Recover old handler for all signals
83+
for (int signo = 0; signo < NSIG; ++signo) {
84+
const struct sigaction* old_handler = &old_handlers[signo];
85+
86+
if (!old_handler->sa_handler) {
87+
continue;
88+
}
89+
90+
sigaction(signo, old_handler, nullptr);
91+
}
92+
}
93+
94+
bool native_crash_handler_fini() {
95+
// Check if already deinitialized
96+
if (!crashInContext) return false;
97+
98+
// Unregister signal handlers
99+
unregister_sig_handler(crashInContext->old_handlers);
100+
101+
// Free singleton crash handler context
102+
free(crashInContext);
103+
crashInContext = nullptr;
104+
105+
log_print(ANDROID_LOG_ERROR, "Native crash handler successfully deinitialized.");
106+
107+
return true;
108+
}
109+
110+
bool native_crash_handler_init() {
111+
// Check if already initialized
112+
if (crashInContext) {
113+
log_print(ANDROID_LOG_INFO, "Native crash handler is already initialized.");
114+
return false;
115+
}
116+
117+
// Initialize singleton crash handler context
118+
crashInContext = static_cast<CrashInContext *>(malloc(sizeof(CrashInContext)));
119+
memset(crashInContext, 0, sizeof(CrashInContext));
120+
121+
// Trying to register signal handler.
122+
if (!register_sig_handler(&native_crash_sig_handler, crashInContext->old_handlers)) {
123+
native_crash_handler_fini();
124+
log_print(ANDROID_LOG_ERROR, "Native crash handler initialization failed.");
125+
return false;
126+
}
127+
128+
return true;
129+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Java
2+
#ifndef NDK_CRASH_H
3+
#define NDK_CRASH_H
4+
5+
// Call this method to register native crash handling
6+
bool native_crash_handler_init();
7+
// Call this method to de-register native crash handling
8+
bool native_crash_handler_fini();
9+
10+
#endif // NDK_CRASH_H

0 commit comments

Comments
 (0)