我们看一下如何在Android环境下引用/system/lib下的.so文件(若您也对此有所了解,还望不吝赐教后面的问题,先谢!)。
为避免讲得混淆,先将我的代码的结构贴出来。
首先,新建Android工程:AndroidJniTest,在AndroidJniTestActivity.java中的代码如下:
- package mars.com;
- import android.app.Activity;
- import android.os.Bundle;
- public class AndroidJniTestActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- System.loadLibrary("test");
- CallNative callnative = new CallNative();
- byte[] cmd = {(byte)'\u004c'};
- int a = callnative.writeCmd(cmd, "/system/lib");
- }
- }
再在包mars.com下建立文件:CallNative.java 代码:
- package mars.com;
- public class CallNative {
- public native byte[] readCmd(String path);
- public native int writeCmd(byte[] cmd, String path);
- }
利用javah工具创建本地库文件的头文件mars_com_CallNative.h 代码:
-
- #include <jni.h>
-
- #ifndef _Included_mars_com_CallNative
- #define _Included_mars_com_CallNative
- #ifdef __cplusplus
- extern "C" {
- #endif
-
-
-
-
-
- JNIEXPORT jbyteArray JNICALL Java_mars_com_CallNative_readCmd
- (JNIEnv *, jobject, jstring);
-
-
-
-
-
- JNIEXPORT jint JNICALL Java_mars_com_CallNative_writeCmd
- (JNIEnv *, jobject, jbyteArray, jstring);
- #ifdef __cplusplus
- }
- #endif
- #endif
- <pre class="cpp" name="code"><pre>
至于如何生成此头文件,可自行学习,这里不多讲了
第二,在工程目录下建立文件夹:jni,将文件mars_com_CallNative.h 拷贝到此目录下,再在此目录下建立文件test.c,代码:
#include"mars_com_CallNative.h"
- #include<jni.h>
- #include<stdio.h>
- #include <string.h>
- #include <assert.h>
- #include <android/log.h>
- #include <dlfcn.h>
- #include<unistd.h>
- #include<sys/types.h>
- #include"include/telephony/ril.h"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "keymatch", __VA_ARGS__)
- JNIEXPORT jbyteArray JNICALL Java_mars_com_CallNative_readCmd(JNIEnv *evn, jobject obj, jstring jstr)
- {
- exit(0);
- }
- JNIEXPORT jint JNICALL Java_mars_com_CallNative_writeCmd(JNIEnv *evn, jobject jobj, jbyteArray jba, jstring jstr)
- {
- return 56;
- }
- jint JNI_OnLoad(JavaVM* vm, void* reserved) {
- LOGD("JNI ONLOAD success!");
- char *path = "/system/lib/libril.so";
- void* filehandle0 = dlopen(path, RTLD_LAZY|RTLD_GLOBAL );
- char *ll;
- int pid;
- if(filehandle0)
- {
- LOGD("open so success!");
- char*(*requesttostring)(int);
- if( 0 == pid)
- {
- sleep(1);
- requesttostring = (char *(*)(int))dlsym(filehandle0, "requestToString");
- pid = fork();
- if( requesttostring )
- {
- LOGD("call function requesttostring OK!");
- ll = requesttostring(RIL_REQUEST_GET_NEIGHBORING_CELL_IDS);
- LOGD("the value of requesttostring is %s", *ll);
- }
- else
- {
- LOGD("call function getinformation! ERROR!");
- }
- LOGD("ok");
- }
- else if(0 < pid)
- {
- LOGD("in the parent %s\n",getpid());
- }
- else LOGD("fork error");
- }
- }
将Android源码hardware/ril下的include文件夹也拷贝到jni文件夹下(因为在requesttostring(RIL_REQUEST_GET_NEIGHBORING_CELL_IDS)中使用的RIL_REQUEST_GET_NEIGHBORING_CELL_IDS在include文件夹下的ril.h中定义了)。 在jni文件夹下新建Android.mk文件,内容如下:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := test
- LOCAL_SRC_FILES := test.c
- LOCAL_LDLIBS := -llog
- LOCAL_CERTIFICATE := platform
- include $(BUILD_SHARED_LIBRARY)
第三,接下来就是编译的时候了。在cygwin下 $ndk/ndk-build
显示编译通过了,F5刷新工程,发现在工程目录下多了一下文件夹:libs,其中就包含了生成的文件:libtest.so
最后,运行。发现在Logcat下有这些信息:
。。。。。。
好了,问题来了。问题一、从绿色部分的内容来看,应该是成功引用了/system/lib/libril.so的,但为什么在上面只输出了
在test.c中,我用了fork创建了两个进程,而且在子进程中sleep(1),睡眠了一秒,按理说在这时应该运行父进程,也就是说应该运行如下部分代码
else if(0 < pid) { LOGD("in the parent %s\n",getpid()); }
Logcat : in the parent + pid ,但问题是在运行时没有输出,这是why??
问题二、在Logcat中可以看到,程序跑着跑着就死了
是怎么死的呢?会不会是因为在模拟器中无法进行通信(libril.so是通信模块的一部分)?但如果是意外终止的话,模拟器中却一直是运行正常的,没有弹出意外终止的对话框。
|