• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Native heap profiler
2
3NOTE: **heapprofd requires Android 10 or higher**
4
5Heapprofd is a tool that tracks native heap allocations & deallocations of an
6Android process within a given time period. The resulting profile can be used to
7attribute memory usage to particular call-stacks, supporting a mix of both
8native and java code. The tool can be used by Android platform and app
9developers to investigate memory issues.
10
11On debug Android builds, you can profile all apps and most system services.
12On "user" builds, you can only use it on apps with the debuggable or
13profileable manifest flag.
14
15## Quickstart
16
17See the [Memory Guide](/docs/case-studies/memory.md#heapprofd) for getting
18started with heapprofd.
19
20## UI
21
22Dumps from heapprofd are shown as flamegraphs in the UI after clicking on the
23diamond. Each diamond corresponds to a snapshot of the allocations and
24callstacks collected at that point in time.
25
26![heapprofd snapshots in the UI tracks](/docs/images/profile-diamond.png)
27
28![heapprofd flamegraph](/docs/images/native-flamegraph.png)
29
30## SQL
31
32Information about callstacks is written to the following tables:
33
34* [`stack_profile_mapping`](/docs/analysis/sql-tables.autogen#stack_profile_mapping)
35* [`stack_profile_frame`](/docs/analysis/sql-tables.autogen#stack_profile_frame)
36* [`stack_profile_callsite`](/docs/analysis/sql-tables.autogen#stack_profile_callsite)
37
38The allocations themselves are written to
39[`heap_profile_allocation`](/docs/analysis/sql-tables.autogen#heap_profile_allocation).
40
41Offline symbolization data is stored in
42[`stack_profile_symbol`](/docs/analysis/sql-tables.autogen#stack_profile_symbol).
43
44See [Example Queries](#heapprofd-example-queries) for example SQL queries.
45
46## Recording
47
48Heapprofd can be configured and started in three ways.
49
50#### Manual configuration
51
52This requires manually setting the
53[HeapprofdConfig](/docs/reference/trace-config-proto.autogen#HeapprofdConfig)
54section of the trace config. The only benefit of doing so is that in this way
55heap profiling can be enabled alongside any other tracing data sources.
56
57#### Using the tools/heap_profile script (recommended)
58
59You can use the `tools/heap_profile` script. If you are having trouble
60make sure you are using the
61[latest version](
62https://raw.githubusercontent.com/google/perfetto/master/tools/heap_profile).
63
64You can target processes either by name (`-n com.example.myapp`) or by PID
65(`-p 1234`). In the first case, the heap profile will be initiated on both on
66already-running processes that match the package name and new processes launched
67after the profiling session is started.
68For the full arguments list see the
69[heap_profile cmdline reference page](/docs/reference/heap_profile-cli).
70
71#### Using the Recording page of Perfetto UI
72
73You can also use the [Perfetto UI](https://ui.perfetto.dev/#!/record/memory)
74to record heapprofd profiles. Tick "Heap profiling" in the trace configuration,
75enter the processes you want to target, click "Add Device" to pair your phone,
76and record profiles straight from your browser. This is also possible on
77Windows.
78
79## Viewing the data
80
81The resulting profile proto contains four views on the data
82
83* **space**: how many bytes were allocated but not freed at this callstack the
84  moment the dump was created.
85* **alloc\_space**: how many bytes were allocated (including ones freed at the
86  moment of the dump) at this callstack
87* **objects**: how many allocations without matching frees were done at this
88  callstack.
89* **alloc\_objects**: how many allocations (including ones with matching frees)
90  were done at this callstack.
91
92_(Googlers: You can also open the gzipped protos using http://pprof/)_
93
94TIP: you might want to put `libart.so` as a "Hide regex" when profiling apps.
95
96You can use the [Perfetto UI](https://ui.perfetto.dev) to visualize heap dumps.
97Upload the `raw-trace` file in your output directory. You will see all heap
98dumps as diamonds on the timeline, click any of them to get a flamegraph.
99
100Alternatively [Speedscope](https://speedscope.app) can be used to visualize
101the gzipped protos, but will only show the space view.
102
103TIP: Click Left Heavy on the top left for a good visualization.
104
105## Sampling interval
106
107Heapprofd samples heap allocations by hooking calls to malloc/free and C++'s
108operator new/delete. Given a sampling interval of n bytes, one allocation is
109sampled, on average, every n bytes allocated. This allows to reduce the
110performance impact on the target process. The default sampling rate
111is 4096 bytes.
112
113The easiest way to reason about this is to imagine the memory allocations as a
114stream of one byte allocations. From this stream, every byte has a 1/n
115probability of being selected as a sample, and the corresponding callstack
116gets attributed the complete n bytes. For more accuracy, allocations larger than
117the sampling interval bypass the sampling logic and are recorded with their true
118size.
119See the [heapprofd Sampling](/docs/design-docs/heapprofd-sampling) document for
120details.
121
122## Startup profiling
123
124When specifying a target process name (as opposite to the PID), new processes
125matching that name are profiled from their startup. The resulting profile will
126contain all allocations done between the start of the process and the end
127of the profiling session.
128
129On Android, Java apps are usually not exec()-ed from scratch, but fork()-ed from
130the [zygote], which then specializes into the desired app. If the app's name
131matches a name specified in the profiling session, profiling will be enabled as
132part of the zygote specialization. The resulting profile contains all
133allocations done between that point in zygote specialization and the end of the
134profiling session. Some allocations done early in the specialization process are
135not accounted for.
136
137At the trace proto level, the resulting [ProfilePacket] will have the
138`from_startup` field set to true in the corresponding `ProcessHeapSamples`
139message. This is not surfaced in the converted pprof compatible proto.
140
141[ProfilePacket]: /docs/reference/trace-packet-proto.autogen#ProfilePacket
142[zygote]: https://developer.android.com/topic/performance/memory-overview#SharingRAM
143
144## Runtime profiling
145
146When a profiling session is started, all matching processes (by name or PID)
147are enumerated and are signalled to request profiling. Profiling isn't actually
148enabled until a few hundred milliseconds after the next allocation that is
149done by the application. If the application is idle when profiling is
150requested, and then does a burst of allocations, these may be missed.
151
152The resulting profile will contain all allocations done between when profiling
153is enabled, and the end of the profiling session.
154
155The resulting [ProfilePacket] will have `from_startup` set to false in the
156corresponding `ProcessHeapSamples` message. This does not get surfaced in the
157converted pprof compatible proto.
158
159## Concurrent profiling sessions
160
161If multiple sessions name the same target process (either by name or PID),
162only the first relevant session will profile the process. The other sessions
163will report that the process had already been profiled when converting to
164the pprof compatible proto.
165
166If you see this message but do not expect any other sessions, run
167
168```shell
169adb shell killall perfetto
170```
171
172to stop any concurrent sessions that may be running.
173
174The resulting [ProfilePacket] will have `rejected_concurrent` set  to true in
175otherwise empty corresponding `ProcessHeapSamples` message. This does not get
176surfaced in the converted pprof compatible proto.
177
178## {#heapprofd-targets} Target processes
179
180Depending on the build of Android that heapprofd is run on, some processes
181are not be eligible to be profiled.
182
183On _user_ (i.e. production, non-rootable) builds, only Java applications with
184either the profileable or the debuggable manifest flag set can be profiled.
185Profiling requests for non-profileable/debuggable processes will result in an
186empty profile.
187
188On userdebug builds, all processes except for a small set of critical
189services can be profiled (to find the set of disallowed targets, look for
190`never_profile_heap` in [heapprofd.te](
191https://cs.android.com/android/platform/superproject/+/master:system/sepolicy/private/heapprofd.te?q=never_profile_heap).
192This restriction can be lifted by disabling SELinux by running
193`adb shell su root setenforce 0` or by passing `--disable-selinux` to the
194`heap_profile` script.
195
196<center>
197
198|                         | userdebug setenforce 0 | userdebug | user |
199|-------------------------|:----------------------:|:---------:|:----:|
200| critical native service |            Y           |     N     |  N   |
201| native service          |            Y           |     Y     |  N   |
202| app                     |            Y           |     Y     |  N   |
203| profileable app         |            Y           |     Y     |  Y   |
204| debuggable app          |            Y           |     Y     |  Y   |
205
206</center>
207
208To mark an app as profileable, put `<profileable android:shell="true"/>` into
209the `<application>` section of the app manifest.
210
211```xml
212<manifest ...>
213    <application>
214        <profileable android:shell="true"/>
215        ...
216    </application>
217</manifest>
218```
219
220## DEDUPED frames
221
222If the name of a Java method includes `[DEDUPED]`, this means that multiple
223methods share the same code. ART only stores the name of a single one in its
224metadata, which is displayed here. This is not necessarily the one that was
225called.
226
227## Triggering heap snapshots on demand
228
229Heap snapshot are recorded into the trace either at regular time intervals, if
230using the `continuous_dump_config` field, or at the end of the session.
231
232You can also trigger a snapshot of all currently profiled processes by running
233`adb shell killall -USR1 heapprofd`. This can be useful in lab tests for
234recording the current memory usage of the target in a specific state.
235
236This dump will show up in addition to the dump at the end of the profile that is
237always produced. You can create multiple of these dumps, and they will be
238enumerated in the output directory.
239
240## Symbolization
241
242### Set up llvm-symbolizer
243
244You only need to do this once.
245
246To use symbolization, your system must have llvm-symbolizer installed and
247accessible from `$PATH` as `llvm-symbolizer`. On Debian, you can install it
248using `sudo apt install llvm-9`.
249This will create `/usr/bin/llvm-symbolizer-9`. Symlink that to somewhere in
250your `$PATH` as `llvm-symbolizer`.
251
252For instance, `ln -s /usr/bin/llvm-symbolizer-9 ~/bin/llvm-symbolizer`, and
253add `~/bin` to your path (or run the commands below with `PATH=~/bin:$PATH`
254prefixed).
255
256### Symbolize your profile
257
258If the profiled binary or libraries do not have symbol names, you can
259symbolize profiles offline. Even if they do, you might want to symbolize in
260order to get inlined function and line number information. All tools
261(traceconv, trace_processor_shell, the heap_profile script) support specifying
262the `PERFETTO_BINARY_PATH` as an environment variable.
263
264```
265PERFETTO_BINARY_PATH=somedir tools/heap_profile --name ${NAME}
266```
267
268You can persist symbols for a trace by running
269`PERFETTO_BINARY_PATH=somedir tools/traceconv symbolize raw-trace > symbols`.
270You can then concatenate the symbols to the trace (
271`cat raw-trace symbols > symbolized-trace`) and the symbols will part of
272`symbolized-trace`. The `tools/heap_profile` script will also generate this
273file in your output directory, if `PERFETTO_BINARY_PATH` is used.
274
275The symbol file is the first with matching Build ID in the following order:
276
2771. absolute path of library file relative to binary path.
2782. absolute path of library file relative to binary path, but with base.apk!
279    removed from filename.
2803. basename of library file relative to binary path.
2814. basename of library file relative to binary path, but with base.apk!
282    removed from filename.
2835. in the subdirectory .build-id: the first two hex digits of the build-id
284    as subdirectory, then the rest of the hex digits, with ".debug" appended.
285    See
286    https://fedoraproject.org/wiki/RolandMcGrath/BuildID#Find_files_by_build_ID
287
288For example, "/system/lib/base.apk!foo.so" with build id abcd1234,
289is looked for at:
290
2911. $PERFETTO_BINARY_PATH/system/lib/base.apk!foo.so
2922. $PERFETTO_BINARY_PATH/system/lib/foo.so
2933. $PERFETTO_BINARY_PATH/base.apk!foo.so
2944. $PERFETTO_BINARY_PATH/foo.so
2955. $PERFETTO_BINARY_PATH/.build-id/ab/cd1234.debug
296
297Alternatively, you can set the `PERFETTO_SYMBOLIZER_MODE` environment variable
298to `index`, and the symbolizer will recursively search the given directory for
299an ELF file with the given build id. This way, you will not have to worry
300about correct filenames.
301
302## Deobfuscation
303
304If your profile contains obfuscated Java methods (like `fsd.a`), you can
305provide a deobfuscation map to turn them back into human readable.
306To do so, use the `PERFETTO_PROGUARD_MAP` environment variable, using the
307format `packagename=filename[:packagename=filename...]`, e.g.
308`PERFETTO_PROGUARD_MAP=com.example.pkg1=foo.txt:com.example.pkg2=bar.txt`.
309All tools
310(traceconv, trace_processor_shell, the heap_profile script) support specifying
311the `PERFETTO_PROGUARD_MAP` as an environment variable.
312
313You can get a deobfuscation map for your trace using
314`tools/traceconv deobfuscate`. Then concatenate the resulting file to your
315trace to get a deobfuscated version of it.
316
317```
318PERFETTO_PROGUARD_MAP=com.example.pkg tools/traceconv deobfuscate ${TRACE} > deobfuscation_map
319cat ${TRACE} deobfuscation_map > deobfuscated_trace
320```
321
322## Troubleshooting
323
324### Buffer overrun
325
326If the rate of allocations is too high for heapprofd to keep up, the profiling
327session will end early due to a buffer overrun. If the buffer overrun is
328caused by a transient spike in allocations, increasing the shared memory buffer
329size (passing `--shmem-size` to `tools/heap_profile`) can resolve the issue.
330Otherwise the sampling interval can be increased (at the expense of lower
331accuracy in the resulting profile) by passing `--interval=16000` or higher.
332
333### Profile is empty
334
335Check whether your target process is eligible to be profiled by consulting
336[Target processes](#heapprofd-targets) above.
337
338Also check the [Known Issues](#known-issues).
339
340### Implausible callstacks
341
342If you see a callstack that seems to impossible from looking at the code, make
343sure no [DEDUPED frames](#deduped-frames) are involved.
344
345Also, if your code is linked using _Identical Code Folding_
346(ICF), i.e. passing `-Wl,--icf=...` to the linker, most trivial functions, often
347constructors and destructors, can be aliased to binary-equivalent operators
348of completely unrelated classes.
349
350### Symbolization: Could not find library
351
352When symbolizing a profile, you might come across messages like this:
353
354```bash
355Could not find /data/app/invalid.app-wFgo3GRaod02wSvPZQ==/lib/arm64/somelib.so
356(Build ID: 44b7138abd5957b8d0a56ce86216d478).
357```
358
359Check whether your library (in this example somelib.so) exists in
360`PERFETTO_BINARY_PATH`. Then compare the Build ID to the one in your
361symbol file, which you can get by running
362`readelf -n /path/in/binary/path/somelib.so`. If it does not match, the
363symbolized file has a different version than the one on device, and cannot
364be used for symbolization.
365If it does, try moving somelib.so to the root of `PERFETTO_BINARY_PATH` and
366try again.
367
368### Only one frame shown
369If you only see a single frame for functions in a specific library, make sure
370that the library has unwind information. We need one of
371
372* `.gnu_debugdata`
373* `.eh_frame` (+ preferably `.eh_frame_hdr`)
374* `.debug_frame`.
375
376Frame-pointer unwinding is *not supported*.
377
378To check if an ELF file has any of those, run
379
380```console
381$ readelf -S file.so | grep "gnu_debugdata\|eh_frame\|debug_frame"
382  [12] .eh_frame_hdr     PROGBITS         000000000000c2b0  0000c2b0
383  [13] .eh_frame         PROGBITS         0000000000011000  00011000
384  [24] .gnu_debugdata    PROGBITS         0000000000000000  000f7292
385```
386
387If this does not show one or more of the sections, change your build system
388to not strip them.
389
390## (non-Android) Linux support
391
392NOTE: Do not use this for production purposes.
393
394You can use a standalone library to profile memory allocations on Linux.
395First [build Perfetto](/docs/contributing/build-instructions.md). You only need
396to do this once.
397
398```
399tools/build_all_configs.py
400ninja -C out/linux_clang_release
401```
402
403Then, run traced
404
405```
406out/linux_clang_release/traced
407```
408
409Start the profile (e.g. targeting trace_processor_shell)
410
411```
412tools/heap_profile -n trace_processor_shell --print-config  | \
413out/linux_clang_release/perfetto \
414  -c - --txt \
415  -o ~/heapprofd-trace
416```
417
418Finally, run your target (e.g. trace_processor_shell) with LD_PRELOAD
419
420```
421LD_PRELOAD=out/linux_clang_release/libheapprofd_glibc_preload.so out/linux_clang_release/trace_processor_shell <trace>
422```
423
424Then, Ctrl-C the Perfetto invocation and upload ~/heapprofd-trace to the
425[Perfetto UI](https://ui.perfetto.dev).
426
427NOTE: by default, heapprofd lazily initalizes to avoid blocking your program's
428main thread. However, if your program makes memory allocations on startup,
429these can be missed. To avoid this from happening, set the enironment variable
430`PERFETTO_HEAPPROFD_BLOCKING_INIT=1`; on the first malloc, your program will
431be blocked until heapprofd initializes fully but means every allocation will
432be correctly tracked.
433
434## Known Issues
435
436### {#known-issues-android11} Android 11
437
438* 32-bit programs cannot be targeted on 64-bit devices.
439* Setting `sampling_interval_bytes` to 0 crashes the target process.
440  This is an invalid config that should be rejected instead.
441* For startup profiles, some frame names might be missing. This will be
442  resolved in Android 12.
443* `Failed to send control socket byte.` is displayed in logcat at the end of
444  every profile. This is benign.
445* The object count may be incorrect in `dump_at_max` profiles.
446* Choosing a low shared memory buffer size and `block_client` mode might
447  lock up the target process.
448
449### {#known-issues-android10} Android 10
450* Function names in libraries with load bias might be incorrect. Use
451  [offline symbolization](#symbolization) to resolve this issue.
452* For startup profiles, some frame names might be missing. This will be
453  resolved in Android 12.
454* 32-bit programs cannot be targeted on 64-bit devices.
455* x86 / x86_64 platforms are not supported. This includes the Android
456_Cuttlefish_.
457  emulator.
458* On ARM32, the bottom-most frame is always `ERROR 2`. This is harmless and
459  the callstacks are still complete.
460* If heapprofd is run standalone (by running `heapprofd` in a root shell, rather
461  than through init), `/dev/socket/heapprofd` get assigned an incorrect SELinux
462  domain. You will not be able to profile any processes unless you disable
463  SELinux enforcement.
464  Run `restorecon /dev/socket/heapprofd` in a root shell to resolve.
465* Using `vfork(2)` or `clone(2)` with `CLONE_VM` and allocating / freeing
466  memory in the child process will prematurely end the profile.
467  `java.lang.Runtime.exec` does this, calling it will prematurely end
468  the profile. Note that this is in violation of the POSIX standard.
469* Setting `sampling_interval_bytes` to 0 crashes the target process.
470  This is an invalid config that should be rejected instead.
471* `Failed to send control socket byte.` is displayed in logcat at the end of
472  every profile. This is benign.
473* The object count may be incorrect in `dump_at_max` profiles.
474* Choosing a low shared memory buffer size and `block_client` mode might
475  lock up the target process.
476
477## Heapprofd vs malloc_info() vs RSS
478
479When using heapprofd and interpreting results, it is important to know the
480precise meaning of the different memory metrics that can be obtained from the
481operating system.
482
483**heapprofd** gives you the number of bytes the target program
484requested from the default C/C++ allocator. If you are profiling a Java app from
485startup, allocations that happen early in the application's initialization will
486not be visible to heapprofd. Native services that do not fork from the Zygote
487are not affected by this.
488
489**malloc\_info** is a libc function that gives you information about the
490allocator. This can be triggered on userdebug builds by using
491`am dumpheap -m <PID> /data/local/tmp/heap.txt`. This will in general be more
492than the memory seen by heapprofd, depending on the allocator not all memory
493is immediately freed. In particular, jemalloc retains some freed memory in
494thread caches.
495
496**Heap RSS** is the amount of memory requested from the operating system by the
497allocator. This is larger than the previous two numbers because memory can only
498be obtained in page size chunks, and fragmentation causes some of that memory to
499be wasted. This can be obtained by running `adb shell dumpsys meminfo <PID>` and
500looking at the "Private Dirty" column.
501RSS can also end up being smaller than the other two if the device kernel uses
502memory compression (ZRAM, enabled by default on recent versions of android) and
503the memory of the process get swapped out onto ZRAM.
504
505|                     | heapprofd         | malloc\_info | RSS |
506|---------------------|:-----------------:|:------------:|:---:|
507| from native startup |          x        |      x       |  x  |
508| after zygote init   |          x        |      x       |  x  |
509| before zygote init  |                   |      x       |  x  |
510| thread caches       |                   |      x       |  x  |
511| fragmentation       |                   |              |  x  |
512
513If you observe high RSS or malloc\_info metrics but heapprofd does not match,
514you might be hitting some pathological fragmentation problem in the allocator.
515
516## Convert to pprof
517
518You can use [traceconv](/docs/quickstart/traceconv.md) to convert the heap dumps
519in a trace into the [pprof](https://github.com/google/pprof) format. These can
520then be viewed using the pprof CLI or a UI (e.g. Speedscope, or Google-internal
521pprof/).
522
523```bash
524tools/traceconv profile /tmp/profile
525```
526
527This will create a directory in `/tmp/` containing the heap dumps. Run:
528
529```bash
530gzip /tmp/heap_profile-XXXXXX/*.pb
531```
532
533to get gzipped protos, which tools handling pprof profile protos expect.
534
535## {#heapprofd-example-queries} Example SQL Queries
536
537We can get the callstacks that allocated using an SQL Query in the
538Trace Processor. For each frame, we get one row for the number of allocated
539bytes, where `count` and `size` is positive, and, if any of them were already
540freed, another line with negative `count` and `size`. The sum of those gets us
541the `space` view.
542
543```sql
544select a.callsite_id, a.ts, a.upid, f.name, f.rel_pc, m.build_id, m.name as mapping_name,
545        sum(a.size) as space_size, sum(a.count) as space_count
546      from heap_profile_allocation a join
547           stack_profile_callsite c ON (a.callsite_id = c.id) join
548           stack_profile_frame f ON (c.frame_id = f.id) join
549           stack_profile_mapping m ON (f.mapping = m.id)
550      group by 1, 2, 3, 4, 5, 6, 7 order by space_size desc;
551```
552
553| callsite_id | ts | upid | name | rel_pc | build_id | mapping_name | space_size | space_count |
554|-------------|----|------|-------|-----------|------|--------|----------|------|
555|6660|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |106496|4|
556|192 |5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |26624 |1|
557|1421|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |26624 |1|
558|1537|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |26624 |1|
559|8843|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |26424 |1|
560|8618|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |24576 |4|
561|3750|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |12288 |1|
562|2820|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |8192  |2|
563|3788|5|1| malloc |244716| 8126fd.. | /apex/com.android.runtime/lib64/bionic/libc.so |8192  |2|
564
565We can see all the functions are "malloc" and "realloc", which is not terribly
566informative. Usually we are interested in the _cumulative_ bytes allocated in
567a function (otherwise, we will always only see malloc / realloc). Chasing the
568parent_id of a callsite (not shown in this table) recursively is very hard in
569SQL.
570
571There is an **experimental** table that surfaces this information. The **API is
572subject to change**.
573
574```sql
575select name, map_name, cumulative_size
576       from experimental_flamegraph
577       where ts = 8300973884377
578            and upid = 1
579            and profile_type = 'native'
580       order by abs(cumulative_size) desc;
581```
582
583| name | map_name | cumulative_size |
584|------|----------|----------------|
585|__start_thread|/apex/com.android.runtime/lib64/bionic/libc.so|392608|
586|_ZL15__pthread_startPv|/apex/com.android.runtime/lib64/bionic/libc.so|392608|
587|_ZN13thread_data_t10trampolineEPKS|/system/lib64/libutils.so|199496|
588|_ZN7android14AndroidRuntime15javaThreadShellEPv|/system/lib64/libandroid_runtime.so|199496|
589|_ZN7android6Thread11_threadLoopEPv|/system/lib64/libutils.so|199496|
590|_ZN3art6Thread14CreateCallbackEPv|/apex/com.android.art/lib64/libart.so|193112|
591|_ZN3art35InvokeVirtualOrInterface...|/apex/com.android.art/lib64/libart.so|193112|
592|_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc|/apex/com.android.art/lib64/libart.so|193112|
593|art_quick_invoke_stub|/apex/com.android.art/lib64/libart.so|193112|
594