当前位置:   article > 正文

Android应用通过JNI调用ioctl操作设备驱动_android touch jni

android touch jni

目录

前提背景:

NDK环境搭建和Demo代码实现

环境搭建

下载NDK包和配置环境变量

代码实现

创建Android.mk, Application.mk, touch.cpp这3个文件

 应用层app demo实现

 使用android studio创建默认工程

 引用libtouch.so库文件

 编译运行安装touch应用

设备驱动程序ioctl实现关键代码


前提背景:

1. 底层设备驱动已经实现ioctl相关操作接口

2. 本篇主要讲如何实现JNI层和应用层的ioctl相关内容

3. 这里是基于sda810开发板调试,其他arm开发板搭载安卓系统均可以调试

NDK环境搭建和Demo代码实现

环境搭建

下载NDK包和配置环境变量

 1.到官网下载android-ndk-r13b-windows-x86_64.zip(我用的是这个版本,最新版本

 2.解压缩后将目录添加到PATH中,我这里是d:\android-ndk-r13b\

 3.测试如下图,表示配置成功

代码实现

创建Android.mk, Application.mk, touch.cpp这3个文件

Note:这3个文件放在同一目录,我这里放在jni目录

1. Android.mk

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_LDLIBS :=-llog
  4. LOCAL_MODULE := touch
  5. LOCAL_SRC_FILES := touch.cpp
  6. include $(BUILD_SHARED_LIBRARY)

2. Application.mk

APP_ABI := all #编译所有平台

3. touch.cpp (文件名和Android.mk 的 MODULE匹配, JNI里面的语法知识不做介绍)

  1. #include<android/log.h>
  2. #include <jni.h>
  3. #include <fcntl.h>
  4. #define TAG "TOUCH-JNI" // 这个是自定义的LOG的标识
  5. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
  6. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
  7. #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
  8. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
  9. #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
  10. #define IOCTL_GET_DRIVER_VERSION 0x80084300
  11. #define IOCTL_GET_DEVICE_TYPE 0x80084301
  12. extern "C"
  13. {
  14. jstring Java_com_morgen_touch_MainActivity_getStringFromJni(JNIEnv* jni, jobject obj) {
  15. return jni->NewStringUTF("Hello jni!");
  16. }
  17. jlong Java_com_morgen_touch_MainActivity_ioctl(JNIEnv* jni, jobject obj, jint code, jlong arg) {
  18. char path[30] = "/proc/icn85xx_tool";
  19. int fd = 0;
  20. LOGE("code:0x%x arg:0x%x", code, arg);
  21. fd = open(path, O_RDWR);
  22. if (fd < 0) {
  23. LOGE("Open file failed");
  24. return -1;
  25. }
  26. switch (code) {
  27. case IOCTL_GET_DRIVER_VERSION:
  28. case IOCTL_GET_DEVICE_TYPE:
  29. ioctl(fd, code, &arg);//注意这里是核心代码
  30. LOGE("arg:0x%x", arg);
  31. break;
  32. default:
  33. LOGE("CTLCODE was not right");
  34. }
  35. close(fd);
  36. LOGE("ioctl successfully");
  37. return arg;
  38. }
  39. }//extern "C"

4.到这里基本的jni层相关代码都配置OK了,接下来编译

        a.打开命令窗口进入jni目录,输入ndk-build,

        b.如下图,可以看到相关平台的so文件都已经编译成功

        c.编译好了之后so文件在jni同级目录的libs目录下  (libtouch.so以生成)

        d.到这里就为应用层app调用jni so库文件做好了准备

 应用层app demo实现

 使用android studio创建默认工程

 1.创建好的工程目录如下(怎么创建android demo工程这里就不赘述了,只需要创建一个空壳应用就好):

 2.将ndk编译好的libs目录拷贝到touch工程中的main目录下,如上图

 引用libtouch.so库文件

 1.在app工程目录下的build.gradle文件中添加 ndk和sourceSets.main这两个代码段

  1. android {
  2. compileSdkVersion 30
  3. buildToolsVersion "30.0.3"
  4. defaultConfig {
  5. applicationId "com.morgen.touch"
  6. minSdkVersion 15
  7. targetSdkVersion 30
  8. versionCode 1
  9. versionName "1.0"
  10. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  11. ndk { //1.添加ndk模块名
  12. moduleName "touch"
  13. }
  14. }
  15. sourceSets.main{ //2.添加jni lib目录
  16. jni.srcDirs=[]
  17. jniLibs.srcDir "src/main/libs"
  18. }
  19. }

 3.然后在MainActivity中载入touch模块

 4.然后在onCreate中调用

 5.MainActivity完整代码如下(到这里,引用和调用都以完成):

  1. package com.morgen.touch;
  2. import android.os.Bundle;
  3. import com.google.android.material.bottomnavigation.BottomNavigationView;
  4. import androidx.appcompat.app.AppCompatActivity;
  5. import androidx.annotation.NonNull;
  6. import android.util.Log;
  7. import android.view.MenuItem;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.TextView;
  11. import java.io.File;
  12. public class MainActivity extends AppCompatActivity {
  13. private TextView mTextMessage;
  14. private Button mButton;
  15. static {
  16. System.loadLibrary("touch");
  17. }
  18. public native long ioctl(int a, long b);
  19. private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
  20. = new BottomNavigationView.OnNavigationItemSelectedListener() {
  21. @Override
  22. public boolean onNavigationItemSelected(@NonNull MenuItem item) {
  23. switch (item.getItemId()) {
  24. case R.id.navigation_home:
  25. mTextMessage.setText(R.string.title_home);
  26. return true;
  27. case R.id.navigation_dashboard:
  28. mTextMessage.setText(R.string.title_dashboard);
  29. return true;
  30. case R.id.navigation_notifications:
  31. mTextMessage.setText(R.string.title_notifications);
  32. return true;
  33. }
  34. return false;
  35. }
  36. };
  37. @Override
  38. protected void onCreate(Bundle savedInstanceState) {
  39. super.onCreate(savedInstanceState);
  40. setContentView(R.layout.activity_main);
  41. BottomNavigationView navView = findViewById(R.id.nav_view);
  42. mTextMessage = findViewById(R.id.message);
  43. navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
  44. mButton = findViewById(R.id.button);
  45. mButton.setOnClickListener(new View.OnClickListener() {
  46. @Override
  47. public void onClick(View v) {
  48. long arg = 0;
  49. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084300, arg)));
  50. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084301, arg)));
  51. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084302, arg)));
  52. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084303, arg)));
  53. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0x80084304, arg)));
  54. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0xc0084310, arg)));
  55. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0xc0084320, arg)));
  56. Log.e("TOUCH-APP", "0x" + Long.toHexString(ioctl(0xc0084321, arg)));
  57. }
  58. });
  59. }
  60. }

 编译运行安装touch应用

  1.安装后的应用

  2.点击按钮运行,同时抓取logcat log(如下图),这里可以看到app层和jni层的log都有打印出来,但是有没有被底层识别呢,接下来我们再看底层设备驱动的简单实现

  1. 130|root@msm8994:/ # logcat | grep TOUCH
  2. E/TOUCH-JNI(14217): code:0x80084300 arg:0x0
  3. E/TOUCH-JNI(14217): arg:0x10310
  4. E/TOUCH-JNI(14217): ioctl successfully
  5. E/TOUCH-APP(14217): 0x10310
  6. E/TOUCH-JNI(14217): code:0x80084301 arg:0x0
  7. E/TOUCH-JNI(14217): arg:0x991110
  8. E/TOUCH-JNI(14217): ioctl successfully
  9. E/TOUCH-APP(14217): 0x991110
  10. E/TOUCH-JNI(14217): code:0x80084302 arg:0x0
  11. E/TOUCH-JNI(14217): arg:0x212
  12. E/TOUCH-JNI(14217): ioctl successfully
  13. E/TOUCH-APP(14217): 0x212
  14. E/TOUCH-JNI(14217): code:0x80084303 arg:0x0
  15. E/TOUCH-JNI(14217): arg:0x61702cf
  16. E/TOUCH-JNI(14217): ioctl successfully
  17. E/TOUCH-APP(14217): 0x61702cf
  18. E/TOUCH-JNI(14217): code:0x80084304 arg:0x0
  19. E/TOUCH-JNI(14217): arg:0x120020
  20. E/TOUCH-JNI(14217): ioctl successfully
  21. E/TOUCH-APP(14217): 0x120020
  22. E/TOUCH-JNI(14217): code:0xc0084310 arg:0x0
  23. E/TOUCH-JNI(14217): arg:0x0
  24. E/TOUCH-JNI(14217): ioctl successfully
  25. E/TOUCH-APP(14217): 0x0
  26. E/TOUCH-JNI(14217): code:0xc0084320 arg:0x0
  27. E/TOUCH-JNI(14217): arg:0x0
  28. E/TOUCH-JNI(14217): ioctl successfully
  29. E/TOUCH-APP(14217): 0x0
  30. E/TOUCH-JNI(14217): code:0xc0084321 arg:0x0
  31. E/TOUCH-JNI(14217): arg:0x0
  32. E/TOUCH-JNI(14217): ioctl successfully
  33. E/TOUCH-APP(14217): 0x0

       

