Python中使用adb - doranbai/Note GitHub Wiki

使用os.system("cmd")

os.system("cmd")
以阻塞的方式启动一个子进程,仅仅在一个子终端运行系统命令, 而不能获取命令执行后的返回信息(返回信息只会显示在终端上,没有方法读取),返回值是脚本的退出状态码,不能交互。 返回结果为1表示执行成功,返回0表示失败 函数的时候通常会阻塞它的调用者,直到所启动的命令行程序退出。非阻塞方式启动需要在command前面添加start。os.system("start command")

os.popen

以非阻塞的方式启动一个子进程,返回值是脚本执行过程中的输出内容。实际使用时视需求情况而选择。像调用”ls”这样的shell命令,应该使用popen的方法来获得内容。不能交互 从命令cmd打开一个管道,返回值是连接管道的文件对象,通过该对象可以进行读或写。默认以非阻塞,想用阻塞的方式使用read()或readlines()对命令的执行结果进行读操作。read阻塞到标准输出直到执行命令的那个子进程退出。也就是说,如果子进程一直不退出,那么read将卡死在这里。readline的话可以循环读取标准输出,但是子进程不退出一样卡死。另外,如果执行的命令有标准错误输出,将会直接显示到控制台,不能获取

os.popen(command[, mode[, bufsize]]) command -- 使用的命令。

mode -- 模式权限可以是 'r'(默认) 或 'w'。

bufsize -- 指明了文件需要的缓冲大小:0意味着无缓冲;1意味着行缓冲;其它正值表示使用参数大小的缓冲(大概值,以字节为单位)。负的bufsize意味着使用系统的默认值,一般来说,对于tty设备,它是行缓冲;对于其它文件,它是全缓冲。如果没有改参数,使用系统的默认值。

with os.popen(command, "r") as p: r = p.read()

subprocess.call

阻塞,不能交互 ubprocess.call(args[, stdout, ...]):执行args命令,返回值为命令执行状态码; 若未指定stdout,则命令执行后的结果输出到屏幕; 若指定stdout,则命令执行后的结果输出到stdout; 若执行成功,则函数返回值为0;若执行失败,则函数返回值为1; (类似os.system)

subprocess.Popen

subprocess模块中只定义了一个类: Popen。可以使用Popen来创建进程,并与进程进行复杂的交互,非阻塞方式。可以创建子进程并连接子进程的标准输入/输出/错误。越来越强大的函数。从只能获取返回码,到只能获取子进程的标准输出,再到获取标准输入/输出/错误,注意,这个可以输入,也就是可以交互。 subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0) 真长!!! 参数说明:

args:要调用的外部系统命令。参数args可以是字符串或者序列类型(如:list,元组),用于指定进程的可执行文件及其参数。如果是序列类型,第一个元素通常是可执行文件的路径。

bufsize:默认值为0, 表示不缓存,。为1表示行缓存,。其他正数表示缓存使用的大小,,负数-1表示使用系统默认的缓存大小。

stdin、stdout、stdout:分别表示标准输入、标准输出和标准错误。其值可以为PIPE、文件描述符和None等。默认值为None,表示从父进程继承。

shell Linux:参数值为False时,Linux上通过调用os.execvp执行对应的程序。为True时,Linux上直接调用系统shell来执行程序。 Windows:参数shell设为true,程序将通过shell来执行。

executable:用于指定可执行程序。一般情况下我们通过args参数来设置所要运行的程序。如果将参数shell设为 True,executable将指定程序使用的shell。在windows平台下,默认的shell由COMSPEC环境变量来指定。

preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用

cwd:设置子进程当前目录

env:env是字典类型,用于指定子进程的环境变量。默认值为None,表示子进程的环境变量将从父进程中继承。

Universal_newlines:不同操作系统下,文本的换行符是不一样的。如:windows下用’/r/n’表示换,而Linux下用 ‘/n’。如果将此参数设置为True,Python统一把这些换行符当作’/n’来处理。 参数stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。他们可以是PIPE,文件描述符或文件对象,也可以设置为None,表示从父进程继承。subprocess.PIPE,在创建Popen对象时,subprocess.PIPE可以初始化stdin, stdout或stderr参数。表示与子进程通信的标准流。subprocess.STDOUT,创建Popen对象时,用于初始化stderr参数,表示将错误通过标准输出流输出。 此函数返回一个Popen对象。 Popen类具有三个与输入输出相关的属性:Popen.stdin, Popen.stdout和Popen.stderr,分别对应子进程的标准输入/输出/错误

Popen的方法 Popen.poll() 用于检查子进程是否已经结束,设置并返回returncode属性,没有结束返回None。不阻塞

Popen.wait() 等待子进程结束。设置并返回returncode属性。阻塞

Popen.communicate(input=None) 阻塞 与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。

Popen.send_signal(signal) 向子进程发送信号。

Popen.terminate() 停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程。

Popen.kill() 杀死子进程。

Popen.stdin,Popen.stdout ,Popen.stderr 如果在创建Popen对象时,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于向子进程发送指令。否则返回None。 stdin, stdout and stderr specify the executed programs’ standard input, standard output and standard error file handles, respectively. Valid values are PIPE, an existing file descriptor (a positive integer), an existing file object, and None.

Popen.pid 获取子进程的进程ID。

Popen.returncode 获取进程的返回值。如果进程还没有结束,返回None。

import os
import subprocess


with os.popen("adb shell pm path com.doran.RecorderDemo", mode="r") as p:
    path = p.read()

CLASSPATH = path.split(":", 1)[1][0:-1]
LD_LIBRARY_PATH = CLASSPATH.rsplit("/", 1)[0]+"/lib/arm64/:/system/lib64/:/system/lib/"
cmd = "adb shell "+"\""+ "export CLASSPATH="+CLASSPATH+" && export LD_LIBRARY_PATH="+LD_LIBRARY_PATH+" && exec app_process /system/bin com.doran.RecorderDemo.ScreenRecorder \""
cmd = "adb shell "+"\""+ "export CLASSPATH="+CLASSPATH+" && export LD_LIBRARY_PATH="+LD_LIBRARY_PATH+" && exec app_process /system/bin com.doran.RecorderDemo.ScreenRecorder --timelimit 10000\""
# a = os.popen(cmd, 'r', 1)
# print("qqq"+ a.readline())
# a.close()

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines= True)
# with os.popen("adb shell \"ps -A | grep -r app_process\"", "r") as pid:
#     pidnum = pid.read()
pidnum= subprocess.getoutput("adb shell \"ps -A | grep -r app_process\"").split()
print(pidnum)

while True:

    buf = p.stdout.readline()
    if buf:
        print(buf,end='')
    #if(buf=='' and p.poll()!= None):
    if (buf == '' and p.poll() != None):
        break

在文件中,如果遇到一个空白行,readline()并不会返回一个空串,因为每一行的末尾还有一个或多个分隔符,因此“空白行”至少会有一个换行符或者系统使用的其他符号。只有当真的读到文件末尾时,才会读到空串'',不是返回None,也不是所谓的-1 或者报异常。这个跟C 和java等其他语言很不一样。Python中,空串的not返回true,即not line时为读到EOF(文件末尾)。