driver5.py代码分析

Posted pudding

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了driver5.py代码分析相关的知识,希望对你有一定的参考价值。

#!/usr/bin/env python

import sys
import os
import subprocess
import logging
from threading import Thread

import plg.utils.androidutil as au
import plg.utils.logcat as lc
from plg.metadata import getmetadata
from plg.explore import explore
from plg.settings import LAUNCHER_PKG
from plg.androdevice import run_monkey

MAX_EMULATOR_WAIT = 120 # in seconds

def finish(device):
    print(‘killing‘, device, file=sys.stderr)
    au.killemulator(device)



# *args 是一个元组tuple(元组与列表类似,不同之处在于元组的元素不能修改)
# 可以接受序列的输入参数。当函数的参数不确定时,可以使用 *args
def main(avd, app, *args):
    emu_cmd = [‘emulator64-x86‘, ‘@{}‘.format(avd)] #启动模拟器的命令
    
    # 如果输入在args中的前两个元素是:-system filepath
    # 这个是用来指定初始系统文件。提供文件名,以及绝对路径或相对于工作目录的路径
    # 如果不使用此选项,则默认为系统目录中的 system.img 文件
    if args and args[0] == ‘-system‘: 
        emu_cmd.extend(args[:2]) # 顾头不顾尾,取前两个元素放到emu_cmd列表后
        args = args[2:] # args中第三个元素一直到最后重新赋值给args元组
    
    
    #对于计算机上运行的第一个虚拟设备实例,默认值为 5554
    # 在特定计算机上运行的第一个虚拟设备的控制台使用控制台端口 5554 和 adb 端口 5555。
    # 后续实例使用的端口号渐增 2,例如 5556/5557、5558/5559 等。
    # 范围是 5554 到 5682,可用于 64 个并发虚拟设备。 
    port = 5554
    if args:
        port, *args = args
    
    log = ‘log.txt‘
    if args:
        log, *args = args # we will ignore other args
    
    #启动模拟器的命令;
    #extend()函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
    #-no-snapshot-save:执行快速启动,但在退出时不保存模拟器状态
    #-port:设置用于控制台和 adb 的 TCP 端口号
    #-m 512:是给客户机分配 512MB 内存
    #-enable-kvm:利用 KVM 来访问硬件提供的虚拟化服务
    emu_cmd.extend([‘-no-snapshot-save‘, ‘-port‘, str(port), ‘-qemu‘, ‘-m‘,
        ‘512‘, ‘-enable-kvm‘]) 
    
    # the x86 emulators need help finding some libraries
    
    
    
    # environ 是一个字符串所对应环境的映像对象
    #把 android-sdk/tools/lib 添加到 LD_LIBRARY_PATH 路径中
    emu_env = os.environ.copy()
    emu_env[‘LD_LIBRARY_PATH‘] = (‘/home/ubuntu/Android/sdk/‘
        ‘tools/lib‘)
    
    
    device = ‘emulator-{}‘.format(port)

    au.init() # 杀死当前存在的模拟器
    # file=sys.stderr:将当前默认的错误输出结果保存为 file
    print(‘launching‘, device, file=sys.stderr)
    
    # subprocess.Popen 类来处理基本的进程创建和管理
    # 开始执行命令
    subprocess.Popen(emu_cmd, env=emu_env)
    
    
    ‘‘‘ Python的异常处理机制的语法结构: 
    try:
        <语句>
    except <name>:
        <语句>  #如果在try部份引发了名为‘name‘的异常,则执行这段代码
    else:
        <语句>  #如果没有异常发生,则执行这段代码
    ‘‘‘
    try:
        # 等待设备上线
        au.waitfordevice(device, timeout=MAX_EMULATOR_WAIT)
    except subprocess.TimeoutExpired:
        # 保留一个“timeout”用于错误处理
        # 当想要自己的模拟器启动,它实际上可能并没有启动
        print(‘time out expired while waiting for‘, device, file=sys.stderr)
        raise # 该语句引发当前上下文中捕获的异常
    
    
    # 从 time 模块中引入sleep函数
    # 使用sleep函数可以让程序休眠(推迟调用线程的运行)
    from time import sleep
    #sleep(300)   # 休眠300秒
    # getadbcmd():帮助函数,返回命令 adb -s emulator-5554 install app
    # 这个命令的意思是:在emulator-5554模拟器上安装app(.apk)
    install_cmd = au.getadbcmd([‘install‘, app], device)
    
    
    try:
        # 子进程执行install_cmd中的命令,并将其输出形成字符串返回
        subprocess.check_output(install_cmd, stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        info = ‘install-failed ret:%d %s‘ % (e.returncode,
                b‘ ‘.join(e.output.splitlines()))
        print(‘info‘, file=sys.stderr)
        finish(device)

    # config logcat
    lc_file = log
    lc.clearlogcat(device)
    lc.logcat(lc_file, device) # file open/close is done by callee

    metainfo = getmetadata(app)

    # launch monkey to prevent straying and deal with ANRs
    t = Thread(target=run_monkey, args=(device, metainfo[‘name‘]))
    t.daemon = True
    t.start()

    print(‘begin exploring‘)
    explore(device, metainfo)
    print(‘finish exploring‘)
    finish(device)


if __name__ == ‘__main__‘:
    if (‘help‘ in sys.argv or ‘-h‘ in sys.argv or ‘-help‘ in sys.argv or
            len(sys.argv) < 3):
        print(‘usage:‘, sys.argv[0],
                ‘avd app [-system <system.img>] [port [log]]‘)
        sys.exit(2 if len(sys.argv) < 3 else 0)
    logging.basicConfig(level=logging.WARNING, stream=sys.stderr)
    main(*sys.argv[1:])

  • plg.utils.androidutil中的init()函数:
# 杀死任何已存在的模拟器
def init(logfile=None):
    if not logfile:
        logfile = sys.stderr  # 将当前默认的错误输出结果保存为logfile
    print(‘(re)starting adb server‘, file=logfile)
    killserver()
    startserver()
    #sleep(10) # let adb start
    print(‘killing any emulators already present‘, file=logfile)
    for device in getdevices():
        killemulator(device)
  • plg.utils.androidutil中的getadbcmd()函数:
def getadbcmd(args=None, device=None):
    ‘‘‘ helper function:
        args - arguments excluding adb and device‘‘‘
    preargs = [ADB]
    if device:
        #strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
        device = device.strip() 
        if device:
            preargs += [‘-s‘, device]
    if not args:
        return preargs
    return preargs + args

参考文献

以上是关于driver5.py代码分析的主要内容,如果未能解决你的问题,请参考以下文章

Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段

Android 插件化VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )(代码片段

优化 C# 代码片段、ObservableCollection 和 AddRange

分享几个实用的代码片段(附代码例子)

分享几个实用的代码片段(附代码例子)

前端防扒代码片段