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

2 篇文章 0 订阅
1 篇文章 0 订阅

         在上一篇文章中,我写了如何在Linux下引用.so文件,那是为在Android下引用/system/lib下的系统库做热身。接下来我们看一下如何在Android环境下引用/system/lib下的.so文件(若您也对此有所了解,还望不吝赐教后面的问题,先谢!)。

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

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

package mars.com;
import android.app.Activity;
import android.os.Bundle;
public class AndroidJniTestActivity extends Activity {
    /** Called when the activity is first created. */
    @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  代码:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class mars_com_CallNative */
#ifndef _Included_mars_com_CallNative
#define _Included_mars_com_CallNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     mars_com_CallNative
 * Method:    readCmd
 * Signature: (Ljava/lang/String;)[B
 */
JNIEXPORT jbyteArray JNICALL Java_mars_com_CallNative_readCmd
  (JNIEnv *, jobject, jstring);
/*
 * Class:     mars_com_CallNative
 * Method:    writeCmd
 * Signature: ([BLjava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_mars_com_CallNative_writeCmd
  (JNIEnv *, jobject, jbyteArray, jstring);
#ifdef __cplusplus
}
#endif
#endif


 

 

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

第二,在工程目录下建立文件夹: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 ); //引用path指向的库:/system/lib/libril.so
 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);
    //RIL_REQUEST_GET_NEIGHBORING_CELL_IDS定义在include/telephony/ril.h中
    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是通信模块的一部分)?但如果是意外终止的话,模拟器中却一直是运行正常的,没有弹出意外终止的对话框。

        这个问题困扰了我很久,希望能得到高人指点,谢谢!

















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值