Android App层通过JNI从驱动获取Input Event

本博客介绍了一种不通过Android Input Framework直接读取电磁笔触屏事件的方法,详细解析了JNI层和App层的实现过程。

1 概述

 

尝试在App层直接读取驱动的Input Event,获取触屏事件(本文获取的是电磁笔触屏事件),而不通过AndroidInput Framework.

 

 

2 架构



3 实现

3.1 JNI

共有以下几个文件:

 

3.1.1 input_pen.h

 

首先看input_pen.h

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifndef _INPUT_PEN_H  
  2. #define _INPUT_PEN_H  
  3.    
  4.    
  5. #include <pthread.h>  
  6. #include <linux/input.h>  
  7. #include <sys/types.h>  
  8. #include <linux/types.h>  
  9.    
  10. #ifdef _cplusplus  
  11. extern "C" {  
  12. #endif  
  13.    
  14. //获取input_event数据的方法指针,由App层提供  
  15.     typedef void (*get_event_callback)(__u16 type, __u16 code, __s32 value );  
  16.    
  17. //创建线程的函数指针,通过Java虚拟机创建  
  18.     typedef pthread_t (*create_thread_callback)(const char* name, void (*start)(void *), void* arg);  
  19.    
  20. //释放线程资源的函数指针  
  21.     typedef int (*detach_thread_callback)(void);  
  22.    
  23. //回调函数结构体  
  24.     typedef struct {  
  25.         get_event_callback get_event_cb;  
  26.         create_thread_callback create_thread_cb;  
  27.         detach_thread_callback detach_thread_cb;  
  28.     } input_callback;  
  29.    
  30.     /*******************************************************************/  
  31. //public methods  
  32.    
  33. //初始化函数  
  34.     unsigned char input_pen_init(input_callback *callback);  
  35.    
  36. //退出函数  
  37.     void input_pen_exit();  
  38.    
  39.    
  40. /*******************************************************************/  
  41.    
  42.    
  43. #ifdef _cplusplus  
  44. }  
  45. #endif  
  46.    
  47. #endif  
  48.    
  49.    

 

