• 自动化预备知识上&&下Android自动化测试学历历程


    主要讲解内容及笔记:

    一、需要具备的能力:

    测试一年,编程一年,熟悉并掌握业界自动化测试工具(monkey--压力测试、monkeyrunner--基于坐标点的可用作功能测试和回归测试、robotium、UIAutomator-google2013年推出的基于控件的框架),Python脚本写过自动化

    二、希望具备能力:

    1、linux命令(上学学过,但是忘记了,需要回顾和使用)

    2、会android简单开发(只是停留在超级基础阶段,还需要看教程)

    3、会eclipse插件开发(需要查看资料,自我学习)

    三、业界自动化框架(需要自学)

    1、基于坐标点触屏:monkeyrunner、北京播思自研工具

    2、基于随机流的单元测试:CTS(针对android的framework的测试,防止把android架构改的面目全非)、Monkey(命令:adb monkey -p -v)

    3、基于元素图形对比:SeeTest(网址:http://experitest.com)、I-Test

    4、腾讯Bita(bita.qq.com)和GT(gt.tencent.com,关注性能测试)

    5、百度云和ITestIn(http://testin.cn)、阿里巴巴(TMTS)

    6、基于控件信息:Robotium+Junit4框架、东舟Smart-Robot、美国风河公司:wind test managerment

    7、NativeDriver和Selenium(已经被UIAutomator替代)

    四、ADB详解

    1、ADB——官网文档(PORT:TCP 5037)

    ADB(android debug bridge)即调试桥接,是一种命令行工具,可以与你的模拟器或者是andorid设备进行通讯,包括三部分组成:

    (1)是一个客户端,可以运行在你的开发机上

    (2)是一个服务器,以后台形式运行在你的开发机上,当一个server启动后,它就会绑定TCP的5037端口并且监听从adb客户端发出的请求 ——所有的adb客户端都使用这个端口5037来与server进行通信,如果安装了其他如腾讯手机助手啊之类的,把这个端口占用了,就会导致adb不可 用,就需要通过kill servers将其杀掉

    (3)是一个守护进程,使得每一个模拟器或者设备的实例都能够运行在后台

    adb.exe的具体位置:安装程序/sdk/platform-tools,如D:\Program Files\adt-bundle-windows-x86-20130717\sdk\platform-tools

    2、测试ADB

    adb命令行:

    (1)adb devices     #查看设备列表

    问题:这里提示unauthorized?为什么?

    没有授权,也就是说手机连接电脑后提示的USB调试的授权,点击确定后,就能够被识别,不行就多试几次

    但是为什么用手机助手就能够装上呢?他怎么处理的未授权的问题呢?

    (2)adb install 拖进来的apk文件    #安装apk文件

    如:abd install wifinext.apk,之后会提示安装进度和success,即提示成功了

    (3)adb uninstall 已经安装的apk文件    #卸载apk文件

    adb uninstall wifinext.apk,之后会提示Failure

    原因在于安装后的包名已将改变,变为AndroidMainifest.xml文件中<manifest>节点下,package元素所指定的名字

    因此使用:adb uninstall com.qihoo.linker ,之后提示success

    (4)adb push 拖进来的一个文件  /data/local/tmp     #将某文件push进一个目录下

    作用:可以测试当空间被占满之类的情况下程序的运行情况,如可以拖进来一个很大的程序,关注内存等

    (5)adb pull          #与push相对,将文件拉出

    如:adb pull  /data/local/tmp/xxx.apk    C://

    (6)adb kill-server

    (7)adb shell之后出现的$:表示没有被root,是#:表示被root

    3、AndroidDebugBridge源码详解

    ADB的源码位置:D:\Program Files\adt-bundle-windows-x86-20130717\sdk\tools\lib\ddmlib.jar

    就是要包含这个ddmlib.jar,具体如何理解:

    http://stackoverflow.com/questions/17381324/how-to-tell-if-android-device-detected-by-adb

    这个是在stackoverflow上的一个问答:关于如何才能知道android设备是否连接通过adb?

    查看一下androiddebugbridge的源码,能够看到里面有一个createbrige的方法,源代码如下:

    能够搜索到有两个createbridge方法,一种是createbridge()方法,该方法会判断是否存在一个adb连接,是则将其返回;

    另一种是createbridge(String osLocation, boolean forceNewBridge)

    该方法会生成一个新的adb连接,不论原来是否存在

    复制代码
       1 /*
       2  * Copyright (C) 2007 The Android Open Source Project
       3  *
       4  * Licensed under the Apache License, Version 2.0 (the "License");
       5  * you may not use this file except in compliance with the License.
       6  * You may obtain a copy of the License at
       7  *
       8  *      http://www.apache.org/licenses/LICENSE-2.0
       9  *
      10  * Unless required by applicable law or agreed to in writing, software
      11  * distributed under the License is distributed on an "AS IS" BASIS,
      12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13  * See the License for the specific language governing permissions and
      14  * limitations under the License.
      15  */
      16 
      17 package org.athrun.ddmlib;
      18 
      19 
      20 import java.io.BufferedReader;
      21 import java.io.IOException;
      22 import java.io.InputStreamReader;
      23 import java.lang.Thread.State;
      24 import java.net.InetAddress;
      25 import java.net.InetSocketAddress;
      26 import java.net.UnknownHostException;
      27 import java.security.InvalidParameterException;
      28 import java.util.ArrayList;
      29 import java.util.Map;
      30 import java.util.regex.Matcher;
      31 import java.util.regex.Pattern;
      32 
      33 import org.athrun.ddmlib.Log.LogLevel;
      34 
      35 /**
      36  * A connection to the host-side android debug bridge (adb)
      37  * <p/>
      38  * This is the central point to communicate with any devices, emulators, or the
      39  * applications running on them.
      40  * <p/>
      41  * <b>{@link #init(boolean)} must be called before anything is done.</b>
      42  */
      43 public final class AndroidDebugBridge {
      44 
      45     /*
      46      * Minimum and maximum version of adb supported. This correspond to
      47      * ADB_SERVER_VERSION found in //device/tools/adb/adb.h
      48      */
      49 
      50     private final static int ADB_VERSION_MICRO_MIN = 20;
      51     private final static int ADB_VERSION_MICRO_MAX = -1;
      52 
      53     private final static Pattern sAdbVersion = Pattern
      54             .compile("^.*(\\d+)\\.(\\d+)\\.(\\d+)$"); //$NON-NLS-1$
      55 
      56     private final static String ADB = "adb"; //$NON-NLS-1$
      57     private final static String DDMS = "ddms"; //$NON-NLS-1$
      58     private final static String SERVER_PORT_ENV_VAR = "ANDROID_ADB_SERVER_PORT"; //$NON-NLS-1$
      59 
      60     // Where to find the ADB bridge.
      61     final static String ADB_HOST = "127.0.0.1"; //$NON-NLS-1$
      62     final static int ADB_PORT = 5037;
      63 
      64     private static InetAddress sHostAddr;
      65     private static InetSocketAddress sSocketAddr;
      66 
      67     private static AndroidDebugBridge sThis;
      68     private static boolean sInitialized = false;
      69     private static boolean sClientSupport;
      70 
      71     /** Full path to adb. */
      72     private String mAdbOsLocation = null;
      73 
      74     private boolean mVersionCheck;
      75 
      76     private boolean mStarted = false;
      77 
      78     private DeviceMonitor mDeviceMonitor;
      79 
      80     private final static ArrayList<IDebugBridgeChangeListener> sBridgeListeners = new ArrayList<IDebugBridgeChangeListener>();
      81     private final static ArrayList<IDeviceChangeListener> sDeviceListeners = new ArrayList<IDeviceChangeListener>();
      82     private final static ArrayList<IClientChangeListener> sClientListeners = new ArrayList<IClientChangeListener>();
      83 
      84     // lock object for synchronization
      85     private static final Object sLock = sBridgeListeners;
      86 
      87     /**
      88      * Classes which implement this interface provide a method that deals with
      89      * {@link AndroidDebugBridge} changes.
      90      */
      91     public interface IDebugBridgeChangeListener {
      92         /**
      93          * Sent when a new {@link AndroidDebugBridge} is connected.
      94          * <p/>
      95          * This is sent from a non UI thread.
      96          * 
      97          * @param bridge
      98          *            the new {@link AndroidDebugBridge} object.
      99          */
     100         public void bridgeChanged(AndroidDebugBridge bridge);
     101     }
     102 
     103     /**
     104      * Classes which implement this interface provide methods that deal with
     105      * {@link IDevice} addition, deletion, and changes.
     106      */
     107     public interface IDeviceChangeListener {
     108         /**
     109          * Sent when the a device is connected to the {@link AndroidDebugBridge}
     110          * .
     111          * <p/>
     112          * This is sent from a non UI thread.
     113          * 
     114          * @param device
     115          *            the new device.
     116          */
     117         public void deviceConnected(IDevice device);
     118 
     119         /**
     120          * Sent when the a device is connected to the {@link AndroidDebugBridge}
     121          * .
     122          * <p/>
     123          * This is sent from a non UI thread.
     124          * 
     125          * @param device
     126          *            the new device.
     127          */
     128         public void deviceDisconnected(IDevice device);
     129 
     130         /**
     131          * Sent when a device data changed, or when clients are
     132          * started/terminated on the device.
     133          * <p/>
     134          * This is sent from a non UI thread.
     135          * 
     136          * @param device
     137          *            the device that was updated.
     138          * @param changeMask
     139          *            the mask describing what changed. It can contain any of
     140          *            the following values: {@link IDevice#CHANGE_BUILD_INFO},
     141          *            {@link IDevice#CHANGE_STATE},
     142          *            {@link IDevice#CHANGE_CLIENT_LIST}
     143          */
     144         public void deviceChanged(IDevice device, int changeMask);
     145     }
     146 
     147     /**
     148      * Classes which implement this interface provide methods that deal with
     149      * {@link Client} changes.
     150      */
     151     public interface IClientChangeListener {
     152         /**
     153          * Sent when an existing client information changed.
     154          * <p/>
     155          * This is sent from a non UI thread.
     156          * 
     157          * @param client
     158          *            the updated client.
     159          * @param changeMask
     160          *            the bit mask describing the changed properties. It can
     161          *            contain any of the following values:
     162          *            {@link Client#CHANGE_INFO},
     163          *            {@link Client#CHANGE_DEBUGGER_STATUS},
     164          *            {@link Client#CHANGE_THREAD_MODE},
     165          *            {@link Client#CHANGE_THREAD_DATA},
     166          *            {@link Client#CHANGE_HEAP_MODE},
     167          *            {@link Client#CHANGE_HEAP_DATA},
     168          *            {@link Client#CHANGE_NATIVE_HEAP_DATA}
     169          */
     170         public void clientChanged(Client client, int changeMask);
     171     }
     172 
     173     /**
     174      * Initializes the <code>ddm</code> library.
     175      * <p/>
     176      * This must be called once <b>before</b> any call to
     177      * {@link #createBridge(String, boolean)}.
     178      * <p>
     179      * The library can be initialized in 2 ways:
     180      * <ul>
     181      * <li>Mode 1: <var>clientSupport</var> == <code>true</code>.<br>
     182      * The library monitors the devices and the applications running on them. It
     183      * will connect to each application, as a debugger of sort, to be able to
     184      * interact with them through JDWP packets.</li>
     185      * <li>Mode 2: <var>clientSupport</var> == <code>false</code>.<br>
     186      * The library only monitors devices. The applications are left untouched,
     187      * letting other tools built on <code>ddmlib</code> to connect a debugger to
     188      * them.</li>
     189      * </ul>
     190      * <p/>
     191      * <b>Only one tool can run in mode 1 at the same time.</b>
     192      * <p/>
     193      * Note that mode 1 does not prevent debugging of applications running on
     194      * devices. Mode 1 lets debuggers connect to <code>ddmlib</code> which acts
     195      * as a proxy between the debuggers and the applications to debug. See
     196      * {@link Client#getDebuggerListenPort()}.
     197      * <p/>
     198      * The preferences of <code>ddmlib</code> should also be initialized with
     199      * whatever default values were changed from the default values.
     200      * <p/>
     201      * When the application quits, {@link #terminate()} should be called.
     202      * 
     203      * @param clientSupport
     204      *            Indicates whether the library should enable the monitoring and
     205      *            interaction with applications running on the devices.
     206      * @see AndroidDebugBridge#createBridge(String, boolean)
     207      * @see DdmPreferences
     208      */
     209     public static synchronized void init(boolean clientSupport) {
     210         if (sInitialized) {
     211             throw new IllegalStateException(
     212                     "AndroidDebugBridge.init() has already been called.");
     213         }
     214         sInitialized = true;
     215         sClientSupport = clientSupport;
     216 
     217         // Determine port and instantiate socket address.
     218         initAdbSocketAddr();
     219 
     220         MonitorThread monitorThread = MonitorThread.createInstance();
     221         monitorThread.start();
     222 
     223         HandleHello.register(monitorThread);
     224         HandleAppName.register(monitorThread);
     225         HandleTest.register(monitorThread);
     226         HandleThread.register(monitorThread);
     227         HandleHeap.register(monitorThread);
     228         HandleWait.register(monitorThread);
     229         HandleProfiling.register(monitorThread);
     230         HandleNativeHeap.register(monitorThread);
     231     }
     232 
     233     /**
     234      * Terminates the ddm library. This must be called upon application
     235      * termination.
     236      */
     237     public static synchronized void terminate() {
     238         // kill the monitoring services
     239         if (sThis != null && sThis.mDeviceMonitor != null) {
     240             sThis.mDeviceMonitor.stop();
     241             sThis.mDeviceMonitor = null;
     242         }
     243 
     244         MonitorThread monitorThread = MonitorThread.getInstance();
     245         if (monitorThread != null) {
     246             monitorThread.quit();
     247         }
     248 
     249         sInitialized = false;
     250     }
     251 
     252     /**
     253      * Returns whether the ddmlib is setup to support monitoring and interacting
     254      * with {@link Client}s running on the {@link IDevice}s.
     255      */
     256     static boolean getClientSupport() {
     257         return sClientSupport;
     258     }
     259 
     260     /**
     261      * Returns the socket address of the ADB server on the host.
     262      */
     263     public static InetSocketAddress getSocketAddress() {
     264         return sSocketAddr;
     265     }
     266 
     267     /**
     268      * Creates a {@link AndroidDebugBridge} that is not linked to any particular
     269      * executable.
     270      * <p/>
     271      * This bridge will expect adb to be running. It will not be able to
     272      * start/stop/restart adb.
     273      * <p/>
     274      * If a bridge has already been started, it is directly returned with no
     275      * changes (similar to calling {@link #getBridge()}).
     276      * 
     277      * @return a connected bridge.
     278      */
     279     public static AndroidDebugBridge createBridge() {
     280         synchronized (sLock) {
     281             if (sThis != null) {
     282                 return sThis;
     283             }
     284 
     285             try {
     286                 sThis = new AndroidDebugBridge();
     287                 sThis.start();
     288             } catch (InvalidParameterException e) {
     289                 sThis = null;
     290             }
     291 
     292             // because the listeners could remove themselves from the list while
     293             // processing
     294             // their event callback, we make a copy of the list and iterate on
     295             // it instead of
     296             // the main list.
     297             // This mostly happens when the application quits.
     298             IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners
     299                     .toArray(new IDebugBridgeChangeListener[sBridgeListeners
     300                             .size()]);
     301 
     302             // notify the listeners of the change
     303             for (IDebugBridgeChangeListener listener : listenersCopy) {
     304                 // we attempt to catch any exception so that a bad listener
     305                 // doesn't kill our
     306                 // thread
     307                 try {
     308                     listener.bridgeChanged(sThis);
     309                 } catch (Exception e) {
     310                     Log.e(DDMS, e);
     311                 }
     312             }
     313 
     314             return sThis;
     315         }
     316     }
     317 
     318     /**
     319      * Creates a new debug bridge from the location of the command line tool.
     320      * <p/>
     321      * Any existing server will be disconnected, unless the location is the same
     322      * and <code>forceNewBridge</code> is set to false.
     323      * 
     324      * @param osLocation
     325      *            the location of the command line tool 'adb'
     326      * @param forceNewBridge
     327      *            force creation of a new bridge even if one with the same
     328      *            location already exists.
     329      * @return a connected bridge.
     330      */
     331     public static AndroidDebugBridge createBridge(String osLocation,
     332             boolean forceNewBridge) {
     333         synchronized (sLock) {
     334             if (sThis != null) {
     335                 if (sThis.mAdbOsLocation != null
     336                         && sThis.mAdbOsLocation.equals(osLocation)
     337                         && forceNewBridge == false) {
     338                     return sThis;
     339                 } else {
     340                     // stop the current server
     341                     sThis.stop();
     342                 }
     343             }
     344 
     345             try {
     346                 sThis = new AndroidDebugBridge(osLocation);
     347                 sThis.start();
     348             } catch (InvalidParameterException e) {
     349                 sThis = null;
     350             }
     351 
     352             // because the listeners could remove themselves from the list while
     353             // processing
     354             // their event callback, we make a copy of the list and iterate on
     355             // it instead of
     356             // the main list.
     357             // This mostly happens when the application quits.
     358             IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners
     359                     .toArray(new IDebugBridgeChangeListener[sBridgeListeners
     360                             .size()]);
     361 
     362             // notify the listeners of the change
     363             for (IDebugBridgeChangeListener listener : listenersCopy) {
     364                 // we attempt to catch any exception so that a bad listener
     365                 // doesn't kill our
     366                 // thread
     367                 try {
     368                     listener.bridgeChanged(sThis);
     369                 } catch (Exception e) {
     370                     Log.e(DDMS, e);
     371                 }
     372             }
     373 
     374             return sThis;
     375         }
     376     }
     377 
     378     /**
     379      * Returns the current debug bridge. Can be <code>null</code> if none were
     380      * created.
     381      */
     382     public static AndroidDebugBridge getBridge() {
     383         return sThis;
     384     }
     385 
     386     /**
     387      * Disconnects the current debug bridge, and destroy the object.
     388      * <p/>
     389      * This also stops the current adb host server.
     390      * <p/>
     391      * A new object will have to be created with
     392      * {@link #createBridge(String, boolean)}.
     393      */
     394     public static void disconnectBridge() {
     395         synchronized (sLock) {
     396             if (sThis != null) {
     397                 sThis.stop();
     398                 sThis = null;
     399 
     400                 // because the listeners could remove themselves from the list
     401                 // while processing
     402                 // their event callback, we make a copy of the list and iterate
     403                 // on it instead of
     404                 // the main list.
     405                 // This mostly happens when the application quits.
     406                 IDebugBridgeChangeListener[] listenersCopy = sBridgeListeners
     407                         .toArray(new IDebugBridgeChangeListener[sBridgeListeners
     408                                 .size()]);
     409 
     410                 // notify the listeners.
     411                 for (IDebugBridgeChangeListener listener : listenersCopy) {
     412                     // we attempt to catch any exception so that a bad listener
     413                     // doesn't kill our
     414                     // thread
     415                     try {
     416                         listener.bridgeChanged(sThis);
     417                     } catch (Exception e) {
     418                         Log.e(DDMS, e);
     419                     }
     420                 }
     421             }
     422         }
     423     }
     424 
     425     /**
     426      * Adds the listener to the collection of listeners who will be notified
     427      * when a new {@link AndroidDebugBridge} is connected, by sending it one of
     428      * the messages defined in the {@link IDebugBridgeChangeListener} interface.
     429      * 
     430      * @param listener
     431      *            The listener which should be notified.
     432      */
     433     public static void addDebugBridgeChangeListener(
     434             IDebugBridgeChangeListener listener) {
     435         synchronized (sLock) {
     436             if (sBridgeListeners.contains(listener) == false) {
     437                 sBridgeListeners.add(listener);
     438                 if (sThis != null) {
     439                     // we attempt to catch any exception so that a bad listener
     440                     // doesn't kill our
     441                     // thread
     442                     try {
     443                         listener.bridgeChanged(sThis);
     444                     } catch (Exception e) {
     445                         Log.e(DDMS, e);
     446                     }
     447                 }
     448             }
     449         }
     450     }
     451 
     452     /**
     453      * Removes the listener from the collection of listeners who will be
     454      * notified when a new {@link AndroidDebugBridge} is started.
     455      * 
     456      * @param listener
     457      *            The listener which should no longer be notified.
     458      */
     459     public static void removeDebugBridgeChangeListener(
     460             IDebugBridgeChangeListener listener) {
     461         synchronized (sLock) {
     462             sBridgeListeners.remove(listener);
     463         }
     464     }
     465 
     466     /**
     467      * Adds the listener to the collection of listeners who will be notified
     468      * when a {@link IDevice} is connected, disconnected, or when its properties
     469      * or its {@link Client} list changed, by sending it one of the messages
     470      * defined in the {@link IDeviceChangeListener} interface.
     471      * 
     472      * @param listener
     473      *            The listener which should be notified.
     474      */
     475     public static void addDeviceChangeListener(IDeviceChangeListener listener) {
     476         synchronized (sLock) {
     477             if (sDeviceListeners.contains(listener) == false) {
     478                 sDeviceListeners.add(listener);
     479             }
     480         }
     481     }
     482 
     483     /**
     484      * Removes the listener from the collection of listeners who will be
     485      * notified when a {@link IDevice} is connected, disconnected, or when its
     486      * properties or its {@link Client} list changed.
     487      * 
     488      * @param listener
     489      *            The listener which should no longer be notified.
     490      */
     491     public static void removeDeviceChangeListener(IDeviceChangeListener listener) {
     492         synchronized (sLock) {
     493             sDeviceListeners.remove(listener);
     494         }
     495     }
     496 
     497     /**
     498      * Adds the listener to the collection of listeners who will be notified
     499      * when a {@link Client} property changed, by sending it one of the messages
     500      * defined in the {@link IClientChangeListener} interface.
     501      * 
     502      * @param listener
     503      *            The listener which should be notified.
     504      */
     505     public static void addClientChangeListener(IClientChangeListener listener) {
     506         synchronized (sLock) {
     507             if (sClientListeners.contains(listener) == false) {
     508                 sClientListeners.add(listener);
     509             }
     510         }
     511     }
     512 
     513     /**
     514      * Removes the listener from the collection of listeners who will be
     515      * notified when a {@link Client} property changed.
     516      * 
     517      * @param listener
     518      *            The listener which should no longer be notified.
     519      */
     520     public static void removeClientChangeListener(IClientChangeListener listener) {
     521         synchronized (sLock) {
     522             sClientListeners.remove(listener);
     523         }
     524     }
     525 
     526     /**
     527      * Returns the devices.
     528      * 
     529      * @see #hasInitialDeviceList()
     530      */
     531     public IDevice[] getDevices() {
     532         synchronized (sLock) {
     533             if (mDeviceMonitor != null) {
     534                 return mDeviceMonitor.getDevices();
     535             }
     536         }
     537 
     538         return new IDevice[0];
     539     }
     540 
     541     /**
     542      * Returns whether the bridge has acquired the initial list from adb after
     543      * being created.
     544      * <p/>
     545      * Calling {@link #getDevices()} right after
     546      * {@link #createBridge(String, boolean)} will generally result in an empty
     547      * list. This is due to the internal asynchronous communication mechanism
     548      * with <code>adb</code> that does not guarantee that the {@link IDevice}
     549      * list has been built before the call to {@link #getDevices()}.
     550      * <p/>
     551      * The recommended way to get the list of {@link IDevice} objects is to
     552      * create a {@link IDeviceChangeListener} object.
     553      */
     554     public boolean hasInitialDeviceList() {
     555         if (mDeviceMonitor != null) {
     556             return mDeviceMonitor.hasInitialDeviceList();
     557         }
     558 
     559         return false;
     560     }
     561 
     562     /**
     563      * Sets the client to accept debugger connection on the custom
     564      * "Selected debug port".
     565      * 
     566      * @param selectedClient
     567      *            the client. Can be null.
     568      */
     569     public void setSelectedClient(Client selectedClient) {
     570         MonitorThread monitorThread = MonitorThread.getInstance();
     571         if (monitorThread != null) {
     572             monitorThread.setSelectedClient(selectedClient);
     573         }
     574     }
     575 
     576     /**
     577      * Returns whether the {@link AndroidDebugBridge} object is still connected
     578      * to the adb daemon.
     579      */
     580     public boolean isConnected() {
     581         MonitorThread monitorThread = MonitorThread.getInstance();
     582         if (mDeviceMonitor != null && monitorThread != null) {
     583             return mDeviceMonitor.isMonitoring()
     584                     && monitorThread.getState() != State.TERMINATED;
     585         }
     586         return false;
     587     }
     588 
     589     /**
     590      * Returns the number of times the {@link AndroidDebugBridge} object
     591      * attempted to connect to the adb daemon.
     592      */
     593     public int getConnectionAttemptCount() {
     594         if (mDeviceMonitor != null) {
     595             return mDeviceMonitor.getConnectionAttemptCount();
     596         }
     597         return -1;
     598     }
     599 
     600     /**
     601      * Returns the number of times the {@link AndroidDebugBridge} object
     602      * attempted to restart the adb daemon.
     603      */
     604     public int getRestartAttemptCount() {
     605         if (mDeviceMonitor != null) {
     606             return mDeviceMonitor.getRestartAttemptCount();
     607         }
     608         return -1;
     609     }
     610 
     611     /**
     612      * Creates a new bridge.
     613      * 
     614      * @param osLocation
     615      *            the location of the command line tool
     616      * @throws InvalidParameterException
     617      */
     618     private AndroidDebugBridge(String osLocation)
     619             throws InvalidParameterException {
     620         if (osLocation == null || osLocation.length() == 0) {
     621             throw new InvalidParameterException();
     622         }
     623         mAdbOsLocation = osLocation;
     624 
     625         checkAdbVersion();
     626     }
     627 
     628     /**
     629      * Creates a new bridge not linked to any particular adb executable.
     630      */
     631     private AndroidDebugBridge() {
     632     }
     633 
     634     /**
     635      * Queries adb for its version number and checks it against
     636      * {@link #MIN_VERSION_NUMBER} and {@link #MAX_VERSION_NUMBER}
     637      */
     638     private void checkAdbVersion() {
     639         // default is bad check
     640         mVersionCheck = false;
     641 
     642         if (mAdbOsLocation == null) {
     643             return;
     644         }
     645 
     646         try {
     647             String[] command = new String[2];
     648             command[0] = mAdbOsLocation;
     649             command[1] = "version"; //$NON-NLS-1$
     650             Log.d(DDMS,
     651                     String.format("Checking '%1$s version'", mAdbOsLocation)); //$NON-NLS-1$
     652             Process process = Runtime.getRuntime().exec(command);
     653 
     654             ArrayList<String> errorOutput = new ArrayList<String>();
     655             ArrayList<String> stdOutput = new ArrayList<String>();
     656             int status = grabProcessOutput(process, errorOutput, stdOutput,
     657                     true /* waitForReaders */);
     658 
     659             if (status != 0) {
     660                 StringBuilder builder = new StringBuilder(
     661                         "'adb version' failed!"); //$NON-NLS-1$
     662                 for (String error : errorOutput) {
     663                     builder.append('\n');
     664                     builder.append(error);
     665                 }
     666                 Log.logAndDisplay(LogLevel.ERROR, "adb", builder.toString());
     667             }
     668 
     669             // check both stdout and stderr
     670             boolean versionFound = false;
     671             for (String line : stdOutput) {
     672                 versionFound = scanVersionLine(line);
     673                 if (versionFound) {
     674                     break;
     675                 }
     676             }
     677             if (!versionFound) {
     678                 for (String line : errorOutput) {
     679                     versionFound = scanVersionLine(line);
     680                     if (versionFound) {
     681                         break;
     682                     }
     683                 }
     684             }
     685 
     686             if (!versionFound) {
     687                 // if we get here, we failed to parse the output.
     688                 Log.logAndDisplay(LogLevel.ERROR, ADB,
     689                         "Failed to parse the output of 'adb version'"); //$NON-NLS-1$
     690             }
     691 
     692         } catch (IOException e) {
     693             Log.logAndDisplay(LogLevel.ERROR, ADB,
     694                     "Failed to get the adb version: " + e.getMessage()); //$NON-NLS-1$
     695         } catch (InterruptedException e) {
     696         } finally {
     697 
     698         }
     699     }
     700 
     701     /**
     702      * Scans a line resulting from 'adb version' for a potential version number.
     703      * <p/>
     704      * If a version number is found, it checks the version number against what
     705      * is expected by this version of ddms.
     706      * <p/>
     707      * Returns true when a version number has been found so that we can stop
     708      * scanning, whether the version number is in the acceptable range or not.
     709      * 
     710      * @param line
     711      *            The line to scan.
     712      * @return True if a version number was found (whether it is acceptable or
     713      *         not).
     714      */
     715     @SuppressWarnings("all")
     716     // With Eclipse 3.6, replace by @SuppressWarnings("unused")
     717     private boolean scanVersionLine(String line) {
     718         if (line != null) {
     719             Matcher matcher = sAdbVersion.matcher(line);
     720             if (matcher.matches()) {
     721                 int majorVersion = Integer.parseInt(matcher.group(1));
     722                 int minorVersion = Integer.parseInt(matcher.group(2));
     723                 int microVersion = Integer.parseInt(matcher.group(3));
     724 
     725                 // check only the micro version for now.
     726                 if (microVersion < ADB_VERSION_MICRO_MIN) {
     727                     String message = String.format(
     728                             "Required minimum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
     729                                     + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
     730                             majorVersion, minorVersion, ADB_VERSION_MICRO_MIN,
     731                             microVersion);
     732                     Log.logAndDisplay(LogLevel.ERROR, ADB, message);
     733                 } else if (ADB_VERSION_MICRO_MAX != -1
     734                         && microVersion > ADB_VERSION_MICRO_MAX) {
     735                     String message = String.format(
     736                             "Required maximum version of adb: %1$d.%2$d.%3$d." //$NON-NLS-1$
     737                                     + "Current version is %1$d.%2$d.%4$d", //$NON-NLS-1$
     738                             majorVersion, minorVersion, ADB_VERSION_MICRO_MAX,
     739                             microVersion);
     740                     Log.logAndDisplay(LogLevel.ERROR, ADB, message);
     741                 } else {
     742                     mVersionCheck = true;
     743                 }
     744 
     745                 return true;
     746             }
     747         }
     748         return false;
     749     }
     750 
     751     /**
     752      * Starts the debug bridge.
     753      * 
     754      * @return true if success.
     755      */
     756     boolean start() {
     757         if (mAdbOsLocation != null
     758                 && (mVersionCheck == false || startAdb() == false)) {
     759             return false;
     760         }
     761 
     762         mStarted = true;
     763 
     764         // now that the bridge is connected, we start the underlying services.
     765         mDeviceMonitor = new DeviceMonitor(this);
     766         mDeviceMonitor.start();
     767 
     768         return true;
     769     }
     770 
     771     /**
     772      * Kills the debug bridge, and the adb host server.
     773      * 
     774      * @return true if success
     775      */
     776     boolean stop() {
     777         // if we haven't started we return false;
     778         if (mStarted == false) {
     779             return false;
     780         }
     781 
     782         // kill the monitoring services
     783         mDeviceMonitor.stop();
     784         mDeviceMonitor = null;
     785 
     786         if (stopAdb() == false) {
     787             return false;
     788         }
     789 
     790         mStarted = false;
     791         return true;
     792     }
     793 
     794     /**
     795      * Restarts adb, but not the services around it.
     796      * 
     797      * @return true if success.
     798      */
     799     public boolean restart() {
     800         if (mAdbOsLocation == null) {
     801             Log.e(ADB,
     802                     "Cannot restart adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
     803             return false;
     804         }
     805 
     806         if (mVersionCheck == false) {
     807             Log.logAndDisplay(LogLevel.ERROR, ADB,
     808                     "Attempting to restart adb, but version check failed!"); //$NON-NLS-1$
     809             return false;
     810         }
     811         synchronized (this) {
     812             stopAdb();
     813 
     814             boolean restart = startAdb();
     815 
     816             if (restart && mDeviceMonitor == null) {
     817                 mDeviceMonitor = new DeviceMonitor(this);
     818                 mDeviceMonitor.start();
     819             }
     820 
     821             return restart;
     822         }
     823     }
     824 
     825     /**
     826      * Notify the listener of a new {@link IDevice}.
     827      * <p/>
     828      * The notification of the listeners is done in a synchronized block. It is
     829      * important to expect the listeners to potentially access various methods
     830      * of {@link IDevice} as well as {@link #getDevices()} which use internal
     831      * locks.
     832      * <p/>
     833      * For this reason, any call to this method from a method of
     834      * {@link DeviceMonitor}, {@link IDevice} which is also inside a
     835      * synchronized block, should first synchronize on the
     836      * {@link AndroidDebugBridge} lock. Access to this lock is done through
     837      * {@link #getLock()}.
     838      * 
     839      * @param device
     840      *            the new <code>IDevice</code>.
     841      * @see #getLock()
     842      */
     843     void deviceConnected(IDevice device) {
     844         // because the listeners could remove themselves from the list while
     845         // processing
     846         // their event callback, we make a copy of the list and iterate on it
     847         // instead of
     848         // the main list.
     849         // This mostly happens when the application quits.
     850         IDeviceChangeListener[] listenersCopy = null;
     851         synchronized (sLock) {
     852             listenersCopy = sDeviceListeners
     853                     .toArray(new IDeviceChangeListener[sDeviceListeners.size()]);
     854         }
     855 
     856         // Notify the listeners
     857         for (IDeviceChangeListener listener : listenersCopy) {
     858             // we attempt to catch any exception so that a bad listener doesn't
     859             // kill our
     860             // thread
     861             try {
     862                 listener.deviceConnected(device);
     863             } catch (Exception e) {
     864                 Log.e(DDMS, e);
     865             }
     866         }
     867     }
     868 
     869     /**
     870      * Notify the listener of a disconnected {@link IDevice}.
     871      * <p/>
     872      * The notification of the listeners is done in a synchronized block. It is
     873      * important to expect the listeners to potentially access various methods
     874      * of {@link IDevice} as well as {@link #getDevices()} which use internal
     875      * locks.
     876      * <p/>
     877      * For this reason, any call to this method from a method of
     878      * {@link DeviceMonitor}, {@link IDevice} which is also inside a
     879      * synchronized block, should first synchronize on the
     880      * {@link AndroidDebugBridge} lock. Access to this lock is done through
     881      * {@link #getLock()}.
     882      * 
     883      * @param device
     884      *            the disconnected <code>IDevice</code>.
     885      * @see #getLock()
     886      */
     887     void deviceDisconnected(IDevice device) {
     888         // because the listeners could remove themselves from the list while
     889         // processing
     890         // their event callback, we make a copy of the list and iterate on it
     891         // instead of
     892         // the main list.
     893         // This mostly happens when the application quits.
     894         IDeviceChangeListener[] listenersCopy = null;
     895         synchronized (sLock) {
     896             listenersCopy = sDeviceListeners
     897                     .toArray(new IDeviceChangeListener[sDeviceListeners.size()]);
     898         }
     899 
     900         // Notify the listeners
     901         for (IDeviceChangeListener listener : listenersCopy) {
     902             // we attempt to catch any exception so that a bad listener doesn't
     903             // kill our
     904             // thread
     905             try {
     906                 listener.deviceDisconnected(device);
     907             } catch (Exception e) {
     908                 Log.e(DDMS, e);
     909             }
     910         }
     911     }
     912 
     913     /**
     914      * Notify the listener of a modified {@link IDevice}.
     915      * <p/>
     916      * The notification of the listeners is done in a synchronized block. It is
     917      * important to expect the listeners to potentially access various methods
     918      * of {@link IDevice} as well as {@link #getDevices()} which use internal
     919      * locks.
     920      * <p/>
     921      * For this reason, any call to this method from a method of
     922      * {@link DeviceMonitor}, {@link IDevice} which is also inside a
     923      * synchronized block, should first synchronize on the
     924      * {@link AndroidDebugBridge} lock. Access to this lock is done through
     925      * {@link #getLock()}.
     926      * 
     927      * @param device
     928      *            the modified <code>IDevice</code>.
     929      * @see #getLock()
     930      */
     931     void deviceChanged(IDevice device, int changeMask) {
     932         // because the listeners could remove themselves from the list while
     933         // processing
     934         // their event callback, we make a copy of the list and iterate on it
     935         // instead of
     936         // the main list.
     937         // This mostly happens when the application quits.
     938         IDeviceChangeListener[] listenersCopy = null;
     939         synchronized (sLock) {
     940             listenersCopy = sDeviceListeners
     941                     .toArray(new IDeviceChangeListener[sDeviceListeners.size()]);
     942         }
     943 
     944         // Notify the listeners
     945         for (IDeviceChangeListener listener : listenersCopy) {
     946             // we attempt to catch any exception so that a bad listener doesn't
     947             // kill our
     948             // thread
     949             try {
     950                 listener.deviceChanged(device, changeMask);
     951             } catch (Exception e) {
     952                 Log.e(DDMS, e);
     953             }
     954         }
     955     }
     956 
     957     /**
     958      * Notify the listener of a modified {@link Client}.
     959      * <p/>
     960      * The notification of the listeners is done in a synchronized block. It is
     961      * important to expect the listeners to potentially access various methods
     962      * of {@link IDevice} as well as {@link #getDevices()} which use internal
     963      * locks.
     964      * <p/>
     965      * For this reason, any call to this method from a method of
     966      * {@link DeviceMonitor}, {@link IDevice} which is also inside a
     967      * synchronized block, should first synchronize on the
     968      * {@link AndroidDebugBridge} lock. Access to this lock is done through
     969      * {@link #getLock()}.
     970      * 
     971      * @param device
     972      *            the modified <code>Client</code>.
     973      * @param changeMask
     974      *            the mask indicating what changed in the <code>Client</code>
     975      * @see #getLock()
     976      */
     977     void clientChanged(Client client, int changeMask) {
     978         // because the listeners could remove themselves from the list while
     979         // processing
     980         // their event callback, we make a copy of the list and iterate on it
     981         // instead of
     982         // the main list.
     983         // This mostly happens when the application quits.
     984         IClientChangeListener[] listenersCopy = null;
     985         synchronized (sLock) {
     986             listenersCopy = sClientListeners
     987                     .toArray(new IClientChangeListener[sClientListeners.size()]);
     988 
     989         }
     990 
     991         // Notify the listeners
     992         for (IClientChangeListener listener : listenersCopy) {
     993             // we attempt to catch any exception so that a bad listener doesn't
     994             // kill our
     995             // thread
     996             try {
     997                 listener.clientChanged(client, changeMask);
     998             } catch (Exception e) {
     999                 Log.e(DDMS, e);
    1000             }
    1001         }
    1002     }
    1003 
    1004     /**
    1005      * Returns the {@link DeviceMonitor} object.
    1006      */
    1007     DeviceMonitor getDeviceMonitor() {
    1008         return mDeviceMonitor;
    1009     }
    1010 
    1011     /**
    1012      * Starts the adb host side server.
    1013      * 
    1014      * @return true if success
    1015      */
    1016     synchronized boolean startAdb() {
    1017         if (mAdbOsLocation == null) {
    1018             Log.e(ADB,
    1019                     "Cannot start adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
    1020             return false;
    1021         }
    1022 
    1023         Process proc;
    1024         int status = -1;
    1025 
    1026         try {
    1027             String[] command = new String[2];
    1028             command[0] = mAdbOsLocation;
    1029             command[1] = "start-server"; //$NON-NLS-1$
    1030             Log.d(DDMS, String.format(
    1031                     "Launching '%1$s %2$s' to ensure ADB is running.", //$NON-NLS-1$
    1032                     mAdbOsLocation, command[1]));
    1033             ProcessBuilder processBuilder = new ProcessBuilder(command);
    1034             if (DdmPreferences.getUseAdbHost()) {
    1035                 String adbHostValue = DdmPreferences.getAdbHostValue();
    1036                 if (adbHostValue != null && adbHostValue.length() > 0) {
    1037                     // TODO : check that the String is a valid IP address
    1038                     Map<String, String> env = processBuilder.environment();
    1039                     env.put("ADBHOST", adbHostValue);
    1040                 }
    1041             }
    1042             proc = processBuilder.start();
    1043 
    1044             ArrayList<String> errorOutput = new ArrayList<String>();
    1045             ArrayList<String> stdOutput = new ArrayList<String>();
    1046             status = grabProcessOutput(proc, errorOutput, stdOutput, false /* waitForReaders */);
    1047 
    1048         } catch (IOException ioe) {
    1049             Log.d(DDMS, "Unable to run 'adb': " + ioe.getMessage()); //$NON-NLS-1$
    1050             // we'll return false;
    1051         } catch (InterruptedException ie) {
    1052             Log.d(DDMS, "Unable to run 'adb': " + ie.getMessage()); //$NON-NLS-1$
    1053             // we'll return false;
    1054         }
    1055 
    1056         if (status != 0) {
    1057             Log.w(DDMS,
    1058                     "'adb start-server' failed -- run manually if necessary"); //$NON-NLS-1$
    1059             return false;
    1060         }
    1061 
    1062         Log.d(DDMS, "'adb start-server' succeeded"); //$NON-NLS-1$
    1063 
    1064         return true;
    1065     }
    1066 
    1067     /**
    1068      * Stops the adb host side server.
    1069      * 
    1070      * @return true if success
    1071      */
    1072     private synchronized boolean stopAdb() {
    1073         if (mAdbOsLocation == null) {
    1074             Log.e(ADB,
    1075                     "Cannot stop adb when AndroidDebugBridge is created without the location of adb."); //$NON-NLS-1$
    1076             return false;
    1077         }
    1078 
    1079         Process proc;
    1080         int status = -1;
    1081 
    1082         try {
    1083             String[] command = new String[2];
    1084             command[0] = mAdbOsLocation;
    1085             command[1] = "kill-server"; //$NON-NLS-1$
    1086             proc = Runtime.getRuntime().exec(command);
    1087             status = proc.waitFor();
    1088         } catch (IOException ioe) {
    1089             // we'll return false;
    1090         } catch (InterruptedException ie) {
    1091             // we'll return false;
    1092         }
    1093 
    1094         if (status != 0) {
    1095             Log.w(DDMS, "'adb kill-server' failed -- run manually if necessary"); //$NON-NLS-1$
    1096             return false;
    1097         }
    1098 
    1099         Log.d(DDMS, "'adb kill-server' succeeded"); //$NON-NLS-1$
    1100         return true;
    1101     }
    1102 
    1103     /**
    1104      * Get the stderr/stdout outputs of a process and return when the process is
    1105      * done. Both <b>must</b> be read or the process will block on windows.
    1106      * 
    1107      * @param process
    1108      *            The process to get the ouput from
    1109      * @param errorOutput
    1110      *            The array to store the stderr output. cannot be null.
    1111      * @param stdOutput
    1112      *            The array to store the stdout output. cannot be null.
    1113      * @param displayStdOut
    1114      *            If true this will display stdout as well
    1115      * @param waitforReaders
    1116      *            if true, this will wait for the reader threads.
    1117      * @return the process return code.
    1118      * @throws InterruptedException
    1119      */
    1120     private int grabProcessOutput(final Process process,
    1121             final ArrayList<String> errorOutput,
    1122             final ArrayList<String> stdOutput, boolean waitforReaders)
    1123             throws InterruptedException {
    1124         assert errorOutput != null;
    1125         assert stdOutput != null;
    1126         // read the lines as they come. if null is returned, it's
    1127         // because the process finished
    1128         Thread t1 = new Thread("") { //$NON-NLS-1$
    1129             @Override
    1130             public void run() {
    1131                 // create a buffer to read the stderr output
    1132                 InputStreamReader is = new InputStreamReader(
    1133                         process.getErrorStream());
    1134                 BufferedReader errReader = new BufferedReader(is);
    1135 
    1136                 try {
    1137                     while (true) {
    1138                         String line = errReader.readLine();
    1139                         if (line != null) {
    1140                             Log.e(ADB, line);
    1141                             errorOutput.add(line);
    1142                         } else {
    1143                             break;
    1144                         }
    1145                     }
    1146                 } catch (IOException e) {
    1147                     // do nothing.
    1148                 }
    1149             }
    1150         };
    1151 
    1152         Thread t2 = new Thread("") { //$NON-NLS-1$
    1153             @Override
    1154             public void run() {
    1155                 InputStreamReader is = new InputStreamReader(
    1156                         process.getInputStream());
    1157                 BufferedReader outReader = new BufferedReader(is);
    1158 
    1159                 try {
    1160                     while (true) {
    1161                         String line = outReader.readLine();
    1162                         if (line != null) {
    1163                             Log.d(ADB, line);
    1164                             stdOutput.add(line);
    1165                         } else {
    1166                             break;
    1167                         }
    1168                     }
    1169                 } catch (IOException e) {
    1170                     // do nothing.
    1171                 }
    1172             }
    1173         };
    1174 
    1175         t1.start();
    1176         t2.start();
    1177 
    1178         // it looks like on windows process#waitFor() can return
    1179         // before the thread have filled the arrays, so we wait for both threads
    1180         // and the
    1181         // process itself.
    1182         if (waitforReaders) {
    1183             try {
    1184                 t1.join();
    1185             } catch (InterruptedException e) {
    1186             }
    1187             try {
    1188                 t2.join();
    1189             } catch (InterruptedException e) {
    1190             }
    1191         }
    1192 
    1193         // get the return code from the process
    1194         return process.waitFor();
    1195     }
    1196 
    1197     /**
    1198      * Returns the singleton lock used by this class to protect any access to
    1199      * the listener.
    1200      * <p/>
    1201      * This includes adding/removing listeners, but also notifying listeners of
    1202      * new bridges, devices, and clients.
    1203      */
    1204     static Object getLock() {
    1205         return sLock;
    1206     }
    1207 
    1208     /**
    1209      * Instantiates sSocketAddr with the address of the host's adb process.
    1210      */
    1211     private static void initAdbSocketAddr() {
    1212         try {
    1213             int adb_port = determineAndValidateAdbPort();
    1214             sHostAddr = InetAddress.getByName(ADB_HOST);
    1215             sSocketAddr = new InetSocketAddress(sHostAddr, adb_port);
    1216         } catch (UnknownHostException e) {
    1217             // localhost should always be known.
    1218         }
    1219     }
    1220 
    1221     /**
    1222      * Determines port where ADB is expected by looking at an env variable.
    1223      * <p/>
    1224      * The value for the environment variable ANDROID_ADB_SERVER_PORT is
    1225      * validated, IllegalArgumentException is thrown on illegal values.
    1226      * <p/>
    1227      * 
    1228      * @return The port number where the host's adb should be expected or
    1229      *         started.
    1230      * @throws IllegalArgumentException
    1231      *             if ANDROID_ADB_SERVER_PORT has a non-numeric value.
    1232      */
    1233     private static int determineAndValidateAdbPort() {
    1234         String adb_env_var;
    1235         int result = ADB_PORT;
    1236         try {
    1237             adb_env_var = System.getenv(SERVER_PORT_ENV_VAR);
    1238 
    1239             if (adb_env_var != null) {
    1240                 adb_env_var = adb_env_var.trim();
    1241             }
    1242 
    1243             if (adb_env_var != null && adb_env_var.length() > 0) {
    1244                 // C tools (adb, emulator) accept hex and octal port numbers, so
    1245                 // need to accept
    1246                 // them too.
    1247                 result = Integer.decode(adb_env_var);
    1248 
    1249                 if (result <= 0) {
    1250                     String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
    1251                             + ": must be >=0, got " //$NON-NLS-1$
    1252                             + System.getenv(SERVER_PORT_ENV_VAR);
    1253                     throw new IllegalArgumentException(errMsg);
    1254                 }
    1255             }
    1256         } catch (NumberFormatException nfEx) {
    1257             String errMsg = "env var " + SERVER_PORT_ENV_VAR //$NON-NLS-1$
    1258                     + ": illegal value '" //$NON-NLS-1$
    1259                     + System.getenv(SERVER_PORT_ENV_VAR) + "'"; //$NON-NLS-1$
    1260             throw new IllegalArgumentException(errMsg);
    1261         } catch (SecurityException secEx) {
    1262             // A security manager has been installed that doesn't allow access
    1263             // to env vars.
    1264             // So an environment variable might have been set, but we can't
    1265             // tell.
    1266             // Let's log a warning and continue with ADB's default port.
    1267             // The issue is that adb would be started (by the forked process
    1268             // having access
    1269             // to the env vars) on the desired port, but within this process, we
    1270             // can't figure out
    1271             // what that port is. However, a security manager not granting
    1272             // access to env vars
    1273             // but allowing to fork is a rare and interesting configuration, so
    1274             // the right
    1275             // thing seems to be to continue using the default port, as forking
    1276             // is likely to
    1277             // fail later on in the scenario of the security manager.
    1278             Log.w(DDMS,
    1279                     "No access to env variables allowed by current security manager. " //$NON-NLS-1$
    1280                             + "If you've set ANDROID_ADB_SERVER_PORT: it's being ignored."); //$NON-NLS-1$
    1281         }
    1282         return result;
    1283     }
    1284 
    1285 }
    复制代码

    在以上源码中,还有一个connect方法和disconnect方法,可以通过复写这两个方法,将adb当前的连接情况打印出来脚本信息

    4、ADB在自动化工具和框架中的作用

    可以使用adb的方法,通过打印脚本信息来判断设备连接情况,这是最初级且最基础的技术

    备注:

    BAT测试笔试面试题目:

    腾讯笔试题目:

    1、如何测试分布式ATM机?     这个针对一些大系统的题目,集群部署

    2、使用一个数组实现三个堆栈,要求有效的使用数组的存储空间,可以使用其他数据结构

    涉及到一个测试人员对整个系统的了解,包括前段的负载均衡到主备应用等

    3、编写一个脚本,统计log文件中首个单词出现的次数:error:xxxx

    阿里2面的部分面试题目

    1、Robotium源码架构实现

    2、Robotium的工具怎么根据id找到脚本id(脚本id和架构映射原理)

    3、Monkeyrunner和UIAutomator的原理

    4、你们怎么做电量测试(如何做到app进程级别,而不是整机?比如发一个intent请求之类的?)

    5、影响手机电量的因素列举一下

    6、稳定性和压力怎么做?

    7、Robotium WebView怎么实现?

    8、怎么让系统不休眠:1、通过PowerManager来精细控制,具体函数请指出    2、在View中设置FLAG_KEEP_SCREE_ON

    百度1面题目

    1、测试客户端 日文输入法,如果不认识日文,怎么用自动化解决?

    2、不用变量交换两个数

    3、脚本 怎么用并行和串行调bat批处理

    4、怎么解决控件和点触屏自动化(要规划自动化方案)

    5、用户安装了百度客户端,怎么实现自动化

    6、自动化要验证功能准确性、性能还有UI界面,一个自动化验证多个?还是一个自动化脚本只验证一条用例?

    7、怎么实现监控内存   在eclipse显示 DSS是什么意思

    8、ANS出现怎么解决?

    9、进程和线程 handle和runnable  以及广播和服务

    10、Robotium和Monkeyrunner的区别

    11、Radiobox和Checkbox自动化脚本怎么复用? (考的是正交法)

    12、GC原理

    13、android性能自动化怎么做

    14、电量对比测试

    15、android安全自动化怎么做

    16、有个客户装了百度客户端,怎么规划灰度测试版本自动化

    17、UI线程阻塞,怎么复现查log 

    网易云课堂:

    上:http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=877113&courseId=712011

    下:http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=877114&courseId=712011

    金阳光测试

    新浪微博:金阳光woody

             

              网站地址

    1、百度搜:金阳光测试

    2、官网:www.goldensunshine.cc

    微信公众号

  • 相关阅读:
    【5】TensorFlow光速入门-图片分类完整代码
    【4】TensorFlow光速入门-保存模型及加载模型并使用
    科研数据库结构
    高并发请求的缓存设计策略
    iOS-KVC的原理
    iOS-KVO的原理
    Kafka too many open files问题解决
    VLOOKUP函数-Excel
    arcgis sql 字符串替换
    ArcGIS矢量转栅格再发布切片服务,还是直接发布切片服务?有何区别?
  • 原文地址:https://www.cnblogs.com/GoldenSunshinetester/p/4324131.html
Copyright © 2020-2023  润新知