主要讲解内容及笔记:
一、需要具备的能力:
测试一年,编程一年,熟悉并掌握业界自动化测试工具(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 |
微信公众号 |