├── .gitignore
├── README.md
├── demo
├── 1581129760409.folded
├── 1581129760409.png
├── 1581129760409.svg
├── 1581129760409.txt
└── methodMapping.txt
├── device
├── __init__.py
└── device.py
├── importer
├── __init__.py
├── interpreter.py
└── trace_file.py
├── main.py
└── symbols
├── __init__.py
├── apk_symbols.py
└── mapping_symbols.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Example user template template
3 | ### Example user template
4 |
5 | # IntelliJ project files
6 | .idea
7 | *.iml
8 | out
9 | gen
10 | ### Python template
11 | # Byte-compiled / optimized / DLL files
12 | __pycache__/
13 | *.py[cod]
14 | *$py.class
15 |
16 | # C extensions
17 | *.so
18 |
19 | # Distribution / packaging
20 | .Python
21 | build/
22 | develop-eggs/
23 | dist/
24 | downloads/
25 | eggs/
26 | .eggs/
27 | lib/
28 | lib64/
29 | parts/
30 | sdist/
31 | var/
32 | wheels/
33 | pip-wheel-metadata/
34 | share/python-wheels/
35 | *.egg-info/
36 | .installed.cfg
37 | *.egg
38 | MANIFEST
39 |
40 | # PyInstaller
41 | # Usually these files are written by a python script from a template
42 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
43 | *.manifest
44 | *.spec
45 |
46 | # Installer logs
47 | pip-log.txt
48 | pip-delete-this-directory.txt
49 |
50 | # Unit test / coverage reports
51 | htmlcov/
52 | .tox/
53 | .nox/
54 | .coverage
55 | .coverage.*
56 | .cache
57 | nosetests.xml
58 | coverage.xml
59 | *.cover
60 | *.py,cover
61 | .hypothesis/
62 | .pytest_cache/
63 |
64 | # Translations
65 | *.mo
66 | *.pot
67 |
68 | # Django stuff:
69 | *.log
70 | local_settings.py
71 | db.sqlite3
72 | db.sqlite3-journal
73 |
74 | # Flask stuff:
75 | instance/
76 | .webassets-cache
77 |
78 | # Scrapy stuff:
79 | .scrapy
80 |
81 | # Sphinx documentation
82 | docs/_build/
83 |
84 | # PyBuilder
85 | target/
86 |
87 | # Jupyter Notebook
88 | .ipynb_checkpoints
89 |
90 | # IPython
91 | profile_default/
92 | ipython_config.py
93 |
94 | # pyenv
95 | .python-version
96 |
97 | # pipenv
98 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
99 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
100 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
101 | # install all needed dependencies.
102 | #Pipfile.lock
103 |
104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
105 | __pypackages__/
106 |
107 | # Celery stuff
108 | celerybeat-schedule
109 | celerybeat.pid
110 |
111 | # SageMath parsed files
112 | *.sage.py
113 |
114 | # Environments
115 | .env
116 | .venv
117 | env/
118 | venv/
119 | ENV/
120 | env.bak/
121 | venv.bak/
122 |
123 | # Spyder project settings
124 | .spyderproject
125 | .spyproject
126 |
127 | # Rope project settings
128 | .ropeproject
129 |
130 | # mkdocs documentation
131 | /site
132 |
133 | # mypy
134 | .mypy_cache/
135 | .dmypy.json
136 | dmypy.json
137 |
138 | # Pyre type checker
139 | .pyre/
140 |
141 | **/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Matrix Trace Processor
2 |
3 | 处理 [matrix-trace-canary](https://github.com/Tencent/matrix/tree/master/matrix/matrix-android/matrix-trace-canary) 中的堆栈信息。
4 |
5 | ## Thanks
6 |
7 | [profilo](https://github.com/facebookincubator/profilo)
8 |
9 | ## Demo
10 |
11 | 
12 |
13 | ## Usage
14 |
15 | 1. 保存堆栈信息到文件中
16 |
17 | 2. 将 matrix 生成的 methodMapping.txt 保存下来
18 |
19 | 3. 执行 python 脚本
20 |
21 | ``` shell
22 | python3 main.py workflow_traces demo/1581129760409.log > demo/1581129760409.txt demo/methodMapping.txt
23 | ```
24 |
25 | 4. 使用 [FlameGraph](https://github.com/brendangregg/FlameGraph) 将上面输出的 1581129760409.txt 转到 svg 文件
26 |
27 | ``` shell
28 | stackcollapse.pl demo/1581129760409.txt > demo/1581129760409.folded
29 | flamegraph.pl demo/1581129760409.folded > demo/1581129760409.svg
30 | ```
31 |
32 | ## Contributing
33 |
34 | PRs accepted.
35 |
36 | ## License
37 |
38 | MIT
--------------------------------------------------------------------------------
/demo/1581129760409.folded:
--------------------------------------------------------------------------------
1 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms);sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms);sample.tencent.matrix.trace.TestTraceMainActivity D ()V(16ms) 1
2 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms);sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms);sample.tencent.matrix.trace.TestTraceMainActivity E ()V(15ms) 1
3 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms);sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms);sample.tencent.matrix.trace.TestTraceMainActivity F ()V(21ms) 1
4 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms);sample.tencent.matrix.trace.TestTraceMainActivity G ()V(20ms) 1
5 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms);sample.tencent.matrix.trace.TestTraceMainActivity I ()V(21ms) 1
6 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms);sample.tencent.matrix.trace.TestTraceMainActivity J ()V(5ms) 1
7 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms);sample.tencent.matrix.trace.TestTraceMainActivity K ()V(11ms) 1
8 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms);sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms);sample.tencent.matrix.trace.TestTraceMainActivity L ()V(10001ms) 1
9 |
--------------------------------------------------------------------------------
/demo/1581129760409.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinXiaoTao/matrix-trace-processor/99746552e1942d9579427c5de980b9db36eab6e9/demo/1581129760409.png
--------------------------------------------------------------------------------
/demo/1581129760409.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
437 |
--------------------------------------------------------------------------------
/demo/1581129760409.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | sample.tencent.matrix.trace.TestTraceMainActivity D ()V(16ms)
6 | sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms)
7 | sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms)
8 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
9 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
10 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
11 | 1
12 |
13 |
14 | sample.tencent.matrix.trace.TestTraceMainActivity E ()V(15ms)
15 | sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms)
16 | sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms)
17 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
18 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
19 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
20 | 1
21 |
22 |
23 | sample.tencent.matrix.trace.TestTraceMainActivity F ()V(21ms)
24 | sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms)
25 | sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms)
26 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
27 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
28 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
29 | 1
30 |
31 |
32 | sample.tencent.matrix.trace.TestTraceMainActivity G ()V(20ms)
33 | sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms)
34 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
35 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
36 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
37 | 1
38 |
39 |
40 | sample.tencent.matrix.trace.TestTraceMainActivity I ()V(21ms)
41 | sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms)
42 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
43 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
44 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
45 | 1
46 |
47 |
48 | sample.tencent.matrix.trace.TestTraceMainActivity J ()V(5ms)
49 | sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms)
50 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
51 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
52 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
53 | 1
54 |
55 |
56 | sample.tencent.matrix.trace.TestTraceMainActivity K ()V(11ms)
57 | sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms)
58 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
59 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
60 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
61 | 1
62 |
63 |
64 | sample.tencent.matrix.trace.TestTraceMainActivity L ()V(10001ms)
65 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms)
66 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V(11237ms)
67 | android.os.Handler dispatchMessage (Landroid.os.Message;)V(11239ms)
68 | 1
69 |
70 |
71 |
--------------------------------------------------------------------------------
/demo/methodMapping.txt:
--------------------------------------------------------------------------------
1 | 1,0,sample.tencent.matrix.trace.TestFpsActivity$3 (Lsample.tencent.matrix.trace.TestFpsActivity;Landroid.content.Context;I[Ljava.lang.Object;)V
2 | 2,1,sample.tencent.matrix.trace.TestTraceFragmentActivity ()V
3 | 3,1,sample.tencent.matrix.listener.TestPluginListener (Landroid.content.Context;)V
4 | 4,1,sample.tencent.matrix.trace.TestFpsActivity ()V
5 | 5,0,sample.tencent.matrix.trace.TestFpsActivity$1 (Lsample.tencent.matrix.trace.TestFpsActivity;)V
6 | 6,1,sample.tencent.matrix.trace.TestFpsActivity$2 doFrameAsync (Ljava.lang.String;JJIZ)V
7 | 7,1,sample.tencent.matrix.listener.TestPluginListener onReportIssue (Lcom.tencent.matrix.report.Issue;)V
8 | 8,1,sample.tencent.matrix.trace.TestFpsActivity$1 execute (Ljava.lang.Runnable;)V
9 | 9,4,sample.tencent.matrix.SplashActivity onCreate (Landroid.os.Bundle;)V
10 | 10,1,sample.tencent.matrix.trace.StartUpService onStartCommand (Landroid.content.Intent;II)I
11 | 11,1,sample.tencent.matrix.trace.StartUpBroadcastReceiver onReceive (Landroid.content.Context;Landroid.content.Intent;)V
12 | 12,1,sample.tencent.matrix.trace.FirstFragment onCreateView (Landroid.view.LayoutInflater;Landroid.view.ViewGroup;Landroid.os.Bundle;)Landroid.view.View;
13 | 13,1,sample.tencent.matrix.trace.SecondFragment onCreateView (Landroid.view.LayoutInflater;Landroid.view.ViewGroup;Landroid.os.Bundle;)Landroid.view.View;
14 | 14,1,sample.tencent.matrix.trace.TestTraceFragmentActivity$1 onClick (Landroid.view.View;)V
15 | 15,1,sample.tencent.matrix.listener.TestPluginListener jumpToIssueActivity ()V
16 | 16,9,sample.tencent.matrix.config.MatrixEnum values ()[Lsample.tencent.matrix.config.MatrixEnum;
17 | 17,9,sample.tencent.matrix.config.MatrixEnum valueOf (Ljava.lang.String;)Lsample.tencent.matrix.config.MatrixEnum;
18 | 18,1,sample.tencent.matrix.config.DynamicConfigImplDemo get (Ljava.lang.String;I)I
19 | 19,4,sample.tencent.matrix.trace.TestOtherProcessActivity onCreate (Landroid.os.Bundle;)V
20 | 20,10,sample.tencent.matrix.MatrixApplication initSQLiteLintConfig ()Lcom.tencent.sqlitelint.config.SQLiteLintConfig;
21 | 21,4,sample.tencent.matrix.MainActivity onResume ()V
22 | 22,4,sample.tencent.matrix.trace.TestStartUpActivity onCreate (Landroid.os.Bundle;)V
23 | 23,1,sample.tencent.matrix.config.DynamicConfigImplDemo get (Ljava.lang.String;J)J
24 | 24,1,sample.tencent.matrix.io.TestIOActivity$1 run ()V
25 | 25,1,sample.tencent.matrix.trace.TestStartUpActivity callByContentResolver ()V
26 | 26,4,sample.tencent.matrix.trace.TestTraceMainActivity onCreate (Landroid.os.Bundle;)V
27 | 27,1,sample.tencent.matrix.MainActivity$2 onClick (Landroid.view.View;)V
28 | 28,8,sample.tencent.matrix.config.MatrixEnum ()V
29 | 29,4,sample.tencent.matrix.io.TestIOActivity onCreate (Landroid.os.Bundle;)V
30 | 30,4,sample.tencent.matrix.trace.TestTraceMainActivity onActivityResult (IILandroid.content.Intent;)V
31 | 31,2,sample.tencent.matrix.io.TestIOActivity requestPer ()V
32 | 32,4,sample.tencent.matrix.trace.TestTraceMainActivity onDestroy ()V
33 | 33,2,sample.tencent.matrix.listener.TestPluginListener saveStackFile (Lcom.tencent.matrix.report.Issue;)V
34 | 34,1,sample.tencent.matrix.issue.IssuesListActivity$ViewHolder (Landroid.view.View;)V
35 | 35,2,sample.tencent.matrix.trace.TestTraceMainActivity canDrawOverlays ()Z
36 | 36,1,sample.tencent.matrix.issue.IssuesListActivity$Adapter$1 onClick (Landroid.view.View;)V
37 | 37,1,sample.tencent.matrix.issue.IssuesListActivity$Adapter (Landroid.content.Context;)V
38 | 38,2,sample.tencent.matrix.trace.TestTraceMainActivity requestWindowPermission ()V
39 | 39,4,sample.tencent.matrix.trace.TestFpsActivity onCreate (Landroid.os.Bundle;)V
40 | 40,1,sample.tencent.matrix.issue.IssuesListActivity$Adapter onCreateViewHolder (Landroid.view.ViewGroup;I)Lsample.tencent.matrix.issue.IssuesListActivity$ViewHolder;
41 | 41,1,sample.tencent.matrix.trace.TestTraceMainActivity testEnter (Landroid.view.View;)V
42 | 42,1,sample.tencent.matrix.trace.TestTraceMainActivity testFps (Landroid.view.View;)V
43 | 43,4,sample.tencent.matrix.trace.TestFpsActivity onDestroy ()V
44 | 44,1,sample.tencent.matrix.issue.IssuesListActivity$Adapter onBindViewHolder (Lsample.tencent.matrix.issue.IssuesListActivity$ViewHolder;I)V
45 | 45,1,sample.tencent.matrix.issue.IssuesListActivity$ViewHolder bind (Lcom.tencent.matrix.report.Issue;)V
46 | 46,9,sample.tencent.matrix.issue.IssuesMap put (Ljava.lang.String;Lcom.tencent.matrix.report.Issue;)V
47 | 47,1,sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View;)V
48 | 48,1,sample.tencent.matrix.issue.IssuesListActivity$Adapter getItemCount ()I
49 | 49,1,sample.tencent.matrix.trace.TestTraceMainActivity testANR (Landroid.view.View;)V
50 | 50,9,sample.tencent.matrix.issue.IssuesMap get (Ljava.lang.String;)Ljava.util.List;
51 | 51,9,sample.tencent.matrix.issue.ParseIssueUtil parseIssue (Lcom.tencent.matrix.report.Issue;Z)Ljava.lang.String;
52 | 52,4161,sample.tencent.matrix.issue.IssuesListActivity$Adapter onBindViewHolder (Landroid.support.v7.widget.RecyclerView$ViewHolder;I)V
53 | 53,2,sample.tencent.matrix.trace.TestTraceMainActivity A ()V
54 | 54,9,sample.tencent.matrix.issue.IssuesMap getCount ()I
55 | 55,4161,sample.tencent.matrix.issue.IssuesListActivity$Adapter onCreateViewHolder (Landroid.view.ViewGroup;I)Landroid.support.v7.widget.RecyclerView$ViewHolder;
56 | 56,2,sample.tencent.matrix.trace.TestTraceMainActivity B ()V
57 | 57,9,sample.tencent.matrix.issue.IssuesMap clear ()V
58 | 58,9,sample.tencent.matrix.issue.ParseIssueUtil pauseJsonObj (Ljava.lang.StringBuilder;Lorg.json.JSONObject;)Ljava.lang.StringBuilder;
59 | 59,8,sample.tencent.matrix.trace.TestFpsActivity ()V
60 | 60,2,sample.tencent.matrix.trace.TestTraceMainActivity C ()V
61 | 61,1,sample.tencent.matrix.io.TestIOActivity onClick (Landroid.view.View;)V
62 | 62,8,sample.tencent.matrix.issue.IssuesMap ()V
63 | 63,1,sample.tencent.matrix.issue.IssuesListActivity$ViewHolder readMappingFile (Ljava.util.Map;)V
64 | 64,2,sample.tencent.matrix.trace.TestTraceMainActivity D ()V
65 | 65,1,sample.tencent.matrix.io.TestIOActivity toastStartTest (Ljava.lang.String;)V
66 | 66,2,sample.tencent.matrix.trace.TestTraceMainActivity E ()V
67 | 67,2,sample.tencent.matrix.io.TestIOActivity smallBuffer ()V
68 | 68,2,sample.tencent.matrix.trace.TestTraceMainActivity F ()V
69 | 69,2,sample.tencent.matrix.trace.TestTraceMainActivity G ()V
70 | 70,4,sample.tencent.matrix.issue.IssuesListActivity onCreate (Landroid.os.Bundle;)V
71 | 71,2,sample.tencent.matrix.trace.TestTraceMainActivity H ()V
72 | 72,1,sample.tencent.matrix.issue.IssuesListActivity initRecyclerView ()V
73 | 73,1,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity ()V
74 | 74,9,sample.tencent.matrix.sqlitelint.TestDBHelper get ()Lsample.tencent.matrix.sqlitelint.TestDBHelper;
75 | 75,2,sample.tencent.matrix.trace.TestTraceMainActivity I ()V
76 | 76,2,sample.tencent.matrix.trace.TestTraceMainActivity J ()V
77 | 77,8,sample.tencent.matrix.issue.IssuesListActivity ()V
78 | 78,1,sample.tencent.matrix.issue.IssuesListActivity$ViewHolder showIssue (Lcom.tencent.matrix.report.Issue;)V
79 | 79,4,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity onCreate (Landroid.os.Bundle;)V
80 | 80,2,sample.tencent.matrix.trace.TestTraceMainActivity K ()V
81 | 81,1,sample.tencent.matrix.issue.IssuesListActivity$ViewHolder hideIssue ()V
82 | 82,2,sample.tencent.matrix.trace.TestTraceMainActivity L ()V
83 | 83,1,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity$1 onPublish (Ljava.util.List;)V
84 | 84,9,sample.tencent.matrix.sqlitelint.TestSQLiteLintHelper initIssueList (Landroid.content.Context;Ljava.util.Map;)V
85 | 85,4,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity onDestroy ()V
86 | 86,1,sample.tencent.matrix.trace.StartUpContentProvider call (Ljava.lang.String;Ljava.lang.String;Landroid.os.Bundle;)Landroid.os.Bundle;
87 | 87,1,sample.tencent.matrix.sqlitelint.TestDBHelper onCreate (Landroid.database.sqlite.SQLiteDatabase;)V
88 | 88,8,sample.tencent.matrix.trace.StartUpContentProvider ()V
89 | 89,1,sample.tencent.matrix.trace.TestTraceMainActivity stopAppMethodBeat (Landroid.view.View;)V
90 | 90,1,sample.tencent.matrix.sqlitelint.TestDBHelper onUpgrade (Landroid.database.sqlite.SQLiteDatabase;II)V
91 | 91,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity insert ()V
92 | 92,1,sample.tencent.matrix.MainActivity$4 onClick (Landroid.view.View;)V
93 | 93,1,sample.tencent.matrix.MainActivity$1 onClick (Landroid.view.View;)V
94 | 94,1,sample.tencent.matrix.trace.TestTraceMainActivity evilMethod5 (Z)V
95 | 95,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity batchInsert (I)V
96 | 96,1,sample.tencent.matrix.trace.TestTraceMainActivity testInnerSleep ()V
97 | 97,1,sample.tencent.matrix.resource.TestLeakActivity$1 run ()V
98 | 98,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity deleteAll ()V
99 | 99,9,sample.tencent.matrix.sqlitelint.TestSQLiteLintHelper genRandomString (I)Ljava.lang.String;
100 | 100,2,sample.tencent.matrix.trace.TestTraceMainActivity tryHeavyMethod ()V
101 | 101,1,sample.tencent.matrix.MainActivity$3 onClick (Landroid.view.View;)V
102 | 102,1,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity onClick (Landroid.view.View;)V
103 | 103,1,sample.tencent.matrix.MainActivity$5 run ()V
104 | 104,1,sample.tencent.matrix.trace.TestTraceMainActivity onForeground (Z)V
105 | 105,9,sample.tencent.matrix.sqlitelint.TestSQLiteLintHelper getAssetAsString (Landroid.content.Context;Ljava.lang.String;)Ljava.lang.String;
106 | 106,4,sample.tencent.matrix.trace.TestTraceFragmentActivity onCreate (Landroid.os.Bundle;)V
107 | 107,2,sample.tencent.matrix.io.TestIOActivity writeLongSth ()V
108 | 108,1,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity toastStartTest (Ljava.lang.String;)V
109 | 109,4,sample.tencent.matrix.resource.TestLeakActivity onCreate (Landroid.os.Bundle;)V
110 | 110,2,sample.tencent.matrix.trace.TestTraceFragmentActivity loadFragment (Landroid.support.v4.app.Fragment;)V
111 | 111,4,sample.tencent.matrix.resource.TestLeakActivity onStart ()V
112 | 112,4104,sample.tencent.matrix.trace.TestTraceFragmentActivity access$000 (Lsample.tencent.matrix.trace.TestTraceFragmentActivity;Landroid.support.v4.app.Fragment;)V
113 | 113,4,sample.tencent.matrix.resource.TestLeakActivity onRestart ()V
114 | 114,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity doTest ()V
115 | 115,2,sample.tencent.matrix.io.TestIOActivity writeSth ()V
116 | 116,9,sample.tencent.matrix.sqlitelint.TestSQLiteLintHelper convertStreamToString (Ljava.io.InputStream;)Ljava.lang.String;
117 | 117,4,sample.tencent.matrix.resource.TestLeakActivity onDestroy ()V
118 | 118,8,sample.tencent.matrix.resource.TestLeakActivity ()V
119 | 119,1,sample.tencent.matrix.MatrixApplication onCreate ()V
120 | 120,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity startTest ()V
121 | 121,1,sample.tencent.matrix.trace.TestTraceFragmentActivity$2 onClick (Landroid.view.View;)V
122 | 122,9,sample.tencent.matrix.sqlitelint.TestSQLiteLintHelper qualityClose (Ljava.io.Closeable;)V
123 | 123,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity stopTest ()V
124 | 124,2,sample.tencent.matrix.io.TestIOActivity readSth ()V
125 | 125,4,sample.tencent.matrix.trace.TestEnterActivity onCreate (Landroid.os.Bundle;)V
126 | 126,1,sample.tencent.matrix.SplashActivity$1 run ()V
127 | 127,4,sample.tencent.matrix.MainActivity onCreate (Landroid.os.Bundle;)V
128 | 128,2,sample.tencent.matrix.sqlitelint.TestSQLiteLintActivity startDBCreateTest ()V
129 | 129,1,sample.tencent.matrix.trace.TestFpsActivity$3 getView (ILandroid.view.View;Landroid.view.ViewGroup;)Landroid.view.View;
130 | 130,2,sample.tencent.matrix.io.TestIOActivity leakSth ()V
131 | 1048574,1,android.os.Handler dispatchMessage (Landroid.os.Message;)V
132 |
--------------------------------------------------------------------------------
/device/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018-present, Facebook, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (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 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | 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 |
--------------------------------------------------------------------------------
/device/device.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018-present, Facebook, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (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 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | 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 |
18 | import collections
19 | import datetime
20 | import os
21 | import subprocess
22 | import sys
23 | from io import BytesIO
24 |
25 |
26 | # Traces go to the cache/ directory when they are created, then moved into the
27 | # cache/upload/ directory for uploading, and then moved back to cache/ once
28 | # the upload is finished. This exception will get thrown if a trace file was
29 | # found in one place and then moved and thus was not found at a later point
30 | # in time.
31 | class FileMovedException(Exception):
32 | def __init__(self, message):
33 | Exception.__init__(self, message)
34 |
35 | # FileManager#getBaseFolder has the logic for where Profilo traces will exist. For
36 | # now we assume that the traces will exist inside the internal data dir of our
37 | # package, under the cache/ folder.
38 | _PROFILO_DIR = 'cache/'
39 | _TRACE_FILE_EXT = ".log"
40 | _TRACE_FILE_EXPRESSION = '*' + _TRACE_FILE_EXT
41 | _PROFILO_HEADER_START = 'dt\n'.encode("utf-8")
42 |
43 | # -t to order by modified time for a nice default ordering.
44 | _ADB_CMD_BASE = ['adb', 'shell', 'run-as']
45 | _GET_DATA_DIR_FULL_PATH_CMD = ['pwd']
46 | _GET_TRACES_CMD_FIND = ['find', '.', '-name', _TRACE_FILE_EXPRESSION]
47 | _GET_TRACES_CMD_LS = ['ls', '-R', '|', 'grep', '-B', '1', '\.log']
48 | _GET_FILE_MODIFIED_UNIX_TIME_CMD = ['stat', '-c', '%Y']
49 | _GET_FILE_SIZE_CMD = ['stat', '-c', '%s']
50 | # I'd rather use `test -d $dir` but we need a binary to run within `run-as`
51 | _CHECK_PROFILO_DIR_EXISTS_CMD = ['ls', _PROFILO_DIR]
52 | _ADB_EXEC_OUT_CMD_BASE = ['adb', 'exec-out', 'run-as']
53 | _CAT_CMD = ['cat']
54 |
55 | _NO_SUCH_FILE = b'No such file or directory'
56 |
57 |
58 | DeviceTrace = collections.namedtuple('DeviceTrace', ['file_name', 'full_path',
59 | 'modified_time', 'size'])
60 |
61 |
62 | def _get_file_modified_unix_time(package, path):
63 | # ls on Android phones is missing --time-style, so use `stat` to get the
64 | # precise modified time.
65 | command = list(_ADB_CMD_BASE) + [package] \
66 | + list(_GET_FILE_MODIFIED_UNIX_TIME_CMD) + [path]
67 | output = subprocess.Popen(command, stdout=subprocess.PIPE,
68 | stderr=subprocess.PIPE)
69 | o_out, o_err = output.communicate()
70 | if o_err and _NO_SUCH_FILE in o_err:
71 | raise FileMovedException("File {f} was moved".format(f=path))
72 | return int(o_out.strip())
73 |
74 |
75 | def _get_data_dir_full_path(package):
76 | command = list(_ADB_CMD_BASE) + [package] + list(_GET_DATA_DIR_FULL_PATH_CMD)
77 | return subprocess.check_output(command).decode("utf-8").strip()
78 |
79 |
80 | def _is_profilo_trace(gzip_file):
81 | try:
82 | data = gzip_file.read()
83 | if not data.startswith(_PROFILO_HEADER_START):
84 | return False
85 | except IOError:
86 | # Not a gzipped file
87 | return False
88 |
89 | return True
90 |
91 |
92 | def _validate_trace(package, data_dir_path, file_path):
93 | """
94 | 1) If the file is a zip file (not gzip) then this is a multiproc trace,
95 | so unzip it and validate that all the files inside are profilo traces
96 | (skipping the "extra" directory)
97 | 2) If the file is not a zip file, validate that it is a profilo trace
98 |
99 | A file is a "profilo trace" if:
100 |
101 | a) It is a gzipped file
102 | b) It starts with the magic _PROFILO_HEADER_START bytes
103 | """
104 | full_path = "/data/data/{package}/{path}".format(
105 | package=package, path=file_path)
106 | command = list(_ADB_EXEC_OUT_CMD_BASE) + [package] + list(_CAT_CMD) + [full_path]
107 |
108 | output = subprocess.Popen(command, stdout=subprocess.PIPE,
109 | stderr=subprocess.PIPE)
110 | o_out, o_err = output.communicate()
111 |
112 | # I've seen "no such file or directory" errors in cat being thrown to
113 | # STDOUT (in Android devices) and to STDERR in Linux desktops, so I'm
114 | # not going to take any chances and will just check both
115 | if (o_out and _NO_SUCH_FILE in o_out) or \
116 | (o_err and _NO_SUCH_FILE in o_err):
117 | raise FileMovedException("File {f} was moved".format(f=full_path))
118 |
119 | content = o_out
120 |
121 | file_like = BytesIO(content)
122 | # Not Check
123 | # if zipfile.is_zipfile(file_like):
124 | # with zipfile.ZipFile(file_like) as zipped:
125 | # info = zipped.infolist()
126 | # for info_file in info:
127 | # # Ignore *.tnd files
128 | # if info_file.filename.startswith("extra/"):
129 | # continue
130 | # f = zipped.open(info_file)
131 | # gz = gzip.GzipFile(fileobj=BytesIO(f.read()))
132 | # if not _is_profilo_trace(gz):
133 | # return False
134 | # else:
135 | # gz = gzip.GzipFile(fileobj=BytesIO(content))
136 | # if not _is_profilo_trace(gz):
137 | # return False
138 |
139 | return True
140 |
141 |
142 | def _create_trace(package, data_dir_path, file_path):
143 | """
144 | Note: we could pull thet trace ID out of the filename, but this would be
145 | confusing because the ID is sanitized (special chars like '/' replaced)
146 | before being used as part of the filename, so it's likely the real ID
147 | is different.
148 | """
149 |
150 | file_path = file_path.strip()
151 | full_path = os.path.join(data_dir_path, file_path)
152 | full_path = os.path.abspath(full_path)
153 | file_name = os.path.basename(file_path)
154 |
155 | modified_time = \
156 | datetime.datetime.fromtimestamp(_get_file_modified_unix_time(package,
157 | full_path))
158 |
159 | command = list(_ADB_CMD_BASE) + [package] + list(_GET_FILE_SIZE_CMD) + \
160 | [full_path]
161 |
162 | output = subprocess.Popen(command, stdout=subprocess.PIPE,
163 | stderr=subprocess.PIPE)
164 | o_out, o_err = output.communicate()
165 | if o_err and _NO_SUCH_FILE in o_err:
166 | raise FileMovedException("File {f} was moved".format(f=full_path))
167 |
168 | size = int(o_out.strip())
169 |
170 | return DeviceTrace(file_name=file_name, full_path=full_path,
171 | modified_time=modified_time, size=size)
172 |
173 |
174 | def _pull_trace(package, trace):
175 | # Since we're pulling files from internal data (without root), we can't use
176 | # adb pull :( So we just `cat` the file and write it out to a local file
177 | # with the same trace name.
178 | with open(trace.file_name, 'w') as trace_file:
179 | command = list(_ADB_EXEC_OUT_CMD_BASE) + [package] + list(_CAT_CMD) + [trace.full_path]
180 | popen = subprocess.Popen(command, stdout=trace_file)
181 | return popen.wait() == 0
182 |
183 |
184 | def _check_profilo_dir_exists(package):
185 | dev_null = open(os.devnull, 'w')
186 | command = list(_ADB_CMD_BASE) + [package] + list(_CHECK_PROFILO_DIR_EXISTS_CMD)
187 | return subprocess.call(command, stdout=dev_null) == 0
188 |
189 |
190 | def list_traces(package):
191 | if not _check_profilo_dir_exists(package):
192 | print("Profilo directory doesn't exist, looked for", _PROFILO_DIR,
193 | "inside package internal storage", file=sys.stderr)
194 | return []
195 |
196 | data_dir_path = _get_data_dir_full_path(package)
197 | used_ls = False
198 |
199 | try:
200 | command = list(_ADB_CMD_BASE) + [package] + list(_GET_TRACES_CMD_FIND)
201 | trace_files = subprocess.check_output(command).decode("utf-8").split('\n')
202 | trace_files = [x.strip() for x in trace_files]
203 | trace_files = [_f for _f in trace_files if _f]
204 | except subprocess.CalledProcessError as e:
205 | # Some devices don't have "find", so do this with "ls -R"
206 | print(str(e) + " Retrying with ls", file=sys.stderr)
207 | used_ls = True
208 |
209 | if used_ls:
210 | command = list(_ADB_CMD_BASE) + [package] + list(_GET_TRACES_CMD_LS)
211 | trace_files = subprocess.check_output(command).decode("utf-8").split('\n')
212 | trace_files = [x.strip() for x in trace_files]
213 | trace_files = [_f for _f in trace_files if _f]
214 | directory = trace_files.pop(0)[:-1] # Remove trailing ":"
215 | trace_files = ["{d}/{f}".format(d=directory, f=x) for x in trace_files]
216 |
217 | # Due to the generality of the trace file expression, we might get stuff
218 | # that isn't actually a trace. Thus, do some validation.
219 | trace_files = [x for x in trace_files if _validate_trace(package, data_dir_path, x)]
220 | traces = [_create_trace(package, data_dir_path, x) for x in trace_files]
221 | traces = [_f for _f in traces if _f]
222 | return traces
223 |
224 |
225 | def copy_to_host(package, trace):
226 | if _pull_trace(package, trace):
227 | print(trace.file_name)
228 | return(trace.file_name)
229 | else:
230 | print("Error pulling trace {}".format(trace.file_name))
231 | return None
232 |
233 |
234 | def get_traces(package):
235 | while True:
236 | try:
237 | traces = list_traces(package)
238 | break
239 | except FileMovedException as e:
240 | print(str(e) + ". Retrying...", file=sys.stderr)
241 | except Exception as e:
242 | print(str(e) + ". Exiting", file=sys.stderr)
243 | sys.exit(1)
244 | return traces
245 |
246 |
247 | def pull_all_traces(package):
248 | traces = get_traces(package)
249 | for trace in traces:
250 | copy_to_host(package, trace)
251 |
252 |
253 | def pull_n_traces(package, n):
254 | traces = get_traces(package)
255 | traces.sort(key=lambda x: x.modified_time, reverse=True)
256 | for trace in traces[:n]:
257 | copy_to_host(package, trace)
258 |
259 |
260 | def pull_last_trace(package):
261 | traces = get_traces(package)
262 | if not traces:
263 | print("Could not find any traces for package", package, file=sys.stderr)
264 | return None
265 |
266 | last_trace = max(traces, key=lambda x: x.modified_time)
267 |
268 | return copy_to_host(package, last_trace)
269 |
--------------------------------------------------------------------------------
/importer/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinXiaoTao/matrix-trace-processor/99746552e1942d9579427c5de980b9db36eab6e9/importer/__init__.py
--------------------------------------------------------------------------------
/importer/interpreter.py:
--------------------------------------------------------------------------------
1 | class TraceFileInterpreter(object):
2 | def __init__(self, trace_file, symbols=None):
3 | self.trace_file = trace_file
4 | self.symbols = symbols
5 |
6 | def interpret(self):
7 | trace_data = self.trace_file.data
8 | method_index = self.symbols.method_index
9 | parse_trace_data = []
10 | for item in trace_data:
11 | depth = int(item['depth'])
12 | method = method_index[item['method_id']]
13 | if not method:
14 | method = '_%s' % item['method_id']
15 | parse_trace_data.append({
16 | 'depth': depth,
17 | 'method': method,
18 | 'durtime': item['durtime']
19 | })
20 | return parse_trace_data
21 |
--------------------------------------------------------------------------------
/importer/trace_file.py:
--------------------------------------------------------------------------------
1 | class TraceFile(object):
2 |
3 | def __init__(self, data):
4 | super(TraceFile, self).__init__()
5 | self.data = data
6 |
7 | @staticmethod
8 | def from_string(data):
9 | result = []
10 | for item in data:
11 | item = item.replace('\n', '')
12 | result.append({
13 | 'depth': item.split(',')[0],
14 | 'method_id': item.split(',')[1],
15 | 'count': item.split(',')[2],
16 | 'durtime': item.split(',')[3]
17 | })
18 | return TraceFile(result)
19 |
20 | @staticmethod
21 | def from_file(file):
22 | with open(file) as fd:
23 | data = fd.readlines()
24 | return TraceFile.from_string(data)
25 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import os
3 | import sys
4 | from collections import defaultdict
5 |
6 | from device.device import pull_last_trace, pull_all_traces, pull_n_traces
7 | from importer.interpreter import TraceFileInterpreter
8 | from importer.trace_file import TraceFile
9 | from symbols.mapping_symbols import extract_mapping_symbols
10 |
11 |
12 | def pull_traces(args):
13 | if args.last:
14 | pull_last_trace(args.package)
15 | elif args.all:
16 | pull_all_traces(args.package)
17 | else:
18 | pull_n_traces(args.package, args.count)
19 | return
20 |
21 |
22 | def workflow_traces(args):
23 | # Make sure the trace file exists
24 | if not os.path.exists(args.trace):
25 | print(args.trace, "no such file or directory")
26 | sys.exit(2)
27 |
28 | if not os.path.exists(args.methodMapping):
29 | print('{methodMapping}: no such file'.format(methodMapping=args.methodMapping))
30 | sys.exit(2)
31 |
32 | symbols = extract_mapping_symbols(args.methodMapping)
33 | tracefile = TraceFile.from_file(args.trace)
34 | interpreter = TraceFileInterpreter(tracefile, symbols)
35 | trace = interpreter.interpret()
36 |
37 | stacks = defaultdict(int) # [frame] -> int (count)
38 | traversal(trace, stacks)
39 |
40 | # DTrace collapser ignores the first three lines
41 | print("\n\n\n")
42 | for k, v in stacks.items():
43 | for frame in k:
44 | if str(frame).isdigit():
45 | print("_", frame, sep='')
46 | else:
47 | print(frame, sep='')
48 | print(v)
49 | print("\n")
50 |
51 |
52 | def traversal(trace, stacks):
53 | stack = []
54 | index = 0
55 | while index < len(trace):
56 | if len(stack) == 0:
57 | stack.append(trace[index])
58 | else:
59 | cur = trace[index]
60 | last = stack[len(stack) - 1]
61 | depth = last['depth']
62 | if depth < cur['depth']:
63 | stack.append(cur)
64 | else:
65 | result = []
66 | for item in stack:
67 | result.append('%s(%sms)' % (item['method'], item['durtime']))
68 | result.reverse()
69 | stacks[tuple(result)] = 1
70 | while len(stack) > 0 and stack[len(stack) - 1]['depth'] >= cur['depth']:
71 | stack.pop()
72 | stack.append(cur)
73 | index = index + 1
74 | if len(stack) > 0:
75 | result = []
76 | for item in stack:
77 | result.append('%s(%sms)' % (item['method'], item['durtime']))
78 | result.reverse()
79 | stacks[tuple(result)] = 1
80 | return
81 |
82 |
83 | if __name__ == '__main__':
84 | parse = argparse.ArgumentParser(description="Matrix commandline utility!")
85 | subparsers = parse.add_subparsers(help='Supported features')
86 |
87 | pull_traces_parser = subparsers.add_parser('pull_traces', help='Pull traces from the device')
88 | pull_traces_parser.set_defaults(func=pull_traces)
89 | pull_traces_group = pull_traces_parser.add_mutually_exclusive_group(required=True)
90 | pull_traces_group.add_argument('--last', action='store_true', help='Pull only the last trace')
91 | pull_traces_group.add_argument("--all", action="store_true", help="Pull all existing traces")
92 | pull_traces_group.add_argument("--count", type=int, help="Pull the last COUNT traces")
93 | pull_traces_parser.add_argument('package', type=str, help='Specify the package name using Matrix, e.g. com.foo.bar')
94 |
95 | workflow_traces_parser = subparsers.add_parser('workflow_traces', help='Processing analysis traces')
96 | workflow_traces_parser.add_argument('trace', type=str, help='Path to downloaded trace')
97 | workflow_traces_parser.add_argument('methodMapping', type=str, help='methodMapping')
98 | workflow_traces_parser.set_defaults(func=workflow_traces)
99 |
100 | args = parse.parse_args()
101 | args.func(args)
102 |
--------------------------------------------------------------------------------
/symbols/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018-present, Facebook, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (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 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | 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 |
--------------------------------------------------------------------------------
/symbols/apk_symbols.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright 2018-present, Facebook, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (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 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | 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 |
18 | import struct
19 | import sys
20 | import zipfile
21 | import tempfile
22 | from collections import namedtuple
23 |
24 | DEX_FILE_VERSION_MAX = 38
25 |
26 |
27 | def parse_dex_id(signature):
28 | """Take first 4 bytes of the Dex signature as Dex Id """
29 | return struct.unpack(""
227 | ...
228 | },
229 | "method_index" : {
230 | ((method_id << 32) | dex_id) : ""
231 | ...
232 | }
233 | }
234 | """
235 | class_index = {}
236 | method_index = {}
237 |
238 | with zipfile.ZipFile(apk_path) as apk_file:
239 | tempdir = tempfile.mkdtemp()
240 | assert("classes.dex" in apk_file.namelist())
241 | index = 1
242 | dex_file_format = "classes{}.dex"
243 | dex_file = dex_file_format.format("")
244 | while dex_file in apk_file.namelist():
245 | dex_path = apk_file.extract(dex_file, tempdir)
246 | with open(dex_path, 'rb') as dex_file:
247 | dex = Dex(dex_file)
248 | class_index.update(dex.get_classes_map())
249 | method_index.update(dex.get_methods_map())
250 | index += 1
251 | dex_file = dex_file_format.format(index)
252 |
253 | return namedtuple('ApkSymbols', ['class_index', 'method_index'])(class_index, method_index)
254 |
255 |
256 | if __name__ == '__main__':
257 | import json
258 | apk_path = sys.argv[1]
259 | symbols = extract_apk_symbols(apk_path)
260 | print(json.dumps({"class_index": symbols.class_index, "method_index": symbols.method_index, }))
261 |
--------------------------------------------------------------------------------
/symbols/mapping_symbols.py:
--------------------------------------------------------------------------------
1 | from collections import namedtuple
2 |
3 | ACC_PUBLIC = 1
4 | ACC_PRIVATE = 2
5 | ACC_PROTECTED = 4
6 | ACC_STATIC = 8
7 | ACC_FINAL = 16
8 | ACC_SUPER = 32
9 | ACC_SYNCHRONIZED = 32
10 | ACC_VOLATILE = 64
11 | ACC_BRIDGE = 64
12 | ACC_VARARGS = 128
13 | ACC_TRANSIENT = 128
14 | ACC_NATIVE = 256
15 | ACC_ERFACE = 512
16 | ACC_ABSTRACT = 1024
17 | ACC_STRICT = 2048
18 | ACC_SYNTHETIC = 4096
19 | ACC_ANNOTATION = 8192
20 | ACC_ENUM = 16384
21 | ACC_MANDATED = 32768
22 | ACC_DEPRECATED = 131072
23 |
24 |
25 | def format_access_flag(access_flag):
26 | result = ''
27 | if access_flag & ACC_PUBLIC:
28 | result += 'public '
29 | if access_flag & ACC_PRIVATE:
30 | result += 'private '
31 | if access_flag & ACC_PROTECTED:
32 | result += 'protected '
33 | if access_flag & ACC_STATIC:
34 | result += 'static '
35 | if access_flag & ACC_FINAL:
36 | result += 'final '
37 | if access_flag & ACC_SUPER:
38 | result += 'super '
39 | if access_flag & ACC_SYNCHRONIZED:
40 | result += 'synchronized '
41 | if access_flag & ACC_VOLATILE:
42 | result += 'volatile '
43 | if access_flag & ACC_BRIDGE:
44 | result += 'bridge '
45 | if access_flag & ACC_NATIVE:
46 | result += 'native '
47 | if access_flag & ACC_ABSTRACT:
48 | result += 'abstract'
49 | return result
50 |
51 |
52 | def extract_mapping_symbols(mapping):
53 | method_index = {}
54 | with open(mapping) as mapping_file:
55 | mapping_content = mapping_file.readlines()
56 | for symbol in mapping_content:
57 | symbol = symbol.replace('\n', '')
58 | method_id = symbol.split(',')[0]
59 | method_info = symbol.split(',')[2]
60 | method_index[method_id] = method_info
61 | return namedtuple('MappingSymbols', ['method_index'])(method_index)
62 |
--------------------------------------------------------------------------------