adb command in "self timer 44" to intercept Logcat log with one click

This article is very difficult, reading time is long, and the experience is advanced...

During Android system test or App test,
Some Android terminal devices do not start the logcat sequence log with the system because the disk is too small,
That is, the logcat log is not intercepted in the background in real time, so the tester needs to manually intercept the logcat log,
In this case, we usually use direct cmd, ADB logcat - V threadtime > D: \ logcat.txt,
Use the above command to manually intercept the Logcat log.
I once considered a more convenient and quick Python script to intercept Logcat,
Directly click to run the Python script without manually typing the above command!
This week focuses on the command line call through subprocess.Popen() class to destroy (kill) the process!


Preparation stage
  1. ADB logcat - V threadime > D: \ logcat.Txt can print and save the log by thread time to a file.
  2. Since the adb logcat command is a continuous output command,
    If it is not destroyed (killing process), it will continue to be intercepted.
  3. The os.system() function and os.popen() function are not suitable for sub process destruction,
    At this time, we need to consider a higher-end subprocess.Popen() class to implement process destruction.

Introduction to subprocess.Popen() class

Python officially recommends using the subprocess.Popen() class to invoke other commands (that is, create subprocesses),
It has the characteristics of high-quality sub process management (creation, destruction, standard input, standard output, error output, etc.).
Why is it a class rather than a function? See the screenshot of the source code:

Since it is a class, first look at the initialization source code of this class:

    def __init__(self, args, bufsize=-1, executable=None,
                 stdin=None, stdout=None, stderr=None,
                 preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=None,
                 startupinfo=None, creationflags=0,
                 restore_signals=True, start_new_session=False,
                 pass_fds=(), *, encoding=None, errors=None, text=None):


We only need to know the following initialization parameters:

parameter Interpretation Example of parameter initialization
args Command or command array to be executed by subprocess args="adb reboot"
args=["adb", "reboot"]
stdin standard input
Define the standard input object of a subprocess
If our subprocesses do not need interactive input subsequently:
stdin=None (default)
If our subprocesses need interactive input:
stdin=subprocess.PIPE
stdin=None
or
stdin=subprocess.PIPE
stdout standard output
Define the standard output of a subprocess.
If we don't need to capture standard output: stdout=None (default)
If you need to capture and analyze the standard output: stdout=subprocess.PIPE
If you need to store the standard output: stdout=open("log.txt","wb")

stdout=None
or
stdout=subprocess.PIPE
or
stdout=open("log.txt","wb")
stderr standard error
Define the standard exception error message of a subprocess,
If we don't need to catch exception error message: stderr=None (default)
If you need to catch and analyze abnormal errors: stderr=subprocess.PIPE
If you need to store exception errors: stderr=open("log.txt","wb")

stderr=None
or
stderr=subprocess.PIPE
or
stderr=open("log.txt","wb")
shell If the subprocess is required to pass cmd /c
Or / system/bin/sh -c, you must shell=True.
For our general command, please use shell=False (default value) directly.

For example, if you execute the adb command on windows,
If shell=True, the cmd process is additionally called, followed by the adb process
If shell=False, only the adb process will be called (this is recommended)

shell=False
or
shell=True


If it is a class, it must be instantiated into an object before concrete operations can be performed,
If it is a class, it involves the definition of the class's attributes (variables), methods (functions),
We assume that the name of the initialized object is p obj, which is interpreted as follows:

List of properties (variables) Interpretation
p_obj.pid Process pid of subprocess object
p_obj.returncode Of subprocess object: current state
None: the command representing the subprocess is still executing, unable to get its status
0: the subprocess command is executed normally and ends normally
1: It means the end of an exception, such as being kill ed or terminate d
p_obj.args Executed by subprocess object: specific command


Method (function) list Interpretation
Method (function) list Interpretation
p_obj.kill() On the Windows system, the same function as terminate() is to kill the process
On Linux system, SIGTKILL signal is sent, that is, kill your process forcibly, similar to kill-9

Universal recommended usage (perform the following 2 functions in sequence):
p_obj.terminate()
p_obj.kill()
p_obj.terminate() On the Windows system, the same function as terminate() is to kill the process
On the Linux system, SIGTERM signal is sent, that is, to inform the subprocess to finish by itself, similar to kill-15

Universal usage (perform the following 2 functions in sequence):
p_obj.terminate()
p_obj.kill()


Python batch script form
# coding=utf-8
import os
import subprocess
from datetime import datetime

command = "adb logcat -v threadtime"

now_time = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = "Logcat_" + now_time + ".txt"

hf = open("%s" % log_file, "wb")
# Because no specific path is specified, the default is to create the log file under the current script running path

# Start adb command
p_obj = subprocess.Popen(
        args=command,
        stdin=None, stdout=hf,
        stderr=hf, shell=False)

