1.app部分编写代码流程
jni : java native interface
java代码调用jni的方式:
1, 加载jni的动态库
static{
System.loadLibrary("led_jni"); // /system/lib/libled_jni.so
}
2, 声明本地native方法
public native int openDev();
public native int devOn();
public native int devOff();
public native int closeDev();
3, 直接调用native方法
mynative.openDev();
示例代码如下:
LedActive.java
package com.example.ducks;
import com.hq.lowlevel.LedNative;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.Toast;
import android.view.View;
import android.view.View.OnClickListener;
public class LedActivity extends Activity{
LedNative mynative;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_led);
initUI();
mynative = new LedNative();
mynative.openDev();
}
private void initUI() {
// TODO Auto-generated method stub
Button btn_on = (Button) findViewById(R.id.led1_off);
Button btn_off = (Button) findViewById(R.id.led1_on);
btn_on.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("LedActivity", "led on");
Toast.makeText(LedActivity.this, "狼来了,请闭眼", 3000).show();
mynative.devOn();
}
});
btn_off.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("LedActivity", "led off");
Toast.makeText(LedActivity.this, "天亮了,请睁眼", 3000).show();
mynative.devOff();
}
});
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mynative.closeDev();
}
}
led图形界面activity代码如下:
package com.example.keeprun;
import com.hq.lowlevel.LedNative;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class LedActivity extends Activity {
Button btn_on;
Button btn_off;
LedNative mynative;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_led);
initUI();
mynative = new LedNative();
//调用本地方法
mynative.openDev();
}
private void initUI() {
// TODO Auto-generated method stub
btn_on = (Button) findViewById(R.id.btn_on);
btn_off = (Button) findViewById(R.id.btn_off);
btn_on.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("LedActivity", "led on");
Toast.makeText(LedActivity.this, "灯亮了", 1000).show();
mynative.devOn();
}
});
btn_off.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("LedActivity", "led off");
Toast.makeText(LedActivity.this, "灯灭了", 1000).show();
mynative.devOff();
}
});
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mynative.closeDev();
}
}
至此,app调用jni静态库部分代码完成。
2.jni c++代码
基本代码框架思想流程:
Ubuntu去编写jni:
模板:
development/samples/SimpleJNI/jni/
编写工具:sourceinsight
只需要一个头文件:
dalvik\libnativehelper\include\nativehelper\jni.h
jni中的映射表:
typedef struct {
const char* name; //java的方法名
const char* signature; //方法的描述
void* fnPtr; //c/c++的函数名
} JNINativeMethod;
//构建一个映射表
JNINativeMethod led_methods[] = {
{"openDev", "()I", (void*)open_jni_led},
{"devOn", "()I", (void*)led_jni_on},
{"devOff", "()I", (void*)led_jni_off},
{"closeDev", "()I", (void*)close_jni_led},
};
// 实现一个函数--jni_onload(), 在函数中注册映射表
//返回值--正确返回JNI_VERSION_1_4, 出错返回负数
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
int ret;
//通过一个环境变量对象来注册, 环境变量对象能够提供各种函数: 数据转换,注册映射表,回调java方法
JNIEnv *env = NULL;
//初始化环境变量对象
ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4);
if(ret != JNI_OK)
{
LOGE("vm->GetEnv error");
return -1;
}
jclass clz = env->FindClass("com/hq/lowlevel/LedNative");
if(clz == NULL)
{
LOGE("env->FindClass error");
return -1;
}
//参数1--java本地方法对应的类
ret = env->RegisterNatives(clz, led_methods, ARRAY_SIZE(led_methods));
if(ret < 0)
{
LOGE("env->RegisterNatives error");
return -1;
}
return JNI_VERSION_1_4;
}
还需要编写 Android,mk(类似于Makefile)用于生成led_jni.so动态库。
jni示例代码如下:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#define LOG_TAG "led_jni_log"
#include <utils/Log.h>
#include "jni.h"
#define LED_NUM_ON _IOW('L',0x1122,int)
#define LED_NUM_OFF _IOW('L',0x3344,int)
#define LED_ALL_ON _IO('L',0x1234)
#define LED_ALL_OFF _IO('L',0x5678)
#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
static jint fd;
jint open_jni_led()
{
LOGD("--------%s----------", __FUNCTION__);
fd = open("/dev/led1",O_RDWR);
if(fd < 0)
{
LOGE("open : %s", strerror(errno));
return -1;
}
return 0;
}
jint led_jni_on()
{
LOGD("--------%s----------", __FUNCTION__);
int ret;
ret = ioctl(fd,LED_NUM_ON,1);
if(ret < 0)
{
LOGE("ioctl on : %s", strerror(errno));
return -1;
}
return 0;
}
jint led_jni_off()
{
LOGD("--------%s----------", __FUNCTION__);
int ret;
ret = ioctl(fd,LED_NUM_OFF,1);
if(ret < 0)
{
LOGE("ioctl off : %s", strerror(errno));
return -1;
}
return 0;
}
jint close_jni_led()
{
LOGD("--------%s----------", __FUNCTION__);
close(fd);
return 0;
}
//构建一个映射表
JNINativeMethod led_methods[] = {
{"openDev", "()I", (void*)open_jni_led},
{"devOn", "()I", (void*)led_jni_on},
{"devOff", "()I", (void*)led_jni_off},
{"closeDev", "()I", (void*)close_jni_led},
};
// 实现一个函数--jni_onload(), 在函数中注册映射表
//返回值--正确返回JNI_VERSION_1_4, 出错返回负数
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
int ret;
//通过一个环境变量对象来注册, 环境变量对象能够提供各种函数: 数据转换,注册映射表,回调java方法
JNIEnv *env = NULL;
//初始化环境变量对象
ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4);
if(ret != JNI_OK)
{
LOGE("vm->GetEnv error");
return -1;
}
jclass clz = env->FindClass("com/hq/lowlevel/LedNative");
if(clz == NULL)
{
LOGE("env->FindClass error");
return -1;
}
//参数1--java本地方法对应的类
ret = env->RegisterNatives(clz, led_methods, ARRAY_SIZE(led_methods));
if(ret < 0)
{
LOGE("env->RegisterNatives error");
return -1;
}
return JNI_VERSION_1_4;
}
Android.mk代码如下:
====================================================
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
#注意:目标文件的名字一定要java中加载的so的名字保持一致
LOCAL_MODULE:= libled_jni
LOCAL_SRC_FILES:= led_jni.cpp
#因为使用了LOGD()
LOCAL_SHARED_LIBRARIES := \
libcutils
#指定jni.h所在的路径
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
include $(BUILD_SHARED_LIBRARY)
============================================
运行Android.mk生成动态库.so文件
clover@ubuntn:~/Clover/android4.4$
clover@ubuntn:~/Clover/android4.4$ source build/envsetup.sh
including device/generic/x86/vendorsetup.sh
including device/generic/armv7-a-neon/vendorsetup.sh
including device/generic/mips/vendorsetup.sh
including device/samsung/manta/vendorsetup.sh
including device/softwinner/polaris-common/vendorsetup.sh
including device/softwinner/fspad-723/vendorsetup.sh
including device/asus/deb/vendorsetup.sh
including device/asus/tilapia/vendorsetup.sh
including device/asus/flo/vendorsetup.sh
including device/asus/grouper/vendorsetup.sh
including device/lge/mako/vendorsetup.sh
including device/lge/hammerhead/vendorsetup.sh
including sdk/bash_completion/adb.bash
clover@ubuntn:~/Clover/android4.4$
clover@ubuntn:~/Clover/android4.4$ lunch
You're building on Linux
Lunch menu... pick a combo:
1. aosp_arm-eng
2. aosp_x86-eng
3. aosp_mips-eng
4. vbox_x86-eng
5. mini_x86-userdebug
6. mini_armv7a_neon-userdebug
7. mini_mips-userdebug
8. aosp_manta-userdebug
9. fspad_723-eng
10. aosp_deb-userdebug
11. aosp_tilapia-userdebug
12. aosp_flo-userdebug
13. aosp_grouper-userdebug
14. aosp_mako-userdebug
15. aosp_hammerhead-userdebug
Which would you like? [aosp_arm-eng] 9 //选择对应平板产品
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.4.2
TARGET_PRODUCT=fspad_723
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=cortex-a7
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-32-generic-x86_64-with-Ubuntu-14.04-trusty
HOST_BUILD_TYPE=release
BUILD_ID=KVT49L
OUT_DIR=out
============================================
clover@ubuntn:~/Clover/android4.4$ mmm /home/clover/Desktop/led/led_jni //Android.mk和jni.cpp程序的路径
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.4.2
TARGET_PRODUCT=fspad_723
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=cortex-a7
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-32-generic-x86_64-with-Ubuntu-14.04-trusty
HOST_BUILD_TYPE=release
BUILD_ID=KVT49L
OUT_DIR=out
============================================
No private recovery resources for TARGET_DEVICE fspad-723
make: Entering directory `/home/clover/Clover/android4.4'
target thumb C++: libled_jni <= /home/clover/Desktop/led/led_jni/led_jni.cpp
target SharedLib: libled_jni (out/target/product/fspad-723/obj/SHARED_LIBRARIES/libled_jni_intermediates/LINKED/libled_jni.so)
target Symbolic: libled_jni (out/target/product/fspad-723/symbols/system/lib/libled_jni.so)
target Strip: libled_jni (out/target/product/fspad-723/obj/lib/libled_jni.so)
Install: out/target/product/fspad-723/system/lib/libled_jni.so
make: Leaving directory `/home/clover/Clover/android4.4'
clover@ubuntn:~/Clover/android4.4$
3.led驱动代码
参考上一篇文章
如果需要查看驱动的printk打印信息需要给予最高优先级
printk("<0>" “hello world! 0\n”);
详看
https://blog.csdn.net/shi18363123750/article/details/83346855
4.调试验证结果 (app点亮平板的led灯)
=================================
运行代码:
1, 安装apk:
2, libjni_led.so ==> /system/lib/
把jni动态库libjni_led.so通过adb push到arm板子上路径为/system/lib/

