'Android NDK fopen returns error 2 "No such file or directory" on a file I know exits

My app is accessing audio files and I'm doing some processing on them in OBOE. So I have JNI working, the files are located in my documents tree. All the parts are there and normally I'm loading the file into a byte array and passing it over the JNI for processing.

Now, I want to open a file directly in the Native code.

Essentially, on the Java side, I'm doing the following in an onActivityResult which is triggered by an ACTION_OPEN_DOCUMENT intent.

AudioUri = data.getData();
String filepath = AudioUri.getPath();

So filepath is being passed as a jstring in the JNI method. On the C++ side I'm doing the following

    JNIEXPORT void JNICALL
Java_com_myco_fileload_MainActivity_setFilepathNative(JNIEnv *env, jobject thiz,
                                                         jstring filepath) {

    std::string file_path = ConvertJString( env, filepath );

    __android_log_print(ANDROID_LOG_INFO, TAG,  "%s", file_path.c_str());

    FILE* file = fopen(file_path.c_str(),"rb");
    if(file){
        __android_log_print(ANDROID_LOG_INFO, TAG,  "%s", "it's a file");
    } else {
        __android_log_print(ANDROID_LOG_INFO, TAG,  "%s", "it's null");
        __android_log_print(ANDROID_LOG_INFO, TAG,  "%d", errno);
        __android_log_print(ANDROID_LOG_INFO, TAG,  "%s", strerror(errno));
    }
}

fopen() always results in null with errorcode 2 - 'No such file or directory'

filepath is /document/primary:Documents/myFolder/myfile.wav

So what is the issue? Is that the path is wrong? A permission error? Any thoughts?

edit #1 I found that if I change the filepath to /storage/emulated/0/Documents/myFolder/myfile.wav the error changes to errorcode 13, Permission Denied.

So my question is now w do I get the correct file path?

And why would I get permission denied on reading a file with Native that I can read with Java?

btw, my manifest contained the user permissions

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>

edit #2 It turns out this was a file permissions issue. I had to set permission to ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION, which is fine for my use case, but seems a bit excessive.

So, my question is now - how can I give the native code the permissions that are available to the java-side of my app?



Solution 1:[1]

Well, ACTION_OPEN_DOCUMENT returns a content:// and the getPath() on it is only valid for the respective content provider (its "authority"). So you can only access it through the content resolver interface.

I'd assume you're opening a file descriptor through ContentResolver#openFileDescriptor and the operating on it in Java. What you should do is get the file descriptor from the ParcelFileDescriptor (ParcelFileDescriptor#getFd()) and pass it on to NDK where you can operate on it like any other file descriptor. Just an FYI you should take care of the life time of the file descriptor however.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 codeconscious