├── README.md
└── matrix_method_parser
├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── README
├── matrix耗时方法解析.png
└── matrix耗时方法解析工具.jar
├── libs
├── gson-2.8.5.jar
├── json-20190722.jar
├── reactive-streams-1.0.2.jar
└── rxjava-2.2.11.jar
└── src
└── com
└── matrix
└── parser
├── Constant.java
├── MatrixParser.java
├── MethodIssueParser.java
├── model
├── GBC.java
└── Issue.java
└── util
└── Util.java
/README.md:
--------------------------------------------------------------------------------
1 | # matrix_evil_method_stack_parser
2 | matrix的耗时方法日志解析
3 |
4 | # README文件夹中有可执行的工具
5 |
6 |
--------------------------------------------------------------------------------
/matrix_method_parser/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/matrix_method_parser/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/matrix_method_parser/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | matrix_method_parser
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/matrix_method_parser/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.8
12 |
--------------------------------------------------------------------------------
/matrix_method_parser/README/matrix耗时方法解析.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SilentSword2020/matrix_evil_method_stack_parser/518676273ad0d757b1a6c622ccb8c23b310d2156/matrix_method_parser/README/matrix耗时方法解析.png
--------------------------------------------------------------------------------
/matrix_method_parser/README/matrix耗时方法解析工具.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SilentSword2020/matrix_evil_method_stack_parser/518676273ad0d757b1a6c622ccb8c23b310d2156/matrix_method_parser/README/matrix耗时方法解析工具.jar
--------------------------------------------------------------------------------
/matrix_method_parser/libs/gson-2.8.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SilentSword2020/matrix_evil_method_stack_parser/518676273ad0d757b1a6c622ccb8c23b310d2156/matrix_method_parser/libs/gson-2.8.5.jar
--------------------------------------------------------------------------------
/matrix_method_parser/libs/json-20190722.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SilentSword2020/matrix_evil_method_stack_parser/518676273ad0d757b1a6c622ccb8c23b310d2156/matrix_method_parser/libs/json-20190722.jar
--------------------------------------------------------------------------------
/matrix_method_parser/libs/reactive-streams-1.0.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SilentSword2020/matrix_evil_method_stack_parser/518676273ad0d757b1a6c622ccb8c23b310d2156/matrix_method_parser/libs/reactive-streams-1.0.2.jar
--------------------------------------------------------------------------------
/matrix_method_parser/libs/rxjava-2.2.11.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SilentSword2020/matrix_evil_method_stack_parser/518676273ad0d757b1a6c622ccb8c23b310d2156/matrix_method_parser/libs/rxjava-2.2.11.jar
--------------------------------------------------------------------------------
/matrix_method_parser/src/com/matrix/parser/Constant.java:
--------------------------------------------------------------------------------
1 | package com.matrix.parser;
2 |
3 | public final class Constant {
4 | public static final String TITLE = "Matrix方法耗时解析";
5 | public static final String FILE_METHOD_MAPPING = "methodMapping.txt文件";
6 | public static final String LABEL_ISSUE_CONTENT = "问题内容(json格式)";
7 | public static final String LABEL_START_PARSER = "开始解析";
8 | public static final String LABEL_SELECT_FILE = "选择文件";
9 | public static final String LABEL_PARSER_RESULT = "解析结果";
10 | public static final String test_matrix_method_mapping_error = "请选择methodMapping.txt文件";
11 | public static final String test_matrix_issue_hint = "请输入问题内容";
12 | public static final String test_matrix_parser_fail = "解析失败";
13 | public static final String test_matrix_method_not_found = "没有找到对应的方法声明:可能methodMapping.txt和安装的APK不一致";
14 | public static final String test_matrix_stack_not_found = "没有找到对应的stack:json数据格式可能不对";
15 | public static final String test_matrix_result = "进程:\r\n%1$s\r\n\r\n具体的耗时场景:\r\n%2$s\r\n\r\n耗时:\r\n%3$sms\r\n\r\n\r\n耗时方法:\r\n%4$s\r\n\r\n\r\n方法调用的栈信息:\r\n%5$s\r\n\r\n\r\n详细信息:\r\n%6$s\r\n";
16 | public static final String test_matrix_stack_line = "[%1$s 执行次数:%2$s 总耗时:%3$sms]\r\n\r\n";
17 | public static final String[] matrix_method_scene = new String[] { "NORMAL: 普通慢函数场景", "ENTER: Activity进入场景",
18 | "ANR: anr超时场景", "FULL: 满buffer场景", "STARTUP: 启动耗时场景" };
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/matrix_method_parser/src/com/matrix/parser/MatrixParser.java:
--------------------------------------------------------------------------------
1 | package com.matrix.parser;
2 |
3 | import java.awt.GridBagLayout;
4 | import java.awt.event.ActionEvent;
5 | import java.awt.event.ActionListener;
6 | import java.awt.event.WindowAdapter;
7 | import java.awt.event.WindowEvent;
8 | import java.io.File;
9 |
10 | import javax.swing.JButton;
11 | import javax.swing.JFileChooser;
12 | import javax.swing.JFrame;
13 | import javax.swing.JLabel;
14 | import javax.swing.JOptionPane;
15 | import javax.swing.JScrollPane;
16 | import javax.swing.JTextArea;
17 |
18 | import com.matrix.parser.MethodIssueParser.ParserResult;
19 | import com.matrix.parser.model.GBC;
20 | import com.matrix.parser.util.Util;
21 |
22 | /**
23 | * 界面
24 | *
25 | * @author yangqh
26 | *
27 | */
28 | public class MatrixParser {
29 |
30 | //
31 | private JFrame mainFrame;
32 | private JLabel containerLabel;
33 |
34 | //
35 | private JButton methodMappingChooser;
36 | private JLabel filePathLabel;
37 | private JTextArea issueArea;
38 | private JTextArea resultArea;
39 |
40 | //
41 | private MethodIssueParser methodIssueParser;
42 |
43 | public static void main(String[] args) {
44 | new MatrixParser().show();
45 | }
46 |
47 | public MatrixParser() {
48 | initParser();
49 | initUI();
50 | }
51 |
52 | /**
53 | * 初始化解析器
54 | */
55 | private void initParser() {
56 | methodIssueParser = new MethodIssueParser(new MethodIssueParser.Listener() {
57 |
58 | @Override
59 | public void onResult(ParserResult result) {
60 | // 显示解析结果
61 | if (resultArea != null) {
62 | String content = String.format(Constant.test_matrix_result, result.processName, result.scene,
63 | result.costTime, result.costStackKey, result.stackDetail, result.result);
64 | resultArea.setText(content);
65 | }
66 | }
67 |
68 | @Override
69 | public void onError(CharSequence msg) {
70 | // 显示错误提示
71 | JOptionPane.showMessageDialog(mainFrame, msg, "", JOptionPane.WARNING_MESSAGE);
72 | }
73 | });
74 | }
75 |
76 | /**
77 | * 清理数据,退出界面
78 | */
79 | private void clearAndExit() {
80 | if (methodIssueParser != null) {
81 | methodIssueParser.clear();
82 | methodIssueParser = null;
83 | }
84 | System.exit(0);
85 | }
86 |
87 | /**
88 | * 显示界面
89 | */
90 | private void show() {
91 | if (mainFrame != null) {
92 | mainFrame.setVisible(true);
93 | }
94 | }
95 |
96 | /**
97 | * 初始化ui
98 | */
99 | private void initUI() {
100 | mainFrame = new JFrame(Constant.TITLE);
101 | mainFrame.addWindowListener(new WindowAdapter() {
102 | public void windowClosing(WindowEvent windowEvent) {
103 | // 点击关闭按钮
104 | clearAndExit();
105 | }
106 |
107 | });
108 | mainFrame.setBounds(200, 200, 500, 800);
109 |
110 | initComponents();
111 |
112 | mainFrame.setVisible(true);
113 | }
114 |
115 | /**
116 | * 初始化子控件
117 | */
118 | private void initComponents() {
119 | // 容器
120 | containerLabel = new JLabel("", JLabel.CENTER);
121 | containerLabel.setLayout(new GridBagLayout());
122 | mainFrame.add(containerLabel);
123 |
124 | int row = 2;
125 | // methodMapping.txt文件
126 | JLabel methodMappingLabel = new JLabel(Constant.FILE_METHOD_MAPPING, JLabel.CENTER);
127 | containerLabel.add(methodMappingLabel, new GBC(0, row, 1, 1));
128 | // 选择文件
129 | methodMappingChooser = new JButton(Constant.LABEL_SELECT_FILE);
130 | methodMappingChooser.setBounds(0, 0, 50, 64);
131 | methodMappingChooser.addActionListener(new ActionListener() {
132 |
133 | @Override
134 | public void actionPerformed(ActionEvent e) {
135 | selectFile();
136 | }
137 | });
138 | containerLabel.add(methodMappingChooser, new GBC(0, ++row, 1, 1));
139 |
140 | // 文件路径
141 | filePathLabel = new JLabel("", JLabel.CENTER);
142 | containerLabel.add(filePathLabel, new GBC(0, ++row, 1, 1).setFill(GBC.BOTH));
143 |
144 | // 日志内容标题
145 | JLabel issueLabel = new JLabel(Constant.LABEL_ISSUE_CONTENT, JLabel.CENTER);
146 | containerLabel.add(issueLabel, new GBC(0, ++row, 1, 1));
147 |
148 | // 日志内容
149 | issueArea = new JTextArea();
150 | JScrollPane jScrollPane = new JScrollPane();
151 | jScrollPane.setViewportView(issueArea);
152 | containerLabel.add(jScrollPane, new GBC(0, ++row, 1, 1).setWeight(1, 0.5f).setFill(GBC.BOTH));
153 |
154 | // 开始解析按钮
155 | JButton parserBtn = new JButton(Constant.LABEL_START_PARSER);
156 | parserBtn.setBounds(0, 0, 50, 64);
157 | parserBtn.addActionListener(new ActionListener() {
158 |
159 | @Override
160 | public void actionPerformed(ActionEvent e) {
161 | startParser();
162 | }
163 |
164 | });
165 | containerLabel.add(parserBtn, new GBC(0, ++row, 1, 1));
166 |
167 | // 解析结果的标题
168 | JLabel resultLabel = new JLabel(Constant.LABEL_PARSER_RESULT, JLabel.CENTER);
169 | containerLabel.add(resultLabel, new GBC(0, ++row, 1, 1).setFill(GBC.BOTH));
170 |
171 | // 解析结果
172 | jScrollPane = new JScrollPane();
173 | resultArea = new JTextArea();
174 | jScrollPane.setViewportView(resultArea);
175 | containerLabel.add(jScrollPane, new GBC(0, ++row, 1, 1).setWeight(1, 1).setFill(GBC.BOTH));
176 |
177 | }
178 |
179 | /**
180 | * 开始解析
181 | */
182 | private void startParser() {
183 | formatIssueTxt();
184 | if (methodIssueParser != null && issueArea != null) {
185 | methodIssueParser.start(issueArea.getText());
186 | }
187 |
188 | }
189 |
190 | /**
191 | * 格式化问题内容
192 | */
193 | private void formatIssueTxt() {
194 | if (methodIssueParser != null && issueArea != null) {
195 | String result = methodIssueParser.getPrettyStr(issueArea.getText());
196 | if (!Util.isEmpty(result)) {
197 | issueArea.setText(result);
198 | }
199 | }
200 | }
201 |
202 | /**
203 | * 选择文件
204 | */
205 | private void selectFile() {
206 | JFileChooser fileChooser = new JFileChooser();
207 | fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
208 | fileChooser.showDialog(new JLabel(), Constant.LABEL_SELECT_FILE);
209 | File file = fileChooser.getSelectedFile();
210 | if (file == null || file.isDirectory()) {
211 | return;
212 | }
213 | if (file.isFile()) {
214 | System.out.println(file.getAbsolutePath());
215 | if (filePathLabel != null) {
216 | filePathLabel.setText(file.getAbsolutePath());
217 | }
218 | if (methodIssueParser != null) {
219 | methodIssueParser.setMethodMappingFile(file);
220 | }
221 |
222 | }
223 | }
224 |
225 | }
--------------------------------------------------------------------------------
/matrix_method_parser/src/com/matrix/parser/MethodIssueParser.java:
--------------------------------------------------------------------------------
1 | package com.matrix.parser;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.InputStreamReader;
7 | import java.util.HashMap;
8 | import java.util.Locale;
9 |
10 | import org.json.JSONObject;
11 |
12 | import com.google.gson.Gson;
13 | import com.matrix.parser.model.Issue;
14 | import com.matrix.parser.util.Util;
15 |
16 | import io.reactivex.Observable;
17 | import io.reactivex.ObservableOnSubscribe;
18 | import io.reactivex.annotations.NonNull;
19 | import io.reactivex.annotations.Nullable;
20 | import io.reactivex.schedulers.Schedulers;
21 |
22 | /**
23 | * 方法耗时问题解析
24 | */
25 | public class MethodIssueParser {
26 |
27 | private static final int MOTHOD_ID_INVILID = -1;
28 |
29 | private File methodMappingFile;
30 | private final HashMap methodMap = new HashMap<>();
31 | private Listener listener;
32 | private Gson gson;
33 |
34 | public void clear() {
35 | methodMappingFile = null;
36 | listener = null;
37 | methodMap.clear();
38 | gson = null;
39 | }
40 |
41 | public MethodIssueParser(Listener listener) {
42 | this.listener = listener;
43 | }
44 |
45 | public File getMethodMappingFile() {
46 | return methodMappingFile;
47 | }
48 |
49 | /**
50 | * 设置methodMapping.txt文件
51 | *
52 | * @param methodMappingFile
53 | */
54 | public void setMethodMappingFile(File methodMappingFile) {
55 | this.methodMappingFile = methodMappingFile;
56 | }
57 |
58 | public void start(String issueJson) {
59 |
60 | // 判断methodMapping.txt是否存在
61 | if (!Util.isExists(methodMappingFile)) {
62 | if (listener != null) {
63 | listener.onError(Constant.test_matrix_method_mapping_error);
64 | }
65 | return;
66 | }
67 |
68 | if (Util.isEmpty(issueJson)) {
69 | if (listener != null) {
70 | listener.onError(Constant.test_matrix_issue_hint);
71 | }
72 | return;
73 | }
74 |
75 | Observable.create((ObservableOnSubscribe) emitter -> {
76 | ParserResult result = getParserResult(issueJson);
77 | if (result == null) {
78 | emitter.onError(new Throwable("result is null"));
79 | } else {
80 | emitter.onNext(result);
81 | emitter.onComplete();
82 | }
83 |
84 | }).subscribeOn(Schedulers.newThread()).subscribe(result -> {
85 | if (listener != null && result != null) {
86 | listener.onResult(result);
87 | }
88 | }, throwable -> {
89 | if (throwable != null) {
90 | throwable.printStackTrace();
91 | }
92 | if (listener != null) {
93 | listener.onError(String.format(Constant.test_matrix_parser_fail));
94 | }
95 |
96 | });
97 |
98 | }
99 |
100 | private ParserResult getParserResult(String issueJson) {
101 |
102 | // 去掉content中 key: nameValuePairs,把内容放到content下
103 | try {
104 | String nameValueKey = "nameValuePairs";
105 | if (issueJson != null && issueJson.contains(nameValueKey)) {
106 | JSONObject issueObj = new JSONObject(issueJson);
107 | String contentKey = "content";
108 | JSONObject contentObj = issueObj != null ? issueObj.optJSONObject(contentKey) : null;
109 | if (contentObj != null && contentObj.has(nameValueKey)) {
110 | JSONObject nameValuePairs = contentObj.optJSONObject(nameValueKey);
111 | if (nameValuePairs != null) {
112 | issueObj.put(contentKey, nameValuePairs);
113 | issueJson = issueObj.toString();
114 | }
115 | }
116 | }
117 | } catch (Exception e) {
118 | e.printStackTrace();
119 | }
120 |
121 | Issue issue = getIssue(issueJson);
122 | if (issue == null) {
123 | System.out.println("MethodIssueParser.getParserResult() issue is null");
124 | return null;
125 | }
126 | try {
127 | // 初始化方法映射map
128 | initMethodMap();
129 |
130 | // 开始解析相关的堆栈
131 | HashMap content = issue.getContent();
132 |
133 | // stack
134 | String stackKeyName = "stack";
135 | String stack = String.valueOf(content.get(stackKeyName));
136 | stack = parserStack(stack);
137 | if (Util.isEmpty(stack)) {
138 | stack = Constant.test_matrix_stack_not_found;
139 | }
140 | content.put(stackKeyName, stack);
141 |
142 | // stackKey
143 | stackKeyName = "stackKey";
144 | String stackKey = String.valueOf(content.get(stackKeyName));
145 | String methodId = (Util.isEmpty(stackKey) || !stackKey.contains("|")) ? ""
146 | : stackKey.substring(0, stackKey.indexOf('|'));
147 | stackKey = methodMap.get(Util.getInt(methodId, MOTHOD_ID_INVILID));
148 | if (Util.isEmpty(stackKey)) {
149 | stackKey = String.format(Constant.test_matrix_method_not_found);
150 | }
151 | content.put(stackKeyName, stackKey);
152 |
153 | //
154 | issue.setContent(content);
155 |
156 | //
157 | ParserResult result = new ParserResult();
158 | result.processName = String.valueOf(content.get("process"));
159 | result.scene = getSceneStr(String.valueOf(content.get("detail")));
160 | result.costTime = String.valueOf(content.get("cost"));
161 | result.costStackKey = stackKey;
162 | result.stackDetail = stack;
163 | result.result = getJsonStr(issue);
164 | return result;
165 | } catch (Throwable e) {
166 | System.out.println("MethodIssueParser.getParserResult() fail:" + e.getLocalizedMessage());
167 | }
168 | return null;
169 | }
170 |
171 | /**
172 | * 获取耗时的场景描述
173 | *
174 | * @param name
175 | * @return
176 | */
177 | private String getSceneStr(String name) {
178 | if (Util.isEmpty(name)) {
179 | return "scene name is null";
180 | }
181 | try {
182 | return Scene.valueOf(name).getDesc();
183 | } catch (Throwable e) {
184 | e.printStackTrace();
185 | }
186 | return "scene name is unknown";
187 | }
188 |
189 | private String parserStack(String stack) {
190 | if (Util.isEmpty(stack)) {
191 | return stack;
192 | }
193 | // 解析stack
194 | // stack每行的格式:stack层级,方法id,方法执行次数,方法执行总耗时
195 | String[] items = stack.split("\n");
196 | if (Util.isEmpty(items)) {
197 | return stack;
198 | }
199 | StringBuilder builder = new StringBuilder();
200 | String lineFormat = Constant.test_matrix_stack_line;
201 | for (String item : items) {
202 | if (Util.isEmpty(item)) {
203 | continue;
204 | }
205 | String[] temp = item.split(",");
206 | if (Util.isEmpty(temp) || temp.length < 4) {
207 | continue;
208 | }
209 | String method = methodMap.get(Util.getInt(temp[1], MOTHOD_ID_INVILID));
210 | if (Util.isEmpty(method)) {
211 | method = String.format(Constant.test_matrix_method_not_found);
212 | }
213 | builder.append(String.format(Locale.getDefault(), lineFormat, method, temp[2], temp[3]));
214 | }
215 | return builder.toString();
216 |
217 | }
218 |
219 | /**
220 | * 初始化方法映射map
221 | */
222 | private void initMethodMap() {
223 | if (methodMap != null && methodMap.size() > 0) {
224 | // 已经初始化
225 | return;
226 | }
227 | if (methodMappingFile == null) {
228 | return;
229 | }
230 | FileInputStream fis = null;
231 | BufferedReader bufferReader = null;
232 | try {
233 |
234 | if (!methodMappingFile.exists()) {
235 | return;
236 | }
237 | fis = new FileInputStream(methodMappingFile);
238 | bufferReader = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
239 | String line;
240 | while ((line = bufferReader.readLine()) != null) {
241 | // methodMapping.txt每行的格式:方法id,方法accessType,类名,方法名,方法描述;
242 | String[] items = line.split(",");
243 | if (Util.isEmpty(items)) {
244 | continue;
245 | }
246 | // 方法id->方法声明
247 | int key = Util.getInt(items[0], MOTHOD_ID_INVILID);
248 | if (key == MOTHOD_ID_INVILID) {
249 | System.out.println("MethodIssueParser initMethodMap methodId:" + items[0] + " can't parser to int");
250 | continue;
251 | }
252 | methodMap.put(key, items[2]);
253 | }
254 | } catch (Exception e) {
255 | e.printStackTrace();
256 | } finally {
257 | Util.closeQuietly(fis);
258 | Util.closeQuietly(bufferReader);
259 | }
260 |
261 | }
262 |
263 | /**
264 | * 获取issue
265 | *
266 | * @param issueJson
267 | * @return
268 | */
269 | @Nullable
270 | private Issue getIssue(@NonNull String issueJson) {
271 | if (Util.isEmpty(issueJson)) {
272 | return null;
273 | }
274 | synchronized (this) {
275 | if (gson == null) {
276 | gson = Util.getGson();
277 | }
278 | }
279 | try {
280 | return gson.fromJson(issueJson, Issue.class);
281 | } catch (Throwable e) {
282 | e.printStackTrace();
283 | }
284 | return null;
285 | }
286 |
287 | /**
288 | * 获取issue
289 | *
290 | * @param issueJson
291 | * @return
292 | */
293 | @SuppressWarnings("unchecked")
294 | @Nullable
295 | private HashMap getContent(@NonNull String contentJson) {
296 | if (Util.isEmpty(contentJson)) {
297 | return null;
298 | }
299 | synchronized (this) {
300 | if (gson == null) {
301 | gson = Util.getGson();
302 | }
303 | }
304 | try {
305 | return gson.fromJson(contentJson, HashMap.class);
306 | } catch (Throwable e) {
307 | e.printStackTrace();
308 | }
309 | return null;
310 | }
311 |
312 | /**
313 | * 获取优美的json格式
314 | *
315 | * @param json
316 | * @return
317 | */
318 | public String getPrettyStr(String json) {
319 | if (Util.isEmpty(json)) {
320 | return null;
321 | }
322 | synchronized (this) {
323 | if (gson == null) {
324 | gson = Util.getGson();
325 | }
326 | }
327 | try {
328 | return gson.toJson(gson.fromJson(json, Issue.class));
329 | } catch (Throwable e) {
330 | e.printStackTrace();
331 | }
332 | return null;
333 | }
334 |
335 | /**
336 | * 获取issue的json字符串
337 | *
338 | * @param issue
339 | * @return
340 | */
341 | private String getJsonStr(@NonNull Issue issue) {
342 | if (issue == null) {
343 | return null;
344 | }
345 | synchronized (this) {
346 | if (gson == null) {
347 | gson = Util.getGson();
348 | }
349 | }
350 | try {
351 | return gson.toJson(issue);
352 | } catch (Throwable e) {
353 | e.printStackTrace();
354 | }
355 | return null;
356 | }
357 |
358 | /**
359 | * 获取methodMapping的文件路径
360 | *
361 | * @return
362 | */
363 | public String getMethodMappingFilePath() {
364 | return methodMappingFile != null ? methodMappingFile.getAbsolutePath() : null;
365 | }
366 |
367 | /**
368 | * 耗时的场景
369 | */
370 | public enum Scene {
371 | NORMAL, // 普通慢函数场景
372 | ENTER, // Activity进入场景
373 | ANR, // anr超时场景
374 | FULL, // 满buffer场景
375 | STARTUP;// 启动耗时场景
376 |
377 | public String getDesc() {
378 | return Util.getItemAt(Constant.matrix_method_scene, ordinal());
379 | }
380 | }
381 |
382 | /**
383 | * 解析结果
384 | */
385 | public static class ParserResult {
386 | /**
387 | * 进程名称
388 | */
389 | public String processName;
390 | /**
391 | * 具体的耗时场景
392 | */
393 | public String scene;
394 | /**
395 | * 耗时(单位 ms)
396 | */
397 | public String costTime;
398 | /**
399 | * 耗时的方法信息
400 | */
401 | public String costStackKey;
402 | /**
403 | * 方法调用的栈信息
404 | */
405 | public String stackDetail;
406 |
407 | /**
408 | * 最详细的信息
409 | */
410 | public String result;
411 | }
412 |
413 | public interface Listener {
414 | /**
415 | * 错误
416 | *
417 | * @param msg
418 | */
419 | void onError(CharSequence msg);
420 |
421 | /**
422 | * 结果
423 | *
424 | * @param result
425 | */
426 | void onResult(ParserResult result);
427 | }
428 |
429 | }
430 |
--------------------------------------------------------------------------------
/matrix_method_parser/src/com/matrix/parser/model/GBC.java:
--------------------------------------------------------------------------------
1 | package com.matrix.parser.model;
2 |
3 | import java.awt.GridBagConstraints;
4 | import java.awt.Insets;
5 |
6 | public class GBC extends GridBagConstraints {
7 |
8 | private static final long serialVersionUID = 1L;
9 |
10 | // 初始化左上角位置
11 | public GBC(int gridx, int gridy) {
12 | this.gridx = gridx;
13 | this.gridy = gridy;
14 | }
15 |
16 | // 初始化左上角位置和所占行数和列数
17 | public GBC(int gridx, int gridy, int gridwidth, int gridheight) {
18 | this.gridx = gridx;
19 | this.gridy = gridy;
20 | this.gridwidth = gridwidth;
21 | this.gridheight = gridheight;
22 | }
23 |
24 | // 对齐方式
25 | public GBC setAnchor(int anchor) {
26 | this.anchor = anchor;
27 | return this;
28 | }
29 |
30 | // 是否拉伸及拉伸方向
31 | public GBC setFill(int fill) {
32 | this.fill = fill;
33 | return this;
34 | }
35 |
36 | // x和y方向上的增量
37 | public GBC setWeight(double weightx, double weighty) {
38 | this.weightx = weightx;
39 | this.weighty = weighty;
40 | return this;
41 | }
42 |
43 | // 外部填充
44 | public GBC setInsets(int distance) {
45 | this.insets = new Insets(distance, distance, distance, distance);
46 | return this;
47 | }
48 |
49 | // 外填充
50 | public GBC setInsets(int top, int left, int bottom, int right) {
51 | this.insets = new Insets(top, left, bottom, right);
52 | return this;
53 | }
54 |
55 | // 内填充
56 | public GBC setIpad(int ipadx, int ipady) {
57 | this.ipadx = ipadx;
58 | this.ipady = ipady;
59 | return this;
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/matrix_method_parser/src/com/matrix/parser/model/Issue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making wechat-matrix available.
3 | * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.
4 | * Licensed under the BSD 3-Clause License (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing,
11 | * software distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.matrix.parser.model;
18 |
19 | import java.util.HashMap;
20 |
21 | /**
22 | * Data struct contains the issues
23 | *
24 | * Created by zhangshaowen on 2017/8/1.
25 | */
26 | public class Issue {
27 | private Integer type;
28 | private String tag;
29 | private String key;
30 | private HashMap content;
31 |
32 | public static final String ISSUE_REPORT_TYPE = "type";
33 | public static final String ISSUE_REPORT_TAG = "tag";
34 | public static final String ISSUE_REPORT_PROCESS = "process";
35 | public static final String ISSUE_REPORT_TIME = "time";
36 |
37 | public Issue() {
38 |
39 | }
40 |
41 | public void setType(Integer type) {
42 | this.type = type;
43 | }
44 |
45 | public HashMap getContent() {
46 | return content;
47 | }
48 |
49 | public void setContent(HashMap content) {
50 | this.content = content;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return String.format("tag[%s]type[%d];key[%s];content[%s]", tag, type, key, content);
56 | }
57 |
58 | public void setKey(String key) {
59 | this.key = key;
60 | }
61 |
62 | public void setTag(String tag) {
63 | this.tag = tag;
64 | }
65 |
66 | public Integer getType() {
67 | return type;
68 | }
69 |
70 | public String getKey() {
71 | return key;
72 | }
73 |
74 | public String getTag() {
75 | return tag;
76 | }
77 |
78 | public void setType(int type) {
79 | this.type = type;
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/matrix_method_parser/src/com/matrix/parser/util/Util.java:
--------------------------------------------------------------------------------
1 | package com.matrix.parser.util;
2 |
3 | import java.io.Closeable;
4 | import java.io.File;
5 | import java.io.IOException;
6 |
7 | import com.google.gson.ExclusionStrategy;
8 | import com.google.gson.FieldAttributes;
9 | import com.google.gson.Gson;
10 | import com.google.gson.GsonBuilder;
11 |
12 | import io.reactivex.annotations.Nullable;
13 |
14 | public final class Util {
15 | /**
16 | * 是否文件存在
17 | *
18 | * @param file
19 | * @return
20 | */
21 | public static boolean isExists(File file) {
22 | return file != null && file.exists();
23 | }
24 |
25 | /**
26 | * 关闭IO,不抛出异常
27 | *
28 | * @param closeable 可以为null
29 | */
30 | public static void closeQuietly(@Nullable Closeable closeable) {
31 | if (closeable == null)
32 | return;
33 | try {
34 | closeable.close();
35 | } catch (IOException ignored) {
36 |
37 | }
38 | }
39 |
40 | /**
41 | * 数组中指定index的item
42 | *
43 | * @param list
44 | * @param index
45 | * @param
46 | * @return
47 | */
48 | @Nullable
49 | public static T getItemAt(@Nullable T[] list, int index) {
50 | if (list != null && index >= 0 && list.length > index) {
51 | return list[index];
52 | }
53 | return null;
54 | }
55 |
56 | /**
57 | * 数组是否为空
58 | *
59 | * @param list
60 | * @param
61 | * @return
62 | */
63 | public static boolean isEmpty(@Nullable T[] list) {
64 | return list == null || list.length <= 0;
65 | }
66 |
67 | /***
68 | * string to int
69 | *
70 | * @param numberStr 数字字符串
71 | * @return
72 | */
73 | public static int getInt(String numberStr, int defaultValue) {
74 | if (isEmpty(numberStr)) {
75 | return defaultValue;
76 | }
77 | try {
78 | return Integer.valueOf(numberStr);
79 | } catch (Exception e) {
80 |
81 | }
82 | return defaultValue;
83 | }
84 |
85 | /**
86 | * 是否为空或空串
87 | *
88 | * @param str
89 | * @return
90 | */
91 | public static boolean isEmpty(String str) {
92 | return str == null || str.length() == 0;
93 | }
94 |
95 | /**
96 | * 获取Gson实例
97 | *
98 | * @return
99 | */
100 | public static Gson getGson() {
101 | return new GsonBuilder().setPrettyPrinting().setExclusionStrategies(new ExclusionStrategy() {
102 | @Override
103 | public boolean shouldSkipField(FieldAttributes f) {
104 | // 对plugin字段不做序列化和反序列化
105 | return f != null && "plugin".equals(f.getName());
106 | }
107 |
108 | @Override
109 | public boolean shouldSkipClass(Class> clazz) {
110 | return false;
111 | }
112 | }).create();
113 | }
114 | }
115 |
--------------------------------------------------------------------------------