3.1.2 input_pen.cpp

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <pthread.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <errno.h>  
  5. #include <string.h>  
  6. #include <unistd.h>  
  7. #include <fcntl.h>  
  8. #include <sys/types.h>  
  9. #include <sys/epoll.h>  
  10. #include <sys/wait.h>  
  11. #include <sys/un.h>  
  12. #include <stddef.h>  
  13. #include <linux/input.h>  
  14.    
  15. #include "input_pen.h"  
  16. #include "debug.h"  
  17.    
  18.    
  19.    
  20. //驱动路径  
  21. #define DEV_PATH "/dev/input/event1"  
  22.    
  23. //最大侦听  
  24. #define MAX_EVENTS 1  
  25.    
  26. //epoll_wait的最大时间  
  27. #define EPOLL_SLEEP 200  
  28.    
  29. //线程是否由pthread创建,否则由JVM创建  
  30. #define USING_PTHREAD 0  
  31.    
  32.    
  33. #if USING_PTHREAD  
  34. #define LOGD(fmt, arg...) do{printf(fmt"\n", ##arg);}while(0)  
  35. #define LOGE LOGD  
  36. #endif  
  37.    
  38. /**************************************************************************************/  
  39.    
  40. //static variable  
  41.    
  42. //当前驱动文件指针  
  43. static int fd = 0;  
  44. //epoll文件指针  
  45. static int epoll_fd = 0;  
  46. //epoll_event数组  
  47. static struct epoll_event events[MAX_EVENTS];  
  48. //回调函数  
  49. static input_callback *callbacks = NULL;  
  50.    
  51. //标记线程是否已启动  
  52. static unsigned char start_flag = 0;  
  53. //标记线程是否已退出  
  54. static unsigned char exit_flag = 0;  
  55. //线程锁  
  56. static pthread_mutex_t exit_mutex;  
  57.    
  58. /**************************************************************************************/  
  59.    
  60.    
  61. //set non-blocking for fd  
  62. static int set_non_blocking(int fd) {  
  63.     int opts;  
  64.    
  65.     opts = fcntl(fd, F_GETFL);  
  66.     if (opts < 0) {  
  67.         LOGE("fcntl F_GETFL error: %s", strerror(errno));  
  68.         return -1;  
  69.     }  
  70.     opts = (opts | O_NONBLOCK);  
  71.     if (fcntl(fd, F_SETFL, opts) < 0) {  
  72.         LOGE("fcntl F_SETFL error: %s", strerror(errno));  
  73.         return -1;  
  74.     }  
  75.    
  76.     return 0;  
  77. }  
  78.    
  79. //register epoll events for fd  
  80. static void epoll_register( int  epoll_fd, int  fd ) {  
  81.     struct epoll_event  ev;  
  82.     int         ret;  
  83.    
  84.     ev.events  = EPOLLIN;//interested in receiving data  
  85.     ev.data.fd = fd;  
  86.    
  87.     do {  
  88.         //register events for fd  
  89.         ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );  
  90.     } while (ret < 0 && errno == EINTR);  
  91.    
  92. }  
  93.    
  94.    
  95.    
  96. //remove epoll events for fd  
  97. static void epoll_unregister( int  epoll_fd, int  fd ) {  
  98.     int  ret;  
  99.     do {  
  100.         ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );  
  101.     } while (ret < 0 && errno == EINTR);  
  102.    
  103. }  
  104.    
  105.    
  106. //通知退出线程,由其他线程调用  
  107. static void thread_cancel() {  
  108.     LOGD("thread_cancel");  
  109.     pthread_mutex_lock(&exit_mutex);  
  110.    
  111.     exit_flag = 1;  
  112.    
  113.     pthread_mutex_unlock(&exit_mutex);  
  114. }  
  115.    
  116. //停止线程,由本线程调用  
  117. static void thread_exit() {  
  118.     unsigned char flag ;  
  119.    
  120.    
  121.     pthread_mutex_lock(&exit_mutex);  
  122.    
  123.     flag = exit_flag;  
  124.    
  125.     pthread_mutex_unlock(&exit_mutex);  
  126.    
  127.     if (flag == 1) {  
  128.         LOGD("thread_exit");  
  129.         //close devices  
  130.         close(fd);  
  131.    
  132.         //clean variablies  
  133.         fd = 0;  
  134.         epoll_fd = 0;  
  135.         start_flag = 0;  
  136.         exit_flag = 0;  
  137.         //release thread resources  
  138.         if (callbacks != NULL && callbacks->detach_thread_cb != NULL) {  
  139.             callbacks->detach_thread_cb();  
  140.             LOGD("callbacks->detach_thread_cb();\n");  
  141.         }  
  142.    
  143.         //exit current thread  
  144.         pthread_exit(NULL);  
  145.    
  146.    
  147.     }  
  148. }  
  149.    
  150.    
  151. //线程运行函数  
  152. #if USING_PTHREAD  
  153. static void *run(void *args) {  
  154. #else  
  155. static void run(void *args) {  
  156.    
  157. #endif  
  158.     int n = 0;  
  159.     int i = 0;  
  160.     int res;  
  161.     struct input_event event;  
  162.    
  163.     LOGD("run...");  
  164.     while (1) {  
  165.    
  166.         thread_exit();//每次检测是否要退出运行  
  167.    
  168.    
  169.         n = epoll_wait(epoll_fd, events, MAX_EVENTS, EPOLL_SLEEP);//检测是否有事件发生  
  170.         if (n == -1) {  
  171.             LOGE("epoll_wait error:%s", strerror(errno));  
  172.             continue;  
  173.         }  
  174.    
  175.         for (i = 0; i < n; i++) {  
  176.             if (events[i].data.fd == fd) { //有读事件发生  
  177.                 res = read(fd, &event, sizeof(event));  
  178.                 if (res < (int)sizeof(event)) {  
  179.                     LOGE("could not get event\n");  
  180.                     continue;  
  181.                 }  
  182.    
  183. #if (!USING_PTHREAD)  
  184.                 //把input_event的数据回调到java层  
  185.                 if (callbacks != NULL && callbacks->get_event_cb != NULL) {  
  186.                     callbacks->get_event_cb(event.type, event.code, event.value);  
  187.                 }  
  188. #else  
  189.                 //printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);  
  190.                 if (event.type == EV_ABS) {  
  191.                     printf("%04x %04x %08x\n", event.type, event.code, event.value);  
  192.                 }  
  193. #endif  
  194.             }  
  195.         }  
  196.     }  
  197. #if USING_PTHREAD  
  198.     return NULL;  
  199. #else  
  200.     return ;  
  201. #endif  
  202.    
  203. }  
  204.    
  205.    
  206. //初始化函数  
  207. unsigned char input_pen_init(input_callback *cb) {  
  208.    
  209.     pthread_t thread;  
  210.    
  211.     LOGD("input_pen_init");  
  212.     if (start_flag) {  
  213.         return 1;  
  214.     }  
  215.    
  216.     //callbacks  
  217.     callbacks = cb;  
  218.    
  219.     //open device  
  220.     fd = open(DEV_PATH, O_RDWR);  
  221.     if (fd < 0) {  
  222.         LOGE("open device failed!\n");  
  223.         return 0;  
  224.     }  
  225.    
  226.     //create epoll  
  227.     epoll_fd = epoll_create(MAX_EVENTS);  
  228.     if (epoll_fd == -1) {  
  229.         LOGE("epoll_create failed!\n");  
  230.         return 0;  
  231.     }  
  232.     //set non-blocking  
  233.     set_non_blocking(fd);  
  234.    
  235.     //epoll register  
  236.     epoll_register(epoll_fd, fd);  
  237.    
  238.     //mutex  
  239.     if (pthread_mutex_init(&exit_mutex, NULL) != 0) {  
  240.         LOGE("pthread_mutex_initn failed!");  
  241.         return 0;  
  242.     }  
  243.    
  244.     //create thread  
  245. #if USING_PTHREAD  
  246.     if (pthread_create(&thread, NULL, run, (void *)NULL) != 0) {  
  247.         LOGE("pthread_create failed!\n");  
  248.         return 0;  
  249.     }  
  250. #else  
  251.     if (callbacks != NULL && callbacks->create_thread_cb != NULL) {  
  252.         thread = callbacks->create_thread_cb("input_pen_thread", run, NULL);  
  253.         if (thread == 0) {  
  254.             LOGE("create thread failed!\n");  
  255.             return 0;  
  256.         }  
  257.    
  258.         start_flag = 1;  
  259.         LOGD("input_pen_init success!");  
  260.         return 1;  
  261.    
  262.     }  
  263. #endif  
  264.    
  265.    
  266.    
  267.     return 0;  
  268.    
  269. }  
  270.    
  271. //退出函数  
  272. void input_pen_exit() {  
  273.     thread_cancel();  
  274. }  
  275.    
  276. #if USING_PTHREAD  
  277. int main() {  
  278.     int count = 0;  
  279.     input_pen_init(NULL);  
  280.    
  281.     while (1) {  
  282.         sleep(1);  
  283.         count ++;  
  284.         if (count == 20) {  
  285.             thread_cancel();  
  286.             sleep(1);  
  287.             break;  
  288.         }  
  289.     }  
  290.     return 0;  
  291. }  
  292. #endif  
  293.    
  294.    
  295.    
  296.    

以上的关键流程为:

 

1、open驱动文件,初始化epoll,创建线程。

2、在线程中通过epoll_wait检测事件,有事件发生则通过read函数读取驱动的input_event数据,并通过get_event_cb回调到Jav层。

 

3.1.3 com_jiagutech_input_InputPen.cpp

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdlib.h>  
  2. #include <malloc.h>  
  3. #include <jni.h>  
  4. #include <JNIHelp.h>  
  5. #include <utils/Log.h>  
  6. #include "android_runtime/AndroidRuntime.h"  
  7.    
  8. #include "input_pen.h"  
  9. #include "debug.h"  
  10.    
  11. //Java类名  
  12. #define CLASS_NAME "com/jiagutech/input/InputPen"  
  13.    
  14. using namespace android;  
  15.    
  16.    
  17. static jobject mCallbacksObj = NULL;  
  18. static jmethodID method_get_event;  
  19.    
  20.    
  21. static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {  
  22.     if (env->ExceptionCheck()) {  
  23.         LOGE("An exception was thrown by callback '%s'.", methodName);  
  24.         LOGE_EX(env);  
  25.         env->ExceptionClear();  
  26.     }  
  27. }  
  28.    
  29. //获得input_event数据的回调函数  
  30. static void GetEventCallback(__u16 type, __u16 code, __s32 value) {  
  31.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  32.     //invoke java callback method  
  33.     env->CallVoidMethod(mCallbacksObj, method_get_event, type, code, value);  
  34.    
  35.     checkAndClearExceptionFromCallback(env, __FUNCTION__);  
  36. }  
  37.    
  38. //创建线程的回调函数  
  39. static pthread_t CreateThreadCallback(const char* name, void (*start)(void *), void* arg) {  
  40.     return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);  
  41. }  
  42.    
  43. //释放线程资源的回调函数  
  44. static int DetachThreadCallback(void) {  
  45.     JavaVM* vm;  
  46.     jint result;  
  47.    
  48.     vm = AndroidRuntime::getJavaVM();  
  49.     if (vm == NULL) {  
  50.         LOGE("detach_thread_callback :getJavaVM failed\n");  
  51.         return -1;  
  52.     }  
  53.    
  54.     result = vm->DetachCurrentThread();  
  55.     if (result != JNI_OK)  
  56.         LOGE("ERROR: thread detach failed\n");  
  57.     return result;  
  58. }  
  59.    
  60.    
  61. //回调函数结构体变量  
  62. static input_callback mCallbacks = {  
  63.     GetEventCallback,  
  64.     CreateThreadCallback,  
  65.     DetachThreadCallback,  
  66. };  
  67.    
  68. //初始化Java的回调函数  
  69. static void jni_class_init_native  
  70. (JNIEnv* env, jclass clazz) {  
  71.     LOGD("jni_class_init_native");  
  72.    
  73.     method_get_event = env->GetMethodID(clazz, "getEvent""(III)V");  
  74.    
  75.    
  76. }  
  77.    
  78. //初始化  
  79. static jboolean jni_input_pen_init  
  80. (JNIEnv *env, jobject obj) {  
  81.     LOGD("jni_input_pen_init");  
  82.    
  83.     if (!mCallbacksObj)  
  84.         mCallbacksObj = env->NewGlobalRef(obj);  
  85.    
  86.     return  input_pen_init(&mCallbacks);  
  87. }  
  88.    
  89.    
  90. //退出  
  91. static void jni_input_pen_exit  
  92. (JNIEnv *env, jobject obj) {  
  93.     LOGD("jni_input_pen_exit");  
  94.     input_pen_exit();  
  95. }  
  96.    
  97. static const JNINativeMethod gMethods[] = {  
  98.     { "class_init_native","()V", (void *)jni_class_init_native },  
  99.     { "native_input_pen_init","()Z", (void *)jni_input_pen_init },  
  100.     { "native_input_pen_exit","()V", (void *)jni_input_pen_exit },  
  101. };  
  102.    
  103.    
  104.    
  105. static int registerMethods(JNIEnv* env) {  
  106.    
  107.    
  108.     const charconst kClassName = CLASS_NAME;  
  109.     jclass clazz;  
  110.     /* look up the class */  
  111.     clazz = env->FindClass(kClassName);  
  112.     if (clazz == NULL) {  
  113.         LOGE("Can't find class %s/n", kClassName);  
  114.         return -1;  
  115.     }  
  116.     /* register all the methods */  
  117.     if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK) {  
  118.         LOGE("Failed registering methods for %s/n", kClassName);  
  119.         return -1;  
  120.     }  
  121.     /* fill out the rest of the ID cache */  
  122.     return 0;  
  123. }  
  124.    
  125.    
  126. jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
  127.     JNIEnv* env = NULL;  
  128.     jint result = -1;  
  129.     LOGI("InputPen JNI_OnLoad");  
  130.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  131.         LOGE("ERROR: GetEnv failed/n");  
  132.         goto fail;  
  133.     }  
  134.    
  135.     if (env == NULL) {  
  136.         goto fail;  
  137.     }  
  138.     if (registerMethods(env) != 0) {  
  139.         LOGE("ERROR: PlatformLibrary native registration failed/n");  
  140.         goto fail;  
  141.     }  
  142.     /* success -- return valid version number */  
  143.     result = JNI_VERSION_1_4;  
  144. fail:  
  145.     return result;  
  146. }  
  147.    
  148.    
  149.    