3, 驱动-》装载
如果驱动加载失败,查看对应的字符设备例如led,是否卸载响应的驱动。就可以正确加载。
uid=0 gid=1007@android:/ # insmod led_drv.ko
<kernel>call led_init()
major=203
#chmod 777 /dev/led1 //给文件所有权限,不然驱动,打不开字符设备
uid=0 gid=1007@android:/ # logcat
--------- beginning of /dev/log/main
D/AudioHardware( 2148): AudioHardware pcm playback is exiting standby.
D/AudioHardware( 2148): openPcmOut_l() mPcmOpenCnt: 0
E/AudioHardware( 2148): openPcmOut_l() cannot open pcm_out driver: cannot open device '/dev/snd/pcmC0D0p': No such file or directory
--------- beginning of /dev/log/system
I/ActivityManager( 2249): START {cmp=com.example.keeprun/.LedActivity} from pid 3009
D/led_jni_log( 3009): --------open_jni_led----------
E/led_jni_log( 3009): open : Permission denied //解决:chmod 777 /dev/led1
D/dalvikvm( 2249): GC_CONCURRENT freed 525K, 8% free 9313K/10055K, paused 2ms+30ms
I/WindowManager( 2249): WIN DEATH: Window{412ecb50 com.example.keeprun/com.example.keeprun.MainActivity paused=false}
I/ActivityManager( 2249): Process com.example.keeprun (pid 3009) has died.
W/ActivityManager( 2249): Force removing ActivityRecord{41333150 com.example.keeprun/.LedActivity}: app died, no saved state
I/WindowManager( 2249): WIN DEATH: Window{413c0eb0 Toast paused=false}
W/ActivityManager( 2249): Force removing ActivityRecord{412eb708 com.example.keeprun/.MainActivity}: app died, no saved state
D/Zygote ( 2146): Process 3009 exited cleanly (1)
binder: 2500:2500 transaction failed 29189, size 92-0
W/InputManagerService( 2249): Got RemoteException sending setActive(false) notification to pid 3009 uid 10054
binder: 2249:2263 transaction failed 29189, size 80-0
W/NotificationService( 2249): Object died trying to hide notification android.app.ITransientNotification$Stub$Proxy@412d0ce8 in package com.example.keeprun
W/ActivityManager( 2249): setProcessForeground called on unknown pid: 3009
uid=0 gid=1007@android:/ # logcat -c
uid=0 gid=1007@android:/ # logcat
--------- beginning of /dev/log/system
I/ActivityManager( 2249): START {cmp=com.example.keeprun/.LedActivity} from pid 3092
--------- beginning of /dev/log/main
D/dalvikvm( 3092): GC_CONCURRENT freed 135K, 4% free 7070K/7303K, paused 2ms+11ms
D/led_jni_log( 3092): --------open_jni_led----------
<kernel>45 call led_open
I/ActivityManager( 2249): Displayed com.example.keeprun/.LedActivity: +229ms
D/OpenGLRenderer( 3092): Flushing caches (mode 0)
I/LedActivity( 3092): led on
D/led_jni_log( 3092): --------led_jni_on----------
<kernel> call led_ioctl
LED_NUM_ON 1074027810
I/LedActivity( 3092): led off
D/led_jni_log( 3092): --------led_jni_off----------
<kernel> call led_ioctl
========================================
开机就装载驱动:
修改init.rc
283 insmod /led_drv.ko
284 chmod 777 /dev/led1
285 setprop vnc.srv.start 1
286 setprop service.adb.tcp.port 77888
287
288 on boot
289 # basic network init
本文详细介绍了如何在Linux环境下,通过app调用JNI接口来加载C++编写的JNI库,进而操作LED驱动以点亮LED灯。首先展示了app部分的图形界面activity代码,接着是JNI的C++实现,包括基本的代码框架和Android.mk文件。LED驱动的实现参考了作者之前的文章,并提示调试时需注意printk的日志级别。最终,经过调试验证,app成功点亮了平板上的LED灯。
3048

被折叠的 条评论
为什么被折叠?



