【问题标题】:Invalid indirect reference on NewObject callNewObject 调用的间接引用无效
【发布时间】:2012-06-18 19:33:34
【问题描述】:

好的,所以我有下面的本机代码。 我正在尝试从中返回一个 FilePermissionInfo 数组,其中填充了一些由 stat() 返回的数据。 问题是第一次调用 NewObject 时出现以下错误:

06-15 20:25:17.621:W/dalvikvm(2287):间接引用无效 decodeIndirectRef 06-15 20:25:17.621 中的 0x40005820:E/dalvikvm(2287): 虚拟机中止

这很奇怪,因为我拥有的唯一引用对象是 jclass(用于 FilePermissionInfo),我将其转换为全局引用。

代码是:

JNIEXPORT jobjectArray JNICALL
Java_com_mn_rootscape_utils_NativeMethods_getFilesPermissions( JNIEnv* env, jobject thizz, jobjectArray filePathsArray ) 
{
jobjectArray result;
int size = (*env)->GetArrayLength(env, filePathsArray);
jboolean isCopy;

jclass filePermInfoCls = (*env)->FindClass(env, kFilePermissionInfoPath);
if(!filePermInfoCls)
{
    LOGE("getFilesPermissions: failed to get class reference.");
    return NULL;
}

gFilePermInfoClass = (jclass)(*env)->NewGlobalRef(env, filePermInfoCls);
LOGI("got gFilePermInfoClass");

jmethodID filePermInfoClsConstructor = (*env)->GetMethodID(env, gFilePermInfoClass, "<init>", kFilePermInfoConstructorSig);
if(!filePermInfoClsConstructor)
{
    LOGE("getFilesPermissions: failed to get method reference.");
    return NULL;
}

struct stat sb;

LOGI("starting...");
result = (jobjectArray)(*env)->NewObjectArray(env, size, gFilePermInfoClass, NULL);
for(int i = 0; i != size; ++i) 
{
    jstring string = (jstring) (*env)->GetObjectArrayElement(env, filePathsArray, i);
const char *rawString = (*env)->GetStringUTFChars(env, string, &isCopy);    

    if(stat(rawString, &sb) == -1) 
    {
        LOGE("stat error for: %s", rawString);
    }

    LOGI("%ld %ld %ld %ld %ld %ld %ld %ld", sb.st_dev, sb.st_mode, sb.st_nlink, sb.st_uid, sb.st_gid, sb.st_atime, sb.st_mtime, sb.st_ctime);

    jobject permInfo = (*env)->NewObject(env, 
                            gFilePermInfoClass, 
                            filePermInfoClsConstructor, 
                            (long)sb.st_dev,
                            (long)sb.st_mode,
                            (long)sb.st_nlink,
                            (long)sb.st_uid,
                            (long)sb.st_gid,
                            (long)sb.st_atime,
                            (long)sb.st_mtime,
                            (long)sb.st_ctime,
                            "",
                            "",
                            1,
                            "");

    LOGI("xxx1");
    (*env)->SetObjectArrayElement(env, result, i, permInfo);
    LOGI("xxx2");
    (*env)->ReleaseStringUTFChars(env, string, rawString);
    LOGI("xxx3");
}

(*env)->DeleteLocalRef(env, filePermInfoCls);

return result;

}

Java 类构造函数签名和路径为:

const char* kFilePermissionInfoPath = "com/mn/rootscape/utils/FilePermissionInfo";
const char* kFilePermInfoConstructorSig = "(JJJJJJJJLjava/lang/String;Ljava/lang/String;ZLjava/lang/String;)V";

请注意,如果我在默认构造函数上调用 NewObject,那么它可以正常工作。

【问题讨论】:

  • 我真的希望这不是 NDK (v8) 中的错误。我已经尝试了各种方法,它与默认构造函数(即“()V”)一起使用非常奇怪。最终我可以使用该类中的设置器来设置值,但我不想调用太多JNI 边界上的方法。

标签: android android-ndk android-4.0-ice-cream-sandwich native-code


【解决方案1】:

好的,找到了。 jstring 参数有问题。事实证明,您不能将空字符串(甚至是 NULL)作为jstring 传递。 相反,我使用 (*env)-&gt;NewStringUTF(env, NULL) 创建了一个 NULL jstring

现在似乎可以正常工作了。


由于这个问题引起了一些活跃,我将在下面发布最终解决方案。请注意,nullString 变量将在其作用域结束时(或使用完毕时)被释放:

        jstring nullString = (*env)->NewStringUTF(env, NULL);
...
        jobject permInfo = (*env)->NewObject(env, 
                                gFilePermInfoClass, 
                                filePermInfoClsConstructor, 
                                (jbyte)permsOwner,
                                (jbyte)permsGroup,
                                (jbyte)permsOthers,
                                (jlong)sb.st_uid,
                                (jlong)sb.st_gid,
                                (jlong)sb.st_atime,
                                (jlong)sb.st_mtime,
                                (jlong)sb.st_ctime,
                                nullString,
                                nullString,
                                (jboolean)1,
                                nullString);
...
       (*env)->DeleteLocalRef(env, nullString);

【讨论】:

  • 您的意思是将(*env)-&gt;NewObject(...)函数调用中的"","",参数替换为jstring myNullString = (*env)-&gt;NewStringUTF(env, NULL),然后将myNullString作为参数传递?
  • 我不确定这仍然是空 jstrings 的问题,如最初所述。我遇到了这个问题,但能够使用类似的东西来修复它:std:string empty(""); jstring myemptyString = (*env)->NewStringUTF(empty.c_str());请注意,我正在使用 android 4.3 进行测试。
  • @MichaelMarsella:我认为这只是传递一个非空值。似乎并不关心底层缓冲区实际上是 NULL 还是空字符串。但是,由于我无法对其进行测试,因此无法确定 4.3 或 4.4 中的行为是否发生了变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多