3.1.4 Android.mk

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3.   
  4. LOCAL_SRC_FILES:= \  
  5.     input_pen.cpp \  
  6.     com_jiagutech_input_InputPen.cpp  
  7.       
  8. LOCAL_MODULE_TAGS := optional  
  9.   
  10. LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper  
  11. LOCAL_PRELINK_MODULE := false  
  12.   
  13. LOCAL_MODULE:= libinput_pen  
  14. include $(BUILD_SHARED_LIBRARY)  
  15.   
  16.   
  17. #LOCAL_MODULE:=inputpen  
  18. #include $(BUILD_EXECUTABLE)   


1.1.1 Debug.h

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #ifndef _DEBUG_H  
  2. #define _DEBUG_H  
  3.    
  4. #include <utils/Log.h>  
  5.    
  6. #ifdef ALOGD  
  7. #define LOGD      ALOGD  
  8. #endif  
  9. #ifdef ALOGV  
  10. #define LOGV      ALOGV  
  11. #endif  
  12. #ifdef ALOGE  
  13. #define LOGE      ALOGE  
  14. #endif  
  15. #ifdef ALOGI  
  16. #define LOGI      ALOGI  
  17. #endif  
  18.    
  19. #define LOG_TAG "InputPen"  
  20.    
  21. #endif   
  22.    
  23.    



