Skip to content

Issues when opening LMDB on x86 devices with old android API levels #709

Description

@yukibtc

x86_64 + API 35 => ✅
x86_64 + API 30 => ✅
x86 + API 35 => ✅
x86 + API 30 => ❌
x86 + API 26 => ❌

Error

FATAL EXCEPTION: main
Process: com.example.myapplication2, PID: 3129
rust.nostr.sdk.NostrSdkException$Generic: Out of memory (os error 12)
	at rust.nostr.sdk.FfiConverterTypeNostrSdkError.read(nostr_sdk.kt:40398)
	at rust.nostr.sdk.FfiConverterTypeNostrSdkError.read(nostr_sdk.kt:40394)
	at rust.nostr.sdk.FfiConverter$DefaultImpls.liftFromRustBuffer(nostr_sdk.kt:195)
	at rust.nostr.sdk.FfiConverterRustBuffer$DefaultImpls.liftFromRustBuffer(nostr_sdk.kt:207)
	at rust.nostr.sdk.FfiConverterTypeNostrSdkError.liftFromRustBuffer(nostr_sdk.kt:40394)
	at rust.nostr.sdk.FfiConverterTypeNostrSdkError.liftFromRustBuffer(nostr_sdk.kt:40394)
	at rust.nostr.sdk.FfiConverterRustBuffer$DefaultImpls.lift(nostr_sdk.kt:208)
	at rust.nostr.sdk.FfiConverterTypeNostrSdkError.lift(nostr_sdk.kt:40394)
	at rust.nostr.sdk.FfiConverterTypeNostrSdkError.lift(nostr_sdk.kt:40394)
	at rust.nostr.sdk.NostrSdkException$ErrorHandler.lift(nostr_sdk.kt:40390)
	at rust.nostr.sdk.NostrSdkException$ErrorHandler.lift(nostr_sdk.kt:40389)
	at rust.nostr.sdk.Nostr_sdkKt.uniffiCheckCallStatus(nostr_sdk.kt:271)
	at rust.nostr.sdk.Nostr_sdkKt.access$uniffiCheckCallStatus(nostr_sdk.kt:1)
	at rust.nostr.sdk.NostrDatabase$Companion.lmdb(nostr_sdk.kt:47588)
	at com.example.myapplication2.MainActivityKt$Greeting$getLocationOnClick$1$1.invokeSuspend(MainActivity.kt:61)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
	at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
	at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
	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)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@c447515, androidx.compose.runtime.BroadcastFrameClock@810702a, StandaloneCoroutine{Cancelling}@ba8be1b, AndroidUiDispatcher@4a75bb8]

To reproduce

package com.example.nostrtest

import android.os.Build
import android.os.Bundle
import androidx.compose.material3.Button
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import com.example.nostrtest.ui.theme.NostrTestTheme
import kotlinx.coroutines.launch
import rust.nostr.sdk.*

class MainActivity : ComponentActivity() {
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NostrTestTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Android")
                }
            }
        }
    }
}

@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    val coroutineScope = rememberCoroutineScope()

    val ctx = LocalContext.current
    val path = ctx.applicationInfo.dataDir

    val lmdbPath = "$path/database"

    val getLocationOnClick: () -> Unit = {
        coroutineScope.launch {
            initLogger(LogLevel.INFO)

            val keys = Keys.generate()
            val signer = NostrSigner.keys(keys = keys)
            val database = NostrDatabase.lmdb(lmdbPath)
            val client = ClientBuilder().signer(signer).database(database).build()
            client.addRelay("wss://relay.damus.io")

            client.connect()

            val filter = Filter().kind(Kind(1u)).limit(1000u)
            client.sync(filter, SyncOptions())

            // Query
            val f = Filter().kind(Kind(1u)).limit(10u)
            val events = database.query(listOf(f))

            events.toVec().forEach { event ->
                println(event.asJson())
            }
        }
    }

    Button(onClick = getLocationOnClick) {
        Text("Start")
    }
}

@RequiresApi(Build.VERSION_CODES.O)
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    NostrTestTheme {
        Greeting("Android")
    }
}
plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
}

android {
    namespace = "com.example.nostrtest"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.nostrtest"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
            signingConfig = signingConfigs.getByName("debug")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.1"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }

    splits {
        abi {
            isEnable = true
            reset()
            include("arm64-v8a", "x86_64")
            isUniversalApk = true
        }
    }
}

dependencies {

    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(libs.androidx.material3)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    androidTestImplementation(platform(libs.androidx.compose.bom))
    androidTestImplementation(libs.androidx.ui.test.junit4)
    debugImplementation(libs.androidx.ui.tooling)
    debugImplementation(libs.androidx.ui.test.manifest)

    implementation("org.rust-nostr:nostr-sdk:0.38.0")
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions