ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Android:检测内存泄漏的自动化测试Python脚本

2020-04-11 20:00:14  阅读:449  来源: 互联网

标签:info shell Python adb 内存 command Android os logger


以下两个变量根据需求修改:

(1)packageName = "com.android.systemui"

(2)OUTPUT_DIR = os.path.join('d:\\', '\\tools\\tmp\\')    # 目录"D:\tools\tmp"

 

#! /usr/bin/python3
# -*- coding: utf-8 -*-

import os, sys, time, logging

# 下列时间单位均为秒
# 执行时间
exec_time = 15 * 60 * 60  # 10 hours, 可改成60s供测试该脚本
# 记录内存间隔时间,exec_time/exec_interval + 1 即为记录内存次数
exec_interval = 10  # 10 s
# 导出hprof文件间隔
dump_interval = 60 * 60  # 1 hour, 可改成30s供测试该脚本

time_passed = 0
# 打印提示间隔次数,以查看当前进度
print_interval = 1
packageName = "com.android.systemui"
bulid_type = ""

# 所有产生文件的输出目录,必须指定且存在
# OUTPUT_DIR = os.path.join(os.path.expanduser('~'), "test") # 目录"~/test"
OUTPUT_DIR = os.path.join('d:\\', '\\tools\\tmp\\')  # 目录"D:\tools\tmp"

logger = logging.getLogger('memoryleak')
FILE_LOG = True
LOG_LEVEL = logging.DEBUG


def init_logger():
    logger.setLevel(LOG_LEVEL)
    # create formatter
    # [%(filename)s:%(lineno)d] 代码位置,暂不配
    log_format = logging.Formatter("%(asctime)s %(name)s %(levelname)-8s: %(message)s")

    def add_ch():
        # create console handler and set level to debug
        ch = logging.StreamHandler()
        ch.setLevel(LOG_LEVEL)
        ch.setFormatter(log_format)
        # add handler to logger
        logger.addHandler(ch)

    def add_fh():
        logfile = os.path.join(OUTPUT_DIR, "memoryleak_" + time.strftime('%Y%m%d%H%M%S') + ".log")
        fh = logging.FileHandler(logfile)
        fh.setLevel(LOG_LEVEL)
        fh.setFormatter(log_format)
        logger.warning('log will be outputed to console and file:[%s]' % logfile)
        logger.addHandler(fh)

    add_ch()
    if not (OUTPUT_DIR and os.path.isdir(OUTPUT_DIR) and os.access(OUTPUT_DIR, os.W_OK)):
        logger.error('OUTPUT_DIR: ' + OUTPUT_DIR + ' not exist or not writable, please check it up, exiting...')
        sys.exit(-1)
    if FILE_LOG:
        add_fh()


def start_monkey():
    # adb shell monkey -p com.gionee.filemanager --throttle 800 -v -v 300
    command = "adb shell monkey -p " + packageName
    command += " --ignore-crashes"
    command += " --ignore-timeouts"
    command += " --ignore-security-exceptions"
    command += " --ignore-native-crashes"
    command += " --monitor-native-crashes"
    command += " --throttle 800"
    command += " -v -v 1000000"
    command += " > " + os.path.join(OUTPUT_DIR, "monkeytest.log")
    logger.info("插入monkey命令:" + command)
    os.popen(command)


def record_memory():
    global time_passed
    if "eng" in bulid_type:
        memfile = os.path.join(OUTPUT_DIR, 'procrank.txt')
        # 第一次执行命令
        command = 'adb shell \"procrank | grep ' + packageName + '\|cmdline' + ' > ' + memfile
        # 后续执行命令
        commandOther = 'adb shell \"procrank | grep ' + packageName + ' >> ' + memfile + "\""
    else:
        memfile = os.path.join(OUTPUT_DIR, "meminfo.txt")
        command = 'adb shell \"dumpsys meminfo ' + packageName + \
                             ' | grep "Dalvik Heap" -A 14 -B 4 | grep -ie Private -ie Tota\"' + ' > ' + memfile
                             
        commandOther = 'adb shell \"dumpsys meminfo ' + packageName + ' | grep TOTAL -m 1\"' + ' >> ' + memfile

    exec_count = exec_time // exec_interval + 1
    logger.info("开始记录内存信息,待记录次数:" + str(exec_count))
    for i in range(exec_count):
        os.popen(command)  # 运行命令
        # 执行初始命令后切换为后续命令
        if i == 0:
            command = commandOther

        if i % print_interval == 0:
            logger.info("当前记录内存次数: " + str(i))

        if (time_passed) % dump_interval == 0:
            logger.info("当前dump hprof次数: " + str(time_passed // dump_interval))
            dumpheap(str(time_passed // dump_interval))

        time_passed += exec_interval
        time.sleep(exec_interval)  # 休息n秒,再进入下一个循环,也就是每隔n秒打印一次procrank的信息

    logger.info("记录内存信息结束")  # 运行完毕的标志


def dumpheap(name):
    command = "adb shell \"am dumpheap " + packageName + " /data/local/tmp/hprofs/\""
    command += "count" + name + ".hprof"
    os.popen(command)


def stop_monkey():
    # adb shell kill -9 `adb shell ps | grep com.android.commands.monkey | awk '{print $2}'`
    pid = os.popen("adb shell \"ps | grep monkey | awk '{print $2}'\"").read()
    pid = pid.replace("\n", "")
    logger.info("monkey pid is: " + pid + ", kill it")
    os.system("adb shell kill " + pid)


def copyheap():
    logger.info("开始导出hprof文件...")
    os.system("adb pull /data/local/tmp/hprofs/ " + OUTPUT_DIR)
    os.system("adb shell rm -r /data/local/tmp/hprofs")
    logger.info("导出hprof文件结束")


# Ensure in eng release or seleted app has flag android:debuggable="true"
def check_env():
    global bulid_type
    bulid_type_prop = os.popen("adb shell \"getprop | grep ro.build.type\"").read()
    logger.info("当前rom版本信息 :" + bulid_type_prop)
    if "eng" in bulid_type_prop:
        bulid_type = "eng"
        logger.info("当前rom版本: eng")
    elif "userdebug" in bulid_type_prop:
        bulid_type = "userdebug"
        logger.info("当前rom版本: userdebug")
    else:
        bulid_type = "user"
        logger.info("当前rom版本: user")
        package_flags = os.popen("adb shell \"dumpsys package " + packageName + " | grep pkgFlags=\"").read()
        if "DEBUGGABLE" not in package_flags:
            logger.info("当前为user版本且应用没有设置android:debuggable=\"true\", 无法导出内存信息, 请确认环境。")
            sys.exit(-1)

    # 清空及建立hprof文件存放目录
    if 'hprofs' in os.popen('adb shell ls /data/local/tmp').read():
        logger.info('在设备中清除上次运行产生的临时目录"/data/local/tmp/hprofs"...')
        os.system("adb shell rm -r /data/local/tmp/hprofs")
    logger.info('在设备中新建临时目录"/data/local/tmp/hprofs"...')
    os.system("adb shell mkdir -p /data/local/tmp/hprofs")


def main():
    init_logger()
    check_env()
    start_monkey()
    # 循环进行,程序主体
    record_memory()
    stop_monkey()
    copyheap()


if __name__ == '__main__':
    main()

 

标签:info,shell,Python,adb,内存,command,Android,os,logger
来源: https://www.cnblogs.com/blogs-of-lxl/p/12681847.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有