3.2 App

共有两个文件:

PenEvent.java

InputPen.java

 

3.2.1 PenEvent.java

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.jiagutech.input;  
  2.    
  3. public class PenEvent {  
  4.    
  5.    
  6.     public PenEvent() {  
  7.    
  8.     }  
  9.    
  10.     public final static int ACTION_DOWN = 0x0;  
  11.     public final static int ACTION_UP = 0x1;  
  12.     public final static int ACTION_MOVE = 0x2;  
  13.    
  14.     //表示事件类型,down/up/move  
  15.     private int action;  
  16.     //x轴坐标  
  17.     private float x;  
  18.     //y轴坐标  
  19.     private float y;  
  20.     //压力数据  
  21.     private float pressure;  
  22.    
  23.     public void setAction(int action) {  
  24.         this.action = action;  
  25.     }  
  26.    
  27.     public int getAction() {  
  28.         return action;  
  29.     }  
  30.    
  31.    
  32.     public void setX(float x) {  
  33.         this.x = x;  
  34.     }  
  35.    
  36.     public float getX() {  
  37.         return x;  
  38.     }  
  39.    
  40.    
  41.     public void setY(float y) {  
  42.         this.y = y;  
  43.     }  
  44.    
  45.     public float getY() {  
  46.         return y;  
  47.     }  
  48.    
  49.     public void setPressure(float p) {  
  50.         this.pressure = p;  
  51.     }  
  52.    
  53.     public float getPressure() {  
  54.         return pressure;  
  55.     }  
  56.    
  57.    
  58.    
  59. }  
  60.    
  61.    

