Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android only bug - Due to how the compiled library is being loaded - rather loaded twice (JNI load issue) #1868

Closed
debanjanbasu opened this issue Apr 9, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@debanjanbasu
Copy link
Contributor

debanjanbasu commented Apr 9, 2024

Describe the bug

I'm working on a project, which does require android_context to be initialized beforehand. The challenge is the I followed this guide: https://cjycode.com/flutter_rust_bridge/manual/troubleshooting#android-context-was-not-initialized-or-ndk_context-initialization

`pub mod api;
mod frb_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */

#[cfg(target_os = "android")]
use {
    jni::{sys::jint, JNIVersion, JavaVM},
    log::info,
    ndk_context::initialize_android_context,
};

#[cfg(target_os = "android")]
#[no_mangle]
pub extern "C" fn JNI_OnLoad(vm: JavaVM, res: *mut std::os::raw::c_void) -> jint {
    info!("Threads attached: {:?}", vm.threads_attached());

    // Initialize the android context
    unsafe { initialize_android_context(vm.get_java_vm_pointer() as *mut std::ffi::c_void, res) };

    JNIVersion::V6.into()
}

and obviously in the the main Kotling file:

package com.example.spareshare

import io.flutter.embedding.android.FlutterActivity

class MainActivity : FlutterActivity() {
    // this `init` block, where "foo" is the name of your library
    // ex: if it's libfoo.so, then use "foo"
    init {
        System.loadLibrary("rust_lib_spareshare")
    }
}

Also, I'm using regular await Rustlib.init()

When my application is trying to attach the current android thread, it's getting attached to different threads, as two threads are being spun up.

info!("👺 Initializing Android Context...");

        // Get a VM for executing JNI calls
        let ctx = android_context();
        let vm = unsafe { JavaVM::from_raw(ctx.vm().cast()) }?;
        let _context = unsafe { JObject::from_raw(ctx.context().cast()) };
        let env = vm.attach_current_thread_as_daemon()?;

        info!("Threads attached: {:?}", vm.threads_attached());`

The above code is getting attached to the second thread, wherein the regular other FRB functions are to the first one. Is there a way to avoid this? 🤔 I've been splitting my head over this for almost a week now. I've tried all possibly ways, as am not an avid Kotling developer, I really want to avoid customizing the Kotlin files, also that might not even solve the issue, if FRB, and the JNI_Onload are running on two separate threads.

Steps to reproduce

It's a unique problem, but I would try to reproduce the problem from an example code. I'm sure there might be a simpler workaround.

Logs

The issue is not being logged from FRB, rather when the actual flutter app is being deployed.

INFO: Precompiled binaries are disabled
INFO: Building rust_lib_spareshare for aarch64-linux-android
INFO: Building rust_lib_spareshare for i686-linux-android
INFO: Building rust_lib_spareshare for x86_64-linux-android
Running Gradle task 'assembleDebug'...                             32.3s
✓ Built build/app/outputs/flutter-apk/app-debug.apk
Installing build/app/outputs/flutter-apk/app-debug.apk...        1,774ms
E/flutter (28603): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: AnyhowException(Generic: Could not initialize the protected store.
E/flutter (28603):
E/flutter (28603): Stack backtrace:
E/flutter (28603):    0: <unknown>
E/flutter (28603):    1: <unknown>
E/flutter (28603):    2: <unknown>
E/flutter (28603):    3: <unknown>
E/flutter (28603):    4: <unknown>
E/flutter (28603):    5: <unknown>
E/flutter (28603):    6: <unknown>
E/flutter (28603):    7: <unknown>
E/flutter (28603):    8: <unknown>

The root cause is that it's running in two separate threads.

Expected behavior

Expected to have one thread so when we're trying to get the android_context, it does work as expected, unless we're actually spinning up another thread.

Generated binding code

No response

OS

MacOS

Version of flutter_rust_bridge_codegen

dev.30

Flutter info

[✓] Flutter (Channel main, 3.22.0-6.0.pre.24, on macOS 14.5 23F5049f darwin-arm64, locale en-AU)
    • Flutter version 3.22.0-6.0.pre.24 on channel main at /opt/homebrew/Caskroom/flutter/3.16.2/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 4967a94cd9 (3 hours ago), 2024-04-09 11:30:04 +0300
    • Engine revision 5a824e22de
    • Dart version 3.5.0 (build 3.5.0-36.0.dev)
    • DevTools version 2.34.1

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/debanjanbasu/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/debanjanbasu/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.9+0-17.0.9b1087.7-11185874)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15E204a
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.9+0-17.0.9b1087.7-11185874)

