1. 程式人生 > >Android系統底層事件跨程序注入,遠端控制螢幕的觸控、點選、滑動

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*寫入一個相應的訊號-&gt;jni部分,android迴圈讀取/dev/input/event*的事件,再分發給WindowManagerServer,最後再發到相應的ViewGroup和View。這裡可以通過往/dev/input/event*寫訊號的方式,來達到模擬事件的目的,接下來關心的就是訊號的協議了。

關於sendevent命令使用推薦兩篇部落格:

我們在做的時候基本實現了需要的功能,觸控、點選、滑屏、返回、選單、Home、聲音按鈕的控制