3.2.2 InputPen.java

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.jiagutech.input;  
  2.    
  3. import java.util.LinkedList;  
  4.    
  5. import android.os.Handler;  
  6.    
  7.    
  8. public class InputPen {  
  9.    
  10.     /**********************************************************************************/  
  11.     private static InputPen instance = null;  
  12.    
  13.     private boolean mStarted = false;  
  14.    
  15.     private final static String TAG = "InputPen";  
  16.    
  17.     //主线程Handler  
  18.     private Handler mHandler = null;  
  19.     //PenEvent列表  
  20.     private LinkedList<PenEvent> mEventList = new LinkedList<PenEvent>();  
  21.     //锁  
  22.     private Object mListLock = new Object();  
  23.    
  24.     /*******************************************************************/  
  25.     //以下定义请参考input_event.h文件  
  26.     private final static int EV_SYN = 0x0;  
  27.     private final static int EV_KEY = 0x01;  
  28.    
  29.     private final static int EV_ABS = 0x03;  
  30.    
  31.    
  32.     private final static int  ABS_X = 0x00;  
  33.     private final static int  ABS_Y = 0x01;  
  34.     private final static int  ABS_PRESSURE = 0x18;  
  35.     private final static int  BTN_TOUCH = 0x14a;  
  36.     private final static int  BTN_TOOL_PEN = 0x140;  
  37.     private final static int  BTN_STYLUS = 0x14b;  
  38.     /*******************************************************************/  
  39.     //原始的x最大分辨率  
  40.     private static final float MAX_X = 15360.0f;  
  41.     //屏幕x最大分辨率  
  42.     private static final float MAX_X_STANDARD = 1280.0f;  
  43.    
  44.     //原始的y最大分辨率  
  45.     private static final float MAX_Y = 9600.0f;  
  46.     //屏幕y最大分辨率  
  47.     private static final float MAX_Y_STANDARD = 800.0f;  
  48.    
  49.     //原始的最大压力数据  
  50.     private static final float MAX_PRESSURE = 1023.0f;  
  51.     //Android标准最大压力数据  
  52.     private static final float MAX_PRESSURE_STANDARD= 1.0f;  
  53.    
  54.     private int _x=-1,_y=-1,_pressure=-1;  
  55.     private int _bintouch = 0, _lastBinTouch = 0;  
  56.     //x轴转换系数  
  57.     private float xScale = MAX_X_STANDARD / MAX_X;  
  58.     //y轴转换系数  
  59.     private float yScale = MAX_Y_STANDARD / MAX_Y;  
  60.     //压力值转换系统  
  61.     private float pScale = MAX_PRESSURE_STANDARD / MAX_PRESSURE;  
  62.    
  63.     //y轴便宜  
  64.     private float yOffset = 73.0f;  
  65.    
  66.     /** 
  67.      * 加载libinput_pen.so,并初始化回调函数 
  68.      */  
  69.     static {  
  70.         try {  
  71.             System.loadLibrary("input_pen");  
  72.             class_init_native();  
  73.    
  74.    
  75.         } catch (UnsatisfiedLinkError e) {  
  76.             e.printStackTrace();  
  77.         }  
  78.    
  79.     }  
  80.    
  81.     private InputPen() {  
  82.     }  
  83.    
  84.     /** 
  85.      * 单例模式 
  86.      * @return 
  87.      */  
  88.     public static synchronized InputPen getInstance() {  
  89.         if (instance == null) {  
  90.             instance = new InputPen();  
  91.         }  
  92.         return instance;  
  93.     }  
  94.    
  95.     /** 
  96.      * 通知主线程获取PenEvent进行处理 
  97.      * 
  98.      */  
  99.     private void onPenTouch() {  
  100.         if (mHandler != null) {  
  101.             mHandler.sendEmptyMessage(0);  
  102.         }  
  103.    
  104.     }  
  105.    
  106.     /** 
  107.      * 设置主线程handler 
  108.      * @param handler 
  109.      */  
  110.     public void setHandler(Handler handler) {  
  111.         mHandler = handler;  
  112.     }  
  113.    
  114.     /** 
  115.      * 添加PenEvent到list 
  116.      * @param event 
  117.      */  
  118.     private void addPenEvent(PenEvent event) {  
  119.         synchronized (mListLock) {  
  120.             mEventList.add(event);  
  121.         }  
  122.     }  
  123.    
  124.     /** 
  125.      * 从list获取最旧的PenEvent 
  126.      * @return 
  127.      */  
  128.     public PenEvent getPenEvent() {  
  129.         PenEvent event = null;  
  130.         synchronized (mListLock) {  
  131.             if (mEventList.size() > 0) {  
  132.                 event = mEventList.removeFirst();  
  133.             }  
  134.         }  
  135.    
  136.         return event;  
  137.     }  
  138.    
  139.    
  140.     /*******************************************************************/  
  141.     //public method  
  142.    
  143.     /** 
  144.      * 坐标转换,并生成PenEvent数据 
  145.      * @param event 
  146.      */  
  147.     protected void transform(PenEvent event) {  
  148.         float x = MAX_Y_STANDARD - ((float)_y) * yScale;  
  149.         float y = (float)_x * xScale - yOffset;  
  150.         float p = (float)_pressure * pScale;  
  151.         event.setX(x);  
  152.         event.setY(y);  
  153.         event.setPressure(p);  
  154.     }  
  155.    
  156.     /** 
  157.      * 处理input_event数据 
  158.      */  
  159.     protected void processEvent() {  
  160.    
  161.         if (_bintouch != _lastBinTouch ) {  
  162.             _lastBinTouch = _bintouch;  
  163.             //Log.d(TAG, String.format("x=%d,y=%d,pressure=%d,bintouch=%d", _x,_y,_pressure,_bintouch));  
  164.             if (_bintouch == 1) { //down事件  
  165.                 PenEvent event = new PenEvent();  
  166.                 event.setAction(PenEvent.ACTION_DOWN);  
  167.                 transform(event);  
  168.                 addPenEvent(event);  
  169.                 onPenTouch();  
  170.    
  171.             } else { //up事件  
  172.                 PenEvent event = new PenEvent();  
  173.                 event.setAction(PenEvent.ACTION_UP);  
  174.                 transform(event);  
  175.                 addPenEvent(event);  
  176.                 onPenTouch();  
  177.             }  
  178.         } else if (_bintouch == 1) { //move事件  
  179.             PenEvent event = new PenEvent();  
  180.             event.setAction(PenEvent.ACTION_MOVE);  
  181.             transform(event);  
  182.             addPenEvent(event);  
  183.             onPenTouch();  
  184.    
  185.         }  
  186.    
  187.    
  188.    
  189.    
  190.     }  
  191.    
  192.     /** 
  193.      * 获取input_event数据,由jni层调用此函数 
  194.      * @param type 
  195.      * @param code 
  196.      * @param value 
  197.      */  
  198.     protected void getEvent(int type, int code, int value) {  
  199.         switch (type) {  
  200.    
  201.         case EV_SYN:  
  202.             processEvent();  
  203.             break;  
  204.    
  205.         case EV_KEY:  
  206.             if (code == BTN_TOUCH) {  
  207.                 _bintouch = value;  
  208.             }  
  209.             break;  
  210.         case EV_ABS:  
  211.             if (code == ABS_X) {  
  212.                 _x = value;  
  213.             } else if (code == ABS_Y) {  
  214.                 _y = value;  
  215.             } else if (code == ABS_PRESSURE) {  
  216.                 _pressure = value;  
  217.             }  
  218.             break;  
  219.         default:  
  220.             break;  
  221.         }  
  222.     }  
  223.    
  224.     /** 
  225.      * 启动线程 
  226.      */  
  227.     protected void start() {  
  228.         if (!mStarted) {  
  229.             if (native_input_pen_init()) {  
  230.                 mStarted = true;  
  231.             }  
  232.    
  233.         }  
  234.    
  235.    
  236.     }  
  237.    
  238.     /** 
  239.      * 停止线程 
  240.      */  
  241.     protected void stop() {  
  242.         if (mStarted) {  
  243.             native_input_pen_exit();  
  244.             mStarted = false;  
  245.         }  
  246.    
  247.     }  
  248.    
  249.     public void dispose() {  
  250.         stop();  
  251.     }  
  252.    
  253.     @Override  
  254.     protected void finalize() throws Throwable {  
  255.    
  256.         stop();  
  257.         // TODO Auto-generated method stub  
  258.         super.finalize();  
  259.     }  
  260.    
  261.    
  262.     /*******************************************************************/  
  263.     //native method  
  264.     protected  static native void class_init_native();  
  265.    
  266.     protected  native boolean native_input_pen_init();  
  267.    
  268.     protected  native void native_input_pen_exit();  
  269. }  
  270.    
  271.    
  272.    


