如前文《[誰動了我的截圖?--Monkeyrunner takeSnapshot方法源碼跟蹤分析](http://blog.csdn.net/zhubaitian/article/details/40262831)》所述,本文主要會嘗試描述android的自動化測試框架MonkeyRunner究竟是如何和目標設備進行通信的。
在上一篇文章中我們其實已經描述了其中一個方法,就是通過adb協議發送adb服務器請求的方式驅動android設備的adbd守護進程去獲取FrameBuffer的數據生成屏幕截圖。那么MonkeyRunner還會用其他方式和目標設備進行通信嗎?答案是肯定的,且看我們一步步分析道來。
## 1.概述
MonkeyRunner和目標設備打交道都是通過ChimpChat層進行封裝分發但最終是在ddmlib進行處理的,其中囊括的方法大體如下:
- **發送monkey命令**:MonkeyRunner先通過adb shell發送命令"monkey -port ?12345"在目標機器上啟動monkey以監聽端口接受連接,然后MonkeyRunner通過連接該端口建立socket并發送monkey命令。所有與界面相關的操作都是通過這種方式發送到目標機器的。
- **發送adb協議請求**:通過發送adb協議請求來與目標設備通信的,詳情請查看<<[誰動了我的截圖?--Monkeyrunner takeSnapshot方法源碼跟蹤分析](http://blog.csdn.net/zhubaitian/article/details/40262831)>>和<<[adb概覽及協議參考](http://blog.csdn.net/zhubaitian/article/details/40260783)>>,其實adb命令行客戶端的所有命令最終都是通過發送遵循adb協議的請求來實現的,只是做成命令行方式方便終端用戶使用而已
- **發送adb shell命令**:模擬adb命令行工具發送adb shell命令,只是不是真正的直接命令行調用adb工具,而是在每一個命令執行之前先通過上面的“**發送adb協議請求**“發送“shell:”請求建立一個和adb服務器通信的adb shell的socket連接通道,adb服務器再和目標設備的adb守護進程進行通信
以下是MonkeyDevice所有請求對應的與設備通信方式
<table cellspacing="0" cellpadding="0" class=" " style="border-collapse:collapse"><tbody><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:19px; padding:4px; background-color:rgb(191,191,191)"><p align="center" style="margin-top:0px; margin-bottom:0px; text-align:center"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px"><strong>請求</strong></span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:19px; padding:4px; background-color:rgb(191,191,191)"><p align="center" style="margin-top:0px; margin-bottom:0px; text-align:center"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px"><strong>是否需要和目標設備通信</strong></span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:19px; padding:4px; background-color:rgb(191,191,191)"><p align="center" style="margin-top:0px; margin-bottom:0px; text-align:center"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px"><strong>通信方式</strong></span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:19px; padding:4px; background-color:rgb(191,191,191)"><p align="center" style="margin-top:0px; margin-bottom:0px; text-align:center"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px"><strong>注解</strong></span></p></td></tr><tr><td colspan="4" valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:383px; height:13px; padding:4px; background-color:rgb(255,192,114)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px"><strong>發送</strong></span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px"><strong>adb shell</strong></span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px"><strong>命令</strong></span></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:28px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">getSystemProperty</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:28px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:28px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:28px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:46px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">installPackage</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:46px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:46px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:46px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">傳送數據時發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">協議請求,發送安裝命令時使用</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">startActivity</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:29px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">broadcastIntent</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:29px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:29px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:29px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">instrument</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:34px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">shell</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:34px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:34px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:34px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令為空,所以相當于直接執行</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">”adb shell “</span></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">removePackage</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb shell</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td colspan="4" valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:383px; height:13px; padding:4px; background-color:rgb(255,192,114)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">monkey</span><span style="font-size:11px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">getProperty</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">wake</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; line-height:26px"><span style="font-size:14px; line-height:normal; font-family:Arial; letter-spacing:0px; color:rgb(54,46,43)">dispose?</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-family:Heiti SC Light; font-size:10px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">? ?</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">press</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">type</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">touch</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">drag</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">getViewIdList</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">getView</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">getViews</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">getRootView</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">monkey</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">??</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td colspan="4" valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:383px; height:13px; padding:4px; background-color:rgb(255,192,114)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">adb</span><span style="font-size:11px; font-family:'Heiti SC Light'; letter-spacing:0px">協議請求</span></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Arial; letter-spacing:0px">takeSnapshot</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">協議請求</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:13px; padding:4px"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">reboot</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">協議命令</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:14px; padding:4px; background-color:rgb(239,239,239)"><p style="margin-top:0px; margin-bottom:0px; font-family:Helvetica; min-height:14px"><br/></p></td></tr><tr><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:36px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:11px; font-family:Monaco; letter-spacing:0px">installPackage</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:36px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">是</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:36px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">協議請求</span></p></td><td valign="top" style="border-style:solid; border-color:rgb(0,0,0); width:89px; height:36px; padding:4px"><p style="margin-top:0px; margin-bottom:0px"><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">相當于直接發送</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">adb</span><span style="font-size:10px; font-family:'Heiti SC Light'; letter-spacing:0px">命令行命令</span><span style="font-size:10px; font-family:Helvetica; letter-spacing:0px">’adb push’</span></p></td></tr></tbody></table>
分析之前請大家準備好對應的幾個庫的源碼:

## 2. 發送monkey命令
在剖析如何發送monkey命令之前,我們需要先去了解一個類,因為這個類是處理所有monkey命令的關鍵,這就是ChimpChat庫的ChimpManager類。
我們先查看其構造函數,看它是怎么初始化的:
~~~
/* */ private Socket monkeySocket;
/* */
/* */ private BufferedWriter monkeyWriter;
/* */
/* */ private BufferedReader monkeyReader;
/* */
/* */
/* */ public ChimpManager(Socket monkeySocket)
/* */ throws IOException
/* */ {
/* 62 */ this.monkeySocket = monkeySocket;
/* 63 */ this.monkeyWriter = new BufferedWriter(new OutputStreamWriter(monkeySocket.getOutputStream()));
/* */
/* 65 */ this.monkeyReader = new BufferedReader(new InputStreamReader(monkeySocket.getInputStream()));
/* */ }
~~~
初始化所做的事情如下
- 把構造函數傳進來的monkeySocket這個socket對象保存起來,往下會分析這個socket是如何創立的
- 初始化monkeyWriter這個BufferedWriter,今后往monkey的socket發送命令的時候用的就是它
- 初始化monkeyReader這個BufferedReader,今后從monkey的socket讀返回的時候用的就是它
好,那么現在我們返回來看這個類是什么時候實例化的。請定位到AdbChimpDevice的構造函數:
~~~
/* */ private ChimpManager manager;
/* */
/* */ public AdbChimpDevice(IDevice device)
/* */ {
/* 70 */ this.device = device;
/* 71 */ this.manager = createManager("127.0.0.1", 12345);
/* */
/* 73 */ Preconditions.checkNotNull(this.manager);
/* */ }
~~~
可以看到ChimpManager是在AdbChimpDevice構造的時候已經開始初始化的了,初始化傳入的地址是"127.0.0.1"和端口是12345,這個是在下面分析的createManager這個方法中創建socket用的,也就是我們上面提到的monkeySocket.在繼續之前這里我們先整理下思路,結合上一篇文章,我們看到幾個重要的類的初始化流程是這樣的:
- MonkeyRunner在啟動的時候會先啟動MonkeyRunnerStarter這個類,該類的構造函數調用ChimpChat的getInstance方法實例化ChimpChat.
- ChimpChat的getInstance方法會先實例化AdbBackend這個類,然后構建 ChimpChat自身這個實例
- 用戶調用MonkeyRunner.waitForConnection()方法初始化MonkeyDevice
- 以上的waitForConnection()又調用的是ChimpChat的waitforConnection()方法
- ChimpChat的waitForConnection方法調用的是AdbBackend的waitForConnection方法最終會findAttachedDevice找到目標設備然后用該設備初始化AdbChimpDevice
根據以上的流程我們就很清晰AdbChimpDevice其實在測試腳本一調用MonkeyRunner.waitForConnection方法的時候就已經會初始化的了,也就是說ChimpManager也在這個時候已經初始化的了。
好,那么我們繼續看AdbChimpDevice里面的方法createManager是如何對ChimpManager進行初始化的:
~~~
/* */ private ChimpManager createManager(String address, int port) {
/* */ try {
/* 125 */ this.device.createForward(port, port);
/* */ } catch (TimeoutException e) {
/* 127 */ LOG.log(Level.SEVERE, "Timeout creating adb port forwarding", e);
/* 128 */ return null;
/* */ } catch (AdbCommandRejectedException e) {
/* 130 */ LOG.log(Level.SEVERE, "Adb rejected adb port forwarding command: " + e.getMessage(), e);
/* 131 */ return null;
/* */ } catch (IOException e) {
/* 133 */ LOG.log(Level.SEVERE, "Unable to create adb port forwarding: " + e.getMessage(), e);
/* 134 */ return null;
/* */ }
/* */
/* 137 */ String command = "monkey --port " + port;
/* 138 */ executeAsyncCommand(command, new LoggingOutputReceiver(LOG, Level.FINE));
/* */
/* */ try
/* */ {
/* 142 */ Thread.sleep(1000L);
/* */ } catch (InterruptedException e) {
/* 144 */ LOG.log(Level.SEVERE, "Unable to sleep", e);
/* */ }
/* */ InetAddress addr;
/* */ try
/* */ {
/* 149 */ addr = InetAddress.getByName(address);
/* */ } catch (UnknownHostException e) {
/* 151 */ LOG.log(Level.SEVERE, "Unable to convert address into InetAddress: " + address, e);
/* 152 */ return null;
/* */ }
/* */
/* */
/* */
/* */
/* */
/* 159 */ boolean success = false;
/* 160 */ ChimpManager mm = null;
/* 161 */ long start = System.currentTimeMillis();
/* */
/* 163 */ while (!success) {
/* 164 */ long now = System.currentTimeMillis();
/* 165 */ long diff = now - start;
/* 166 */ if (diff > 30000L) {
/* 167 */ LOG.severe("Timeout while trying to create chimp mananger");
/* 168 */ return null;
/* */ }
/* */ try
/* */ {
/* 172 */ Thread.sleep(1000L);
/* */ } catch (InterruptedException e) {
/* 174 */ LOG.log(Level.SEVERE, "Unable to sleep", e);
/* */ }
/* */ Socket monkeySocket;
/* */ try
/* */ {
/* 179 */ monkeySocket = new Socket(addr, port);
/* */ } catch (IOException e) {
/* 181 */ LOG.log(Level.FINE, "Unable to connect socket", e);
/* 182 */ success = false; }
/* 183 */ continue;
/* */
/* */ try
/* */ {
/* 187 */ mm = new ChimpManager(monkeySocket);
/* */ } catch (IOException e) {
/* 189 */ LOG.log(Level.SEVERE, "Unable to open writer and reader to socket"); }
/* 190 */ continue;
/* */
/* */ try
/* */ {
/* 194 */ mm.wake();
/* */ } catch (IOException e) {
/* 196 */ LOG.log(Level.FINE, "Unable to wake up device", e);
/* 197 */ success = false; }
/* 198 */ continue;
/* */
/* 200 */ success = true;
/* */ }
/* */
/* 203 */ return mm;
/* */ }
~~~
這個方法比較長,但大體做的事情如下:
- 通過調用ddmlib的device類里面的createForward方法來把主機pc端本地的端口轉發給目標機器端的monkey監聽端口,這樣子做的好處是我們通過直接連接主機pc端的轉發端口發送命令就會等同于通過網絡連接上目標機器的monkey監聽端口來發送monkey命令
- 調用executeAsyncCommand方法發送異步adb shell命令 “monkey -port"到目標機器開啟monkey并監聽以上描述的端口
- 創建連接到主機pc對應目標設備monkey監聽端口的monkeySocket
- 把該monkeySocket傳遞到本章節開頭說的ChimpManager構造函數對ChimpManager進行實例化
分析到這里我們可以看到monkey已經在目標機器起來了,那么我們就需要去分析MonkeyRunner是如何發送monkey命令過去控制設備的了。這里我們會以典型的press這個方法作為例子來進行闡述。
我們先看AdbChimpDevice里面的press方法:
~~~
/* */ public void press(String keyName, TouchPressType type)
/* */ {
/* */ try
/* */ {
/* 326 */ switch (3.$SwitchMap$com$android$chimpchat$core$TouchPressType[type.ordinal()]) {
/* */ case 1:
/* 328 */ this.manager.press(keyName);
/* 329 */ break;
/* */ case 2:
/* 331 */ this.manager.keyDown(keyName);
/* 332 */ break;
/* */ case 3:
/* 334 */ this.manager.keyUp(keyName);
/* */ }
/* */ }
/* */ catch (IOException e) {
/* 338 */ LOG.log(Level.SEVERE, "Error sending press event: " + keyName + " " + type, e);
/* */ }
/* */ }
~~~
方法很簡單,就是根據不同的按下類型來調用ChimpManager中不同的press的方法,我們這里假設用戶按下的是 DOWN_AND_UP這個類型,也就是說調用的是ChimpMananer里面的press方法:
~~~
/* */ public boolean press(String name)
/* */ throws IOException
/* */ {
/* 135 */ return sendMonkeyEvent("press " + name);
/* */ }
~~~
跟著調用sendMonkeyEvent:
~~~
/* */ private boolean sendMonkeyEvent(String command)
/* */ throws IOException
/* */ {
/* 234 */ synchronized (this) {
/* 235 */ String monkeyResponse = sendMonkeyEventAndGetResponse(command);
/* 236 */ return parseResponseForSuccess(monkeyResponse);
/* */ }
/* */ }
~~~
跟著調用sendMonkeyEventAndGetResponse方法:
~~~
/* */ private String sendMonkeyEventAndGetResponse(String command)
/* */ throws IOException
/* */ {
/* 182 */ command = command.trim();
/* 183 */ LOG.info("Monkey Command: " + command + ".");
/* */
/* */
/* 186 */ this.monkeyWriter.write(command + "\n");
/* 187 */ this.monkeyWriter.flush();
/* 188 */ return this.monkeyReader.readLine();
/* */ }
~~~
以上這幾個方法都是在ChimpManager這個類里面的成員方法。從最后這個sendMonkeyEventAndGetResponse方法我們可以看到它所做的事情就是用我們前面描述的monkeyWritter和monkeyReader這兩個成員變量往主機pc這邊的終會轉發給目標機器monkey那個端口(其實就是上面的monkeySocket)進行讀寫操作。
## 3. 發送adb協議請求
請查看《[誰動了我的截圖?--Monkeyrunner takeSnapshot方法源碼跟蹤分析](http://blog.csdn.net/zhubaitian/article/details/40262831)》
## 4. 發送adb shell命令
通過上一篇文章《[誰動了我的截圖?--Monkeyrunner takeSnapshot方法源碼跟蹤分析](http://blog.csdn.net/zhubaitian/article/details/40262831)》的分析,我們知道MonkeyRunner分發不同的設備控制信息是在ChimpChat庫的AdbChimpDevice這個類里面進行的。所以這里我就不會從頭開始分析我們是怎么進入到這個類里面的了,大家不清楚的請先查看上一篇投石問路的文章再返回來看本文。
這里我們嘗試以getSystemProperty這個稍微復雜點的方法為例子分析下MonkeyRunner是真么通過adb shell發送命令的,我們首先定位到AdbChimpDevice的該方法:
~~~
/* */ public String getSystemProperty(String key)
/* */ {
/* 224 */ return this.device.getProperty(key);
/* */ }
~~~
這里的device成員函數指的就是ddmlib庫里面的Device這個類(請查看上一篇文章),那么我們進去該類看下getProperty這個方法:
~~~
/* */ public String getProperty(String name)
/* */ {
/* 379 */ return (String)this.mProperties.get(name);
/* */ }
~~~
該方法直接使用mProperties這個Device類的成員變量的get方法根據property的名字獲得返回值,從定義可以看出這是個map:
~~~
/* 65 */ private final Map<String, String> mProperties = new HashMap();
~~~
且這個map是在初始化Device實例之前就已經定義好的了,因為其構造函數并沒有代碼提及,但是我們可以看到Device類里面有一個函數專門往這個map里面添加property:
~~~
/* */ void addProperty(String label, String value) {
/* 779 */ this.mProperties.put(label, value);
/* */ }
~~~
那么這個addProperty又是在哪里被調用了呢?一番查看后發現是在ddmlib里面的GetPropertyReceiver這個類里面的processNewLines這個方法:
~~~
/* */ public void processNewLines(String[] lines)
/* */ {
/* 49 */ for (String line : lines) {
/* 50 */ if ((!line.isEmpty()) && (!line.startsWith("#")))
/* */ {
/* */
/* */
/* 54 */ Matcher m = GETPROP_PATTERN.matcher(line);
/* 55 */ if (m.matches()) {
/* 56 */ String label = m.group(1);
/* 57 */ String value = m.group(2);
/* */
/* 59 */ if (!label.isEmpty()) {
/* 60 */ this.mDevice.addProperty(label, value);
/* */ }
/* */ }
/* */ }
/* */ }
/* */ }
~~~
給這個map增加所有property的地方是知道了,但是問題是什么時候增加呢?這里我們先賣個關子。
繼續之前我們先要了解下ddmlib這個庫里面的DeviceMonitor這個類,這個類會啟動一個線程來監控所有連接到主機的設備的狀態。
~~~
/* */ boolean start()
/* */ {
/* 715 */ if ((this.mAdbOsLocation != null) && (sAdbServerPort != 0) && ((!this.mVersionCheck) || (!startAdb()))) {
/* 716 */ return false;
/* */ }
/* */
/* 719 */ this.mStarted = true;
/* */
/* */
/* 722 */ this.mDeviceMonitor = new DeviceMonitor(this);
/* 723 */ this.mDeviceMonitor.start();
/* */
/* 725 */ return true;
/* */ }
~~~
線程的啟動是在我們之前見過的AdbDebugBridge里面,一旦adb啟動,就會去調用構造函數去初始化DeviceMonitor實例,并調用實例的上面這個start方法來啟動一個線程。
~~~
/* */ boolean start()
/* */ {
/* 715 */ if ((this.mAdbOsLocation != null) && (sAdbServerPort != 0) && ((!this.mVersionCheck) || (!startAdb()))) {
/* 716 */ return false;
/* */ }
/* */
/* 719 */ this.mStarted = true;
/* */
/* */
/* 722 */ this.mDeviceMonitor = new DeviceMonitor(this);
/* 723 */ this.mDeviceMonitor.start();
/* */
/* 725 */ return true;
/* */ }
~~~
該線程會進行一個無限循環來檢測設備的變動。
~~~
private void deviceMonitorLoop()
/* */ {
/* */ do
/* */ {
/* */ try
/* */ {
/* 161 */ if (this.mMainAdbConnection == null) {
/* 162 */ Log.d("DeviceMonitor", "Opening adb connection");
/* 163 */ this.mMainAdbConnection = openAdbConnection();
/* 164 */ if (this.mMainAdbConnection == null) {
/* 165 */ this.mConnectionAttempt += 1;
/* 166 */ Log.e("DeviceMonitor", "Connection attempts: " + this.mConnectionAttempt);
/* 167 */ if (this.mConnectionAttempt > 10) {
/* 168 */ if (!this.mServer.startAdb()) {
/* 169 */ this.mRestartAttemptCount += 1;
/* 170 */ Log.e("DeviceMonitor", "adb restart attempts: " + this.mRestartAttemptCount);
/* */ }
/* */ else {
/* 173 */ this.mRestartAttemptCount = 0;
/* */ }
/* */ }
/* 176 */ waitABit();
/* */ } else {
/* 178 */ Log.d("DeviceMonitor", "Connected to adb for device monitoring");
/* 179 */ this.mConnectionAttempt = 0;
/* */ }
/* */ }
/* */
/* 183 */ if ((this.mMainAdbConnection != null) && (!this.mMonitoring)) {
/* 184 */ this.mMonitoring = sendDeviceListMonitoringRequest();
/* */ }
/* */
/* 187 */ if (this.mMonitoring)
/* */ {
/* 189 */ int length = readLength(this.mMainAdbConnection, this.mLengthBuffer);
/* */
/* 191 */ if (length >= 0)
/* */ {
/* 193 */ processIncomingDeviceData(length);
/* */
/* */
/* 196 */ this.mInitialDeviceListDone = true;
/* */ }
/* */ }
/* */ }
/* */ catch (AsynchronousCloseException ace) {}catch (TimeoutException ioe)
/* */ {
/* 202 */ handleExpectionInMonitorLoop(ioe);
/* */ } catch (IOException ioe) {
/* 204 */ handleExpectionInMonitorLoop(ioe);
/* */ }
/* 206 */ } while (!this.mQuit);
/* */ }
~~~
一旦發現設備有變動,該循環會立刻調用processIncomingDeviceData這個方法來更新設備信息
~~~
/* */ private void processIncomingDeviceData(int length) throws IOException
/* */ {
/* 298 */ ArrayList<Device> list = new ArrayList();
/* */
/* 300 */ if (length > 0) {
/* 301 */ byte[] buffer = new byte[length];
/* 302 */ String result = read(this.mMainAdbConnection, buffer);
/* */
/* 304 */ String[] devices = result.split("\n");
/* */
/* 306 */ for (String d : devices) {
/* 307 */ String[] param = d.split("\t");
/* 308 */ if (param.length == 2)
/* */ {
/* 310 */ Device device = new Device(this, param[0], IDevice.DeviceState.getState(param[1]));
/* */
/* */
/* */
/* 314 */ list.add(device);
/* */ }
/* */ }
/* */ }
/* */
/* */
/* 320 */ updateDevices(list);
/* */ }
~~~
該方法首先會取得所有的device列表(類似"adb devices -l"命令獲得所有device列表),然后調用updateDevices這個方法來對所有設備信息進行一次更新:
~~~
private void updateDevices(ArrayList<Device> newList)
/* */ {
/* 329 */ synchronized ()
/* */ {
/* */
/* */
/* 333 */ ArrayList<Device> devicesToQuery = new ArrayList();
/* 334 */ synchronized (this.mDevices)
/* */ {
/* */
/* */
/* */
/* */
/* */
/* */
/* */
/* */
/* 344 */ for (int d = 0; d < this.mDevices.size();) {
/* 345 */ Device device = (Device)this.mDevices.get(d);
/* */
/* */
/* 348 */ int count = newList.size();
/* 349 */ boolean foundMatch = false;
/* 350 */ for (int dd = 0; dd < count; dd++) {
/* 351 */ Device newDevice = (Device)newList.get(dd);
/* */
/* 353 */ if (newDevice.getSerialNumber().equals(device.getSerialNumber())) {
/* 354 */ foundMatch = true;
/* */
/* */
/* 357 */ if (device.getState() != newDevice.getState()) {
/* 358 */ device.setState(newDevice.getState());
/* 359 */ device.update(1);
/* */
/* */
/* */
/* 363 */ if (device.isOnline()) {
/* 364 */ if ((AndroidDebugBridge.getClientSupport()) &&
/* 365 */ (!startMonitoringDevice(device))) {
/* 366 */ Log.e("DeviceMonitor", "Failed to start monitoring " + device.getSerialNumber());
/* */ }
/* */
/* */
/* */
/* */
/* 372 */ if (device.getPropertyCount() == 0) {
/* 373 */ devicesToQuery.add(device);
/* */ }
/* */ }
/* */ }
/* */
/* */
/* 379 */ newList.remove(dd);
/* 380 */ break;
/* */ }
/* */ }
/* */
/* 384 */ if (!foundMatch)
/* */ {
/* */
/* 387 */ removeDevice(device);
/* 388 */ this.mServer.deviceDisconnected(device);
/* */ }
/* */ else {
/* 391 */ d++;
/* */ }
/* */ }
/* */
/* */
/* */
/* 397 */ for (Device newDevice : newList)
/* */ {
/* 399 */ this.mDevices.add(newDevice);
/* 400 */ this.mServer.deviceConnected(newDevice);
/* */
/* */
/* 403 */ if ((AndroidDebugBridge.getClientSupport()) &&
/* 404 */ (newDevice.isOnline())) {
/* 405 */ startMonitoringDevice(newDevice);
/* */ }
/* */
/* */
/* */
/* 410 */ if (newDevice.isOnline()) {
/* 411 */ devicesToQuery.add(newDevice);
/* */ }
/* */ }
/* */ }
/* */
/* */
/* 417 */ for (Device d : devicesToQuery) {
/* 418 */ queryNewDeviceForInfo(d);
/* */ }
/* */ }
/* 421 */ newList.clear();
/* */ }
~~~
該方法我們關注的是最后面它會循環每個設備,然后調用queryNewDeviceForInfo這個方法去更新每個設備所有的porperty信息。
~~~
/* */ private void queryNewDeviceForInfo(Device device)
/* */ {
/* */ try
/* */ {
/* 446 */ device.executeShellCommand("getprop", new GetPropReceiver(device));
/* */
/* */
/* 449 */ queryNewDeviceForMountingPoint(device, "EXTERNAL_STORAGE");
/* 450 */ queryNewDeviceForMountingPoint(device, "ANDROID_DATA");
/* 451 */ queryNewDeviceForMountingPoint(device, "ANDROID_ROOT");
/* */
/* */
/* 454 */ if (device.isEmulator()) {
/* 455 */ EmulatorConsole console = EmulatorConsole.getConsole(device);
/* 456 */ if (console != null) {
/* 457 */ device.setAvdName(console.getAvdName());
/* 458 */ console.close();
/* */ }
/* */ }
/* */ } catch (TimeoutException e) {
/* 462 */ Log.w("DeviceMonitor", String.format("Connection timeout getting info for device %s", new Object[] { device.getSerialNumber() }));
/* */
/* */ }
/* */ catch (AdbCommandRejectedException e)
/* */ {
/* 467 */ Log.w("DeviceMonitor", String.format("Adb rejected command to get device %1$s info: %2$s", new Object[] { device.getSerialNumber(), e.getMessage() }));
/* */
/* */ }
/* */ catch (ShellCommandUnresponsiveException e)
/* */ {
/* 472 */ Log.w("DeviceMonitor", String.format("Adb shell command took too long returning info for device %s", new Object[] { device.getSerialNumber() }));
/* */
/* */ }
/* */ catch (IOException e)
/* */ {
/* 477 */ Log.w("DeviceMonitor", String.format("IO Error getting info for device %s", new Object[] { device.getSerialNumber() }));
/* */ }
/* */ }
~~~
到了這里我們終于看到了該方法調用了一個ddmlib庫的device類里面的executeShellCommand方法來執行‘getprop'這個命令。到目前位置我們達到的目的是知道了getSystemProperty這個MonkeyDevice的api最終確實是通過發送'adb shell getporp‘命令來獲得設備屬性的。
但這里遺留了兩個問題
- 一個是之前提到的GetPropertyReceiver這個類里面的增加property的processNewLines方法是在哪里調用的
- 一個是executeShellCommand究竟是怎么工作的
各位看官不用著急,且看我們往下分析,很快就會水落石出了。我們繼續跟蹤executeShellCommand這個方法,在我們的例子中其以命令'getprop'和new的GetPropertyReceiver對象實例為參數,最終會調用到Device這個類里面的executeShellCommand這個方法。注意這個GetPropertyReceiver很重要,我們往后會看到。
~~~
/* */ public void executeShellCommand(String command, IShellOutputReceiver receiver, int maxTimeToOutputResponse)
/* */ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException
/* */ {
/* 618 */ AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this, receiver, maxTimeToOutputResponse);
/* */ }
~~~
方法中繼續把調用直接拋給AdbHelper這個工具類,
~~~
/* */ static void executeRemoteCommand(InetSocketAddress adbSockAddr, String command, IDevice device, IShellOutputReceiver rcvr, long maxTimeToOutputResponse, TimeUnit maxTimeUnits)
/* */ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException
/* */ {
/* 378 */ long maxTimeToOutputMs = 0L;
/* 379 */ if (maxTimeToOutputResponse > 0L) {
/* 380 */ if (maxTimeUnits == null) {
/* 381 */ throw new NullPointerException("Time unit must not be null for non-zero max.");
/* */ }
/* 383 */ maxTimeToOutputMs = maxTimeUnits.toMillis(maxTimeToOutputResponse);
/* */ }
/* */
/* 386 */ Log.v("ddms", "execute: running " + command);
/* */
/* 388 */ SocketChannel adbChan = null;
/* */ try {
/* 390 */ adbChan = SocketChannel.open(adbSockAddr);
/* 391 */ adbChan.configureBlocking(false);
/* */
/* */
/* */
/* */
/* 396 */ setDevice(adbChan, device);
/* */
/* 398 */ byte[] request = formAdbRequest("shell:" + command);
/* 399 */ write(adbChan, request);
/* */
/* 401 */ AdbResponse resp = readAdbResponse(adbChan, false);
/* 402 */ if (!resp.okay) {
/* 403 */ Log.e("ddms", "ADB rejected shell command (" + command + "): " + resp.message);
/* 404 */ throw new AdbCommandRejectedException(resp.message);
/* */ }
/* */
/* 407 */ byte[] data = new byte['?'];
/* 408 */ ByteBuffer buf = ByteBuffer.wrap(data);
/* 409 */ long timeToResponseCount = 0L;
/* */
/* */ for (;;)
/* */ {
/* 413 */ if ((rcvr != null) && (rcvr.isCancelled())) {
/* 414 */ Log.v("ddms", "execute: cancelled");
/* 415 */ break;
/* */ }
/* */
/* 418 */ int count = adbChan.read(buf);
/* 419 */ if (count < 0)
/* */ {
/* 421 */ rcvr.flush();
/* 422 */ Log.v("ddms", "execute '" + command + "' on '" + device + "' : EOF hit. Read: " + count);
/* */
/* 424 */ break; }
/* 425 */ if (count == 0) {
/* */ try {
/* 427 */ int wait = 25;
/* 428 */ timeToResponseCount += wait;
/* 429 */ if ((maxTimeToOutputMs > 0L) && (timeToResponseCount > maxTimeToOutputMs)) {
/* 430 */ throw new ShellCommandUnresponsiveException();
/* */ }
/* 432 */ Thread.sleep(wait);
/* */ }
/* */ catch (InterruptedException ie) {}
/* */ }
/* */ else {
/* 437 */ timeToResponseCount = 0L;
/* */
/* */
/* 440 */ if (rcvr != null) {
/* 441 */ rcvr.addOutput(buf.array(), buf.arrayOffset(), buf.position());
/* */ }
/* 443 */ buf.rewind();
/* */ }
/* */ }
/* */ } finally {
/* 447 */ if (adbChan != null) {
/* 448 */ adbChan.close();
/* */ }
/* 450 */ Log.v("ddms", "execute: returning");
/* */ }
/* */ }
~~~
方法中先創建一個面向adb服務器的socket通道,然后通過發送adb協議請求的'shell:'命令獲得一個adb shell然后再把相應的adb shell命令發送到該socket。從這里可以看到,“發送adb shell命令“其實是基于”發送adb協議請求“的,因為在發送命令之前需要先通過組織基于adb協議的請求”shell:“來獲得adb shell。對比上一篇文章《[誰動了我的截圖?--Monkeyrunner takeSnapshot方法源碼跟蹤分析](http://blog.csdn.net/zhubaitian/article/details/40262831)》我們可以看到“發送adb協議請求”跟“發送adb shell命名”的最大區別就是:
- 發送adb協議請求:不需要初始化adb shell,直接通過構造基于adb協議的請求把命令發送出去給adb服務器。
- 發送adb shell命令:每個命令都需要先發送“adb協議請求”的“shell:”來先建立一個adb shell,然后才能夠發送命令到adb服務器,再由adb服務器轉發到設備端的adb守護進程或者服務。
發送完請求后最終會調用rcvr.addOutput(buf.array(),buf.arrayOffset(),?buf.position())這個方法,這里的rcvr就是通過參數傳進來的我們上面提到的很重要的那個GetPropertyReceiver,那么我們去看下該類下面的addOutput究竟是怎么處理返回信息的,這里要查看的是GetPropertyReceiver父類MultiLineReceiver類的成員函數addOutPut:
~~~
/* */ public final void addOutput(byte[] data, int offset, int length)
/* */ {
/* 53 */ if (!isCancelled()) {
/* 54 */ String s = new String(data, offset, length, Charsets.UTF_8);
/* */
/* */
/* */
/* 58 */ if (this.mUnfinishedLine != null) {
/* 59 */ s = this.mUnfinishedLine + s;
/* 60 */ this.mUnfinishedLine = null;
/* */ }
/* */
/* */
/* 64 */ this.mArray.clear();
/* 65 */ int start = 0;
/* */ for (;;) {
/* 67 */ int index = s.indexOf("\r\n", start);
/* */
/* */
/* */
/* 71 */ if (index == -1) {
/* 72 */ this.mUnfinishedLine = s.substring(start);
/* 73 */ break;
/* */ }
/* */
/* */
/* */
/* 78 */ String line = s.substring(start, index);
/* 79 */ if (this.mTrimLines) {
/* 80 */ line = line.trim();
/* */ }
/* 82 */ this.mArray.add(line);
/* */
/* */
/* 85 */ start = index + 2;
/* */ }
/* */
/* 88 */ if (!this.mArray.isEmpty())
/* */ {
/* */
/* 91 */ String[] lines = (String[])this.mArray.toArray(new String[this.mArray.size()]);
/* */
/* */
/* 94 */ processNewLines(lines);
/* */ }
/* */ }
/* */ }
~~~
這個函數所作的事情就是把'adb shell getprop‘返回的所有信息一行一行的進行處理,注意最終處理的函數就是processNewLines。還記得這個函數吧?這個就是我們上面提到的GetPropertyReceiver這個類中用來往mProperties這個map增加property的了。迄今為止我們算是把以上留下了兩個疑問給解決完了
<table cellspacing="0" cellpadding="0" width="539" class=" " style="margin:0px 0px 10px; padding:0px; border-collapse:collapse; width:668px; max-width:100%; word-wrap:break-word!important"><tbody style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><tr style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><td valign="top" width="112" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important">?</td></tr><tr style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><td valign="top" width="111" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">作者</span></p></td><td valign="top" width="112" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">自主博客</span></p></td><td valign="top" width="111" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">微信</span></p></td><td valign="top" width="112" height="13" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(190,192,191)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important">CSDN</span></p></td></tr><tr style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"><td valign="top" width="111" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important; background-color:rgb(227,228,228)"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">天地會珠海分舵</span></p></td><td valign="top" width="112" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; font-size:11px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important"><a target="_blank" href="http://techgogogo.com/">http://techgogogo.com</a></span><span style="margin:0px; padding:0px; max-width:100%; font-family:Helvetica; font-size:11px; letter-spacing:0px; word-wrap:break-word!important"/></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:14px; white-space:pre-wrap; font-family:Helvetica; word-wrap:break-word!important"><br style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important"/></p></td><td valign="top" width="111" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">服務號</span><span style="margin:0px; padding:0px; max-width:100%; font-size:10px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important">:TechGoGoGo</span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; word-wrap:break-word!important">掃描碼</span><span style="margin:0px; padding:0px; max-width:100%; font-size:10px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important">:</span></p><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:14px; white-space:pre-wrap; font-family:Helvetica; word-wrap:break-word!important"><img src="image/47cf4f9ec59b0ef1f807a6c33ab5ce5f.jpg" alt="" style="max-width:100%; margin:0px; padding:0px; height:auto!important; word-wrap:break-word!important; width:auto!important; visibility:visible!important"/></p></td><td valign="top" width="112" height="39" style="border-style:solid; border-color:rgb(0,0,0); margin:0px; padding:4px; word-break:break-all; max-width:100%; word-wrap:break-word!important"><p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; max-width:100%; clear:both; min-height:1em; white-space:pre-wrap; color:rgb(62,62,62); font-family:'Helvetica Neue',Helvetica,'Hiragino Sans GB','Microsoft YaHei',?¢èí??oú,Arial,sans-serif; font-size:18px; line-height:28.7999992370605px; word-wrap:break-word!important"><span style="margin:0px; padding:0px; max-width:100%; color:rgb(0,0,0); font-size:11px; font-family:Helvetica; letter-spacing:0px; word-wrap:break-word!important"><a target="_blank" href="http://blog.csdn.net/zhubaitian">http://blog.csdn.net/zhubaitian</a></span><span style="margin:0px; padding:0px; max-width:100%; color:rgb(0,0,0); font-family:Helvetica; font-size:11px; letter-spacing:0px; line-height:28.7999992370605px; word-wrap:break-word!important"/></p><div><span style="margin:0px; padding:0px; max-width:100%; color:rgb(0,0,0); font-family:Helvetica; font-size:11px; letter-spacing:0px; line-height:28.7999992370605px; word-wrap:break-word!important"><br/></span></div></td></tr></tbody></table>
- 前言
- MonkeyRunner創建一個Note的實例
- MonkeyRunner在Windows下的Eclipse開發環境搭建步驟(兼解決網上Jython配置出錯的問題)
- MonkenRunner通過HierarchyViewer定位控件的方法和建議(Appium/UIAutomator/Robotium姊妹篇)
- MonkeyDevcie API 實踐全記錄
- MonkeyImage API 實踐全記錄
- EasyMonkeyDevice vs MonkeyDevice&amp;HierarchyViewer API Mapping Matrix
- adb概覽及協議參考
- MonkeyRunner源碼分析之-誰動了我的截圖?
- MonkeyRunner源碼分析之與Android設備通訊方式
- MonkeyRunner源碼分析之啟動
- Monkey源碼分析之運行流程
- Monkey源碼分析之事件源
- Monkey源碼分析番外篇之WindowManager注入事件如何跳出進程間安全限制
- Monkey源碼分析番外篇之Android注入事件的三種方法比較
- Monkey源碼分析之事件注入
- monkey源碼分析之事件注入方法變化
- MonkeyRunner源碼分析之工作原理圖
- Android自動化測試框架新書:&lt;&lt;MonnkeyRunner實現原理剖析&gt;&gt;交流