Table of Contents
Introduction
Android Debug Bridge (ADB) is a versatile command-line tool. Using ADB (ADB), you can interact with an emulator instance or linked Android devices. Even though ADB commands are strong on their own, including them in Python scripts can lead to even more opportunities for automation. This blog post will guide you to execute ADB shell commands using Python scripts on multiple devices and smooth the exit of the processes using Python’s ‘psutil’ module.
Overview of ADB-Android Debug Bridge
ADB is a component of the Android SDK (Software Development Kit) and is mostly used on Android devices for shell commands, app installation, file transfers, debugging, and viewing device logs.
Main Elements of ADB:
- Client: The device that receives ADB commands.
- Daemon (adbd): An Android device background process that receives and processes ADB commands.
- Server: Manages the daemon and client’s communication. The server operates on your computer in the background.
The most commonly used commands in ADB are:
- Command to connect to a device: #adb connect <device_ip>
- Command to disconnect from a device: #adb disconnect <device_ip>
- List of connected devices: #adb devices
- Install a .apk to the device: #adb install <apk_name>
- Command to view device log: #adb logcat
ADB is incredibly useful for Android developers, testers, and power users because it provides low-level control over Android devices. It is simpler to debug apps, automate processes, and manage devices remotely using ADB. It’s especially useful for performing actions that aren’t easily accessible through the standard Android user interface.
View the output of #adb –help to learn about all of the useful ADB commands.
Overview of ADB Shell
There is ‘adb shell’ command along with the other commands of Android Debug Bridge (ADB) tool, which is used to connect to and manage Android devices from a computer. With the adb shell command, for example, you may run several commands directly on the connected Android device by opening a shell interface.
Key Uses of ‘adb shell’:
When you run adb shell, it opens a shell session on the device, where you can execute Linux-based commands. This can be helpful for managing processes, monitoring system logs, and traversing the file system—tasks that are simpler to complete from the command line.
The common adb shell commands are, e.g., listing files, getting device information, disk usage, etc. You can also run specific commands directly by appending them to adb shell. For example:
#adb shell “ls /sdcard/ “ (lists the files in the /sdcard/ directory on the device.)
#adb shell “iotop” (display and monitor the disk IO usage details of the device)
‘adb shell’ is an effective command for low-level system interaction on Android devices, allowing developers and users to carry out a variety of operations straight from the command line.
Overview of ‘psutil’ Python Module:
A Python package called psutil (Python system and process utilities) is used to get data on processes that are currently operating and system utilization (CPU, memory, storage, network, and sensors). It offers a means of interacting with system operations and collecting different performance indicators.
Some Important features of ‘psutil’
Process Management: Details about active processes, including CPU and memory consumption and status, can be retrieved. Additionally, you can stop or pause processes.
System Monitoring: It lets you keep an eye on the utilization of all system resources, including memory, CPU, disk, and network.
Cross-Platform Compatibility: ‘psutil’ is made to function on a number of different operating systems, including FreeBSD, Linux, Windows, and macOS.
Sensor Data: Psutil can also retrieve sensor data, including battery status, fan speed, and temperature, for systems that it is compatible with.
Psutil is extensively utilized in Python scripts that require system interaction or data collection, system monitoring tools, and performance analysis.
Environment Setup:
- Download the Android SDK Platform Tools ZIP file as per your system’s OS Link: https://developer.android.com/tools/releases/platform-tools
- Extract the zip file and set the directory path in system environment variable.
- Verify the installation from command line using command #adb devices.
- Developer mode should be enabled on all the test android devices.
- Download and install Python as per your system operating system if python is not available in your system. Here is the link: https://www.python.org/downloads/ Please follow the steps which are coming during installation of the python application.
- There are multiple editor and IDE supported for python code development like PyCharm, Visual Studio Code, and Eclipse. Please use any one for your development.
- Install psutil module from command line using below command.
# pip install psutil
Sample Use Case:
Recently, I developed a script to monitor disk utilization across several Android devices as they spend a few hours watching OTT or live video. A tool like Witbe, etc., or an open-source automation framework can be used to play content on an Android smartphone. I’ll talk about this in a separate blog post. You may like my another blog on Appium Inspector https://dasfascination.com/exploring-appium-inspector-features/
Together with the parent process, (the script that calls the ‘adb shell’), all child processes (‘adb shell’, ‘cmd’) must be cleanly terminated. Python’s module ‘psutil’ is used to identify the unique identifier of all the child processes and to kill those processes.
Sample Code:
This automation flow of the above sample use case
- Power on the device
- Connect the Android device.
- Start ADB Shell command in the background to check 1 hour disk usage of the device and save the output in a file. The command on ‘adb shell’ is “iotop -P -m 50 -s write -a -d 10 >> ” + filename + ” &”
- Play Live content for 3 hours.
- Pull the file from the device which contains the disk usage information.
- Again, repeat steps 2–5, but with OTT content playback.
- Again, repeat steps 2–5, with the live content playback.
The sample code to execute the ADB Shell command is below:
def start_adb_command(filename):
command_1 = "adb connect "+ DEVICE_IP
command_2 = "iotop -P -m 50 -s write -a -d 10 >> " + filename + " &"
command_3 = "adb -s " + DEVICE_IP + " shell " + '"' + command_2 + '"'
print("Connecting the Adb shell")
os.system(command_1)
root_command = "adb -s " + DEVICE_IP + " root "
os.system(root_command)
print("Starting Command iotop")
command_4 = 'start cmd /K ' + command_3
print(command_4)
os.system(command_4)
# 2 second wait to start the process
time.sleep(2)
# check the cmd.exe PID for clean exit at the end
processes = [p for p in psutil.process_iter(['pid', 'name', 'create_time']) if p.info['name'] == 'cmd.exe']
#
# # Sort processes by creation time
processes.sort(key=lambda p: p.info['create_time'], reverse=True)
# Get the last started cmd.exe process
if processes:
last_cmd_process = processes[0]
start_time = datetime.fromtimestamp(last_cmd_process.info['create_time'])
target_cmd_pid = last_cmd_process.info['pid']
print("Last cmd.exe process PID: ", target_cmd_pid, "start_time: ", start_time)
else:
print("No cmd.exe process found.")
# check the adb.exe PID for clean exit at the end
processes = [p for p in psutil.process_iter(['pid', 'name', 'create_time']) if p.info['name'] == 'adb.exe']
#
# # Sort processes by creation time
processes.sort(key=lambda p: p.info['create_time'], reverse=True)
# Get the last started cmd.exe process
if processes:
last_adb_process = processes[0]
start_time = datetime.fromtimestamp(last_adb_process.info['create_time'])
target_adb_pid = last_adb_process.info['pid']
print("Last adb.exe process PID: ", target_adb_pid, "start_time: ", start_time)
else:
print("No adb.exe process found.")
return target_adb_pid, target_cmd_pid
The sample code to pull the disk usage file from the device.
def adb_pull(filename):
print("Connecting to the STB")
command_1 = "adb connect "+ DEVICE_IP
os.system(command_1)
root_command = "adb -s " + DEVICE_IP + " root "
os.system(root_command)
command = "adb -s " + DEVICE_IP + " pull " + filename
os.system(command)
print("File pulled from DEVICE")
The part of the main function
adb_pid1, cmd_pid1 = start_adb_command("/data/emmc_stby.log")
print("Playing Live service for 3 hours")
live_service_3_hour()
adb_pull("/data/emmc_stby.log")
if pid_exists(adb_pid1):
os.kill(adb_pid1, signal.SIGTERM)
Key Points to explain:
- To check disk usage for 1 hour on ADB shell, another command process with the ‘iotop’ command is launched (command_4).
- ‘psutil’ module is used to know all the last process ID by creating time (psutil.process_iter)
- Sort the process ID and check the last launched ADB process and CMD process ID to kill at the end of the script.
- The OS module function os.kill is used to kill the launched adb and cmd processes for a clear exit of the script execution.