diff --git a/README.md b/README.md index ef8c1e621..85acb5cae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Matrix-icon](assets/img/readme/header.png) -[![license](http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](https://github.com/Tencent/matrix/blob/master/LICENSE)[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/matrix/pulls)[![WeChat Approved](https://img.shields.io/badge/Wechat%20Approved-0.5.1-red.svg)](https://github.com/Tencent/matrix/wiki) +[![license](http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](https://github.com/Tencent/matrix/blob/master/LICENSE)[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/matrix/pulls)[![WeChat Approved](https://img.shields.io/badge/Wechat%20Approved-0.5.2-red.svg)](https://github.com/Tencent/matrix/wiki) (中文版本请参看[这里](#matrix_cn)) @@ -172,7 +172,7 @@ At this point, Matrix has been integrated into the app and is beginning to colle 1. Configure `MATRIX_VERSION` in gradle.properties. ``` gradle - MATRIX_VERSION=0.5.1 + MATRIX_VERSION=0.5.2 ``` 2. Add `matrix-gradle-plugin` in your build.gradle: @@ -289,11 +289,11 @@ You can get more about Matrix output at the wiki [The output of Matrix](https:// #### APK Checker Usage -APK Checker can run independently in Jar ([matrix-apk-canary-0.5.1.jar](https://jcenter.bintray.com/com/tencent/matrix/matrix-apk-canary/0.5.1/matrix-apk-canary-0.5.1.jar)) mode, usage: +APK Checker can run independently in Jar ([matrix-apk-canary-0.5.2.jar](https://jcenter.bintray.com/com/tencent/matrix/matrix-apk-canary/0.5.2/matrix-apk-canary-0.5.2.jar)) mode, usage: ```shell -java -jar matrix-apk-canary-0.5.1.jar +java -jar matrix-apk-canary-0.5.2.jar Usages: --config CONFIG-FILE-PATH or @@ -352,7 +352,7 @@ Matrix is under the BSD license. See the [LICENSE](https://github.com/Tencent/Ma # Matrix ![Matrix-icon](assets/img/readme/header.png) -[![license](http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](https://github.com/Tencent/matrix/blob/master/LICENSE)[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/matrix/pulls) [![WeChat Approved](https://img.shields.io/badge/Wechat%20Approved-0.5.1-red.svg)](https://github.com/Tencent/matrix/wiki) +[![license](http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](https://github.com/Tencent/matrix/blob/master/LICENSE)[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/matrix/pulls) [![WeChat Approved](https://img.shields.io/badge/Wechat%20Approved-0.5.2-red.svg)](https://github.com/Tencent/matrix/wiki) **Matrix** 是一款微信团队研发并日常使用的应用性能接入框架,支持iOS, macOS和Android。 Matrix 通过接入各种性能监控方案,对性能监控项的异常数据进行采集和分析,输出相应的问题分析、定位与优化建议,从而帮助开发者开发出更高质量的应用。 @@ -510,7 +510,7 @@ Matrix-android 当前监控范围包括:应用安装包大小,帧率变化 1. 在你项目根目录下的 gradle.properties 中配置要依赖的 Matrix 版本号,如: ``` gradle - MATRIX_VERSION=0.5.1 + MATRIX_VERSION=0.5.2 ``` 2. 在你项目根目录下的 build.gradle 文件添加 Matrix 依赖,如: @@ -624,10 +624,10 @@ Matrix 分析后的输出字段的含义请查看 [Matrix 输出内容的含义 #### APK Checker -APK Check 以独立的 jar 包提供 ([matrix-apk-canary-0.5.1.jar](https://jcenter.bintray.com/com/tencent/matrix/matrix-apk-canary/0.5.1/matrix-apk-canary-0.5.1.jar)),你可以运行: +APK Check 以独立的 jar 包提供 ([matrix-apk-canary-0.5.2.jar](https://jcenter.bintray.com/com/tencent/matrix/matrix-apk-canary/0.5.2/matrix-apk-canary-0.5.2.jar)),你可以运行: ```cmd -java -jar matrix-apk-canary-0.5.1.jar +java -jar matrix-apk-canary-0.5.2.jar ``` 查看 Usages 来使用它。 diff --git a/matrix/matrix-android/matrix-gradle-plugin/src/main/groovy/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTask.groovy b/matrix/matrix-android/matrix-gradle-plugin/src/main/groovy/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTask.groovy index 2ad4f95f9..2845b6a44 100644 --- a/matrix/matrix-android/matrix-gradle-plugin/src/main/groovy/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTask.groovy +++ b/matrix/matrix-android/matrix-gradle-plugin/src/main/groovy/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTask.groovy @@ -237,7 +237,9 @@ public class RemoveUnusedResourcesTask extends DefaultTask { //Log.d(TAG, "styleable %s", styleableMap.keySet().size()); String newResTxtFile = resTxtFile.getParentFile().getAbsolutePath() + "/" + resTxtFile.getName().substring(0, resTxtFile.getName().indexOf('.')) + "_shrinked.txt"; shrinkResourceTxtFile(newResTxtFile, resourceMap, styleableMap); - new File(newResTxtFile).renameTo(resTxtFile); + + //Other plugins such as "Tinker" may depend on the R.txt file, so we should not modify R.txt directly . + //new File(newResTxtFile).renameTo(resTxtFile); } } finally { diff --git a/matrix/matrix-iOS/Script/ks2apple.py b/matrix/matrix-iOS/Script/ks2apple.py new file mode 100644 index 000000000..259c0462d --- /dev/null +++ b/matrix/matrix-iOS/Script/ks2apple.py @@ -0,0 +1,844 @@ +#!/usr/bin/env python2.7 +#-*- coding: utf-8 -*- +''' +@Author: mattzheng +@since: 2019-05-13 11:46:33 +@lastTime: 2019-07-01 18:06:08 +@LastAuthor: Do not edit +''' + + +import json +import os +import sys +import cgi +import optparse +import traceback +from datetime import datetime + + +reload(sys) +sys.setdefaultencoding('utf-8') + +device_map = { + 'iPod1,1' : 'iPod touch 1G', + 'iPod2,1' : 'iPod touch 2G', + 'iPod3,1' : 'iPod touch 3G', + 'iPod4,1' : 'iPod touch 4G', + 'iPod5,1' : 'iPod touch 5G', + + 'iPad2,5' : 'iPad mini 1G', + 'iPad2,6' : 'iPad mini 1G', + 'iPad2,7' : 'iPad mini 1G', + 'iPad4,4' : 'iPad mini 2G', + 'iPad4,5' : 'iPad mini 2G', + 'iPad4,6' : 'iPad mini 2G', + + 'iPad1,1' : 'iPad 1G', + 'iPad2,1' : 'iPad 2', + 'iPad2,2' : 'iPad 2', + 'iPad2,3' : 'iPad 2', + 'iPad2,4' : 'iPad 2', + 'iPad3,1' : 'iPad 3', + 'iPad3,2' : 'iPad 3', + 'iPad3,3' : 'iPad 3', + 'iPad3,4' : 'iPad 4', + 'iPad3,5' : 'iPad 4', + 'iPad3,6' : 'iPad 4', + 'iPad4,1' : 'iPad Air', + 'iPad4,2' : 'iPad Air', + 'iPad4,3' : 'iPad Air', + + + 'iPhone1,1' : 'iPhone', + 'iPhone1,2' : 'iPhone 3G', + 'iPhone2,1' : 'iPhone 3GS', + 'iPhone3,1' : 'iPhone 4', + 'iPhone3,2' : 'iPhone 4', + 'iPhone3,3' : 'iPhone 4', + 'iPhone4,1' : 'iPhone 4s', + 'iPhone5,1' : 'iPhone 5', + 'iPhone5,2' : 'iPhone 5', + 'iPhone5,3' : 'iPhone 5c', + 'iPhone5,4' : 'iPhone 5c', + 'iPhone6,1' : 'iPhone 5s', + 'iPhone6,2' : 'iPhone 5s', + + 'iPhone7,1' : 'iPhone 6 Plus', + 'iPhone7,2' : 'iPhone 6', + 'iPhone8,1' : 'iPhone 6s', + 'iPhone8,2' : 'iPhone 6s Plus', + 'iPhone8,4' : 'iPhone SE', + 'iPhone9,1' : 'iPhone 7', + 'iPhone9,3' : 'iPhone 7', + 'iPhone9,2' : 'iPhone 7 Plus', + 'iPhone9,4' : 'iPhone 7 Plus', + 'iPhone10,1' : 'iPhone 8', + 'iPhone10,4' : 'iPhone 8', + 'iPhone10,2' : 'iPhone 8 Plus', + 'iPhone10,5' : 'iPhone 8 Plus', + 'iPhone10,3' : 'iPhone X', + 'iPhone10,6' : 'iPhone X', + 'iPhone11,2' : 'iPhone XS', + 'iPhone11,4' : 'iPhone XS Max', + 'iPhone11,6' : 'iPhone XS Max', + 'iPhone11,8' : 'iPhone XR', +} + +def dump_json(obj): + return json.dumps(obj, indent=4, + sort_keys=True, separators=(',',': ')) + +def get_system_info(report): + '''Get system information from report''' + return report.get('system', None) + +def get_report_info(report): + '''Get report information from report''' + return report.get('report', None) + +def get_crash_info(report): + '''Get crash information from report''' + return report.get('crash', None) + +def get_cpu_type(arch): + return {'arm64': 'ARM-64', + 'arm': 'ARM', + 'x86': 'X86', + 'x86_64': 'X86_64'}.get(arch, 'Unknow') + +def get_cpu_arch(report): + system = get_system_info(report) + arch = system.get('cpu_arch', '') + return get_cpu_type(arch) + +def get_app_name(report): + system = get_system_info(report) + return system.get('CFBundleExecutable', 'unknown') + +def get_binary_img_info(report): + # key: name, value: uuid + img_info = {} + + images = report.get('binary_images', []) + for image in images: + name = os.path.basename(image["name"]) + uuid = image['uuid'].lower().replace('-', '') + + if name not in img_info: + img_info[str(name)] = str(uuid) + + return img_info + +def get_belong_img(report, addr): + images = report.get('binary_images', []) + for img in images: + if img['image_addr'] <= addr <= (img['image_addr'] + img['image_size']): + return img + + return None + +CPU_TYPE_ARM = 12 +CPU_ARCH_ABI64 = 0x01000000 +CPU_TYPE_ARM64 = CPU_TYPE_ARM | CPU_ARCH_ABI64 +CPU_TYPE_X86 = 7 +CPU_TYPE_X86_64 = CPU_TYPE_X86 | CPU_ARCH_ABI64 + +CPU_SUBTYPE_ARM_V6 = 6 +CPU_SUBTYPE_ARM_V7 = 9 +CPU_SUBTYPE_ARM_V7F = 10 +CPU_SUBTYPE_ARM_V7S = 11 +CPU_SUBTYPE_ARM_V7K = 12 +CPU_SUBTYPE_ARM_V6M = 14 +CPU_SUBTYPE_ARM_V7M = 15 +CPU_SUBTYPE_ARM_V7EM = 16 +CPU_SUBTYPE_ARM_V8 = 13 + +CPU_ARM_TYPES = { + CPU_SUBTYPE_ARM_V6: 'armv6', + CPU_SUBTYPE_ARM_V7: 'armv7', + CPU_SUBTYPE_ARM_V7F: 'armv7f', + CPU_SUBTYPE_ARM_V7S: 'armv7s', + CPU_SUBTYPE_ARM_V7K: 'armv7k', + CPU_SUBTYPE_ARM_V6M: 'armv6m', + CPU_SUBTYPE_ARM_V7M: 'armv7m', + CPU_SUBTYPE_ARM_V7EM: 'armv7em', + CPU_SUBTYPE_ARM_V8: 'armv8', +} + +def get_detail_cpu_arch(major, minor): + if major == CPU_TYPE_ARM: + return CPU_ARM_TYPES.get(minor, 'arm') + elif major == CPU_TYPE_ARM64: + return 'arm64' + elif major == CPU_TYPE_X86: + return 'i386' + elif major == CPU_TYPE_X86_64: + return 'x86_64' + + return 'unknown({0},{1})'.format(major, minor) + +def get_last_exception(report): + report_info = get_report_info(report) + process = report_info.get('process', None) + if not process: + return None + return process.get('last_dealloced_nsexception', None) + +def get_time(report): + '''Get crash time from report + @return time like "2015-12-28 17:48:03 +0800" + ''' + + info = get_report_info(report) + timestamp = info.get('timestamp', None) + if not timestamp: + return '' + + if type(timestamp) == type(0): + return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") + else: + return timestamp + + #from dateutil import parser, tz + #date = parser.parse(timestamp) + #return date.astimezone(tz.tzlocal())\ + # .strftime('%Y-%m-%d %H:%M:%S.000 %z') + +def get_crash_thread(report): + crash = get_crash_info(report) + if not crash: + return [] + #print crash + threads = crash['threads'] + for thread in threads: + crashed = thread.get('crashed', False) + if crashed: + return thread + + return crash.get('crashed_thread', None) + + +def parse_user_info(report): + user_info = report.get("user", None) + if not user_info: + return [] + + result = ['\nUser Info: {'] + if user_info and user_info.get(APP_NAME): + uin = user_info[APP_NAME].get("uin", None) + if uin: + result.append(show_color(' Uin: {0}'.format(uin))) + if user_info[APP_NAME].get("UsrName"): + result.append(' UsrName: {0}'.format(user_info[APP_NAME].get("UsrName"))) + if user_info[APP_NAME].get("heavyUser", -1) != -1: + result.append(' heavyUser: {0}'.format(user_info[APP_NAME].get("heavyUser"))) + if user_info[APP_NAME].get("heavyUserType", -1) != -1: + result.append(' heavyUserType: {0}'.format(user_info[APP_NAME].get("heavyUserType"))) + if user_info[APP_NAME].get("heavyPoint", -1) != -1: + result.append(' heavyPoint: {0}'.format(user_info[APP_NAME].get("heavyPoint"))) + if user_info[APP_NAME].get("DumpType", -1) != -1: + result.append(' dumpType: {0}'.format(user_info[APP_NAME].get("DumpType"))) + if user_info[APP_NAME].get("blockTime"): + result.append(' blockTime: {0}'.format(user_info[APP_NAME].get("blockTime"))) + if user_info[APP_NAME].get("LastScene"): + result.append(' LastScene: {0}'.format(user_info[APP_NAME].get("LastScene"))) + if user_info[APP_NAME].get("SecondLastScene"): + result.append(' SecondLastScene: {0}'.format(user_info[APP_NAME].get("SecondLastScene"))) + if user_info[APP_NAME].get("WeAppScene"): + result.append(' WeAppScene: {0}'.format(user_info[APP_NAME].get("WeAppScene"))) + if user_info[APP_NAME].get("ExistWeAppCount"): + result.append(' ExistWeAppCount: {0}'.format(user_info[APP_NAME].get("ExistWeAppCount"))) + if len(result) < 2: + result.append(json.dumps(user_info, indent=4)) + result.append('}') + return result + +def parse_system_info(report): + '''Parse system information from report. + @return header lines + ''' + + sys = get_system_info(report) + if not sys: + return [] + info = get_report_info(report) + + _s = lambda x: sys.get(x, '') + _i = lambda x: info.get(x, '') + + headers = ['System Info: {'] + device = _s('machine') + if device_map.has_key(device): + device = device_map[device] + headers.append(' Device: {0}'.format(device)) + headers.append(' OS Version: {0} {1} ({2})'.format(_s('system_name'), _s('system_version'), _s('os_version'))) + + user_info = report.get("user", None) + if user_info and user_info.get('WeChat'): + jb_info = user_info.get('WeChat').get('Jailbreak', None) + if jb_info: + headers.append(' Jailbreak: {0}'.format(jb_info)) + + mem = sys.get("memory") + if mem: + fmt = lambda x: " Mem {0:6}: {1:4} M".format(x, int(mem[x])/1024/1024) + headers.append(fmt("usable")) + headers.append(show_color(fmt("free"))) + headers.append(fmt("size")) + + headers.append('}') + return headers +def show_color(str,color='blue'): + return str + # return '%s'%(color,str) + +def zombie_exception(report): + crash = get_crash_info(report) + error = crash['error'] + mach = error['mach'] + exc_name = mach.get('exception_name', '0') + code_name = mach.get('code_name', '0x00000000') + + if exc_name != 'EXC_BAD_ACCESS' or code_name != 'KERN_INVALID_ADDRESS': + return False + + last_exception = get_last_exception(report) + if not last_exception: + return False + + last_addr = last_exception['address'] + thread = get_crash_thread(report) + registers = thread['registers']['basic'] + for reg, addr in registers: + if addr == last_addr: + return True + + return False + + +def parse_error_info(report): + crash = get_crash_info(report) + if not crash: + return [] + error = crash.get('error') + if not error: + print "waring: no error found in crash" + return [] + mach = error['mach'] + signal = error['signal'] + + exc_name = mach.get('exception_name', '0') + sig_name = signal.get('name', None) + if not sig_name: + sig_name = signal.get('signal', '') + + code_name = mach.get('code_name', '0x00000000') + addr = error.get('address', '0') + + crash_thread = 0 + thread = get_crash_thread(report) + if thread: + crash_thread = thread['index'] + + result = [''] + result.append('Exception Type: {0} ({1})'.format(exc_name, sig_name)) + result.append('Exception Codes: {0} at {1:016x}'.format(code_name, int(addr))) + result.append('Crashed Thread: {0}'.format(crash_thread)) + + diagnosis = crash.get('diagnosis', None) + #print "fuck haha", diagnosis + if diagnosis: + result.append('\nCrashDoctor Diagnosis: {0}'.format(diagnosis)) + #print result + return result + +def parse_crash_reason(report): + result = [''] + reason_fmt = ("Application Specific Information" + "*** Terminating app due to uncaught exception '{0}', " + "reason: '{1}'") + fmt = lambda x, y: reason_fmt.format(x, y) + + crash = get_crash_info(report) + if not crash: + return [] + + error = crash.get('error') + if not error: + print "warning: no error found in crash" + return [] + crash_type = error['type'] + + user_exception = error.get('user_reported', None) + ns_exception = error.get('nsexception', None) + if ns_exception: + result.append(fmt(ns_exception['name'], error.get('reason', ''))) + elif zombie_exception(report): + last_exception = get_last_exception(report) + if (last_exception): + result.append(fmt(last_exception['name'], last_exception['reason'])) + elif user_exception: + result.append(fmt(user_exception['name'], error['reason'])) + line = user_exception.get('line_of_code', None) + backtrace = user_exception.get('backtrace', []) + if line or backtrace: + result.append('Custom Backtrace:') + if line: + result.append('Line: {0}'.format(line)) + for entry in backtrace: + result.append(entry) + + elif crash_type == 'cpp_exception': + #cpp_exception = error['cppexception'] + cpp_exception = error.get('cppexception', None) + if cpp_exception and cpp_exception.get('name'): + result.append(fmt(cpp_exception['name'], error['reason'])) + elif crash_type == 'deadlock': + result.append('Application main thread deadlocked') + return result + +def parse_backtrace(report, backtrace): + num = 0 + result = [] + for trace in backtrace.get('contents', []): + try: + pc = trace['instruction_addr'] + except: + traceback.print_exc() + continue + + img = get_belong_img(report, pc) + if not img: + print "error, no img found for pc: %s" % pc + result.append('{0:<4}{1:31} 0x{2:016x}'.format(num, 'unknown', pc)) + num += 1 + continue + + # uuid = img['uuid'].lower().replace('-', '') + obj_addr = img['image_addr'] + offset = pc - obj_addr + obj_name = os.path.basename(img['name']) + + symbol_name = trace.get('symbol_name', None) + # symbol_addr = trace.get('symbol_addr', 0) + + preamble = '{0:<4}{1:31} 0x{2:016x}'.format(num, obj_name, pc) + unsymbolicated = '0x{0:04x} + {1}'.format(obj_addr, offset) + symbolicated = '(null)' + is_unsymbolicated = False + if symbol_name: + symbolicated = '{0}'.format(symbol_name) + #symbolicated = '{0} + {1}'.format(symbol_name, pc-symbol_addr) + else: + is_unsymbolicated = True + if symbol_name == '': + is_unsymbolicated = True + + if is_unsymbolicated: + result.append('{0} {1}'.format(preamble, unsymbolicated)) + else: + result.append('{0} {1:30} ({2})'.format(preamble, unsymbolicated, symbolicated)) + + num += 1 + + return result + +def parse_thread_info(thread, report): + result = [] + crashed = thread.get('crashed', False) + index = thread.get('index', -1) + if index == -1: + return result + + name = thread.get('name', None) + queue = thread.get('dispatch_queue', None) + + if name: + result.append('Thread {0} name: {1}'.format(index, name)) + elif queue: + result.append('Thread {0} name: Dispatch queue: {1}'\ + .format(index, queue)) + if crashed: + result.append('Thread {0} Crashed:'.format(index)) + else: + result.append('Thread {0}:'.format(index)) + + if "backtrace" in thread: + backtrace = parse_backtrace(report, thread['backtrace']) + result += backtrace + + return result + +def parse_thread_list(report): + crash = get_crash_info(report) + if not crash: + return [] + #print dump_json( crash) + threads = crash['threads'] + + result = [] + for thread in threads: + result.append('') + result += parse_thread_info(thread, report) + + return result + +def get_register_order(cpu): + cpu = cpu.lower() + #print "cpu %s" % cpu + arm = [ 'x'+str(i) for i in range(30)] + ['fp','sp', 'lr', 'pc', + 'cpsr'] + x86 = ['eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', + 'esp', 'ss', 'eflags', 'eip', 'cs', 'ds', 'es', + 'fs', 'gs'] + x86_64 = ['rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', + 'rsp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', + 'r14', 'r15', 'rip', 'rflags', 'cs', 'fs', 'gs'] + if cpu.startswith('arm'): + return arm + elif cpu in ('x86', 'i386', 'i486', 'i686'): + return x86 + elif cpu == 'x86_64': + return x86_64 + else: + return arm + +def parse_cpu_state(report): + result = [''] + crashed = get_crash_thread(report) + if not crashed: + return result + index = crashed['index'] + + system = get_system_info(report) + cpu = get_detail_cpu_arch(system['binary_cpu_type'], + system['binary_cpu_subtype']) + cpu = get_cpu_type(cpu) + result.append('Thread {0} crashed with {1} Thread State:'.format(index, cpu)) + + registers = crashed.get('registers', {}).get('basic', {}) + order = get_register_order(cpu) + if not order: + return result + + line = '' + for i, reg in enumerate(order): + if (i != 0) and (i % 4 == 0): + result.append(line[:-1]) + line = '' + try: + line += '{0:>6}: 0x{1:016x} '.format(reg, registers.get(reg, 0)) + except: + continue + + if line: + result.append(line[:-1]) + + return result + +def parse_binary_images(report): + result = ['\nBinary Images:'] + system = get_system_info(report) + if not system: + return result + + exe_path = system['CFBundleExecutablePath'] + + images = report.get('binary_images', []) + images = sorted(images, key=lambda k: k['image_addr']) + + image_count = 0 + for image in images: + try: + image_count = image_count + 1 + cpu = image.get('cpu_type') + if not cpu: + cpu = image.get('cpuType') + #cpu_sub = image['cpu_subtype'] + addr = image['image_addr'] + size = image['image_size'] + path = image['name'] + name = os.path.basename(path) + uuid = image['uuid'].lower().replace('-', '') + is_base = '+' if path==exe_path else ' ' + if False:#image_count <=10 and not is_image_wechat(name) and simple_symbol_find.uuid_find(uuid) == False: + #name = "%s"%name + result.append('{0:>#18x} - {1:>#18x} {2}{3} <{4}> {5}'\ + .format(addr, addr+size-1, is_base, name, + uuid, path)) + else: + if name == 'WeChat': + print '{0:>#18x} - {1:>#18x} {2}{3} <{4}> {5}'.format(addr, addr+size-1, is_base, name,uuid, path) + result.append('{0:>#18x} - {1:>#18x} {2}{3} <{4}> {5}'\ + .format(addr, addr+size-1, is_base, name, + uuid, path)) + except: + traceback.print_exc() + continue + + return result + +def parse_mem_info(report): + result = ['\nMemory: {'] + system = get_system_info(report) + mem = system.get("memory") + + fmt = lambda x: " {0:6}: {1:4} M,".format(x, int(mem[x])/1024/1024) + result.append(fmt("usable")) + result.append(fmt("free")) + result.append(fmt("size")[:-1]) + result.append('}') + + return result + +def parse_app_info(report): + result = ['\nApplication Info:{'] + system = get_system_info(report) + if not system: + return [] + + _s = lambda x: system.get(x, '') + info = get_report_info(report) + _i = lambda x: info.get(x, '') + + app_stats = system.get('application_stats', None) + if not app_stats: + return [] + try: + if app_stats.get('app_launch_time'): + app_stats['app_launch_time'] = datetime.fromtimestamp(app_stats.get('app_launch_time')).strftime("%Y-%m-%d %H:%M:%S") + app_stats['app_crash__time'] = get_time(report) + + app_stats['Process'] = '{0} [{1}]'.format(_s('process_name'), _s('process_id')) + app_stats["Identifier"] = '{0}'.format(_i('id')) + app_stats['Version'] = '{0} ({1})'.format(_s('CFBundleShortVersionString'), _s('CFBundleVersion')) + + except: + traceback.print_exc() + + user_info = report.get("user", None) + if user_info and user_info.get(APP_NAME): + commit_id = user_info[APP_NAME].get("commit_id", None) + if commit_id: + app_stats['Commit ID'] = '{0}'.format(commit_id) + wcdb_commit_id = user_info[APP_NAME].get("wcdb_commit_id", None) + if wcdb_commit_id: + app_stats['WCDB_Commit ID'] = '{0}'.format(wcdb_commit_id) + app_stats['Code Type'] = '{0}'.format(get_cpu_arch(report)) + + reason = "".join(parse_crash_reason(report)) + if reason: + asi = 'Application Specific Information' + app_stats[asi] = reason.replace(asi, '') + + for item in parse_error_info(report): + if not item: + continue + items = item.split(':') + if len(items) == 2: + app_stats[items[0].strip()] = items[1].strip() + + if app_stats: + #result.append('\nApplication Info:\n{0}'\ + # .format(dump_json(app_stats).replace('"', ''))) + + for key in sorted(app_stats): + fmt = lambda x: " {0:36}: {1}".format(key, app_stats[key]) + result.append(fmt(key)) + # if key in ['Crashed Thread','Application Specific Information','Exception Type','Version','app_crash__time','app_launch_time']: + # result.append(show_color(fmt(key))) + # else: + # result.append(fmt(key)) + + result.append('}\n') + return result + + +def parse_extra_info(report): + result = ['', 'Extra Information:'] + crash = get_crash_info(report) + if not crash: + return [] + error = crash.get('error') + if not error: + return [] + ns_exception = error.get('nsexception', None) + if ns_exception: + ref_obj = ns_exception.get('referenced_object', None) + if ref_obj: + result.append('Object referenced by NSException:') + result.append(dump_json(ref_obj)) + + crashed = get_crash_thread(report) + if crashed: + stack = crashed.get('stack', None) + if stack: + result.append('Stack Dump (0x{0:08x}-0x{1:08x}):'\ + .format(stack['dump_start'], stack['dump_end'])) + result.append('') + result.append(stack.get('contents', '')) + notable_addr = crashed.get('notable_addresses', None) + if notable_addr: + for _tmp_stack in notable_addr: + if notable_addr[_tmp_stack].get('address', None): + notable_addr[_tmp_stack]['address'] = hex(notable_addr[_tmp_stack]['address']) + result.append('Notable Addresses:\n{0}'\ + .format(dump_json(notable_addr))) + last_exception = get_last_exception(report) + if last_exception: + addr = last_exception['address'] + name = last_exception['name'] + reason = last_exception['reason'] + + result.append('\nLast deallocated NSException (0x{0:016x}): {1}: {2}'\ + .format(addr, name, reason)) + + ref_obj = last_exception.get('referenced_object', None) + if ref_obj: + result.append('Referenced object:\n{0}'\ + .format(dump_json(ref_obj))) + info = get_report_info(report) + app = info['process_name'] + backtrace = parse_backtrace(crashed['backtrace'], app) + result += backtrace + + ''' + app_stats = system.get('application_stats', None) + if app_stats: + result.append('\nApplication Stats:\n{0}'\ + .format(dump_json(app_stats))) + ''' + + return result + +def parse_log_info(report): + result = ['', 'MMLog:'] + user_info = report.get("user", None) + if not user_info or not user_info.get(APP_NAME, None) or not user_info[APP_NAME].get("log"): + result.append("no log found...") + return result + + log_list = user_info[APP_NAME]["log"] + result += log_list + + return result + +def parse_click_info(report): + result = ['', 'Click:'] + user_info = report.get("user", None) + if not user_info or not user_info.get(APP_NAME, None) or not user_info[APP_NAME].get("click"): + result.append("no click found...") + return [] + + click_list = user_info[APP_NAME]["click"] + result += click_list + + return result + +def parse_other_info(report): + result = [''] + user_info = report.get("user", None) + if not user_info or not user_info.get(APP_NAME, None) or not user_info[APP_NAME].get("log"): + print "no log found..." + return result + + log_list = user_info[APP_NAME]["log"][-2:] + result += log_list + + return result + +def ks_json_2_apple(report, fout): + global IMG_INFO_MAP, APP_NAME + IMG_INFO_MAP = get_binary_img_info(report) + APP_NAME = get_app_name(report) + + headers = parse_system_info(report) + for line in headers: + fout.write(line+'\n') + + try: + errors = parse_error_info(report) + except: + traceback.print_exc() + errors = [] + for line in errors: + line = cgi.escape(line) + fout.write(line+'\n') + + try: + reason = parse_crash_reason(report) + except: + traceback.print_exc() + reason = [] + for line in reason: + line = cgi.escape(line) + fout.write(line+'\n') + + try: + user_info = parse_user_info(report) + for line in user_info: + fout.write(line+'\n') + except: + traceback.print_exc() + + ''' + try: + mems = parse_mem_info(report) + for line in mems: + fout.write(line+'\n') + except: + traceback.print_exc() + ''' + + app_info = parse_app_info(report) + for line in app_info: + fout.write(line+'\n') + #fout.write('\n\n') + + #other_info = parse_other_info(report) + #for line in other_info: + # fout.write(line+'\n') + click_info = parse_click_info(report) + for line in click_info: + line = cgi.escape(line) + fout.write(line+'\n') + + threads = parse_thread_list(report) + for line in threads: + line = cgi.escape(line) + fout.write(line+'\n') + + cpu_state = parse_cpu_state(report) + for line in cpu_state: + line = cgi.escape(line) + fout.write(line+'\n') + + images = parse_binary_images(report) + for line in images: + #line = cgi.escape(line) + fout.write(line+'\n') + + extra = parse_extra_info(report) + for line in extra: + line = cgi.escape(line) + fout.write(line+'\n') + + log_info = parse_log_info(report) + for line in log_info: + line = cgi.escape(line) + fout.write(line+'\n') + +if __name__ == '__main__': + parser = optparse.OptionParser() + parser.add_option("-i","--input_file", help="input ks json file") + parser.add_option("-o","--output_file", help="output file") + (options, args) = parser.parse_args() + if not (options.input_file and options.output_file): + parser.print_help() + sys.exit(1) + + report = json.load(open(options.input_file)) + fout = open(options.output_file, 'w') + ks_json_2_apple(report, fout) + fout.close() \ No newline at end of file diff --git a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java index b2f0d9075..610329417 100644 --- a/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java +++ b/samples/sample-android/app/src/main/java/sample/tencent/matrix/MatrixApplication.java @@ -18,9 +18,6 @@ import android.app.Application; import android.content.Context; -import android.os.Build; -import android.os.Debug; -import android.os.SystemClock; import com.tencent.matrix.Matrix; import com.tencent.matrix.iocanary.IOCanaryPlugin; @@ -34,8 +31,6 @@ import com.tencent.sqlitelint.SQLiteLintPlugin; import com.tencent.sqlitelint.config.SQLiteLintConfig; -import java.util.HashSet; - import sample.tencent.matrix.config.DynamicConfigImplDemo; import sample.tencent.matrix.listener.TestPluginListener; import sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity;