当前位置:首页 » 安卓系统 » androidjni调试

androidjni调试

发布时间: 2022-10-24 13:12:24

⑴ android studio 项目在添加jni后,调试很慢

一、前提条件

1、Android studio版本最好2.0以上,在1.5上试过各种问题

2、Ndk版本最好是android-ndk-r10d,ndk的路径要在项目根目录下的local.properties下指定,例如ndk.dir=F:\android-ndk-r10d

二、加入gradle-experimental插件

1、打开项目根目录下的build.gradle文件,加入

classpath "com.android.tools.build:gradle-experimental:0.7.0"

如下图:

2、默认使用的是com.android.application这个插件,如果要进行jni调试最好换掉这个插件,也就是使用之前加入的gradle-experimental插件,据说不换好像也行,但是没试过。下面贴出具体的配置:

[java]view plain

  • applyplugin:'com.android.model.application'

  • model{

  • android{

  • compileSdkVersion24

  • buildToolsVersion"24.0.2"

  • defaultConfig.with{

  • minSdkVersion.apiLevel=15

  • targetSdkVersion.apiLevel=24

  • applicationId"com.exampl.myapplication"

  • }

  • }

  • android.buildTypes{

  • release{

  • minifyEnabled=false

  • proguardFiles.add(file('proguard-rules.pro'))

  • }

  • }

  • android.ndk{

  • moleName="hello-jni"

  • ldLibs.addAll(["android","log"])

  • stl="gnustl_shared"

  • /*

  • *

  • *cppFlags.add("-fno-rtti")

  • *cppFlags.add("-fno-exceptions")

  • *ldLibs.addAll(["android","log"])

  • *stl="system"

  • */

  • }

  • android.proctFlavors{

  • create("arm"){

  • ndk.abiFilters.add("armeabi")

  • }

  • create("arm7"){

  • ndk.abiFilters.add("armeabi-v7a")

  • }

  • create("arm8"){

  • ndk.abiFilters.add("arm64-v8a")

  • }

  • create("x86"){

  • ndk.abiFilters.add("x86")

  • }

  • create("x86-64"){

  • ndk.abiFilters.add("x86_64")

  • }

  • create("mips"){

  • ndk.abiFilters.add("mips")

  • }

  • create("mips-64"){

  • ndk.abiFilters.add("mips64")

  • }

  • //Toincludeallcpuarchitectures,leavesabiFiltersempty

  • create("all")

  • }

  • }

  • dependencies{

  • compilefileTree(dir:'libs',include:['*.jar'])

  • testCompile'junit:junit:4.12'

  • compile'com.android.support:appcompat-v7:24.1.1'

  • compile'com.android.support:design:24.1.1'

  • }

⑵ 如何在android的jni线程中实现回调

jni回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。

其中一种在Android系统的解决方案是:

把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。

假设有c++函数:

[cpp] view plain
void *thread_entry(void *args)
{
while(1)
{
printf("thread running...\n");
sleep(1);
}

}

void init()
{
pthread_t thread;
pthread_create(&thread,NULL,thread_entry,(void *)NULL);
}

init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive:

[cpp] view plain
public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback:" + msg;
Log.d("Test", msg);
}

首先在c++中定义回调函数指针:

[cpp] view plain
//test.h
#include <pthread.h>
//function type for receiving data from native
typedef void (*ReceiveCallback)(unsigned char *buf, int len);

/** Callback for creating a thread that can call into the Java framework code.
* This must be used to create any threads that report events up to the framework.
*/
typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);

typedef struct{
ReceiveCallback recv_cb;
CreateThreadCallback create_thread_cb;
}Callback;

再修改c++中的init和thread_entry函数:

[cpp] view plain
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include "test.h"

void *thread_entry(void *args)
{
char *str = "i'm happy now";
Callback cb = NULL;
int len;
if(args != NULL){
cb = (Callback *)args;
}

len = strlen(str);
while(1)
{
printf("thread running...\n");
//invoke callback method to java
if(cb != NULL && cb->recv_cb != NULL){
cb->recv_cb((unsigned char*)str, len);
}
sleep(1);
}

}

void init(Callback *cb)
{
pthread_t thread;
//pthread_create(&thread,NULL,thread_entry,(void *)NULL);
if(cb != NULL && cb->create_thread_cb != NULL)
{
cb->create_thread_cb("thread",thread_entry,(void *)cb);
}
}

然后在jni中实现回调函数,以及其他实现:

[cpp] view plain
//jni_test.c
#include <stdlib.h>
#include <malloc.h>
#include <jni.h>
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"

#include "test.h"
#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"

using namespace android;

static jobject mCallbacksObj = NULL;
static jmethodID method_receive;

static void (JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}

static void receive_callback(unsigned char *buf, int len)
{
int i;
JNIEnv* env = AndroidRuntime::getJNIEnv();
jcharArray array = env->NewCharArray(len);
jchar *pArray ;

if(array == NULL){
LOGE("receive_callback: NewCharArray error.");
return;
}

pArray = (jchar*)calloc(len, sizeof(jchar));
if(pArray == NULL){
LOGE("receive_callback: calloc error.");
return;
}

// buffer to jchar array
for(i = 0; i < len; i++)
{
*(pArray + i) = *(buf + i);
}
// buffer to jcharArray
env->SetCharArrayRegion(array,0,len,pArray);
//invoke java callback method
env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
//release resource
env->DeleteLocalRef(array);
free(pArray);
pArray = NULL;

(env, __FUNCTION__);
}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}

static Callback mCallbacks = {
receive_callback,
create_thread_callback
};

static void jni_class_init_native
(JNIEnv* env, jclass clazz)
{
method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");
}

static int jni_init
(JNIEnv *env, jobject obj)
{

if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);

return init(&mCallbacks);
}

static const JNINativeMethod gMethods[] = {
{ "class_init_native", "()V", (void *)jni_class_init_native },
{ "native_init", "()I", (void *)jni_init },
};

