# 感慨
經過三個月的蹉跎,項目終于可以推出1.0版本。中間經歷過很多坑,中途我們的主程離職走了,我硬著頭皮接替了他的工作,從cts框架的啟動開始,一點一點地研究源碼,debug來debug去,一點一點的理解其中的思想,到現在已經能在cts的框架的基礎上做二次開發,能簡單的認識到cts處理方式。很有幸我一進入自動化領域首先認識的是cts這套框架,隨著研究的深入越來越佩服開發這套框架的google工程師們。我想說的是,做自動化框架開發的人都應該好好研究這個框架,肯定會受益匪淺。其實在學習的時候,我就已經寫過好幾篇文章,我也將其整理成合集,放到了[testerhome](http://testerhome.com/topics/1808)上。但那個時候畢竟還是懵懂時期,也沒有跳出框架從全局來考慮,現在剛好有點時間,慢慢的把這幾個月的研究成果總結一下。
# 設備管理的重要性
做Android自動化工具開發的都了解,你首先要解決的問題是設備管理問題,在支持 Mult Device的工具中尤其重要。新設備的加入、已有設備的斷線離線,在執行case的過程中遇到設備離線了如何去恢復等等,都是在設備管理范疇之內的。那么cts是如何做到的?
## 1.包裹ADB
~~~
package com.android.tradefed.device;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
import com.android.ddmlib.IDevice;
/**
* A wrapper that directs {@link IAndroidDebugBridge} calls to the 'real'
* {@link AndroidDebugBridge}.
*/
class AndroidDebugBridgeWrapper implements IAndroidDebugBridge {
private AndroidDebugBridge mAdbBridge = null;
/**
* Creates a {@link AndroidDebugBridgeWrapper}.
*/
AndroidDebugBridgeWrapper() {
}
/**
* {@inheritDoc}
*/
@Override
public IDevice[] getDevices() {
if (mAdbBridge == null) {
throw new IllegalStateException("getDevices called before init");
}
return mAdbBridge.getDevices();
}
/**
* {@inheritDoc}
*/
@Override
public void addDeviceChangeListener(IDeviceChangeListener listener) {
AndroidDebugBridge.addDeviceChangeListener(listener);
}
/**
* {@inheritDoc}
*/
@Override
public void removeDeviceChangeListener(IDeviceChangeListener listener) {
AndroidDebugBridge.removeDeviceChangeListener(listener);
}
/**
* {@inheritDoc}
*/
@Override
public void init(boolean clientSupport, String adbOsLocation) {
AndroidDebugBridge.init(clientSupport);
mAdbBridge = AndroidDebugBridge.createBridge(adbOsLocation, false);
}
/**
* {@inheritDoc}
*/
@Override
public void terminate() {
AndroidDebugBridge.terminate();
}
/**
* {@inheritDoc}
*/
@Override
public void disconnectBridge() {
AndroidDebugBridge.disconnectBridge();
}
}
~~~
這里實際上用到了代理模式。cts中自定義的類`AndroidDebugBridgeWrapper`包裹了`AndroidDebugBridge`,我們只需要和`AndroidDebugBridgeWrapper`交互就行了。然后在`AndroidDebugBridge`的基礎上自定義了一些方法。繼承的方法中重要的是`addDeviceChangeListener`和`removeDeviceChangeListener`這兩個方法,待會我們就要用到。
## 2.啟動ADB
~~~
public class DeviceManager implements IDeviceManager {
......
private IAndroidDebugBridge mAdbBridge;
private ManagedDeviceListener mManagedDeviceListener;
......
/**
* The DeviceManager should be retrieved from the {@link GlobalConfiguration}
*/
public DeviceManager() {
}
/**
* Initialize the device manager. This must be called once and only once before any other
* methods are called.
*/
synchronized void init(IDeviceSelection globalDeviceFilter,
List<IDeviceMonitor> globalDeviceMonitors, IManagedTestDeviceFactory deviceFactory) {
......
mAdbBridge = createAdbBridge();
mManagedDeviceListener = new ManagedDeviceListener();
......
mAdbBridge.addDeviceChangeListener(mManagedDeviceListener);
......
mAdbBridge.init(false /* client support */, "adb");
......
}
/**
* Creates the {@link IAndroidDebugBridge} to use.
* <p/>
* Exposed so tests can mock this.
* @returns the {@link IAndroidDebugBridge}
*/
synchronized IAndroidDebugBridge createAdbBridge() {
return new AndroidDebugBridgeWrapper();
}
}
~~~
在`DeviceManage`類的`init`方法中,首先通過`createAdbBridge()`方法創建一個`IAndroidDebugBridge`對象,其實質是剛才定義的`AndroidDebugBridgeWrapper`對象。這樣的話我們就得到了該對象的一個實例,接著我們調用了該實例的`init`方法(其實有2行代碼我故意忽略了,后面會隆重登場),這樣`ADB`的初始化工作就完成了。
## 3.狀態監聽器
~~~
private class ManagedDeviceListener implements IDeviceChangeListener {
/**
* {@inheritDoc}
*/
@Override
public void deviceChanged(IDevice idevice, int changeMask) {
......
}
/**
* {@inheritDoc}
*/
@Override
public void deviceConnected(IDevice idevice) {
......
}
/**
* {@inheritDoc}
*/
@Override
public void deviceDisconnected(IDevice disconnectedDevice) {
......
}
}
~~~
在`DeviceManager`類中定義了一個私有類`ManagedDeviceListener`,該類實現了`ADB`中的接口`IDeviceChangeListener`。該接口實際上是觀察者模式中的一個抽象觀察者,我們定義的`ManagedDeviceListener`類是一個具體觀察者。當我們注冊為設備狀態的觀察者后,設備狀態發生變化后,我們會被通知到。這個時候我們隆重請出剛才我們忽略的2行代碼:
~~~
mManagedDeviceListener = new ManagedDeviceListener();
......
mAdbBridge.addDeviceChangeListener(mManagedDeviceListener);
~~~
這兩行代碼首先初始化了一個設備狀態的具體觀察者對象的實例,然后將其添加到通知列表中,這個時候`ADB`設備發生改變后,就會通知我們的對象,其中相應的三個方法`deviceChanged`,`deviceConnected`,`deviceDisconnected`會被調用,這個時候我們就可以通過一些處理得到新加入的設備,或者已有設備中離線的設備,然后將其刪除。這樣我們就能很好的監聽著設備狀態的改變。
## 4.得到設備
既然我們能準確的監聽著設備狀態的改變,我們就要用一個(或許是多個)容器去保存這些設備。具體的操作流程我覺得單獨寫一篇文章來講比較好,這樣才能對得起它良好的設計。
- 前言
- (1)-windows下cts配置
- (2)-cts調試環境的搭建
- (3)-基礎庫tradefederation配置
- (4)-任務的添加
- (5)-9大組件配置
- (6)-任務的執行
- (7)-任務執行的調度室
- (8)-IBuildProvider
- (9)-IDeviceRecovery
- (10)-TestDeviceOptions
- (11)-ICommandOptions
- (12)-ITargetPreparer
- (13)-任務執行過程
- (14)-任務執行過程
- (15)-任務執行完
- (16)-logcat信息收集系統
- (17)-fastboot狀態監聽器
- (18)-設備恢復
- (19)-設備狀態的分類以及恢復模式的分類
- (20)-cts自身log系統
- (21)-測試結果收集系統
- (22)-自動檢測設備
- (23)-設備分類
- (24)-case的組織