3.2.3 Activity

Activity可以通过调用InputPenstart函数,启动读取线程,再调用setHandler设置Handler,从而就可在Handler中处理PenEvent数据了。


<think>好的,用户现在的问题是想要解析在wl.smartled环境下misight_perf和inputevent相关的错误日志,特别是错误代码[902002002, wl.smartled, 23178],并且处理app的延迟问题。首先,我需要回顾之前的对话,看看有没有相关的信息可以借鉴。 用户之前询问过如何捕获和解析来自AudioSystem-JNI的错误消息,我给出了关于错误捕获机制、特定错误代码处理以及日志分析的方法。现在的问题涉及到不同的组件,misight_perf和inputevent,还有特定的环境wl.smartled,可能需要类似的日志分析步骤,但具体工具和方法可能不同。 首先,用户提供的引用[1]、[2]、[3]都是关于perf_event_open系统调用的,这可能与性能监有关。这可能意味着用户在处理性能相关的问题,需要利用perf工具或者类似的性能监机制来分析错误。不过用户现在的具体问题涉及misight_perf和inputevent的错误日志,可能需要结合这些引用中的信息,尤其是perf_event的结构和ioctl操作。 接下来,用户提到的错误日志格式是[902002002, wl.smartled, 23178],其中902002002可能是错误代码,wl.smartled是模块或环境名称,23178可能是进程ID。需要解析这些字段的含义。根据之前的回答,错误代码通常需要查阅相关文档或源码来解析,比如在Android系统中,错误代码可能有特定的定义。 处理app的延迟问题,可能需要分析性能数据,比如CPU使用率、线程调度、锁竞争、I/O等待等。结合perf_event_open,可以监这些指标,找出瓶颈所在。此外,inputevent相关的错误可能涉及到输入事件处理延迟,比如摸事件或传感器事件的处理不及时,导致应用响应慢。 接下来,我需要考虑用户可能的深需求。用户可能是在开发或维护一个基于wl.smartled环境的智能设备(比如智能灯),遇到了性能问题和输入事件处理错误,导致应用延迟。需要系统地分析日志,定位问题根源,并优化性能。 根据之前的回答,解析错误日志通常涉及以下步骤:捕获日志、解析错误代码、关联上下文信息、定位源码或文档、进行调试和优化。对于misight_perf,可能需要使用性能分析工具,而inputevent可能需要检查输入子系统的事件处理流程。 需要结合用户提供的引用中的perf_event_open和ioctl操作,可能涉及到如何设置性能监事件,启用或禁用计数器,以及处理性能数据。例如,引用[2]中的_perf_ioctl函数处理ENABLE、DISABLE、RESET等命令,这可能用于制性能监的开始和停止。 另外,用户提到的错误代码中的数字,比如EV_CYCLES和EV_REF_CYCLES,可能与性能事件类型有关,需要确认这些定义在源码中的位置,以理解具体监的是什么事件。 对于错误日志解析,可能需要从日志中提取关键字段,如时间戳、进程ID、线程ID、错误代码、模块名称等,然后根据这些信息查找对应的文档或源码注释。例如,错误代码902002002可能需要分解成不同部分,如902可能代表主类别,002002代表子错误,或者参考类似Android错误代码的解析方法。 处理app延迟问题,可能需要检查以下几个方面:主线程是否被阻塞、是否有过多的GC活动、是否有死锁或线程竞争、I/O操作是否在主线程执行、第三方库的性能问题等。使用性能分析工具如Perf、Systrace、Android Profiler可以帮助定位这些问题。 最后,用户可能需要具体的命令或代码示例来解析日志和监性能,比如使用adb logcat过滤特定标签的日志,或者编写脚本自动化分析日志文件。此外,可能需要指导如何配置perf_event_open来监特定事件,以及如何处理收集到的性能数据。 总结来说,回答需要包括错误日志解析的步骤、工具使用、代码示例,以及处理app延迟的具体优化建议,结合用户之前的问题中提到的JNI错误处理方法和性能分析技巧。</think>### 解析 `misight_perf` 和 `wl.smartled` 中 `inputevent` 相关错误日志的方法 在 `wl.smartled` 环境下解析 `misight_perf` 和 `inputevent` 的错误日志(如 `[902002002, wl.smartled, 23178]`)需要结合日志格式、系统性能监机制和事件处理逻辑。以下是具体步骤: --- #### 1. **错误日志结构分析** 日志 `[902002002, wl.smartled, 23178]` 包含以下关键信息: - **902002002**: 错误代码,通常包含级化的错误分类(如模块标识、错误类型等)。 - **wl.smartled**: 关联的模块或组件名称。 - **23178**: 进程 ID(PID),标识发错误的进程。 **解析方法**: - **错误代码分解**: 根据引用[1]中 `perf_event_open` 的结构设计,错误代码可能包含多段信息。例如: ```plaintext 902002002 → 9 (主分类) | 020 (子模块) | 02 (错误类型) | 002 (具体错误码) ``` 需查阅 `misight_perf` 的文档或源码定义(类似引用[3]的 `EV_CYCLES` 宏)明确具体含义[^3]。 - **模块关联性**: `wl.smartled` 可能涉及硬件抽象(HAL)或输入事件处理逻辑,需检查其与 `inputevent` 的交互代码。 --- #### 2. **日志捕获与过滤** 通过 `adb logcat` 或系统日志工具捕获完整错误堆栈: ```bash adb logcat -v threadtime | grep -E 'misight_perf|wl.smartled|inputevent' ``` 示例输出: ```plaintext E wl.smartled: [inputevent] latency detected: PID=23178, Code=902002002 E misight_perf: AppLatencyMonitor: Thread blocking detected (delay=450ms) ``` **关键字段**: - `latency detected`: 输入事件处理延迟。 - `Thread blocking detected`: 应用主线程阻塞。 --- #### 3. **性能数据分析(`misight_perf` 相关)** `misight_perf` 可能基于 `perf_event_open` 实现性能监(引用[1][^1])。针对应用延迟(App Latency),需监以下指标: - **CPU 调度延迟**:通过 `perf_event_open` 监上下文切换次数(`PERF_COUNT_SW_CONTEXT_SWITCHES`)。 - **线程阻塞时间**:跟踪 `sched_stat_blocked` 事件。 - **I/O 等待**:使用 `PERF_COUNT_SW_PAGE_FAULTS` 监缺页异常。 **示例代码**(配置性能事件): ```cpp struct perf_event_attr attr; memset(&attr, 0, sizeof(attr)); attr.type = PERF_TYPE_SOFTWARE; attr.size = sizeof(attr); attr.config = PERF_COUNT_SW_CONTEXT_SWITCHES; attr.disabled = 1; attr.inherit = 1; int fd = perf_event_open(&attr, 23178, -1, -1, 0); ioctl(fd, PERF_EVENT_IOC_RESET, 0); ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); // 读取计数器值以分析调度延迟 ``` --- #### 4. **输入事件延迟优化(`inputevent` 相关)** `inputevent` 的延迟通常由以下原因导致: - **主线程阻塞**:输入事件处理被耗时操作(如同步 I/O)阻塞。 - **Binder 调用延迟**:跨进程通信(如与 `wl.smartled` 服务交互)耗时过长。 **调试方法**: - **Systrace 分析**: 使用 Systrace 抓取输入事件处理轨迹: ```bash python systrace.py sched input view wm -t 5 -o trace.html ``` 检查 `InputDispatcher` 和 `InputConsumer` 的时间线,定位事件传递瓶颈。 - **Binder 调用监**: 通过 `binder_stats` 或 `dumpsys binder` 查看 Binder 事务耗时: ```bash adb shell dumpsys binder transactions | grep 23178 ``` --- #### 5. **错误处理与代码修复** 针对日志 `902002002` 和延迟问题,可能的修复方向: 1. **异步化输入事件处理**: 将输入事件回调中的耗时操作移至工作线程。 ```java inputManager.registerInputDeviceListener(new InputDeviceListener() { @Override public void onInputDeviceChanged(int deviceId) { new Thread(() -> handleDeviceChange(deviceId)).start(); } }, null); ``` 2. **优化 HAL 实现**: 检查 `wl.smartled` 的 HAL 实现(如 `smartled_hal.c`),确保无阻塞调用。 3. **调整进程优先级**: 通过 `setpriority(PRIO_PROCESS, 23178, -10)` 提升关键进程的调度优先级。 --- ### 相关问题 1. **如何通过 `perf_event_open` 监 Android 应用的线程调度延迟?** 2. **Binder 调用性能优化的常见方法有哪些?** 3. **在 Systrace 中如何识别输入子系统的瓶颈?** --- 通过结合性能监工具、日志分析和代码优化,可系统化解决 `wl.smartled` 环境下的错误日志解析与延迟问题。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值