Android 模拟系统事件(二)
来源:互联网 发布:詹姆斯07年总决赛数据 编辑:程序博客网 时间:2024/06/05 19:19
简介
JNI(Java Native Interface)是本地编程接口,它允许Java代码和其他语言写的代码进行交互,它可以在 Java 虚拟机 (VM) 内部运行的 Java 代码与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。
功能
通过jni实现向Android系统注入事件,从而实现模拟按键、模拟触屏等操作!用它直接跳过上面的Android平台权限的问题!
原理是在jni中通过Linux内核的ioctl函数和c语言函数(memset、write)来实现对设备的I/O通道进行管理的。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下:
int ioctl(int fd, ind cmd, …)
void *memset(void *s,int c,size_t n) //总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。
ssize_t write(int fd,const void *buf,size_t nbytes) //将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能.
代码实现
关键代码如下:
jint Java_net_pocketmagic_keyinjector_NativeInput_intEnableDebug( JNIEnv* env,jobject thiz, jint enable ) {g_debug = enable;if (enable == 1) debug("Debug enabled.");return g_debug;}jint Java_net_pocketmagic_keyinjector_NativeInput_intCreate( JNIEnv* env,jobject thiz, jstring inputdev, jint keyboard, jint mouse){jboolean iscopy;char szDev[255] = "";const char *pszDev = (*env)->GetStringUTFChars(env, inputdev, &iscopy);if (pszDev) strncpy(szDev, pszDev, 255);(*env)->ReleaseStringUTFChars(env, inputdev, pszDev);debug("intCreate call (%s)", szDev);struct uinput_dev dev;int fd_kb, aux;fd_kb = open(szDev, O_RDWR);if (fd_kb < 0) {debug("Can't open input device:%s ", szDev);return -1;}memset(&dev, 0, sizeof(dev));strcpy(dev.name, "AndroidKeyInjector Input");dev.id.bustype = 0x0003;// BUS_USB;dev.id.vendor = 0x0000;dev.id.product = 0x0000;dev.id.version = 0x0000;if (write(fd_kb, &dev, sizeof(dev)) < 0) {debug("Can't write device information");close(fd_kb);return -1;}if (mouse) {ioctl(fd_kb, UI_SET_EVBIT, EV_REL);for (aux = REL_X; aux <= REL_MISC; aux++)ioctl(fd_kb, UI_SET_RELBIT, aux);}if (keyboard) {ioctl(fd_kb, UI_SET_EVBIT, EV_KEY);ioctl(fd_kb, UI_SET_EVBIT, EV_LED);ioctl(fd_kb, UI_SET_EVBIT, EV_REP);for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++)ioctl(fd_kb, UI_SET_KEYBIT, aux);//for (aux = LED_NUML; aux <= LED_MISC; aux++)//ioctl(fd_kb, UI_SET_LEDBIT, aux);}if (mouse) {ioctl(fd_kb, UI_SET_EVBIT, EV_KEY);for (aux = BTN_LEFT; aux <= BTN_BACK; aux++)ioctl(fd_kb, UI_SET_KEYBIT, aux);}ioctl(fd_kb, UI_DEV_CREATE);debug("intCreate success: %d", fd_kb);return fd_kb;}void Java_net_pocketmagic_keyinjector_NativeInput_intClose( JNIEnv* env,jobject thiz, jint fd_kb){close(fd_kb);}void Java_net_pocketmagic_keyinjector_NativeInput_intSendEvent( JNIEnv* env,jobject thiz, int fd_kb, uint16_t type, uint16_t code, int32_t value){debug("intSendEvent call (%d,%d,%d,%d)", fd_kb, type, code, value);struct uinput_event event;int len;if (fd_kb <= fileno(stderr))return;memset(&event, 0, sizeof(event));event.type = type;event.code = code;event.value = value;len = write(fd_kb, &event, sizeof(event));debug("intSendEvent done:%d",len);}
其中的事件id 可以参考Android源码地址。
调用代码如下:
public class NativeInput {int m_fd;final static int EV_KEY = 0x01;public NativeInput() {intEnableDebug(1);for (int i = 0; i < 8; i++) {m_fd = intCreate("/dev/input/event" + i, 1, 0);if (m_fd != -1)break;}}public static int chmod(String path, int mode) throws Exception {Class fileUtils = Class.forName("android.os.FileUtils");Method setPermissions = fileUtils.getMethod("setPermissions",String.class, int.class, int.class, int.class);return (Integer) setPermissions.invoke(null, path, mode, -1, -1);}public int SendKey(int key, boolean state) {if (state)return intSendEvent(m_fd, EV_KEY, key, 1); // key downelsereturn intSendEvent(m_fd, EV_KEY, key, 0); // key up}native int intEnableDebug(int enabled); // 1 will output to logcat, 0 will// disable//native int intCreate(String dev, int kb, int mouse);native void intClose(int fd);native int intSendEvent(int fd, int type, int code, int value);static {System.loadLibrary("input");}}
其它相关代码如下:
int EVT_open(struct NATIVE_INFO *info){ struct input_absinfo absinfo; if(initEVT) return 0; if(info == NULL) { LOGE("info null point."); goto fail; } if(info->FB_width == 0 || info->FB_height == 0) { LOGE("error width %d and height %d.", info->FB_width, info->FB_height); goto fail; } memset(&ei, 0, sizeof(ei)); ei.screen_width = info->FB_width; ei.screen_height = info->FB_height; scan_dir(DEV_DIR); if(ioctl(ei.fd_touch, EVIOCGABS(ABS_X), &absinfo)) { LOGI("Error reading absolute controller ABS_X[%d]: %s", errno, strerror(errno)); return; } ei.abs_x_min = absinfo.minimum; ei.abs_x_max = absinfo.maximum; if(ioctl(ei.fd_touch, EVIOCGABS(ABS_Y), &absinfo)) { LOGI("Error reading absolute controller ABS_Y[%d]: %s", errno, strerror(errno)); return; } ei.abs_y_min = absinfo.minimum; ei.abs_y_max = absinfo.maximum; initEVT = 1; return 0; fail: EVT_close(); return -1;} int EVT_close(){ if(ei.fd_key > 0) close(ei.fd_key); if(ei.fd_touch > 0) close(ei.fd_touch); initEVT = 0; return 0;} int EVT_touch(int action, float x, float y){ int abs_x, abs_y; if(initEVT == 0) { LOGE("event not inital"); return -1; } switch(action) { case ACTION_DOWN: calculateXY(x, y, &abs_x, &abs_y); write_event(ei.fd_touch, 3, 0, abs_x); write_event(ei.fd_touch, 3, 1, abs_y); write_event(ei.fd_touch, 1, 330, 1); write_event(ei.fd_touch, 0, 0, 0); break; case ACTION_UP: write_event(ei.fd_touch, 1, 330, 0); write_event(ei.fd_touch, 0, 0, 0); break; case ACTION_MOVE: calculateXY(x, y, &abs_x, &abs_y); write_event(ei.fd_touch, 3, 0, abs_x); write_event(ei.fd_touch, 3, 1, abs_y); write_event(ei.fd_touch, 0, 0, 0); break; } return 0;} int EVT_key(int action, int key){ if(initEVT == 0) { LOGE("event not inital"); return -1; } switch(action) { case ACTION_DOWN: write_event(ei.fd_key, 1, key, 1); break; case ACTION_UP: write_event(ei.fd_key, 1, key, 0); break; } return 0;} int scan_dir(const char *dirname){ char devname[PATH_MAX]; char *filename; DIR *dir; struct dirent *de; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); open_dev(devname); } closedir(dir); return 0;} int open_dev(const char *deviceName){ int fd; int version; uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)]; fd = open(deviceName, O_RDWR); if(fd < 0) { LOGI("could not open device[%d]: %s", errno, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGVERSION, &version)) { return -1; } memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD), sizeof_bit_array(BTN_DIGI)) || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1))) { ei.fd_key = fd; LOGI("get key input device: %s", deviceName); } } memset(abs_bitmask, 0, sizeof(abs_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { ei.fd_touch = fd; LOGI("get multi-touch input device: %s", deviceName); // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, key_bitmask) && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { ei.fd_touch = fd; LOGI("get single-touch input device: %s", deviceName); } }} int write_event(int fd, int type, int code, int value){ struct input_event event; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; if(write(fd, &event, sizeof(event)) < sizeof(event)) { LOGI("write event failed[%d]: %s", errno, strerror(errno)); return -1; } return 0;} void calculateXY(float x, float y, int *abs_x, int *abs_y){ *abs_x = ei.abs_x_min + (int)((x * (float)(ei.abs_x_max - ei.abs_x_min)) / ei.screen_width + 0.5); *abs_y = ei.abs_y_min + (int)((y * (float)(ei.abs_y_max - ei.abs_y_min)) / ei.screen_height + 0.5);} int containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex){ const uint8_t* end = array + endIndex; array += startIndex; while (array != end) { if (*(array++) != 0) { return 1; } } return 0;}
结论
以上是使用ioctl来实现对设备i/o控制,如果不用ioctl的话,也可以实现对设备I/O通道的控制。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。
下载
项目下载
- Android 模拟系统事件(二)
- Android 模拟系统事件(二)
- Android 模拟系统事件(一)
- Android 模拟系统事件(三)
- Android 模拟系统事件(一)
- Android 模拟系统事件(三)
- 模拟“事件监听器”(二)
- Android系统触屏事件传递派发浅析(二)
- android远程控制(三)----通过后台服务实现系统点击事件模拟
- Android系统上实现类似按键精灵的效果(模拟触屏点击事件)
- Android中的 事件流----浅析安卓中的动与静(二) 系统事件流
- Android模拟、实现、触发系统按键事件的方法
- 模拟模拟交易系统(二)——系统设计
- android 模拟键盘事件
- Android模拟MotionEvent事件
- Android模拟input事件
- Android模拟产生事件
- Android模拟产生事件
- runtime与include,forward,redirect
- C++指针数组和数组指针--笔试面试系列
- 进程虚拟地址空间与物理内存关系
- Gridview删除选中,编辑
- C++运算符重载实现矩阵除法
- Android 模拟系统事件(二)
- 三周C#总结7oop--多态
- Mac OS X系统中Eclipse使用问题汇总
- 《算法竞赛-训练指南》第三章-3.6_LA 3027(并查集)
- hadoop学习过程-2013.08.22.2--hadoop1.2.1修改WordCount并编译
- 简单JAVA观察者模式监测文件是否改动
- cocos2d-x android 调试
- jsf里写自定义的标签
- 设置eclipse启动时手动选择工作空间