diff --git a/anrs/anrs-impl/src/main/java/com/duckduckgo/app/anr/ndk/NativeCrashInit.kt b/anrs/anrs-impl/src/main/java/com/duckduckgo/app/anr/ndk/NativeCrashInit.kt index bb5c2d1ab3da..3ee91fb31ff3 100644 --- a/anrs/anrs-impl/src/main/java/com/duckduckgo/app/anr/ndk/NativeCrashInit.kt +++ b/anrs/anrs-impl/src/main/java/com/duckduckgo/app/anr/ndk/NativeCrashInit.kt @@ -20,21 +20,18 @@ import android.content.Context import android.util.Log import androidx.lifecycle.LifecycleOwner import com.duckduckgo.app.browser.customtabs.CustomTabDetector -import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.IsMainProcess import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.app.lifecycle.VpnProcessLifecycleObserver import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.appbuildconfig.api.isInternalBuild -import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.checkMainThread import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.library.loader.LibraryLoader +import com.duckduckgo.library.loader.LibraryLoader.LibraryLoaderListener import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn import javax.inject.Inject -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import logcat.LogPriority.ERROR import logcat.asLog import logcat.logcat @@ -49,33 +46,21 @@ import logcat.logcat ) @SingleInstanceIn(AppScope::class) class NativeCrashInit @Inject constructor( - context: Context, + private val context: Context, @IsMainProcess private val isMainProcess: Boolean, private val customTabDetector: CustomTabDetector, private val appBuildConfig: AppBuildConfig, private val nativeCrashFeature: NativeCrashFeature, - private val dispatcherProvider: DispatcherProvider, - @AppCoroutineScope private val coroutineScope: CoroutineScope, -) : MainProcessLifecycleObserver, VpnProcessLifecycleObserver { +) : MainProcessLifecycleObserver, VpnProcessLifecycleObserver, LibraryLoaderListener { private val isCustomTab: Boolean by lazy { customTabDetector.isCustomTab() } private val processName: String by lazy { if (isMainProcess) "main" else "vpn" } - init { - try { - LibraryLoader.loadLibrary(context, "crash-ndk") - } catch (ignored: Throwable) { - logcat(ERROR) { "ndk-crash: Error loading crash-ndk lib: ${ignored.asLog()}" } - } - } - private external fun jni_register_sighandler(logLevel: Int, appVersion: String, processName: String, isCustomTab: Boolean) override fun onCreate(owner: LifecycleOwner) { if (isMainProcess) { - coroutineScope.launch { - jniRegisterNativeSignalHandler() - } + asyncLoadNativeLibrary() } else { logcat(ERROR) { "ndk-crash: onCreate wrongly called in a secondary process" } } @@ -83,18 +68,21 @@ class NativeCrashInit @Inject constructor( override fun onVpnProcessCreated() { if (!isMainProcess) { - coroutineScope.launch { - jniRegisterNativeSignalHandler() - } + asyncLoadNativeLibrary() } else { logcat(ERROR) { "ndk-crash: onCreate wrongly called in the main process" } } } - private suspend fun jniRegisterNativeSignalHandler() = withContext(dispatcherProvider.io()) { + override fun success() { + // do not call on main thread + checkMainThread() + runCatching { - if (isMainProcess && !nativeCrashFeature.nativeCrashHandling().isEnabled()) return@withContext - if (!isMainProcess && !nativeCrashFeature.nativeCrashHandlingSecondaryProcess().isEnabled()) return@withContext + logcat(ERROR) { "ndk-crash: Library loaded in process $processName" } + + if (isMainProcess && !nativeCrashFeature.nativeCrashHandling().isEnabled()) return + if (!isMainProcess && !nativeCrashFeature.nativeCrashHandlingSecondaryProcess().isEnabled()) return val logLevel = if (appBuildConfig.isDebug || appBuildConfig.isInternalBuild()) { Log.VERBOSE @@ -106,4 +94,12 @@ class NativeCrashInit @Inject constructor( logcat(ERROR) { "ndk-crash: Error calling jni_register_sighandler: ${it.asLog()}" } } } + + override fun failure(t: Throwable?) { + logcat(ERROR) { "ndk-crash: error loading library in process $processName: ${t?.asLog()}" } + } + + private fun asyncLoadNativeLibrary() { + LibraryLoader.loadLibrary(context, "crash-ndk", this) + } } diff --git a/library-loader/library-loader-api/build.gradle b/library-loader/library-loader-api/build.gradle index 0a2fd6dcc9d0..81d8ca45bc43 100644 --- a/library-loader/library-loader-api/build.gradle +++ b/library-loader/library-loader-api/build.gradle @@ -23,7 +23,7 @@ apply from: "$rootProject.projectDir/gradle/android-library.gradle" dependencies { - implementation "com.getkeepsafe.relinker:relinker:_" + api "com.getkeepsafe.relinker:relinker:_" } android { diff --git a/library-loader/library-loader-api/src/main/java/com/duckduckgo/library/loader/LibraryLoader.kt b/library-loader/library-loader-api/src/main/java/com/duckduckgo/library/loader/LibraryLoader.kt index e973c8f123a4..f761a852ac5e 100644 --- a/library-loader/library-loader-api/src/main/java/com/duckduckgo/library/loader/LibraryLoader.kt +++ b/library-loader/library-loader-api/src/main/java/com/duckduckgo/library/loader/LibraryLoader.kt @@ -18,11 +18,18 @@ package com.duckduckgo.library.loader import android.content.Context import com.getkeepsafe.relinker.ReLinker +import com.getkeepsafe.relinker.ReLinker.LoadListener class LibraryLoader { companion object { fun loadLibrary(context: Context, name: String) { ReLinker.loadLibrary(context, name) } + + fun loadLibrary(context: Context, name: String, listener: LibraryLoaderListener) { + ReLinker.loadLibrary(context, name, listener) + } } + + interface LibraryLoaderListener : LoadListener }