Search code examples
androidc++android-ndkjava-native-interface

Android NDK values coming as empty sometimes


I am trying to use NDK for my android application. I am using the map to store some key values as follow:

#include <jni.h>
#include <string>

#include <iostream>
#include <unordered_map>

class UrlHash {

    std::unordered_map<std::string, std::string> urlHash;

public:
    std::string getUrl(std::string urlKey) {
        return urlHash[debugUrlKey];
    }

    UrlHash() {
        urlHash["dummy"] = "dumyValue";
        urlHash["dump_url"] = "https://dump.server.com";
        urlHash["dump_url2"] = "https://dump2.server.com";
    }
};

extern "C"
JNIEXPORT jstring JNICALL
Java_my_com_mynativecapp_UrlProvider_getUrl(JNIEnv *env, jobject thiz, jstring urlName) {
UrlHash _debugHashtableInstance;
const char *NativeUrlName = env->GetStringUTFChars(urlName, 0);
env->ReleaseStringUTFChars(urlName, NativeUrlName);
return env->NewStringUTF(_debugHashtableInstance.getDebugUrl(NativeUrlName).c_str());
}

retrieving these values in the following way:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<Button>(R.id.sample_text).setOnClickListener {
            doExe()
        }

    fun doExe(){
        var dummy  = getUrl("dummy")
        var dump_url  = getUrl("dump_url")
        var dump_url2  = getUrl("dump_url2")
    }

    external fun getUrl(urlName: String): String

    companion object {
        init {
            System.loadLibrary("native-lib")
        }
    }
}

The above code works perfectly fine on other android versions except Android 5.1 and Android 6. On Android versions 5.1 and 6 sometimes the above values are obtained as empty values. This behaviour is not consistent. Sometimes it returns correct values and sometimes it returns empty values.

Code works perfectly fine on other Android versions like Android 7,8,10.


Solution

  • The buffer returned from GetStringUTFChars is only usable as long as you do not call ReleaseStringUTFChars.

    Do the lookup while you the buffer is usable, instead:

    const char *NativeUrlName = env->GetStringUTFChars(urlName, 0);
    auto result = _debugHashtableInstance.getDebugUrl(NativeUrlName);
    env->ReleaseStringUTFChars(urlName, NativeUrlName);
    return env->NewStringUTF(result.c_str());
    

    As a side note: operator[] on an std::unordered_map will insert and return a dummy string if the key is not present. You may not want this behavior.