设备驱动程序ioctl实现关键代码

1.代码如下:

  1. static long tool_ioctl(struct file *file, unsigned int cmd,
  2. unsigned long arg)
  3. {
  4. struct ts_data *data;
  5. struct device *dev;
  6. pr_info("ioctl, cmd=0x%08x, arg=0x%08lx", cmd, arg);
  7. data = file->private_data;
  8. if (data == NULL) {
  9. pr_err("IOCTL with private data = NULL");
  10. return -EFAULT;
  11. }
  12. switch (cmd) {
  13. case IOCTL_GET_DRIVER_VERSION:
  14. return put_user(CTS_DRIVER_VERSION_CODE,
  15. (unsigned int __user *)arg);
  16. case IOCTL_GET_DEVICE_TYPE:
  17. return put_user(dev->hwdata->hwid,
  18. (unsigned int __user *)arg);
  19. }
  20. return -ENOTSUPP;
  21. }
  22. static int tool_open(struct inode *inode, struct file *file)
  23. {
  24. file->private_data = PDE_DATA(inode);
  25. return 0;
  26. }
  27. static struct file_operations tool_fops = {
  28. .owner = THIS_MODULE,
  29. .llseek = no_llseek,
  30. .open = tool_open,
  31. .unlocked_ioctl = tool_ioctl,
  32. };

 2.这时候抓取kernel log如下(cat dev/kmsg):

  这里可以看到应用层传下来的cmd,底层设备驱动已经接收到了,这就说明从app-jni-kernel的ioctl功能已经实现

  1. <I>Tool ioctl, cmd=0x80084300, arg=0x7fd4dc4508
  2. <I>Tool ioctl, cmd=0x80084301, arg=0x7fd4dc4508
  3. <I>Tool ioctl, cmd=0x80084302, arg=0x7fd4dc4508
  4. <I>Tool ioctl, cmd=0x80084303, arg=0x7fd4dc4508
  5. <I>Tool ioctl, cmd=0x80084304, arg=0x7fd4dc4508

======== 完 =========

到这里,从应用层到JNI层再到kernel层,功能实现OK,这就是上层应用来控制底层设备的大概逻辑。

以上,如有错误欢迎大家指出,共同进步,谢谢!

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/236290
推荐阅读
相关标签
  

闽ICP备14008679号

        
cppcmd=keepalive&