Android學習之開源項目分析--screencast

Update: 最近觀看了ELC2011的關於android的一個視頻, 裏面提到了Android System Test Environment Runtime這麼一個可以在PC端控制並執行一些定製的script測試腳本的測試框架, 其中PC與Device之間的UI同步用的就是screencast類似的機制--不停的傳遞screenshot, 而不是hack fbdev driver來傳遞實時的framebuffer中的內容。我另外會總結一篇對於ASTER的文章,希望和大家一起學習下.


Screencast是一個C/S的實用小程序, 用來通過desktop pc控制android device. 實現的相當精巧.


項目的地址: http://code.google.com/p/androidscreencast/


關鍵技術:

Java web start

適合dalvik的可執行jar包的生成

利用ADB實現PC與device的通信

通過app_process直接啓動一個可執行的android jar包,而不需要安裝它

我們先來看看它的client的實現:

1. 把AndroidScreencastClient導入eclipse, 查看對應.classpath, 修改對應的3個jar包指向你的環境中的對應位置

2. 使用提供的MyInjectEventApp.jardesc,生成Server端需要使用的MyInjectEventApp.jar

3. 按照MyInjectEventApp的描述, 生成包含classes.dex的jar包,這個包之後才能在android device被執行!!

!!這一步很重要,像我們展示了,如何使用普通的java工程, 生成普通的jar包(但是,這個包裏包含有android的相關類), 再利用android提供的dx, aapt生成能在android device上執行的可執行jar包!!

以上編譯準備工作做好,就可以看它的實現了

Main.java -- 很簡單的一個入口點, 從PC測接收一個端口號, 以此新建一個socket通信, 並新起一個線程來使用該socket.

ClientHandler.java -- 關鍵做事的類, 利用常用的hook android framework的方法, 使用ServiceManage獲得"window" service的Binder, 然後調用它所對應的WindowManager的內部接口來進行,point/key/trackball事件的觸發

IBinder wmbinder = ServiceManager.getService( "window" );
final IWindowManager wm = IWindowManager.Stub.asInterface( wmbinder );

injectPointerEvent/injectKeyEvent/injectTrackballEvent就是WindowsManager中的內部接口, 對應的代碼在frameworks/base/services/java/com/android/server/wm/WindowManagerService.java

如何讀取設備上的framebuffer

Process p = Runtime.getRuntime().exec("/system/bin/cat /dev/graphics/fb0");
InputStream is = p.getInputStream();
System.out.println("Starting sending framebuffer");
OutputStream os = s.getOutputStream();

再來看看Server(即desktop PC)的實現:

使用swt構建了PC側的UI.

使用了非公開的DDMS提供的ADB接口完成通信

AndroidDebugBridge bridge = AndroidDebugBridge.createBridge();
		waitDeviceList(bridge);
IDevice devices[] = bridge.getDevices();

使用了ADB daemon提供的接口來獲得各種adb service提供的功能, 比如獲得framebuffer的內容,從而顯示到PC端. (adb daemon提供的service文檔, 參見system/core/adb/SERVICES.TXT):具體的通信還是由傳統的socket通信來完成, 沒要求一次screenshot, 就會發一次獲得當前framebuffer的請求.

RawImage rawImage = null;
synchronized (device) {
	rawImage = device.getScreenshot();
}

通過反射,使用ddms提供的syncmanager的接口, 從而提供了DDMS提供的pull/push文件的功能

Method m = device.getSyncService().getClass().getDeclaredMethod(
					"doPullFile", String.class, String.class,
					ISyncProgressMonitor.class);

!!通過使用app_process來執行一個android的可執行jar包!!

String fullCmd = "export CLASSPATH=" + REMOTE_AGENT_JAR_LOCATION;
fullCmd += "; exec app_process /system/bin " + AGENT_MAIN_CLASS + " "
	+ cmdList;
System.out.println(fullCmd);
device.executeShellCommand(fullCmd,
		new OutputStreamShellOutputReceiver(System.out));



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章