Exemplo n.º 1
0
def _write_data_to_file(data: list, file: _io.TextIOWrapper) -> None:
    """
    write data to file
    :param data:
    :param file:
    :return:
    """
    file.writelines(data)
    file.flush()
Exemplo n.º 2
0
def parseLogDir(destDir: str,
                resonFile: TextIOWrapper,
                packageName: str = DEFAULT_PACKAGE):
    #保存所有公共变量
    globalValues = GlobalValues()
    #获取目录下的所有文件
    allFiles = toolUtils.getAllFileName(destDir)
    #获取所有的 system log文件
    systemFiles = [file for file in allFiles if 'system.txt' in file]
    systemFiles.sort(reverse=True)
    #获取所有的 events log文件
    eventFiles = [file for file in allFiles if 'events.txt' in file]
    eventFiles.sort(reverse=True)
    #获取所有的 main log文件
    mainFiles = [file for file in allFiles if 'main.txt' in file]
    mainFiles.sort(reverse=True)
    #获取所有的 radio log文件
    radioFiles = [file for file in allFiles if 'radio.txt' in file]
    radioFiles.sort(reverse=True)
    #获取所有的 kernel log文件
    kernelFiles = [file for file in allFiles if 'kernel.txt' in file]
    kernelFiles.sort(reverse=True)
    #获取所有的 crash log文件
    crashFiles = [file for file in allFiles if 'crash.txt' in file]
    #获取所有的 anr trace文件
    anrFiles = [
        file for file in allFiles
        if sep.join(['anr', 'anr_' + str(packageName)]) in file
    ]
    anrFiles.sort(reverse=False)
    #获取所有的 system.prop文件
    propFiles = [file for file in allFiles if 'system.prop' in file]
    #解析prop文件获取手机信息
    propMsg = toolUtils.parseProp(propFiles)

    #添加所有需要需要解析的log文件
    parseFiles = []
    for f in systemFiles:
        parseFiles.append(f)
    for f in eventFiles:
        parseFiles.append(f)
    for f in mainFiles:
        parseFiles.append(f)
    for f in radioFiles:
        parseFiles.append(f)
    for f in kernelFiles:
        parseFiles.append(f)
    #用于保存重要的信息行LogLine对象
    allLine = []
    #用于保存所有的Anr对象
    allAnr = []
    # 从systemui解析有多少个anr
    systemLog = SystemLog(systemFiles, allAnr, globalValues, packageName)
    systemLog.findAllAnr()
    if len(allAnr) == 0:
        eventLog = EventLog(eventFiles, allAnr, globalValues, packageName)
        eventLog.findAllAnr()
    #解析所有的anr trace
    mainStacks = list()
    blockStacks = dict()
    pattern = 'anr_[\w|\.]+_([\d]+)_([\d|-]+)'
    parseTracesPids = list()
    tracesLogs = []
    for file in anrFiles:
        match = re.match(pattern, basename(file))
        if match:
            pid = match.group(1)
            if not pid in parseTracesPids:
                parseTracesPids.append(pid)
                willParser = False
                for anr in allAnr:
                    if str(pid) == str(anr.pid):
                        willParser = True
                if willParser:
                    log(file)
                    trace = TracesLog(file, globalValues, packageName)
                    trace.parser()
                    tracesLogs.append(trace)
                    stack: ThreadStack = trace.getMainStack()
                    #如果堆栈出现两次相同则加入到数列中
                    if stack != None:
                        mainStacks.append(stack)
    #最后一行main log,用于验证main log是否包含anr时间
    mainLine = None
    #保存最后发生anr的时间,当mainLine时间小于anr时间则main log不全
    anrTimeFloat = 0
    for file in parseFiles:
        log('--' + file + '--')
        with open(file, encoding=toolUtils.checkFileCode(file)) as mFile:
            #全局变量,当前解析的文件
            globalValues.currentFile = file
            linenum = 0
            #是否在解析main log
            isMainLine = True if ('main.txt' in file) else False
            while True:
                line = mFile.readline()
                linenum = linenum + 1
                if not line:
                    break
                else:
                    line = line.strip()
                    temp = LogLine(line, linenum, globalValues)
                    if temp.isLogLine:
                        #保存最后一行main log
                        if isMainLine:
                            if (mainLine == None
                                    or temp.timeFloat > mainLine.timeFloat):
                                mainLine = temp
                            if temp.pid == temp.tid:
                                for anr in allAnr:
                                    temp.addAnrMainLog(anr)
                        #解析该行
                        parseLine(allAnr, allLine, temp, packageName)

    log('####################start write######################')
    if GLOBAL_VALUES.only_filter:
        for line in allLine:
            if line.filter:
                start = len(dirname(dirname(dirname(destDir)))) + 1
                resonFile.writelines("filter: in file {} -> line={}\n".format(
                    line.file[start:], line.linenum))
                resonFile.writelines("\t{}\n".format(line.line.strip()))
        return globalValues
    #将手机的信息写入到文件

    for (key, value) in propMsg.items():
        temp = "{}:{}\n".format(key, value)
        globalValues.showMessage.append(temp)
        resonFile.writelines(temp)
    temp = '\n'
    globalValues.showMessage.append(temp)
    resonFile.writelines(temp)

    #讲对应的am anr添加到主要信息中
    for anr in allAnr:
        if not anr.anrCoreLine and anr.anrCoreReserveLine:
            anr.setCoreLine(anr.anrCoreReserveLine)
        anr.computerAnrTime()
        anr.findAllCoreLine(allLine)
        if len(anr.systemAnr.lines) >= 8:
            for line in anr.systemAnr.lines[0:8]:
                allLine.append(line)

    #保存发生anr的pid,从堆栈trace中查找对应的pid
    pids = []
    #将所有的anr信息输出到文件
    for anr in allAnr:
        pids.append(anr.pid)
        temp = "pid:" + str(anr.pid) + '\n' + "发生时间:" + str(
            anr.anrTimeStr) + '\n' + "发生原因:" + anr.anrReason + '\n\n'
        globalValues.showMessage.append(temp)
        resonFile.writelines(temp)
        mainMsg: [] = anr.addMainLogBlock(allLine)
        if mainMsg:
            font = mainMsg[0]
            back = mainMsg[1]
            temp = ('主线程阻塞:{}  ==>  {}\n\t{}\n\t{}'.format(
                font.timeStr, back.timeStr, font.line, back.line)) + '\n\n'
            globalValues.showMessage.append(temp)
            resonFile.writelines(temp)

        startDelayLine = anr.anrCoreLine
        key = lambda line: line.delayStartTimeFloat
        if anr.anrCoreLines:
            temp = '核心log:\n'
            globalValues.showMessage.append(temp)
            resonFile.writelines(temp)
            delayLines = [
                delayLine for delayLine in anr.anrCoreLines
                if delayLine.isDelayLine
            ]
            for line in delayLines:
                temp = '\t' + line.line + '\n'
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)
                temp = "\t\tstartTime:{}\n".format(line.delayStartTimeStr)
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)
            delayLines = sorted(delayLines, key=key, reverse=True)
            for line in delayLines:
                if startDelayLine == None or (
                        line.delayStartTimeFloat <
                        startDelayLine.delayStartTimeFloat and
                        line.timeFloat > startDelayLine.delayStartTimeFloat):
                    startDelayLine = line
            temp = '\n'
            globalValues.showMessage.append(temp)
            resonFile.writelines(temp)

            # 输出阻塞的堆栈
        for stack in [
                stack for item in mainStacks if str(item.pid) == str(anr.pid)
        ]:
            if stack:
                temp = '\t\nmain pid=' + str(stack.pid) + ' time=' + str(
                    stack.pidStack.time) + ' java栈:' + '\t\n\t' + str(
                        stack.top) + '\n'
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)
                temp = '\t\t' + '\n\t\t'.join(stack.javaStacks if len(
                    stack.javaStacks) < 10 else stack.javaStacks[0:10])
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)
                temp = '\n\n'
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)

        if startDelayLine:
            temp = '起始阻塞log:\n' + '\t' + startDelayLine.line + "\n\t\tstartTime:{}\n".format(
                startDelayLine.delayStartTimeStr) + '\n'
            globalValues.showMessage.append(temp)
            resonFile.writelines(temp)

        log(anr.anrTimeStr)
        log(anr.anrTimeFloat)
        #获取最后发生anr的时间,用于推断main log是否全
        if anr.anrTimeFloat > anrTimeFloat:
            anrTimeFloat = anr.anrTimeFloat
        log(anr.anrReason)
    # 将主要信息按时间排序
    allLine.sort(key=lambda line: line.timeFloat)
    #判断是否main log不足
    if mainLine != None and (mainLine.timeFloat < anrTimeFloat):
        log("main log 不足")
        temp = "main log 不足 time:" + str(
            toolUtils.getTimeStamp(mainLine.timeFloat)) + '\n\n'
        globalValues.showMessage.append(temp)
        resonFile.writelines(temp)
    #输出pid和线程名称到文件
    if len(globalValues.pidMap) > 0:
        temp = "线程名称:\n\t"
        resonFile.writelines(temp)
        globalValues.showMessage.append(temp)
        count = 0
        temp = ''
        for key in sorted(globalValues.pidMap.keys()):
            temp = temp + 'pid={} : name={},\t\t'.format(
                key, globalValues.pidMap[key])
            count = count + 1
            if len(temp) > 80:
                temp = temp + '\n\t'
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)
                temp = ''
        if len(temp) > 0:
            resonFile.writelines(temp)
            globalValues.showMessage.append(temp)
    #查找最异常binder
    hungerBinder = dict()
    maxBinderNum = 0
    maxBinder = ''
    for key, value in globalValues.hungerBinders.items():
        newKey = '{}:{}'.format(key.split(':')[0], value.split(':')[0])
        if newKey in hungerBinder.keys():
            hungerBinder[newKey] = hungerBinder[newKey] + 1
        else:
            hungerBinder[newKey] = 1
        if maxBinderNum < hungerBinder[newKey]:
            maxBinder = newKey
            maxBinderNum = hungerBinder[newKey]

    if hungerBinder:
        temp = '\n\ndump时候异常binder 等待binder共有{}个:'.format(
            len(globalValues.hungerBinders))
        for key, value in hungerBinder.items():
            if maxBinderNum == value or value > 3 or len(hungerBinder) == 1:
                pids = key.split(':')
                fromPid = int(pids[0])
                if fromPid in globalValues.pidMap:
                    fromPid = '{}({})'.format(fromPid,
                                              globalValues.pidMap[fromPid])
                toPid = int(pids[1])
                if toPid in globalValues.pidMap:
                    toPid = '{}({})'.format(toPid, globalValues.pidMap[toPid])
                temp = temp + '\n\t其中 binder form pid:{} to pid:{}, 数量 = {}。'.format(
                    fromPid, toPid, value)

        globalValues.showMessage.append(temp)
        resonFile.writelines(temp)

    if len(tracesLogs) > 0 and len(tracesLogs[0].suspiciousStack) > 0:
        temp = '\n\n阻塞线程\n'
        globalValues.showMessage.append(temp)
        resonFile.writelines(temp)
        for tracesLog in tracesLogs:
            temp = '\n'
            for title, stack in tracesLog.suspiciousStack.items():
                pidStack: PidStack = stack
                if len(pidStack.javaStacks) < 10:
                    temp = '{}\t{}\n\t\t{}\n'.format(
                        temp, title, '\n\t\t'.join(pidStack.javaStacks))
                else:
                    temp = '{}\t{}\n\t\t{}\n\t\t{}\n\t\t{}\n'.format(
                        temp, title, '\n\t\t'.join(pidStack.javaStacks[:5]),
                        '......', '\n\t\t'.join(pidStack.javaStacks[-4:]))
                globalValues.showMessage.append(temp)
                resonFile.writelines(temp)

    temp = '\n'
    globalValues.showMessage.append(temp)
    resonFile.writelines(temp)
    log("len ==  " + str(len(allLine)))
    #未找到相关log
    if (len(allLine)) == 0 and mainLine != None:
        log(mainLine.timeFloat)
        log(anrTimeFloat)
    else:
        #输出所有的分析行信息到文件
        resonFile.writelines("\n关键log:\n")
        for line in allLine:
            if line.filter:
                start = len(dirname(dirname(dirname(destDir)))) + 1
                resonFile.writelines(
                    "\n filter: in file {} -> line={}\n".format(
                        line.file[start:], line.linenum))
                resonFile.writelines("\t{}\n".format(line.line.strip()))
            else:
                if line.isAnrCore:
                    start = len(dirname(dirname(dirname(destDir)))) + 1
                    resonFile.writelines(
                        "\n  My Anr core: in file {} -> line={}\n\n".format(
                            line.file[start:], line.linenum))
                resonFile.writelines("\t{}\n".format(line.line.strip()))
                if line.isDelayLine:
                    resonFile.writelines("\t\tstartTime:{}\n".format(
                        line.delayStartTimeStr))
        resonFile.writelines("\n")

    # 判断是否有anr
    if len(allAnr) == 0:
        temp = ("{}未找到anr报错信息\n".format(basename(destDir)))
        logUtils.info(temp)
        globalValues.showMessage.append(temp)
        resonFile.writelines(temp)
    log('####################end write######################')
    return globalValues