print("Logcat catching...")
# Keep asking if you need to stop intercepting
judgement = input("If you think it is enough, please input Y:")
while (judgement != "Y" and judgement != "y"):  ###This must be and
    print("Invalid input, please input Y")
    judgement = input("If you think it is enough, please input Y:")
else:
    if (judgement == "Y" or judgement == "y"):  # If the stop Yes signal is received, the interception begins and ends
        p_obj.terminate()
        p_obj.kill()

hf.close()
print("Logcat log has saved to %s" % os.path.abspath(log_file))
os.system("pause")


Python procedure oriented function form

In this optimization, the COMMAND is used as a constant, and the constant is generally all uppercase in coding style.
When it comes to open reading and writing of files, try to use with form.

# coding=utf-8
import os
import subprocess
from datetime import datetime

COMMAND = "adb logcat -v threadtime"


def catch_logcat():
    now_time = datetime.now().strftime("%Y%m%d_%H%M%S")
    log_file = "Logcat_" + now_time + ".txt"
    # Because no specific path is specified, the default is to create the log file under the current script running path

    # Start adb command
    with open("%s" % log_file, "wb") as hf:
        p_obj = subprocess.Popen(
                args=COMMAND,
                stdin=None, stdout=hf,
                stderr=hf, shell=False)

        print("Logcat catching...")
        # Keep asking if you need to stop intercepting
        judgement = input("If you think it is enough, please input Y:")
        while (judgement != "Y" and judgement != "y"):  ###This must be and
            print("Invalid input, please input Y")
            judgement = input("If you think it is enough, please input Y:")
        else:
            if (judgement == "Y" or judgement == "y"):  # If the stop Yes signal is received, the interception begins and ends
                p_obj.terminate()
                p_obj.kill()

    return os.path.abspath(log_file)


print("Logcat log has saved to %s" % catch_logcat())
os.system("pause")


Python object oriented form

This optimization:

  1. When initializing a class, do what you have to do.
    LogcatCatcher() class initialization does not need any parameter input, but it needs to create 2 new properties,
    These two properties must be created during initialization.
  2. For functions (or attributes) that are not necessarily exposed to other modules, try to consider privatization. Just add; such as \.
# coding=utf-8
import os
import subprocess
from datetime import datetime

COMMAND = "adb logcat -v threadtime"  # constant


class LogcatCathcher():
    def __init__(self):
        self.log_file = None
        self.hf = None
        self._create_hf()
        self.p_obj = subprocess.Popen(
                args=COMMAND,
                stdin=None, stdout=self.hf,
                stderr=self.hf, shell=False)

    def _create_hf(self):
        now_time = datetime.now().strftime("%Y%m%d_%H%M%S")
        self.log_file = "Logcat_" + now_time + ".txt"
        # Because no specific path is specified, the default is to create the log file under the current script running path
        self.hf = open("%s" % self.log_file, "wb")

    def catch_logcat(self):
        print("Logcat catching...")
        # Keep asking if you need to stop intercepting
        judgement = input("If you think it is enough, please input Y:")
        while (judgement != "Y" and judgement != "y"):  ###This must be and
            print("Invalid input, please input Y")
            judgement = input("If you think it is enough, please input Y:")
        else:
            if (judgement == "Y" or judgement == "y"):  # If the stop Yes signal is received, the interception begins and ends
                self.p_obj.terminate()
                self.p_obj.kill()
                self.hf.close()  # close a file handle
        return os.path.abspath(self.log_file)


if __name__ == '__main__':
    l_obj = LogcatCathcher()
    print("Logcat log has saved to %s" % l_obj.catch_logcat())
    os.system("pause")


Code operation mode

Make sure the Android device is connected to the computer through the USB cable, and the adb device is effectively connected,
The three implementation forms of the above code can be run directly, for example, saved as catch ﹣ logcat.py and placed on the desktop,
It is recommended to run Python catch ﹣ logcat.py, or double-click it.
The operation effect is as follows:


When you encounter complex source code, don't worry. Slowly analyze it according to the above methods,
It is very necessary to check Official subprocess module documentation of Python Or comments on the source code;
If you still don't understand, you can read python's source code for subprocess (C:\Users
\Administrator\AppData\Local\Programs\Python\Python37-32\Lib\subprocess.py),
If you want to know how others call it, you can use findstr or grep to search the whole folder of python37-32,
How many source code modules call subprocess.Popen to see how others call it.
If you have no problem with the method you call, but an error is reported, you can search www.bing.com for the reason of the code error,
There are always more ways than difficulties. Come on!


For more and better original articles, please visit the official website: www.zipython.com
Selfie course (Python course of automatic test, compiled by Wu Sanren)
Original link: https://www.zipython.com/#/detail?id=d6b406f34b4f470a9d95eddc426a273c
You can also follow the wechat subscription number of "wusanren" and accept the article push at any time.

Tags: Python shell Android Windows

Posted on Tue, 17 Mar 2020 05:55:01 -0700 by babyrocky1