Hello, Hackernoon! My name is Alexander Karpenko, and I work as a QA Engineer at . I have prepared this article for novice QA specialists. Below, I will tell you how to use (ADB) in mobile application testing and why it’s needed in the first place. inDrive Android Debug Bridge I imagine you already have basic knowledge of testing fundamentals so I will skip the process of preparing and setting up projects. ADB's capabilities are constantly expanding, but I will share some valuable techniques that will improve your daily workflow. As my story is about mobile app testing, I will focus on macOS, which lets you work effectively with all popular mobile platforms. For other operating systems, the examples might be slightly different, but hopefully, Windows users won’t hold this against me. To begin with, let's touch on the most basic commands to make sure the later points are presented in a logical sequence. Displaying a list of connected devices and connecting to the device Normally, we work with one device, but sometimes several devices are connected, e.g., via TCP/IP. In this case, we have to manually specify the device we want to run the command on. Display the list of all connected devices to get an identifier — displays the list of connected devices (using the switch pulls up an extended list of properties). This is useful if multiple devices are connected and it’s not immediately clear which one we need. adb devices -l To tell ADB which device to target, the serial number of the device must be specified after the switch: -s , where is the serial number of the device from the list and is the command to execute on the device. adb -s <serial_number> <command> <serial_number> <command> For example, installing an application on a specific device from the list: adb -s 32312b96 install user/download/app.apk Another frequent scenario is when the operation simultaneously involves a real device and an emulator, e.g., for the different roles of executor/originator. In this case, the devices are easily distinguishable not by their serial number but based on the switches after the adbcommand. Example: —d —e — the command will be executed on the real device, with the switch on the emulator. adb —d install user/download/app.apk —е We can also connect to the device over TCP/IP when it uses the same Wi-Fi network. To do this, connect the device to the PC with a cable and change the operating mode on the device from USB to TCP/IP by using the command: adb tcpip 5555 Determine the IP address of the device by any available method For example, via the phone settings in General Information or with the command: adb shell ifconfig wlan0 If your device is already disconnected from the PC at this point, be sure to additionally specify the S/N of the device. Next, we connect to it: adb connect ip_address:5555 The device can be disabled with the command: adb disconnect ip_address:5555 — to disable all of our TCP/IP devices. adb disconnect To return to USB mode, use the command: (lowercase is important). adb usb Installing and uninstalling the application, and locating the package on the device The application is installed using the command: , where is the absolute path to our APK application file. adb install <apk_path> <apk_path> Here are some useful switches after the install command that are often used: — reinstalls with a downgraded version. Otherwise, there will be a failure (error) ). —d [INSTALL_FAILED_VERSION_DOWNGRADE] — reinstalls the application with data saved. —r — grants all permissions specified in the application manifest during the installation process. —g For example, an app installed with this switch will not ask you to allow access to geolocation or storage space for downloading photos. The application is uninstalled based on the name of the package. To do this, you need to know how the application is registered in the system. Use the Shell and thePackage Manager (pm). Run the following command to display the list of all installed applications: adb shell pm list packages The list can be filtered by application name. You will need this if the list is quite large, but we know which word is contained in the name of the package: adb shell pm list packages | grep com.myApp You can also output to a separate file and find the package needed there: adb shell pm list packages > /Users/username/packages.txt Now that we know how to figure out the name of the application package, let's go back to how to remove it from the device. This can be done using the command: adb uninstall com.myApp — deletes the application but saves data and cache files. adb uninstall -k com.myApp I will separately present a command that may often prove useful: — cleans up the cache and data of the app. adb shell pm clear com.myApp Downloading the APK file from the device I think this is a rare situation to come across. But this might come in handy for someone, just as it once did for me. All installed applications store their APK files in the /data/appfolder. Since you know the name of the package, you can find the place where the application is installed and download its APK from there. To do this, run the following command: — displays the installation directory of the application. adb shell pm path com.myApp This may not look all that presentable: package:/data/app/~~YcTsnr19yQR6ENa0q2EMag==/com.myApp—IHasf91SDB0erQLagc8j0Q==/base.apk But this is exactly how we need this path to look. Let's skip a little bit ahead and see how we can copy the file we need to the PC from the phone. This can be done using the command: , where is the output of our previous command, is the path on the PC where you want to copy our file to. adb pull <crazyPath> /Users/username/ <crazyPath> /Users/username/ Text fields Let's briefly talk about checking text fields. For instance, you have to check the limit for the maximum number of characters that can be entered into a text field. If you use a single device, different sets of transferred data can be stored on the phone or in the cloud. However, if the testing has to be done on different devices, the test data can be stored on the PC and transferred to the devices via the following commands: adb shell input text <text> Example: — the string "test test" will be entered. Replace the spaces with the special characters , otherwise, only the part preceding the space will be sent to the device. If we use special characters like in the text being transmitted, they have to be marked by inserting a backslash ( ) in front of them. adb shell input text test%stest %s !@# \ For example, the command: will display on-screen adb shell input text test\!\@\#\$%stest “test!@#$ test” (ADB doesn’t work with Cyrillic characters and generates a NullPointerException error). The contents of a clipboard can be transferred this way: adb shell input text $(pbpaste) Keep in mind that some characters may not be transmitted as they appear on the PC. The problem can be solved by using a streaming text editor (sed). Here is an example of an extended command where we replace all the spaces in the buffer with the special characters we need to make sure the text is transferred to the device in the correct manner: adb shell input text $(pbpaste | sed -e 's/ /\%s/g') is the text that is contained in the buffer. pbpaste The switch— allows you to execute the commands needed to edit text. ”—e” is the template (pattern) to use. “s/take this/change_it_to/option” is the flag to replace all matches for a particular template, without exception. /g Deep links Let’s keep in mind that it’s best when the testing is done in an environment as close to real life as possible, but it’s helpful to know that this option is also available. This strategy will help you check the deep links to the screens needed, when multiple screens are used, or if we have problems with the infrastructure and no push notifications come through, or if none of them have arrived yet but you need to check how the application behaves. You can also check to see if the application works correctly and doesn’t crash if an invalid deep link appears in the push notification alert. Or when dealing with a situation where we follow a deep link to a screen that no longer exists, or whose status has changed, or if we shouldn't have access to that screen in the first place, because the push alert has been in the notifications for a long time. There may be a lot of situations like this. In Shell ADB, we can use the Activity Manager (AM) to execute commands. We start off our activity and send the deep link that we want to check. The deep link usually contains the character “&”, which separates the screens. Therefore, when opening through a terminal, a backslash (\) has to be inserted in front of it. adb shell am start -W -a android.intent.action.VIEW -d “myApp://open/client/trip\&last_trip=test” com.myApp — calls up the Activity Manager. am — waiting for download before executing a command. W — determines which action is to be taken. In this case, it’s . a action.View — data needed for the run. In this case, we’re talking about the deep link itself and then the application that should be used to open it. d You might have to re-insert the quotation marks manually or replace them with single quotes when transferring the command to the terminal. If there's a syntax error, you may get an appropriate message. Creating screenshots and recording videos from the device screen Use this command to take a screenshot: adb shell screencap -p <device_path/screenshot_name.png> Example: — takes a screenshot and saves a file named on the device to the folder. adb shell screencap -p /sdcard/screencap.png screencap.png /sdcard/screencap.png You can save the screenshot on your computer as follows: — by default, the file is copied to the directory of the current user, i.e., . adb pull /sdcard/screencap.png /Users/username/screencap.png Or you can run the entire command at once: adb shell screencap -p /sdcard/screencap.png && adb pull /sdcard/screencap.png In the latest versions of ADB, the following command can be used to get a screenshot: — the screenshot file will also appear in the current user’s directory on the PC. adb exec—out screencap —p > screen.png The default path can be changed manually by being added at the end of the command: — and the screenshot will appear in the folder. adb exec—out screencap -p > downloads/test/screen.png /Users/username/downloads/test/screen.png If interested, you can also automate this process a bit by adding an alias to . In macOS, you can use the Automator Service to create and set up hotkeys. bash_profile Use this command to record a video: . adb shell screenrecord device_path Example: — use this command to start recording the device screen based on the default settings for three minutes, and save the result to the file on the device. adb shell screenrecord /sdcard/screenrecord.mp4 /sdcard/screenrecord.mp4 You can manually specify the recording time by using the switch (in seconds, but the length of the recording is still limited to 180 seconds). —time—limit time The recording can be stopped ahead of time by pressing CTRL + C The file can also be copied by using the pull command, in a similar way to the screenshot procedure. You can also check out the additional features of this utility by using the switch. Incidentally, it is able to change the recording resolution and bitrate, as well as add additional data for the bug report. --help It’s helpful to use the switch, which adds information about the system used for the recording as the first frame in the video. -bugreport Now that we have covered how to download some content from the device, let's focus a little on how to upload something to it. We opened it on our PC, adjusted the format and content, made a download to our phone, and checked to make sure that the application responds correctly to unknown formats and oversize limits. To upload a file to your phone from your PC, you can use this command: adb push /Users/username/file <device_path> Let's run the command: — this will copy our file to the phone's SD card. adb push /Users/username/screen.png sdcard screen.png Checking to see if the app’s state has been restored after its deletion by the system Another example from experience is concerned with checking to see if the app’s state has been restored after its deletion by the system. Collapse the application, kill the process - this action simulates the situation when the system stops the process because there is not enough memory available: adb shell am kill com.myApp Run it again and check to see if everything is working fine. We came across this scenario: a user minimizes an application while on a certain screen. After a while, the system slows down the process and caches its state. When the user tries to expand the application, it crashes. This happens when data from the cache is accessed, because the fragments are restoring their stack and state, but the cache is already empty. Unfortunately, this bug was overlooked during the testing phase, because we had not encountered it before, and so it ended up in production. Now that you know it's possible, you can make sure that you don't repeat our mistakes. Logs It’s a good idea to check the logs when trying to find out what caused an application to crash. If you want to save the current log buffer content, this can be done by using the following command: — displays logs in real time. adb logcat — displays log information at the moment the command is run, without adding real events on the device. It’s also possible to output the log to a separate file by using the command: (the file is created in the directory of the current user). adb logcat —d adb logcat —d > file.log And the command will write the log directly into the file, adding all the real events on the device. adb logcat >> file.log There are several levels in ascending order of priority: V — Verbose, D — Debug, I — Info, W — Warn, E — Error, F — Fatal, S — Silent, for instance: — will output logs with errors and a level higher. adb logcat '*:E' Now let’s dwell briefly on output formatting and filters. You can change the format of the output to the console by using the -v switch, for example: — outputs logs sequentially by recording time points. adb logcat -v time — displays each level of logs in a different color (which is helpful when reading). adb logcat -v color — displays the process priority, tag, and PID. adb logcat -v brief Each log message has a tag and its related priority. You can use them to reduce the amount of output to the console: — will display the analytics events we send via the swrve service. The parameter indicates that the log output is limited to the filter expression we explicitly specified. adb logcat SwrveSDK:I '*:S' *:S (-s) And as always, you can use the grep utility to filter the output: adb logcat '*:E' —v color | grep com.myApp Traditionally, for further information, you can always turn to your assistant adb logcat --help Now let's see how to use it For example, if a bug is reproduced while the device is not connected, you can immediately connect it and redirect the log to a file. For further debugging, before collecting logs, you can pre-clear the log buffer before reproducing the bug to eliminate superfluous data. This can be done via the command: , then we reproduce the bug and run adb logcat —c adb logcat —d For those who like to dig through piles of logs, there is another tool to consider — ADB bugreport. This tool allows you to create zip archives with full debugging information in plain text format ( ). .txt — creates a zip archive in the specified directory. adb bugreport /Users/username Copies all information about the device, such asdumpstate, dumpsys, and logcat data to the specified folder. By default, error reports are stored in /bugreports and can be viewed via: adb shell ls /bugreports/ The most important information for us is stored in bugreport-BUILD_ID-DATE.txt Crash Monitoring and ANR (Application Not Responding) is another interesting tool for working with crashes. Run it by using this command: , and then we reproduce our crash. The console will display information about the crash without any redundant details and three options for continuing our monitoring efforts: . adb shell am monitor (c)ontinue: show crash dialog, (k)ill: immediately kill app, (q)uit: finish monitoring Emulators Displaying a list of configured emulators: emulator -list-avds Running the emulator we need: emulator @avdname When working with emulators, sometimes it’s necessary to restart services, and the server must be reset once the emulator is started, but fairly often even one command is enough: . If this doesn’t help, then run the entire script: adb kill-server — displays a list of configured emulators. emulator -list-avds — stops the server. adb kill-server (or )— where is the name of the emulator. emulator -avd avdname emulator @avdname avdname — restarts the server. adb start—server — displays the list of connected devices where our lost emulator should appear. adb devices For the laziest among you, an emulator can be created from the command line. For example, the following command creates an emulator named "test" using an x86 system image with API 25:): avdmanager create avd —n test —k "system—images;android—25;google_apis;x86" If the desired image is not available, you can pre-install it with the command: sdkmanager --install "system—images;android—25;google_apis;x86" — displays a list of images available for download sdkmanager --list | grep system—images With emulators, “phantom” problems also sometimes occur during operation, and one frequently used command that helps here is to “cold-boot” the emulator without pulling up the automatic snapshot. The snapshot made at the output will be as follows: emulator @avdname —no—snapshot—load Here are a few more useful switches to consider when starting the emulator: — no automatic snapshot will be saved -no-snapshot-save — no snapshot will be downloaded or saved -no-snapshot If the emulator still doesn’t function properly, it can be cleared by using the switch that returns the emulator to its original state: -wipe-data Snapshot creation is a very useful feature for saving the device's different states. Manually, this can be done through the emulator settings or by running this command: — saves the emulator’s state where is the name of the snapshot to be stored on the device adb emu avd snapshot save test test — runs our emulator named @avd and displays the snapshot list in the console emulator @avdname —snapshot—list Next, you can load a previously saved snapshot by using this command: — where is the name of a previously saved snapshot adb emu avd snapshot load test test — deletes the snapshot named adb emu avd snapshot delete test test It’s also possible to immediately run the emulator with the snapshot we need: emulator @avdname -snapshot test You can also use the command to get a snapshot from the device: pull adb emu avd snapshot pull test /Users/username/ Our emulator can be operated via the console. But first you have to install it. The easiest way to do that is through the package manager, if you have it. If not, then it's time to find out what it is and how to use it. So, install by using the command: telnet brew telnet brew install telnet. Next, run our emulator, and in another tab of the terminal, connect to it with the command: Example: telnet localhost port, — connects to our emulator which uses port 5554 telnet localhost 5554 After completing the command, we can do all sorts of useful stuff with our emulator, including working with geo (e.g., the command will set our desired location at the specified coordinates), the network or the battery, whereas a complete list of commands as always can be found via help. geo fix 40.748840 -73.984279 For example, the same procedure with snapshots is somewhat simplified, while the commands outlined in the previous section are reduced to . avd snapshot <command> Changing the resolution on the device The window manager (wm) has some useful commands to make sure the elements on the screen of the device are displayed correctly. They let you adjust the pixel density resolution so you can go through all the necessary options for screen sizes and see how our app will adapt to them, without having the appropriate number of devices on hand: — sets the custom screen resolution, with a width of 1080 and a height of 1920. adb shell wm size 1080x1920 — resets all our changed settings. adb shell wm size reset — changes the pixel density, where the minimum value is 72. The greater the value, the larger the elements on the screen. adb shell wm density X — resets all our changed settings. adb shell wm density reset If we run our commands without any arguments, we will get back the current screen resolution and pixel density of the connected device/emulator. Monkey Separately, we can mention the Monkey - a tool which generates random user events on the emulator or device, such as clicks, taps, and gestures, as well as a number of system-level events that resemble the movements of a silly monkey. The Monkey can be used for stress testing. — displays all Monkey parameters. adb shell monkey Example of a complete scenario: adb shell monkey ——throttle 100 ——pct—syskeys 0 —p com.myApp —v 10 The key — sets the delay between actions in milliseconds. As the Monkey performs all the actions quickly, this switch (key) is usually used when we want to visually control what is happening on screen. --throttle The key — defines the percentage of system buttons that will be pressed during a scenario. In this example, it’s set to 0, which implies that no system buttons will be pressed. --pct-syskeys The switch — the name of the packet being transmitted -p The switch — the number of actions to be performed -v Application permissions Normally, the operations involved here imply revoking app permissions, because permissions are usually granted via an app request - something that can be done quickly and easily - whereas revoking permissions is done through system settings. — displays a list of available application permissions, e.g., — mandatory permissions that are granted when installing the application, — permissions that are requested at a specific moment, e.g., when accessing the file storage. Note that if a permission is missing from the requested permission list, you will not be able to grant access to it. adb shell dumpsys package com.MyApp | grep permission install permissions runtime permissions So, the following command has to be run to revoke the permission of our application: , example: adb shell pm revoke packageName permissionName — revokes the access of to the camera. Once we return to the application and try to use the camera through it, we will see a new request for permission. adb shell pm revoke com.MyApp android.permission.CAMERA com.myApp The grant command gives permission to the application, for example: — grants access to the phone's camera for our application. adb shell pm grant com.myApp android.permission.CAMERA The battery Let's take a brief look here at the battery and standby mode. — displays battery information. adb shell dumpsys battery — sets the battery charge level, where X is the percentage of charge. adb shell dumpsys battery set level X — simulates a battery unplug. adb shell dumpsys battery unplug — resets all our changed settings. adb shell dumpsys battery reset Now let's look at standby modes. Starting from Android 6 there is the function known as Doze Mode, for saving battery power and extending battery life by limiting app activity after the user has not interacted with the device for some time and when the device is not on charge. The system periodically exits Doze Mode to complete pending background tasks. App Standby is another similar Android feature. Unlike Doze Mode, it tracks the state of a specific app that has been idle for a certain period of time and then activates standby mode. Our job is to make sure that the app recovers normally after exiting these two power saving modes, that it doesn’t crash, that notifications continue to come through, etc. To switch the device to Doze Mode, run the following commands: — unplugs the battery . adb shell dumpsys battery unplug — the command might have to be executed several times until is displayed: . adb shell dumpsys deviceidle step Stepped to deep: IDLE After all the routines we have completed with the battery, it’s best to run the command: — which returns it to its original state. adb shell dumpsys battery reset This command can also be used to force the device into Doze Mode: — sometimes, prior to this, you have to run the command: adb shell dumpsys deviceidle force—idle adb shell dumpsys deviceidle enable. You can reactivate it back from Doze Mode with the command: — and don't forget to reset the battery status: adb shell dumpsys deviceidle unforce . adb shell dumpsys battery reset Now a little bit about App Standby. To deploy the application in this mode, the following commands need to be run: — disconnects the battery as in the previous case. adb shell dumpsys battery unplug — deploys the application in App Standby mode. adb shell am set—inactive com.myApp true Next, switch our application out of App Standby mode by using this command: . adb shell am set—inactive com.myApp false You can check the app status by running this command: adb shell am get—inactive com.myApp A few more useful commands to consider — reboots the device (relevant for the real device as well). adb reboot — displays full information about a specific application. adb shell dumpsys package com.myApp — to check out the memory usage of the application on the device, ranging from the space taken up to displaying the databases used by this app, as well as the path to them. adb shell dumpsys meminfo com.myApp — shows a list of available device properties (manufacturer, device model, hardware specifications, etc.) adb shell getprop Display the list of activities that are accessible for the application: . adb shell dumpsys package com.myApp | grep —i Activity Display the name of the running activity: . adb shell dumpsys window | grep Focused Run the selected app activity: — this way you can run any installed apps, including system applications. Example: adb shell am start -n com.android.settings/.Settings displays our phone settings. adb shell am start —n com.myApp/.ActivityClass Make a call to the specified phone number: . adb shell am start —a android.intent.action.CALL tel:+790900000XX Open a page in your web browser: adb shell am start —a android.intent.action.VIEW 'https://indriver.com' Final Thoughts I’d like to point out that it’s impossible to cram all the features of Android Debug Bridge into one article or conduct a thorough study of them. Changes are constantly occurring: what works today may suddenly stop working tomorrow, and the need for knowledge of certain tools will arise as we search for solutions to specific issues. But I can say with confidence that the material we have covered today is enough to get you started and then keep going for a while. Good luck in your endeavors and I hope you enjoy diving into the exciting world of software testing!