Android CTS CTS 设备管理之自动检测设备

易寒 · 2015年01月13日 · 最后由 berylyl 回复于 2016年09月26日 · 2950 次阅读
本帖已被设为精华帖!

感慨

经过三个月的蹉跎,项目终于可以推出 1.0 版本。中间经历过很多坑,中途我们的主程离职走了,我硬着头皮接替了他的工作,从 cts 框架的启动开始,一点一点地研究源码,debug 来 debug 去,一点一点的理解其中的思想,到现在已经能在 cts 的框架的基础上做二次开发,能简单的认识到 cts 处理方式。很有幸我一进入自动化领域首先认识的是 cts 这套框架,随着研究的深入越来越佩服开发这套框架的 google 工程师们。我想说的是,做自动化框架开发的人都应该好好研究这个框架,肯定会受益匪浅。其实在学习的时候,我就已经写过好几篇文章,我也将其整理成合集,放到了testerhome上。但那个时候毕竟还是懵懂时期,也没有跳出框架从全局来考虑,现在刚好有点时间,慢慢的把这几个月的研究成果总结一下。

设备管理的重要性

做 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的基础上自定义了一些方法。继承的方法中重要的是addDeviceChangeListenerremoveDeviceChangeListener这两个方法,待会我们就要用到。

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.得到设备

既然我们能准确的监听着设备状态的改变,我们就要用一个 (或许是多个) 容器去保存这些设备。具体的操作流程我觉得单独写一篇文章来讲比较好,这样才能对得起它良好的设计。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 5 条回复 时间 点赞

cts 的确被很多人忽略了。

#1 楼 @lihuazhang 做 rom 的公司会意识到这个工具,其实做工具的,不管是针对 app 还是 rom,应该都能从中找到有用的东西。

#2 楼 @doctorq CTS 里面有很多的代码和架构很值得学习啊~

#3 楼 @monkey 是啊,前辈,所以我想着写点文字把这些东西放到大家的面前,让大家了解了解。

易寒 [该话题已被删除] 中提及了此贴 06月29日 17:52
易寒 [该话题已被删除] 中提及了此贴 06月29日 17:52
恒温 [该话题已被删除] 中提及了此贴 06月29日 17:52

智商不够看不懂。cts 和 ddmlib 是一个东西吗

恒温 Android CTS 合集 中提及了此贴 11月24日 17:04
易寒 CTS 框架解析 中提及了此贴 01月16日 15:34
易寒 CTS 设备管理之设备分类 中提及了此贴 01月20日 00:13
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册