使用C++实现JNI接口需要注意的事项

 

Android NDK带的jni例子都是使用C定义JNI接口,但是在项目中,因为Native代码是用C++编写的,所以我就使用C++定义JNI接口。没有想到,问题来了,现将问题总结如下:

1、JNIEnv *env参数的使用

所有JNI接口的第一个参数是JNIEnv *env, 在C中,使用方法是

(*env)->NewStringUTF(env, "Hello from JNI!");

但在C++中,其调用方法是

env->NewStringUTF("Hello from JNI!");

为什么有这种区别呢,看看jni.h中关于JNIEnv的定义就可以知道了:

#if defined(__cplusplus)

typedef _JNIEnv JNIEnv;

#else

typedef const struct JNINativeInterface* JNIEnv;

#endif

可以看到,对于C和C++,定义有所不同,主要原因是C不支持类,所以采用了一种变通的方法。

2、接口找不到

在Java中调用JNI接口时,出现异常,察看日志,发现有如下错误:

WARN/dalvikvm(422): No implementation found for native Lcom/whty/wcity/HelixPlayer;.setDllPath (Ljava/lang/String;)V

检查了几遍代码,Cpp中确实定义了这个接口,而且仔细对照了Java的包名、类名,确实没有错误,那为什么会出现这种问题呢。后来突然想到,JNI接口都是以C的方式定义的,现在使用C++实现,函数定义前是否需要加上extern "C"呢?为此定义了一个头文件,在CPP文件中include该头文件,头文件加上如下代码片断:

#ifdef __cplusplus

extern "C" {

#endif

#endif

...

#ifdef __cplusplus

}

再次尝试,调用成功!

3. 因业务需求,在JNI C++代码中需要用到多线程,同时加入了互斥锁等机制,编译时出现如下问题:

/home/chenzhengyong/android/source/eclair/frameworks/base/include/utils/threads.h:214: undefined reference to `android::Mutex::lock()'

察看了一下ndk中的STABLE-APIS.TXT文档,上面有这样一句:

Note that the Android C library includes support for pthread (<pthread.h>),

so "LOCAL_LIBS := -lpthread" is not needed. The same is true for real-time

extensions (-lrt on typical Linux distributions).

也就是说使用多线程,并不需要增加-lpthread编译选项,看来解决问题还需要从源代码入手。察看frameworks/base/include/utils/threads.h文件,关于Mutex有如下代码片断:

#if defined(HAVE_PTHREADS)

inline Mutex::Mutex() {

    pthread_mutex_init(&mMutex, NULL);

}

inline Mutex::Mutex(const char* name) {

    pthread_mutex_init(&mMutex, NULL);

}

inline Mutex::Mutex(int type, const char* name) {

    if (type == SHARED) {

        pthread_mutexattr_t attr;

        pthread_mutexattr_init(&attr);

        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);

        pthread_mutex_init(&mMutex, &attr);

        pthread_mutexattr_destroy(&attr);

    } else {

        pthread_mutex_init(&mMutex, NULL);

    }

}

inline Mutex::~Mutex() {

    pthread_mutex_destroy(&mMutex);

}

inline status_t Mutex::lock() {

    return -pthread_mutex_lock(&mMutex);

}

inline void Mutex::unlock() {

    pthread_mutex_unlock(&mMutex);

}

inline status_t Mutex::tryLock() {

    return -pthread_mutex_trylock(&mMutex);

}

#endif // HAVE_PTHREADS

也就是说如果定义了HAVE_PTHREADS宏,就有Mutex的相关方法实现,如果没有定义这个宏,Mutex的方法又是如何实现的,下面看看frameworks/base/libs/utils/Threads.cpp中的代码:
#if defined(HAVE_PTHREADS)
// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
Mutex::Mutex()
{
      HANDLE hMutex;
      assert(sizeof(hMutex) == sizeof(mState));
      hMutex = CreateMutex(NULL, FALSE, NULL);
      mState = (void*) hMutex;
}
Mutex::Mutex(const char* name)
{
      // XXX: name not used for now
      HANDLE hMutex;
      assert(sizeof(hMutex) == sizeof(mState));
      hMutex = CreateMutex(NULL, FALSE, NULL);
      mState = (void*) hMutex;
}
Mutex::Mutex(int type, const char* name)
{
      // XXX: type and name not used for now
      HANDLE hMutex;
      assert(sizeof(hMutex) == sizeof(mState));
      hMutex = CreateMutex(NULL, FALSE, NULL);
      mState = (void*) hMutex;
}
Mutex::~Mutex()
{
      CloseHandle((HANDLE) mState);
}
status_t Mutex::lock()
{
      DWORD dwWaitResult;
      dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
      return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
}
void Mutex::unlock()
{
      if (!ReleaseMutex((HANDLE) mState))
          LOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n");
}
status_t Mutex::tryLock()
{
      DWORD dwWaitResult;
      dwWaitResult = WaitForSingleObject((HANDLE) mState, 0);
      if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT)
          LOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n");
      return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1;
}
#else
#error "Somebody forgot to implement threads for this platform."
#endif
也就是说,要么定义HAVE_PTHREADS宏,要么定义HAVE_WIN32_THREADS宏,否则,Mutex类的方法就没有实现代码。对于andorid来说,需要定义HAVE_PTHREADS宏。从上面的代码中还可以看出,android的线程实现实际上还是使用了 pthread库,只是在上面进行了一个封装。在Android.mk中增加下面一条语句,问题解决:
LOCAL_CXXFLAGS := -DHAVE_PTHREADS

4. jni函数名带下划线,结果出错,将函数名的下划线去掉,解决问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值