Android系統底層事件跨程序注入,遠端控制螢幕的觸控、點選、滑動
Android底層事件注入,在知道要實現這個功能的時候,我感覺技術含量瞬間提高了很多,涉及到底層事務。
Android實現按鈕觸發事件方法有多種,但並不是每種都適用,這裡使用的方法是呼叫"sendevent"命令,這是Linux的系統命令,在Android上使用首先要將機器獲取到root許可權,root過的手機才能使用“Runtime.getRuntime().exec("cmd")”這個方法取得操作Android底層的環境;這個東西主要就是用來模擬一套linux系統環境,在這個環境下可以通過Linux的一些系統命令實現對Linux系統(Android核心)的操作,使用方法非常簡單:
DataOutputStream dos = null; try { //注入su命令獲取許可權 Process p = Runtime.getRuntime().exec("su"); dos = new DataOutputStream(p.getOutputStream()); System.out.println(cmd); //下面語句列出sdcard下的檔案資訊,並將資訊輸出到dos流中,可以新建一個輸入流獲取 dos.writeBytes("ls /mnt/sdcard\n"); dos.flush(); dos.writeBytes("exit\n"); dos.flush(); p.waitFor(); } catch (Exception e) { e.printStackTrace(); } finally { if (dos != null) { try { dos.close(); } catch (IOException e) { e.printStackTrace(); } } }
上面的程式碼模擬了獲取sdcard下檔案目錄的資訊島輸出流dos中的操作,我們暫把這個操作命名為“RuntimeExec操作”,需要注意的問題是:
1. exec的輸入輸出流需要自己處理
2. exec執行時阻塞、非阻塞,返回結果問題
3. 注意許可權問題
--------------------------------------------------------------------------------------------------------------------------------
我們要實現向按鈕、螢幕等硬體傳送底層事件,需要先獲取硬體裝置檔案許可權(檔案許可權跟root許可權不同),再呼叫open函式開啟裝置,裝置檔案一般在Android系統目錄的dev/input結構下:
static int open_device(int index) { if (index >= nDevsCount || pDevs == NULL) return -1; debug("open_device prep to open"); char *device = pDevs[index].device_path; debug("open_device call %s", device); int version; int fd; char name[80]; char location[80]; char idstr[80]; struct input_id id; fd = open(device, O_RDWR); if(fd < 0) { pDevs[index].ufds.fd = -1; pDevs[index].device_name = NULL; debug("could not open %s, %s", device, strerror(errno)); return -1; } pDevs[index].ufds.fd = fd; ufds[index].fd = fd; name[sizeof(name) - 1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { debug("could not get device name for %s, %s", device, strerror(errno)); name[0] = '\0'; } debug("Device %d: %s: %s", nDevsCount, device, name); pDevs[index].device_name = strdup(name); return 0; }
獲取檔案許可權可使用“RuntimeExec操作”注入命令"chmod 777 filepath"的方法獲取;一般來說dev/input目錄下會有event0、event1等等檔案,這些檔案對應我們的一個硬體裝置,比如螢幕,滑鼠等
有了這些,我們就可以使用sendevent命令了。
首先android介面捕獲事件的流程。使用者在螢幕上點選一下後,程式裡面的OnClickListener是怎樣收到這個事件的。大致流程如下
使用者點選-(硬體驅動部分)硬體產生一箇中斷,往/dev/input/event*寫入一個相應的訊號->jni部分,android迴圈讀取/dev/input/event*的事件,再分發給WindowManagerServer,最後再發到相應的ViewGroup和View。這裡可以通過往/dev/input/event*寫訊號的方式,來達到模擬事件的目的,接下來關心的就是訊號的協議了。
關於sendevent命令使用推薦兩篇部落格:
我們在做的時候基本實現了需要的功能,觸控、點選、滑屏、返回、選單、Home、聲音按鈕的控制