static int registerMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
LOGE("Can't find class %s/n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)
{
LOGE("Failed registering methods for %s/n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
LOGI("Radio JNI_OnLoad");
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed/n");
goto fail;
}

if(env == NULL){
goto fail;
}
if (registerMethods(env) != 0) {
LOGE("ERROR: PlatformLibrary native registration failed/n");
goto fail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
fail:
return result;
}

jni的Android.mk文件中共享库设置为:

[cpp] view plain
LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最后再实现Java中的Test类:

[java] view plain
//com.tonny.Test.java

public class Test {

static{
try {
System.loadLibrary("test");
class_init_native();

} catch(UnsatisfiedLinkError ule){
System.err.println("WARNING: Could not load library libtest.so!");
}

}

public int initialize() {
return native_radio_init();
}

public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback" + msg;
Log.d("Test", msg);
}

protected static native void class_init_native();

protected native int native_init();

}

⑶ 如何调试android NDK 交叉编译的cpp文件

主要讲一下具体的步骤,具体的ndk指令我就不说了,贴的文章都有:
首先是写一个.java文件,本例中是HprofDumper.java
具体如下:

public class HprofDumper {

public native boolean hprofDumper(String filename, String outname);
}

然后用命令javac HprofDumper.java 生成.class文件
再用javah HprofDumper 生成相应的.h文件

生成的.h文件如下
#include

#ifndef _Included_HprofDumper
#define _Included_HprofDumper
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean JNICALL Java_HprofDumper_hprofDumper
(JNIEnv *, jobject, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif

然后只需要在对应的.cpp文件完成相应函数即可,核心代码如下:
#include "HprofDumper.h"
#include "hprof.h"

JNIEXPORT jboolean JNICALL Java_HprofDumper_hprofDumper
(JNIEnv *env, jobject obj, jstring in_file, jstring out_file)
{
const char *filename = env->GetStringUTFChars(in_file, 0);
const char *outname = env->GetStringUTFChars(out_file, 0);
return hprof_mp(filename, outname);
}
其中hprof_mp是纯c++代码,引入即可。
有一点需要注意,标红了已经,就是生成的.h文件函数并没具体形参名字,只有形参类型,在.cpp文件中要加入相应的形参名字,本例为env、 obj、 in_file和out_file。
还有一点c和c++的区别,就是env的使用。
本例中C++为env->GetStringUTFChars(in_file, 0);
如果是C就应该改为(env)->GetStringUTFChars(env,in_file, 0);
调用Java类型 : C中调用Java中的String类型为 jstring;

C语言方法名规则 : Java_完整包名类名_方法名(JNIEnv *env, jobject thiz), 注意完整的类名包名中包名的点要用 _ 代替;

参数介绍 : C语言方法中有两个重要的参数, JNIEnv *env, jobject thiz ;
-- JNIEnv参数 : 该参数代表Java环境, 通过这个环境可以调用Java中的方法;
-- jobject参数 : 该参数代表调用jni方法的类,;

调用jni.h中的NewStringUTF方法 : 该方法的作用是在C语言中创建一个Java语言中的String类型对象, jni.h中是这样定义的 jstring (*NewStringUTF)(JNIEnv*, const char*), JNIEnv 结构体中包含了 NewStringUTF 函数指针, 通过 JNIEnv 就可以调用这个方法;

完成代码编写后,在当前目录下完成Android.mk和Application.mk的编写
首先是Android.mk
本例中为:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hprof-mper
LOCAL_C_INCLUDES += external/stlport/stlport
LOCAL_C_INCLUDES += bionic
LOCAL_C_INCLUDES += bionic/libstdc++/include
LOCAL_SRC_FILES := HprofDumper.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xx.cpp \
xxx.cpp
LOCAL_SHARED_LIBRARIES := libstlport
include $(BUILD_SHARED_LIBRARY)
注意标红的是最关键的,LOCAL_C_INCLUDES 顾名思义是需要的头文件的所在的目录,那三个参数主要为了引入STL,最重要!!LOCAL_SHARED_LIBRARIES 我一直生成失败就是没加这个参数,不光要引入头文件,还要引入具体的lib,这就是这个字段的作用。
具体字段的作用:
-- LOCAL_PATH : 代表mk文件所在的目录;
-- include $(CLEAR_VARS) : 编译工具函数, 通过该函数可以进行一些初始化操作;
-- LOCAL_MODULE : 编译后的 .so 后缀文件叫什么名字;
-- LOCAL_SRC_FILES: 指定编译的源文件名称;
-- include $(BUILD_SHARED_LIBRARY) : 告诉编译器需要生成动态库;

Applicaion.mk中就一行
APP_STL = stlport_static
表示使用stl静态库。

注意:我用了STL,大家没有用STL的当然不用引入这些啦~

⑷ 如何在android的jni线程中实现回调

JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。

其中一种在Android系统的解决方案是:

把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。

假设有c++函数:

[cpp] view plain
void *thread_entry(void *args)
{
while(1)
{
printf("thread running...\n");
sleep(1);
}

}

void init()
{
pthread_t thread;
pthread_create(&thread,NULL,thread_entry,(void *)NULL);
}

init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive:

[cpp] view plain
public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback:" + msg;
Log.d("Test", msg);
}

首先在c++中定义回调函数指针:

[cpp] view plain
//test.h
#include <pthread.h>
//function type for receiving data from native
typedef void (*ReceiveCallback)(unsigned char *buf, int len);

/** Callback for creating a thread that can call into the Java framework code.
* This must be used to create any threads that report events up to the framework.
*/
typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);

typedef struct{
ReceiveCallback recv_cb;
CreateThreadCallback create_thread_cb;
}Callback;

再修改c++中的init和thread_entry函数:

[cpp] view plain
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include "test.h"

