赞
踩
目录
创建Android.mk, Application.mk, touch.cpp这3个文件
1. 底层设备驱动已经实现ioctl相关操作接口
2. 本篇主要讲如何实现JNI层和应用层的ioctl相关内容
3. 这里是基于sda810开发板调试,其他arm开发板搭载安卓系统均可以调试
1.到官网下载android-ndk-r13b-windows-x86_64.zip(我用的是这个版本,最新版本)
2.解压缩后将目录添加到PATH中,我这里是d:\android-ndk-r13b\
3.测试如下图,表示配置成功
Note:这3个文件放在同一目录,我这里放在jni目录
1. Android.mk
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_LDLIBS :=-llog
- LOCAL_MODULE := touch
- LOCAL_SRC_FILES := touch.cpp
- include $(BUILD_SHARED_LIBRARY)
2. Application.mk
APP_ABI := all #编译所有平台
3. touch.cpp (文件名和Android.mk 的 MODULE匹配, JNI里面的语法知识不做介绍)
- #include<android/log.h>
- #include <jni.h>
- #include <fcntl.h>
-
- #define TAG "TOUCH-JNI" // 这个是自定义的LOG的标识
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
- #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
- #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
-
- #define IOCTL_GET_DRIVER_VERSION 0x80084300
- #define IOCTL_GET_DEVICE_TYPE 0x80084301
-
- extern "C"
- {
- jstring Java_com_morgen_touch_MainActivity_getStringFromJni(JNIEnv* jni, jobject obj) {
- return jni->NewStringUTF("Hello jni!");
- }
-
- jlong Java_com_morgen_touch_MainActivity_ioctl(JNIEnv* jni, jobject obj, jint code, jlong arg) {
- char path[30] = "/proc/icn85xx_tool";
- int fd = 0;
-
- LOGE("code:0x%x arg:0x%x", code, arg);
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- LOGE("Open file failed");
- return -1;
- }
-
- switch (code) {
- case IOCTL_GET_DRIVER_VERSION:
- case IOCTL_GET_DEVICE_TYPE:
- ioctl(fd, code, &arg);//注意这里是核心代码
- LOGE("arg:0x%x", arg);
- break;
- default:
- LOGE("CTLCODE was not right");
- }
-
- close(fd);
- LOGE("ioctl successfully");
- return arg;
- }
- }//extern "C"
4.到这里基本的jni层相关代码都配置OK了,接下来编译
a.打开命令窗口进入jni目录,输入ndk-build,
b.如下图,可以看到相关平台的so文件都已经编译成功
c.编译好了之后so文件在jni同级目录的libs目录下 (libtouch.so以生成)
d.到这里就为应用层app调用jni so库文件做好了准备
1.创建好的工程目录如下(怎么创建android demo工程这里就不赘述了,只需要创建一个空壳应用就好):
2.将ndk编译好的libs目录拷贝到touch工程中的main目录下,如上图
1.在app工程目录下的build.gradle文件中添加 ndk和sourceSets.main这两个代码段
- android {
- compileSdkVersion 30
- buildToolsVersion "30.0.3"
- defaultConfig {
- applicationId "com.morgen.touch"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- ndk { //1.添加ndk模块名
- moduleName "touch"
- }
- }
- sourceSets.main{ //2.添加jni lib目录
- jni.srcDirs=[]
- jniLibs.srcDir "src/main/libs"
- }
- }
3.然后在MainActivity中载入touch模块
4.然后在onCreate中调用
5.MainActivity完整代码如下(到这里,引用和调用都以完成):
- package com.morgen.touch;
-
- import android.os.Bundle;
- import com.google.android.material.bottomnavigation.BottomNavigationView;
- import androidx.appcompat.app.AppCompatActivity;
- import androidx.annotation.NonNull;
- import android.util.Log;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
-
- import java.io.File;
-
- public class MainActivity extends AppCompatActivity {
- private TextView mTextMessage;
- private Button mButton;
-
- static {
- System.loadLibrary("touch");
- }
- public native long ioctl(int a, long b);
-
- private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
- = new BottomNavigationView.OnNavigationItemSelectedListener() {
-
- @Override
- public boolean onNavigationItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.navigation_home:
- mTextMessage.setText(R.string.title_home);
- return true;
- case R.id.navigation_dashboard:
- mTextMessage.setText(R.string.title_dashboard);
- return true;
- case R.id.navigation_notifications:
- mTextMessage.setText(R.string.title_notifications);
- return true;
- }
- return false;
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- BottomNavigationView navView = findViewById(R.id.nav_view);
- mTextMessage = findViewById(R.id.message);
- navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
- mButton = findViewById(R.id.button);
-
- mButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- long arg = 0;
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084300, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084301, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084302, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084303, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084304, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0xc0084310, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0xc0084320, arg)));
- Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0xc0084321, arg)));
- }
- });
- }
- }
1.安装后的应用
2.点击按钮运行,同时抓取logcat log(如下图),这里可以看到app层和jni层的log都有打印出来,但是有没有被底层识别呢,接下来我们再看底层设备驱动的简单实现
- 130|root@msm8994:/ # logcat | grep TOUCH
- E/TOUCH-JNI(14217): code:0x80084300 arg:0x0
- E/TOUCH-JNI(14217): arg:0x10310
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x10310
- E/TOUCH-JNI(14217): code:0x80084301 arg:0x0
- E/TOUCH-JNI(14217): arg:0x991110
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x991110
- E/TOUCH-JNI(14217): code:0x80084302 arg:0x0
- E/TOUCH-JNI(14217): arg:0x212
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x212
- E/TOUCH-JNI(14217): code:0x80084303 arg:0x0
- E/TOUCH-JNI(14217): arg:0x61702cf
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x61702cf
- E/TOUCH-JNI(14217): code:0x80084304 arg:0x0
- E/TOUCH-JNI(14217): arg:0x120020
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x120020
- E/TOUCH-JNI(14217): code:0xc0084310 arg:0x0
- E/TOUCH-JNI(14217): arg:0x0
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x0
- E/TOUCH-JNI(14217): code:0xc0084320 arg:0x0
- E/TOUCH-JNI(14217): arg:0x0
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x0
- E/TOUCH-JNI(14217): code:0xc0084321 arg:0x0
- E/TOUCH-JNI(14217): arg:0x0
- E/TOUCH-JNI(14217): ioctl successfully
- E/TOUCH-APP(14217): 0x0
1.代码如下:
- static long tool_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- struct ts_data *data;
- struct device *dev;
-
- pr_info("ioctl, cmd=0x%08x, arg=0x%08lx", cmd, arg);
-
- data = file->private_data;
- if (data == NULL) {
- pr_err("IOCTL with private data = NULL");
- return -EFAULT;
- }
-
- switch (cmd) {
- case IOCTL_GET_DRIVER_VERSION:
- return put_user(CTS_DRIVER_VERSION_CODE,
- (unsigned int __user *)arg);
- case IOCTL_GET_DEVICE_TYPE:
- return put_user(dev->hwdata->hwid,
- (unsigned int __user *)arg);
- }
-
- return -ENOTSUPP;
- }
- static int tool_open(struct inode *inode, struct file *file)
- {
- file->private_data = PDE_DATA(inode);
- return 0;
- }
- static struct file_operations tool_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = tool_open,
- .unlocked_ioctl = tool_ioctl,
- };
2.这时候抓取kernel log如下(cat dev/kmsg):
这里可以看到应用层传下来的cmd,底层设备驱动已经接收到了,这就说明从app-jni-kernel的ioctl功能已经实现
- <I>Tool ioctl, cmd=0x80084300, arg=0x7fd4dc4508
- <I>Tool ioctl, cmd=0x80084301, arg=0x7fd4dc4508
- <I>Tool ioctl, cmd=0x80084302, arg=0x7fd4dc4508
- <I>Tool ioctl, cmd=0x80084303, arg=0x7fd4dc4508
- <I>Tool ioctl, cmd=0x80084304, arg=0x7fd4dc4508
======== 完 =========
到这里,从应用层到JNI层再到kernel层,功能实现OK,这就是上层应用来控制底层设备的大概逻辑。
以上,如有错误欢迎大家指出,共同进步,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。