分享

Android下引用系统库的方法及问题

 昵称2485290 2012-03-22
我们看一下如何在Android环境下引用/system/lib下的.so文件(若您也对此有所了解,还望不吝赐教后面的问题,先谢!)。

为避免讲得混淆,先将我的代码的结构贴出来。

首先,新建Android工程:AndroidJniTest,在AndroidJniTestActivity.java中的代码如下:

  1. package mars.com;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. public class AndroidJniTestActivity extends Activity {
  5. /** Called when the activity is first created. */
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.main);
  10. System.loadLibrary("test");
  11. CallNative callnative = new CallNative();
  12. byte[] cmd = {(byte)'\u004c'};
  13. int a = callnative.writeCmd(cmd, "/system/lib");
  14. }
  15. }


再在包mars.com下建立文件:CallNative.java 代码:

  1. package mars.com;
  2. public class CallNative {
  3. public native byte[] readCmd(String path);
  4. public native int writeCmd(byte[] cmd, String path);
  5. }


利用javah工具创建本地库文件的头文件mars_com_CallNative.h 代码:

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class mars_com_CallNative */
  4. #ifndef _Included_mars_com_CallNative
  5. #define _Included_mars_com_CallNative
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10. * Class: mars_com_CallNative
  11. * Method: readCmd
  12. * Signature: (Ljava/lang/String;)[B
  13. */
  14. JNIEXPORT jbyteArray JNICALL Java_mars_com_CallNative_readCmd
  15. (JNIEnv *, jobject, jstring);
  16. /*
  17. * Class: mars_com_CallNative
  18. * Method: writeCmd
  19. * Signature: ([BLjava/lang/String;)I
  20. */
  21. JNIEXPORT jint JNICALL Java_mars_com_CallNative_writeCmd
  22. (JNIEnv *, jobject, jbyteArray, jstring);
  23. #ifdef __cplusplus
  24. }
  25. #endif
  26. #endif
  1. <pre>
  1. <pre class="cpp" name="code"><pre>

至于如何生成此头文件,可自行学习,这里不多讲了

第二,在工程目录下建立文件夹:jni,将文件mars_com_CallNative.h 拷贝到此目录下,再在此目录下建立文件test.c,代码:

#include"mars_com_CallNative.h"

  1. #include<jni.h>
  2. #include<stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <android/log.h>
  6. #include <dlfcn.h>
  7. #include<unistd.h>
  8. #include<sys/types.h>
  9. #include"include/telephony/ril.h"
  10. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "keymatch", __VA_ARGS__)
  11. JNIEXPORT jbyteArray JNICALL Java_mars_com_CallNative_readCmd(JNIEnv *evn, jobject obj, jstring jstr)
  12. {
  13. exit(0);
  14. }
  15. JNIEXPORT jint JNICALL Java_mars_com_CallNative_writeCmd(JNIEnv *evn, jobject jobj, jbyteArray jba, jstring jstr)
  16. {
  17. return 56;
  18. }
  19. jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  20. LOGD("JNI ONLOAD success!");
  21. char *path = "/system/lib/libril.so";
  22. void* filehandle0 = dlopen(path, RTLD_LAZY|RTLD_GLOBAL ); //引用path指向的库:/system/lib/libril.so
  23. char *ll;
  24. int pid;
  25. if(filehandle0)
  26. {
  27. LOGD("open so success!");
  28. char*(*requesttostring)(int);
  29. if( 0 == pid)
  30. {
  31. sleep(1);//子进程睡眠一秒
  32. requesttostring = (char *(*)(int))dlsym(filehandle0, "requestToString");
  33. pid = fork();
  34. if( requesttostring )
  35. {
  36. LOGD("call function requesttostring OK!");
  37. ll = requesttostring(RIL_REQUEST_GET_NEIGHBORING_CELL_IDS);
  38. //RIL_REQUEST_GET_NEIGHBORING_CELL_IDS定义在include/telephony/ril.h中
  39. LOGD("the value of requesttostring is %s", *ll);
  40. }
  41. else
  42. {
  43. LOGD("call function getinformation! ERROR!");
  44. }
  45. LOGD("ok");
  46. }
  47. else if(0 < pid)
  48. {
  49. LOGD("in the parent %s\n",getpid());
  50. }
  51. else LOGD("fork error");
  52. }
  53. }


将Android源码hardware/ril下的include文件夹也拷贝到jni文件夹下(因为在requesttostring(RIL_REQUEST_GET_NEIGHBORING_CELL_IDS)中使用的RIL_REQUEST_GET_NEIGHBORING_CELL_IDS在include文件夹下的ril.h中定义了)。
在jni文件夹下新建Android.mk文件,内容如下:

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE := test
  4. LOCAL_SRC_FILES := test.c
  5. LOCAL_LDLIBS := -llog
  6. LOCAL_CERTIFICATE := platform
  7. 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是通信模块的一部分)?但如果是意外终止的话,模拟器中却一直是运行正常的,没有弹出意外终止的对话框。 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多