├── .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 | ![demo](https://raw.githubusercontent.com/LinXiaoTao/matrix-trace-processor/master/demo/1581129760409.png) 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 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 367 | 368 | Flame Graph 369 | 370 | Reset Zoom 371 | Search 372 | ic 373 | 374 | 375 | 376 | sample.tencent.matrix.trace.TestTraceMainActivity I ()V(21ms) (1 samples, 12.50%) 377 | sample.tencent.mat.. 378 | 379 | 380 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms) (8 samples, 100.00%) 381 | android.os.Handler dispatchMessage (Landroid.os.Message:)V(11239ms) 382 | 383 | 384 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms) (8 samples, 100.00%) 385 | sample.tencent.matrix.trace.TestTraceMainActivity A ()V(11237ms) 386 | 387 | 388 | sample.tencent.matrix.trace.TestTraceMainActivity D ()V(16ms) (1 samples, 12.50%) 389 | sample.tencent.mat.. 390 | 391 | 392 | sample.tencent.matrix.trace.TestTraceMainActivity G ()V(20ms) (1 samples, 12.50%) 393 | sample.tencent.mat.. 394 | 395 | 396 | sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms) (4 samples, 50.00%) 397 | sample.tencent.matrix.trace.TestTraceMainActivity B ()V(381ms) 398 | 399 | 400 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms) (8 samples, 100.00%) 401 | sample.tencent.matrix.trace.TestTraceMainActivity testJankiess (Landroid.view.View:)V(11237ms) 402 | 403 | 404 | sample.tencent.matrix.trace.TestTraceMainActivity E ()V(15ms) (1 samples, 12.50%) 405 | sample.tencent.mat.. 406 | 407 | 408 | sample.tencent.matrix.trace.TestTraceMainActivity K ()V(11ms) (1 samples, 12.50%) 409 | sample.tencent.mat.. 410 | 411 | 412 | sample.tencent.matrix.trace.TestTraceMainActivity F ()V(21ms) (1 samples, 12.50%) 413 | sample.tencent.mat.. 414 | 415 | 416 | all (8 samples, 100%) 417 | 418 | 419 | 420 | sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms) (3 samples, 37.50%) 421 | sample.tencent.matrix.trace.TestTraceMainActivity H ()V(57ms) 422 | 423 | 424 | sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms) (3 samples, 37.50%) 425 | sample.tencent.matrix.trace.TestTraceMainActivity C ()V(160ms) 426 | 427 | 428 | sample.tencent.matrix.trace.TestTraceMainActivity L ()V(10001ms) (1 samples, 12.50%) 429 | sample.tencent.mat.. 430 | 431 | 432 | sample.tencent.matrix.trace.TestTraceMainActivity J ()V(5ms) (1 samples, 12.50%) 433 | sample.tencent.mat.. 434 | 435 | 436 | 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 | --------------------------------------------------------------------------------