[✓] VS Code (version 1.89.0-insider)
    • VS Code at /Applications/Visual Studio Code - Insiders.app/Contents
    • Flutter extension version 3.87.20240402

[✓] Connected device (5 available)
    • sdk gphone64 arm64 (mobile)     • emulator-5554             • android-arm64  • Android 14 (API 34) (emulator)
    • Debanjan Basu’s iPhone (mobile) • 00008110-001A44C63E10401E • ios            • iOS 17.5 21F5048f
    • macOS (desktop)                 • macos                     • darwin-arm64   • macOS 14.5 23F5049f darwin-arm64
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad     • darwin         • macOS 14.5 23F5049f darwin-arm64
    • Chrome (web)                    • chrome                    • web-javascript • Google Chrome 123.0.6312.107

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Version of clang++

No response

Additional context

No response

@debanjanbasu debanjanbasu added the bug Something isn't working label Apr 9, 2024
Copy link

welcome bot commented Apr 9, 2024

Hi! Thanks for opening your first issue here! 😄

@fzyzcjy fzyzcjy added the awaiting Waiting for responses, PR, further discussions, upstream release, etc label Apr 9, 2024
@fzyzcjy
Copy link
Owner

fzyzcjy commented Apr 9, 2024

Hi, I am also not an Android expert, and here are my two cents:

@debanjanbasu
Copy link
Contributor Author

debanjanbasu commented Apr 12, 2024

Finally got to solve it by using this code block in this way:

in MainActivity.kt

package com.example.spareshare

import android.content.Context
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

class MainActivity : FlutterActivity() {
    override fun configureFlutterEngine(
        @NonNull flutterEngine: FlutterEngine,
    ) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine.plugins.add(MyPlugin())
    }
}

class MyPlugin : FlutterPlugin, MethodCallHandler {
    companion object {
        init {
            System.loadLibrary("rust_lib_spareshare")
        }
    }

    external fun init_android(ctx: Context)

    override fun onAttachedToEngine(
        @NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding,
    ) {
        init_android(flutterPluginBinding.applicationContext)
    }

    override fun onMethodCall(
        @NonNull call: MethodCall,
        @NonNull result: Result,
    ) {
        result.notImplemented()
    }

    override fun onDetachedFromEngine(
        @NonNull binding: FlutterPlugin.FlutterPluginBinding,
    ) {
    }
}

and in lib.rs

#[cfg(target_os = "android")]
use {
    jni::{objects::JClass, objects::JObject, JNIEnv},
    mylib::setup_android,
};

#[cfg(target_os = "android")]
#[no_mangle]
pub extern "system" fn Java_com_example_spareshare_MyPlugin_init_1android(
    env: JNIEnv,
    _class: JClass,
    ctx: JObject,
) {
    setup_android(env, ctx);
}

@debanjanbasu
Copy link
Contributor Author

Closing it, as has been resolved.

@fzyzcjy
Copy link
Owner

fzyzcjy commented Apr 12, 2024

Happy to see it is resolved!

Copy link
Contributor

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 26, 2024
@fzyzcjy fzyzcjy removed the awaiting Waiting for responses, PR, further discussions, upstream release, etc label Jun 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants