├── LICENSE
├── MethodTrace
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
└── src
│ ├── InfoBean.java
│ ├── Log.java
│ ├── MethodTabModel.java
│ ├── Trace.java
│ ├── TraceScanner.java
│ ├── Utils.java
│ └── VerticalFlowLayout.java
├── README.md
├── art
└── preview.png
└── tool
└── MethodTrace.jar
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/MethodTrace/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MethodTrace/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | MethodTrace
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 |
--------------------------------------------------------------------------------
/MethodTrace/.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 |
--------------------------------------------------------------------------------
/MethodTrace/src/InfoBean.java:
--------------------------------------------------------------------------------
1 |
2 | public class InfoBean {
3 | private String tId;//2939
4 | private String type;//"xit ent"
5 | private int xitTime;//11494456
6 | private int entTime;//11494489
7 | private int result;
8 | private String key;
9 | private String clsName;//PartInquiryListAdapter
10 | private String methodName;//PartInquiryListAdapter$1.onClick (Landroid/view/View;)V
11 | private String fullClassName;//trading.adapter.part.purchase.PartInquiryListAdapter
12 |
13 | public String getFullClassName() {
14 | return fullClassName;
15 | }
16 | public void setFullClassName(String fullClassName) {
17 | this.fullClassName = fullClassName;
18 | }
19 | public String getClsName() {
20 | return clsName;
21 | }
22 | public void setClsName(String clsName) {
23 | this.clsName = clsName;
24 | }
25 | public String getMethodName() {
26 | return methodName;
27 | }
28 | public void setMethodName(String methodName) {
29 | this.methodName = methodName;
30 | }
31 | public String getKey() {
32 | return key;
33 | }
34 | public void setKey(String key) {
35 | this.key = key;
36 | }
37 | public String gettId() {
38 | return tId;
39 | }
40 | public void settId(String tId) {
41 | this.tId = tId;
42 | }
43 | public String getType() {
44 | return type;
45 | }
46 | public void setType(String type) {
47 | this.type = type;
48 | }
49 | public int getXitTime() {
50 | return xitTime;
51 | }
52 | public void setXitTime(int xitTime) {
53 | this.xitTime = xitTime;
54 | }
55 | public int getEntTime() {
56 | return entTime;
57 | }
58 | public void setEntTime(int entTime) {
59 | this.entTime = entTime;
60 | }
61 | public int getResult() {
62 | return result;
63 | }
64 | public void setResult(int result) {
65 | this.result = result;
66 | }
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/MethodTrace/src/Log.java:
--------------------------------------------------------------------------------
1 | /**
2 | * 打印Log信息,格式:
3 | * [类名 | 行号 | 方法名] =======: 信息
4 | * 例如:
5 | * [Utils.java | 118 | fillClassInfo] ======: classInfo: Launcher.java
6 | *
7 | * Created by yuchuan on 15/06/2017.
8 | */
9 | public class Log {
10 |
11 | private final static boolean sEnablePrint = true;
12 |
13 | public static String getTag() {
14 | if (!sEnablePrint) {
15 | return "";
16 | }
17 | // 获取当前方法名
18 | // StackTraceElement traceElement = ((new Exception()).getStackTrace())[0];
19 | // 获取调用者方法名
20 | StackTraceElement traceElement = ((new Exception()).getStackTrace())[1];
21 | return "[" + traceElement.getFileName() + " | "
22 | + traceElement.getLineNumber() + " | "
23 | + traceElement.getMethodName() + "]";
24 |
25 | }
26 |
27 | public static void e(String tag, String log) {
28 | if (sEnablePrint) {
29 | System.out.println(tag + " ======: " + log);
30 | }
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/MethodTrace/src/MethodTabModel.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 |
4 | import javax.swing.table.AbstractTableModel;
5 |
6 | /**
7 | * 内容显示面板Tab栏
8 | */
9 | public class MethodTabModel extends AbstractTableModel {
10 | private ArrayList content = new ArrayList();
11 | private String[] columns = new String[]{"Thread", "Time(μs)", "Class", "Method"};
12 |
13 | public MethodTabModel() {
14 |
15 | }
16 |
17 | @Override
18 | public int getRowCount() {// 行数
19 | return content.size();
20 | }
21 |
22 | @Override
23 | public int getColumnCount() {// 列数
24 | return columns.length;
25 | }
26 |
27 | @Override
28 | public Object getValueAt(int rowIndex, int columnIndex) {
29 | InfoBean bean = this.content.get(rowIndex);
30 | switch (columnIndex) {// 每个列显示的内容定制
31 | case 0:
32 | return bean.gettId();
33 | case 1:
34 | if (bean.getXitTime() == 0) {
35 | return "unknown";
36 | } else {
37 | return bean.getXitTime() - bean.getEntTime();
38 | }
39 | case 2:
40 | return bean.getFullClassName();
41 | case 3:
42 | return bean.getMethodName();
43 |
44 | }
45 | return null;
46 | }
47 |
48 | @Override
49 | public String getColumnName(int column) {
50 | return columns[column];
51 | }
52 |
53 | public void setContent(List content) {
54 | this.content.clear();
55 | this.content.addAll(content);
56 | fireTableDataChanged();
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/MethodTrace/src/Trace.java:
--------------------------------------------------------------------------------
1 | import java.awt.BorderLayout;
2 | import java.awt.FlowLayout;
3 | import java.awt.datatransfer.DataFlavor;
4 | import java.awt.dnd.DnDConstants;
5 | import java.awt.dnd.DropTarget;
6 | import java.awt.dnd.DropTargetAdapter;
7 | import java.awt.dnd.DropTargetDropEvent;
8 | import java.awt.event.ActionEvent;
9 | import java.awt.event.ActionListener;
10 | import java.awt.event.MouseEvent;
11 | import java.awt.event.MouseListener;
12 | import java.io.File;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | import javax.swing.BoxLayout;
17 | import javax.swing.JButton;
18 | import javax.swing.JFileChooser;
19 | import javax.swing.JFrame;
20 | import javax.swing.JLabel;
21 | import javax.swing.JMenu;
22 | import javax.swing.JMenuBar;
23 | import javax.swing.JMenuItem;
24 | import javax.swing.JOptionPane;
25 | import javax.swing.JPanel;
26 | import javax.swing.JScrollPane;
27 | import javax.swing.JTable;
28 | import javax.swing.JTextField;
29 |
30 | public class Trace {
31 |
32 | static JLabel JlPath;
33 | private static final String PATH = "........................................................";
34 |
35 | public static void main(String[] args) {
36 | String packageName = null;
37 |
38 | int windowWidth = 1280;
39 | int windowHeight = 600;
40 | if (Utils.isMacOS()) {
41 | windowWidth = 1080;
42 | windowHeight = 720;
43 | }
44 |
45 | // 窗口标题名
46 | JFrame window = new JFrame("App method trace analysis");
47 | window.setSize(windowWidth, windowHeight);
48 | window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
49 | window.setResizable(false);// 窗体大小不可变
50 |
51 | JMenuBar menuBar = new JMenuBar();
52 |
53 | // 设置菜单--File
54 | JMenu menuFile = new JMenu("File");
55 | menuBar.add(menuFile);
56 | JMenuItem itemOpen = new JMenuItem("Open");
57 | menuFile.add(itemOpen);
58 |
59 | // 设置菜单--About
60 | JMenu menuAbout = new JMenu("About");
61 | JMenuItem itemAbout = new JMenuItem("About Me");
62 | menuAbout.add(itemAbout);
63 | menuBar.add(menuAbout);
64 |
65 | // 添加菜单
66 | window.setJMenuBar(menuBar);
67 |
68 | JPanel panel = new JPanel();
69 | JPanel root = new JPanel();
70 | window.setContentPane(root);
71 | root.setLayout(new BoxLayout(root, BoxLayout.Y_AXIS));
72 | panel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 5, 5,
73 | true, false));
74 |
75 | JPanel path = new JPanel();
76 | path.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
77 | path.add(new JLabel("File Path:"));
78 | JlPath = new JLabel(PATH);
79 | path.add(JlPath);
80 | panel.add(path);
81 |
82 | drag();//启用拖拽
83 |
84 | JPanel top = new JPanel();
85 | top.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
86 | top.add(new JLabel("Filter Package Name:"));
87 | JTextField jpName = new JTextField("package name", 30);// com.jushi.trading
88 | jpName.setBounds(10, 10, 100, 20);
89 | // 设置文本的水平对齐方式
90 | jpName.setHorizontalAlignment(JTextField.CENTER);
91 | top.add(jpName, BorderLayout.PAGE_START);
92 |
93 | // 分析按钮
94 | JButton jGo = new JButton("analysis");
95 | top.add(jGo);
96 | panel.add(top);
97 |
98 | JPanel jpStatus = new JPanel();
99 | jpStatus.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
100 | JLabel jlStatus = new JLabel("Info:");
101 | jpStatus.add(jlStatus);
102 | panel.add(jpStatus);
103 | jpStatus.setVisible(false);
104 |
105 | root.add(panel, BorderLayout.PAGE_START);
106 |
107 | // 内容显示列表
108 | JTable table = new JTable(new MethodTabModel());
109 | // 可滑动面板
110 | JScrollPane scrollPane = new JScrollPane(table);
111 | root.add(scrollPane, BorderLayout.CENTER);
112 | table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
113 | // 点击监听
114 | table.addMouseListener(new MouseListener() {
115 |
116 | @Override
117 | public void mouseReleased(MouseEvent e) {
118 | // TODO Auto-generated method stub
119 |
120 | }
121 |
122 | @Override
123 | public void mousePressed(MouseEvent e) {
124 | // TODO Auto-generated method stub
125 |
126 | }
127 |
128 | @Override
129 | public void mouseExited(MouseEvent e) {
130 | // TODO Auto-generated method stub
131 |
132 | }
133 |
134 | @Override
135 | public void mouseEntered(MouseEvent e) {
136 | // TODO Auto-generated method stub
137 |
138 | }
139 |
140 | @Override
141 | public void mouseClicked(MouseEvent e) {
142 | if (e.getClickCount() == 2) {//
143 | Log.e(Log.getTag(), "双击");
144 | }
145 |
146 | }
147 | });
148 |
149 | // 分析按钮点击监听
150 | jGo.addActionListener(new ActionListener() {
151 |
152 | @Override
153 | public void actionPerformed(ActionEvent e) {
154 | Log.e(Log.getTag(), JlPath.getText());
155 | if (JlPath.getText().equals(PATH)) {
156 | JOptionPane.showMessageDialog(root, "请导入trace文件", "提示消息",
157 | JOptionPane.WARNING_MESSAGE);
158 | } else if (!JlPath.getText().endsWith("trace")) {
159 | JOptionPane.showMessageDialog(root, "请导入有效的trace文件",
160 | "提示消息", JOptionPane.WARNING_MESSAGE);
161 | } else if (jpName.getText().equals("package name") || jpName.getText().equals("")) {
162 | JOptionPane.showMessageDialog(root, "请输入需过滤的包名", "提示消息",
163 | JOptionPane.WARNING_MESSAGE);
164 | } else {
165 | TraceScanner scanner = new TraceScanner(new File(JlPath.getText()));
166 | // 赋值
167 | scanner.setPackageName(jpName.getText());
168 | jlStatus.setText("analysis...");
169 | MethodTabModel model = (MethodTabModel) table.getModel();
170 | ArrayList tableArray = Utils
171 | .mapConvert2Array(scanner.convertFile(JlPath
172 | .getText()));
173 | ArrayList xmlBean = new ArrayList();
174 | xmlBean.addAll(tableArray);
175 | model.setContent(tableArray);
176 | Utils.fitTableColumns(table);
177 | for (int i = 0; i < xmlBean.size(); i++) {
178 | System.out.println("");
179 | }
180 | }
181 | }
182 | });
183 |
184 | itemAbout.addActionListener(new ActionListener() {
185 |
186 | @Override
187 | public void actionPerformed(ActionEvent e) {
188 | Object[] options = {"Go", "No!"};
189 | int n = JOptionPane
190 | .showOptionDialog(null,
191 | "Visit me :https://github.com/Harlber",
192 | "About Me", JOptionPane.YES_NO_OPTION,
193 | JOptionPane.QUESTION_MESSAGE, null, options,
194 | options[0]);
195 | if (n == 0) {
196 | try {
197 | Utils.browse("https://github.com/Harlber");
198 | } catch (Exception e1) {
199 | e1.printStackTrace();
200 | }
201 | }
202 | }
203 | });
204 |
205 | // File菜单中Open选项点击事件
206 | itemOpen.addActionListener(new ActionListener() {
207 |
208 | @Override
209 | public void actionPerformed(ActionEvent arg0) {
210 | JFileChooser jfc = new JFileChooser();
211 | jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
212 | jfc.showDialog(new JLabel(), "选择");
213 | File file = jfc.getSelectedFile();
214 | if (file.isDirectory()) {
215 | Log.e(Log.getTag(), "文件夹:" + file.getAbsolutePath());
216 | } else if (file.isFile()) {
217 | Log.e(Log.getTag(), "文件:" + file.getAbsolutePath());
218 | }
219 | JlPath.setText(file.getAbsolutePath());
220 | jpName.setText(Utils.getPackageName(file.getAbsolutePath()));
221 | }
222 | });
223 | window.setVisible(true);
224 | }
225 |
226 |
227 | public static void drag()//定义的拖拽方法
228 | {
229 | //panel表示要接受拖拽的控件
230 | new DropTarget(JlPath, DnDConstants.ACTION_COPY_OR_MOVE, new DropTargetAdapter() {
231 | public void drop(DropTargetDropEvent dtde)//重写适配器的drop方法
232 | {
233 | try {
234 | if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor))//如果拖入的文件格式受支持
235 | {
236 | dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);//接收拖拽来的数据
237 | List list = (List) (dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor));
238 | String temp = "";
239 | for (File file : list) {
240 | temp = file.getAbsolutePath();
241 | JlPath.setText(temp);
242 | break;
243 | }
244 | //JOptionPane.showMessageDialog(null, temp);
245 | dtde.dropComplete(true);//指示拖拽操作已完成
246 | } else {
247 | dtde.rejectDrop();//否则拒绝拖拽来的数据
248 | }
249 | } catch (Exception e) {
250 | e.printStackTrace();
251 | }
252 | }
253 | });
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/MethodTrace/src/TraceScanner.java:
--------------------------------------------------------------------------------
1 | import java.io.BufferedReader;
2 | import java.io.File;
3 | import java.io.InputStreamReader;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 |
7 | /**
8 | * 文件扫描
9 | */
10 | public class TraceScanner {
11 | private File file;
12 | private String packageName = "";
13 | private AnalysisListener listener;
14 |
15 | public TraceScanner(File file) {
16 | super();
17 | this.file = file;
18 | System.out.println("file:" + file);
19 | }
20 |
21 | public void setFile(File file) {
22 | this.file = file;
23 | }
24 |
25 | public void setPackageName(String packageName) {
26 | this.packageName = packageName;
27 | }
28 |
29 | public void setListener(AnalysisListener listener) {
30 | this.listener = listener;
31 | }
32 |
33 | public HashMap convertFile(String path) {
34 | ArrayList index = new ArrayList();
35 | HashMap result = new HashMap();
36 | String osName = System.getProperty("os.name");
37 |
38 | Log.e(Log.getTag(),"packageName:" + packageName);
39 | index.add("PackageName: " + packageName + "\n");
40 | index.add("start dmtracedump\n");
41 | String oName = packageName.replaceAll("[.]", "/");
42 | if (listener != null) {
43 | listener.startAnalysis();
44 | }
45 | if (!file.exists()) {
46 | System.out.println("File does not exist");
47 | } else {
48 | Runtime runtime = Runtime.getRuntime();
49 | BufferedReader br = null;
50 | try {
51 | Process p;
52 | if (osName.contains("Windows") || osName.contains("windows")) {
53 | p = Runtime.getRuntime().exec(Utils.getWinCommand(path));
54 | } else {
55 | // mac or linux
56 | p = Runtime.getRuntime().exec(Utils.getMacCommand(path));
57 | }
58 |
59 | br = new BufferedReader(new InputStreamReader(
60 | p.getInputStream()));
61 | String lineTxt = null;
62 | // 读取每行的数据
63 | while ((lineTxt = br.readLine()) != null) {
64 | if (lineTxt.contains(packageName)
65 | || lineTxt.contains(oName)) {
66 | result = Utils.convert2Tab(result, lineTxt.replaceAll("[.]{2,}+", ""));
67 | index.add(lineTxt + "\n");
68 | }
69 | }
70 | } catch (Exception e) {
71 | result = Utils.convert2Tab(result,
72 | "unknown ent 0 exec dmtracedump exception");
73 | index.add("执行dmtracedump命令异常\n");
74 | e.printStackTrace();
75 | } finally {
76 | if (br != null) {
77 | try {
78 | br.close();
79 | } catch (Exception e) {
80 | e.printStackTrace();
81 | }
82 | }
83 | index.add("end dmtracedump\n");
84 | System.out.println("cmd end");
85 | if (listener != null) {
86 | listener.afterAnalysis();
87 | }
88 | }
89 | }
90 | return result;
91 |
92 | }
93 |
94 | public interface AnalysisListener {
95 | void startAnalysis();
96 |
97 | void afterAnalysis();
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/MethodTrace/src/Utils.java:
--------------------------------------------------------------------------------
1 | import java.lang.reflect.Method;
2 | import java.util.ArrayList;
3 | import java.util.Arrays;
4 | import java.util.Enumeration;
5 | import java.util.HashMap;
6 | import java.util.List;
7 |
8 | import javax.swing.JTable;
9 | import javax.swing.table.JTableHeader;
10 | import javax.swing.table.TableColumn;
11 |
12 | public class Utils {
13 |
14 | public static String getWinCommand(String path) {
15 | return "dmtracedump -o " + path;
16 | }
17 |
18 | public static String[] getMacCommand(String path) {
19 | String dumpCmd = "dmtracedump -o " + path;
20 | String[] result = {"bash", "-c", dumpCmd};
21 | return result;
22 | }
23 |
24 | @SuppressWarnings("finally")
25 | public static String getPackageName(String str) {
26 | if (null == str || str.equals("")) {
27 | return "";
28 | }
29 | String result = "";
30 | int start = 0;
31 | try {
32 | if (System.getProperty("os.name").contains("Windows")
33 | || System.getProperty("os.name").contains("windows")) {
34 | start = str.lastIndexOf("\\");
35 | } else if (isMacOS()) {
36 | start = str.lastIndexOf("/");
37 | } else {
38 | start = str.lastIndexOf("//");
39 | }
40 | int end = str.indexOf("_");
41 | result = str.substring(start + 1, end);
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | } finally {
45 | return result;
46 | }
47 | }
48 |
49 | public static String[] removeArrayEmptyTextBackNewArray(String[] strArray) {
50 | List strList = Arrays.asList(strArray);
51 | List strListNew = new ArrayList<>();
52 | for (int i = 0; i < strList.size(); i++) {
53 | if (strList.get(i) != null && !strList.get(i).equals("")) {
54 | strListNew.add(strList.get(i));
55 | }
56 | }
57 | String[] strNewArray = strListNew
58 | .toArray(new String[strListNew.size()]);
59 | return strNewArray;
60 | }
61 |
62 | public static HashMap convert2Tab(
63 | HashMap keyInfo, String index) {
64 |
65 | String[] indexStr = index.split(" ");// replaceAll("[.]+", "")
66 | String[] str = removeArrayEmptyTextBackNewArray(indexStr);
67 | if (str.length > 6) {
68 | for (int i = 0; i < str.length; i++)
69 | System.out.println(str[i]);
70 | }
71 | /*
72 | * System.out.println("[0]:" + str[0] + "[1]:" + str[1] + "[3]:" +
73 | * str[3] + "length:" + str.length);
74 | */
75 | StringBuffer key = new StringBuffer();
76 | for (int i = 3; i < str.length; i++) {
77 | key.append(str[i]);
78 | key.append(" ");
79 | }
80 |
81 | if (keyInfo.containsKey(key.toString())) {//
82 | InfoBean bean = keyInfo.get(key.toString());
83 | if (str[1].equals("ent")) {
84 | bean.setXitTime(Integer.valueOf(str[2]));
85 | } else {
86 | bean.setXitTime(Integer.valueOf(str[2]));
87 | }
88 | fillClassInfo(index, bean);
89 | keyInfo.replace(key.toString(), bean);
90 | } else {
91 | InfoBean bean = new InfoBean();
92 | bean.setKey(key.toString());
93 | bean.settId(str[0]);
94 | bean.setType(str[1]);
95 | if (str[1].equals("ent")) {
96 | bean.setEntTime(Integer.valueOf(str[2]));
97 | } else {
98 | bean.setXitTime(Integer.valueOf(str[2]));
99 | }
100 | fillClassInfo(index, bean);
101 | keyInfo.put(key.toString(), bean);
102 | }
103 | return keyInfo;
104 |
105 | }
106 |
107 | /* 坑点:内部类 adapter$1.ViewHolder */
108 | static void fillClassInfo(String index, InfoBean info) {
109 | if (isEmpty(index)) {
110 | return;
111 | }
112 | Log.e(Log.getTag(), "index: " + index);
113 | // unknown ent 0 exec dmtracedump exception
114 | if (index.indexOf("java") < 0 && index.contains("dmtracedump")) {
115 | info.setClsName("Exception");
116 | info.setMethodName(index);
117 | } else {
118 | String[] names = index.split("\t");
119 | if (names.length < 1) {
120 | return;
121 | }
122 | Log.e(Log.getTag(), "names: " + names.length);
123 | String classInfo = names[names.length - 1];
124 | String className;
125 | if (classInfo.contains(".")) {
126 | className = classInfo.substring(0, classInfo.indexOf("."));
127 | } else {
128 | className = classInfo;
129 | }
130 | String class_pot = className + ".";
131 | String class_$ = className + "$";
132 |
133 | String methodName = "";
134 | String methodStr = names[names.length - 2];
135 | Log.e(Log.getTag(), "methodStr: " + methodStr);
136 |
137 |
138 | int dexPot = methodStr.indexOf(class_pot);
139 | int dex$ = methodStr.indexOf(class_$);
140 |
141 | Log.e(Log.getTag(), "dexPot: " + dexPot);
142 | Log.e(Log.getTag(), "dex$: " + dex$);
143 | int start = Math.max(dexPot, dex$);
144 | methodName = methodStr.substring(start < 0 ? 0 : start,
145 | methodStr.length());
146 |
147 | info.setClsName(className);
148 | info.setMethodName(methodName);
149 | info.setFullClassName(info.getKey().substring(0,
150 | info.getKey().indexOf(className))
151 | + className);
152 | }
153 | }
154 |
155 | public static ArrayList mapConvert2Array(
156 | HashMap map) {
157 | ArrayList result = new ArrayList();
158 | for (InfoBean value : map.values()) {
159 | result.add(value);
160 | }
161 | return result;
162 | }
163 |
164 | public static void fitTableColumns(JTable myTable) {
165 |
166 | JTableHeader header = myTable.getTableHeader();
167 | int rowCount = myTable.getRowCount();
168 | Enumeration columns = myTable.getColumnModel().getColumns();
169 | while (columns.hasMoreElements()) {
170 | TableColumn column = (TableColumn) columns.nextElement();
171 | int col = header.getColumnModel().getColumnIndex(
172 | column.getIdentifier());
173 | int width = (int) myTable
174 | .getTableHeader()
175 | .getDefaultRenderer()
176 | .getTableCellRendererComponent(myTable,
177 | column.getIdentifier(), false, false, -1, col)
178 | .getPreferredSize().getWidth();
179 | for (int row = 0; row < rowCount; row++) {
180 | int preferedWidth = (int) myTable
181 | .getCellRenderer(row, col)
182 | .getTableCellRendererComponent(myTable,
183 | myTable.getValueAt(row, col), false, false,
184 | row, col).getPreferredSize().getWidth();
185 | width = Math.max(width, preferedWidth);
186 | }
187 | header.setResizingColumn(column); // 此行很重要
188 | column.setWidth(width + myTable.getIntercellSpacing().width + 4);// 使表格看起来不是那么拥挤,起到间隔作用
189 | }
190 | }
191 |
192 | public static void browse(String url) throws Exception {
193 | // 获取操作系统的名字
194 | String osName = System.getProperty("os.name", "");
195 | if (osName.startsWith("Mac OS")) {
196 | // 苹果的打开方式
197 | Class fileMgr = Class.forName("com.apple.eio.FileManager");
198 | Method openURL = fileMgr.getDeclaredMethod("openURL",
199 | new Class[]{String.class});
200 | openURL.invoke(null, new Object[]{url});
201 | } else if (osName.startsWith("Windows")) {
202 | // windows的打开方式。
203 | Runtime.getRuntime().exec(
204 | "rundll32 url.dll,FileProtocolHandler " + url);
205 | } else {
206 | // Unix or Linux的打开方式
207 | String[] browsers = {"firefox", "opera", "konqueror", "epiphany",
208 | "mozilla", "netscape"};
209 | String browser = null;
210 | for (int count = 0; count < browsers.length && browser == null; count++)
211 | // 执行代码,在brower有值后跳出,
212 | // 这里是如果进程创建成功了,==0是表示正常结束。
213 | if (Runtime.getRuntime()
214 | .exec(new String[]{"which", browsers[count]})
215 | .waitFor() == 0)
216 | browser = browsers[count];
217 | if (browser == null)
218 | throw new Exception("Could not find web browser");
219 | else
220 | // 这个值在上面已经成功的得到了一个进程。
221 | Runtime.getRuntime().exec(new String[]{browser, url});
222 | }
223 | }
224 |
225 |
226 | public static boolean isMacOS() {
227 | return System.getProperty("os.name", "").startsWith("Mac OS");
228 | }
229 |
230 | public static boolean isEmpty(String s) {
231 | return s == null || s.isEmpty();
232 | }
233 |
234 | }
235 |
--------------------------------------------------------------------------------
/MethodTrace/src/VerticalFlowLayout.java:
--------------------------------------------------------------------------------
1 | import java.awt.Component;
2 | import java.awt.Container;
3 | import java.awt.Dimension;
4 | import java.awt.FlowLayout;
5 | import java.awt.Insets;
6 |
7 | /**
8 | * VerticalFlowLayout is similar to FlowLayout except it lays out components
9 | * vertically. Extends FlowLayout because it mimics much of the behavior of the
10 | * FlowLayout class, except vertically. An additional feature is that you can
11 | * specify a fill to edge flag, which causes the VerticalFlowLayout manager to
12 | * resize all components to expand to the column width Warning: This causes
13 | * problems when the main panel has less space that it needs and it seems to
14 | * prohibit multi-column output. Additionally there is a vertical fill flag,
15 | * which fills the last component to the remaining height of the container.
16 | */
17 | public class VerticalFlowLayout extends FlowLayout {
18 |
19 | /**
20 | * Specify alignment top.
21 | */
22 | public static final int TOP = 0;
23 |
24 | /**
25 | * Specify a middle alignment.
26 | */
27 | public static final int MIDDLE = 1;
28 |
29 | /**
30 | * Specify the alignment to be bottom.
31 | */
32 | public static final int BOTTOM = 2;
33 |
34 | int hgap;
35 | int vgap;
36 | boolean hfill;
37 | boolean vfill;
38 |
39 | /**
40 | * Construct a new VerticalFlowLayout with a middle alignment, and the fill
41 | * to edge flag set.
42 | */
43 | public VerticalFlowLayout() {
44 | this(TOP, 5, 5, true, false);
45 | }
46 |
47 | /**
48 | * Construct a new VerticalFlowLayout with a middle alignment.
49 | *
50 | * @param hfill
51 | * the fill to edge flag
52 | * @param vfill
53 | * the vertical fill in pixels.
54 | */
55 | public VerticalFlowLayout(boolean hfill, boolean vfill) {
56 | this(TOP, 5, 5, hfill, vfill);
57 | }
58 |
59 | /**
60 | * Construct a new VerticalFlowLayout with a middle alignment.
61 | *
62 | * @param align
63 | * the alignment value
64 | */
65 | public VerticalFlowLayout(int align) {
66 | this(align, 5, 5, true, false);
67 | }
68 |
69 | /**
70 | * Construct a new VerticalFlowLayout.
71 | *
72 | * @param align
73 | * the alignment value
74 | * @param hfill
75 | * the horizontalfill in pixels.
76 | * @param vfill
77 | * the vertical fill in pixels.
78 | */
79 | public VerticalFlowLayout(int align, boolean hfill, boolean vfill) {
80 | this(align, 5, 5, hfill, vfill);
81 | }
82 |
83 | /**
84 | * Construct a new VerticalFlowLayout.
85 | *
86 | * @param align
87 | * the alignment value
88 | * @param hgap
89 | * the horizontal gap variable
90 | * @param vgap
91 | * the vertical gap variable
92 | * @param hfill
93 | * the fill to edge flag
94 | * @param vfill
95 | * true if the panel should vertically fill.
96 | */
97 | public VerticalFlowLayout(int align, int hgap, int vgap, boolean hfill,
98 | boolean vfill) {
99 | setAlignment(align);
100 | this.hgap = hgap;
101 | this.vgap = vgap;
102 | this.hfill = hfill;
103 | this.vfill = vfill;
104 | }
105 |
106 | /**
107 | * Returns the preferred dimensions given the components in the target
108 | * container.
109 | *
110 | * @param target
111 | * the component to lay out
112 | */
113 | public Dimension preferredLayoutSize(Container target) {
114 | Dimension tarsiz = new Dimension(0, 0);
115 |
116 | for (int i = 0; i < target.getComponentCount(); i++) {
117 | Component m = target.getComponent(i);
118 | if (m.isVisible()) {
119 | Dimension d = m.getPreferredSize();
120 | tarsiz.width = Math.max(tarsiz.width, d.width);
121 | if (i > 0) {
122 | tarsiz.height += hgap;
123 | }
124 | tarsiz.height += d.height;
125 | }
126 | }
127 | Insets insets = target.getInsets();
128 | tarsiz.width += insets.left + insets.right + hgap * 2;
129 | tarsiz.height += insets.top + insets.bottom + vgap * 2;
130 | return tarsiz;
131 | }
132 |
133 | /**
134 | * Returns the minimum size needed to layout the target container.
135 | *
136 | * @param target
137 | * the component to lay out.
138 | * @return the minimum layout dimension.
139 | */
140 | public Dimension minimumLayoutSize(Container target) {
141 | Dimension tarsiz = new Dimension(0, 0);
142 |
143 | for (int i = 0; i < target.getComponentCount(); i++) {
144 | Component m = target.getComponent(i);
145 | if (m.isVisible()) {
146 | Dimension d = m.getMinimumSize();
147 | tarsiz.width = Math.max(tarsiz.width, d.width);
148 | if (i > 0) {
149 | tarsiz.height += vgap;
150 | }
151 | tarsiz.height += d.height;
152 | }
153 | }
154 | Insets insets = target.getInsets();
155 | tarsiz.width += insets.left + insets.right + hgap * 2;
156 | tarsiz.height += insets.top + insets.bottom + vgap * 2;
157 | return tarsiz;
158 | }
159 |
160 | /**
161 | * Set true to fill vertically.
162 | *
163 | * @param vfill
164 | * true to fill vertically.
165 | */
166 | public void setVerticalFill(boolean vfill) {
167 | this.vfill = vfill;
168 | }
169 |
170 | /**
171 | * Returns true if the layout vertically fills.
172 | *
173 | * @return true if vertically fills the layout using the specified.
174 | */
175 | public boolean getVerticalFill() {
176 | return vfill;
177 | }
178 |
179 | /**
180 | * Set to true to enable horizontally fill.
181 | *
182 | * @param hfill
183 | * true to fill horizontally.
184 | */
185 | public void setHorizontalFill(boolean hfill) {
186 | this.hfill = hfill;
187 | }
188 |
189 | /**
190 | * Returns true if the layout horizontally fills.
191 | *
192 | * @return true if horizontally fills.
193 | */
194 | public boolean getHorizontalFill() {
195 | return hfill;
196 | }
197 |
198 | /**
199 | * places the components defined by first to last within the target
200 | * container using the bounds box defined.
201 | *
202 | * @param target
203 | * the container.
204 | * @param x
205 | * the x coordinate of the area.
206 | * @param y
207 | * the y coordinate of the area.
208 | * @param width
209 | * the width of the area.
210 | * @param height
211 | * the height of the area.
212 | * @param first
213 | * the first component of the container to place.
214 | * @param last
215 | * the last component of the container to place.
216 | */
217 | private void placethem(Container target, int x, int y, int width,
218 | int height, int first, int last) {
219 | int align = getAlignment();
220 | if (align == MIDDLE)
221 | y += height / 2;
222 | if (align == BOTTOM)
223 | y += height;
224 |
225 | for (int i = first; i < last; i++) {
226 | Component m = target.getComponent(i);
227 | Dimension md = m.getSize();
228 | if (m.isVisible()) {
229 | int px = x + (width - md.width) / 2;
230 | m.setLocation(px, y);
231 | y += vgap + md.height;
232 | }
233 | }
234 | }
235 |
236 | /**
237 | * Lays out the container.
238 | *
239 | * @param target
240 | * the container to lay out.
241 | */
242 | public void layoutContainer(Container target) {
243 | Insets insets = target.getInsets();
244 | int maxheight = target.getSize().height
245 | - (insets.top + insets.bottom + vgap * 2);
246 | int maxwidth = target.getSize().width
247 | - (insets.left + insets.right + hgap * 2);
248 | int numcomp = target.getComponentCount();
249 | int x = insets.left + hgap, y = 0;
250 | int colw = 0, start = 0;
251 |
252 | for (int i = 0; i < numcomp; i++) {
253 | Component m = target.getComponent(i);
254 | if (m.isVisible()) {
255 | Dimension d = m.getPreferredSize();
256 | // fit last component to remaining height
257 | if ((this.vfill) && (i == (numcomp - 1))) {
258 | d.height = Math.max((maxheight - y),
259 | m.getPreferredSize().height);
260 | }
261 |
262 | // fit component size to container width
263 | if (this.hfill) {
264 | m.setSize(maxwidth, d.height);
265 | d.width = maxwidth;
266 | } else {
267 | m.setSize(d.width, d.height);
268 | }
269 |
270 | if (y + d.height > maxheight) {
271 | placethem(target, x, insets.top + vgap, colw,
272 | maxheight - y, start, i);
273 | y = d.height;
274 | x += hgap + colw;
275 | colw = d.width;
276 | start = i;
277 | } else {
278 | if (y > 0)
279 | y += vgap;
280 | y += d.height;
281 | colw = Math.max(colw, d.width);
282 | }
283 | }
284 | }
285 | placethem(target, x, insets.top + vgap, colw, maxheight - y, start,
286 | numcomp);
287 | }
288 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 分析应用方法耗时的swing工具
2 | > 采用该项目(https://github.com/zjw-swun/AppMethodOrder) 的思路,基于trace文件分析过滤出当前应用(包名)下的方法信息.
3 | # 使用方法
4 | - 将``sdk\platform-tools``下的dmtracedump添加到系统环境变量
5 | - 使用tool文件夹下的``MethodTrace.jar`` 直接导入`.trace文件`,一键分析
6 | # 效果图
7 |
8 |
9 |
10 | # 注意点
11 | - 建议在`jdk 1.8`环境下运行,如是1.7及以下的jdk,请自行修改代码兼容
12 | - 目前该小工具可使用于Windows平台下,Mac及Linux可自行修改代码兼容(目前无Mac设备,无法测试-_-!)
13 | >Mac下可通过 `java -jar tool/MethodTrace.jar`执行
14 | - 需先将`dmtracedump`添加至环境变量
15 | - 方法耗时的单位为`μs`
16 | - `unknow`意味着该方法未结束调用
17 | # TODO
18 | - 可视化方法调用图
19 |
20 |
21 | # 编译Method_Trace_Tool工程
22 |
23 | 1. Method_Trace_Tool工程包括编译好的jar包,以及项目源码
24 | 2. MethodTrace目录对应的是一个eclipse工程,可以选择用eclipse开发工具import这个工程,或者是使用IntelliJ IDEA工具open这个工程
25 | 3. 打开工程后,直接在Trace.java类处run main方法即可启动图形化界面
26 | 4. 或者是选择export为jar包的形式,具体可[参考](https://stackoverflow.com/a/9463915/5279354)(idea开发工具)
--------------------------------------------------------------------------------
/art/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Harlber/Method_Trace_Tool/2ee23ba7a3a6823c087b3d56b540c2401c158c56/art/preview.png
--------------------------------------------------------------------------------
/tool/MethodTrace.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Harlber/Method_Trace_Tool/2ee23ba7a3a6823c087b3d56b540c2401c158c56/tool/MethodTrace.jar
--------------------------------------------------------------------------------