void *thread_entry(void *args)
{
char *str = "i'm happy now";
Callback cb = NULL;
int len;
if(args != NULL){
cb = (Callback *)args;
}

len = strlen(str);
while(1)
{
printf("thread running...\n");
//invoke callback method to java
if(cb != NULL && cb->recv_cb != NULL){
cb->recv_cb((unsigned char*)str, len);
}
sleep(1);
}

}

void init(Callback *cb)
{
pthread_t thread;
//pthread_create(&thread,NULL,thread_entry,(void *)NULL);
if(cb != NULL && cb->create_thread_cb != NULL)
{
cb->create_thread_cb("thread",thread_entry,(void *)cb);
}
}

然后在jni中实现回调函数,以及其他实现:

[cpp] view plain
//jni_test.c
#include <stdlib.h>
#include <malloc.h>
#include <jni.h>
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"

#include "test.h"
#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"

using namespace android;

static jobject mCallbacksObj = NULL;
static jmethodID method_receive;

static void (JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}

static void receive_callback(unsigned char *buf, int len)
{
int i;
JNIEnv* env = AndroidRuntime::getJNIEnv();
jcharArray array = env->NewCharArray(len);
jchar *pArray ;

if(array == NULL){
LOGE("receive_callback: NewCharArray error.");
return;
}

pArray = (jchar*)calloc(len, sizeof(jchar));
if(pArray == NULL){
LOGE("receive_callback: calloc error.");
return;
}

// buffer to jchar array
for(i = 0; i < len; i++)
{
*(pArray + i) = *(buf + i);
}
// buffer to jcharArray
env->SetCharArrayRegion(array,0,len,pArray);
//invoke java callback method
env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
//release resource
env->DeleteLocalRef(array);
free(pArray);
pArray = NULL;

(env, __FUNCTION__);
}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}

static Callback mCallbacks = {
receive_callback,
create_thread_callback
};

static void jni_class_init_native
(JNIEnv* env, jclass clazz)
{
method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");
}

static int jni_init
(JNIEnv *env, jobject obj)
{

if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);

return init(&mCallbacks);
}

static const JNINativeMethod gMethods[] = {
{ "class_init_native", "()V", (void *)jni_class_init_native },
{ "native_init", "()I", (void *)jni_init },
};

static int registerMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
LOGE("Can't find class %s/n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)
{
LOGE("Failed registering methods for %s/n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
LOGI("Radio JNI_OnLoad");
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed/n");
goto fail;
}

if(env == NULL){
goto fail;
}
if (registerMethods(env) != 0) {
LOGE("ERROR: PlatformLibrary native registration failed/n");
goto fail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
fail:
return result;
}

jni的Android.mk文件中共享库设置为:

[cpp] view plain
LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper

最后再实现Java中的Test类:

[java] view plain
//com.tonny.Test.java

public class Test {

static{
try {
System.loadLibrary("test");
class_init_native();

} catch(UnsatisfiedLinkError ule){
System.err.println("WARNING: Could not load library libtest.so!");
}

}

public int initialize() {
return native_radio_init();
}

public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback" + msg;
Log.d("Test", msg);
}

protected static native void class_init_native();

protected native int native_init();

}

⑸ 如何在Android下使用JNI

Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。
2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库
3.android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。

NDK编译步骤:
1.选择 ndk 自带的例子 hello-jni ,我的位于E:\android-ndk-r5\samples\hello-jni( 根据具体的安装位置而定 ) 。
2.运行 cygwin ,输入命令 cd /cygdrive/e/android-ndk-r5/samples/hello-jni ,进入到 E:\android-ndk-r5\samples\hello-jni 目录。
3.输入 $NDK/ndk-build ,执行成功后,它会自动生成一个 libs 目录,把编译生成的 .so 文件放在里面。 ($NDK是调用我们之前配置好的环境变量, ndk-build 是调用 ndk 的编译程序 )
4.此时去 hello-jni 的 libs 目录下看有没有生成的 .so 文件,如果有,ndk 就运行正常啦。

⑹ 如何在android的jni线程中实现回调

JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。 其中一种在Android系统的解决方案是: 把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。 假设有c++函数: [cpp] view plain void *thread_entry(void *args) { while(1) { printf("thread running...\n"); sleep(1); } } void init() { pthread_t thread; pthread_create(&thread,NULL,thread_entry,(void *)NULL); } init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive: [cpp] view plain public void Receive(char buffer[],int length){ String msg = new String(buffer); msg = "received from jni callback:" + msg; Log.d("Test", msg); } 首先在c++中定义回调函数指针: [cpp] view plain //test.h #include <pthread.h> //function type for receiving data from native typedef void (*ReceiveCallback)(unsigned char *buf, int len); /** Callback for creating a thread that can call into the Java framework code. * This must be used to create any threads that report events up to the framework. */ typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg); typedef struct{ ReceiveCallback recv_cb; CreateThreadCallback create_thread_cb; }Callback; 再修改c++中的init和thread_entry函数: [cpp] view plain //test.c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/wait.h> #include <unistd.h> #include "test.h" void *thread_entry(void *args) { char *str = "i'm happy now"; Callback cb = NULL; int len; if(args != NULL){ cb = (Callback *)args; } len = strlen(str); while(1) { printf("thread running...\n"); //invoke callback method to java if(cb != NULL && cb->recv_cb != NULL){ cb->recv_cb((unsigned char*)str, len); } sleep(1); } } void init(Callback *cb) { pthread_t thread; //pthread_create(&thread,NULL,thread_entry,(void *)NULL); if(cb != NULL && cb->create_thread_cb != NULL) { cb->create_thread_cb("thread",thread_entry,(void *)cb); } } 然后在jni中实现回调函数,以及其他实现: [cpp] view plain //jni_test.c #include <stdlib.h> #include <malloc.h> #include <jni.h> #include <JNIHelp.h> #include "android_runtime/AndroidRuntime.h" #include "test.h" #define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test" using namespace android; static jobject mCallbacksObj = NULL; static jmethodID method_receive; static void (JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); LOGE_EX(env); env->ExceptionClear(); } } static void receive_callback(unsigned char *buf, int len) { int i; JNIEnv* env = AndroidRuntime::getJNIEnv(); jcharArray array = env->NewCharArray(len); jchar *pArray ; if(array == NULL){ LOGE("receive_callback: NewCharArray error."); return; } pArray = (jchar*)calloc(len, sizeof(jchar)); if(pArray == NULL){ LOGE("receive_callback: calloc error."); return; } // buffer to jchar array for(i = 0; i < len; i++) { *(pArray + i) = *(buf + i); } // buffer to jcharArray env->SetCharArrayRegion(array,0,len,pArray); //invoke java callback method env->CallVoidMethod(mCallbacksObj, method_receive,array,len); //release resource env->DeleteLocalRef(array); free(pArray); pArray = NULL; (env, __FUNCTION__); } static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) { return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg); } static Callback mCallbacks = { receive_callback, create_thread_callback }; static void jni_class_init_native (JNIEnv* env, jclass clazz) { method_receive = env->GetMethodID(clazz, "Receive", "([CI)V"); } static int jni_init (JNIEnv *env, jobject obj) { if (!mCallbacksObj) mCallbacksObj = env->NewGlobalRef(obj); return init(&mCallbacks); } static const JNINativeMethod gMethods[] = { { "class_init_native", "()V", (void *)jni_class_init_native }, { "native_init", "()I", (void *)jni_init }, }; static int registerMethods(JNIEnv* env) { const char* const kClassName = RADIO_PROVIDER_CLASS_NAME; jclass clazz; /* look up the class */ clazz = env->FindClass(kClassName); if (clazz == NULL) { LOGE("Can't find class %s/n", kClassName); return -1; } /* register all the methods */ if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK) { LOGE("Failed registering methods for %s/n", kClassName); return -1; } /* fill out the rest of the ID cache */ return 0; } jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; LOGI("Radio JNI_OnLoad"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed/n"); goto fail; } if(env == NULL){ goto fail; } if (registerMethods(env) != 0) { LOGE("ERROR: PlatformLibrary native registration failed/n"); goto fail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; fail: return result; } jni的Android.mk文件中共享库设置为: [cpp] view plain LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper 最后再实现Java中的Test类: [java] view plain //com.tonny.Test.java public class Test { static{ try { System.loadLibrary("test"); class_init_native(); } catch(UnsatisfiedLinkError ule){ System.err.println("WARNING: Could not load library libtest.so!"); } } public int initialize() { return native_radio_init(); } public void Receive(char buffer[],int length){ String msg = new String(buffer); msg = "received from jni callback" + msg; Log.d("Test", msg); } protected static native void class_init_native(); protected native int native_init(); }

⑺ 如何在Android下使用JNI

关于如何在Android使用JNI调用C/C++代码库,网上已经有很多优秀的文章了,这里说一个大概过程吧:

首先需要懂C,其次要明白JNI的开发流程,然后还要知道NDK如何使用

1、在java代码中声明了一个native本地方法

Public native String helloFromc();

2、在项目目录中创建JNI文件夹

3、在JNI文件夹里面创建C文件,按照规范写代码

Jstring
Java_com_cheng_jnitest_MainActivity_helloFromc(JNIEnv* env,jobject obj)

4、用ndk-build指令编译
编译前需要配置Android.mk文件
//指定编译的文件夹,指定当前的目录
LOCAL_PATH := $(call my-dir)

//编译器在编译的时候会产生很多临时变量,中间变量最好在编译前清空所有的临时变量

include $(CLEAR_VARS)

//编译完成后的模块名
LOCAL_MOUDLE := hello
//编译的源文件

LOCAL_SRC_FILES:=hello.c

//编译一个动态库

//动态库.so 只包含运行的函数,不包含依赖,所以体积小,运行的时候回去系统寻找依赖

//静态库.a 包含所有的函数和运行的依赖,所以体积大,包含所有的api

include $(BUILD_SHARED_LIBRARY)

5、生成了一个so动态库,放到了libs里面

6、项目中引入依赖库

Static{

System.loadLibrary("hello");

}

⑻ Android-NDK:JNI本地文件中怎么调试打印输出到LOGCAT

加入头文件
#include <android/log.h>
函数__android_log_print(ANDROID_LOG_INFO,LOG_TAG,TITLE)
第一个参数ANDROID_LOG_INFO(还有ANDROID_LOG_ERROR等),表示什么类型
的输出,上面的函数相当于android的java代码的Log.i(LOG_TAG,TITLE),第二个参数就是logcat里的tag,第三个就是打印的内容。具体的请到log.h中自己查看。
Android之NDK开发
一、NDK产生的背景
Android平台从诞生起,就已经支持C、C++开发。众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Java语言。但这并不等同于“第三方应用只能使用Java”。在Android SDK首次发布时,Google就宣称其虚拟机Dalvik支持JNI编程方式,也就是第三方应用完全可以通过JNI调用自己的C动态库,即在Android平台上,“Java+C”的编程方式是一直都可以实现的。
不过,Google也表示,使用原生SDK编程相比Dalvik虚拟机也有一些劣势,Android SDK文档里,找不到任何JNI方面的帮助。即使第三方应用开发者使用JNI完成了自己的C动态链接库(so)开发,但是so如何和应用程序一起打包成apk并发布?这里面也存在技术障碍。比如程序更加复杂,兼容性难以保障,无法访问Framework API,Debug难度更大等。开发者需要自行斟酌使用。
于是NDK就应运而生了。NDK全称是Native Development Kit。
NDK的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。NDK将是Android平台支持C开发的开端。

二、为什么使用NDK
1.代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2.可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
3.提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
4.便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。

三、NDK简介
1.NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。
NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
2.NDK提供了一份稳定、功能有限的API头文件声明
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。

⑼ 如何使用android framework 中的串口jni

网络上搜索“串口调试助手”或者“串口调试精灵”,进行简单的安装。 点击运行串口调试助手,进入相应的界面。 设置串口通讯的接口,波特率校验位等相关信息。 在发送栏输入要发送的信息,选择手动发送或者自动发送,这时如果没有什么错误,对方的串口通信工具就会收到发送的内容。 设置接收区域的相关信息,这时对方如果发送信息,接收区就会收到相应的内容。 另外也可以进行文件的发送,但是串口通信的速率过慢,传输文件的话会很耗时,不过可以用来检测通信的正确性。

⑽ 如何实现在android studio中附加模式调试app

我在学习的过程中,亲历的这件事:项目组要做一个复杂的工程,分为sdk工程和demo工程,里面有java和jni层
而so和aar是sdk工程中生成的,拷贝到demo工程中编译成最终apk。
java层的调试,是简单的。可以在运行的时候用sdk工程的android studio附加app,如果直接用demo附加,sdk中的源码有些并不好显现,只能通过工程目录jar文件来查看。
而so层的附加,默认情况下是不可行的,因为jni层调试是启动型调试,我们来看下android studio处理各种调试行为的过程:

java层调试:
adb push 1.apk /data/local/tmp/1.apk
am start -D -n com.example.test/.MainActivity
android studio等待app状态正常
设置断点
执行remote connect,使用java调试协议附加

jni层调试:
adb push 1.apk /data/local/tmp/1.apk
am start -D -n com.example.test/.MainActivity
android studio等待app状态正常
adb push lldb_server
./lldb_server ..............建立Lldb调试服务器
lldbfrontend.exe ...........连接lldb调试服务器
向lldb_server发送附加调试命令
设置java/c层断点
执行remote connect,使用java调试协议附加

附加调试:
设置断点
执行remote connect,使用java调试协议附加

1.在研究过程中发现jni层在编译时生成2个so,带符号的是obj/local目录下的so,apk中编译好的的so是可以不带符号的,此时用gdb调试,吧文件设置为带符号的so,即可调试。继续研究发现带符号的so和无符号的so,前面字节完全相同。
2.android studio建立jni工程,需要自动安装lldb,修改gradle脚本,build.gradle
debug {
jniDebuggable true
}
3.android studio附加按钮只是采用Run/Debug Configuration中的Remote Configuaration

从上述过程可见,附加并不能触发jni层调试步骤,而jni层调试步骤又是写死的,必须把前面加载apk部分去掉,于是对android-ndk.jar做修改
最终实现了效果。其中一些重要的类:
IDevice:描述移动设备
Client:描述app包进程
AndroidNativeDebugProcess 控制jni调试,和lldb_server通信
AndroidNativeDeubgRunner 控制调试器部分
AndroidNativeRunConfiguration 配置Run/Debug Configuration中的Natvie-Debug选项,我在里面添加了用户app进程列表方便调试
配置界面控件
AndroidLLDBDebuggerContext jni层建立lldb调试器
AndroidLLDBDriver 实现基本调试功能

热点内容
学java有发展吗 发布:2025-01-31 21:44:45 浏览:566
HBX编程 发布:2025-01-31 21:39:26 浏览:158
数据库精品课 发布:2025-01-31 21:38:14 浏览:418
sqlsever语句 发布:2025-01-31 21:34:57 浏览:142
文泰里配置文件列表如何改 发布:2025-01-31 21:34:45 浏览:440
python的jieba分词 发布:2025-01-31 21:33:23 浏览:672
外企配置怎么说 发布:2025-01-31 21:31:11 浏览:270
搜索算法bd 发布:2025-01-31 21:29:34 浏览:538
安卓系统怎么安装文件 发布:2025-01-31 21:21:32 浏览:866
分布式缓存架构图 发布:2025-01-31 21:19:54 浏览:661