Update NDK prebuilts to build 7221526.

Taken from branch aosp-simpleperf-release.

Bug: 181075274
Test: run test/test.py on different hosts and android versions.

Change-Id: I29d12ba9cffd13dcb04dbcba09f2c5be29b522c4
diff --git a/bin/android/arm/simpleperf b/bin/android/arm/simpleperf
index 2a0c7c2..044f391 100755
--- a/bin/android/arm/simpleperf
+++ b/bin/android/arm/simpleperf
Binary files differ
diff --git a/bin/android/arm64/simpleperf b/bin/android/arm64/simpleperf
index 83bb427..b2c583a 100755
--- a/bin/android/arm64/simpleperf
+++ b/bin/android/arm64/simpleperf
Binary files differ
diff --git a/bin/android/x86/simpleperf b/bin/android/x86/simpleperf
index a8cc8c6..b2df399 100755
--- a/bin/android/x86/simpleperf
+++ b/bin/android/x86/simpleperf
Binary files differ
diff --git a/bin/android/x86_64/simpleperf b/bin/android/x86_64/simpleperf
index 30ad0fd..8c9d345 100755
--- a/bin/android/x86_64/simpleperf
+++ b/bin/android/x86_64/simpleperf
Binary files differ
diff --git a/bin/darwin/x86_64/libsimpleperf_report.dylib b/bin/darwin/x86_64/libsimpleperf_report.dylib
index e0e5d8f..4f3ebb2 100755
--- a/bin/darwin/x86_64/libsimpleperf_report.dylib
+++ b/bin/darwin/x86_64/libsimpleperf_report.dylib
Binary files differ
diff --git a/bin/darwin/x86_64/simpleperf b/bin/darwin/x86_64/simpleperf
index f304795..41d7647 100755
--- a/bin/darwin/x86_64/simpleperf
+++ b/bin/darwin/x86_64/simpleperf
Binary files differ
diff --git a/bin/linux/x86_64/libsimpleperf_report.so b/bin/linux/x86_64/libsimpleperf_report.so
index f050a26..be21e1c 100755
--- a/bin/linux/x86_64/libsimpleperf_report.so
+++ b/bin/linux/x86_64/libsimpleperf_report.so
Binary files differ
diff --git a/bin/linux/x86_64/simpleperf b/bin/linux/x86_64/simpleperf
index 113c7c2..eaafc3c 100755
--- a/bin/linux/x86_64/simpleperf
+++ b/bin/linux/x86_64/simpleperf
Binary files differ
diff --git a/bin/windows/x86/libsimpleperf_report.dll b/bin/windows/x86/libsimpleperf_report.dll
deleted file mode 100755
index 3f5bea7..0000000
--- a/bin/windows/x86/libsimpleperf_report.dll
+++ /dev/null
Binary files differ
diff --git a/bin/windows/x86/libwinpthread-1.dll b/bin/windows/x86/libwinpthread-1.dll
deleted file mode 100755
index ed00b46..0000000
--- a/bin/windows/x86/libwinpthread-1.dll
+++ /dev/null
Binary files differ
diff --git a/bin/windows/x86/simpleperf.exe b/bin/windows/x86/simpleperf.exe
deleted file mode 100755
index 4e899cb..0000000
--- a/bin/windows/x86/simpleperf.exe
+++ /dev/null
Binary files differ
diff --git a/bin/windows/x86_64/libsimpleperf_report.dll b/bin/windows/x86_64/libsimpleperf_report.dll
index 6d644d2..580ef90 100755
--- a/bin/windows/x86_64/libsimpleperf_report.dll
+++ b/bin/windows/x86_64/libsimpleperf_report.dll
Binary files differ
diff --git a/bin/windows/x86_64/simpleperf.exe b/bin/windows/x86_64/simpleperf.exe
index 052b435..47a3d2d 100755
--- a/bin/windows/x86_64/simpleperf.exe
+++ b/bin/windows/x86_64/simpleperf.exe
Binary files differ
diff --git a/debug_unwind_reporter.py b/debug_unwind_reporter.py
index 9eef568..7a291b2 100755
--- a/debug_unwind_reporter.py
+++ b/debug_unwind_reporter.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # Copyright (C) 2017 The Android Open Source Project
 #
@@ -15,457 +15,258 @@
 # limitations under the License.
 #
 
-"""debug_unwind_reporter.py: report dwarf unwinding results generated by debug-unwind cmd.
-    Below is an example using debug_unwind_reporter.py:
-    1. Record with "-g --no-unwind" option on device.
-       simpleperf record -g --no-unwind --app com.google.sample.tunnel --duration 10
-    2. Use debug-unwind cmd to unwind samples in perf.data on device.
-       simpleperf debug-unwind
-    3. Pull perf.data.debug on host, and report it with this script.
-       python debug_unwind_reporter.py
+"""debug_unwind_reporter.py: report failed dwarf unwinding cases generated by debug-unwind cmd.
 
-    It reports below items:
-    1. time used for offline dwarf unwinding for each sample.
-    2. mem consumption before and after unwinding samples.
-    3. For samples that don't have complete callchains, report their regs, stack data,
-       unwinding failure info, callchains. Samples having the same failure reason
-       in the same function are only reported once.
+Below is an example using debug_unwind_reporter.py:
+1. Record with "-g --keep-failed-unwinding-debug-info" option on device.
+    $ simpleperf record -g --keep-failed-unwinding-debug-info --app com.google.sample.tunnel \\
+        --duration 10
+    The generated perf.data can be used for normal reporting. But it also contains stack data
+    and binaries for debugging failed unwinding cases.
 
-    It can be used to:
-    1. show unwinding failures.
-    2. show performance and memory consumption change caused by simpleperf/unwinder changes.
+2. Generate report with debug-unwind cmd.
+    $ simpleperf debug-unwind -i perf.data --generate-report -o report.txt
+    The report contains details for each failed unwinding case. It is usually too long to
+    parse manually. That's why we need debug_unwind_reporter.py.
+
+3. Use debug_unwind_reporter.py to parse the report.
+    $ simpleperf debug-unwind -i report.txt --summary
+    $ simpleperf debug-unwind -i report.txt --include-error-code 1
+    ...
 """
 
-from __future__ import print_function
 import argparse
-import bisect
-import collections
-import copy
-import re
-import subprocess
-
-from simpleperf_utils import bytes_to_str, log_exit, log_fatal, get_host_binary_path
+from collections import Counter, defaultdict
+from collections.abc import Iterator
+from simpleperf_utils import ArgParseFormatter
+from texttable import Texttable
+from typing import List, Dict
 
 
-class MapEntry(object):
-
-    def __init__(self, start, end, filename):
-        self.start = start
-        self.end = end
-        self.filename = filename
-
-    def __lt__(self, other):
-        return self.start < other.start
-
-class ProcessMaps(object):
-
+class CallChainNode:
     def __init__(self):
-        self.process_maps = {}  # map from pid to a sorted list of MapEntry.
-
-    def add(self, pid, map_entry):
-        old_list = self.process_maps.get(pid, [])
-        new_list = []
-        map_entry_used = False
-        for entry in old_list:
-            if entry.end <= map_entry.start:
-                new_list.append(entry)
-            elif entry.start < map_entry.start:
-                entry.end = map_entry.start
-                new_list.append(entry)
-            else:
-                if not map_entry_used:
-                    new_list.append(map_entry)
-                    map_entry_used = True
-                if entry.start >= map_entry.end:
-                    new_list.append(entry)
-                elif entry.end > map_entry.end:
-                    entry.start = map_entry.end
-                    new_list.append(entry)
-        if not map_entry_used:
-            new_list.append(map_entry)
-        self.process_maps[pid] = new_list
-
-    def fork_pid(self, pid, ppid):
-        if pid == ppid:
-            return
-        entry_list = self.process_maps.get(ppid, [])
-        self.process_maps[pid] = copy.deepcopy(entry_list)
-
-    def find(self, pid, addr):
-        key = MapEntry(addr, addr, '')
-        entry_list = self.process_maps.get(pid, [])
-        pos = bisect.bisect_right(entry_list, key)
-        if pos > 0 and entry_list[pos - 1].end > addr:
-            return entry_list[pos - 1]
-        return None
-
-    def show(self):
-        for pid in sorted(self.process_maps):
-            print('  pid %d' % pid)
-            for entry in self.process_maps[pid]:
-                print('    map [%x-%x] %s' %
-                      (entry.start, entry.end, entry.filename))
+        self.dso = ''
+        self.symbol = ''
 
 
-class UnwindingTimes(object):
+class Sample:
+    """ A failed unwinding case """
 
-    def __init__(self):
-        self.total_time = 0
-        self.count = 0
-        self.max_time = 0
+    def __init__(self, raw_lines: List[str]):
+        self.raw_lines = raw_lines
+        self.sample_time = 0
+        self.error_code = 0
+        self.callchain: List[CallChainNode] = []
+        self.parse()
 
-    def add_time(self, used_time):
-        self.total_time += used_time
-        self.count += 1
-        self.max_time = max(self.max_time, used_time)
+    def parse(self):
+        for line in self.raw_lines:
+            key, value = line.split(': ', 1)
+            if key == 'sample_time':
+                self.sample_time = int(value)
+            elif key == 'unwinding_error_code':
+                self.error_code = int(value)
+            elif key.startswith('dso'):
+                callchain_id = int(key.rsplit('_', 1)[1])
+                self._get_callchain_node(callchain_id).dso = value
+            elif key.startswith('symbol'):
+                callchain_id = int(key.rsplit('_', 1)[1])
+                self._get_callchain_node(callchain_id).symbol = value
+
+    def _get_callchain_node(self, callchain_id: int) -> CallChainNode:
+        callchain_id -= 1
+        if callchain_id == len(self.callchain):
+            self.callchain.append(CallChainNode())
+        return self.callchain[callchain_id]
 
 
-class UnwindingMemConsumption(object):
-
-    def __init__(self):
-        self.before_unwinding = None
-        self.after_unwinding = None
+class SampleFilter:
+    def match(self, sample: Sample) -> bool:
+        raise Exception('unimplemented')
 
 
-class CallChainNode(object):
-
-    """ Representing a node in a call chain."""
-
-    def __init__(self, ip, sp, filename, vaddr_in_file, function_name, map_start_addr,
-                 map_end_addr):
-        self.ip = ip
-        self.sp = sp
-        self.filename = filename
-        self.vaddr_in_file = vaddr_in_file
-        self.function_name = function_name
-        self.map_start_addr = map_start_addr
-        self.map_end_addr = map_end_addr
-
-
-class SampleResult(object):
-
-    """ Unwinding result per sample. """
-
-    def __init__(self, pid, tid, unwinding_result, callchain, sample_record):
-        self.pid = pid
-        self.tid = tid
-        self.unwinding_result = unwinding_result
-        self.callchain = callchain
-        self.sample_record = sample_record
-
-    def show(self):
-        print('  pid: %d' % self.pid)
-        print('  tid: %d' % self.tid)
-        for key, value in self.unwinding_result.items():
-            print('  %s: %s' % (key, value))
-        for i, node in enumerate(self.callchain):
-            print('  node %d: ip 0x%x, sp 0x%x, %s (%s[+%x]), map [%x-%x]' % (
-                i, node.ip, node.sp, node.function_name, node.filename, node.vaddr_in_file,
-                node.map_start_addr, node.map_end_addr))
-        if self.sample_record:
-            print('  original sample record:')
-            for line in self.sample_record:
-                print('    %s' % line)
-
-
-class FunctionResult(object):
-
-    """ Unwinding result per function. """
-
-    def __init__(self):
-        # Map from Unwinding result reason to [SampleResult].
-        self.sample_results = {}
-
-    def add_sample_result(self, sample_result):
-        stop_reason = sample_result.unwinding_result['stop_reason']
-        result_list = self.sample_results.get(stop_reason)
-        if not result_list:
-            result_list = self.sample_results[stop_reason] = []
-        for result in result_list:
-            if result.callchain[-1].vaddr_in_file == sample_result.callchain[-1].vaddr_in_file:
-                # This sample_result duplicates with an existing one.
-                return
-        # We don't want to store too many sample results for a function.
-        if len(result_list) < 10:
-            result_list.append(sample_result)
-
-    def show(self):
-        for stop_reason in sorted(self.sample_results):
-            for sample_result in self.sample_results[stop_reason]:
-                sample_result.show()
-
-
-class FileResult(object):
-
-    """ Unwinding result per shared library. """
-
-    def __init__(self):
-        self.function_results = {}  # Map from function_name to FunctionResult.
-
-    def add_sample_result(self, sample_result):
-        function_name = sample_result.callchain[-1].function_name
-        function_result = self.function_results.get(function_name)
-        if not function_result:
-            function_result = self.function_results[
-                function_name] = FunctionResult()
-        function_result.add_sample_result(sample_result)
-
-    def show(self):
-        for function_name in sorted(self.function_results):
-            print('  function %s' % function_name)
-            self.function_results[function_name].show()
-            print('\n')
-
-
-class UnwindingResultErrorReport(object):
-
-    """ Report time used for unwinding and unwinding result errors. """
-
-    def __init__(self, omit_callchains_fixed_by_joiner):
-        self.omit_callchains_fixed_by_joiner = omit_callchains_fixed_by_joiner
-        self.process_maps = ProcessMaps()
-        self.unwinding_times = UnwindingTimes()
-        self.mem_stat = UnwindingMemConsumption()
-        self.file_results = {}  # map from filename to FileResult.
-
-    def add_sample_result(self, sample_result, joined_record):
-        self.unwinding_times.add_time(int(sample_result.unwinding_result['used_time']))
-        if self.should_omit(sample_result, joined_record):
-            return
-        filename = sample_result.callchain[-1].filename
-        file_result = self.file_results.get(filename)
-        if not file_result:
-            file_result = self.file_results[filename] = FileResult()
-        file_result.add_sample_result(sample_result)
-
-    def add_mem_stat(self, name, mem_str):
-        # mem_str is like VmPeak:202464 kB;VmSize:183456 kB;VmHWM:98256 kB;VmRSS:33680 kB.
-        items = []
-        for p in mem_str.split(';'):
-            key, value = p.split(':')
-            items.append((key, value))
-        if name == 'debug_unwind_mem_before':
-            self.mem_stat.before_unwinding = items
-        else:
-            self.mem_stat.after_unwinding = items
-
-    def should_omit(self, sample_result, joined_record):
-        # 1. Can't unwind code generated in memory.
-        for name in ['/dev/ashmem/dalvik-jit-code-cache', '[anon:dalvik-jit-code-cache]', '//anon']:
-            if name in sample_result.callchain[-1].filename:
+class CompleteCallChainFilter(SampleFilter):
+    def match(self, sample: Sample) -> bool:
+        for node in sample.callchain:
+            if node.dso.endswith('libc.so') and (node.symbol in ('__libc_init', '__start_thread')):
                 return True
-        # 2. Don't report complete callchains, which can reach __libc_init or __start_thread in
-        # libc.so.
-        def is_callchain_complete(callchain):
-            for node in callchain:
-                if (node.filename.endswith('libc.so') and
-                        node.function_name in ['__libc_init', '__start_thread']):
-                    return True
-            return False
-        if is_callchain_complete(sample_result.callchain):
-            return True
-        # 3. Omit callchains made complete by callchain joiner.
-        if self.omit_callchains_fixed_by_joiner and is_callchain_complete(joined_record.callchain):
-            return True
         return False
 
-    def show(self):
-        print('Unwinding time info:')
-        print('  total time: %f ms' % (self.unwinding_times.total_time / 1e6))
-        print('  unwinding count: %d' % self.unwinding_times.count)
-        if self.unwinding_times.count > 0:
-            print('  average time: %f us' % (
-                self.unwinding_times.total_time / 1e3 / self.unwinding_times.count))
-        print('  max time: %f us' % (self.unwinding_times.max_time / 1e3))
-        print('Unwinding mem info:')
-        for items in zip(self.mem_stat.before_unwinding, self.mem_stat.after_unwinding):
-            assert items[0][0] == items[1][0]
-            print('  %s: %s -> %s' % (items[0][0], items[0][1], items[1][1]))
-        print('Process maps:')
-        self.process_maps.show()
-        for filename in sorted(self.file_results):
-            print('filename %s' % filename)
-            self.file_results[filename].show()
-            print('\n')
+
+class ErrorCodeFilter(SampleFilter):
+    def __init__(self, error_code: List[int]):
+        self.error_code = set(error_code)
+
+    def match(self, sample: Sample) -> bool:
+        return sample.error_code in self.error_code
 
 
-class CallChainRecord(object):
-    """ Store data of a callchain record. """
+class EndDsoFilter(SampleFilter):
+    def __init__(self, end_dso: List[str]):
+        self.end_dso = set(end_dso)
 
+    def match(self, sample: Sample) -> bool:
+        return sample.callchain[-1].dso in self.end_dso
+
+
+class EndSymbolFilter(SampleFilter):
+    def __init__(self, end_symbol: List[str]):
+        self.end_symbol = set(end_symbol)
+
+    def match(self, sample: Sample) -> bool:
+        return sample.callchain[-1].symbol in self.end_symbol
+
+
+class SampleTimeFilter(SampleFilter):
+    def __init__(self, sample_time: List[int]):
+        self.sample_time = set(sample_time)
+
+    def match(self, sample: Sample) -> bool:
+        return sample.sample_time in self.sample_time
+
+
+class ReportInput:
     def __init__(self):
-        self.pid = None
-        self.tid = None
-        self.callchain = []
+        self.exclude_filters: List[SampleFilter] = []
+        self.include_filters: List[SampleFilter] = []
 
-def parse_sample_record(lines, i):
-    """ Read the lines belong to a SampleRecord."""
-    if i == len(lines) or not lines[i].startswith('record sample:'):
-        log_fatal('unexpected dump output near line %d' % i)
-    start_line = i
-    i += 1
-    while i < len(lines) and (not lines[i] or lines[i].startswith(' ')):
-        i += 1
-    return i, lines[start_line:i]
+    def set_filters(self, args: argparse.Namespace):
+        if not args.show_callchain_fixed_by_joiner:
+            self.exclude_filters.append(CompleteCallChainFilter())
+        if args.exclude_error_code:
+            self.exclude_filters.append(ErrorCodeFilter(args.exclude_error_code))
+        if args.exclude_end_dso:
+            self.exclude_filters.append(EndDsoFilter(args.exclude_end_dso))
+        if args.exclude_end_symbol:
+            self.exclude_filters.append(EndSymbolFilter(args.exclude_end_symbol))
+        if args.exclude_sample_time:
+            self.exclude_filters.append(SampleTimeFilter(args.exclude_sample_time))
 
-def parse_callchain_record(lines, i, chain_type, process_maps):
-    if i == len(lines) or not lines[i].startswith('record callchain:'):
-        log_fatal('unexpected dump output near line %d' % i)
-    i += 1
-    record = CallChainRecord()
-    ips = []
-    sps = []
-    function_names = []
-    filenames = []
-    vaddr_in_files = []
-    map_start_addrs = []
-    map_end_addrs = []
-    in_callchain = False
-    while i < len(lines) and not lines[i].startswith('record'):
-        line = lines[i].strip()
-        items = line.split()
-        if not items:
-            i += 1
-            continue
-        if items[0] == 'pid' and len(items) == 2:
-            record.pid = int(items[1])
-        elif items[0] == 'tid' and len(items) == 2:
-            record.tid = int(items[1])
-        elif items[0] == 'chain_type' and len(items) == 2:
-            if items[1] != chain_type:
-                log_fatal('unexpected dump output near line %d' % i)
-        elif items[0] == 'ip':
-            m = re.search(r'ip\s+0x(\w+),\s+sp\s+0x(\w+)$', line)
-            if m:
-                ips.append(int(m.group(1), 16))
-                sps.append(int(m.group(2), 16))
-        elif items[0] == 'callchain:':
-            in_callchain = True
-        elif in_callchain:
-            # "dalvik-jit-code-cache (deleted)[+346c] ([anon:dalvik-jit-code-cache]
-            #  (deleted)[+346c])"
-            if re.search(r'\)\[\+\w+\]\)$', line):
-                break_pos = line.rfind('(', 0, line.rfind('('))
-            else:
-                break_pos = line.rfind('(')
-            if break_pos > 0:
-                m = re.match(r'(.*)\[\+(\w+)\]\)', line[break_pos + 1:])
-                if m:
-                    function_names.append(line[:break_pos].strip())
-                    filenames.append(m.group(1))
-                    vaddr_in_files.append(int(m.group(2), 16))
-        i += 1
+        if args.include_error_code:
+            self.include_filters.append(ErrorCodeFilter(args.include_error_code))
+        if args.include_end_dso:
+            self.include_filters.append(EndDsoFilter(args.include_end_dso))
+        if args.include_end_symbol:
+            self.include_filters.append(EndSymbolFilter(args.include_end_symbol))
+        if args.include_sample_time:
+            self.include_filters.append(SampleTimeFilter(args.include_sample_time))
 
-    for ip in ips:
-        map_entry = process_maps.find(record.pid, ip)
-        if map_entry:
-            map_start_addrs.append(map_entry.start)
-            map_end_addrs.append(map_entry.end)
-        else:
-            map_start_addrs.append(0)
-            map_end_addrs.append(0)
-    n = len(ips)
-    if (None in [record.pid, record.tid] or n == 0 or len(sps) != n or
-            len(function_names) != n or len(filenames) != n or len(vaddr_in_files) != n or
-            len(map_start_addrs) != n or len(map_end_addrs) != n):
-        log_fatal('unexpected dump output near line %d' % i)
-    for j in range(n):
-        record.callchain.append(CallChainNode(ips[j], sps[j], filenames[j], vaddr_in_files[j],
-                                              function_names[j], map_start_addrs[j],
-                                              map_end_addrs[j]))
-    return i, record
+    def get_samples(self, input_file: str) -> Iterator[Sample]:
+        sample_lines: List[str] = []
+        in_sample = False
+        with open(input_file, 'r') as fh:
+            for line in fh.readlines():
+                line = line.rstrip()
+                if line.startswith('sample_time:'):
+                    in_sample = True
+                elif not line:
+                    if in_sample:
+                        in_sample = False
+                        sample = Sample(sample_lines)
+                        sample_lines = []
+                        if self.filter_sample(sample):
+                            yield sample
+                if in_sample:
+                    sample_lines.append(line)
+
+    def filter_sample(self, sample: Sample) -> bool:
+        """ Return true if the input sample passes filters. """
+        for exclude_filter in self.exclude_filters:
+            if exclude_filter.match(sample):
+                return False
+        for include_filter in self.include_filters:
+            if not include_filter.match(sample):
+                return False
+        return True
 
 
-def build_unwinding_result_report(args):
-    simpleperf_path = get_host_binary_path('simpleperf')
-    proc = subprocess.Popen([simpleperf_path, 'dump', args.record_file[0]],
-                            stdout=subprocess.PIPE)
-    (stdoutdata, _) = proc.communicate()
-    stdoutdata = bytes_to_str(stdoutdata)
-    if 'debug_unwind = true' not in stdoutdata:
-        log_exit("Can't parse unwinding result. Because " +
-                 "%s was not generated by the debug-unwind cmd." % args.record_file[0])
-    unwinding_report = UnwindingResultErrorReport(args.omit_callchains_fixed_by_joiner)
-    process_maps = unwinding_report.process_maps
-    lines = stdoutdata.split('\n')
-    i = 0
-    while i < len(lines):
-        if lines[i].startswith('record mmap:') or lines[i].startswith('record mmap2:'):
-            i += 1
-            pid = None
-            start = None
-            end = None
-            filename = None
-            while i < len(lines) and not lines[i].startswith('record'):
-                if lines[i].startswith('  pid'):
-                    m = re.search(r'pid\s+(\d+).+addr\s+0x(\w+).+len\s+0x(\w+)', lines[i])
-                    if m:
-                        pid = int(m.group(1))
-                        start = int(m.group(2), 16)
-                        end = start + int(m.group(3), 16)
-                elif 'filename' in lines[i]:
-                    pos = lines[i].find('filename') + len('filename')
-                    filename = lines[i][pos:].strip()
-                i += 1
-            if None in [pid, start, end, filename]:
-                log_fatal('unexpected dump output near line %d' % i)
-            process_maps.add(pid, MapEntry(start, end, filename))
-        elif lines[i].startswith('record unwinding_result:'):
-            i += 1
-            unwinding_result = collections.OrderedDict()
-            while i < len(lines) and not lines[i].startswith('record'):
-                strs = (lines[i].strip()).split()
-                if len(strs) == 2:
-                    unwinding_result[strs[0]] = strs[1]
-                i += 1
-            for key in ['time', 'used_time', 'stop_reason']:
-                if key not in unwinding_result:
-                    log_fatal('unexpected dump output near line %d' % i)
+class ReportOutput:
+    def report(self, sample: Sample):
+        pass
 
-            i, sample_record = parse_sample_record(lines, i)
-            i, original_record = parse_callchain_record(lines, i, 'ORIGINAL_OFFLINE', process_maps)
-            i, joined_record = parse_callchain_record(lines, i, 'JOINED_OFFLINE', process_maps)
-            if args.omit_sample:
-                sample_record = []
-            sample_result = SampleResult(original_record.pid, original_record.tid,
-                                         unwinding_result, original_record.callchain,
-                                         sample_record)
-            unwinding_report.add_sample_result(sample_result, joined_record)
-        elif lines[i].startswith('record fork:'):
-            i += 1
-            pid = None
-            ppid = None
-            while i < len(lines) and not lines[i].startswith('record'):
-                if lines[i].startswith('  pid'):
-                    m = re.search(r'pid\s+(\w+),\s+ppid\s+(\w+)', lines[i])
-                    if m:
-                        pid = int(m.group(1))
-                        ppid = int(m.group(2))
-                i += 1
-            if None in [pid, ppid]:
-                log_fatal('unexpected dump output near line %d' % i)
-            process_maps.fork_pid(pid, ppid)
-        elif lines[i].startswith('    debug_unwind_mem'):
-            items = lines[i].strip().split(' = ')
-            if len(items) == 2:
-                unwinding_report.add_mem_stat(items[0], items[1])
-            i += 1
-        else:
-            i += 1
-    return unwinding_report
+    def end_report(self):
+        pass
+
+
+class ReportOutputDetails(ReportOutput):
+    def report(self, sample: Sample):
+        for line in sample.raw_lines:
+            print(line)
+        print()
+
+
+class ReportOutputSummary(ReportOutput):
+    def __init__(self):
+        self.error_code_counter = Counter()
+        self.symbol_counters: Dict[int, Counter] = defaultdict(Counter)
+
+    def report(self, sample: Sample):
+        symbol_key = (sample.callchain[-1].dso, sample.callchain[-1].symbol)
+        self.symbol_counters[sample.error_code][symbol_key] += 1
+        self.error_code_counter[sample.error_code] += 1
+
+    def end_report(self):
+        self.draw_error_code_table()
+        self.draw_symbol_table()
+
+    def draw_error_code_table(self):
+        table = Texttable()
+        table.set_cols_align(['l', 'c'])
+        table.add_row(['Count', 'Error Code'])
+        for error_code, count in self.error_code_counter.most_common():
+            table.add_row([count, error_code])
+        print(table.draw())
+
+    def draw_symbol_table(self):
+        table = Texttable()
+        table.set_cols_align(['l', 'c', 'l', 'l'])
+        table.add_row(['Count', 'Error Code', 'Dso', 'Symbol'])
+        for error_code, _ in self.error_code_counter.most_common():
+            symbol_counter = self.symbol_counters[error_code]
+            for symbol_key, count in symbol_counter.most_common():
+                dso, symbol = symbol_key
+                table.add_row([count, error_code, dso, symbol])
+        print(table.draw())
+
+
+def get_args() -> argparse.Namespace:
+    parser = argparse.ArgumentParser(description=__doc__, formatter_class=ArgParseFormatter)
+    parser.add_argument('-i', '--input-file', required=True,
+                        help='report file generated by debug-unwind cmd')
+    parser.add_argument(
+        '--show-callchain-fixed-by-joiner', action='store_true',
+        help="""By default, we don't show failed unwinding cases fixed by callchain joiner.
+                Use this option to show them.""")
+    parser.add_argument('--summary', action='store_true',
+                        help='show summary instead of case details')
+    parser.add_argument('--exclude-error-code', metavar='error_code', type=int, nargs='+',
+                        help='exclude cases with selected error code')
+    parser.add_argument('--exclude-end-dso', metavar='dso', nargs='+',
+                        help='exclude cases ending at selected binary')
+    parser.add_argument('--exclude-end-symbol', metavar='symbol', nargs='+',
+                        help='exclude cases ending at selected symbol')
+    parser.add_argument('--exclude-sample-time', metavar='time', type=int,
+                        nargs='+', help='exclude cases with selected sample time')
+    parser.add_argument('--include-error-code', metavar='error_code', type=int,
+                        nargs='+', help='include cases with selected error code')
+    parser.add_argument('--include-end-dso', metavar='dso', nargs='+',
+                        help='include cases ending at selected binary')
+    parser.add_argument('--include-end-symbol', metavar='symbol', nargs='+',
+                        help='include cases ending at selected symbol')
+    parser.add_argument('--include-sample-time', metavar='time', type=int,
+                        nargs='+', help='include cases with selected sample time')
+    return parser.parse_args()
 
 
 def main():
-    parser = argparse.ArgumentParser(
-        description='Report dwarf unwinding results generated by the debug-unwind cmd.')
-    parser.add_argument('-i', '--record_file', nargs=1, default=['perf.data.debug'], help="""
-                        Set profiling data to report. Default is perf.data.debug.""")
-    parser.add_argument('--omit-callchains-fixed-by-joiner', action='store_true', help="""
-                        Don't show incomplete callchains fixed by callchain joiner.""")
-    parser.add_argument('--omit-sample', action='store_true', help="""Don't show original sample
-                        records.""")
-    args = parser.parse_args()
-    report = build_unwinding_result_report(args)
-    report.show()
+    args = get_args()
+    report_input = ReportInput()
+    report_input.set_filters(args)
+    report_output = ReportOutputSummary() if args.summary else ReportOutputDetails()
+    for sample in report_input.get_samples(args.input_file):
+        report_output.report(sample)
+    report_output.end_report()
+
 
 if __name__ == '__main__':
     main()
diff --git a/repo.prop b/repo.prop
index b44d23e..40a439a 100644
--- a/repo.prop
+++ b/repo.prop
@@ -1,674 +1,703 @@
-device/amlogic/yukawa 846b1637d445372289074718687a82c023f2aa73
-device/amlogic/yukawa-kernel 8e4926a91bc698bceac1c7e2f1babd46ad344f77
-device/common e3bdb003b9db6e1cffa0909463b33c2117d7ec4c
+device/amlogic/yukawa 427cf58068ebbf12b255ad15e741dd5df69a8f3c
+device/amlogic/yukawa-kernel 0f7b0ed678822f65ba891fefabfddd523544de09
+device/common dc68423f4385eacd64a7050a70b8ad186b42f5a0
 device/generic/arm64 c93f2bee499dd0f944dde9788dbe1e926c04cb79
-device/generic/armv7-a-neon ab6a7fe91ab2204fefb1086fc9b393d7965aec43
-device/generic/art 3bbf69adeacd94bbbcadec7c604f312fbf4f25d3
-device/generic/car d25770afce84af3a59293d8d30ed0d435de4c933
-device/generic/common 76438dff2f96e507572a411c933b394f7a223bfd
-device/generic/goldfish d42708a066e8287ab90e7dafe70c22f7e544caac
-device/generic/goldfish-opengl 6d84526d9ab37d9200ff85ae15b16dc10fddad32
+device/generic/armv7-a-neon 587516fbda3a5e0bcf95048b39a3ff4b6575357d
+device/generic/art 9194671dc64b387b1bc0b3b87946fbbb76f1638d
+device/generic/car 03ab79178ff0ed9189ca40657e9fa7a78b3045a3
+device/generic/common bf8ca669a4732e5ac203798a5544463d44447408
+device/generic/goldfish e4bfb96b29ae865be99dd6f5c758aeb1b17efcef
+device/generic/goldfish-opengl 5ccdec1f15a3a499fc723c4ce2a844fec80ef36d
 device/generic/mini-emulator-arm64 92751453f781a886cfa122ae2806b5a6fee5dc9a
 device/generic/mini-emulator-armv7-a-neon 758713275939470693bf476494ed1dada61c0dce
 device/generic/mini-emulator-x86 eaec2c1cf2953668654db11bb9c4bd44016314aa
 device/generic/mini-emulator-x86_64 8ab94877e0a77be0ebd5c7a74f3a2349b9d15960
-device/generic/opengl-transport 9f9c02592610e9c2bea6c9a2a2e361de38d32e2c
+device/generic/opengl-transport 17d78f0164e543314d449c0dae9c82a563256a9c
 device/generic/qemu 8c485393b917e27434cceffcb7b61a09a0ac3f3a
-device/generic/trusty 1637a92165d8b09c4ef8667a7db9ac6646c060d5
-device/generic/uml 323cc35973dbe047c9a3388930993530673b0ffc
-device/generic/vulkan-cereal bec74ae336eb373ae91dfd0c4aed8d54a4841dcc
+device/generic/trusty b21a6ab222b535a0d4cd55019cd489b15826dbc2
+device/generic/uml 9df233acb5d04613bcc9f67fe6685d6c484988d2
+device/generic/vulkan-cereal 15072483cdd4bd372c0c4edca6315a42c329cfd9
 device/generic/x86 7a984f0e394a7e96a6e20c1b51cd3dfcec9f289e
 device/generic/x86_64 142654f9aa7cec5e8f14f631c0a79a340266e563
-device/google/atv eb788922f3ced9b03bb440eb8e57c0d84fc9d92a
-device/google/bonito 0edfb68192b67c26cba543f165b749ed65788af4
-device/google/bonito-kernel e010d42cab925d9cb2ce5538afe99cbe4da55f1b
-device/google/bonito-sepolicy f1ea74125b994b9b80ca0a5d0c676f68d65b7672
-device/google/bramble 222aba5f76de3c2f78845c78d5ccae51b4f6aa05
-device/google/bramble-kernel 3ee922bbcbfbb0f30717ae64076b8af5cc6864dd
-device/google/bramble-sepolicy 2f705e61cbf5646f7b515a5668f74953e2eb0032
-device/google/contexthub 7cedd78dc8ded370ac096acdf22ff5de56086cf2
-device/google/coral 6e98b6d816bd3d50a7a0a438b27dd52877df1534
-device/google/coral-kernel b9bfc6c132ae4224f6771b44a9995b677945ff1b
-device/google/coral-sepolicy 3594a050d2354a5724e784206d2dc122383052a6
-device/google/crosshatch bbd55e4d10809e7d031d18aefff40751b9fa42e8
-device/google/crosshatch-kernel 9636bcec978079d89e31e8e0b2b697f4d23e8a7e
-device/google/crosshatch-sepolicy b6ce268b28c8f51b8de35ceb68a8895f6c89ec5a
-device/google/cuttlefish b84124448b227e7dd93280cae5c657c927fd6c22
-device/google/cuttlefish_prebuilts 160b98814ea94dab6d6a46780940b689c8defbee
-device/google/fuchsia 972bf6f6872f058c6762f3614d7ac8350fb9cd01
-device/google/redbull a50a240c0dbd4cf027e799bf907112e71c08783c
-device/google/redbull-sepolicy 7f00d8fa3113880afd5d2d7c289e5addc3f5be9c
-device/google/redfin 851d259991a0eb7aed7953b32bfce78fc2515d87
-device/google/redfin-kernel cea228ce6fb5bce8400b4a910f1af28c2b619442
-device/google/redfin-sepolicy 37ebf4e920883f54f7438b081489c8a372a59eed
-device/google/sunfish 0138da03a613cf6c99ece7eab24f6e5c428f818a
-device/google/sunfish-kernel b2b456c2f923dd0e1a694a8d0766835be116e33e
-device/google/sunfish-sepolicy 4469f0e00cedd92a69959c764a11ed85d2cdf14d
-device/google/trout 827ec90e79c560113a823eeddf1cc9f531762a07
-device/google/vrservices d782c7470ced4326cc20f8819cdce98eb909aa3c
-device/google_car 572bec54a7d4cd9efa7c79deab0525dd8f586ffd
-device/linaro/dragonboard de6ba42ace4291aaed31ac211d4f457f99999af2
-device/linaro/dragonboard-kernel 7275c6f05d36b48a411204a892a7ec11a424990b
-device/linaro/hikey 4f24664d454fefa7877992d860aa9ec2d24e7a27
-device/linaro/hikey-kernel 18f96414721b76371ed06fe0364398e8da283596
-device/linaro/poplar 5d0311b3d22597e9c5f9da26d870cd5ef59893ce
+device/google/atv cf0c7d22c2a24489b64298697d4a367688c1c599
+device/google/bonito 348ec623a2a999d543dc5614189fcac25bbbaaef
+device/google/bonito-kernel cb19ec1d835575cc83fe2ac6e940303a129f7f76
+device/google/bonito-sepolicy 1b75d7ccdbfdabc18ca0d03b400540d83a8366b6
+device/google/bramble 1409ae4c833d48abeddedc38dbbedf9b42acf4f0
+device/google/bramble-sepolicy 01f9cc4955cfd3de4345cfd2681fe3f922ef69e1
+device/google/contexthub 95db61f4e6573e22d8317e48a7bd63f03edd32dd
+device/google/coral 3586e5843c7ec923349e867c37ae5e8fd5e553bf
+device/google/coral-kernel b429c30709f166e66aa6354d215278db42713e46
+device/google/coral-sepolicy 07b918494faabb1f3770f2e46ac6546565eacb63
+device/google/crosshatch a78aa5f05ad9c488a7f4d44db4fd411164f586cb
+device/google/crosshatch-kernel e44ce7ba2cb01b7860c7eb6f3b9ef91d51ad651c
+device/google/crosshatch-sepolicy a3f087427f1d4155cfdeeeb2031b912ea6d2aa74
+device/google/cuttlefish 1891599a078af98fc09b93d5d3599925fdd307ff
+device/google/cuttlefish_prebuilts d0025fecd51fed82531cd8414a449c48076e8868
+device/google/fuchsia 911ad0a8666f74bdf61bb0713b79cde9ae7e92df
+device/google/redbull 593d10082b72549b9490345a9023ba738c085bb7
+device/google/redbull-kernel 1191553815a5f7c5d009029fc0e5298f6a2823a2
+device/google/redbull-sepolicy 32a2f2f83bf409496bffa6b0224a0f4cf3b9fa86
+device/google/redfin b487d94a4db5be77a253207af213b134287c3734
+device/google/redfin-sepolicy aba7953d4f5df7453e7448e4948d49a62ec4c1cc
+device/google/sunfish f62d631a8f77374a3998628ac3cd2ece22a90c09
+device/google/sunfish-kernel 789351f46b528856a16acd57781147a8a62785fb
+device/google/sunfish-sepolicy 44ee98f4b684c3d25e94ea108f7c799bc790b1b0
+device/google/trout 5c6c171e942fc9fbbdd01c415a02119becf3e081
+device/google/vrservices 54457e28f6e28d4ad886669b49a413118ceccef3
+device/google_car 39eeba215b46b0c462f08a0f19d19256eaffc28d
+device/linaro/dragonboard e254575bc227963d91ff28aa4ec9ca9425710363
+device/linaro/dragonboard-kernel bf708c43622b1fae56706b28b89e8b0cdec9ef3c
+device/linaro/hikey b90bdb65351e3058eecd33cb857efdf0904bdda0
+device/linaro/hikey-kernel 5cd64c73aba49366b82869a19ed6fea0d30f0f66
+device/linaro/poplar 11a20ea3ba3840de7c1418be6dbdd81562325ade
 device/linaro/poplar-kernel dc5a5f37e19871ed67bb9e9209e7318bb3e6ad31
-device/mediatek/wembley-sepolicy 3b003f2110b8a6605d7bb1f59bf4c7ab6e7a299d
-device/sample 7b4d50e1a7f2c47a833fb4c903d1c4ebc8faa599
-device/ti/beagle-x15 dd19a5b0cc0aec8ab509467aafd675159fb83373
+device/mediatek/wembley-sepolicy ab669365ea23fb6404d1ae45237b712d289b90c8
+device/sample 46dbcedf0a43288a5142d6c5a1e590176bb879b1
+device/ti/beagle-x15 155e2c4a644c901e6e1341487067c4d3e17351df
 device/ti/beagle-x15-kernel 8aacfce3cc5e2a17970c5af35cffeca6f5eed4b2
-kernel/configs 80b59337c496ef40a70434bbefbe6e9fdeb4f43f
-kernel/prebuilts/4.19/arm64 466adced29033d68070e99043ec1f6f8931c087a
-kernel/prebuilts/5.10/arm64 7f48e4de6bd77bcb7b79d8fa5eb4dd8bdb3f2365
-kernel/prebuilts/5.10/x86-64 b27ce587f6c82c55eb4382bce7e9f18a0f1fa9e8
-kernel/prebuilts/5.4/arm64 f76e70779964b24f6784cc2ce046866385153112
-kernel/prebuilts/5.4/x86-64 1be9972137f86063e5ce2b14a3139b59627d6be5
+kernel/configs 07d86016e20181729640ca960f4eaa2488909b20
+kernel/prebuilts/4.19/arm64 c3236f7ab3d508ce8502cf2a91707e4a0faba825
+kernel/prebuilts/5.10/arm64 30a99dfc69f1ba69005398eb55b2a50f81ce065a
+kernel/prebuilts/5.10/x86-64 c1809d4e0562339d8416a632e6d27b1c49b33657
+kernel/prebuilts/5.4/arm64 06acae2461acf159bece5114a07e94f65122ed60
+kernel/prebuilts/5.4/x86-64 74a670bcae7f2412d1588c19520506db539b0ad8
 kernel/prebuilts/common-modules/virtual-device/4.19/arm64 31fa2c2d74f8b3659d8a2093f727486c4d890540
 kernel/prebuilts/common-modules/virtual-device/4.19/x86-64 396ea43be7fdb2f7fa7f5ebf3e9aa2a3491a0e68
-kernel/prebuilts/common-modules/virtual-device/5.10/arm64 2930b04ab8af2ff4b49bcda6d29d2d4606e4089a
-kernel/prebuilts/common-modules/virtual-device/5.10/x86-64 c9cc01a7c498c27f69b455aa5a4d48ff4aabe12f
-kernel/prebuilts/common-modules/virtual-device/5.4/arm64 1d935d41303dc1ddf958e94389b0e53c3709f0db
-kernel/prebuilts/common-modules/virtual-device/5.4/x86-64 48135bb8b36e547d34c9c5bbd67df053a8cbf3eb
+kernel/prebuilts/common-modules/virtual-device/5.10/arm64 285fc5136e0389da1a8d103fbdfdbb88a18b9dcd
+kernel/prebuilts/common-modules/virtual-device/5.10/x86-64 a484bde74502075a102d807b8921eb3c608a1b2b
+kernel/prebuilts/common-modules/virtual-device/5.4/arm64 141cc2d0b612ea33a7af9c8601e18b74d936a8c3
+kernel/prebuilts/common-modules/virtual-device/5.4/x86-64 e9c9b0d44a21eb76b17a7ad9d5b0121483788607
 kernel/prebuilts/common-modules/virtual-device/mainline/arm64 c413b2256fc3ab41da32a5b790bb8f8a465f4cac
 kernel/prebuilts/common-modules/virtual-device/mainline/x86-64 8bd5dbee62d3a4e2666123e138f34939d9162b07
-kernel/prebuilts/mainline/arm64 e49e86aa82fe4c7aad0cb9ccedfe9b79b8def744
-kernel/tests cc8df4bff6445bd192da38d0eef8196076c35ebd
-platform/art e5b4d703c5b79a9bf78c5143c85272d20b3e8aef
-platform/bionic 0ab91b28f6de3d51c2db67c859d20ac851900aae
-platform/bootable/libbootloader f8d38e3445e4c697160d020eb09fdc7463afbb31
-platform/bootable/recovery 4ab5ca08b48f50d9f6a0580c7fdd6e2c1bfc31be
-platform/build 238ad5d6d9df223d917b4a077ca243749d642235
-platform/build/bazel 31bf41c30cbcddc2b58cc49d61b2d00f37b2af17
-platform/build/blueprint 48c3302e0ec24a8a4c63c0013686a5468b10b11a
-platform/build/soong 0701db877d402cdb6450b895702ad786768485f2
-platform/compatibility/cdd 9136ee763c05577d985affbd95cab0df218f2f6e
-platform/cts 2e8b590a8b8d62d764815a25201c864ed63c8fbf
-platform/dalvik 68e226528af2dbdb087d36ecd495e6c7bbb98c50
-platform/developers/build 2bd93c7f89ef1d4d1968700a79e6faa3ea4cfecf
+kernel/prebuilts/mainline/arm64 323fe334e36bf62f3ace809e0e92c4f96b029aa6
+kernel/tests 8a8e063f8f6a235a0ce79ceb92d75bcd16388a08
+platform/art e6d19393f3740019bd8e7eeadf7474e247f601b0
+platform/bionic 557180975b42db4000e268640f5d163d9a654080
+platform/bootable/libbootloader 641e437471b3320d8016d1e2fc3e60a79f2324e4
+platform/bootable/recovery 569319386169ea35aa6c68ae2cd758132299ad9f
+platform/build c951989298a6883c2ee31053e0ff9f12989d0c9d
+platform/build/bazel afd0025c9a6fb3132f7c4b4d4462e0398d4d8160
+platform/build/blueprint cbbb252f37e6c0daf47d5537cbe3c020c3bc53c2
+platform/build/soong 098d5827a512f99c5111a7ff32bd56629e02147c
+platform/compatibility/cdd 8b38c58c3ce44f820bde0554dfc674449477f92b
+platform/cts c1aa80059607b5a5098fa09149ee0a9653c625ff
+platform/dalvik 023fcda67cd1318879287155a96bd18df134287b
+platform/developers/build 92b05279d02a8b095ff6ae24d898ef5ba3e85aae
 platform/developers/demos 03814c35b8ee0a1284c667556260124d97466b28
-platform/developers/samples/android adf9aee621ed59e60b277b407c0e0ab2e0f07f96
-platform/development 7f6b5e54510e054516edff030104ad7f592c2713
-platform/external/FP16 b9cbd0b151f9d780350ea15769382c416dc09cdf
-platform/external/FXdiv a1de7b4e8a93be019ed6de94398dd8044d305514
-platform/external/ImageMagick 0f050b13bc12fb54b4d5e097a579ae5849a05798
+platform/developers/samples/android c96286bf27bdc9e4b2bbad6015ca16ea671cf0b9
+platform/development a47bd654cfbee225607fdca935f3bb1c522fd86a
+platform/external/FP16 904378ca2e143e1f93bc6adac55386edacc526b4
+platform/external/FXdiv 5cffdb8c0198bb3c652fbb3efd39130a350e9bc9
+platform/external/ImageMagick d33afb7fb67b801878ad2f4b2a1f47e5dcc43fae
 platform/external/OpenCL-CTS 600744d85d3a59a067dcf79a3050acbca8ac6351
-platform/external/OpenCSD f885d144e34a4ea7ac02abd44d4fa485f369a29f
-platform/external/Reactive-Extensions/RxCpp 2b82fac5f9c8e0c51f35ca1106af62b35b892159
-platform/external/XNNPACK 6898860f966dcf7d8ae8e31cbef8cf0b5c4b57ad
-platform/external/aac 9101ed6741199b9586005b281f951a0e255c0abe
-platform/external/abseil-cpp 8a5447e64d0143c265dae69ae9fe3b1aa21d4eb6
-platform/external/adhd b0a584c939218e127c14a91f0671c99fa933f79a
+platform/external/OpenCSD 224696f15826f8230f0f5a636912ca82460de005
+platform/external/Reactive-Extensions/RxCpp e4b7717cbf1c754c70cfd04d50303c5b77f66b10
+platform/external/XNNPACK 2d806b1cd8a5a2533ba5f3f8cb0d351aa2ec1eb7
+platform/external/aac 853669b8f0c785e520b736677d0f061bf5626bd0
+platform/external/abseil-cpp 60ca2e92a725aed0097c48aae3fad40bb4d18536
+platform/external/adhd 879b3c950dde2d2add7ee7ee7fff6d65e834fc82
 platform/external/adt-infra fb4938345b8640c51308cbd96799d876e6c9b7b1
-platform/external/android-clat 6d8f7f2af191b0ab4384818cd68c515394b6e56e
-platform/external/androidplot f018b8808a649e458ccfbab3486ff0ab4c3ec81b
-platform/external/angle d41acdef44845c8c35d1ef7c741696f4fe177ebd
-platform/external/ant-glob 8985f690c43dc4e6b5abccc233ed6ff36ffd9fc9
-platform/external/antlr b75ee09dd213c81d96a0ca4a86704f54452df9d5
-platform/external/apache-commons-bcel ef3102b0380a252102f9f961e7004dfd9e83aab2
-platform/external/apache-commons-compress ec0afb5b90b4ef5b85c0bc14634bc2c3605366ee
-platform/external/apache-commons-math 7d6731d83c816ab6f43aa4a10949004a85ef474e
-platform/external/apache-harmony 4ff956e3e69f928c2956465e999af1e5882a4e54
-platform/external/apache-http cfaccfda76254b3277a9c9f5a17361cefceab3b4
-platform/external/apache-xml bd93a39a8cb4249b9612a2fba9ea4da2b66485c8
-platform/external/arm-neon-tests 02fd7b8a2cf8e58cfc6f69c3f74f6b300af707b5
-platform/external/arm-optimized-routines dfb8ccab3a8d4b38a8ae59a6173d16bb55837c04
-platform/external/arm-trusted-firmware 04a88946e189fd93ba9fe8bb4d6c2869d967f9bd
-platform/external/auto 1da05d2180a4078690905a13c1769bd840fd2073
-platform/external/autotest 6bea74afccc0e959ce3ea0bbcc5bde2abfbb1fba
-platform/external/avb 6f70f9ac877ea10bccfa8e1bba5144d1d27146bd
-platform/external/bc 4abc8e3fcd0ad334b922b5f55f45e72bc6a9a990
-platform/external/bcc a41cb7fb5254b0bf9cce9c5be5725777ec7024b7
-platform/external/blktrace 543ac29f8d14b90901e4c1acce06b59b871f5db5
-platform/external/boringssl c852702cee32ff4e874f0e689e93108c516fa9d3
-platform/external/bouncycastle 94113c9a06e6f171a833a5d8d5cbaaf0c76f58cf
-platform/external/brotli cc23df4db3c1a74aea36ad3b4cc93cb8475ef98f
-platform/external/bsdiff f8d134b31347319fa4a6f3e6225506e83802d01a
-platform/external/bzip2 0f40bc5963f2e8543f25a39175b3e7685df27e81
-platform/external/caliper fa0c483eab3bea1cb14e239625473b5ab35de2fb
-platform/external/capstone 2dd8c85f828f4692d88ebe8217450a386baf8366
-platform/external/catch2 b593c39d337ccb6ff12f9159c268ddcdb60a0421
-platform/external/cblas 80ee48529625aee1472459ac6cbe5cf944cb819e
-platform/external/cbor-java dee8f59724ca6d22d5c6590dc79a386db28009f6
-platform/external/chromium-libpac df28d129424202cd906124d5bf927dd145263bce
-platform/external/chromium-trace 26ddf24dfe1f0bfd961ee53879a17cdd89bdcbed
-platform/external/chromium-webview 098b346d8c581d609f8a10a0281329343b8be727
-platform/external/clang 1df15b3827eae2aa7a6d23c306b55ad2e6da4b32
-platform/external/cldr 622c1483bf081d74cd8b7045e4fe82bc0cc6ceb4
-platform/external/cn-cbor 573a02fd43ee532a469703a7dcd69a447a6cd7f7
-platform/external/compiler-rt ad1d6d27b5527e527d9f13420ac4fd0dc78d3ee3
-platform/external/conscrypt b0d5db01a8d7e198348643c8b83f0e94fcd59a5e
-platform/external/cpu_features 66e0a7099cf852ed51774b408dfaec97bd1db801
-platform/external/cpuinfo 87a4b97bb001e709d06c42de35af128b227eeb99
-platform/external/crcalc a63fc8b515a8bc55e4e97f95c8220668859301bc
+platform/external/android-clat 2fe093fbb2173ac9bb5b7fda1a082a99d1816eff
+platform/external/androidplot 7413cee95b59376804f31b313c90c1d32bd2074d
+platform/external/angle 6fcdf3aeb20f8b76fa80cf6ff851681378428f9b
+platform/external/ant-glob b3a81147ca65172a8e2b437f5a5b283700f4b045
+platform/external/antlr af839f4096474de2c1e4aa9d7854dea9874f4f62
+platform/external/apache-commons-bcel 14af157874130e72abee850ca4c9ceb2f04e06cf
+platform/external/apache-commons-compress 1c6999cb200079ab0c771064848c3d50a07cc0ea
+platform/external/apache-commons-math 0629a60f0361b856e2b52b7e47860314471ed339
+platform/external/apache-harmony e6916e6d16dc87e33e2e022d1b4929056cf286cc
+platform/external/apache-http 2a328396555fe9887f843b2eba40e4a919886c26
+platform/external/apache-xml efaba93d74bb39f0fa513bc4b6c8f3961314eed3
+platform/external/arm-neon-tests fc65bcb31e46601d487be8bb17b51d44650be91e
+platform/external/arm-optimized-routines 7ef9a3564d1d2c9acf998dc9acc5c08614be05bc
+platform/external/arm-trusted-firmware a2f667b4ba090bfdb282e377473291519aeae672
+platform/external/auto cfa73b3cc8aee0e61db3a78b3e9dc4c1c51233d8
+platform/external/autotest 29a5450ba48d89c724eefbb7d02b37197ffeab59
+platform/external/avb 9919b83d4acc017379cbd9f7547b1afbdcf927c7
+platform/external/bazelbuild-rules_android 5ff3c4add6884e00e49a9c75cfb557f3d139347b
+platform/external/bc 5cd89187b96e17448f50bb3aaf815b292580e6e4
+platform/external/bcc ec2063e9d0e54d181efceb1bbc9be30f814fdedd
+platform/external/blktrace 4b5d86b02a1289a7d6adab80423903e06f1ce2eb
+platform/external/boringssl a01f619f8a336ba43328813f66ae7489166761fc
+platform/external/bouncycastle 202278f560c931a7ebadb0ad2878f1893cc53190
+platform/external/brotli 469df94fd9eb01bc7422256f78f269f997ca680b
+platform/external/bsdiff 26b367e19d65a4bc62811d607475f67cc89f0bbd
+platform/external/bzip2 6b4635385ef0b2e8a525f3df2870eb95917f696f
+platform/external/caliper 3a2145a093a7c6c4444f72ca88b60cd699d1cfd8
+platform/external/capstone 6f8d22390f224ba55459e2cc2fc519ae69f65c9e
+platform/external/catch2 3e979c6f222df61f90a63cd1101b88fbc824fbc5
+platform/external/cblas e101765596795b6cbb3b9c2cc787ba2d35321281
+platform/external/cbor-java 9abba33685a533c7906a3fcfd593217d24d278ac
+platform/external/chromium-libpac 6bbdc66546765a6467ac38737924dfe1e52d2331
+platform/external/chromium-trace f706bfcfbc3bcc93c0d3fbc12b1dd10c03bf91cb
+platform/external/chromium-webview ed92c319ed6c4ca7423e39487c4f3ccc28c9f319
+platform/external/clang a5ddb2c193e9681648acd9db3e175016c4cd2921
+platform/external/cldr c6d49187b4b375ad09b04613e11cdfc2c745793c
+platform/external/cn-cbor 131b0d69b9739878fa692c9c69c60059ad954311
+platform/external/compiler-rt 8873377e086da838be349f02008d752454891dd5
+platform/external/conscrypt fe33ca2be0495dcb6bc7cbecec87a8dfca259918
+platform/external/cpu_features 02c6ceab2c8e8eeaa30bfe637c6b106e488eb118
+platform/external/cpuinfo 1121204eb14388243ebc8a3405e3624af3739ffc
+platform/external/crcalc 43985ee09512414f7afa69abb5c0f37e585c2462
 platform/external/cros/system_api b8ce2aa98fd8b659666eaf8df8427f19cb11129a
-platform/external/crosvm dbe40c3c2d87ec432fd894b3295cd119a9c2adde
-platform/external/curl ffc1505d24b2d8d2715e0d1f633a5a4de629ca30
-platform/external/dagger2 73c4552e20be8f4f35be7c976283c1277d07b418
-platform/external/deqp 46ed9a4faae2a284fe0cc62007a9a805480628c3
-platform/external/deqp-deps/SPIRV-Headers 65eb928e271d08654eea54dbf740e9c462e7d1d8
-platform/external/deqp-deps/SPIRV-Tools ec673c6825be7ae877d38540f9218a4d2bde7ade
-platform/external/deqp-deps/amber 25b9079b9ede47b6be3d640463f97bcb01695dba
-platform/external/deqp-deps/glslang 5c60da63cea283c8d68f44a0bebbe26ce2a49d9d
-platform/external/desugar df32b996ea38f31cf5964d73039dc1788b15160d
-platform/external/dexmaker dedf49e6a58aedb7327657dbc3767137abaac956
+platform/external/crosvm 13bf900d5e74d04f542cc38ab742baa6a49cd6e4
+platform/external/curl f81af92bd45efa0e34e8ef578780faae9f3cb183
+platform/external/dagger2 765f2513b0b85a4375ed7374db729930bb5c29fb
+platform/external/deqp e096f5385413788e8463ab5c43537df6d0f82e92
+platform/external/deqp-deps/SPIRV-Headers 6e9670e299ce59983a3c5c77b8730f8fb09dcae0
+platform/external/deqp-deps/SPIRV-Tools bb6d6cc4c7b13bcaac9f4e656cf14065824f1014
+platform/external/deqp-deps/amber 5a5070097fec1fa874b83e3ca987887e4489ad4b
+platform/external/deqp-deps/glslang 06735389a4c35defd9e098e5452f9b5c4468975a
+platform/external/desugar 9f1ad211c9a9a74d5edf620787f073180370ef7b
+platform/external/dexmaker 72c183ca835ddafc92630ac7102afeaf986f5b79
 platform/external/dlmalloc 70da7be4c21c6c89360e57b35fa792d9636d5384
-platform/external/dng_sdk 82d88ec2769f0944e9721a37e8a327d907dc052b
-platform/external/dnsmasq 69cd1fc3b7da2f5ac9d2882188833af9f78d347d
-platform/external/doclava ed1872de6cf39a73875645832caa2b83e9d3b37d
-platform/external/dokka 6c8465d3bafd79e0a8e520fbcb01d37d4ae7725f
-platform/external/downloader c0449c875310544ac46adc4334635bff8a86a495
-platform/external/drm_hwcomposer c20f5e96b259b80c160f5fa9d93ff8d1741a486b
-platform/external/drrickorang c7f34a5e87ede8ecf297b05543dd77a58eaf4454
-platform/external/dtc 1cbc6dbd82e08e94e97de1e1c77d7095d1c57212
-platform/external/dynamic_depth 85a76a747428a717a631e165855201561b9f9888
-platform/external/e2fsprogs e263d6d85b46b4756bc6d8faf9d936891e29a638
-platform/external/easymock 998fad1afe6b19bf67c382a4e83c245999f5f1ed
-platform/external/eigen c3e6e3519fbb9535ae810f1e742759a96148faef
-platform/external/elfutils 76793d2f2700fa623848f85fcd1c5a25c712a339
-platform/external/emma f992c9dfc2fcff506b234f5435947bf1b16c72dc
-platform/external/erofs-utils 4730e6cea9bd4426a87293f9a56f487b00963ae2
-platform/external/error_prone e9dfb20ba1dddcd26cc171422809c116b32d3cb6
-platform/external/escapevelocity 4e3c3fac5c9a03acc723d0a33eb80ea05f7b7690
-platform/external/ethtool 379a7d6171721abea5c381f2a3719a50238e577d
-platform/external/exoplayer 6058a85ee809a54277ac90d3f67874181afcb64a
-platform/external/expat 811c28f940ccfd9b75d68f61e002233acea59a86
-platform/external/f2fs-tools 890641892f41cda3fe43f942c182781c12cbcb5b
+platform/external/dng_sdk efc261fca440edab0201f9f766ce913b51caef73
+platform/external/dnsmasq 17bcb3c7caf702678b05ea3d6196e4da428bef40
+platform/external/doclava b22b621891d074cd6c60e79bfaeb146709eedb02
+platform/external/dokka 369d13cc55b5caf4f5c0ac63ce2893816e7d92b2
+platform/external/downloader 266792985abf9a3d6180569b560a147143e750a7
+platform/external/drm_hwcomposer 5ba4c2a4325c60996d3dfb9f61401d9fbac6cfe1
+platform/external/drrickorang 23d443a60c418850c62e3f49992493335179e6c5
+platform/external/dtc ab9936207e2fd175186870e55b74f3b278260122
+platform/external/dynamic_depth bc88b91338cd17cedf374f07a19dcbf7d1689205
+platform/external/e2fsprogs d63070a3933749269d6b0297eef5c9d473a5db86
+platform/external/easymock 23c81546be363df12697ab1fff9ba770925b089d
+platform/external/eigen 9d0675a88eee745cfaadebc2e43e629d579c839a
+platform/external/elfutils d8ea71e27448bc48a7546535ab7e13ab57ee05b5
+platform/external/emma 28a9514cbcaafc8a114cf4872b5f286770df4ac3
+platform/external/erofs-utils 93f7cc86b27ed9cefaa615af44340f67e94905ba
+platform/external/error_prone d0c6bd993053019f4d64acf073afc5e0caffb599
+platform/external/escapevelocity 1040be4d45a62424c46b0b3cbc9d0c38f939e19b
+platform/external/ethtool 460917860af6b140e403eb2ec5869f17804b553e
+platform/external/exoplayer f16b029af0bdaf75112154d80ec6a21f902a16cd
+platform/external/expat 4732b113fa3f2deab8a3ce001fce784a3d88318c
+platform/external/f2fs-tools a05c461032b2e890b00d18f3456f647dd2635f5f
 platform/external/fastrpc d66b565370ef6c6318dd83d0c7b5499f28d04cae
-platform/external/fdlibm 642628e05c47db5437b0ded9a910737196325b4d
-platform/external/fec e536b81c92ab7b0cb08cfc28547e5256b31dbe56
-platform/external/flac edbf760d714de5ae8b8ff3f4e8a4533ab6295957
-platform/external/flatbuffers 05d7b689e93c5b38b7f7a7efabf90f80de639c3f
-platform/external/fmtlib cdc34df0c3ffd259a6a74c41d29b0b830f9d87d3
-platform/external/fonttools dd269f168c7d93c2d5fdb988238932226c2b25ae
-platform/external/freetype 11c97673141f546934261b9a0030bd7e0734aac8
-platform/external/fsck_msdos 867523c38d3b14830cff1f45dda217609a20a663
-platform/external/fsverity-utils 4f8481f1c78f18c685f2e0422d9f0a200f3124d3
-platform/external/gemmlowp d85f94c3d5b5d37c69840b3b163a0c20c42e6d1e
-platform/external/gflags deaec92d289d40e7380a3df52c7c754b3f184b9c
-platform/external/giflib f9b72e00a3cb86b21060091c3685c1075d816c9f
-platform/external/glide aff0e27761f4e47f6c5ba8a75d4dc77a6e520281
-platform/external/golang-protobuf dec51746b6a5c0bfe958cfd0d5cdcaf9c865fe92
-platform/external/google-benchmark 22ff819b7f2cf0a9d3225edf0cd677edf65ee997
-platform/external/google-breakpad 1b4066b384d158480011574f89c2b33cb386716e
-platform/external/google-fonts/arbutus-slab abaf3cd25a595f4c2a33cc1e7db1c3ac1790eb19
-platform/external/google-fonts/arvo ae24169216882e3767ab9fc0d4f211c9b44a1b60
-platform/external/google-fonts/barlow a3cab69c46d32098c3c90b001e3f42cbfcf6409d
-platform/external/google-fonts/big-shoulders-text 78a5c4fb80e98777f70eeed3364554585a45ce5e
-platform/external/google-fonts/carrois-gothic-sc d1df5b0735c6e21c3aa33b5324c9472feb93a246
-platform/external/google-fonts/coming-soon de5b52bd93d6c252e542c5e547c8504e4f384525
-platform/external/google-fonts/cutive-mono c416378dd7b6b485969faec27c650840444e4d15
-platform/external/google-fonts/dancing-script d57bc0b6c0d90a6f688e65c0d83a500dc1014ebc
-platform/external/google-fonts/fraunces 0d69e02bbda3ac91fd0956199b0e2c7b5be88a71
-platform/external/google-fonts/karla 24b87868f84ecbc6f364abae718f368126d1e76c
-platform/external/google-fonts/lato 9ce13fb5956ec7597178ee702f7fc58cbb15ff25
-platform/external/google-fonts/lustria 83ea42f69fb930ed537ae2f86a2e51cc3453ba72
-platform/external/google-fonts/rubik 38bff40a3942f176e7ff97c063e3c71719546a81
-platform/external/google-fonts/source-sans-pro a0d7d938e33775f18ab3322b8d7a0d2fb5fcb2f8
-platform/external/google-fonts/zilla-slab bf3d77d6af0665af7e16b5e345fe58575052f1be
-platform/external/google-fruit 6d74389b2c631ab8f37d128a726a3c0ddc529b9d
-platform/external/google-java-format 838c2344b1f62e878a68f16757eb31af806a604d
+platform/external/fdlibm 1b8891a7556f48de86f5509d5e162d8c4a4fda33
+platform/external/fec ba3f756acac15723b9a414c83685ca15bb60839c
+platform/external/flac a87dbf964f2c88ba0132b8272a50c856b2558619
+platform/external/flatbuffers 05c38570397be07cb9f197af5b6adea513be620d
+platform/external/fmtlib f1c149900f41ea4d5e53a4d1fd84d56bf9d529e8
+platform/external/fonttools 64dd6e5d01d721588473a3829e3ab763fc15038c
+platform/external/freetype eb43740a14d5034e78ca2470ecfdfb694b569582
+platform/external/fsck_msdos 1ff2a0b0c52c41e6dec586e4f86e2fc85e813f9b
+platform/external/fsverity-utils 4a2f68e74c059fb397a5b6c410b1d58bca1191fa
+platform/external/gemmlowp 107daa937fa061e85888e59cb2b78a6f378fdb3e
+platform/external/gflags cf9299afbe15342468909e34624c2ce6bb09396b
+platform/external/giflib 4554b647c947666b63496ed40f80ae8d41bca230
+platform/external/glide 9fd692cf51b443af74192071797cc7b31e942e3f
+platform/external/golang-protobuf a08aa4e050201e7a0f2359d1709b9a6441d65cc3
+platform/external/google-benchmark fd54b6ddce6869675f8d21b4406a5757fc330d89
+platform/external/google-breakpad 33460814422f2e870f9b0246d0544ff11f37d859
+platform/external/google-fonts/arbutus-slab e25e171408a757a0db4d1dec0ff2962df71d5752
+platform/external/google-fonts/arvo b59b321f863455e645fc95b4fb311819c472582a
+platform/external/google-fonts/barlow b6e6b1936c71a12b98d174b4f539c8b7b0677fa3
+platform/external/google-fonts/big-shoulders-text 5c2206481b64c7dc64ae3102e022b7af8b426c4a
+platform/external/google-fonts/carrois-gothic-sc 9918a02d9a5748141aa2fbdf744ff1264213d96d
+platform/external/google-fonts/coming-soon c4514465089bb53949c4b5ca7eb22f3fb8df6aed
+platform/external/google-fonts/cutive-mono 3f31306db53205e091912a7811fa44181c6558e6
+platform/external/google-fonts/dancing-script 06d3bf2b23dce03f15cb8e76e885f048a936e141
+platform/external/google-fonts/fraunces cfbea2a313eaddac4f5edba9642a36eedd5ffec2
+platform/external/google-fonts/karla 339bbf11e12b69cd0ecff1cdd30489b9564928ea
+platform/external/google-fonts/lato 6f2cae7a60717ce19fe79276dd0603f91de9634e
+platform/external/google-fonts/lustria 60e883804ea525d493511377b12be83d63e28f51
+platform/external/google-fonts/rubik c6bb8c4579fa760a7ac8b44c5d6602cadf6268a6
+platform/external/google-fonts/source-sans-pro 3a4d72e035127295a6ee1a818f7e70fca87357ec
+platform/external/google-fonts/zilla-slab 0eb6f312a1bef61ca621ffb2dc718bc8507480fd
+platform/external/google-fruit 4642b2c3b286f1d12220b35b588952b6b8170e29
+platform/external/google-java-format 569b83b746932330f6811854fbb81119d0f7657e
 platform/external/google-styleguide 0b28639e536c03a19b520d4c294a281064f95616
-platform/external/googletest 85252bfc86f3d34411b942b1bff5563c22f7b827
-platform/external/gptfdisk fedcc195f2d44db6d337ea8b2455b5f4f6b43ec5
-platform/external/grpc-grpc ea04c6c49766b95bfb7cc3e4354fa2e84694e2f4
-platform/external/grpc-grpc-java b905ed91d0d5e9f177f771df3073a9aa23c7ae21
-platform/external/guava df96e991152d0f73e1718cbb4c9d6e28e2bf8159
-platform/external/guice 30ffd841ffb152ea8514c91a9e00130fdef3f70c
-platform/external/gwp_asan 2dceee59fba439082bf4ab3badb2ff10dcf2e6e4
-platform/external/hamcrest 5b109acd87f45a4ae4c798d98a6ce2875f73c14b
-platform/external/harfbuzz_ng 79ac99e5388f85044bf161a5c5f7749a90682656
-platform/external/honggfuzz 71aa60c5e5e8f38c4b281fc1f20cc8514e4e25cc
+platform/external/googletest 52987c8027c321ca2c812e879c82bfbceee0532a
+platform/external/gptfdisk 3c93201cccadba4adf3e67b26d449745f7d73771
+platform/external/grpc-grpc 5a9c24f1165a3d82988054b38951cf1a75463fb3
+platform/external/grpc-grpc-java 42c66e265c7d5c8b4f8e0c8944f93554c96edecb
+platform/external/guava 93d9c405426c601339bb9b6d338a4166221d1dee
+platform/external/guice d2da6ff52a9158dd2e049483853e2bccbc6a8645
+platform/external/gwp_asan 42dc404a49cbecd7b08c6623f666fea0c8cf4579
+platform/external/hamcrest fefb5f0dfb01723675836f3312e60de683f385a5
+platform/external/harfbuzz_ng afe3ded7fabee838e9922f507a4bfc3598a594a1
+platform/external/honggfuzz 95ff0083771289a53cf6d76719bc39e473cd5aa1
 platform/external/hyphenation-patterns 7fe89949e5de5b01a12e16715bd877f7cbfb9e3d
-platform/external/icu 5c262da4d224cb72b06492acce10d1cf8cee7621
-platform/external/igt-gpu-tools 4c9ecf1095ef509fac03695f4b4e1d877bdad008
-platform/external/image_io d0e86167cb076c141248753d2d751b107270686e
-platform/external/ims b0e4ef6939c1aaed542dba6b6f7201648cb91ed5
-platform/external/iperf3 d0f0777459bb8db0f2abc1c259c5714082689800
-platform/external/iproute2 cc0fca5733d44dac670c76b35147126eb5a04417
-platform/external/ipsec-tools 1c13751a37a23bcaf7073a67de8b254600d08aec
-platform/external/iptables 3513b3eb2e63b41016a997903e2d501f4abf2707
-platform/external/iputils 9bd47e3b853f283209662299b4ceb3f8d57f9ea4
-platform/external/iw 61169bf474417147bf753d30caeff6cf1e7a2caa
-platform/external/jacoco b68e0296ca7f7b3d46ed961757b1b9b0e5e35619
-platform/external/jarjar 7b07f8d2f356afa0a7d3aff0f4a24fc29ed11c89
-platform/external/javaparser 1d4b830394e4373f74e7392935f726847372b691
-platform/external/javapoet 7d642e315866475bc1d2a8db56256ec0c6a5f303
-platform/external/javasqlite 2871345746ac9d9c065493e3f7023c85a990be72
-platform/external/jcommander 304d4cb5c5b8b45ecf01abc342a84c181c5be829
-platform/external/jdiff 88364ce906370e770c34717fd1b9d761db41844e
-platform/external/jemalloc a1f7d06aa4dcba0bf328b7fb1286d6f9382b0021
-platform/external/jemalloc_new d89a8271c07a92843b7972c696829bb4ebe80d73
-platform/external/jimfs 1859b2ba8fe273b8d6cd206370fc16cb15e54780
-platform/external/jline 7de38e748e23109c327dd25106f994b0ed7a3f49
-platform/external/jsilver aab543ee8f2d305fa3000557479745d1155fd0c5
-platform/external/jsmn 492c5d0c53d6343cfe9c725c97ecc5d463b5d66b
-platform/external/jsoncpp d24646b4819efecddf704f4751fc7d595ea39270
-platform/external/jsr305 ac009d564c531046c73bb423ea14425b8cbf30f3
-platform/external/jsr330 0cb8593874903c4cf2880feb5826f317390f0b5d
-platform/external/junit d0e26ddc36960708d32e4d98825e646fab9f40a1
-platform/external/junit-params 0973ccd1ca7218848b81336465711d3e51afd8aa
-platform/external/kernel-headers 8091a28814012a9e2a92fc7ff78428aa671f00de
-platform/external/kmod 2ecafa93de1369352042100aec8d00adffb8d787
-platform/external/kotlinc 38a6dea5b901692e3da6963d131baf5637a77e29
-platform/external/kotlinx.atomicfu fc7b3e8ef49b5de921071d420da2e797d4058855
-platform/external/kotlinx.coroutines cd7ed457e1f125b8d0d216444901033b996212b4
-platform/external/kotlinx.metadata 539270858830aa72b1ff0e157ece65fc1b16cbe1
-platform/external/ksoap2 25045a692cd850a218657c5c467c3f2097f50cc9
-platform/external/libabigail 202cc988e90bad7574aaff51d5e1e411143ab61f
-platform/external/libaom 724b99cd3d1a35b603d71155b1486287df0ca317
-platform/external/libavc 39d515144b5875634a99120ec0e380db063e3b6d
-platform/external/libbackup 033554b3ca1fceefa3a8e757d49a116beb445d17
-platform/external/libbrillo 534360f90ab11e9c1eec6a3500565bbc235b1fbe
-platform/external/libcap 3a0f58a48eb3b52662650de49b8dafd991c54524
-platform/external/libcap-ng 92bf8e3b7b0fa0c5c0770b4f37050a35637651f8
-platform/external/libchrome b8ed6d4c553b68c82d00cd92309b3ea303e8319f
-platform/external/libchromeos-rs e3d92ec026c362f8d4e8d1793dca6ccad4235a5a
-platform/external/libcppbor d7541a13e1bfc3acfff89f6423de70b9e5facc28
-platform/external/libcups 921930809fbafdbf92a2dde62650a99df927861f
-platform/external/libcxx 8321ae79a493382023f6af4c7a77d6b537638da2
-platform/external/libcxxabi d1fb12537381b3fe0079887d1b268426cd34de03
-platform/external/libdivsufsort 16762cd38fecbf91b2e336103d064ed7cf1979de
-platform/external/libdrm 498b131834195e00c424775f4265be678c7164b0
-platform/external/libepoxy 2990f29064c0e48f6fe57a4b42f7b56317f11df9
-platform/external/libese 8aa2f61d69f28dfeb354a0ee5ad2fe6fb09c6397
-platform/external/libevent 483c00dd0a3f645ab85d22fbcf169bf8237034ae
-platform/external/libexif 3b9ed39308e6f07a6755d57fc3c6b52ea7198be9
-platform/external/libffi 43c6440a1dac2b74d7a02435938dfaf63ebcda48
-platform/external/libfuse 15fd59cc57a9c32d1f36790f057f85adc787d19f
-platform/external/libgav1 8bdc73f8d7f711e93715ffe9a2a06a29f56f88b6
-platform/external/libgsm 0efc44484caf1a42071a1de347df01d2ba085cae
-platform/external/libhevc 6945986492caac5a528073f9cadd6ff61ed517bd
-platform/external/libiio 06fae07bb29e3fc8434e1d28a84c483f3625d95a
-platform/external/libjpeg-turbo a29b9fb0b32dc4b702d30dee4474f04d1d40feb3
-platform/external/libkmsxx 3c1644c7d38174ac5469990cc37ae0335c2b1ee7
-platform/external/libldac e9066c8a0d7d12a668d9210504e9bb1f7f35d2d5
-platform/external/libmpeg2 397e20732a733b16138f86fed73170657504e5fc
-platform/external/libnetfilter_conntrack 92f1d30677a0461a311d84f7e40b910e99a502eb
-platform/external/libnfnetlink 2f01b0dd2c0aa9f3af77ad1d1c5bac6ed15b63cf
-platform/external/libnl 05d3c4f95fa3f55cfd6f0c50033c175a8d86b2a3
-platform/external/libogg 59879adb257442c5507ef065dc6278c98a0364a4
-platform/external/libopus e0e21c0158c654336f9111a90d908edcb045a4ec
-platform/external/libpcap f19351419ab5b37fc2e388e5d3c632fc528219fa
-platform/external/libphonenumber d7843a65a63acac55b7fa9f903d2196c60f07a50
-platform/external/libpng 6515749eaf0dc5a2d25ed165587ee73b7e86aa35
-platform/external/libprotobuf-mutator 0cf207227ed91c1c8f174b55dbdfda39cd1a8f1d
-platform/external/libsrtp2 46cd217cedd3124083b8a1df856263557f74470c
-platform/external/libtextclassifier 618214b78cc5a05a7582c9020e7b4674200b8d6e
-platform/external/libunwind eaf58456de772f8a03589309f2fc6e556ad62e41
-platform/external/libunwind_llvm 73b1ea6975b1526dd18cc498532a5a9ac2623d88
-platform/external/libusb 88ec96d63fb06baaff51c7c695b5c348789c3fb9
-platform/external/libutf cb3ca1d9b1a5c4e7345f3fea17a10b425b0b8104
-platform/external/libvpx 0cded2742baadff1af61773d5a711453dff12bac
-platform/external/libwebm 4d7c35a36b1559ae8555929f2f6cdd74d858a220
-platform/external/libwebsockets 370804f36e6d3511d0e840308528c3e2d01ac00b
-platform/external/libxaac 759bbd92a6901904af42b163c3b7619061bd3dbc
-platform/external/libxkbcommon 41adbe7b2bcd9bd5109f0222b575a9d9e7cadf0b
-platform/external/libxml2 7a9870b596973ef081b4ceaaf2dde34e5f4aefa3
-platform/external/libyuv b53399aee124ca276976a55e8bb8bdc24d07080c
-platform/external/linux-kselftest 8c6a97c56612f4858fd2b55fc020323473d846fe
-platform/external/llvm 81f7e612005d1874f53bc10b8e09764731b81b98
-platform/external/lmfit 7c066ce5d04bfdf4522ca46d26181e64d7585d1e
-platform/external/ltp d7e4d99a0d1971a9da98868c80d51e258fcac1a7
-platform/external/lua 42d3e26019135488b0478d93cbad383aa5e66f28
-platform/external/lz4 5e9ec87dc1a497055d03ce8220a7cfb3642d5205
-platform/external/lzma d4e099ef97aeab5eaffa180f4b79a040f71296b5
-platform/external/marisa-trie 1b1c548bc967cf5ebe967291397978e971af193f
+platform/external/icu 40a8e51f6ab8e427f9d18d12d835c762ae1224bd
+platform/external/igt-gpu-tools 9d22d91a3c4748e22d1543b13f669cf716e8512c
+platform/external/image_io 90bd899b2f6a9e2d8f715785eb3da9957136e241
+platform/external/ims 54248dcc73bc31d4494bb664760416e212012959
+platform/external/iperf3 aa7617a8609ca7e99e59594b656b0df3724f642c
+platform/external/iproute2 686c053b8012f94db3e943b60d50328fb70ae5fc
+platform/external/ipsec-tools c5ba9a773881f0e0704812d6d3a83b694fd4e96a
+platform/external/iptables 57a64ec38ef6726b37771d43932f844d6499892d
+platform/external/iputils 000e9cffa5d4e8b55e92451a19b65d091d77e9c0
+platform/external/iw 794f59a49c830d7a5ab89bddd7f2fcc573e4d2f2
+platform/external/jacoco d7955952c7be257e4096b6f62b1e67c591d42ca4
+platform/external/jarjar 2958c1abf35553036ab1ab7e0a6412af15d9e09a
+platform/external/javaparser b7bcf594499451dd4c7a76763f4da26e118bab30
+platform/external/javapoet def4ffe31b1942fb81e9c5bdf8e602d920afe590
+platform/external/javasqlite 6f80ff4ad5b217f8de3c3ee8550248f9789191a8
+platform/external/jcommander 56559ad16fa874de47d6208f915221ebf18761b4
+platform/external/jdiff d9fc695a287c7bb1f9290d7136eb731b2d575b9c
+platform/external/jemalloc 96aa8db91e275067c9d89c3d458627751dd4932b
+platform/external/jemalloc_new c5a19b0eafeb685e4206c85d5365c27cd74a2142
+platform/external/jimfs c9bc7922d8803afe60ef19236e0e28a5aa944cc8
+platform/external/jline a5594fd540ce941907159aa8e8f2ab95d5cf23b8
+platform/external/jsilver 7133d10d72ce28f0dc49f5f14336c5d783af5d02
+platform/external/jsmn 2c63f11fa12adb3a446dec486bf2371170d0846c
+platform/external/jsoncpp ec3763bb3bf45a7326a427fcf4bec160a3497aa3
+platform/external/jsr305 30b1b0767e61932e872b757bbe50e7713384d657
+platform/external/jsr330 c050a365d2f7cde20e01d31b9d3bb74955562a20
+platform/external/junit e80c8de55ba5d87abaad71d9043bdd7e4d9c0f65
+platform/external/junit-params 53c20bcf1390fd17f3bcfb0963802a1f601b87ba
+platform/external/kernel-headers 20df8e0fad4e54183dec0fc00356f6977f217258
+platform/external/kmod 2c5ecae2fc18065626072fd7c5ebc9c4cee6d334
+platform/external/kotlinc ee28766cc10222c1e1701b23d89b44b4ce081d48
+platform/external/kotlinx.atomicfu f93ec66cd8023239fad5483de549679057fff231
+platform/external/kotlinx.coroutines afbd96776a07c4b11600521b3316465f95cd38ba
+platform/external/kotlinx.metadata b4fe9e830c744c68ae952969e7a5600d1b4bf98b
+platform/external/ksoap2 632cefb64b08b661d64a442e1f3a6f4219252824
+platform/external/libabigail d7daa441e212e7e142620b84b518e1790b554f53
+platform/external/libaom 5d3438d525d7762bdfac252b34552bb703fec3e4
+platform/external/libavc ac03e923fe6c97825e7372a968c539842169a2d1
+platform/external/libbackup aea293f4f6de78897e04118156490c65e4907cf8
+platform/external/libbrillo 6f33165fea62c0738c1212c19fa0da37ddf6f059
+platform/external/libcap d8bc664e184bdcc79e6358224514e3ef61808e3c
+platform/external/libcap-ng 27590f90642de43a84570cac8f3665bffc9e4760
+platform/external/libchrome 2de02add569f1e644f5c046848ecd82a26d9bb35
+platform/external/libchromeos-rs 72f8bfa27b98cff8336ef7e15914026ad6ddce8a
+platform/external/libcppbor 4dcbc8b04a6786a5123efdd8c550548ea570280d
+platform/external/libcups 9f0009107cefcee7ee21aba5e00f2686466b2282
+platform/external/libcxx b43a5772a5740bf10cc0f1237abf59475680e4b2
+platform/external/libcxxabi 3b61f6300e188d35713608d5d7fceda3071ea315
+platform/external/libdivsufsort af70c8bfa92f3dc1e057d8bc8ff8f9ea7d27e96e
+platform/external/libdrm 89eccb3729e8309e073ba0d57d1209bcc4600352
+platform/external/libepoxy 6fa676bc2d36742f9669fd54c79503c90e335018
+platform/external/libese c583f85920b66aa6c3a638279d51fcf5af44e6c1
+platform/external/libevent dd805f402753a254528bcebf0211c4c0fe33310a
+platform/external/libexif 32e50b37c81a4d9d7a2a4953c9ee8562bd624991
+platform/external/libffi 0a79b154a9cc4ee70022875c5182d59e9e62971e
+platform/external/libfuse 64dc0d13e42c23b89d863142cd69e17ae73a7fbc
+platform/external/libgav1 d145a512bee87eca1cadf8c248505c8f4702d345
+platform/external/libgsm 2de17b60fa7ff7a4d0fa51df3940e95e5e82f061
+platform/external/libhevc 68a62463d9c5f38a42d54d54ba6fe1a841869c5d
+platform/external/libiio 5fe7de7e428daaf065b5e624e2b330595df6cf28
+platform/external/libjpeg-turbo 222cf969756020efe7b0334d3394048cc80f1ded
+platform/external/libkmsxx e6adaba653c618cd9822d7c3569116aaf47042a2
+platform/external/libldac 0b827bb99f1d5196b488cee8d6dba2ad9e755c4d
+platform/external/libmpeg2 83a529bb55418afff5097f9539b15487a3c6f75f
+platform/external/libnetfilter_conntrack 2d37814c4aa696f572e27abbf7768f44f6f7c338
+platform/external/libnfnetlink 690342dffd5ef7c8f2c24b5444235b86bf3dc7ba
+platform/external/libnl 4f8448525530cb6a9330b0e12c0c4136af8094a2
+platform/external/libogg 9ba70cb7a21e1bb2369477f97faf37e1b8178cd8
+platform/external/libopus 83f52a8f9947702accaaa83da689107288c998bf
+platform/external/libpcap ba0c2e295c2f03eb9aed463a70651040a7ffbd94
+platform/external/libphonenumber fe3eb3c90d365f9ec729c5c7adf6e040566d1aaa
+platform/external/libpng 9c5e64182a8192384b4a3123962448eb03b597e5
+platform/external/libprotobuf-mutator 092b8e5f56f67eb23c53ac7157ebbcc7c148da6c
+platform/external/libsrtp2 0e586fe5671fa3fddbc1227b388811042c6787fe
+platform/external/libtextclassifier 6cc01d9587e33df0856f8ff5c2dd76f3dab180bb
+platform/external/libunwind 8068cbb3b4b79d0578c21265f6a70b6039ccb05c
+platform/external/libunwind_llvm 14b128def6b3151ab55d96502b8a85907979cb65
+platform/external/libusb 10bc3fea14f43754dbfb46ebb72bd6a72f5a2378
+platform/external/libutf 802ab6a5e1c34a98e41ef055e5bccef27375316e
+platform/external/libvpx ecb634e54b09ef4d760e68b525b9fd7fee89cf2a
+platform/external/libwebm 582d9351f470af8d931e5bbc50a071d3fc55cb08
+platform/external/libwebsockets 8474cc662a00e5eddd8c8e75c57132144314b54f
+platform/external/libxaac 11977fb311f7a2cd1a988d109dd5bfc4c33684b3
+platform/external/libxkbcommon ac4e2b364e781ea56652a1883c71b19b68753337
+platform/external/libxml2 394a5e65723d16e59d2d551177b64cd5b9ec0fbe
+platform/external/libyuv d2fee8aeda778fdb4d0beb99ade2ac0e606840c1
+platform/external/linux-kselftest 197bdb2adf27c7070793f8dff3a5c469c4ab2e8f
+platform/external/llvm 2c6b6e2f885c9a7654773df444a4f032507af4fc
+platform/external/lmfit b6962b41a5625ddbd3296eed6e887c9dc48628dc
+platform/external/ltp 69d562ed70fe37855fb6a5e9ebfb81bf8832df2c
+platform/external/lua 2d8761e8282cb7990268e3beaed44b0ab6e9e591
+platform/external/lz4 63ee9109eacbaebe95cb2f932d38763eb99dd03f
+platform/external/lzma 2ceb6df3b9ff6bcd8a93d11f20652015d3a4005f
+platform/external/marisa-trie 8016418c07c3cac486d827e3fa4ff21aefe38d14
 platform/external/markdown ecaa496397f271f4e5724cba2e352a68206141c7
-platform/external/mdnsresponder ff458309df9b5184a4bfb9d356a7641d9fb66ebc
-platform/external/mesa3d dc4c8bd3947fd3b916837331f376a6003811b154
-platform/external/mime-support 178d02294a2bc5f3b741a970ed555e99f5c9391b
-platform/external/minigbm 24e2e3eb5fecbb8063865c8dfdfba23f05930204
-platform/external/minijail 2312e5650a7bf8000ceb74c0115f0cdd02323de3
-platform/external/mksh 6c548736d07887958542312753618cd1e6f1eed7
-platform/external/mockftpserver f4c72b07389fdbcdb965d6ae47427ed1f083804d
-platform/external/mockito 7766a6f8bf2b6468e27816d54161b0c7a27e3339
-platform/external/mockwebserver 57330b7143e5364d97804f842e6df2913456bf13
-platform/external/modp_b64 55815170b8afced38b8f87bdff8d0f81877a32fd
-platform/external/mp4parser fee0315a4a45e84cea8fb61b588b07cb36c28aa7
-platform/external/ms-tpm-20-ref d44a69547ba52873003f52436cac7e8416987a45
-platform/external/mtpd 2ffe4f766293aedb2ffdea7c0fc16d05ac5747ee
-platform/external/nanohttpd 0c31cb403139fe1e8d2e5bd48b6e6bccbe2cd5e9
-platform/external/nanopb-c 3516aba583e9da0fc39190ebe78b1b7a0d7f7ffd
+platform/external/mdnsresponder 251c584a10d019330c5ae6663db2f03c1a2e151e
+platform/external/mesa3d d66e32083c7a7538251a789360bb7b6d7f24f4cf
+platform/external/mime-support 390989a96740f819f542ebf4f60fddcc4a587297
+platform/external/minigbm d08fb096815de6474395556bb8ec94747d715cdb
+platform/external/minijail 6a09420fda714c9644bac1587bae0c7cae165207
+platform/external/mksh a14bf943d79c23dc975b2c3b95d25bcc38bb610f
+platform/external/mockftpserver 67a6119f73e2796f1c73c8eed0c5648d7bdb3a25
+platform/external/mockito e0cb2606aaa1548ba0998ae70b9147e50c43ec6d
+platform/external/mockwebserver 4dbc97c26f04aa4904976c0622ed26e621a2ca78
+platform/external/modp_b64 96321fe6678dbd65d62545c1915b2fcab8a17025
+platform/external/mp4parser 1c35c86085e266ef74ce926bc153d32aef68738e
+platform/external/ms-tpm-20-ref 464838b431b1b6e9ea89010ab51c49f61c45eabf
+platform/external/mtools 29f36b572acb969674e6db336bed7bcfd437a93d
+platform/external/mtpd 6aecea37d8b99c77dd8a9ee3d35672809cb129fb
+platform/external/nanohttpd 1a4995218a148637884db8d86590e7a6a3c6c154
+platform/external/nanopb-c 2fdaf032cd236f0c5233968b747dd82ad4c763b9
 platform/external/naver-fonts 5a91e834832b722871b0b33c3161b102135198b2
 platform/external/neon_2_sse 0e44cc69654d46fed2e6b9b299159c4329d83025
-platform/external/neven 8bf95b4c129cbb0cf7fd22f3f0e610f0efbdad3b
-platform/external/newfs_msdos abdd328d2d8e3dad64283e7dab6a243413fbd27c
-platform/external/nist-pkits b726eb2cf0008dd6e356df49bd79403f55137437
-platform/external/nist-sip 8d940fc40b332ffb5dd532b240e227e612c1c32a
-platform/external/nos/host/generic 9c8a274455871f58deb6e457b5ee398626e8f6f4
-platform/external/noto-fonts ff3f1c34eb97acf6644e0a6868037806152a31ce
-platform/external/oauth e1b67ce5031bcba5ba10db15e873a2d6b9a4e850
-platform/external/objenesis 51dd03873236d2e2e753b0772f6350867c574718
-platform/external/oboe 2adb4e6f714e0f46883f60ffc8f5ac0ad91476e7
-platform/external/oj-libjdwp 0dabb2230b401923db08e53e944312a05a28f850
-platform/external/okhttp 9aec307ec276fa95ad79c90e089b6addc9405049
+platform/external/neven 8e6ee6f76524df377a55eb534df3453cca96a53b
+platform/external/newfs_msdos 44281499ad4b600170a975436d9b88d80e5b8fe8
+platform/external/nist-pkits 8db84e0cab3fba420aa534ae47998ac3995fecb1
+platform/external/nist-sip f3780fdb89d7296d8ce3d6fb581a3b29216e5118
+platform/external/nos/host/generic ce18edecc01931a7de5ffc4765fc3e3ba0b09609
+platform/external/noto-fonts 4b864367cc55b5ff2b9eaf0f64d8d8abc0ee30a8
+platform/external/oauth 2a399ca00eb14463c034e00e2c01788c52fc4d88
+platform/external/objenesis 1dadbb2ff76bd6c2bb24dc4bde838448b1a69980
+platform/external/oboe 3aea1db41aaeb1e68d2d8d50cd9965427ca1657f
+platform/external/oj-libjdwp a4f69525f22d2aa6ab1e5f811fe19e1035dc2b30
+platform/external/okhttp e8773466a6b5852a47211baa1e18add192a54781
 platform/external/okhttp4 73ae9756098533a6fe58aa1149c88f5304f4124f
-platform/external/one-true-awk cbc92223d03eca3e0c83c935095afcee8bf6365d
-platform/external/opencensus-java 2f2c8a1b335e526f5385b147c40d0002eda02e7d
-platform/external/openscreen 76efb73cf24074e6611621732cdebfea23509272
-platform/external/openssh 96a36e9b9fbd9a1aa6b3ac2c1439792bec9561a5
-platform/external/oss-fuzz 6fede6131f8aa6927b2f82df6b5b4f42d74297fe
-platform/external/owasp/sanitizer 221a2ca18ad856eda5c3a5bb9a3059b8ffd11506
-platform/external/parameter-framework 77db73e2022924aecbdfe2e3070598b6ecf71682
-platform/external/pcre d9c4ff30eba111193f51c750b6188feb9111f0c3
-platform/external/pdfium 3f992789e4afc69cde3dbed39fa822bae5b677d1
-platform/external/perfetto 43569048a90c74e4e8d1c73c7f58899510ada7f1
-platform/external/pffft 61fe6d15b0227df64f0e36ce537dda14ef3b7c71
-platform/external/piex fd1e091fd8136abf3415360a50a3ebebf238c265
-platform/external/ply 9f23f5c1139d4fc11ac4344957b3401f006a95b5
-platform/external/ppp e5d6ad48dec06c5a8d7dd8028e46f62e90a2dad9
+platform/external/one-true-awk ebb1d9a2ff1e80dc7764fe346a90a32f291b0a31
+platform/external/opencensus-java b638efeb5c62a5a68c73d61ee76cd2a0d4285c6a
+platform/external/openscreen 7aad911f78874b2074eb649c1db1da1960062bac
+platform/external/openssh 91f22fe3ed46531e74fec254efce410ed72952eb
+platform/external/oss-fuzz 5244d7370cd739b8eee9c8d7f505703b26a2049f
+platform/external/owasp/sanitizer 8ffbd60d1cca82c99868ac2c294728712674b020
+platform/external/parameter-framework ee0c104d80a842de004153ac4eb97f0a1e462087
+platform/external/pcre 16f15d49071dc8452f702e1f9cd405c1af9f7031
+platform/external/pdfium a93b8cbb101d01f16a389e549290f8742aac759a
+platform/external/perfetto 6a7389b1cff90740f218056884723fb99d1e8d96
+platform/external/pffft cfac4e82aaa4a6d41ca358bcd0437cdb644aee17
+platform/external/piex ba38b6ac8f0be5a7f68ca7d033649c4a9aa10932
+platform/external/ply ab121a19234df34b10909d05db0d9f36cfb35c3f
+platform/external/ppp 65cdd9217d2a8072d513fa18c6e225501b691272
 platform/external/proguard bfa0296b08076d8d97ec9b6cd4f41dc7d7edcc4e
-platform/external/protobuf 020be0f33d9d3db700155a3e5b06138fffcd5f92
-platform/external/psimd 624bc9cdc0715bb80e673d5893cfcb12797029a3
-platform/external/pthreadpool 86d2b22d62a098fc5b5d2094ff67eba1fa3c396c
-platform/external/puffin 908398a78dd11c2f4d13dcc832ee60a917405a92
-platform/external/python/apitools 8e784a666f937459e631359fd853d5685fba3160
-platform/external/python/asn1crypto bf560573d24c2d010192d40aef8f1d9f29bc90c8
-platform/external/python/cffi 9a4f3309921f6f2a69cb0307a1d05160811eb4da
-platform/external/python/cpython2 0c289fc12ab6094229abc798a49cc4276db16b2a
-platform/external/python/cpython3 e6f3df183cb817b39dc746aa4817431acaf9f279
-platform/external/python/cryptography c0dbb583fe644b0bc5a54a094e7e3291d151a073
-platform/external/python/dateutil 31a4ed7986e2e4d0db70c2e32925fb94808277a4
-platform/external/python/enum34 4e489488c3a4c11843dbb0ac6534865c9225053d
-platform/external/python/funcsigs d9c8e87dc037e7d6b0b2f32d3fba0c19a419f589
-platform/external/python/futures 3be64307897bbdcb905575d1c671041e1e595d5b
-platform/external/python/google-api-python-client f0988103975d0c5da639948745e508b4c3ede6d7
-platform/external/python/httplib2 5c630082f3ccec97db1539f08fc62d19c8fdc7d3
-platform/external/python/ipaddress 8ac78b7f0e8a22d0516483db3091df8f31cb2f95
-platform/external/python/mock de67e86d0e12aa3350d81a9395233a59dd5643ac
-platform/external/python/oauth2client 92dc35280fca125b60f9905574fde7768967416f
-platform/external/python/parse_type d07f2b14197c8c3fd46a140745f97d18661ad040
-platform/external/python/pyasn1 f5ca0386e1020963ac88346e44c0138146d0c776
-platform/external/python/pyasn1-modules b3485cd7ada7c47162a9e06a9bebf19601c822fa
-platform/external/python/pybind11 735ab06b11dcf5871ebfe61130fd5a5f4bfef215
-platform/external/python/pycparser adddba7570fd8347001f1c1a6cfc5ad7ebeac69f
-platform/external/python/pyfakefs b50a365b1ade5077998ca121ce50ba1e01f58e2e
-platform/external/python/pyopenssl 0fcbb65fee55423e68575f75990b832b3241f0e3
-platform/external/python/rsa abcc46d79241814ed506717f0cabb64644e4097c
-platform/external/python/setuptools ff0c219e07a30978c29ec164a8ba6dcdfa33a5d5
-platform/external/python/six adb0dba74b422dfb8ef83f93a4e0fde818646c8e
-platform/external/python/uritemplates 0cb74b873f902a57752315041fdfd266cf64b3ef
-platform/external/rappor ee81a8421e4d1e5c4f80a1a0ac8fa3b5a83bbd64
-platform/external/replicaisland fda5bd36a960f1323b342a31fef476d302baa98d
-platform/external/rmi4utils ce19a65506583e9790dead90e66f05d13b5da9b9
-platform/external/rnnoise e6b1746549e5cfc59a438ddd085197370b573ec7
-platform/external/robolectric-shadows 3e442e2e803fd941cf991d0ead509f1ebf98042a
-platform/external/roboto-fonts 7f3bb61f8bb6fb7c22e2b2244e21ea7c47fa88a7
-platform/external/rootdev 69158778d9664e3cadd0feea96bf8f06458c6d2f
-platform/external/rust/crates/ahash d527aa6887c0626c6a9790db06fb0f673ae1b96f
-platform/external/rust/crates/aho-corasick dc2acb2e8579ae95aa3969460fc03708721e5421
-platform/external/rust/crates/android_log-sys 55fd5d8c1044116ced321091ad878af843438ab6
-platform/external/rust/crates/android_logger fb81ef6c98d9207fdb87af7e333ba90c46ad39b9
-platform/external/rust/crates/anyhow 21adb845a5221f39135402a2858d62361122ef69
-platform/external/rust/crates/arbitrary e7a10d99a4f84d9b38c3fc539fc1b4ad8bcfc3ac
-platform/external/rust/crates/async-stream 647493e10df459f2e4cc4cab77918fcba6a887dc
-platform/external/rust/crates/async-stream-impl 4d90486f873777e1b8acfd83716d317ca318e828
-platform/external/rust/crates/async-task 99ac45aa74d283eb31b653275f72864557f75465
-platform/external/rust/crates/async-trait 03e5954829f106294e6b99bef5640c0e7cedad20
-platform/external/rust/crates/bencher cbcb0bd0ee1d920c112f664e8f8c2790dfb0607e
-platform/external/rust/crates/bindgen 178066f3bfe9102ef7f125195afe499fd8899aed
-platform/external/rust/crates/bitflags e336eb263a283db8409392bd4ae729e2ab8ed87b
-platform/external/rust/crates/byteorder 9c1ed6cf9d5fbf7db34afac3ddbca16b5ff5f26e
-platform/external/rust/crates/bytes c9437a46a49ae496b83585e81c54dd6776718338
-platform/external/rust/crates/cexpr 438e42efe2e34e90f6d5d7e35389bc00940a7bf1
-platform/external/rust/crates/cfg-if 25fa8cb2c22ee5abfdaf9fa9365b61fc01eaae77
-platform/external/rust/crates/chrono d9fc68355f1d9dcd0159dc65e53eb9a71435cc4a
-platform/external/rust/crates/clang-sys e324fd16aef528a1a380cc2bdea90fb9b523fd3e
-platform/external/rust/crates/clap dd2cd4423bac875226ac38928e9d579582ea4de6
-platform/external/rust/crates/codespan-reporting a90a69cc8071be8506baa9e4211447bf5eb2748a
-platform/external/rust/crates/crc32fast 9f04d26dc49fe815a98228bd7aedc239ab6eb738
-platform/external/rust/crates/derive_arbitrary fa5cbf736116271892806aefe6a0c21f82984cab
-platform/external/rust/crates/downcast-rs 36d9db99ba05278c68db164fb9d53676c0e55317
-platform/external/rust/crates/env_logger 98c05faa2e17d28eb0fd3e1d11912d1033738ea8
-platform/external/rust/crates/fallible-iterator 65cc588769e9ede2cae56fc988362cd85c701c76
-platform/external/rust/crates/fallible-streaming-iterator b6ebb2a942b303f76bdae01a634eb5047677de26
-platform/external/rust/crates/fnv d1e90553581a5865af318d8277beb5521c3def97
-platform/external/rust/crates/form_urlencoded 2c094bfe86dd3012996f00d06ebc287912020386
-platform/external/rust/crates/futures eae89cd6534c13efc2dfad5e065d3c42aa9d9f77
-platform/external/rust/crates/futures-channel fa4499fd1538b89f906a20009713ad3fd69fe131
-platform/external/rust/crates/futures-core 9a4d3048540aee91a3ece2eb7bd0166d1d86bd81
-platform/external/rust/crates/futures-executor ad82a4230f84f4dc06290ff0edfdbc5522aadc2d
-platform/external/rust/crates/futures-io f67f11684b541513e953f0a3df8df2e95ad04c8f
-platform/external/rust/crates/futures-macro c3586e0eca337c6573d6763f07cabe63ab633328
-platform/external/rust/crates/futures-sink 967d34f051f5fbf0137f97ad077ba3bbc6453ac0
-platform/external/rust/crates/futures-task febacb4ce6b6e7f43f7791dfc7877ca2a9b6a79e
-platform/external/rust/crates/futures-util 644930af7b8b68820fab3304117347efe1840dbc
-platform/external/rust/crates/getrandom 647a424fc855bcd4630814a896cba9935da7caad
-platform/external/rust/crates/glob 19e25f451f2c313ad9ea60b74785fee4d10c174c
-platform/external/rust/crates/grpcio 47604efb449a0e67da47ccc227fb773b3dfdcb6d
-platform/external/rust/crates/grpcio-compiler d851851242a981e239759bb48317aa044b7e072f
-platform/external/rust/crates/grpcio-sys 7b4370762b215e80fd471e10506b58e95d10cc8c
-platform/external/rust/crates/half 029aa05a8f11602b1ce5816d785975c8d0925f88
-platform/external/rust/crates/hashbrown f9672421f627a0a217095248238e12dbc76527e9
-platform/external/rust/crates/hashlink 26beee411095907b8a54b927e29708e7af3bb9e8
-platform/external/rust/crates/heck 817af1604dec3fa70f60cd1294de5c625ecee83f
-platform/external/rust/crates/idna ea1f06090b011cc3ac956c2ed494c7a2155b4dd4
-platform/external/rust/crates/instant 5cddf174013d2800339e5b42e330f5e55b038809
-platform/external/rust/crates/intrusive-collections 9db6ae012822c67e3d329fd36c1b1c85b90e6b46
-platform/external/rust/crates/itoa 43ae2ba3365d65b6efe2a72fc96e697f9a959223
-platform/external/rust/crates/lazy_static 3260febf1f9acec9c6c33312cccb388650305c56
-platform/external/rust/crates/lazycell 86b32eae9e4cae048826a54c262fa24dbb9643cb
-platform/external/rust/crates/libc 11cbf783ef1a0a1562730726f9b1c1963a2b54a0
-platform/external/rust/crates/libfuzzer-sys 05ddbe9040f2c20e250a24db0b452b084c59919c
-platform/external/rust/crates/libloading 25de5610a13af27a68362c8af824d9d3ea490d9f
-platform/external/rust/crates/libm 4face7054b917aa848afebc31ebccd7944b358c3
-platform/external/rust/crates/libsqlite3-sys da3b7ffd8f73011ba0e10b6cc52d84aa7c4226c5
-platform/external/rust/crates/libz-sys 529edd988331992e27531b126402d113227d6805
-platform/external/rust/crates/linked-hash-map 898788a110291683227b4828d759ab8155560672
-platform/external/rust/crates/lock_api 0f838b32e8260487872d1a77b9777cb6d91dc119
-platform/external/rust/crates/log 94c9bd5dd5b20f19a978b6afabf29c7ed25110ac
-platform/external/rust/crates/lru-cache d06bb2c71ce099a8743805e580c30b7d7e277b20
-platform/external/rust/crates/matches 952210330283a2ae00f1c4580bdae6c6cf902d31
-platform/external/rust/crates/memchr a804487cea7994f0743dd75ba3de8719db81989a
-platform/external/rust/crates/memoffset 05c58853bedc60de9b047cad09740b9809533da0
-platform/external/rust/crates/mio 91c9f860452812ab6371168d2803975646ee2e94
-platform/external/rust/crates/nix b033033cd7d254a2fa7cb1e234d9ecdab60cf6f8
-platform/external/rust/crates/no-panic 1e401efa6fc4707a71e1e7793c66c170051f59a5
-platform/external/rust/crates/nom 32d8a6a7f298488b76d0f5b2fc46d1ee51f8399f
-platform/external/rust/crates/num-derive 2805d59c1a900b2d9ed0493470082fdd81c23530
-platform/external/rust/crates/num-integer d189262964147beb60f33f6047bae2dac69719ee
-platform/external/rust/crates/num-traits 2538d74daebcda55d07992c0f30e4b4fa74cb1bc
-platform/external/rust/crates/num_cpus 7089b4c57600a53c3152035773fe1800442393f3
-platform/external/rust/crates/once_cell 2382f5a982e3fa8c5664356178f5e65a13bed367
-platform/external/rust/crates/parking_lot 117faeb662b1c658ce93b8df22515688263a6a35
-platform/external/rust/crates/parking_lot_core da4506cdd634c5a3586854f8d3785539cae53b5f
-platform/external/rust/crates/paste 62fdbd56ae741b62d1beb72cae07454edeb974b3
-platform/external/rust/crates/peeking_take_while 0028c2464e001bb80718e21b65195e1f1c984aa6
-platform/external/rust/crates/percent-encoding afb02dd508a042875e001e67a09280e81bdbd370
-platform/external/rust/crates/pin-project 85346b9ab073eec02ff79210e24e60de041f3de2
-platform/external/rust/crates/pin-project-internal fb4c34859d4c4a5edb171d10f4fcbbd3a1e5658f
-platform/external/rust/crates/pin-project-lite 8a3a8ab259a56a8020b7da88fee7eef6959642e1
-platform/external/rust/crates/pin-utils dc55560a13ddaca3e8976ae44b05afbee2a9b303
-platform/external/rust/crates/ppv-lite86 971fc07a1d83290862916dddd96b57ad6d5325b9
-platform/external/rust/crates/proc-macro-error 0177eeece2d8d8478d8f7d898069d343cf688d65
-platform/external/rust/crates/proc-macro-error-attr 6bddeab96be5c4ae0370f9193806c457f3d9b8e2
-platform/external/rust/crates/proc-macro-hack 1ec846306f145449aaa93d00d5c794b33cf407db
-platform/external/rust/crates/proc-macro-nested c1f33c5b2d41066f7567ab797f781703dffddbd9
-platform/external/rust/crates/proc-macro2 4e63fa00947dd9972a114f735b9f55980b31481c
-platform/external/rust/crates/protobuf e97d9b91a7c2a6bf65b22c35e6fecc9083ce4213
-platform/external/rust/crates/protobuf-codegen 90595cf4606ac7bfeb7e81c211d0b7a8cd37e94b
-platform/external/rust/crates/quiche 6c51d8f71227916400eded023e41145fbd224500
-platform/external/rust/crates/quote a8767d6007445475d70f0474fb7a28f14438bf24
-platform/external/rust/crates/rand b820d09f2a5bcef321e7eebe1b69cfefd03674f5
-platform/external/rust/crates/rand_chacha 2f73123ba636abc086339eb3b83222eeea647814
-platform/external/rust/crates/rand_core bfb8f10bfc406b156a2b0b43836cc3099d86d208
-platform/external/rust/crates/rand_xorshift 3804f99b15cd305c26199ccf5ab29b26f70b092c
-platform/external/rust/crates/regex 202fa64aba80cd6b6ac45caa786fafec0c5b23ff
-platform/external/rust/crates/regex-syntax 16633048c9164334c29ad87011c696e2ee1f27d5
-platform/external/rust/crates/remain bad806b7fbc309d3337585e8d8b9d03e37324e44
-platform/external/rust/crates/ring aa30f37bef10b949befc8e0ba264a784cb2861b5
-platform/external/rust/crates/rusqlite 02437b2b995111a4f6e0c52b9d65cba482e18a7d
-platform/external/rust/crates/rustc-hash db066d1f1932fa24f5450c9bb03d82ed3c8f0bd3
-platform/external/rust/crates/rustversion d550abe65fea6425374f69306f0a4e74585b238c
-platform/external/rust/crates/ryu 69a84c7e55062895a4fde9a560a42f445c35005d
-platform/external/rust/crates/scopeguard 66e3c154bcb450304aa395c17041160a51953236
-platform/external/rust/crates/serde 1efa3b4a1a8e476e429bd889719e242994adac7c
-platform/external/rust/crates/serde_cbor 137e88ed29967b3f098b4d91988afc90f6a2ead9
-platform/external/rust/crates/serde_derive ec2f37fbfccde85e71c251283328ee2c0bd5ba30
-platform/external/rust/crates/serde_json e49ebd23274441ffce11bc8bea0405b66dbb8474
-platform/external/rust/crates/serde_test 9816515e26b09a00a6c0209ec6b0bd6edfa1196c
-platform/external/rust/crates/shlex 93371c6a5b718109ceedbc7f93a4bb60b9078cfd
-platform/external/rust/crates/slab eedc7d1aabcdbd1a727162c6b1645a46b2a96c35
-platform/external/rust/crates/smallvec 6406713a8ffccfffe0e1e82ef3459794ef4f35c3
-platform/external/rust/crates/spin 2f6b4516854c3aa90eba8352a250d6b666a9bc4f
-platform/external/rust/crates/structopt 1b50f91c66cc7c124730391f4b5074a7b38c0bba
-platform/external/rust/crates/structopt-derive c72b26c5e5e4462382aabd1de9729506488eb326
-platform/external/rust/crates/syn c59c4b0e9768b419dd17d159eee89152e4ce49c4
-platform/external/rust/crates/syn-mid 1eba25ec6d604c37adaf191e662333669f3d0c4f
-platform/external/rust/crates/termcolor 976e8f49f13f80f1e9568c6c913c418e2e1db01a
-platform/external/rust/crates/textwrap 38adafb719c166df8cba7d001c4f2f9f6eab8a57
-platform/external/rust/crates/thiserror 92e2ed940ed58bea0ae96c594ea5b4b9ab23b1a8
-platform/external/rust/crates/thiserror-impl d3b5e79c010b7a218bbb739d97688d3ab62b2738
-platform/external/rust/crates/thread_local f5e8a9fbf538f85fe82373fa8cc6b0e99180f3f6
-platform/external/rust/crates/tinyvec db26643f05f3a2cea6c016116ed5e4a8e93ed5b8
-platform/external/rust/crates/tinyvec_macros 15b209bee4cb0e1bd7cd9cf5d03f07cd1fe57de7
-platform/external/rust/crates/tokio 9084d906105ecaa4d5b58ccde2dc1d6a12a486db
-platform/external/rust/crates/tokio-macros 269d77223e7af5e298af99ea665ae963632035ef
-platform/external/rust/crates/tokio-stream b504916fb6e9f99e453b4f0ec480da4b08e1e40b
-platform/external/rust/crates/tokio-test bf372733d2a280c7408bfa28ab8b9d8b7456b287
-platform/external/rust/crates/unicode-bidi 060211debb456d5ca713e2d5394363d51001d93c
-platform/external/rust/crates/unicode-normalization b51473fe72f4f44138749f6143539d0a09c84e50
-platform/external/rust/crates/unicode-segmentation e31efd194a081d40fe185aeeaec57e63e9bf1982
-platform/external/rust/crates/unicode-width 5e6d042284b7fb69a6ad537b367af5a069fd2fc3
-platform/external/rust/crates/unicode-xid fac55f4709386b069a7d50351c47a329fe459e05
-platform/external/rust/crates/untrusted 2d0585dae4e71ab2a743f5c371b5dc93277a8eb0
-platform/external/rust/crates/url 009788d5fe3e559e505ac9b199cc52c214780bd1
-platform/external/rust/crates/vsock 4a94720eb4959ed292ca0832e724d9c1280abae6
-platform/external/rust/crates/weak-table fea02efa947ee1b7c15b8de5fbb433f3508c579b
-platform/external/rust/crates/which aa49be2a837e76759ea96c764cba691bd966a5e6
-platform/external/rust/crates/zip f19c3f2587f29a0177eb1dddefc23c46504bf786
-platform/external/rust/cxx 6e874282a3cf92d32da4d9cbf63bfaa2d2777e90
-platform/external/ruy d23d5384ee2dad29223e8c57248ea83ec23da4bf
-platform/external/scapy de08aad24b9b1dc9cfc95bcca418d90800297d15
-platform/external/scrypt 8a4f74607bf67a12aa39b0cb6bb5a598d84cc05e
-platform/external/scudo e3cde3ad11bc816772604f566a2915e29edf985f
-platform/external/seccomp-tests dc4b4fd458f245081ec019f1b83735d9c51d886c
-platform/external/selinux b921c8248b93365bbbed8fa2ae61d0cc7c75079c
-platform/external/setupcompat c36615c44921d5890389d7c56f0991a9a44892fc
-platform/external/setupdesign e8ddd9b950751f4d2f1c1cc39059a91b693023aa
-platform/external/sfntly 4b08e5b078752ef38b49ce723e29e0f0aef8770b
-platform/external/shaderc/spirv-headers 948185b8f59d57b8252b6b51502ad13167018305
-platform/external/shflags f099443d156ed814e15951f964cf394714ff623a
-platform/external/skia 0f2908e678dc72fb1d3a6a5c917a4fd7966a3ad8
-platform/external/skqp affe6858e8381b66b2d579304749be19e04ba264
-platform/external/sl4a 4025ba1f99d3407597b41376c40bc9dc92d715a3
-platform/external/slf4j 1fba4cf506028e2675d53b29784abf9a1ff39c15
-platform/external/smali fa0f228fb3b75edbe57d05c99c4319e45a110a04
-platform/external/snakeyaml 25bdba5947d69b6712e3df34c1f6655ce10f4946
-platform/external/sonic 96a659bb6a0098ff45a3aabce9edc15358114399
-platform/external/sonivox 524f87758ef8e032fcc1e9c2932f91efa1886ef4
-platform/external/speex 7472c2b2bbaaacdabab8ff8489bfc4049001ba45
-platform/external/sqlite 29cb3ef2e960c81c665f0668c7e9f1e1508da3f5
-platform/external/squashfs-tools 54377b5618eef479d03cbc3baa86182b9f054144
-platform/external/starlark-go cb4dba6bd6c53d73b52da16d0378834a872348c0
-platform/external/strace 33fb16ac1435c28f3594f029ccd9162e3de3db0d
-platform/external/stressapptest a078d71e853cc5fac467c763283fc27ae7d3df11
+platform/external/protobuf b36be836bcd26e445bdcc69217cfe1740e8582a1
+platform/external/psimd 01c349a4b15e782e27bfb0dc78d27c7e3e05f2fb
+platform/external/pthreadpool 1d1a6dc9ab65dc5aa1729db61e9b0cd59a7af913
+platform/external/puffin 035be165606dea5b5cd9b423deac9ce92631c2f5
+platform/external/python/apitools eeb5417b45e0c5c8a9eb6a2c0f07f981906f5de9
+platform/external/python/asn1crypto 9c22af8c1188a0bf9e6f98635b2aceec2df8a0ee
+platform/external/python/cffi f92333f776e7fda763426659da9d56a7a639dad8
+platform/external/python/cpython2 61e068cfb3bd280b87f54504386c83b71fd88c14
+platform/external/python/cpython3 f8c6d0f21375430aa69d2ea7eca99dd8e6b50796
+platform/external/python/cryptography d96243976389bb3101ac49fd198809caa1271ea5
+platform/external/python/dateutil 328673ab96c299b52aa7a341cd15a3dee083f630
+platform/external/python/enum34 271b268ba8ccb35b5093cd968e825f0ed095595e
+platform/external/python/funcsigs dddff0bc89d70fe4dd36c86898201f3d60278de8
+platform/external/python/futures 9734edc53e8e736f20026ba95a254465aa283eb3
+platform/external/python/google-api-python-client 294a9adb31ded774f8a5b91261d9e74b9df5fd16
+platform/external/python/httplib2 c2b04d092b760a862e089ca9aad8ed99af29bf66
+platform/external/python/ipaddress f0e6bc259e9895d40f1682720cc9a364ed202a97
+platform/external/python/mock de9e96a41e060f40737bccb5ac8ca6ea12c631c2
+platform/external/python/oauth2client 346be5d0b2f31fc3e03b8276005c61ed32434ecf
+platform/external/python/parse_type 218378034f7765ec264a3a8f9dabc89cffb13453
+platform/external/python/pyasn1 f885563e3384f4cb7e136a117a7fff0a7211e397
+platform/external/python/pyasn1-modules 6ea2cedc592d6e40bc4b505fbf197842f0611b08
+platform/external/python/pybind11 2af81ac3501c16c1024d3eb83f9f09a2d65f2369
+platform/external/python/pycparser 9edc6e366f37980e79b2f828c05404e6d5827341
+platform/external/python/pyfakefs cf902c0d7ab8c6af7d7051f19cf6ce275843ff98
+platform/external/python/pyopenssl 69d9841b1a45be8410f54e03c5edadf02899929c
+platform/external/python/rsa 4b780210749e833e2de47a6e9f23e6890a7a810f
+platform/external/python/setuptools a6f5ff79328cb9723a40d5214ffe18b2260f9786
+platform/external/python/six fd95f3cd5b3cf59497b621e1dd6654f367b19934
+platform/external/python/uritemplates e969465bbcbf71cd6ab41388cc6413cb77c5fd4a
+platform/external/rappor 788aff89a46653e03ebaa66f4074efeea9819e70
+platform/external/replicaisland 7ec7e088b04d51a1dc214c09b44005e62f342e06
+platform/external/rmi4utils 02df8044122d633e4da4d9d5b7755df85e3a9d87
+platform/external/rnnoise 18da53dea1323b76b515d66718a125698c1ffab2
+platform/external/robolectric-shadows e5f205c8e2b52b8e11583a23adce804615a73255
+platform/external/roboto-fonts c9420042d7446d773970ebb69c787ba04c54063b
+platform/external/rootdev 2165c91c014ab9192c4e3248fc120a2c547c05af
+platform/external/rust/crates/ahash 952524634dd0a1e7d865d9014cc8f42b17de16ea
+platform/external/rust/crates/aho-corasick 44f1ca4ab300d3c3f43042ca8cf7eb3fefb17166
+platform/external/rust/crates/android_log-sys 5383b8ae56a1e15043477e2443f949565218d35e
+platform/external/rust/crates/android_logger 3ae93944f04b2274933221a47e08ca2249a73e6a
+platform/external/rust/crates/anyhow a4a973e03be938f6d3134df77551729fb62bea50
+platform/external/rust/crates/arbitrary 96925396f7a7b8b11c403abe2a6c0f7341818df0
+platform/external/rust/crates/async-stream 70d6a9555980c06ea9abbf8150869b67aec16cfc
+platform/external/rust/crates/async-stream-impl 3368b8e6c8d79dbecaeb8ba98417d87d0bed6ab6
+platform/external/rust/crates/async-task 3b14109130cfb750c9e8bffbfc48b0b041be5547
+platform/external/rust/crates/async-trait 54ac312dfe78c3813a9b679ae4f2b292b10b1d88
+platform/external/rust/crates/atty 9ca1d16d50af5d53d81bd40a0946cdd0a315998f
+platform/external/rust/crates/bencher 106c9023911937d4b43f749468de8aef23229550
+platform/external/rust/crates/bindgen 6563756eebf69524e17eb078328089651f0294c4
+platform/external/rust/crates/bitflags 038365eb9080414105ba1f9af265f4ce6b5963eb
+platform/external/rust/crates/bstr 93bcd2407d663bb37693469d728ba1018253f9e2
+platform/external/rust/crates/byteorder a8439cf050cf8c818d15a9e2b05820ee890931c2
+platform/external/rust/crates/bytes f81e85bab2d0176e176a9931b84abc34f4bdfba7
+platform/external/rust/crates/cast 9052e5cf294fcf64d62a13921cd2e3738e5d6de9
+platform/external/rust/crates/cexpr 5b467c582a16574ed34bfd0e06d3518e0be50730
+platform/external/rust/crates/cfg-if 08460e33f4521eeb95794d1f5be065e63af73642
+platform/external/rust/crates/chrono b14b948689b3d71e17ea4533572276aa0aa256f2
+platform/external/rust/crates/clang-sys d50e74629f6664cd1a533d874cd5400fd28f6c71
+platform/external/rust/crates/clap 98a2fa4fb0bb6c17af3a58afcb59668a971a9236
+platform/external/rust/crates/codespan-reporting 6f1640b283775516fbdd74c6cf82dbb84d3eba13
+platform/external/rust/crates/const_fn ae47280e989846edaae234a1f952fbf4faf4c088
+platform/external/rust/crates/crc32fast bcc1adc9805a318a1764a06341375bc13588fc53
+platform/external/rust/crates/criterion b2bf1f96868f7919f21f666774d17e6f86074dea
+platform/external/rust/crates/criterion-plot f3b262a754e9da78a6f1a05ebd85ab625bbe97cd
+platform/external/rust/crates/crossbeam-channel 4e850f873f26fcadb4b8f312f003a9943906ec4a
+platform/external/rust/crates/crossbeam-deque 61bb216194bfd55010ee467365c7f67deb041699
+platform/external/rust/crates/crossbeam-epoch 97bdd9a85ff41507167dbb57d5df851cc93da576
+platform/external/rust/crates/crossbeam-utils 263d6280a513adbea2b8afb8770396a581f710d9
+platform/external/rust/crates/csv e38b601d94bfcbb48d70eb23ebc377e05b5224fc
+platform/external/rust/crates/csv-core 20c025f1b0b508b0af34c83264bd7cfbf1caffa9
+platform/external/rust/crates/derive_arbitrary 1cc16f216da683aa2305449deeeaf55c6651740e
+platform/external/rust/crates/downcast-rs 2697403dcd33278ccdf96ed18da6cce7ec508cf2
+platform/external/rust/crates/either a8b7e727411f8eaac6d42e6c641c55c3d6c15248
+platform/external/rust/crates/env_logger 26173d2258d99194e8ab1cc17c3a60b6f05f59cd
+platform/external/rust/crates/fallible-iterator 85f59a155b3ba387694fa82561244f08061c32cb
+platform/external/rust/crates/fallible-streaming-iterator a189ec772b0caa7943c6802cbf875d0b9a730c5f
+platform/external/rust/crates/fnv c5d9872ff1129c27c64b31d10ccbb65a9b66ab2c
+platform/external/rust/crates/form_urlencoded b1fd1db7b5100276938e76fb8216d91cc87b0be8
+platform/external/rust/crates/futures ec1b29342a73fc28ddd5b776630e58bc6b628a19
+platform/external/rust/crates/futures-channel 735552c6b7cf75e05b398428495103d17170e0a0
+platform/external/rust/crates/futures-core 4d3b068c8c77bef1d893924aca84d897a15f3d9c
+platform/external/rust/crates/futures-executor 2e616faf9879f346a14d280cc62a98bbd316e09c
+platform/external/rust/crates/futures-io 76e8deb77857d1043382bdd5781f9e0d67ab3230
+platform/external/rust/crates/futures-macro a78d0e06ab2bf930f21f292bc8eac7b8bf472bdb
+platform/external/rust/crates/futures-sink 9cb53d543e6206b2d038b0022669f1876529d69f
+platform/external/rust/crates/futures-task 9736ec7295a0708dda17485228398342fa9005d6
+platform/external/rust/crates/futures-util 610e9acf06206838b99deffbfbdb9dfac672288d
+platform/external/rust/crates/gdbstub ea19a711b08437538c898b9bec96858a5b4ebcc6
+platform/external/rust/crates/getrandom 39a493f96c2dae9199d7bc61184b77000eda78d0
+platform/external/rust/crates/glob 233233e2623cb6c8f4981bcf62272bc9eb9c43f1
+platform/external/rust/crates/grpcio 3313e3553dc45acaa029f4301f67316464e558a3
+platform/external/rust/crates/grpcio-compiler 20e34dfc99bd0821d7dff24525e2331341fbe5f2
+platform/external/rust/crates/grpcio-sys 53bb38819574dfac24ae290f70b08dcd4874f1a4
+platform/external/rust/crates/half 7a8e6e82be27379a98c06b8c4304062ae2b85a87
+platform/external/rust/crates/hashbrown 5ba24bfafc4f5067cb5cba16c534dc74352459d3
+platform/external/rust/crates/hashlink 756e10600bf711cf50237d2f5de0c1b8e39de58c
+platform/external/rust/crates/heck 66971cac2f68bf11c7742d645b19463638a90f15
+platform/external/rust/crates/idna e0e454a9368a9a66939765111d3fe83923bff047
+platform/external/rust/crates/instant 347af6d25b4e89526a245387e27be5ac85876304
+platform/external/rust/crates/intrusive-collections ea25458e6987cfcc539ce19dfbe076415180a105
+platform/external/rust/crates/itertools d5cae2a1f03949475be95ca17bfef8258ae3d383
+platform/external/rust/crates/itoa ed4e56a45848a3667583fc2df206606c4db39da7
+platform/external/rust/crates/lazy_static 3ad5e96f0403b3c4d4a6199e27765839539e76fc
+platform/external/rust/crates/lazycell ac99b47a342736eeacfdf49639dc4d09063e8401
+platform/external/rust/crates/libc d444e9af5184cda88ad33a1d2df27c080295ff4e
+platform/external/rust/crates/libfuzzer-sys 19476ee6a1de21b0a31253550af07d31ab26171e
+platform/external/rust/crates/libloading dab5a8be78d1494b0aa35eff124954b231cdcdee
+platform/external/rust/crates/libm d508dc31378985cd92fb4ad5f39d3b0fdc1a7e9a
+platform/external/rust/crates/libsqlite3-sys 2f70cfb763a16c0999727c01e72f72d0df4d5a0b
+platform/external/rust/crates/libz-sys 128c355f7aeb8b643ca47cfd28ee21af37bdacfd
+platform/external/rust/crates/linked-hash-map c0cf444f5288d5ade6a09a779bb29ef4747c4d05
+platform/external/rust/crates/lock_api 3544947cb88e442d47e7962db473df8fc289df24
+platform/external/rust/crates/log c5250bf1e781240f16af229e9007c5a844fc49c9
+platform/external/rust/crates/lru-cache f7aadfaac3f840d58784e1a3e07c4160a4316ab5
+platform/external/rust/crates/macaddr eada2d10054e8afc8d887e928e58476f2493909b
+platform/external/rust/crates/managed e4b5ebd6163380207c4342d6300997443096ac59
+platform/external/rust/crates/matches 5d9adc44a1673652a35b6496cc94266c249de348
+platform/external/rust/crates/memchr 9e31ff246bdc13891a0d0fa2631a184f5d5c1e2b
+platform/external/rust/crates/memoffset 5f38ffae5da6234c9421b6f2cdfd5de96a90e934
+platform/external/rust/crates/mio 43f97ca714219203c5c54dd32ae3cfe47a91a41e
+platform/external/rust/crates/nix 12f7b75bbc52a46da676b303dd25a82b34b8315e
+platform/external/rust/crates/no-panic 192354e107aacb9fd80684ca3801ae7cac9720da
+platform/external/rust/crates/nom 91601a57a003791219eda34747df12bfe0e15ddf
+platform/external/rust/crates/num-derive 8473012f7f66175d53adc45dc3580682214cbca9
+platform/external/rust/crates/num-integer 20c007cd88889962b349e064d4bed08c9f2d09e9
+platform/external/rust/crates/num-traits ef32c88ba603db392f765b2f1a40f4900bae15a6
+platform/external/rust/crates/num_cpus bb5b7c7e0f65b98a189f883c6a08a541317e4705
+platform/external/rust/crates/once_cell d50fc47a81900a02f5f20c9635407574e8c7d8f8
+platform/external/rust/crates/oorandom bac64b1b46ad58f2ef8c9dbe1d9504ed615c18a9
+platform/external/rust/crates/parking_lot 51a3e42d4ac7a0c9e73480454a84475928578089
+platform/external/rust/crates/parking_lot_core 50b83f1aba40eaf1b02c4d3a404e1777430cad2e
+platform/external/rust/crates/paste dc96824932834aaf3e76e5bf44cb158fc2421484
+platform/external/rust/crates/peeking_take_while fe16cae924694b5696a216251304b7c48271beee
+platform/external/rust/crates/percent-encoding 302c4bb45f80f16071ce47958067ea732e522175
+platform/external/rust/crates/pin-project 1671fac2b00e73222dd1bb4cb5bd3508a5a0f8da
+platform/external/rust/crates/pin-project-internal 36ed9adda514554e5d51626553f3708f3bcb4220
+platform/external/rust/crates/pin-project-lite 28d3909a0c51366513689302f460f2b241a3fd7f
+platform/external/rust/crates/pin-utils bf83c6a4c3bfe5f183be383eb8ffd322649a956b
+platform/external/rust/crates/plotters a26b03b08a03659889e5c5ad09b6c59403e26511
+platform/external/rust/crates/plotters-backend dbbe6ad8a05034d93d7518cd306f8b12a74ad0bc
+platform/external/rust/crates/plotters-svg fff638dc4b7b439bb478723935fefc7318736355
+platform/external/rust/crates/ppv-lite86 8f59b65398abec6a3cb27a359204f64365e0f3ff
+platform/external/rust/crates/proc-macro-error 4a262fa07d6d190531b3f5b7211d743e057fb2cf
+platform/external/rust/crates/proc-macro-error-attr 0fa3d3d713fa9c002e16cd3660d55179ee18d081
+platform/external/rust/crates/proc-macro-hack 0fd11e2d4707b50ac15710e42572b3052c0135be
+platform/external/rust/crates/proc-macro-nested a57bfc75adeb662735c642a2defdaf02b38ab098
+platform/external/rust/crates/proc-macro2 10670f65628de2b8943552610c1a4ebdd7ac595f
+platform/external/rust/crates/protobuf ba5d027f2f5706c760c06e718be91d8fa908e599
+platform/external/rust/crates/protobuf-codegen 65142bdeb57c0312d447797269b4d80f74d3ef14
+platform/external/rust/crates/quiche 293cd8c2676a5c96b8e26a8cf6376468f52df771
+platform/external/rust/crates/quote c6aad879e0a3738a0dfbcdc8ad5bf51f9ed50176
+platform/external/rust/crates/rand c8608c5723d99e9f5a3ebdd703bff49e9fd09c09
+platform/external/rust/crates/rand_chacha 67ab922fafb780aebadfa2dc28a3090bae9affd2
+platform/external/rust/crates/rand_core 602b40f2afe2640d6b68e5a0c4b7682ccc7b26e8
+platform/external/rust/crates/rand_xorshift 7ee620b5a649bf0f3ad7b1ec068889971e863ead
+platform/external/rust/crates/rayon 699324d3cc479ebff3dac92150ed34f2205ce5bd
+platform/external/rust/crates/rayon-core 447f9f94ba70f7f9318e44bb61849c051a7a7012
+platform/external/rust/crates/regex 9d191d5c7313c5e0c97bc3098176a4f500330621
+platform/external/rust/crates/regex-automata eb099668ac591e76b3560485a57c847a4b7d2557
+platform/external/rust/crates/regex-syntax 2ee3e915f2858e4ed0558497f9ccbf69c742dd56
+platform/external/rust/crates/remain ae19714a786073db4e1722acf7b1a763d3ba6120
+platform/external/rust/crates/ring dd64b56f4b9f44dea3cacf82367768583a5b0560
+platform/external/rust/crates/rusqlite 1a7d1e3dcfb4ca1e21d1d27c79c6841ba55df6f8
+platform/external/rust/crates/rustc-hash 47ba03891a06576a065d642ac43b363aef30cb3f
+platform/external/rust/crates/rustversion e5271197d6560cea96dabd523c2e502095645876
+platform/external/rust/crates/ryu 82350cf467b9a293176b708ac14c6714747a757a
+platform/external/rust/crates/same-file dcb367a164a08a78010649c9f919fe6d2bffa9d2
+platform/external/rust/crates/scopeguard 97e3a6b3c729800d99a01dbf4d6058dc2377ddd6
+platform/external/rust/crates/serde 70bb6590dcc1f564b95b688728689640d545d14f
+platform/external/rust/crates/serde_cbor 2b161068bbf4f9bb63a1b280d1a211233984189f
+platform/external/rust/crates/serde_derive 78fc898d3cec206490d0de6e54dc65babf723717
+platform/external/rust/crates/serde_json 5c97bc4d02eca24d368000317f8fea805ce56e28
+platform/external/rust/crates/serde_test d89b54751ed0aaae420de971c6c3c2a36cfd47cc
+platform/external/rust/crates/shlex 065f0049de1b4b5150db01f3353300d6f5be3c95
+platform/external/rust/crates/slab 1c25355efcaeee818f6e8ae3e8693890bd521d35
+platform/external/rust/crates/smallvec fba4dfaae62023b0a9d11ed852efc15560eafbf1
+platform/external/rust/crates/spin e86488665aae2f17bfbbb47bbf0f0a81d8f0d501
+platform/external/rust/crates/structopt 2a6733136772c9262877a067d8544f2f8fca16fa
+platform/external/rust/crates/structopt-derive a36a1bac8b056798ab69ccd6ff0e5e688b50ff5b
+platform/external/rust/crates/syn d92d20cc5e3cab005c9674ba980ae9d86880c99f
+platform/external/rust/crates/syn-mid 5a99f929393959681d27269a740563a8548b6f7e
+platform/external/rust/crates/termcolor f1d119b20479350ac9de281a2f19f11253034fd6
+platform/external/rust/crates/textwrap d929d03a191e3e3dc592165595bfdcac66173435
+platform/external/rust/crates/thiserror 5ef3bfcf6501ca2fb6604204f718348dbebd0979
+platform/external/rust/crates/thiserror-impl 9acf801b75dfc73507f7c16877bf93637487536c
+platform/external/rust/crates/thread_local 915004701e55936da41b9d1da4b51973c2c68cda
+platform/external/rust/crates/tinytemplate 0dfdb24b451750266a2b5170f53c349595b39f16
+platform/external/rust/crates/tinyvec 225db40e4ab47c4342bdc7552582b9074f8e95fc
+platform/external/rust/crates/tinyvec_macros 9a6aa677a42de6942dd80db627b54cd577d1b011
+platform/external/rust/crates/tokio f8fb3d3eab976cf71f3e53d597110ad80c8f750a
+platform/external/rust/crates/tokio-macros 4cebb0f4d1d67d7a5e405b8c2130fe129cddacc8
+platform/external/rust/crates/tokio-stream 5a784843778255954e2c41eb79599a1902c180b7
+platform/external/rust/crates/tokio-test 8297a828173959dfff407010ee46a9a075f37155
+platform/external/rust/crates/unicode-bidi 9226c4341c9633d77ea5b665eca5d1c212fe3919
+platform/external/rust/crates/unicode-normalization 62cffa2bb1a250114d096d021e6655520324f9db
+platform/external/rust/crates/unicode-segmentation 8c368a605da0a06704598957e11938aa9b1c9d90
+platform/external/rust/crates/unicode-width 893c7a3b4d9bd2cffa2e7d3f557313174797b9dd
+platform/external/rust/crates/unicode-xid ab9f1d40adace6d2ec2f621536e2d9681c9eeedb
+platform/external/rust/crates/untrusted d91feb011b504c311f96ce2db5b8010a99ed60c8
+platform/external/rust/crates/url 3d7f0c81167f9ee8c8e0f3a53d4cdfbfdaf955cf
+platform/external/rust/crates/uuid 3ca66ef49829d82b6e070d7120e4f4273e6a5bce
+platform/external/rust/crates/vsock b742081c14552bf57f629ebc6a7099c8e8ad4737
+platform/external/rust/crates/walkdir 630891f6a11b27e3f7cd00845aa357dedbc4571c
+platform/external/rust/crates/weak-table 756f765db8187ce3a0c5bda473501e727818315f
+platform/external/rust/crates/which b14daf1fd98a7dca9971759d4a448ab1d992d020
+platform/external/rust/crates/zip 1d10557cb948d75f5cbb5ddffda7ed33c4429ec9
+platform/external/rust/cxx b12aa19891c1286bc07489bf0c310cbe1b0c3f39
+platform/external/ruy 3b52a0f7a36241b7d1a1c99c43af095de1291eab
+platform/external/scapy b8933d42704b00904a3b73904e46cf988b05b697
+platform/external/scrypt e006d637afcf02ba6268d308d97ef672fd71c77a
+platform/external/scudo 14b9996976a4a9d3eaadc52837d3bca0042b3d37
+platform/external/seccomp-tests 352f2b0cc752162b336c66b85688fe783e05d8cc
+platform/external/selinux 160611f92a46ae6d82e8852361ccd47b4a33939c
+platform/external/setupcompat fde5fe879bdc12b8d6883843cecc4af026a14fad
+platform/external/setupdesign ca1d4d6605ae48c4de5964070430625a8cfc3ccd
+platform/external/sfntly 6a7d565d5ac1c7903c631790be6d6ff40359d14f
+platform/external/shaderc/spirv-headers a08a7e5681c2e3eb2564d33a20a5b358b2055d8b
+platform/external/shflags 8eedc123e267113906dc41c77732170e98280eae
+platform/external/skia 5223a532200ec0811d6d550d4fd1cf4aad701dc2
+platform/external/skqp 5fcd03ae45c679f6ac0a2b68e930a15aa303412e
+platform/external/sl4a 587babfcaea2e51b04b8295e96551566cc594cc1
+platform/external/slf4j ef0004e1f9341d90d961b854984cb18c667a3f4e
+platform/external/smali 83218751843cae10bbb1e3131c5238a3d1f81327
+platform/external/snakeyaml 71168865948567b4ec2b18ac3a3ab297a7f1f80d
+platform/external/sonic 2aa07d273386f3a94bc533c36b396bd3e832ea6b
+platform/external/sonivox 93e5ec2b14c36892f3d93df3f59bde3a731b18f7
+platform/external/speex 596ec77be0b48353862a95fabf897d9f8bc53d50
+platform/external/sqlite 2c8c8893975dc88830203bde7a5c6c4623303062
+platform/external/squashfs-tools 54f4f1723125a38d901abf19a446dfe43f717054
+platform/external/starlark-go 09aa8587d4ac47e6e336a3b1446843062541d442
+platform/external/strace 46a0ebf44f14edfcf512b34790ec6dae82c53fbb
+platform/external/stressapptest 2bd0e6e40eb152d8491f37c58feac80a08543fbc
 platform/external/subsampling-scale-image-view 66ed9ce49803b856050477aa07d042bca4023738
-platform/external/swiftshader 46db842253a1b5bf2b562716c8ff6be48b62ebc6
-platform/external/tagsoup 805050e30f11c3bbe5fb151ddbd9e2e1ab93f315
-platform/external/tcpdump 779a014e9f2d03c08583b2a18bd4fab156b4fef7
-platform/external/tensorflow 7527e5a31ad0f25a337495e76d4d184754db9461
-platform/external/testng 35fea93a6bd6ad3407fec8f457e498239f16e13f
-platform/external/tflite-support 986ea2d63afb173b99c2e8492b87823d8b3e3bb4
+platform/external/swiftshader 710a193d239d45af2d4d4b0f000961a8d990d786
+platform/external/tagsoup b1e8dd98238c5ffba89d1f8746665fdc1397b8cb
+platform/external/tcpdump 9af85a2d7ab48111e2a38450fbd53d5af60518d4
+platform/external/tensorflow 4f00753acb1d3983b29b2cae80ebcc99c850494f
+platform/external/testng 1c57ae7528a682c9b91d0756a82743b86bf18daf
+platform/external/tflite-support 5bd72dd6089f6a0ee9911cec0d3028ea7f53a2d8
 platform/external/timezone-boundary-builder 671355f22a1368e27b8c588bfab35abf30aab0f0
-platform/external/tinyalsa 0eba66ae1f6f07b8eda0b9665a8a75eebca3f60f
-platform/external/tinyalsa_new 4b144d6765e2e1a01a8d6c79794e687776360363
-platform/external/tinycompress 92775f417f373bd5deb8615b2d9b53aaf83eed47
-platform/external/tinyxml2 d6734e4203693d4b40edcc8c735ab772a51a4c0d
-platform/external/toolchain-utils dc6e28ebc3b8768cb9f4165dfd02d8e7123a3fe3
-platform/external/toybox 14e73f87ba2ebf4a9dc4a2eadd4dc9b8968c33f8
-platform/external/tpm2-tss d76c8554b0d99f98e36c29bf2b2396225c5ddd81
-platform/external/tremolo fcf230c0bd8e80ed8796d73a2b3c87571ed93aa3
-platform/external/turbine 8f086eda21ab19c3c2ba502f07166c9f3b15581a
-platform/external/ukey2 a611c4714eefe798367839e15f1be381a26f7a84
-platform/external/unicode 35f79e74cfad2d4c0f68623d93ca0691830ced37
-platform/external/universal-tween-engine ab6d598a15243a3243ab34fbb118857c4a79e835
-platform/external/usrsctp e929f597b746d9707590a5c5558afad9902f36b4
-platform/external/v4l2_codec2 0e44f3a8fd26fe19088c1386690773e357a85599
-platform/external/v8 bad680f00096bfe0bec29f961249807cecd70ed1
-platform/external/vboot_reference 5dc2ad5eeb6caafdbdcf7474dbfa5bc634909369
-platform/external/virglrenderer 050bfd0912d76d633bf352e7aa580892e91c2608
-platform/external/vixl f42ef7bad371eb699471220c5c218d132f10c965
-platform/external/vm_tools/p9 98be033c49df45e9d25f2b6766377ff6837a4e0c
-platform/external/vogar 9c1ff46e47dffdb509d434ea1f2a3d6f9c0bb54f
-platform/external/volley 9608a90ef85b1d02ac4e12dba20ef82ad80ea7c0
-platform/external/vulkan-headers 8a2e3eebd18504a7c33d6b1d4ed887a95dc3bb0a
-platform/external/vulkan-validation-layers 405f78b556b791c49d013d0b7a5b7647860d8784
-platform/external/walt fbc2792a6a214cc66ab52cb6baf3a3ead23adaa6
-platform/external/wayland 5c6fc4d36719b178a50df89ab98831c2c742b881
-platform/external/wayland-protocols 668de5236c35fdd76a7dd84f54c78799e8d6b3da
-platform/external/webp 4000dbacfd1ff121acaf57d1480d859018c6a2e4
-platform/external/webrtc afc46b6cc8f89778876d0393dac9a3e73363d43a
-platform/external/wpa_supplicant_8 196073d0efe6b80a101163ce7ecb34011d54f858
-platform/external/wycheproof 2299b63e4ba214c5c1fc8282cb7bc7b843f439ac
-platform/external/xmp_toolkit 96f5158dfd52dcaa025aa2df2ccb5af54b515fe0
-platform/external/xz-embedded 3c1438c67e3ff1c2105f04767ea284995d8f57de
-platform/external/xz-java 1ff34592d0914f83e41f4edbc620006c3f011211
+platform/external/tinyalsa 8528a8ada4bb923a07020bfec8042991439aec40
+platform/external/tinyalsa_new 34053131deea237915525bc1d36c838f00ba2ff9
+platform/external/tinycompress 18941d7850002a9156f31fc3943a5e23c84e8dc3
+platform/external/tinyxml2 99acff1ff9c02deb1de7f7076cdd04433a4b9845
+platform/external/toolchain-utils 49ec48cec374b8c0a1f84fcf5a5fa624c218cb89
+platform/external/toybox dbfbac1a898fd515c2b456914cfe7d272a31f18c
+platform/external/tpm2-tss ba4e8bb3cb2e44af3ae4d84bf501f6188f9cf9a6
+platform/external/tremolo 3723c30d501c1509cdcdf67ccba177f8434377ce
+platform/external/turbine 62fe80d751944a5af55515d2ff4dcee9d1db000b
+platform/external/ukey2 9786f3980f273f8c67252f907e46cc536f2bd105
+platform/external/unicode 5da89f98890fbdd85d36983540f618a6f55b5fcc
+platform/external/universal-tween-engine cf58e0e0b2229b85a5bd054bb9d76029963d2c5b
+platform/external/usrsctp 62de64b3e7e0457d510f969a2854b3739892f99f
+platform/external/v4l2_codec2 0ef0fc6904b08f293cf4cfb931111c9a0abcc694
+platform/external/v8 cac2d79761fbc4d288448ec52f199f17987eec4c
+platform/external/vboot_reference 3e7aab95ef007313fa78b9346da1e451a838b5ce
+platform/external/virglrenderer c435b8e73249e329f28d11de83ef828d77aec1aa
+platform/external/vixl e68f649be096c0e0589200ecb3e335d2e59a780c
+platform/external/vm_tools/p9 255b5eef35089824c663427c0a61f36657cc4f75
+platform/external/vogar a581125e5aa26788e42ecd2df40a15642c9356e6
+platform/external/volley 49167d7101fadce800f9fa327356e2ab126f7e7a
+platform/external/vulkan-headers 441b1835f9ae5429b03b440ff50657fcb2b8b25b
+platform/external/vulkan-validation-layers a572c23b0e165b73605b4f4ff381804c5b4f2be1
+platform/external/walt ab5628e8edc6133f8e50c22756bd910f456372fc
+platform/external/wayland 802fabc5d6032fd6a07149e04017f3c60824fea5
+platform/external/wayland-protocols c7e9e2ef9f68b9b3cd7d06d2c85f5c68505d6aa9
+platform/external/webp db6b4add3f7b5f2ad4dbba90baa015e22dfd85a1
+platform/external/webrtc 06b1c70722ca056358b8421bd421fb038b96e938
+platform/external/wpa_supplicant_8 9955bf4f99c76ef3842ff5528255af4f1a65a189
+platform/external/wycheproof 39dea66ba7f8893a2d3a61dba9bdcd2651afbfd7
+platform/external/xmp_toolkit ee2cdbe283905314b53fa21dbfa60dee00cba4cf
+platform/external/xz-embedded 2e8bd4287eebc2524750785665c39e9c1a4d8dad
+platform/external/xz-java 0a5723910e87e33428922862e87f2a6cfd99aabc
 platform/external/yapf e415f242082fa26008fe75436c0dedb501507848
-platform/external/zlib b69db4513031e1d60ee19b728275e6f51659085f
-platform/external/zopfli 84adb162e7ad28048fe0c334c64db2f92e6476ba
-platform/external/zstd 864533234cf1e7a1b0ebf1a6892f13ae610b0ba8
-platform/external/zxing 8dfe5d4c319313f3bde27b2212e90b03fccbbb42
-platform/frameworks/av da2d025d8fcfbc6b3045a4ae7c81c06583585467
-platform/frameworks/base 91383486669855316743246b537d2482522f2cbf
-platform/frameworks/compile/libbcc ada5ce9209600c62ac2bf8d9f376a150a2280f31
-platform/frameworks/compile/mclinker fd797d93a8c360e1fa8ca57b84709f093074ade7
-platform/frameworks/compile/slang fec3d02337acc5d0372a659316f41d91dbcf7cae
-platform/frameworks/ex 307bc3fba778575012c3d5968dcc102ef14989c2
-platform/frameworks/hardware/interfaces 610187aa815dd1e5baf478f7d97955f164295ee7
-platform/frameworks/layoutlib d2835b57632b7d9dee954a6e35c8028b53914ff9
-platform/frameworks/libs/modules-utils d6441cf0c8ac7c06ef555dff2e12901b659efbbf
-platform/frameworks/libs/native_bridge_support 91d3eccbfc315b36b126fa863dcae38e85399f68
-platform/frameworks/libs/net f6d1603058f677d10ae3ac2e409e05968a2f4bb7
-platform/frameworks/libs/systemui cfff651a00f77673c93a7428c3acdf15d6a3390d
-platform/frameworks/minikin 18b1f01c01677ad1c45ee78fd984d67f89eac942
-platform/frameworks/multidex b74d220d785679f5f856c93da8f7ed5c17fb646f
-platform/frameworks/native bd6a94ca2bc37c5e0909f9c3f3e89584311319d2
-platform/frameworks/opt/bitmap e2f5daa5f1bbed0c7177b767f450dbf2a2b9628c
-platform/frameworks/opt/calendar 877b348ca5f23befe6eccb1208a2a045f8240b00
-platform/frameworks/opt/car/services 82aedcd0bb2b05d2d7b5546135eb9be58bbf8d48
-platform/frameworks/opt/car/setupwizard a4a78bf6a1b99d68747954b20dc55dd96ff923a4
-platform/frameworks/opt/chips ca6dda1c783218db3f4961a3fbf3155bcb4c545a
-platform/frameworks/opt/colorpicker e7e282dac3d349e8878abcc3358679e178d63204
-platform/frameworks/opt/localepicker b0fcbfcc2ab6338b432c2979dd627bfe4bc04c2e
-platform/frameworks/opt/net/ethernet be14b3bac69d3e04072e36f42956db936d1a93d9
-platform/frameworks/opt/net/ims f882809be1014e06a0db4b821aa3e58fcbb9df27
-platform/frameworks/opt/net/voip b71d83ae8d887a023abf0fa76c357ca3e5bd6f99
-platform/frameworks/opt/net/wifi cc5170caddccff3c9a1c01f98031cb1d818b8c4a
-platform/frameworks/opt/photoviewer 632aaafd49b4cda963644ff32ea12c53718d7bc6
-platform/frameworks/opt/setupwizard ba1ab2acacd55b988c3a70af0c0902b5455e3484
-platform/frameworks/opt/telephony 249556ea80e2288d2b3fdc860ae4eae3eedd2cc6
-platform/frameworks/opt/timezonepicker d7fd9da86b22c37c85cc8bc6e386331d1e8589b6
-platform/frameworks/opt/tv/tvsystem b0a90994dd0caf66f9d6274f5e71c291a08b4266
-platform/frameworks/opt/vcard 8a61a932d51d49031e7928ee94a23c92151f45b2
-platform/frameworks/proto_logging 0f9de1b9beda9922711eb42edb75b1473ebcc85e
-platform/frameworks/rs 1f874cf580683b9fd0f2db373acb00c49cad321c
-platform/frameworks/wilhelm 5ad56c21fe3ac01f3c3e4911c2181e7bd4763363
-platform/hardware/broadcom/libbt 2c76a9c66b2d93a154c88e1886ef29191524076b
-platform/hardware/broadcom/wlan 979e8fe6a1fb93f5f48351da50d0fd16044faadc
-platform/hardware/google/apf a279723b1e26c607a21d48c8e4cfcf9318efa7d0
-platform/hardware/google/av 9a9a1a4350f8abd0af0895cb73293702f671efda
-platform/hardware/google/camera c6f04e5f9aa5fb4aa374109bf4833b54487e15e9
-platform/hardware/google/easel a254fa899083ae26fadf19ec33ecd3d519e16e33
-platform/hardware/google/interfaces 8f0d0eb2940393f84a183744c09fdb6630982c65
-platform/hardware/google/pixel 29f9bb2050b5d22237d6f2f496122271b3e4bde7
-platform/hardware/google/pixel-sepolicy 23fe0abcab4147fe3108c8ad2a1df002f90d1b68
-platform/hardware/interfaces 004e6a110d4931ac5d094151483b873fb1308a8f
-platform/hardware/invensense 82ab99971b88be9eea956d235336f1edc45cd80a
-platform/hardware/knowles/athletico/sound_trigger_hal 16e96953efac09ef0cb422cbe2213c7d93d2ea24
-platform/hardware/libhardware 77d6367551d731a79fec887325b3ee92759b395f
-platform/hardware/libhardware_legacy a21b139830831407ffd852a52c8955cc7396969d
-platform/hardware/nxp/nfc 8a3e11aea02a525659127a52f3542fbd837e8f69
-platform/hardware/nxp/secure_element b56b2a746978df21508d1dbf881306b26233105e
-platform/hardware/qcom/audio c48afbd982dfe0b5322166d052b81672a8f77508
-platform/hardware/qcom/bootctrl 67b145884ce157e66fe7d0a6e14df73c5902154f
-platform/hardware/qcom/bt 9e34b420f94431d2e03a62af5ddf17f3ed393354
-platform/hardware/qcom/camera a82086644867b80edbbd7220e290d924cf436713
-platform/hardware/qcom/data/ipacfg-mgr 3eafef7ae4bfb7fae594033ab6f3a2ab99c4e120
-platform/hardware/qcom/display 84615c837306d05e49cd221f250ef0e7a250f24c
-platform/hardware/qcom/gps dfc8e384e66c6325b92ee9a1e76640bac9735a99
-platform/hardware/qcom/keymaster 3a5f4b7107182a7812c7247aed89eea80cc1948e
-platform/hardware/qcom/media edefba9321b6886194fc25ede6f218241f6428a0
+platform/external/zlib 684a2464f0049ff716b5831eff95429fd52312f5
+platform/external/zopfli 3e08dd324a14750b7e5839d9504b5478755e0ea4
+platform/external/zstd 93293208d7ee6ae1fa6021e3bddd67fe97c94c8c
+platform/external/zxing 4efed8b2f67b1b2db12eb0f7165fa1a7516ce77c
+platform/frameworks/av d15467e05249f6a0b2ab8161cb28e1aa546c2cc1
+platform/frameworks/base 7caf4474337859adefb03c80aab51268ab3469b0
+platform/frameworks/compile/libbcc f4cff9928b56ace0a8b325ba28e357b068b89d9a
+platform/frameworks/compile/mclinker b782df23af76c1f3ede267980f43ccbb76715075
+platform/frameworks/compile/slang a4b31ad90a34232c3786450f62e9913362168448
+platform/frameworks/ex 9ecaef1b4e7de2b4cbeddf9b5d11ce9b1718cb96
+platform/frameworks/hardware/interfaces 46f146827dd2276a4edcbbadc9345867ea942a1c
+platform/frameworks/layoutlib 0d52cf304a79b28e3c388521904a5870cb6cb0dd
+platform/frameworks/libs/modules-utils 53c4595c61218fd4dc3ad5ec085615c3b93ee66b
+platform/frameworks/libs/native_bridge_support ecaa46c73e3955f5e84de5f927eca61013a33208
+platform/frameworks/libs/net fc210ed928e4316f09e98ef7026dd3a66710f8a2
+platform/frameworks/libs/systemui cca1ae8f91732d4ea47e52cbe83504c698b79f42
+platform/frameworks/minikin 8bbb561a3dbed27952c6d6180947253101f37120
+platform/frameworks/multidex 951b8af17bac818351e677a436a33cbef700ad0c
+platform/frameworks/native 44db39b29ded3aa45681ea968c4962160411b754
+platform/frameworks/opt/bitmap 7544caf20090fb1f341174cb6aa48906c5d0b90a
+platform/frameworks/opt/calendar 0cf082d78e527b7e4e66097852f60f59faedcdae
+platform/frameworks/opt/car/services 3e1da703f3beb61d630350e79fe7fdab93bda204
+platform/frameworks/opt/car/setupwizard f5a8955c92d7468bf1937979af36ca75d3a5c667
+platform/frameworks/opt/chips 9227f601443fda5898bb3d5b0188b69bd46823af
+platform/frameworks/opt/colorpicker 4db6c52f5d8ae01a469cfaad1f7209bb14f73607
+platform/frameworks/opt/localepicker 58e0724cac402df80732da9b0a6df398c0435d4f
+platform/frameworks/opt/net/ethernet a59cf1eec1610f86d3868b9b9784aa5afd844b8b
+platform/frameworks/opt/net/ims 429d5d85cdf44dd9fe99d6feabc726ed84678050
+platform/frameworks/opt/net/voip da8fd9fde33f1d18df226756664561416e355236
+platform/frameworks/opt/net/wifi 56e46f85c7edde84ca8c14f38172ff867ac27563
+platform/frameworks/opt/photoviewer 665982e778eb49ada30196d030cbe030de678dfe
+platform/frameworks/opt/setupwizard 7a0081c78e46628cbf5fd43e49ce185613402923
+platform/frameworks/opt/telephony f3630b5f154a883c047f97757639539058125efd
+platform/frameworks/opt/timezonepicker 80ce75b19504eb1f2d4027e4c7806963f455f5cc
+platform/frameworks/opt/tv/tvsystem 9b2edd5e34f058e6236abc8ef4522cd979494626
+platform/frameworks/opt/vcard 595cc0db4a909e1502549e634bfb5ddc553483a6
+platform/frameworks/proto_logging cf4ba8d2a4448fd260446d94b0d776dc7b0519d0
+platform/frameworks/rs 84f3057ef56cd853bdeaf50e42666c28eb008ae9
+platform/frameworks/wilhelm b41aa87846a08baa5bf5cfaa08b7591a20564e3b
+platform/hardware/broadcom/libbt c26de2220cc522b6f5c1e326c34a69fdff84b3bb
+platform/hardware/broadcom/wlan 62b36f6af065f092dbe622d261c7c1bb529e7096
+platform/hardware/google/apf dcd1e37cbfddd642dbb108ffc4445f29ac2d5e71
+platform/hardware/google/av 8dffe8df66c117a452ee0e32dfac15af456bab5e
+platform/hardware/google/camera 9dea491e06d17c7d7ed8ab8cebcd211e8c98a62c
+platform/hardware/google/easel 5c63e6a9bdbb0d2a6de7035da11f83cef1fdda1f
+platform/hardware/google/interfaces c3f90fe8a05b8a1ad4eb43be1eac86e894b610d0
+platform/hardware/google/pixel 6298f74dad3a706afe9c8478da424f3d22aadc7f
+platform/hardware/google/pixel-sepolicy 42e6e935932839c5d4f5f89fc55c3c0d64dbbb30
+platform/hardware/interfaces 1c29375ad21956b2227056a5dc649685d5d1f165
+platform/hardware/invensense a951bc997729cad4a8b3e3cd4bc05ebfc6e40a4d
+platform/hardware/knowles/athletico/sound_trigger_hal 3c7dbce15af390982febeab448776c067af68bb8
+platform/hardware/libhardware 82ccc4cb54d1d336602e0305dc1f45feff728e8b
+platform/hardware/libhardware_legacy 870d6cc7b1489dba2d7d8c454ee6f99015ba76b8
+platform/hardware/nxp/nfc 4eb561cdd738d7d3b31b17c6d21657e95b734feb
+platform/hardware/nxp/secure_element ba7a8900de2e1ea081e11a4b2277e1fcf9118db1
+platform/hardware/qcom/audio 80de8c3aee2f39862ef94f3a4235473bfff7ad1a
+platform/hardware/qcom/bootctrl 0f3a6c26197c105874898c062aa71d5c087bff16
+platform/hardware/qcom/bt 92bf771275ba0d5de2a6b58aa7b30c07d0f8b3ba
+platform/hardware/qcom/camera 47c7ed1e0174936b4d7e6e5b7ccaff2417cb1c43
+platform/hardware/qcom/data/ipacfg-mgr 19daab8bd9ed53a43e0a1568e1c4e79f6316df55
+platform/hardware/qcom/display b8f60d2bec6396e536d8faacf1cad75fb59fa169
+platform/hardware/qcom/gps 02d89c88ab5a2357fe9470f3bf8522d33f993800
+platform/hardware/qcom/keymaster 673d6e9e1f0f59b4b8ced86e39cda59c761c0a66
+platform/hardware/qcom/media fe5ae179e1e551323393f7d240852d6be4d684a3
 platform/hardware/qcom/msm8960 9d39df40bda58237a3b107b61a015c56e5c2f0e5
 platform/hardware/qcom/msm8994 0f5b3f94e491ed789797c9647c0b4263baf9178c
 platform/hardware/qcom/msm8996 6ad317e0cff144f5192293da56f8f5d5ff5c8191
@@ -676,169 +705,170 @@
 platform/hardware/qcom/msm8x26 0c3893df1248b1672447be8bafed48a88633a336
 platform/hardware/qcom/msm8x27 9c56c74bdc19cedfd54c757916bdf0a6f009f72d
 platform/hardware/qcom/msm8x84 1bb54ae7ee26681e01db89e3a59f04ac6871622e
-platform/hardware/qcom/power 1d1b8707904595b22a09ee0851cbcc3abd735a12
-platform/hardware/qcom/sdm845/bt 1c04e0ad0bad01b0241c51a74b3da61f1f4c6f6d
-platform/hardware/qcom/sdm845/data/ipacfg-mgr a81b6cc2420ce96d65bc6af581f3a8140b790920
-platform/hardware/qcom/sdm845/display f98d907c84448542ef2495b0ffb0beb76175369c
-platform/hardware/qcom/sdm845/gps 7c443b489b3d4795c3804109d1bc548f23b58eed
-platform/hardware/qcom/sdm845/media 60c7450143d8606d30fae77bccf0b974de5ba018
-platform/hardware/qcom/sdm845/thermal 9cb01a0132463383f08b49385d9fafa60ee74431
+platform/hardware/qcom/power fe69478e69fc06a955eb0b1a9e704d2ef6623d6b
+platform/hardware/qcom/sdm845/bt c7ee7675818640d5da6af7e484ec06b1d042fc3b
+platform/hardware/qcom/sdm845/data/ipacfg-mgr 0d7fb74b8ca38792bdbe81c923f22b359aafa813
+platform/hardware/qcom/sdm845/display 488c6eddd8184b31ecd01f304e4333dd8bffd3ad
+platform/hardware/qcom/sdm845/gps 28cab03735daef0cbefae582656ded65d6cd12d4
+platform/hardware/qcom/sdm845/media b596afacdd742dab0b2781db67e63a9359a0e46a
+platform/hardware/qcom/sdm845/thermal 554833d55dd252ed296ae1dbfbc3ff922f1a1bdb
 platform/hardware/qcom/sdm845/vr 99dc43d44c9078792ea347873ab5a4d5f21d5ddb
-platform/hardware/qcom/sm7150/gps 4361d8c8bc0eb519b1c5df34f6fc956d85791056
-platform/hardware/qcom/sm7250/display 541bb274dfb32f7469aef8461a492c02cb31ccf7
-platform/hardware/qcom/sm7250/gps 9ee312f02b6b15c89f0f958b1602c58701edb167
-platform/hardware/qcom/sm7250/media dfa57043f03d2deb81682382df166abddff7af3f
-platform/hardware/qcom/sm8150/data/ipacfg-mgr 09cad96fd42a8baa442c4fdec8201a86adfa7cda
-platform/hardware/qcom/sm8150/display 9247eece27a2b20363e6fff9f034f76234377781
-platform/hardware/qcom/sm8150/gps 14ec0d6527cea4c2f91a4aa1681a0a74614ba9ee
-platform/hardware/qcom/sm8150/media 9b59f11af0b0fee7d66550d6c395309e1f74c359
-platform/hardware/qcom/sm8150/thermal 7766fb3acbee3f100e850eb1abccf676944c3b92
-platform/hardware/qcom/sm8150/vr cdeada793804960b6d81fe803c960c41e9ce29b9
+platform/hardware/qcom/sm7150/gps bd5c648ef234a45abd90ecb15381b55813770693
+platform/hardware/qcom/sm7250/display fcf6b3815272d64d4f482451a2ace551ef2c2d3a
+platform/hardware/qcom/sm7250/gps 51f2d0dcf922a28e15158c3bb8d04107beea3db9
+platform/hardware/qcom/sm7250/media 0ef232178b95eb9f3a3d9b66e59ce23ab4f8c512
+platform/hardware/qcom/sm8150/data/ipacfg-mgr d35bfa09840ad2adfea748e5e8e5318098c54216
+platform/hardware/qcom/sm8150/display 41e34c54284ee67d353d123c1f07f3f43381c680
+platform/hardware/qcom/sm8150/gps ced8c9678ca047dbf5a293d72f6c1ae8c04e93cf
+platform/hardware/qcom/sm8150/media 7ccdccf0f9902ab57184a3983745381427da086f
+platform/hardware/qcom/sm8150/thermal 403933e477fa01be983610ae62bc34248a94cec9
+platform/hardware/qcom/sm8150/vr f0460db64199f4f76190a8e2c3d1953375fcbfef
 platform/hardware/qcom/sm8150p/gps 2dcbb1efacb66e4ac019458a44640505b7b9b9c4
-platform/hardware/qcom/wlan cdb645765533723e4128b4c941e97deb34f94c7c
-platform/hardware/ril b35650c91d00b445b4f4e7f3f9756f6e2914ed2c
-platform/hardware/st/nfc e5679f800f6d0440281490cc11a9f03c5d5f1133
-platform/hardware/st/secure_element b3e8e761b72ef75c66eb5e20455588fb4b565727
-platform/hardware/st/secure_element2 783edec321e23de335512d51a83b0d697d527c16
-platform/hardware/ti/am57x 0bee8b12e788af760526a0ccafd732723b39424b
-platform/libcore b4a64b7cafd26f5551b9e4faf957e830f0701d5b
-platform/libnativehelper d4f4c4fdb404f0395ce60b17b72d12183cca4135
-platform/manifest c421fe2c5371986aeb5c509a0c4f03427d8929a1
-platform/packages/apps/BasicSmsReceiver 93cc37e90608c17533b2a9c3cf8ec4390816249c
-platform/packages/apps/Bluetooth f070ebe6c0be2f30a85ec3ddb47975bce93b66f0
-platform/packages/apps/Browser2 069d786a7cb6a6e302e7794bdbfe0c494a26fb1b
-platform/packages/apps/Calendar 242e671c9e7373a0df64f283bdea9699aa5c3b23
-platform/packages/apps/Camera2 005a4c0b1aa51fa913fcf6df2d3da835d094f86f
-platform/packages/apps/Car/Calendar 72aeb06d3220c2fe96928a30733480c5fb0c9fa3
-platform/packages/apps/Car/Cluster 9f5524eda612da73e2ff660baa3bcd4428b711fa
-platform/packages/apps/Car/Dialer b6c52907c3b6953c0f4be0d010905f76f6d2ce06
-platform/packages/apps/Car/Hvac 6ce4d2d251a8d8db74c4b80ef95c738f0fbb8f36
-platform/packages/apps/Car/LatinIME 4ecbd5851126f5dd4c4364028fda704e2d5bf41f
-platform/packages/apps/Car/Launcher 8750980f02a66490661a19cd6ba00749f92f648b
-platform/packages/apps/Car/LinkViewer 412ce13ed3ec9b835a9fb5aeb8c2f470e999e425
-platform/packages/apps/Car/LocalMediaPlayer 8bf05afc44459bc29ce3485ca1986c1b3241ec31
-platform/packages/apps/Car/Media c0cdf1b87881aa5f962733dc727f7be6f37b2cd0
-platform/packages/apps/Car/Messenger c71cb699227ca74bd15bcdad534a418bcc966781
-platform/packages/apps/Car/Notification c41b5c753fc9208582c193d61d51b7d86b19b5ec
-platform/packages/apps/Car/Radio b6e5e1585638ebb73d4b4d7894b099f4431576ea
-platform/packages/apps/Car/RotaryController e5424cb007dd53b9c67526b0b27b63ee61c5e22a
-platform/packages/apps/Car/Settings b50cdf1d5ea7825b306957dfd19f9c0e865ca1d8
-platform/packages/apps/Car/SystemUpdater 4abb6ae0dabf668b2921ef4842512683cfc24286
-platform/packages/apps/Car/libs 88ed6fb938586475c7560559df6f128765e15851
-platform/packages/apps/Car/tests 84ff6a43f63c09d9b21a81b1aa9283aa9edb89f9
-platform/packages/apps/CarrierConfig 002a04f606d9fedf23f59f59e0dfe9a6b91730e1
-platform/packages/apps/CellBroadcastReceiver 6fca6b45e2700d4f3c7f6e28f26c67df74eeceba
-platform/packages/apps/CertInstaller 8def6e3afffcd665350b1b682a6c6efeeb71e985
-platform/packages/apps/Contacts 43fd100a93eada8818c10c6a8b251b267246431e
-platform/packages/apps/DeskClock 238a4bdba88bc617ebe592368e7a7c59a2129081
-platform/packages/apps/DevCamera 853066cda9f6f8df2020fa3b1d4f4a2d20887f99
-platform/packages/apps/Dialer 64b55eba3dfe443e1ecbdaf70c4402949b1f5d51
-platform/packages/apps/DocumentsUI 0651740988cf1bc01cc1f3b0369330efdcef9336
-platform/packages/apps/EmergencyInfo 76020a97da413896b87814bb8fea39d7e7a2c6c3
-platform/packages/apps/Gallery f3e1a17fc92e9636a7c2bd20ceae6a6e874a8778
-platform/packages/apps/Gallery2 9bfc51cb7f7879ee05f42ba1af235d46f9901790
-platform/packages/apps/HTMLViewer 98a0ce499f77ab63d6373682f959a9f6bb0e0cfa
-platform/packages/apps/KeyChain 53f3db051271adcccf50fcf11be3e8ec44c63fbf
-platform/packages/apps/Launcher3 e9be03313c9994614991e5d5861b2192e5aae556
-platform/packages/apps/LegacyCamera 962755f773ef9dc8cdd4b1fee0da5ed6d92de7ee
-platform/packages/apps/ManagedProvisioning 477451307221613ef5aa22e19a0a3cf3372154c5
-platform/packages/apps/Messaging 582d8bf51b765a113ee678d37f046251e8331963
-platform/packages/apps/Music b41aa967c1f3f67f3200d1fcc3337a69dd2400fb
-platform/packages/apps/MusicFX 08429ccb9cf381ebcc9b4192f4170fabba6c833b
-platform/packages/apps/Nfc 0ed2bc93472625abea3862e0d57f9b8c9b960c07
-platform/packages/apps/OnDeviceAppPrediction 68b1595f2aa980cb67195704c617e4d929b6e0b1
-platform/packages/apps/OneTimeInitializer 87d77a3837db44c9117cd898bb3bd9c01b2924d4
-platform/packages/apps/PhoneCommon 5e0c3cb84dca0017e5eb7a11273f56087ad3cce6
-platform/packages/apps/Protips aa88b44828a11201fe3d3312de1d7d937ee09729
-platform/packages/apps/Provision ce629ff99e27654e025640b7d000c282f3110601
-platform/packages/apps/QuickAccessWallet daad97b00cb2b13c7f4cdf3215809561918788cd
-platform/packages/apps/QuickSearchBox e113a5fba4f226806b250c52be0ef62947f96eb6
-platform/packages/apps/RemoteProvisioner fddb0830dfdaa55b2220b4a4a6c15ee0ed7ce68b
-platform/packages/apps/SafetyRegulatoryInfo 3dd38c1260d9bb876b7102c6f34e212b927bf450
+platform/hardware/qcom/wlan 6a087a6df932bd6c3884d1c771dd00cf72b423c0
+platform/hardware/ril 05de5703a253a5cdcca77abdd4ff65a3a72a3aeb
+platform/hardware/samsung/nfc cad43c7232ef9afc7a34a49a273d2ee5a4664ba0
+platform/hardware/st/nfc 8fa8fae26a433fd1203674d49d16bd12819ad208
+platform/hardware/st/secure_element a276c8c39328032a255c2a07e9a1a04c69d178d9
+platform/hardware/st/secure_element2 0f5754aef4e57a683ea8e1b1fd95ce43c46f1b08
+platform/hardware/ti/am57x ab0b6e0248ce3a30327dadcf19c7c4fa2afdee30
+platform/libcore 233259075922ec4a0d8e1586275cfbb30ba41442
+platform/libnativehelper 380d15bcf48a8bdc6e7c645ca08795da63221f84
+platform/manifest 60570b3019e83daac85db8c8366c13681c5567e6
+platform/packages/apps/BasicSmsReceiver fa8727099ee0fcf3860cd2108335271c0351a032
+platform/packages/apps/Bluetooth efcc7654f5df860a0803ffd6a3c2dee621634111
+platform/packages/apps/Browser2 0497822eefb479640000be5a442319c0aadb11a2
+platform/packages/apps/Calendar 6a801c5fd2ed3f42a63c1f9ebd844c0d9199a1f4
+platform/packages/apps/Camera2 937a0bec615f0b8af7d2e43f0897654e6f057bd0
+platform/packages/apps/Car/Calendar 08a631dde79c1d1ccd9b0462be802aefc9800415
+platform/packages/apps/Car/Cluster e7b81c9bfb77efba457ea729a403a6edfcdb7f06
+platform/packages/apps/Car/Dialer fb3eeb0e5ed8f21c347e4ada820bd7bf9144a64d
+platform/packages/apps/Car/Hvac 3aa6dcabab4e4245de6a05f4f60d19a0d59afabc
+platform/packages/apps/Car/LatinIME 1c2d6cefb94ab2e011b836224cca1e5a480df4b3
+platform/packages/apps/Car/Launcher 5b826e5bd1588a4b1fb7f4bab9e89daa8cea8833
+platform/packages/apps/Car/LinkViewer 56dc0c277ff51806d91d6d4def2cbcab5cbf2d06
+platform/packages/apps/Car/LocalMediaPlayer 38f4a70b5d2c0549a48b2cb6e691f046717ca7ea
+platform/packages/apps/Car/Media 6f2767bb1f0e1a22a18040358483e3e276b5076b
+platform/packages/apps/Car/Messenger 83351e13f070ea9d9cc51e7c2e1599f6f9763a6f
+platform/packages/apps/Car/Notification f39d52cca3ac00bf046ea511d5cb784db2e17716
+platform/packages/apps/Car/Radio 6c9d20a0460e5b39f35e637ff8d2b3bb85b9a059
+platform/packages/apps/Car/RotaryController 26d13c5b010786ab326f99b20037839e561ecd3e
+platform/packages/apps/Car/Settings 9bb9e40602e00a7e1b47011ce379080ca05467c4
+platform/packages/apps/Car/SystemUpdater 5f1e7533f5e779a6ecbab125742e80d717b6f1e7
+platform/packages/apps/Car/libs 14314bb4ea629b43b28523cca33fcd685b3f0284
+platform/packages/apps/Car/tests 44479451bad23fe4c44e6a08b58ec1bff2a28b28
+platform/packages/apps/CarrierConfig 250ddbfec45d190063345656d05eb0baf80fb5dd
+platform/packages/apps/CellBroadcastReceiver a3428dfdcae426ba7e27bc3a49a74ec014f71371
+platform/packages/apps/CertInstaller 6da6e3ed269100a0e0ced0148367759688748fae
+platform/packages/apps/Contacts 643300b10229fff9e8c80ef5245e09565992107f
+platform/packages/apps/DeskClock 69de299c860012313d9fce06345b30deaff8caf3
+platform/packages/apps/DevCamera 85ee1ef80a02c0bfdf0381ebeafa47b3b142129e
+platform/packages/apps/Dialer b830fb1786af2750f1d21210d7ee63e384be68e5
+platform/packages/apps/DocumentsUI b12b72d9c7ff1ea21c421762bcf3dcae6d5da38e
+platform/packages/apps/EmergencyInfo 354a62058249c22dd7e9fa3794c01c42d5f257ac
+platform/packages/apps/Gallery 811664b966b3679e3ce12e5012115cafe12f52bb
+platform/packages/apps/Gallery2 9610aeff5833f7b11fb7bfe9c7ec375946167e99
+platform/packages/apps/HTMLViewer f35b6bc2f6bcb7583580755499bd471f3c5473d6
+platform/packages/apps/KeyChain 55a07f913c7a81ed3fb495b013bb7c3d7983208a
+platform/packages/apps/Launcher3 503e6a65efa86582b60d42a8dfc37fbf5038e258
+platform/packages/apps/LegacyCamera 8ce3803568b210d191b45851ad1ca7716ce8334a
+platform/packages/apps/ManagedProvisioning eb9f571b8b193d3fd62c3adb4681a99eb5f9168f
+platform/packages/apps/Messaging 34b63ae5f56efdc588f3743c71feacbf7f96dea2
+platform/packages/apps/Music 29f21f044551cdc4adb129a0df9b59f576c21750
+platform/packages/apps/MusicFX 2aec2246c8a7f392e7704c09b98b75535a8fe62b
+platform/packages/apps/Nfc ea373c1271f2e8574e86898216e68fa00e838e6c
+platform/packages/apps/OnDeviceAppPrediction 8c666841d3a15d113b72b7621bd84b9e7cef96c8
+platform/packages/apps/OneTimeInitializer 1803e1d0e8f6d862fe5724071c52da8c92295487
+platform/packages/apps/PhoneCommon 6b198135d693f74d863122df9fcac0b2521528b8
+platform/packages/apps/Protips 16f343749880937ff32067aa1494d4fd9e24f090
+platform/packages/apps/Provision be9351f14d4a5cfc67c97f133d215952f975b07e
+platform/packages/apps/QuickAccessWallet 66e8f75515125808ca61a1a12678e5a1c91ae9e7
+platform/packages/apps/QuickSearchBox 74542aa99271ac6dbab1f9354bc6e367ab85f279
+platform/packages/apps/RemoteProvisioner eb9ae594ded3f6a7cfae5bb713ce201cefbc31c7
+platform/packages/apps/SafetyRegulatoryInfo 6677dcc22daf4f59691bdf4916a730977986649d
 platform/packages/apps/SampleLocationAttribution 15af5a1c15dd6d72b5d27fb06bd8ebf68829ac66
-platform/packages/apps/SecureElement d90b98d2598b7aa240f3825b6893d68f58ea72d7
-platform/packages/apps/Settings c5dcfacfdab434914f4469e380a247c04a756217
-platform/packages/apps/SettingsIntelligence 80bb4c727045b69fc50e5a5fd797203d98aa03ba
-platform/packages/apps/SpareParts 8baa55d4af3268efeb4c00d515ea1172d0c30636
-platform/packages/apps/Stk 7ff508a66602e7d413f727c8b6f8d1ae117b73e6
-platform/packages/apps/StorageManager c3fbda9749863a93bb92505caaad20a2cfb0aaff
-platform/packages/apps/TV 4f4f2ace5bfd1fc89aeba9e32345c578d2f24cbc
-platform/packages/apps/Tag ce7ef4c60f300385e3c0746296db8ad1ac4c6b95
-platform/packages/apps/Test/connectivity 61dae4174cb79cf915d13b52663d879111ec47d9
-platform/packages/apps/ThemePicker cd1079719a96246fdec689d3d91bc39039cdeda5
-platform/packages/apps/TimeZoneData 473fcf21dbe3d1a92c6297fad04253f10ab5157c
-platform/packages/apps/TimeZoneUpdater 5f7eba16877c58ad6ecee3c944a4295bdc45475e
-platform/packages/apps/Traceur 9a40c2d1133275bf89e0e2a9afd556249b9d3275
-platform/packages/apps/TvSettings 36759b242000a1851d68361dfae39edfb9b1b536
-platform/packages/apps/UniversalMediaPlayer 8b751fb94c456d82d4e2218b8d1b04d79684c64e
-platform/packages/apps/WallpaperPicker fa2d55efa24067fff43c54d2ff84904486e21ae6
-platform/packages/apps/WallpaperPicker2 03e20d6671110841b9ce41bb8f419dd554af082a
-platform/packages/inputmethods/LatinIME c1385705288bd1f62055f33e7fe7ae705d2f24e3
-platform/packages/inputmethods/LeanbackIME e83d6120ec6930183bdf81740eae5f5c71c1a1c7
-platform/packages/modules/ArtPrebuilt bab54827be46882515555850dcbc5bca7fe778ab
-platform/packages/modules/BootPrebuilt/5.10/arm64 ebf863dccbb55605535488a4ca03ea431fb04aed
-platform/packages/modules/BootPrebuilt/5.4/arm64 6bde5a396b9edfe09883620d96920718a9767de5
-platform/packages/modules/CaptivePortalLogin 098d3551b2bead0e272e273022aefc8c4bfbf431
-platform/packages/modules/CellBroadcastService f3b93ca522316b505b4e4407370b06d6507ac7b7
-platform/packages/modules/Connectivity da1fe8c641dc0dec732cae0a51bba38d90152e11
-platform/packages/modules/Cronet b92b8da5da20b6dfaae3984b8c36c9e809eae015
-platform/packages/modules/DnsResolver 2d9bcbb044b22b25f860b48b71e84c42114bf75d
-platform/packages/modules/ExtServices b2b1ae471001490425f3fafbdaa8d5e2ff95cc29
-platform/packages/modules/Gki 1af4ce8eb24e7bd8c975cfbef17a4eb216c385a9
-platform/packages/modules/IPsec 908ba8b8e114b3c2ad5afab2e7d70918d53b0f5e
-platform/packages/modules/ModuleMetadata 680f03b54f29ec25b3f106cfdc83e524869c736b
-platform/packages/modules/NetworkPermissionConfig 36d8c21193c1012a5286c0c93f035756f368f0f5
-platform/packages/modules/NetworkStack 98717634f19574da66dc36742b05d676fe89f8a9
-platform/packages/modules/NeuralNetworks bf4e57048eb5f7781f948d677c530f9fb1e40bad
-platform/packages/modules/Permission 42e7de6908a747ce844669bb131ae2891c2e6641
-platform/packages/modules/RuntimeI18n 1bdfa45df6ccd9e2d9d5bf02b22f50a07181953f
-platform/packages/modules/SdkExtensions 9d78492b5cc7e87d473393e311ee81706349fe46
-platform/packages/modules/StatsD 31dc23ada3d6e02067b48b9e8a4e4511b5d542fc
+platform/packages/apps/SecureElement b09bec825afde52993fd4b3b600b24549fb1f2f1
+platform/packages/apps/Settings 9cb82a39c2204665477d4da5e99aabe7c1075f68
+platform/packages/apps/SettingsIntelligence d7362de9fc8cb91bbe34d9d9891cfe8db3e0ecf5
+platform/packages/apps/SpareParts 8b72fecc78c89aefa23faae2a5413e1f8722846c
+platform/packages/apps/Stk 4b193833d2cbb8768406bf2e7c5980b6637102ac
+platform/packages/apps/StorageManager 42bdf14c159784ba955c2ff98680d3d5e01e2228
+platform/packages/apps/TV a6d8e83215c23edf87fb9fd21ec0783144926201
+platform/packages/apps/Tag 23d86b52222f8bb7d3331b17e964ad5f71b7a96f
+platform/packages/apps/Test/connectivity ff1a723dc756878eb15aa2888d2c19b865311d97
+platform/packages/apps/ThemePicker 7dc246b2c804763508076becc715023276f6303b
+platform/packages/apps/TimeZoneData a8097ab7a525ec388bc617782367c3d965588067
+platform/packages/apps/TimeZoneUpdater 2d75621e21d459329a9a575369674847b55fa64c
+platform/packages/apps/Traceur 59b8bdb173cdc3903ec0ba27033d5a3e9b201286
+platform/packages/apps/TvSettings abcc2c3956527eb9b200dc99f65bd3cd10bcc134
+platform/packages/apps/UniversalMediaPlayer 687798275384bc9de996281cc4957450eb462321
+platform/packages/apps/WallpaperPicker 188cedd4881a20f7d16d99f58e6e7b321811716b
+platform/packages/apps/WallpaperPicker2 0dd3bd847645c3f726435f23e2f0042e77d682b6
+platform/packages/inputmethods/LatinIME 56992c1224529ceb403d264eb4edcf6344b08c78
+platform/packages/inputmethods/LeanbackIME 16e0e3340a83324fbdd11b674addbd4daf4b8df3
+platform/packages/modules/ArtPrebuilt 7fbebf99f429457cdf18124401deacbf29cb98f5
+platform/packages/modules/BootPrebuilt/5.10/arm64 6251f97141cf1bbee97603d09775d2e0a1693082
+platform/packages/modules/BootPrebuilt/5.4/arm64 505a56b149afe2cc734503f2887a7f5f887c3e9c
+platform/packages/modules/CaptivePortalLogin 5dcbcf8762324a3e01e7a3526ed2d0f96445e62f
+platform/packages/modules/CellBroadcastService 780a28eb02b1330bc5e65aecf86bda7b8a5a5939
+platform/packages/modules/Connectivity 77d182ffe1ae4331a6ede775ef1bc889df422e43
+platform/packages/modules/Cronet f1de37c7a10be1600c0ec99de85f7ebe5a05eb55
+platform/packages/modules/DnsResolver 2ec693b17915878f4cfb46c76e94206f4ad674aa
+platform/packages/modules/ExtServices 74622db4c0f8b414ef35774b1edd782811dead95
+platform/packages/modules/Gki 318df7ac2f2c13f420eb00d1a601a8e11478ce43
+platform/packages/modules/IPsec 60b1b8cd402e295d0f2f85cb69bab59b57c0b330
+platform/packages/modules/ModuleMetadata 51a755528b61e31e7c4842492ebd541157f21395
+platform/packages/modules/NetworkPermissionConfig 65e662b8f630ce03726616f9df1150f813ed9f5f
+platform/packages/modules/NetworkStack 4e709d9ec3909a715af8a6bfdb0ac0b6a662509f
+platform/packages/modules/NeuralNetworks 335f945c7e0b3a8bc37736cf3194134500ea174c
+platform/packages/modules/Permission 173e8ec32cee1c4b563093a30801e7062b203c0f
+platform/packages/modules/RuntimeI18n 0db1021a91a79dda9ba8021091856182a06f5ad5
+platform/packages/modules/SdkExtensions 4b0216b1fc03decc2bfbe171d773c7ec5bb2e970
+platform/packages/modules/StatsD b70104cfa70574f2552f5d7d9b18610e5463a3c7
 platform/packages/modules/TestModule 3523a2f0f9b12d4e60374af63aae14f75a2b4c10
-platform/packages/modules/Virtualization a4b32678265260408fd46c3e37f51bc845a64e42
-platform/packages/modules/Wifi 2dc09460651eae835c6b9069358a8e305077f296
-platform/packages/modules/adb deed177f434098940ef67c0cba3f2760494a1c48
-platform/packages/modules/common 1d3f6cd55a368059f2f676703818e0cfd4c08345
-platform/packages/modules/vndk 0788faf7cfe5a697e2960d43decda38508ab044e
-platform/packages/providers/BlockedNumberProvider 057e1da2f1729022f0aaf5b950740511eac7ff1c
-platform/packages/providers/BookmarkProvider 012e9eb18b860804916ecbaa2f21d7047c8d4951
-platform/packages/providers/CalendarProvider 09b6aa82ab765115a7935e938306291c77296ca7
-platform/packages/providers/CallLogProvider 806dfaadb709c9a2b1b8f99e8f9d99750c381782
-platform/packages/providers/ContactsProvider 2cdb9ac5ae53a5c16478b626a18b7d0315819f3f
-platform/packages/providers/DownloadProvider 4d0f6cd88efd710a103567020b42c4ffb3082166
-platform/packages/providers/MediaProvider af0aec5bc3604348729357abcb8b60a11f3e6650
-platform/packages/providers/PartnerBookmarksProvider d72bcd1eb7740003b49bb76da2eb665b90e5d151
-platform/packages/providers/TelephonyProvider b180cdcac8b30e96ec32aba8fe9feadc42f7a8f5
-platform/packages/providers/TvProvider 6761be8ab72885dad71130cd5f393b72b51b1e1f
-platform/packages/providers/UserDictionaryProvider 2c3310087fb83f64d0ac61bfc7f4195e9c2c1c88
-platform/packages/screensavers/Basic 9375f12d1412a2e700c06772143fe213dd0cc210
-platform/packages/screensavers/PhotoTable 7caf434f0d811e5aa848d726f0faca3cfec6be1c
-platform/packages/services/AlternativeNetworkAccess 35baf56facb9953d587d004bc3caff9c8ba6759d
-platform/packages/services/BuiltInPrintService 4156cc99806b6e8bbfe364e2d4d49ddf68ac1478
-platform/packages/services/Car ebe67c2de1613422bf3516430b9c64d315193955
-platform/packages/services/Mms ad884b2295643f26647201b36378e409203450b1
-platform/packages/services/Mtp 563ddeb666190d69afba5b465b6fc67d97b13dfd
-platform/packages/services/Telecomm afd7f1460c812ba6d0c3f5e4444c868df4a4e570
-platform/packages/services/Telephony ef2e0a764cd4d2f665f73a44372f3786e6f9c749
+platform/packages/modules/Virtualization cc7bd3f64a5784ce4e50918d279b20ad948cc946
+platform/packages/modules/Wifi 7c4955427c5c23b19c3181af68f550943746c630
+platform/packages/modules/adb 528ab50c82db58c342b4a2b8ff4bebd0a76b7da7
+platform/packages/modules/common 86c611f1b3afa754a3651e5bccc01a040748a51a
+platform/packages/modules/vndk e567cd6a07f056dca8e90148c8ca97173c51a3d3
+platform/packages/providers/BlockedNumberProvider c4423a6b9482e419ac4fb5ede20518c78f27b670
+platform/packages/providers/BookmarkProvider 76902045e1d3a4b4398c252436e1ee5246b54014
+platform/packages/providers/CalendarProvider 7571c977501ffc1cd9b1db7e94047f54e9e8dfc9
+platform/packages/providers/CallLogProvider 5e3624f8cfff52ce564dc582579be10052b3fc92
+platform/packages/providers/ContactsProvider 6d21d8be03506d57c22e1472f90cae65a51ef943
+platform/packages/providers/DownloadProvider 0874f4c5f607a898171809738e97b79e4efa62ba
+platform/packages/providers/MediaProvider 642ebe9b679a3f27b43d254257de9075d15d01df
+platform/packages/providers/PartnerBookmarksProvider 01781ef4eb4e0a09c2dc79f17f6d5cf5b9532f60
+platform/packages/providers/TelephonyProvider 345b4ee51eb13d8fc4296d8fd1a7c6e5fdae2455
+platform/packages/providers/TvProvider 242f4cbef1a3197c412abae77346989ccce3c60a
+platform/packages/providers/UserDictionaryProvider 3c249c508deeee9e000d7cc203af2e79e8cab05f
+platform/packages/screensavers/Basic e53217195b8284ff748881b00e5571ed7606b1c7
+platform/packages/screensavers/PhotoTable 13eaba2a973323581b3ff98dd25ad7e048503f25
+platform/packages/services/AlternativeNetworkAccess 5a3dfc0a85a568c388cf1229075a3068cca22a43
+platform/packages/services/BuiltInPrintService a917d7e9bb7fd0836fd9c72b4ec582abbf4f445c
+platform/packages/services/Car 2d42be39a8bf6e48f02cfd630bfa43b555ce5aa7
+platform/packages/services/Mms d5a4082d5ba0f895f2268e3e8864e4d2b45a518e
+platform/packages/services/Mtp 993de0ec60033218b0c647e58287212c0b5f3ec2
+platform/packages/services/Telecomm 8279edb263205bcbf41b64913adb93df8eaec8d7
+platform/packages/services/Telephony fd7574092a2453376e69a57823cdd442e36b16f6
 platform/packages/wallpapers/ImageWallpaper 0a1680f07b09889c7642a775b6bb69d1b27f9b09
-platform/packages/wallpapers/LivePicker 991aa56b6ca715a1651fd96e7d2ce35838378494
-platform/pdk 10033e6b2df7aaaffe5d814996e83684de69a8ce
-platform/platform_testing ebdff050f73c7435ddf4efb4cdecbc6dad48c5de
-platform/prebuilts/abi-dumps/ndk 37b7911e6d6c072e288f06018ede920e2bb93276
-platform/prebuilts/abi-dumps/platform 667b9c6101dce3c4a8c07090ed297fb74dd5a041
-platform/prebuilts/abi-dumps/vndk 93c53c3fcba9c419677a6d30aee94ecd21be2430
-platform/prebuilts/android-emulator d51949a8967717478ba88a4850ef11d542a23f42
-platform/prebuilts/asuite 0c39651b3fb9f8dc8fca17baf9f93e9b76110e7d
-platform/prebuilts/bazel/darwin-x86_64 483ebc32d8c381f771aa1005bb5adbdee7990704
-platform/prebuilts/bazel/linux-x86_64 9eb0307b200d9aa0cb2a75fab9c335e21ba7fc90
-platform/prebuilts/build-tools b19a62bbbe247a50234592902da2d8d04f027245
-platform/prebuilts/bundletool cfefebda6347f409be1de0a1069dbf9a477ab41b
+platform/packages/wallpapers/LivePicker 841538a4997c20baddb64f5d8c3dc0b892e07452
+platform/pdk b8a31452571f4d876c53740629ad348f768a48f4
+platform/platform_testing 18131569b72d66eb26e8bcd9749872681b0b4a56
+platform/prebuilts/abi-dumps/ndk ddb94375641ef4554b24a4c08429f09294bbe784
+platform/prebuilts/abi-dumps/platform ba92b078effb696a6f8b9c21b7c36de6379960f5
+platform/prebuilts/abi-dumps/vndk e1d3a6c83700959d8bdd680dadbff571001bb535
+platform/prebuilts/android-emulator f4b75fb7924981ce124352c925a49bc9cb581703
+platform/prebuilts/asuite 408b08804743f4a0b2f26ae6bb11b4cf8b191c71
+platform/prebuilts/bazel/darwin-x86_64 99a1aae5448b145734eabb4b426d8f45bfe05839
+platform/prebuilts/bazel/linux-x86_64 2b8b608aebdfe4221cfcdece0e0c4faeccfc2abd
+platform/prebuilts/build-tools 9358eb5ebac6e12024caf9261433e85c70cc40c8
+platform/prebuilts/bundletool 8ae943b139d700590bea8cdd872ed45ee3a3c02d
 platform/prebuilts/checkcolor 9db4af220ea5dcd1083797ecd0d8bc66cd2a4a07
-platform/prebuilts/checkstyle b79fe457904cdcea7780540c1a543c66db9458c1
-platform/prebuilts/clang-tools 72375769f530feda538a146f6cbea76905e56968
-platform/prebuilts/clang/host/darwin-x86 12f3f3c947091c6fd78034a9f356ecd39cb0bdb8
-platform/prebuilts/clang/host/linux-x86 7dc9c19e9c8f8c60527e5a932340271ae0cc5645
-platform/prebuilts/cmdline-tools 716b16d78c6269c8de5c549a5ddb9795afcb65bf
+platform/prebuilts/checkstyle 5ecf98fb20a83c311b5dc98d81d1e400598ae4ec
+platform/prebuilts/clang-tools d04ed4a48b64580ad6a9497354306eceb7ad2fc1
+platform/prebuilts/clang/host/darwin-x86 e9fee96e6090bb88a00850efe00e89c3e7bb100c
+platform/prebuilts/clang/host/linux-x86 06c8cc59394d8c5fe8b80e6e6b14da084f519ca3
+platform/prebuilts/cmdline-tools bb8a57a1eb368f948774b9241963a51a2df3f31c
 platform/prebuilts/devtools e60e2ac20eeaa2eac82da9ed75579e12d91a527d
 platform/prebuilts/fuchsia_sdk 20304b0e0a0380b823a5ca910a7a0aab8a975bc7
 platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9 a963ca3ad3d644ebd28ffdf15799f6207ea545df
@@ -848,142 +878,142 @@
 platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9 01a6e6784cb1e4ca3687b9662c7166a19693f50d
 platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 42beb707ad2ad0911e798f22ad2dc62c955052e5
 platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9 ed044be71e7a9442baf5c775a2ce5221fda3531f
-platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8 3d71b3715c020a51accdfccc3f7e5a0d78c8f820
-platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8 fbde559c868deadf24933afed2fead0df2a13e9c
+platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8 cab911b9f5d3b97930dfbe3f3c25924ecab7ded9
+platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8 6e981398dd433ed3b19dd35c55026224b547176d
 platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9 aacdf6611a4b21bb1c0c55bc4403bcdf46044e46
 platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9 b936ddef1d13df2739d1b30946876106378e28f4
 platform/prebuilts/gdb/darwin-x86 a23459f98c697a74229705832c574039f633a221
 platform/prebuilts/gdb/linux-x86 cefa0269ee3a79860e3bd629edce2723fc0db43c
-platform/prebuilts/go/darwin-x86 bfc58a68cb797f7b628789f9612d42f92edae1dc
-platform/prebuilts/go/linux-x86 c4872aec836db1ad7339619c3070db208c42c804
-platform/prebuilts/gradle-plugin 919b9e3ed05946ff97559a134c0ba4d6e7be4fa3
-platform/prebuilts/jdk/jdk11 81afaa76d5104fba677b7547029ff54dee2f833e
+platform/prebuilts/go/darwin-x86 88123b318a99ee92f8f03cac9567091cb687b9d8
+platform/prebuilts/go/linux-x86 5cc0df9e72ebf1cc1e1a23463f55f9d9c22a6256
+platform/prebuilts/gradle-plugin 05d2377500f4792dbe79f38c1dd83d607541bb87
+platform/prebuilts/jdk/jdk11 ec6e3f19d728f299d8ecc84019135abd05201364
 platform/prebuilts/jdk/jdk8 ebff3bab14fad9aefec53f8c1efa436be119ee80
 platform/prebuilts/jdk/jdk9 804aa5be223e8b7582022b6794e8279d46a7f33b
 platform/prebuilts/ktlint b471908fc62105596ef96f7a70e63a4537f54ee1
-platform/prebuilts/manifest-merger 7d50a59dd79262e7f30c5437010809dea42dd3cf
+platform/prebuilts/manifest-merger 2fd3c635710919d4e025cfee0f51c0dfaee4fecd
 platform/prebuilts/maven_repo/android dd52ad05c8c4b1e6f8d5a4e2d20264b958eb6051
-platform/prebuilts/maven_repo/bumptech 5037577cbbcfcfcbd492ad88267afab773ad16c2
-platform/prebuilts/misc 22542451d9bfccace780589b2a9ed3642761a05f
-platform/prebuilts/module_sdk/art bc399ed2f9a1f1bf34db51ead76e0b947e9213f4
-platform/prebuilts/ndk d9f4ce950a5c9c4673db3d0e5253b580eb895db0
+platform/prebuilts/maven_repo/bumptech 1c532d9bae452ac4629aef52bee698a4932e4cc1
+platform/prebuilts/misc 25fd60553aa07310865abe8681573cd8234c5b1f
+platform/prebuilts/module_sdk/art 83fc1e14dc56699b496fa993b4fe0805e6acec5a
+platform/prebuilts/ndk 5ab626b2ac17751a60eb38bc3041656d70be9504
 platform/prebuilts/python/darwin-x86/2.7.5 0c5958b1636c47ed7c284f859c8e805fd06a0e63
 platform/prebuilts/python/linux-x86/2.7.5 93bbb3a3bd580dae06a6b90c820a90bad2395bdc
-platform/prebuilts/qemu-kernel d05dbbc1d281f5ec00be5195a9a7406cc83ed840
-platform/prebuilts/r8 894d5e51175b563036c6a17de780fc0ac043333a
-platform/prebuilts/remoteexecution-client 948f43318be1141fc2fc934fe16f633610db5d52
-platform/prebuilts/runtime 45f1f1778c0a37900d9b079a0e9f87061b255af9
-platform/prebuilts/rust 014017faacf2c3c7b2568fffbcd1df771b202c00
-platform/prebuilts/sdk 4049719619c78eaf779ef111acdebcdfe1fb0492
-platform/prebuilts/tools e52a22312757b9be7b2f65ad448a49bc50370218
-platform/prebuilts/vndk/v28 a3fe02b8b194fa05aba9aeb50f67a1831dfa816c
-platform/prebuilts/vndk/v29 6cfd7d791bdbb4a4def057f944c2377264f256e7
-platform/prebuilts/vndk/v30 58bd491428daa36c469e8b506b3c04da9ee36785
-platform/sdk 3f7dfb26b46c3b47c13bfe5655382896cf65f65a
-platform/system/apex 7d1bfcc490f875dc1970af84078cbe72d676cfad
-platform/system/bpf 0baae03485e069607e20dc2a7bfd3a53fda0eaf7
-platform/system/bpfprogs 70d23240a18c18a0facfc98554d65d395ed039aa
-platform/system/bt 3a51a0d9b2f2099a8a3d23a3c0b0e45bb8021e0b
-platform/system/ca-certificates 9d7f8235d6cba2e98623cc4c8bc19af0460f4169
-platform/system/chre 0ce81079567fc04652a2c187ed4b4e986202383b
-platform/system/connectivity/wificond 2dbb355c0d6c7df2c830ae1c3d9f0a56d05391f8
-platform/system/core 506e77af1cf8c101b808b8edfa662dbb6a3a36d8
-platform/system/extras 9c1c060c268fc62ae88df9cfe98bfb990a2bddc7
-platform/system/gatekeeper 39f5d0fe8eed12ffbf29c808e4120d5f434d5740
-platform/system/gsid 2e61c69a156e438b854c2c80e366ba386e0a9d62
-platform/system/hardware/interfaces a90608a0de22023cc46c9e68db71a56c6ffe62e6
-platform/system/hwservicemanager 18bb6170f9d5b1ddcb8b0c2af158d6744b0929d6
-platform/system/incremental_delivery 473e5a18602b5c321dd5fbd9ccdb7c23de7c1dcf
-platform/system/iorap 73a4ca1d2bab55659ebd80cb258e1ca5215b39ca
-platform/system/keymaster c8b966cbfce21696ef52b3f9b2246b16a1193bc0
-platform/system/libartpalette 4d67d7896bee92152bb766251823f8470fb6f01a
-platform/system/libbase fb161a86c71b45d26f5e0a956fce81ca7355de9b
-platform/system/libfmq cf6d2b7d7634d66c9c56ee5543e9f12a6e0a840f
-platform/system/libhidl 29a9160b6365db260295116b3d265c5f4c869d19
-platform/system/libhwbinder 0e48ffc1c33cb4f8f726f23125edd1c527e157af
-platform/system/libprocinfo d40670ed4ceeb77ec5439d4ea13e3cd388f96e08
-platform/system/libsysprop 86c9de2c6e9d16fe5a4f2ac8a2950dc189a61f9c
-platform/system/libufdt 201080e468daf5aa8638d083e008568ccd953390
-platform/system/libvintf 854134b0bb66048c311037ff44fc089bfc09710c
-platform/system/libziparchive f94f2b0935835e9ae962164cdcf2c71aef5c16d9
-platform/system/linkerconfig a837952bdfe04b6591e6ba45785b518e923c9d7f
-platform/system/logging e1834cf45c143b18dedd742d849c9149daf26b1e
-platform/system/media b46f6b0b35c4977a55a57595b3cc380ab4a9597a
-platform/system/memory/libdmabufheap 02ff73d21b10629ee59bf3d5570dc6ad8f696f9c
-platform/system/memory/libion 597a96ba0eb1d81dbf4fc8b514f5abef219a83bb
-platform/system/memory/libmeminfo 60b037ac30d21c02380a71dae1fc7c731955aa99
-platform/system/memory/libmemtrack e706f05fdea35d6b39da746080853c02bbd008af
-platform/system/memory/libmemunreachable 633bf5f9bdc76b7f520126c5d844fc2ff820c83b
-platform/system/memory/lmkd 136bd3c594ba1099d1fc0a5590a06efa308d2b7a
-platform/system/netd c53fb458688b3c2413993834723813628e52b33d
-platform/system/nfc 1061c77baea3485841d787564831d5e7c6a9fc49
-platform/system/nvram 2e6b24799d30a1ea989fef6f1291b191e88bcf9a
-platform/system/security 0d5cb50d10095f2d73fcc21cc5b2c4895399d8a4
-platform/system/sepolicy 0f9b767a2a840adddbda2343ff97682420322c4d
-platform/system/server_configurable_flags 55fcc8e789daf215e27414535ae0dfd827213114
-platform/system/teeui 48dc6d16f584551447c23ac875909a73eee4956f
-platform/system/testing/gtest_extras 70c1dde42c731d0f9e5f663a903f01751902c0fc
-platform/system/timezone ee3c73ce53f531f6dd5a189402122c13194414f9
-platform/system/tools/aidl 574a4f40b4778e2bcfff5ad95819cc7192bb6633
-platform/system/tools/hidl 72b6c9c0e225994297e144377672e88fdb0e1e8e
-platform/system/tools/mkbootimg 5be9b17df9808b4928230c4dc67ff25fd7b481b7
-platform/system/tools/sysprop 21e640ebb6ec1cd81c1c7e9be55bc1e18d20c016
-platform/system/tools/xsdc dc69983c04787fb72d62ac4ce9c6e6438c8e88dc
-platform/system/unwinding c5ba11e009d13a5595339fddce2bfb8165687b7d
-platform/system/update_engine 63be9f3dc3aa4b724353aeeec774030b89bf798e
-platform/system/vold 8b71028270bdfef162636424383767fa91552a78
-platform/test/app_compat/csuite dbd98db5ba602e959359db4fe2a8c86fd7a58eec
-platform/test/cts-root 3e0383547ad0b237601793164d87f5485b4f9b91
-platform/test/framework 8de5dfec73511f3a0d808a08bd2bb687344a5eb1
-platform/test/mlts/benchmark c99f2ddcff191e1bbe89929cb9f02098997d73bf
+platform/prebuilts/qemu-kernel 52516a75679e3b448138ac30db63c773a91529c1
+platform/prebuilts/r8 2a225c6d05c3549daccce8ebe43cd5bc144da0df
+platform/prebuilts/remoteexecution-client 15ff5e936745a0c21bf57da6efe409688ab32ab2
+platform/prebuilts/runtime 3d71394bba668ac41e21b4662b04b7a3b82ca6f5
+platform/prebuilts/rust 0c1fbc97645ff94462d049a9bb68a8b309c8547b
+platform/prebuilts/sdk 24c7218067cf1b2fd8f1b7b74cf5659666476011
+platform/prebuilts/tools de65e6e22c909a4b6dc4a1dead4f7872efd8d947
+platform/prebuilts/vndk/v28 18cb1b8dcafcee7b852e053056f3f43eb458558a
+platform/prebuilts/vndk/v29 035390a82a7e1a0642e9e3f06296db9a1d97ba06
+platform/prebuilts/vndk/v30 fef5690db46ff0ca6ba82c3fca983ba59556cb66
+platform/sdk 3a16163f23f530ffeb509476c10f4ec731a224c4
+platform/system/apex 63bad7986864a84c44b49b68a8dff655bdfb92b6
+platform/system/bpf d05e7ad07cdb615cdf6b29cabbb9af3432de5e53
+platform/system/bpfprogs 0b4f838095bce1cb769b38ff4e7ecca3564e5038
+platform/system/bt 3e0056e11600ab053b39cff772fe41c9f4e63f70
+platform/system/ca-certificates 6a8fe2aa11232f628545f46a9afce6c3c16f10af
+platform/system/chre e91a647a0e38d2888f9210ac393eaee8286f6a80
+platform/system/connectivity/wificond 6b4028754320ef5bb5bf85af43666b38ee4978a7
+platform/system/core f97b842c4aeef3d6a36980605ac41a086922a695
+platform/system/extras 3985aa064ef4b29a7497770d5e89359f558dfc1a
+platform/system/gatekeeper 9135ea37e173bf18d960e5e14a44b6e7e18492f5
+platform/system/gsid 980462fd65dae22d9c898aa5de99c2a1c5d4b41d
+platform/system/hardware/interfaces d816d708e3e80885c0d681711266805ab151218d
+platform/system/hwservicemanager ac6c2c6655da7c71322ebbfdd8c651a9faae18db
+platform/system/incremental_delivery 6cfbdea0d489c0ea35ef831b83e82b48db4c694d
+platform/system/iorap 1151c9ed884187f8875e6e326488d33346b91f07
+platform/system/keymaster 90dfeeaccb12e0642197d638f21dc2f8cc2ff791
+platform/system/libartpalette 45eb4e94698a632c5a484112bc90aadb6b7d3353
+platform/system/libbase f618b27b5407df5055f770354f4bc2ef31a98265
+platform/system/libfmq 2d7f4ffa446e219ac16bb0cf8c6ec53cbb3a7068
+platform/system/libhidl f5ae8e3bf4d21baa23210273aef25d24535e93d5
+platform/system/libhwbinder 446d002c1d9059b979a4853ee5120ac2bb02a280
+platform/system/libprocinfo 6e26e0425ce0e1ddd629e90d35bc24fd34ba7a1a
+platform/system/libsysprop 57a2f8c496738ff2212471cd8178046da3b66566
+platform/system/libufdt f00d9de20bbbb28a61d108f73a95dc18d99ee194
+platform/system/libvintf cdbfa3ca0f0c7764e2d9f230a2e001b563c1421d
+platform/system/libziparchive ba1d1aa504c198193e3956329c07b8271355dc3c
+platform/system/linkerconfig 87616d87068bbf68bc0c6dd9a2bb52a25f23588f
+platform/system/logging 0f7a61968808b940ad312708b3aecca2f8cdca35
+platform/system/media bfb8311a9ca8319a091d6293e89f2b7a8db9cc83
+platform/system/memory/libdmabufheap 4a05ac7b2ee7bf50003862a06d5523a2ce445d71
+platform/system/memory/libion f89922fcec77a139944e5f1e5649d4e3f03c0f5d
+platform/system/memory/libmeminfo e3376fdf30b24179b7e44a4232ed2ed7a8b895b0
+platform/system/memory/libmemtrack c6aebbdae64101ac0975068473737e20c571741c
+platform/system/memory/libmemunreachable ba73459ec5d1502b87a284e4ade33e4bdc499d47
+platform/system/memory/lmkd 57736f806099fbe022fe06f8ffd3d7ec028c60b5
+platform/system/netd 8ff8605560a357fe7fdcf2b8e8f5bd8821daf82b
+platform/system/nfc 35b8298467cb1edfe6087ad538e2019b138a3d9a
+platform/system/nvram 23c83cbb1282bac97b76046127752f370d8e8541
+platform/system/security e3ca60963d20469e62e190726739d5f43cf67405
+platform/system/sepolicy fdc09c1bc9079fa95f4ae3f355cc2d39d11adc4b
+platform/system/server_configurable_flags 4f8ee8bff302b48e5b86aaffacc0167ff050ae0f
+platform/system/teeui 904c7ecb012e3b5a4f06332f5ec8be81c9d387a7
+platform/system/testing/gtest_extras 36e730dd717e8533119a978fd4ac74c233f5a2d2
+platform/system/timezone 4642e92d3807a977c7d3372f9a15c73a595e69d0
+platform/system/tools/aidl 3909883936cebe62550a9800ff675fb6afe0fae2
+platform/system/tools/hidl 1854bf1e9a97ea011c05c1359b5c3deee6b1e15f
+platform/system/tools/mkbootimg c691c52a860759e47d06df5ef71c2b319a208e43
+platform/system/tools/sysprop 0ba8ad4b562758ff5c63e651075b5da6880c21e3
+platform/system/tools/xsdc 4ff580e58539af45cc0c9948762f62d3df52bd7c
+platform/system/unwinding e896b480fc105ad7a1fabdd9a479b31ea31e38ce
+platform/system/update_engine 80804c0feb1fbe7868cf32b3efe3d593805ef824
+platform/system/vold 7f215ee02cd2bf2b563d2fd492e3cd608b1b2948
+platform/test/app_compat/csuite 9c0b458dca7793eb74e191633ad8dbc9ab3d33d4
+platform/test/cts-root 3a109f6e68b696370fcdf5c1bd57d30fab6875c3
+platform/test/framework 5fc2e73c8c1afd2ea15b55e1456d3eb7c265722b
+platform/test/mlts/benchmark 0d984bf3ccaadd91cb39d39e810acc99748c5814
 platform/test/mlts/models d3e31924b0c08b439be624ecb19c7051c513fbe5
-platform/test/mts 51b6a511cdb10dfe5bdb559394df92270f75eddc
-platform/test/suite_harness fa831dad5a776fbdc7edd6a92106d8f6ae86c09e
+platform/test/mts 89dad93594fb25376a7e6f5fe168b6a9741c72e3
+platform/test/suite_harness 6882425adbf73db98742c966eebc87e66801b5d4
 platform/test/vti/dashboard 9f2c217836240213fdc9c38fb8e4ed60dca7508d
 platform/test/vti/fuzz_test_serving 92bbe4107e18344e675d200955112f647262fbc9
 platform/test/vti/test_serving 06776920f2405d8841adc09ed08efe09442dda6f
-platform/test/vts 1ecc1a4c4609d1fe79199e9459590def25bdf7a5
-platform/test/vts-testcase/fuzz 751113955bce954ae59a762db67c108bbed621c1
-platform/test/vts-testcase/hal 30c7eeed49f7081ab42af89f16a0d328ddd9504a
+platform/test/vts 16c09e69eb2725297627f75f255460f86a2d44e3
+platform/test/vts-testcase/fuzz 608c5b9d08c2705789751a8bcdb0dfdee22a47ae
+platform/test/vts-testcase/hal d22640fc5c462420df9e4f6922d46fef34f60caf
 platform/test/vts-testcase/hal-trace 3782d14cb8ca24996b199e175525eeea47758632
-platform/test/vts-testcase/kernel c147d1675be41785bac363902c6a9b579185cec7
-platform/test/vts-testcase/nbu e820ff8671671729b138d5fabf971a655f0752a5
-platform/test/vts-testcase/performance b77dbab6102d7ed8432001d0727bb278cd66ea4b
-platform/test/vts-testcase/security b1756096afd1ace78afd297caa1aa674bc3320e5
-platform/test/vts-testcase/vndk 92e3b185b06b805b4aa5b32d523ef7c5df26dbfe
-platform/tools/aadevtools dc96ecb9c7bd037e4064c788954eba042e916283
-platform/tools/acloud 0ebda242c930b13e32b248920e2b434e32853626
-platform/tools/adt/idea 513d33282e4078b778bee5d9ee4e651246327f7c
-platform/tools/apifinder 2b067bfe06186c8921f7b2e0ea95e5b74a916342
-platform/tools/apksig a996359300e8f111958bb3b5dd872a56f3bcbfeb
-platform/tools/apkzlib a32152bbb13b01ab059e5b583cb5457e92060e5d
-platform/tools/asuite afba6eaa4bde03c8e8f1b93d129dca66dfd04629
+platform/test/vts-testcase/kernel 95d0549c32f8334830b0ab8c85f157e2e9dcdc32
+platform/test/vts-testcase/nbu 7dec4275bccc8010a02a72363d01e52d425b5a01
+platform/test/vts-testcase/performance ce75609fd400dfddc649bca9cf4e4d7b7e524617
+platform/test/vts-testcase/security 2cfa0be1d6cb042ac37b8a6ebc728e546c3547a5
+platform/test/vts-testcase/vndk d9c11eab11f5fd5a956d397812ed6a52e5e8bfb0
+platform/tools/aadevtools 148df3027eac6fc264ee3cb1c0f8587483f28a27
+platform/tools/acloud 1d095eda2efdda7d70d81df7a9bc426951dbdf98
+platform/tools/adt/idea 5aab6497100190850044312f0b4d6bb49ebaafa6
+platform/tools/apifinder 94ad3204f08908329983b7aa1714e1c71dbd4327
+platform/tools/apksig 38a5de0b6854d4d64f5f0999a4af7c3f4fe3ed80
+platform/tools/apkzlib 085b7bc6fb8fba825f3823e9b2e6b00a33631096
+platform/tools/asuite d1859e5016a0c589d585e2b91d483e8100e7715e
 platform/tools/base 05590cea66d0c1031d50418d41c8c2b3ea904bb3
 platform/tools/build 6b1bb180690cf463f31b6c1dd0a92e704713bb5d
-platform/tools/carrier_settings f1f8b4294857e1ee88f60a2088ea3e0c4a026708
-platform/tools/currysrc fb432841c4458cebcca7caa3073ab9809f69fcd4
-platform/tools/dexter d9457557da23548b76f970f37857f25092c47820
-platform/tools/doc_generation 2eccdc7e5e66d7736894ea8031e4e54a6f70db82
-platform/tools/external/fat32lib f0c8abee9e685986df1de01e66438dc3c5bd6882
-platform/tools/external_updater dcebbaffc1bdcc71092c57df9cc99338314a3b8d
+platform/tools/carrier_settings 0e400e44d5e11d3a72318691fdcacaee78e04780
+platform/tools/currysrc 5b8f6f9f58b24a6da60a954b755a5947d14db391
+platform/tools/dexter 3e6a6df37f8e91d447bab183cb1cfd32c601df86
+platform/tools/doc_generation d549436356033bbe6d681b422a513f50ea6a3b28
+platform/tools/external/fat32lib 11f28925316de0130253afe22a6ab444038ba3de
+platform/tools/external_updater 63cb2f053446e33d5a113ea495eef314275a7d11
 platform/tools/idea 9b5d02ac8c92b1e71523cc15cb3d168d57fbd898
-platform/tools/loganalysis 24fcf75fe51f4e1f833d9e99aff492b3f73a0e98
-platform/tools/metalava 7dd307ad0117ea3322422eb84fa3df3389373135
+platform/tools/loganalysis 6ebf2f39ea2003762297bb39cf23cd579e17e213
+platform/tools/metalava f955ecf736212b4904d139b387fce83546d21326
 platform/tools/motodev 69989786cefbde82527960a1e100ec9afba46a98
 platform/tools/ndkports 9bf1830e2bc0719142a96a3a86821b5a82b71921
-platform/tools/repohooks 712ec11c936f8a39c086e749b10978b3ccc5b94c
-platform/tools/security 95998679f32e4b4a4723d9abd13aa92de1d70131
+platform/tools/repohooks 851fd07b5393a21db4b3e52fda6e2c352717daa1
+platform/tools/security 500ea0a6a1cfc3fef60fbbb59d52bc5a7e9a22ba
 platform/tools/studio/cloud 58f06e77e051fff3903adabca7acdaa9dd12ec2d
 platform/tools/swt 8996e71047a2bd11efee46ef14e02435ab5fa07a
-platform/tools/test/connectivity 251a1b66c499643a1285f0ed9ad3b74f8fb4410f
-platform/tools/test/graphicsbenchmark d50de4b7fc121e9171cc08a6e476f8250876de6d
-platform/tools/test/openhst ea2a59957ca27660622bf30111b8129e32cfef71
-platform/tools/tradefederation e130244d452e903587a004f7e81793894d40a0f9
-platform/tools/tradefederation/contrib f63c4466ebeb2c62d817a2f83960d73becafc9b1
-platform/tools/tradefederation/prebuilts 2621f5d30464672c5ad72e9a6a652b010218a996
-platform/tools/treble 085c0fe20bc81ac75322b06e98480809cc54bc5e
-platform/tools/trebuchet 0e36df9dee0d54c25daccfc9b7a37cd5d371c551
-toolchain/benchmark c29d67ccd5521fa1f96ec69d3da5314b3dbd77d8
+platform/tools/test/connectivity 78c75cfbece7671814da8b4e69fe4132e6da345b
+platform/tools/test/graphicsbenchmark 360dd4970c3d31d23cca6d9694c47ec730dc33f5
+platform/tools/test/openhst 1cd8abb78a5a0ce0261fbdb6dfbcfcc3dfae27a7
+platform/tools/tradefederation ed1bb4a85bbc7aab8c73c918e899674e3545bb07
+platform/tools/tradefederation/contrib cf2b5967dd6ff1048304f25333528bb9dd85f31d
+platform/tools/tradefederation/prebuilts e8ff644c4cdac5ee8c341d63aa17494547e6d836
+platform/tools/treble da5de7531874d053bf140f09b00e7aa4b06b3335
+platform/tools/trebuchet 56f4a6bdbd0cf2e028a0075916d1d1a84a3333a1
+toolchain/benchmark bef6a36317a8654310db3f4930c1b7e62b2e1770
 toolchain/llvm-project 664b187160dc951c2cea3b69f92decf358d8e75a
-toolchain/pgo-profiles b1be4c3ab11695403b97b3e9913661546e4813a7
-tools/platform-compat 473b353535dc9da593e9caa0fe6759d4174ee404
+toolchain/pgo-profiles 3955856949b6cbc672aba13faa70edb607e8143b
+tools/platform-compat 36edcf918553c9902cc43db57604699680b77a03
diff --git a/simpleperf_utils.py b/simpleperf_utils.py
index 3bb4d57..2ef6df6 100644
--- a/simpleperf_utils.py
+++ b/simpleperf_utils.py
@@ -29,15 +29,19 @@
 import sys
 import time
 
+
 def get_script_dir():
     return os.path.dirname(os.path.realpath(__file__))
 
+
 def is_windows():
     return sys.platform == 'win32' or sys.platform == 'cygwin'
 
+
 def is_darwin():
     return sys.platform == 'darwin'
 
+
 def get_platform():
     if is_windows():
         return 'windows'
@@ -45,6 +49,7 @@
         return 'darwin'
     return 'linux'
 
+
 def is_python3():
     return sys.version_info >= (3, 0)
 
@@ -64,12 +69,15 @@
 def log_fatal(msg):
     raise Exception(msg)
 
+
 def log_exit(msg):
     sys.exit(msg)
 
+
 def disable_debug_log():
     logging.getLogger().setLevel(logging.WARN)
 
+
 def set_log_level(level_name):
     if level_name == 'debug':
         level = logging.DEBUG
@@ -81,6 +89,7 @@
         log_fatal('unknown log level: %s' % level_name)
     logging.getLogger().setLevel(level)
 
+
 def str_to_bytes(str_value):
     if not is_python3():
         return str_value
@@ -88,6 +97,7 @@
     # hence we have to convert. For now using utf-8 as the encoding.
     return str_value.encode('utf-8')
 
+
 def bytes_to_str(bytes_value):
     if not bytes_value:
         return ''
@@ -95,6 +105,7 @@
         return bytes_value
     return bytes_value.decode('utf-8')
 
+
 def get_target_binary_path(arch, binary_name):
     if arch == 'aarch64':
         arch = 'arm64'
@@ -115,7 +126,7 @@
         elif '.' not in binary_name:
             binary_name += '.exe'
         dirname = os.path.join(dirname, 'windows')
-    elif sys.platform == 'darwin': # OSX
+    elif sys.platform == 'darwin':  # OSX
         if binary_name.endswith('.so'):
             binary_name = binary_name[0:-3] + '.dylib'
         dirname = os.path.join(dirname, 'darwin')
@@ -292,11 +303,9 @@
         self.enable_switch_to_root = enable_switch_to_root
         self.serial_number = None
 
-
     def run(self, adb_args):
         return self.run_and_return_output(adb_args)[0]
 
-
     def run_and_return_output(self, adb_args, log_output=True, log_stderr=True):
         adb_args = [self.adb_path] + adb_args
         log_debug('run adb cmd: %s' % adb_args)
@@ -321,14 +330,12 @@
     def check_run(self, adb_args):
         self.check_run_and_return_output(adb_args)
 
-
     def check_run_and_return_output(self, adb_args, stdout_file=None, log_output=True):
         result, stdoutdata = self.run_and_return_output(adb_args, stdout_file, log_output)
         if not result:
             log_exit('run "adb %s" failed' % adb_args)
         return stdoutdata
 
-
     def _unroot(self):
         result, stdoutdata = self.run_and_return_output(['shell', 'whoami'])
         if not result:
@@ -340,7 +347,6 @@
         self.run(['wait-for-device'])
         time.sleep(1)
 
-
     def switch_to_root(self):
         if not self.enable_switch_to_root:
             self._unroot()
@@ -366,7 +372,6 @@
     def set_property(self, name, value):
         return self.run(['shell', 'setprop', name, value])
 
-
     def get_device_arch(self):
         output = self.check_run_and_return_output(['shell', 'uname', '-m'])
         if 'aarch64' in output:
@@ -380,7 +385,6 @@
         log_fatal('unsupported architecture: %s' % output.strip())
         return ''
 
-
     def get_android_version(self):
         """ Get Android version on device, like 7 is for Android N, 8 is for Android O."""
         build_version = self.get_property('ro.build.version.release')
@@ -429,12 +433,14 @@
         # webbrowser.get() doesn't work well on darwin/windows.
         webbrowser.open_new_tab(report_path)
 
+
 def is_elf_file(path):
     if os.path.isfile(path):
         with open(path, 'rb') as fh:
             return fh.read(4) == b'\x7fELF'
     return False
 
+
 def find_real_dso_path(dso_path_in_record_file, binary_cache_path):
     """ Given the path of a shared library in perf.data, find its real path in the file system. """
     if binary_cache_path:
@@ -477,6 +483,7 @@
         """ Info of a dynamic shared library.
             addrs: a map from address to Addr object in this dso.
         """
+
         def __init__(self):
             self.addrs = {}
 
@@ -486,6 +493,7 @@
             source_lines: a list of [file_id, line_number] for addr.
                           source_lines[:-1] are all for inlined functions.
         """
+
         def __init__(self, func_addr):
             self.func_addr = func_addr
             self.source_lines = None
@@ -732,6 +740,7 @@
 
 class Objdump(object):
     """ A wrapper of objdump to disassemble code. """
+
     def __init__(self, ndk_path, binary_cache_path):
         self.ndk_path = ndk_path
         self.binary_cache_path = binary_cache_path
@@ -794,6 +803,7 @@
 
 class ReadElf(object):
     """ A wrapper of readelf. """
+
     def __init__(self, ndk_path):
         self.readelf_path = find_tool_path('llvm-readelf', ndk_path)
         if not self.readelf_path:
@@ -860,6 +870,7 @@
                 pass
         return section_names
 
+
 def extant_dir(arg):
     """ArgumentParser type that only accepts extant directories.
 
@@ -874,6 +885,7 @@
         raise argparse.ArgumentTypeError('{} is not a directory.'.format(path))
     return path
 
+
 def extant_file(arg):
     """ArgumentParser type that only accepts extant files.
 
@@ -888,4 +900,10 @@
         raise argparse.ArgumentTypeError('{} is not a file.'.format(path))
     return path
 
+
+class ArgParseFormatter(
+        argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
+    pass
+
+
 logging.getLogger().setLevel(logging.DEBUG)
diff --git a/test.py b/test.py
deleted file mode 100755
index 3191901..0000000
--- a/test.py
+++ /dev/null
@@ -1,1888 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""test.py: Tests for simpleperf python scripts.
-
-These are smoke tests Using examples to run python scripts.
-For each example, we go through the steps of running each python script.
-Examples are collected from simpleperf/demo, which includes:
-  SimpleperfExamplePureJava
-  SimpleperfExampleWithNative
-  SimpleperfExampleOfKotlin
-
-Tested python scripts include:
-  app_profiler.py
-  report.py
-  annotate.py
-  report_sample.py
-  pprof_proto_generator.py
-  report_html.py
-
-Test using both `adb root` and `adb unroot`.
-
-"""
-from __future__ import print_function
-import argparse
-import collections
-import filecmp
-import fnmatch
-import inspect
-import json
-import logging
-import os
-import re
-import shutil
-import signal
-import subprocess
-import sys
-import time
-import types
-import unittest
-
-from app_profiler import NativeLibDownloader
-from binary_cache_builder import BinaryCacheBuilder
-from simpleperf_report_lib import ReportLib
-from simpleperf_utils import (
-    AdbHelper, Addr2Nearestline, bytes_to_str, extant_dir, find_tool_path, get_script_dir,
-    is_elf_file, is_python3, is_windows, log_exit, log_info, log_fatal, Objdump, ReadElf, remove,
-    SourceFileSearcher, str_to_bytes)
-
-try:
-    # pylint: disable=unused-import
-    import google.protobuf
-    # pylint: disable=ungrouped-imports
-    from pprof_proto_generator import load_pprof_profile
-    HAS_GOOGLE_PROTOBUF = True
-except ImportError:
-    HAS_GOOGLE_PROTOBUF = False
-
-INFERNO_SCRIPT = os.path.join(get_script_dir(), "inferno.bat" if is_windows() else "./inferno.sh")
-
-
-class TestLogger:
-    """ Write test progress in sys.stderr and keep verbose log in log file. """
-    def __init__(self):
-        self.log_file = 'test.log'
-        remove(self.log_file)
-        # Logs can come from multiple processes. So use append mode to avoid overwrite.
-        self.log_fh = open(self.log_file, 'a')
-        logging.basicConfig(filename=self.log_file)
-
-    def writeln(self, s):
-        return self.write(s + '\n')
-
-    def write(self, s):
-        sys.stderr.write(s)
-        self.log_fh.write(s)
-        # Child processes can also write to log file, so flush it immediately to keep the order.
-        self.flush()
-
-    def flush(self):
-        self.log_fh.flush()
-
-
-TEST_LOGGER = TestLogger()
-
-
-class TestHelper:
-    """ Keep global test info. """
-
-    def __init__(self):
-        self.script_dir = os.path.abspath(get_script_dir())
-        self.cur_dir = os.getcwd()
-        self.testdata_dir = os.path.join(self.cur_dir, 'testdata')
-        self.test_base_dir = os.path.join(self.cur_dir, 'test_results')
-        self.adb = AdbHelper(enable_switch_to_root=True)
-        self.android_version = self.adb.get_android_version()
-        self.device_features = None
-        self.browser_option = []
-        self.progress_fh = None
-        self.ndk_path = None
-
-    def testdata_path(self, testdata_name):
-        """ Return the path of a test data. """
-        return os.path.join(self.testdata_dir, testdata_name.replace('/', os.sep))
-
-    def test_dir(self, test_name):
-        """ Return the dir to run a test. """
-        return os.path.join(self.test_base_dir, test_name)
-
-    def script_path(self, script_name):
-        """ Return the dir of python scripts. """
-        return os.path.join(self.script_dir, script_name)
-
-    def get_device_features(self):
-        if self.device_features is None:
-            args = [sys.executable, self.script_path(
-                'run_simpleperf_on_device.py'), 'list', '--show-features']
-            output = subprocess.check_output(args, stderr=TEST_LOGGER.log_fh)
-            output = bytes_to_str(output)
-            self.device_features = output.split()
-        return self.device_features
-
-    def is_trace_offcpu_supported(self):
-        return 'trace-offcpu' in self.get_device_features()
-
-    def build_testdata(self):
-        """ Collect testdata in self.testdata_dir.
-            In system/extras/simpleperf/scripts, testdata comes from:
-                <script_dir>/../testdata, <script_dir>/script_testdata, <script_dir>/../demo
-            In prebuilts/simpleperf, testdata comes from:
-                <script_dir>/testdata
-        """
-        if os.path.isdir(self.testdata_dir):
-            return  # already built
-        os.makedirs(self.testdata_dir)
-
-        source_dirs = [os.path.join('..', 'testdata'), 'script_testdata',
-                       os.path.join('..', 'demo'), 'testdata']
-        source_dirs = [os.path.join(self.script_dir, x) for x in source_dirs]
-        source_dirs = [x for x in source_dirs if os.path.isdir(x)]
-
-        for source_dir in source_dirs:
-            for name in os.listdir(source_dir):
-                source = os.path.join(source_dir, name)
-                target = os.path.join(self.testdata_dir, name)
-                if os.path.exists(target):
-                    continue
-                if os.path.isfile(source):
-                    shutil.copyfile(source, target)
-                elif os.path.isdir(source):
-                    shutil.copytree(source, target)
-
-    def get_32bit_abi(self):
-        return self.adb.get_property('ro.product.cpu.abilist32').strip().split(',')[0]
-
-    def write_progress(self, progress):
-        if self.progress_fh:
-            self.progress_fh.write(progress + '\n')
-            self.progress_fh.flush()
-
-
-TEST_HELPER = TestHelper()
-
-
-class TestBase(unittest.TestCase):
-    def setUp(self):
-        """ Run each test in a separate dir. """
-        self.test_dir = TEST_HELPER.test_dir('%s.%s' % (
-            self.__class__.__name__, self._testMethodName))
-        os.makedirs(self.test_dir)
-        self.saved_cwd = os.getcwd()
-        os.chdir(self.test_dir)
-        TEST_LOGGER.writeln('begin test %s.%s' % (self.__class__.__name__, self._testMethodName))
-        self.start_time = time.time()
-
-
-    def run(self, result=None):
-        ret = super(TestBase, self).run(result)
-        if result.errors and result.errors[-1][0] == self:
-            status = 'FAILED'
-            err_info = result.errors[-1][1]
-        elif result.failures and result.failures[-1][0] == self:
-            status = 'FAILED'
-            err_info = result.failures[-1][1]
-        else:
-            status = 'OK'
-
-        time_taken = time.time() - self.start_time
-        TEST_LOGGER.writeln(
-            'end test %s.%s %s (%.3fs)' %
-            (self.__class__.__name__, self._testMethodName, status, time_taken))
-        if status != 'OK':
-            TEST_LOGGER.writeln(err_info)
-
-        # Remove test data for passed tests to save space.
-        os.chdir(self.saved_cwd)
-        if status == 'OK':
-            shutil.rmtree(self.test_dir)
-        TEST_HELPER.write_progress(
-            '%s.%s  %s' % (self.__class__.__name__, self._testMethodName, status))
-        return ret
-
-    def run_cmd(self, args, return_output=False, drop_output=True):
-        if args[0] == 'report_html.py' or args[0] == INFERNO_SCRIPT:
-            args += TEST_HELPER.browser_option
-        if TEST_HELPER.ndk_path:
-            if args[0] in ['app_profiler.py', 'binary_cache_builder.py', 'pprof_proto_generator.py',
-                           'report_html.py']:
-                args += ['--ndk_path', TEST_HELPER.ndk_path]
-        if args[0].endswith('.py'):
-            args = [sys.executable, TEST_HELPER.script_path(args[0])] + args[1:]
-        use_shell = args[0].endswith('.bat')
-        try:
-            if return_output:
-                stdout_fd = subprocess.PIPE
-                drop_output = False
-            elif drop_output:
-                if is_python3():
-                    stdout_fd = subprocess.DEVNULL
-                else:
-                    stdout_fd = open(os.devnull, 'w')
-            else:
-                stdout_fd = None
-
-            subproc = subprocess.Popen(args, stdout=stdout_fd,
-                                       stderr=TEST_LOGGER.log_fh, shell=use_shell)
-            stdout_data, _ = subproc.communicate()
-            output_data = bytes_to_str(stdout_data)
-            returncode = subproc.returncode
-
-            if drop_output and not is_python3():
-                stdout_fd.close()
-
-        except OSError:
-            returncode = None
-        self.assertEqual(returncode, 0, msg="failed to run cmd: %s" % args)
-        if return_output:
-            return output_data
-        return ''
-
-    def check_strings_in_file(self, filename, strings):
-        self.check_exist(filename=filename)
-        with open(filename, 'r') as fh:
-            self.check_strings_in_content(fh.read(), strings)
-
-    def check_exist(self, filename=None, dirname=None):
-        if filename:
-            self.assertTrue(os.path.isfile(filename), filename)
-        if dirname:
-            self.assertTrue(os.path.isdir(dirname), dirname)
-
-    def check_strings_in_content(self, content, strings):
-        fulfilled = [content.find(s) != -1 for s in strings]
-        self.check_fulfilled_entries(fulfilled, strings)
-
-    def check_fulfilled_entries(self, fulfilled, entries):
-        failed_entries = []
-        for ok, entry in zip(fulfilled, entries):
-            if not ok:
-                failed_entries.append(entry)
-
-        if failed_entries:
-            self.fail('failed in below entries: %s' % (failed_entries,))
-
-
-class TestExampleBase(TestBase):
-    @classmethod
-    def prepare(cls, example_name, package_name, activity_name, abi=None, adb_root=False):
-        cls.adb = AdbHelper(enable_switch_to_root=adb_root)
-        cls.example_path = TEST_HELPER.testdata_path(example_name)
-        if not os.path.isdir(cls.example_path):
-            log_fatal("can't find " + cls.example_path)
-        for root, _, files in os.walk(cls.example_path):
-            if 'app-profiling.apk' in files:
-                cls.apk_path = os.path.join(root, 'app-profiling.apk')
-                break
-        if not hasattr(cls, 'apk_path'):
-            log_fatal("can't find app-profiling.apk under " + cls.example_path)
-        cls.package_name = package_name
-        cls.activity_name = activity_name
-        args = ["install", "-r"]
-        if abi:
-            args += ["--abi", abi]
-        args.append(cls.apk_path)
-        cls.adb.check_run(args)
-        cls.adb_root = adb_root
-        cls.has_perf_data_for_report = False
-        # On Android >= P (version 9), we can profile JITed and interpreted Java code.
-        # So only compile Java code on Android <= O (version 8).
-        cls.use_compiled_java_code = TEST_HELPER.android_version <= 8
-        cls.testcase_dir = TEST_HELPER.test_dir(cls.__name__)
-
-    @classmethod
-    def tearDownClass(cls):
-        remove(cls.testcase_dir)
-        if hasattr(cls, 'package_name'):
-            cls.adb.check_run(["uninstall", cls.package_name])
-
-    def setUp(self):
-        super(TestExampleBase, self).setUp()
-        if 'TraceOffCpu' in self.id() and not TEST_HELPER.is_trace_offcpu_supported():
-            self.skipTest('trace-offcpu is not supported on device')
-        # Use testcase_dir to share a common perf.data for reporting. So we don't need to
-        # generate it for each test.
-        if not os.path.isdir(self.testcase_dir):
-            os.makedirs(self.testcase_dir)
-            os.chdir(self.testcase_dir)
-            self.run_app_profiler(compile_java_code=self.use_compiled_java_code)
-            os.chdir(self.test_dir)
-
-        for name in os.listdir(self.testcase_dir):
-            path = os.path.join(self.testcase_dir, name)
-            if os.path.isfile(path):
-                shutil.copy(path, self.test_dir)
-            elif os.path.isdir(path):
-                shutil.copytree(path, os.path.join(self.test_dir, name))
-
-    def run(self, result=None):
-        self.__class__.test_result = result
-        super(TestExampleBase, self).run(result)
-
-    def run_app_profiler(self, record_arg="-g --duration 10", build_binary_cache=True,
-                         start_activity=True, compile_java_code=False):
-        args = ['app_profiler.py', '--app', self.package_name, '-r', record_arg, '-o', 'perf.data']
-        if not build_binary_cache:
-            args.append("-nb")
-        if compile_java_code:
-            args.append('--compile_java_code')
-        if start_activity:
-            args += ["-a", self.activity_name]
-        args += ["-lib", self.example_path]
-        if not self.adb_root:
-            args.append("--disable_adb_root")
-        self.run_cmd(args)
-        self.check_exist(filename="perf.data")
-        if build_binary_cache:
-            self.check_exist(dirname="binary_cache")
-
-    def check_file_under_dir(self, dirname, filename):
-        self.check_exist(dirname=dirname)
-        for _, _, files in os.walk(dirname):
-            for f in files:
-                if f == filename:
-                    return
-        self.fail("Failed to call check_file_under_dir(dir=%s, file=%s)" % (dirname, filename))
-
-    def check_annotation_summary(self, summary_file, check_entries):
-        """ check_entries is a list of (name, accumulated_period, period).
-            This function checks for each entry, if the line containing [name]
-            has at least required accumulated_period and period.
-        """
-        self.check_exist(filename=summary_file)
-        with open(summary_file, 'r') as fh:
-            summary = fh.read()
-        fulfilled = [False for x in check_entries]
-        summary_check_re = re.compile(r'accumulated_period:\s*([\d.]+)%.*period:\s*([\d.]+)%')
-        for line in summary.split('\n'):
-            for i, (name, need_acc_period, need_period) in enumerate(check_entries):
-                if not fulfilled[i] and name in line:
-                    m = summary_check_re.search(line)
-                    if m:
-                        acc_period = float(m.group(1))
-                        period = float(m.group(2))
-                        if acc_period >= need_acc_period and period >= need_period:
-                            fulfilled[i] = True
-
-        self.check_fulfilled_entries(fulfilled, check_entries)
-
-    def check_inferno_report_html(self, check_entries, filename="report.html"):
-        self.check_exist(filename=filename)
-        with open(filename, 'r') as fh:
-            data = fh.read()
-        fulfilled = [False for _ in check_entries]
-        for line in data.split('\n'):
-            # each entry is a (function_name, min_percentage) pair.
-            for i, entry in enumerate(check_entries):
-                if fulfilled[i] or line.find(entry[0]) == -1:
-                    continue
-                m = re.search(r'(\d+\.\d+)%', line)
-                if m and float(m.group(1)) >= entry[1]:
-                    fulfilled[i] = True
-                    break
-        self.check_fulfilled_entries(fulfilled, check_entries)
-
-    def common_test_app_profiler(self):
-        self.run_cmd(["app_profiler.py", "-h"])
-        remove("binary_cache")
-        self.run_app_profiler(build_binary_cache=False)
-        self.assertFalse(os.path.isdir("binary_cache"))
-        args = ["binary_cache_builder.py"]
-        if not self.adb_root:
-            args.append("--disable_adb_root")
-        self.run_cmd(args)
-        self.check_exist(dirname="binary_cache")
-        remove("binary_cache")
-        self.run_app_profiler(build_binary_cache=True)
-        self.run_app_profiler()
-        self.run_app_profiler(start_activity=False)
-
-    def common_test_report(self):
-        self.run_cmd(["report.py", "-h"])
-        self.run_cmd(["report.py"])
-        self.run_cmd(["report.py", "-i", "perf.data"])
-        self.run_cmd(["report.py", "-g"])
-        self.run_cmd(["report.py", "--self-kill-for-testing", "-g", "--gui"])
-
-    def common_test_annotate(self):
-        self.run_cmd(["annotate.py", "-h"])
-        remove("annotated_files")
-        self.run_cmd(["annotate.py", "-s", self.example_path])
-        self.check_exist(dirname="annotated_files")
-
-    def common_test_report_sample(self, check_strings):
-        self.run_cmd(["report_sample.py", "-h"])
-        self.run_cmd(["report_sample.py"])
-        output = self.run_cmd(["report_sample.py", "perf.data"], return_output=True)
-        self.check_strings_in_content(output, check_strings)
-
-    def common_test_pprof_proto_generator(self, check_strings_with_lines,
-                                          check_strings_without_lines):
-        if not HAS_GOOGLE_PROTOBUF:
-            log_info('Skip test for pprof_proto_generator because google.protobuf is missing')
-            return
-        self.run_cmd(["pprof_proto_generator.py", "-h"])
-        self.run_cmd(["pprof_proto_generator.py"])
-        remove("pprof.profile")
-        self.run_cmd(["pprof_proto_generator.py", "-i", "perf.data", "-o", "pprof.profile"])
-        self.check_exist(filename="pprof.profile")
-        self.run_cmd(["pprof_proto_generator.py", "--show"])
-        output = self.run_cmd(["pprof_proto_generator.py", "--show", "pprof.profile"],
-                              return_output=True)
-        self.check_strings_in_content(output, check_strings_with_lines + ["has_line_numbers: True"])
-        remove("binary_cache")
-        self.run_cmd(["pprof_proto_generator.py"])
-        output = self.run_cmd(["pprof_proto_generator.py", "--show", "pprof.profile"],
-                              return_output=True)
-        self.check_strings_in_content(output, check_strings_without_lines +
-                                      ["has_line_numbers: False"])
-
-    def common_test_inferno(self):
-        self.run_cmd([INFERNO_SCRIPT, "-h"])
-        remove("perf.data")
-        append_args = [] if self.adb_root else ["--disable_adb_root"]
-        self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-t", "3"] + append_args)
-        self.check_exist(filename="perf.data")
-        self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-f", "1000", "-du", "-t", "1"] +
-                     append_args)
-        self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-e", "100000 cpu-cycles",
-                      "-t", "1"] + append_args)
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-
-    def common_test_report_html(self):
-        self.run_cmd(['report_html.py', '-h'])
-        self.run_cmd(['report_html.py'])
-        self.run_cmd(['report_html.py', '--add_source_code', '--source_dirs', 'testdata'])
-        self.run_cmd(['report_html.py', '--add_disassembly'])
-        # Test with multiple perf.data.
-        shutil.move('perf.data', 'perf2.data')
-        self.run_app_profiler(record_arg='-g -f 1000 --duration 3 -e task-clock:u')
-        self.run_cmd(['report_html.py', '-i', 'perf.data', 'perf2.data'])
-
-
-class TestExamplePureJava(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExamplePureJava",
-                    "com.example.simpleperf.simpleperfexamplepurejava",
-                    ".MainActivity")
-
-    def test_app_profiler(self):
-        self.common_test_app_profiler()
-
-    def test_app_profiler_profile_from_launch(self):
-        self.run_app_profiler(start_activity=True, build_binary_cache=False)
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
-            "__start_thread"])
-
-    def test_app_profiler_multiprocesses(self):
-        self.adb.check_run(['shell', 'am', 'force-stop', self.package_name])
-        self.adb.check_run(['shell', 'am', 'start', '-n',
-                            self.package_name + '/.MultiProcessActivity'])
-        # Wait until both MultiProcessActivity and MultiProcessService set up.
-        time.sleep(3)
-        self.run_app_profiler(start_activity=False)
-        self.run_cmd(["report.py", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", ["BusyService", "BusyThread"])
-
-    def test_app_profiler_with_ctrl_c(self):
-        if is_windows():
-            return
-        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
-        time.sleep(1)
-        args = [sys.executable, TEST_HELPER.script_path("app_profiler.py"),
-                "--app", self.package_name, "-r", "--duration 10000", "--disable_adb_root"]
-        subproc = subprocess.Popen(args)
-        time.sleep(3)
-
-        subproc.send_signal(signal.SIGINT)
-        subproc.wait()
-        self.assertEqual(subproc.returncode, 0)
-        self.run_cmd(["report.py"])
-
-    def test_app_profiler_stop_after_app_exit(self):
-        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
-        time.sleep(1)
-        subproc = subprocess.Popen(
-            [sys.executable, TEST_HELPER.script_path('app_profiler.py'),
-             '--app', self.package_name, '-r', '--duration 10000', '--disable_adb_root'])
-        time.sleep(3)
-        self.adb.check_run(['shell', 'am', 'force-stop', self.package_name])
-        subproc.wait()
-        self.assertEqual(subproc.returncode, 0)
-        self.run_cmd(["report.py"])
-
-    def test_app_profiler_with_ndk_path(self):
-        # Although we pass an invalid ndk path, it should be able to find tools in default ndk path.
-        self.run_cmd(['app_profiler.py', '--app', self.package_name, '-a', self.activity_name,
-                      '--ndk_path', '.'])
-
-    def test_report(self):
-        self.common_test_report()
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
-            "__start_thread"])
-
-    def test_profile_with_process_id(self):
-        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
-        time.sleep(1)
-        pid = self.adb.check_run_and_return_output([
-            'shell', 'pidof', 'com.example.simpleperf.simpleperfexamplepurejava']).strip()
-        self.run_app_profiler(start_activity=False, record_arg='-g --duration 10 -p ' + pid)
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
-            "__start_thread"])
-
-    def test_annotate(self):
-        self.common_test_annotate()
-        if not self.use_compiled_java_code:
-            # Currently annotating Java code is only supported when the Java code is compiled.
-            return
-        self.check_file_under_dir("annotated_files", "MainActivity.java")
-        summary_file = os.path.join("annotated_files", "summary")
-        self.check_annotation_summary(summary_file, [
-            ("MainActivity.java", 80, 80),
-            ("run", 80, 0),
-            ("callFunction", 0, 0),
-            ("line 23", 80, 0)])
-
-    def test_report_sample(self):
-        self.common_test_report_sample(
-            ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
-             "__start_thread"])
-
-    def test_pprof_proto_generator(self):
-        check_strings_with_lines = []
-        if self.use_compiled_java_code:
-            check_strings_with_lines = [
-                "com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java",
-                "run"]
-        self.common_test_pprof_proto_generator(
-            check_strings_with_lines=check_strings_with_lines,
-            check_strings_without_lines=[
-                "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run"])
-
-    def test_inferno(self):
-        self.common_test_inferno()
-        self.run_app_profiler()
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.check_inferno_report_html(
-            [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)])
-        self.run_cmd([INFERNO_SCRIPT, "-sc", "-o", "report2.html"])
-        self.check_inferno_report_html(
-            [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)],
-            "report2.html")
-
-    def test_inferno_in_another_dir(self):
-        test_dir = 'inferno_testdir'
-        os.mkdir(test_dir)
-        os.chdir(test_dir)
-        self.run_cmd(['app_profiler.py', '--app', self.package_name,
-                      '-r', '-e task-clock:u -g --duration 3'])
-        self.check_exist(filename="perf.data")
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-
-    def test_report_html(self):
-        self.common_test_report_html()
-
-    def test_run_simpleperf_without_usb_connection(self):
-        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
-        self.run_cmd(['run_simpleperf_without_usb_connection.py', 'start', '-p',
-                      self.package_name, '--size_limit', '1M'])
-        self.adb.check_run(['kill-server'])
-        time.sleep(3)
-        # Start adb process outside self.test_dir. Because it will be removed after testing.
-        os.chdir(self.saved_cwd)
-        self.adb.check_run(['devices'])
-        os.chdir(self.test_dir)
-        self.run_cmd(['run_simpleperf_without_usb_connection.py', 'stop'])
-        self.check_exist(filename="perf.data")
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-
-
-class TestExamplePureJavaRoot(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExamplePureJava",
-                    "com.example.simpleperf.simpleperfexamplepurejava",
-                    ".MainActivity",
-                    adb_root=True)
-
-    def test_app_profiler(self):
-        self.common_test_app_profiler()
-
-
-class TestExamplePureJavaTraceOffCpu(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExamplePureJava",
-                    "com.example.simpleperf.simpleperfexamplepurejava",
-                    ".SleepActivity")
-
-    def test_smoke(self):
-        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run",
-            "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction",
-            "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction"
-            ])
-        remove("annotated_files")
-        self.run_cmd(["annotate.py", "-s", self.example_path])
-        self.check_exist(dirname="annotated_files")
-        if self.use_compiled_java_code:
-            self.check_file_under_dir("annotated_files", "SleepActivity.java")
-            summary_file = os.path.join("annotated_files", "summary")
-            self.check_annotation_summary(summary_file, [
-                ("SleepActivity.java", 80, 20),
-                ("run", 80, 0),
-                ("RunFunction", 20, 20),
-                ("SleepFunction", 20, 0),
-                ("line 24", 1, 0),
-                ("line 32", 20, 0)])
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.check_inferno_report_html(
-            [('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run', 80),
-             ('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction',
-              20),
-             ('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction',
-              20)])
-
-
-class TestExampleWithNative(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".MainActivity")
-
-    def test_app_profiler(self):
-        self.common_test_app_profiler()
-
-    def test_app_profiler_profile_from_launch(self):
-        self.run_app_profiler(start_activity=True, build_binary_cache=False)
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
-
-    def test_report(self):
-        self.common_test_report()
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
-
-    def test_annotate(self):
-        self.common_test_annotate()
-        self.check_file_under_dir("annotated_files", "native-lib.cpp")
-        summary_file = os.path.join("annotated_files", "summary")
-        self.check_annotation_summary(summary_file, [
-            ("native-lib.cpp", 20, 0),
-            ("BusyLoopThread", 20, 0),
-            ("line 46", 20, 0)])
-
-    def test_report_sample(self):
-        self.common_test_report_sample(
-            ["BusyLoopThread",
-             "__start_thread"])
-
-    def test_pprof_proto_generator(self):
-        check_strings_with_lines = [
-            "native-lib.cpp",
-            "BusyLoopThread",
-            # Check if dso name in perf.data is replaced by binary path in binary_cache.
-            'filename: binary_cache']
-        self.common_test_pprof_proto_generator(
-            check_strings_with_lines,
-            check_strings_without_lines=["BusyLoopThread"])
-
-    def test_inferno(self):
-        self.common_test_inferno()
-        self.run_app_profiler()
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.check_inferno_report_html([('BusyLoopThread', 20)])
-
-    def test_report_html(self):
-        self.common_test_report_html()
-        self.run_cmd(['report_html.py', '--add_source_code', '--source_dirs', 'testdata',
-                      '--add_disassembly', '--binary_filter', "libnative-lib.so"])
-
-
-class TestExampleWithNativeRoot(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".MainActivity",
-                    adb_root=True)
-
-    def test_app_profiler(self):
-        self.common_test_app_profiler()
-
-
-class TestExampleWithNativeTraceOffCpu(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".SleepActivity")
-
-    def test_smoke(self):
-        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
-        self.run_cmd(["report.py", "-g", "--comms", "SleepThread", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "SleepThread(void*)",
-            "RunFunction()",
-            "SleepFunction(unsigned long long)"])
-        remove("annotated_files")
-        self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "SleepThread"])
-        self.check_exist(dirname="annotated_files")
-        self.check_file_under_dir("annotated_files", "native-lib.cpp")
-        summary_file = os.path.join("annotated_files", "summary")
-        self.check_annotation_summary(summary_file, [
-            ("native-lib.cpp", 80, 20),
-            ("SleepThread", 80, 0),
-            ("RunFunction", 20, 20),
-            ("SleepFunction", 20, 0),
-            ("line 73", 20, 0),
-            ("line 83", 20, 0)])
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.check_inferno_report_html([('SleepThread', 80),
-                                        ('RunFunction', 20),
-                                        ('SleepFunction', 20)])
-
-
-class TestExampleWithNativeJniCall(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".MixActivity")
-
-    def test_smoke(self):
-        self.run_app_profiler()
-        self.run_cmd(["report.py", "-g", "--comms", "BusyThread", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run",
-            "Java_com_example_simpleperf_simpleperfexamplewithnative_MixActivity_callFunction"])
-        remove("annotated_files")
-        self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "BusyThread"])
-        self.check_exist(dirname="annotated_files")
-        self.check_file_under_dir("annotated_files", "native-lib.cpp")
-        summary_file = os.path.join("annotated_files", "summary")
-        self.check_annotation_summary(summary_file, [("native-lib.cpp", 5, 0), ("line 40", 5, 0)])
-        if self.use_compiled_java_code:
-            self.check_file_under_dir("annotated_files", "MixActivity.java")
-            self.check_annotation_summary(summary_file, [
-                ("MixActivity.java", 80, 0),
-                ("run", 80, 0),
-                ("line 26", 20, 0),
-                ("native-lib.cpp", 5, 0),
-                ("line 40", 5, 0)])
-
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-
-
-class TestExampleWithNativeForce32Bit(TestExampleWithNative):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".MainActivity",
-                    abi=TEST_HELPER.get_32bit_abi())
-
-
-class TestExampleWithNativeRootForce32Bit(TestExampleWithNativeRoot):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".MainActivity",
-                    abi=TEST_HELPER.get_32bit_abi(),
-                    adb_root=False)
-
-
-class TestExampleWithNativeTraceOffCpuForce32Bit(TestExampleWithNativeTraceOffCpu):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleWithNative",
-                    "com.example.simpleperf.simpleperfexamplewithnative",
-                    ".SleepActivity",
-                    abi=TEST_HELPER.get_32bit_abi())
-
-
-class TestExampleOfKotlin(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleOfKotlin",
-                    "com.example.simpleperf.simpleperfexampleofkotlin",
-                    ".MainActivity")
-
-    def test_app_profiler(self):
-        self.common_test_app_profiler()
-
-    def test_app_profiler_profile_from_launch(self):
-        self.run_app_profiler(start_activity=True, build_binary_cache=False)
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
-            "run", "__start_thread"])
-
-    def test_report(self):
-        self.common_test_report()
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.check_strings_in_file("report.txt", [
-            "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
-            "run", "__start_thread"])
-
-    def test_annotate(self):
-        if not self.use_compiled_java_code:
-            return
-        self.common_test_annotate()
-        self.check_file_under_dir("annotated_files", "MainActivity.kt")
-        summary_file = os.path.join("annotated_files", "summary")
-        self.check_annotation_summary(summary_file, [
-            ("MainActivity.kt", 80, 80),
-            ("run", 80, 0),
-            ("callFunction", 0, 0),
-            ("line 19", 80, 0),
-            ("line 25", 0, 0)])
-
-    def test_report_sample(self):
-        self.common_test_report_sample([
-            "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
-            "run", "__start_thread"])
-
-    def test_pprof_proto_generator(self):
-        check_strings_with_lines = []
-        if self.use_compiled_java_code:
-            check_strings_with_lines = [
-                "com/example/simpleperf/simpleperfexampleofkotlin/MainActivity.kt",
-                "run"]
-        self.common_test_pprof_proto_generator(
-            check_strings_with_lines=check_strings_with_lines,
-            check_strings_without_lines=["com.example.simpleperf.simpleperfexampleofkotlin." +
-                                         "MainActivity$createBusyThread$1.run"])
-
-    def test_inferno(self):
-        self.common_test_inferno()
-        self.run_app_profiler()
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.check_inferno_report_html([('com.example.simpleperf.simpleperfexampleofkotlin.' +
-                                         'MainActivity$createBusyThread$1.run', 80)])
-
-    def test_report_html(self):
-        self.common_test_report_html()
-
-
-class TestExampleOfKotlinRoot(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleOfKotlin",
-                    "com.example.simpleperf.simpleperfexampleofkotlin",
-                    ".MainActivity",
-                    adb_root=True)
-
-    def test_app_profiler(self):
-        self.common_test_app_profiler()
-
-
-class TestExampleOfKotlinTraceOffCpu(TestExampleBase):
-    @classmethod
-    def setUpClass(cls):
-        cls.prepare("SimpleperfExampleOfKotlin",
-                    "com.example.simpleperf.simpleperfexampleofkotlin",
-                    ".SleepActivity")
-
-    def test_smoke(self):
-        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        function_prefix = "com.example.simpleperf.simpleperfexampleofkotlin." + \
-                          "SleepActivity$createRunSleepThread$1."
-        self.check_strings_in_file("report.txt", [
-            function_prefix + "run",
-            function_prefix + "RunFunction",
-            function_prefix + "SleepFunction"
-            ])
-        if self.use_compiled_java_code:
-            remove("annotated_files")
-            self.run_cmd(["annotate.py", "-s", self.example_path])
-            self.check_exist(dirname="annotated_files")
-            self.check_file_under_dir("annotated_files", "SleepActivity.kt")
-            summary_file = os.path.join("annotated_files", "summary")
-            self.check_annotation_summary(summary_file, [
-                ("SleepActivity.kt", 80, 20),
-                ("run", 80, 0),
-                ("RunFunction", 20, 20),
-                ("SleepFunction", 20, 0),
-                ("line 24", 20, 0),
-                ("line 32", 20, 0)])
-
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.check_inferno_report_html([
-            (function_prefix + 'run', 80),
-            (function_prefix + 'RunFunction', 20),
-            (function_prefix + 'SleepFunction', 20)])
-
-
-class TestNativeProfiling(TestBase):
-    def setUp(self):
-        super(TestNativeProfiling, self).setUp()
-        self.is_rooted_device = TEST_HELPER.adb.switch_to_root()
-
-    def test_profile_cmd(self):
-        self.run_cmd(["app_profiler.py", "-cmd", "pm -l", "--disable_adb_root"])
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-
-    def test_profile_native_program(self):
-        if not self.is_rooted_device:
-            return
-        self.run_cmd(["app_profiler.py", "-np", "surfaceflinger"])
-        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
-        self.run_cmd([INFERNO_SCRIPT, "-sc"])
-        self.run_cmd([INFERNO_SCRIPT, "-np", "surfaceflinger"])
-
-    def test_profile_pids(self):
-        if not self.is_rooted_device:
-            return
-        pid = int(TEST_HELPER.adb.check_run_and_return_output(['shell', 'pidof', 'system_server']))
-        self.run_cmd(['app_profiler.py', '--pid', str(pid), '-r', '--duration 1'])
-        self.run_cmd(['app_profiler.py', '--pid', str(pid), str(pid), '-r', '--duration 1'])
-        self.run_cmd(['app_profiler.py', '--tid', str(pid), '-r', '--duration 1'])
-        self.run_cmd(['app_profiler.py', '--tid', str(pid), str(pid), '-r', '--duration 1'])
-        self.run_cmd([INFERNO_SCRIPT, '--pid', str(pid), '-t', '1'])
-
-    def test_profile_system_wide(self):
-        if not self.is_rooted_device:
-            return
-        self.run_cmd(['app_profiler.py', '--system_wide', '-r', '--duration 1'])
-
-
-class TestReportLib(TestBase):
-    def setUp(self):
-        super(TestReportLib, self).setUp()
-        self.report_lib = ReportLib()
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_symbols.data'))
-
-    def tearDown(self):
-        self.report_lib.Close()
-        super(TestReportLib, self).tearDown()
-
-    def test_build_id(self):
-        build_id = self.report_lib.GetBuildIdForPath('/data/t2')
-        self.assertEqual(build_id, '0x70f1fe24500fc8b0d9eb477199ca1ca21acca4de')
-
-    def test_symbol(self):
-        found_func2 = False
-        while self.report_lib.GetNextSample():
-            symbol = self.report_lib.GetSymbolOfCurrentSample()
-            if symbol.symbol_name == 'func2(int, int)':
-                found_func2 = True
-                self.assertEqual(symbol.symbol_addr, 0x4004ed)
-                self.assertEqual(symbol.symbol_len, 0x14)
-        self.assertTrue(found_func2)
-
-    def test_sample(self):
-        found_sample = False
-        while self.report_lib.GetNextSample():
-            sample = self.report_lib.GetCurrentSample()
-            if sample.ip == 0x4004ff and sample.time == 7637889424953:
-                found_sample = True
-                self.assertEqual(sample.pid, 15926)
-                self.assertEqual(sample.tid, 15926)
-                self.assertEqual(sample.thread_comm, 't2')
-                self.assertEqual(sample.cpu, 5)
-                self.assertEqual(sample.period, 694614)
-                event = self.report_lib.GetEventOfCurrentSample()
-                self.assertEqual(event.name, 'cpu-cycles')
-                callchain = self.report_lib.GetCallChainOfCurrentSample()
-                self.assertEqual(callchain.nr, 0)
-        self.assertTrue(found_sample)
-
-    def test_meta_info(self):
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
-        meta_info = self.report_lib.MetaInfo()
-        self.assertTrue("simpleperf_version" in meta_info)
-        self.assertEqual(meta_info["system_wide_collection"], "false")
-        self.assertEqual(meta_info["trace_offcpu"], "true")
-        self.assertEqual(meta_info["event_type_info"], "cpu-cycles,0,0\nsched:sched_switch,2,47")
-        self.assertTrue("product_props" in meta_info)
-
-    def test_event_name_from_meta_info(self):
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_tracepoint_event.data'))
-        event_names = set()
-        while self.report_lib.GetNextSample():
-            event_names.add(self.report_lib.GetEventOfCurrentSample().name)
-        self.assertTrue('sched:sched_switch' in event_names)
-        self.assertTrue('cpu-cycles' in event_names)
-
-    def test_record_cmd(self):
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
-        self.assertEqual(self.report_lib.GetRecordCmd(),
-                         "/data/local/tmp/simpleperf record --trace-offcpu --duration 2 -g " +
-                         "./simpleperf_runtest_run_and_sleep64")
-
-    def test_offcpu(self):
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
-        total_period = 0
-        sleep_function_period = 0
-        sleep_function_name = "SleepFunction(unsigned long long)"
-        while self.report_lib.GetNextSample():
-            sample = self.report_lib.GetCurrentSample()
-            total_period += sample.period
-            if self.report_lib.GetSymbolOfCurrentSample().symbol_name == sleep_function_name:
-                sleep_function_period += sample.period
-                continue
-            callchain = self.report_lib.GetCallChainOfCurrentSample()
-            for i in range(callchain.nr):
-                if callchain.entries[i].symbol.symbol_name == sleep_function_name:
-                    sleep_function_period += sample.period
-                    break
-            self.assertEqual(self.report_lib.GetEventOfCurrentSample().name, 'cpu-cycles')
-        sleep_percentage = float(sleep_function_period) / total_period
-        self.assertGreater(sleep_percentage, 0.30)
-
-    def test_show_art_frames(self):
-        def has_art_frame(report_lib):
-            report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_interpreter_frames.data'))
-            result = False
-            while report_lib.GetNextSample():
-                callchain = report_lib.GetCallChainOfCurrentSample()
-                for i in range(callchain.nr):
-                    if callchain.entries[i].symbol.symbol_name == 'artMterpAsmInstructionStart':
-                        result = True
-                        break
-            report_lib.Close()
-            return result
-
-        report_lib = ReportLib()
-        self.assertFalse(has_art_frame(report_lib))
-        report_lib = ReportLib()
-        report_lib.ShowArtFrames(False)
-        self.assertFalse(has_art_frame(report_lib))
-        report_lib = ReportLib()
-        report_lib.ShowArtFrames(True)
-        self.assertTrue(has_art_frame(report_lib))
-
-    def test_merge_java_methods(self):
-        def parse_dso_names(report_lib):
-            dso_names = set()
-            report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_interpreter_frames.data'))
-            while report_lib.GetNextSample():
-                dso_names.add(report_lib.GetSymbolOfCurrentSample().dso_name)
-                callchain = report_lib.GetCallChainOfCurrentSample()
-                for i in range(callchain.nr):
-                    dso_names.add(callchain.entries[i].symbol.dso_name)
-            report_lib.Close()
-            has_jit_symfiles = any('TemporaryFile-' in name for name in dso_names)
-            has_jit_cache = '[JIT cache]' in dso_names
-            return has_jit_symfiles, has_jit_cache
-
-        report_lib = ReportLib()
-        self.assertEqual(parse_dso_names(report_lib), (False, True))
-
-        report_lib = ReportLib()
-        report_lib.MergeJavaMethods(True)
-        self.assertEqual(parse_dso_names(report_lib), (False, True))
-
-        report_lib = ReportLib()
-        report_lib.MergeJavaMethods(False)
-        self.assertEqual(parse_dso_names(report_lib), (True, False))
-
-    def test_jited_java_methods(self):
-        report_lib = ReportLib()
-        report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_jit_symbol.data'))
-        has_jit_cache = False
-        while report_lib.GetNextSample():
-            if report_lib.GetSymbolOfCurrentSample().dso_name == '[JIT app cache]':
-                has_jit_cache = True
-            callchain = report_lib.GetCallChainOfCurrentSample()
-            for i in range(callchain.nr):
-                if callchain.entries[i].symbol.dso_name == '[JIT app cache]':
-                    has_jit_cache = True
-        report_lib.Close()
-        self.assertTrue(has_jit_cache)
-
-    def test_tracing_data(self):
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_tracepoint_event.data'))
-        has_tracing_data = False
-        while self.report_lib.GetNextSample():
-            event = self.report_lib.GetEventOfCurrentSample()
-            tracing_data = self.report_lib.GetTracingDataOfCurrentSample()
-            if event.name == 'sched:sched_switch':
-                self.assertIsNotNone(tracing_data)
-                self.assertIn('prev_pid', tracing_data)
-                self.assertIn('next_comm', tracing_data)
-                if tracing_data['prev_pid'] == 9896 and tracing_data['next_comm'] == 'swapper/4':
-                    has_tracing_data = True
-            else:
-                self.assertIsNone(tracing_data)
-        self.assertTrue(has_tracing_data)
-
-    def test_dynamic_field_in_tracing_data(self):
-        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path(
-            'perf_with_tracepoint_event_dynamic_field.data'))
-        has_dynamic_field = False
-        while self.report_lib.GetNextSample():
-            event = self.report_lib.GetEventOfCurrentSample()
-            tracing_data = self.report_lib.GetTracingDataOfCurrentSample()
-            if event.name == 'kprobes:myopen':
-                self.assertIsNotNone(tracing_data)
-                self.assertIn('name', tracing_data)
-                if tracing_data['name'] == '/sys/kernel/debug/tracing/events/kprobes/myopen/format':
-                    has_dynamic_field = True
-            else:
-                self.assertIsNone(tracing_data)
-        self.assertTrue(has_dynamic_field)
-
-
-class TestRunSimpleperfOnDevice(TestBase):
-    def test_smoke(self):
-        self.run_cmd(['run_simpleperf_on_device.py', 'list', '--show-features'])
-
-
-class TestTools(TestBase):
-    def test_addr2nearestline(self):
-        self.run_addr2nearestline_test(True)
-        self.run_addr2nearestline_test(False)
-
-    def run_addr2nearestline_test(self, with_function_name):
-        binary_cache_path = TEST_HELPER.testdata_dir
-        test_map = {
-            '/simpleperf_runtest_two_functions_arm64': [
-                {
-                    'func_addr': 0x668,
-                    'addr': 0x668,
-                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:20',
-                    'function': 'main',
-                },
-                {
-                    'func_addr': 0x668,
-                    'addr': 0x6a4,
-                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:7
-                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
-                    'function': """Function1()
-                                   main""",
-                },
-            ],
-            '/simpleperf_runtest_two_functions_arm': [
-                {
-                    'func_addr': 0x784,
-                    'addr': 0x7b0,
-                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:14
-                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
-                    'function': """Function2()
-                                   main""",
-                },
-                {
-                    'func_addr': 0x784,
-                    'addr': 0x7d0,
-                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:15
-                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
-                    'function': """Function2()
-                                   main""",
-                }
-            ],
-            '/simpleperf_runtest_two_functions_x86_64': [
-                {
-                    'func_addr': 0x840,
-                    'addr': 0x840,
-                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:7',
-                    'function': 'Function1()',
-                },
-                {
-                    'func_addr': 0x920,
-                    'addr': 0x94a,
-                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:7
-                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
-                    'function': """Function1()
-                                   main""",
-                }
-            ],
-            '/simpleperf_runtest_two_functions_x86': [
-                {
-                    'func_addr': 0x6d0,
-                    'addr': 0x6da,
-                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:14',
-                    'function': 'Function2()',
-                },
-                {
-                    'func_addr': 0x710,
-                    'addr': 0x749,
-                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:8
-                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
-                    'function': """Function1()
-                                   main""",
-                }
-            ],
-        }
-        addr2line = Addr2Nearestline(TEST_HELPER.ndk_path, binary_cache_path, with_function_name)
-        for dso_path in test_map:
-            test_addrs = test_map[dso_path]
-            for test_addr in test_addrs:
-                addr2line.add_addr(dso_path, test_addr['func_addr'], test_addr['addr'])
-        addr2line.convert_addrs_to_lines()
-        for dso_path in test_map:
-            dso = addr2line.get_dso(dso_path)
-            self.assertIsNotNone(dso, dso_path)
-            test_addrs = test_map[dso_path]
-            for test_addr in test_addrs:
-                expected_files = []
-                expected_lines = []
-                expected_functions = []
-                for line in test_addr['source'].split('\n'):
-                    items = line.split(':')
-                    expected_files.append(items[0].strip())
-                    expected_lines.append(int(items[1]))
-                for line in test_addr['function'].split('\n'):
-                    expected_functions.append(line.strip())
-                self.assertEqual(len(expected_files), len(expected_functions))
-
-                if with_function_name:
-                    expected_source = list(zip(expected_files, expected_lines, expected_functions))
-                else:
-                    expected_source = list(zip(expected_files, expected_lines))
-
-                actual_source = addr2line.get_addr_source(dso, test_addr['addr'])
-                if is_windows():
-                    self.assertIsNotNone(actual_source, 'for %s:0x%x' %
-                                         (dso_path, test_addr['addr']))
-                    for i, source in enumerate(actual_source):
-                        new_source = list(source)
-                        new_source[0] = new_source[0].replace('\\', '/')
-                        actual_source[i] = tuple(new_source)
-
-                self.assertEqual(actual_source, expected_source,
-                                 'for %s:0x%x, expected source %s, actual source %s' %
-                                 (dso_path, test_addr['addr'], expected_source, actual_source))
-
-    def test_objdump(self):
-        binary_cache_path = TEST_HELPER.testdata_dir
-        test_map = {
-            '/simpleperf_runtest_two_functions_arm64': {
-                'start_addr': 0x668,
-                'len': 116,
-                'expected_items': [
-                    ('main():', 0),
-                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
-                    ('694:      	add	x20, x20, #1758', 0x694),
-                ],
-            },
-            '/simpleperf_runtest_two_functions_arm': {
-                'start_addr': 0x784,
-                'len': 80,
-                'expected_items': [
-                    ('main():', 0),
-                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
-                    ('7ae:	bne.n	7a6 <main+0x22>', 0x7ae),
-                ],
-            },
-            '/simpleperf_runtest_two_functions_x86_64': {
-                'start_addr': 0x920,
-                'len': 201,
-                'expected_items': [
-                    ('main():', 0),
-                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
-                    ('96e:      	movl	%edx, (%rbx,%rax,4)', 0x96e),
-                ],
-            },
-            '/simpleperf_runtest_two_functions_x86': {
-                'start_addr': 0x710,
-                'len': 98,
-                'expected_items': [
-                    ('main():', 0),
-                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
-                    ('748:      	cmpl	$100000000, %ebp', 0x748),
-                ],
-            },
-        }
-        objdump = Objdump(TEST_HELPER.ndk_path, binary_cache_path)
-        for dso_path in test_map:
-            dso = test_map[dso_path]
-            dso_info = objdump.get_dso_info(dso_path)
-            self.assertIsNotNone(dso_info, dso_path)
-            disassemble_code = objdump.disassemble_code(dso_info, dso['start_addr'], dso['len'])
-            self.assertTrue(disassemble_code, dso_path)
-            i = 0
-            for expected_line, expected_addr in dso['expected_items']:
-                found = False
-                while i < len(disassemble_code):
-                    line, addr = disassemble_code[i]
-                    if addr == expected_addr and expected_line in line:
-                        found = True
-                        i += 1
-                        break
-                    i += 1
-                if not found:
-                    s = '\n'.join('%s:0x%x' % item for item in disassemble_code)
-                    self.fail('for %s, %s:0x%x not found in disassemble code:\n%s' %
-                              (dso_path, expected_line, expected_addr, s))
-
-    def test_readelf(self):
-        test_map = {
-            'simpleperf_runtest_two_functions_arm64': {
-                'arch': 'arm64',
-                'build_id': '0xe8ecb3916d989dbdc068345c30f0c24300000000',
-                'sections': ['.interp', '.note.android.ident', '.note.gnu.build-id', '.dynsym',
-                             '.dynstr', '.gnu.hash', '.gnu.version', '.gnu.version_r', '.rela.dyn',
-                             '.rela.plt', '.plt', '.text', '.rodata', '.eh_frame', '.eh_frame_hdr',
-                             '.preinit_array', '.init_array', '.fini_array', '.dynamic', '.got',
-                             '.got.plt', '.data', '.bss', '.comment', '.debug_str', '.debug_loc',
-                             '.debug_abbrev', '.debug_info', '.debug_ranges', '.debug_macinfo',
-                             '.debug_pubnames', '.debug_pubtypes', '.debug_line',
-                             '.note.gnu.gold-version', '.symtab', '.strtab', '.shstrtab'],
-            },
-            'simpleperf_runtest_two_functions_arm': {
-                'arch': 'arm',
-                'build_id': '0x718f5b36c4148ee1bd3f51af89ed2be600000000',
-            },
-            'simpleperf_runtest_two_functions_x86_64': {
-                'arch': 'x86_64',
-            },
-            'simpleperf_runtest_two_functions_x86': {
-                'arch': 'x86',
-            }
-        }
-        readelf = ReadElf(TEST_HELPER.ndk_path)
-        for dso_path in test_map:
-            dso_info = test_map[dso_path]
-            path = os.path.join(TEST_HELPER.testdata_dir, dso_path)
-            self.assertEqual(dso_info['arch'], readelf.get_arch(path))
-            if 'build_id' in dso_info:
-                self.assertEqual(dso_info['build_id'], readelf.get_build_id(path), dso_path)
-            if 'sections' in dso_info:
-                self.assertEqual(dso_info['sections'], readelf.get_sections(path), dso_path)
-        self.assertEqual(readelf.get_arch('not_exist_file'), 'unknown')
-        self.assertEqual(readelf.get_build_id('not_exist_file'), '')
-        self.assertEqual(readelf.get_sections('not_exist_file'), [])
-
-    def test_source_file_searcher(self):
-        searcher = SourceFileSearcher(
-            [TEST_HELPER.testdata_path('SimpleperfExampleWithNative'),
-             TEST_HELPER.testdata_path('SimpleperfExampleOfKotlin')])
-        def format_path(path):
-            return os.path.join(TEST_HELPER.testdata_dir, path.replace('/', os.sep))
-        # Find a C++ file with pure file name.
-        self.assertEqual(
-            format_path('SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
-            searcher.get_real_path('native-lib.cpp'))
-        # Find a C++ file with an absolute file path.
-        self.assertEqual(
-            format_path('SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
-            searcher.get_real_path('/data/native-lib.cpp'))
-        # Find a Java file.
-        self.assertEqual(
-            format_path('SimpleperfExampleWithNative/app/src/main/java/com/example/' +
-                        'simpleperf/simpleperfexamplewithnative/MainActivity.java'),
-            searcher.get_real_path('simpleperfexamplewithnative/MainActivity.java'))
-        # Find a Kotlin file.
-        self.assertEqual(
-            format_path('SimpleperfExampleOfKotlin/app/src/main/java/com/example/' +
-                        'simpleperf/simpleperfexampleofkotlin/MainActivity.kt'),
-            searcher.get_real_path('MainActivity.kt'))
-
-    def test_is_elf_file(self):
-        self.assertTrue(is_elf_file(TEST_HELPER.testdata_path(
-            'simpleperf_runtest_two_functions_arm')))
-        with open('not_elf', 'wb') as fh:
-            fh.write(b'\x90123')
-        try:
-            self.assertFalse(is_elf_file('not_elf'))
-        finally:
-            remove('not_elf')
-
-
-class TestNativeLibDownloader(TestBase):
-    def setUp(self):
-        super(TestNativeLibDownloader, self).setUp()
-        self.adb = TEST_HELPER.adb
-        self.adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
-        self.ndk_path = TEST_HELPER.ndk_path
-
-    def tearDown(self):
-        self.adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
-        super(TestNativeLibDownloader, self).tearDown()
-
-    def list_lib_on_device(self, path):
-        result, output = self.adb.run_and_return_output(
-            ['shell', 'ls', '-llc', path], log_output=False)
-        return output if result else ''
-
-    def test_smoke(self):
-        # Sync all native libs on device.
-        downloader = NativeLibDownloader(self.ndk_path, 'arm64', self.adb)
-        downloader.collect_native_libs_on_host(TEST_HELPER.testdata_path(
-            'SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling'))
-        self.assertEqual(len(downloader.host_build_id_map), 2)
-        for entry in downloader.host_build_id_map.values():
-            self.assertEqual(entry.score, 3)
-        downloader.collect_native_libs_on_device()
-        self.assertEqual(len(downloader.device_build_id_map), 0)
-
-        lib_list = list(downloader.host_build_id_map.items())
-        for sync_count in [0, 1, 2]:
-            build_id_map = {}
-            for i in range(sync_count):
-                build_id_map[lib_list[i][0]] = lib_list[i][1]
-            downloader.host_build_id_map = build_id_map
-            downloader.sync_native_libs_on_device()
-            downloader.collect_native_libs_on_device()
-            self.assertEqual(len(downloader.device_build_id_map), sync_count)
-            for i, item in enumerate(lib_list):
-                build_id = item[0]
-                name = item[1].name
-                if i < sync_count:
-                    self.assertTrue(build_id in downloader.device_build_id_map)
-                    self.assertEqual(name, downloader.device_build_id_map[build_id])
-                    self.assertTrue(self.list_lib_on_device(downloader.dir_on_device + name))
-                else:
-                    self.assertTrue(build_id not in downloader.device_build_id_map)
-                    self.assertFalse(self.list_lib_on_device(downloader.dir_on_device + name))
-            if sync_count == 1:
-                self.adb.run(['pull', '/data/local/tmp/native_libs/build_id_list',
-                              'build_id_list'])
-                with open('build_id_list', 'rb') as fh:
-                    self.assertEqual(bytes_to_str(fh.read()),
-                                     '{}={}\n'.format(lib_list[0][0], lib_list[0][1].name))
-                remove('build_id_list')
-
-    def test_handle_wrong_build_id_list(self):
-        with open('build_id_list', 'wb') as fh:
-            fh.write(str_to_bytes('fake_build_id=binary_not_exist\n'))
-        self.adb.check_run(['shell', 'mkdir', '-p', '/data/local/tmp/native_libs'])
-        self.adb.check_run(['push', 'build_id_list', '/data/local/tmp/native_libs'])
-        remove('build_id_list')
-        downloader = NativeLibDownloader(self.ndk_path, 'arm64', self.adb)
-        downloader.collect_native_libs_on_device()
-        self.assertEqual(len(downloader.device_build_id_map), 0)
-
-    def test_download_file_without_build_id(self):
-        downloader = NativeLibDownloader(self.ndk_path, 'x86_64', self.adb)
-        name = 'elf.so'
-        shutil.copyfile(TEST_HELPER.testdata_path('data/symfs_without_build_id/elf'), name)
-        downloader.collect_native_libs_on_host('.')
-        downloader.collect_native_libs_on_device()
-        self.assertIn(name, downloader.no_build_id_file_map)
-        # Check if file wihtout build id can be downloaded.
-        downloader.sync_native_libs_on_device()
-        target_file = downloader.dir_on_device + name
-        target_file_stat = self.list_lib_on_device(target_file)
-        self.assertTrue(target_file_stat)
-
-        # No need to re-download if file size doesn't change.
-        downloader.sync_native_libs_on_device()
-        self.assertEqual(target_file_stat, self.list_lib_on_device(target_file))
-
-        # Need to re-download if file size changes.
-        self.adb.check_run(['shell', 'truncate', '-s', '0', target_file])
-        target_file_stat = self.list_lib_on_device(target_file)
-        downloader.sync_native_libs_on_device()
-        self.assertNotEqual(target_file_stat, self.list_lib_on_device(target_file))
-
-
-class TestReportHtml(TestBase):
-    def test_long_callchain(self):
-        self.run_cmd(['report_html.py', '-i',
-                      TEST_HELPER.testdata_path('perf_with_long_callchain.data')])
-
-    def test_aggregated_by_thread_name(self):
-        # Calculate event_count for each thread name before aggregation.
-        event_count_for_thread_name = collections.defaultdict(lambda: 0)
-        # use "--min_func_percent 0" to avoid cutting any thread.
-        self.run_cmd(['report_html.py', '--min_func_percent', '0', '-i',
-                      TEST_HELPER.testdata_path('aggregatable_perf1.data'),
-                      TEST_HELPER.testdata_path('aggregatable_perf2.data')])
-        record_data = self._load_record_data_in_html('report.html')
-        event = record_data['sampleInfo'][0]
-        for process in event['processes']:
-            for thread in process['threads']:
-                thread_name = record_data['threadNames'][str(thread['tid'])]
-                event_count_for_thread_name[thread_name] += thread['eventCount']
-
-        # Check event count for each thread after aggregation.
-        self.run_cmd(['report_html.py', '--aggregate-by-thread-name',
-                      '--min_func_percent', '0', '-i',
-                      TEST_HELPER.testdata_path('aggregatable_perf1.data'),
-                      TEST_HELPER.testdata_path('aggregatable_perf2.data')])
-        record_data = self._load_record_data_in_html('report.html')
-        event = record_data['sampleInfo'][0]
-        hit_count = 0
-        for process in event['processes']:
-            for thread in process['threads']:
-                thread_name = record_data['threadNames'][str(thread['tid'])]
-                self.assertEqual(thread['eventCount'],
-                                 event_count_for_thread_name[thread_name])
-                hit_count += 1
-        self.assertEqual(hit_count, len(event_count_for_thread_name))
-
-    def test_no_empty_process(self):
-        """ Test not showing a process having no threads. """
-        perf_data = TEST_HELPER.testdata_path('two_process_perf.data')
-        self.run_cmd(['report_html.py', '-i', perf_data])
-        record_data = self._load_record_data_in_html('report.html')
-        processes = record_data['sampleInfo'][0]['processes']
-        self.assertEqual(len(processes), 2)
-
-        # One process is removed because all its threads are removed for not
-        # reaching the min_func_percent limit.
-        self.run_cmd(['report_html.py', '-i', perf_data, '--min_func_percent', '20'])
-        record_data = self._load_record_data_in_html('report.html')
-        processes = record_data['sampleInfo'][0]['processes']
-        self.assertEqual(len(processes), 1)
-
-    def _load_record_data_in_html(self, html_file):
-        with open(html_file, 'r') as fh:
-            data = fh.read()
-        start_str = 'type="application/json"'
-        end_str = '</script>'
-        start_pos = data.find(start_str)
-        self.assertNotEqual(start_pos, -1)
-        start_pos = data.find('>', start_pos)
-        self.assertNotEqual(start_pos, -1)
-        start_pos += 1
-        end_pos = data.find(end_str, start_pos)
-        self.assertNotEqual(end_pos, -1)
-        json_data = data[start_pos:end_pos]
-        return json.loads(json_data)
-
-
-class TestBinaryCacheBuilder(TestBase):
-    def test_copy_binaries_from_symfs_dirs(self):
-        readelf = ReadElf(TEST_HELPER.ndk_path)
-        strip = find_tool_path('strip', arch='arm')
-        self.assertIsNotNone(strip)
-        symfs_dir = os.path.join(self.test_dir, 'symfs_dir')
-        remove(symfs_dir)
-        os.mkdir(symfs_dir)
-        filename = 'simpleperf_runtest_two_functions_arm'
-        origin_file = TEST_HELPER.testdata_path(filename)
-        source_file = os.path.join(symfs_dir, filename)
-        target_file = os.path.join('binary_cache', filename)
-        expected_build_id = readelf.get_build_id(origin_file)
-        binary_cache_builder = BinaryCacheBuilder(TEST_HELPER.ndk_path, False)
-        binary_cache_builder.binaries['simpleperf_runtest_two_functions_arm'] = expected_build_id
-
-        # Copy binary if target file doesn't exist.
-        remove(target_file)
-        self.run_cmd([strip, '--strip-all', '-o', source_file, origin_file])
-        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
-        self.assertTrue(filecmp.cmp(target_file, source_file))
-
-        # Copy binary if target file doesn't have .symtab and source file has .symtab.
-        self.run_cmd([strip, '--strip-debug', '-o', source_file, origin_file])
-        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
-        self.assertTrue(filecmp.cmp(target_file, source_file))
-
-        # Copy binary if target file doesn't have .debug_line and source_files has .debug_line.
-        shutil.copy(origin_file, source_file)
-        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
-        self.assertTrue(filecmp.cmp(target_file, source_file))
-
-    def test_copy_elf_without_build_id_from_symfs_dir(self):
-        binary_cache_builder = BinaryCacheBuilder(TEST_HELPER.ndk_path, False)
-        binary_cache_builder.binaries['elf'] = ''
-        symfs_dir = TEST_HELPER.testdata_path('data/symfs_without_build_id')
-        source_file = os.path.join(symfs_dir, 'elf')
-        target_file = os.path.join('binary_cache', 'elf')
-        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
-        self.assertTrue(filecmp.cmp(target_file, source_file))
-        binary_cache_builder.pull_binaries_from_device()
-        self.assertTrue(filecmp.cmp(target_file, source_file))
-
-
-class TestApiProfiler(TestBase):
-    def run_api_test(self, package_name, apk_name, expected_reports, min_android_version):
-        adb = TEST_HELPER.adb
-        if TEST_HELPER.android_version < ord(min_android_version) - ord('L') + 5:
-            log_info('skip this test on Android < %s.' % min_android_version)
-            return
-        # step 1: Prepare profiling.
-        self.run_cmd(['api_profiler.py', 'prepare'])
-        # step 2: Install and run the app.
-        apk_path = TEST_HELPER.testdata_path(apk_name)
-        adb.run(['uninstall', package_name])
-        adb.check_run(['install', '-t', apk_path])
-        # Without sleep, the activity may be killed by post install intent ACTION_PACKAGE_CHANGED.
-        time.sleep(3)
-        adb.check_run(['shell', 'am', 'start', '-n', package_name + '/.MainActivity'])
-        # step 3: Wait until the app exits.
-        time.sleep(4)
-        while True:
-            result = adb.run(['shell', 'pidof', package_name])
-            if not result:
-                break
-            time.sleep(1)
-        # step 4: Collect recording data.
-        remove('simpleperf_data')
-        self.run_cmd(['api_profiler.py', 'collect', '-p', package_name, '-o', 'simpleperf_data'])
-        # step 5: Check recording data.
-        names = os.listdir('simpleperf_data')
-        self.assertGreater(len(names), 0)
-        for name in names:
-            path = os.path.join('simpleperf_data', name)
-            remove('report.txt')
-            self.run_cmd(['report.py', '-g', '-o', 'report.txt', '-i', path])
-            self.check_strings_in_file('report.txt', expected_reports)
-        # step 6: Clean up.
-        adb.check_run(['uninstall', package_name])
-
-    def run_cpp_api_test(self, apk_name, min_android_version):
-        self.run_api_test('simpleperf.demo.cpp_api', apk_name, ['BusyThreadFunc'],
-                          min_android_version)
-
-    def test_cpp_api_on_a_debuggable_app_targeting_prev_q(self):
-        # The source code of the apk is in simpleperf/demo/CppApi (with a small change to exit
-        # after recording).
-        self.run_cpp_api_test('cpp_api-debug_prev_Q.apk', 'N')
-
-    def test_cpp_api_on_a_debuggable_app_targeting_q(self):
-        self.run_cpp_api_test('cpp_api-debug_Q.apk', 'N')
-
-    def test_cpp_api_on_a_profileable_app_targeting_prev_q(self):
-        # a release apk with <profileable android:shell="true" />
-        self.run_cpp_api_test('cpp_api-profile_prev_Q.apk', 'Q')
-
-    def test_cpp_api_on_a_profileable_app_targeting_q(self):
-        self.run_cpp_api_test('cpp_api-profile_Q.apk', 'Q')
-
-    def run_java_api_test(self, apk_name, min_android_version):
-        self.run_api_test('simpleperf.demo.java_api', apk_name,
-                          ['simpleperf.demo.java_api.MainActivity', 'java.lang.Thread.run'],
-                          min_android_version)
-
-    def test_java_api_on_a_debuggable_app_targeting_prev_q(self):
-        # The source code of the apk is in simpleperf/demo/JavaApi (with a small change to exit
-        # after recording).
-        self.run_java_api_test('java_api-debug_prev_Q.apk', 'P')
-
-    def test_java_api_on_a_debuggable_app_targeting_q(self):
-        self.run_java_api_test('java_api-debug_Q.apk', 'P')
-
-    def test_java_api_on_a_profileable_app_targeting_prev_q(self):
-        # a release apk with <profileable android:shell="true" />
-        self.run_java_api_test('java_api-profile_prev_Q.apk', 'Q')
-
-    def test_java_api_on_a_profileable_app_targeting_q(self):
-        self.run_java_api_test('java_api-profile_Q.apk', 'Q')
-
-
-class TestPprofProtoGenerator(TestBase):
-    def setUp(self):
-        super(TestPprofProtoGenerator, self).setUp()
-        if not HAS_GOOGLE_PROTOBUF:
-            raise unittest.SkipTest(
-                'Skip test for pprof_proto_generator because google.protobuf is missing')
-
-    def run_generator(self, options=None, testdata_file='perf_with_interpreter_frames.data'):
-        testdata_path = TEST_HELPER.testdata_path(testdata_file)
-        options = options or []
-        self.run_cmd(['pprof_proto_generator.py', '-i', testdata_path] + options)
-        return self.run_cmd(['pprof_proto_generator.py', '--show'], return_output=True)
-
-    def generate_profile(self, options, testdata_files):
-        testdata_paths = [TEST_HELPER.testdata_path(f) for f in testdata_files]
-        options = options or []
-        self.run_cmd(['pprof_proto_generator.py', '-i'] + testdata_paths + options)
-        return load_pprof_profile('pprof.profile')
-
-    def test_show_art_frames(self):
-        art_frame_str = 'art::interpreter::DoCall'
-        # By default, don't show art frames.
-        self.assertNotIn(art_frame_str, self.run_generator())
-        # Use --show_art_frames to show art frames.
-        self.assertIn(art_frame_str, self.run_generator(['--show_art_frames']))
-
-    def test_pid_filter(self):
-        key = 'PlayScene::DoFrame()'  # function in process 10419
-        self.assertIn(key, self.run_generator())
-        self.assertIn(key, self.run_generator(['--pid', '10419']))
-        self.assertIn(key, self.run_generator(['--pid', '10419', '10416']))
-        self.assertNotIn(key, self.run_generator(['--pid', '10416']))
-
-    def test_tid_filter(self):
-        key1 = 'art::ProfileSaver::Run()'  # function in thread 10459
-        key2 = 'PlayScene::DoFrame()'  # function in thread 10463
-        for options in ([], ['--tid', '10459', '10463']):
-            output = self.run_generator(options)
-            self.assertIn(key1, output)
-            self.assertIn(key2, output)
-        output = self.run_generator(['--tid', '10459'])
-        self.assertIn(key1, output)
-        self.assertNotIn(key2, output)
-        output = self.run_generator(['--tid', '10463'])
-        self.assertNotIn(key1, output)
-        self.assertIn(key2, output)
-
-    def test_comm_filter(self):
-        key1 = 'art::ProfileSaver::Run()'  # function in thread 'Profile Saver'
-        key2 = 'PlayScene::DoFrame()'  # function in thread 'e.sample.tunnel'
-        for options in ([], ['--comm', 'Profile Saver', 'e.sample.tunnel']):
-            output = self.run_generator(options)
-            self.assertIn(key1, output)
-            self.assertIn(key2, output)
-        output = self.run_generator(['--comm', 'Profile Saver'])
-        self.assertIn(key1, output)
-        self.assertNotIn(key2, output)
-        output = self.run_generator(['--comm', 'e.sample.tunnel'])
-        self.assertNotIn(key1, output)
-        self.assertIn(key2, output)
-
-    def test_build_id(self):
-        """ Test the build ids generated are not padded with zeros. """
-        self.assertIn('build_id: e3e938cc9e40de2cfe1a5ac7595897de(', self.run_generator())
-
-    def test_location_address(self):
-        """ Test if the address of a location is within the memory range of the corresponding
-            mapping.
-        """
-        profile = self.generate_profile(None, ['perf_with_interpreter_frames.data'])
-        # pylint: disable=no-member
-        for location in profile.location:
-            mapping = profile.mapping[location.mapping_id - 1]
-            self.assertLessEqual(mapping.memory_start, location.address)
-            self.assertGreaterEqual(mapping.memory_limit, location.address)
-
-    def test_multiple_perf_data(self):
-        """ Test reporting multiple recording file. """
-        profile1 = self.generate_profile(None, ['aggregatable_perf1.data'])
-        profile2 = self.generate_profile(None, ['aggregatable_perf2.data'])
-        profile_both = self.generate_profile(
-            None, ['aggregatable_perf1.data', 'aggregatable_perf2.data'])
-        # pylint: disable=no-member
-        self.assertGreater(len(profile_both.sample), len(profile1.sample))
-        self.assertGreater(len(profile_both.sample), len(profile2.sample))
-
-
-class TestRecordingRealApps(TestBase):
-    def setUp(self):
-        super(TestRecordingRealApps, self).setUp()
-        self.adb = TEST_HELPER.adb
-        self.installed_packages = []
-
-    def tearDown(self):
-        for package in self.installed_packages:
-            self.adb.run(['shell', 'pm', 'uninstall', package])
-        super(TestRecordingRealApps, self).tearDown()
-
-    def install_apk(self, apk_path, package_name):
-        self.adb.run(['uninstall', package_name])
-        self.adb.run(['install', '-t', apk_path])
-        self.installed_packages.append(package_name)
-
-    def start_app(self, start_cmd):
-        subprocess.Popen(self.adb.adb_path + ' ' + start_cmd, shell=True,
-                         stdout=TEST_LOGGER.log_fh, stderr=TEST_LOGGER.log_fh)
-
-    def record_data(self, package_name, record_arg):
-        self.run_cmd(['app_profiler.py', '--app', package_name, '-r', record_arg])
-
-    def check_symbol_in_record_file(self, symbol_name):
-        self.run_cmd(['report.py', '--children', '-o', 'report.txt'])
-        self.check_strings_in_file('report.txt', [symbol_name])
-
-    def test_recording_displaybitmaps(self):
-        self.install_apk(TEST_HELPER.testdata_path('DisplayBitmaps.apk'),
-                         'com.example.android.displayingbitmaps')
-        self.install_apk(TEST_HELPER.testdata_path('DisplayBitmapsTest.apk'),
-                         'com.example.android.displayingbitmaps.test')
-        self.start_app('shell am instrument -w -r -e debug false -e class ' +
-                       'com.example.android.displayingbitmaps.tests.GridViewTest ' +
-                       'com.example.android.displayingbitmaps.test/' +
-                       'androidx.test.runner.AndroidJUnitRunner')
-        self.record_data('com.example.android.displayingbitmaps', '-e cpu-clock -g --duration 10')
-        if TEST_HELPER.android_version >= 9:
-            self.check_symbol_in_record_file('androidx.test.espresso')
-
-    def test_recording_endless_tunnel(self):
-        self.install_apk(TEST_HELPER.testdata_path(
-            'EndlessTunnel.apk'), 'com.google.sample.tunnel')
-        self.start_app('shell am start -n com.google.sample.tunnel/android.app.NativeActivity -a ' +
-                       'android.intent.action.MAIN -c android.intent.category.LAUNCHER')
-        self.record_data('com.google.sample.tunnel', '-e cpu-clock -g --duration 10')
-        self.check_symbol_in_record_file('PlayScene::DoFrame')
-
-
-def get_all_tests():
-    tests = []
-    for name, value in globals().items():
-        if isinstance(value, type) and issubclass(value, unittest.TestCase):
-            for member_name, member in inspect.getmembers(value):
-                if isinstance(member, (types.MethodType, types.FunctionType)):
-                    if member_name.startswith('test'):
-                        tests.append(name + '.' + member_name)
-    return sorted(tests)
-
-
-def run_tests(tests):
-    TEST_HELPER.build_testdata()
-    argv = [sys.argv[0]] + tests
-    test_runner = unittest.TextTestRunner(stream=TEST_LOGGER, verbosity=0)
-    test_program = unittest.main(argv=argv, testRunner=test_runner, exit=False, verbosity=0)
-    result = test_program.result.wasSuccessful()
-    remove(TEST_HELPER.testdata_dir)
-    return result
-
-
-def main():
-    parser = argparse.ArgumentParser(description='Test simpleperf scripts')
-    parser.add_argument('--list-tests', action='store_true', help='List all tests.')
-    parser.add_argument('--test-from', nargs=1, help='Run left tests from the selected test.')
-    parser.add_argument('--browser', action='store_true', help='pop report html file in browser.')
-    parser.add_argument('--progress-file', help='write test progress file')
-    parser.add_argument('--ndk-path', type=extant_dir, help='Set the path of a ndk release')
-    parser.add_argument('pattern', nargs='*', help='Run tests matching the selected pattern.')
-    args = parser.parse_args()
-    tests = get_all_tests()
-    if args.list_tests:
-        print('\n'.join(tests))
-        return True
-    if args.test_from:
-        start_pos = 0
-        while start_pos < len(tests) and tests[start_pos] != args.test_from[0]:
-            start_pos += 1
-        if start_pos == len(tests):
-            log_exit("Can't find test %s" % args.test_from[0])
-        tests = tests[start_pos:]
-    if args.pattern:
-        patterns = [re.compile(fnmatch.translate(x)) for x in args.pattern]
-        tests = [t for t in tests if any(pattern.match(t) for pattern in patterns)]
-        if not tests:
-            log_exit('No tests are matched.')
-
-    if TEST_HELPER.android_version < 7:
-        print("Skip tests on Android version < N.", file=TEST_LOGGER)
-        return False
-
-    TEST_HELPER.ndk_path = args.ndk_path
-
-    remove(TEST_HELPER.test_base_dir)
-
-    if not args.browser:
-        TEST_HELPER.browser_option = ['--no_browser']
-
-    if args.progress_file:
-        TEST_HELPER.progress_fh = open(args.progress_file, 'w')
-
-    result = run_tests(tests)
-    if not result:
-        print('Tests failed, see %s for details.' % TEST_LOGGER.log_file, file=TEST_LOGGER)
-    TEST_HELPER.write_progress('Test end')
-    return result
-
-
-if __name__ == '__main__':
-    sys.exit(0 if main() else 1)
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..9e41437
--- /dev/null
+++ b/test/__init__.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from . do_test import main
diff --git a/test/api_profiler_test.py b/test/api_profiler_test.py
new file mode 100644
index 0000000..d06cc66
--- /dev/null
+++ b/test/api_profiler_test.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import time
+from simpleperf_utils import remove
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestApiProfiler(TestBase):
+    def run_api_test(self, package_name, apk_name, expected_reports, min_android_version):
+        adb = TEST_HELPER.adb
+        if TEST_HELPER.android_version < ord(min_android_version) - ord('L') + 5:
+            log_info('skip this test on Android < %s.' % min_android_version)
+            return
+        # step 1: Prepare profiling.
+        self.run_cmd(['api_profiler.py', 'prepare'])
+        # step 2: Install and run the app.
+        apk_path = TEST_HELPER.testdata_path(apk_name)
+        adb.run(['uninstall', package_name])
+        adb.check_run(['install', '-t', apk_path])
+        # Without sleep, the activity may be killed by post install intent ACTION_PACKAGE_CHANGED.
+        time.sleep(3)
+        adb.check_run(['shell', 'am', 'start', '-n', package_name + '/.MainActivity'])
+        # step 3: Wait until the app exits.
+        time.sleep(4)
+        while True:
+            result = adb.run(['shell', 'pidof', package_name])
+            if not result:
+                break
+            time.sleep(1)
+        # step 4: Collect recording data.
+        remove('simpleperf_data')
+        self.run_cmd(['api_profiler.py', 'collect', '-p', package_name, '-o', 'simpleperf_data'])
+        # step 5: Check recording data.
+        names = os.listdir('simpleperf_data')
+        self.assertGreater(len(names), 0)
+        for name in names:
+            path = os.path.join('simpleperf_data', name)
+            remove('report.txt')
+            self.run_cmd(['report.py', '-g', '-o', 'report.txt', '-i', path])
+            self.check_strings_in_file('report.txt', expected_reports)
+        # step 6: Clean up.
+        adb.check_run(['uninstall', package_name])
+
+    def run_cpp_api_test(self, apk_name, min_android_version):
+        self.run_api_test('simpleperf.demo.cpp_api', apk_name, ['BusyThreadFunc'],
+                          min_android_version)
+
+    def test_cpp_api_on_a_debuggable_app_targeting_prev_q(self):
+        # The source code of the apk is in simpleperf/demo/CppApi (with a small change to exit
+        # after recording).
+        self.run_cpp_api_test('cpp_api-debug_prev_Q.apk', 'N')
+
+    def test_cpp_api_on_a_debuggable_app_targeting_q(self):
+        self.run_cpp_api_test('cpp_api-debug_Q.apk', 'N')
+
+    def test_cpp_api_on_a_profileable_app_targeting_prev_q(self):
+        # a release apk with <profileable android:shell="true" />
+        self.run_cpp_api_test('cpp_api-profile_prev_Q.apk', 'Q')
+
+    def test_cpp_api_on_a_profileable_app_targeting_q(self):
+        self.run_cpp_api_test('cpp_api-profile_Q.apk', 'Q')
+
+    def run_java_api_test(self, apk_name, min_android_version):
+        self.run_api_test('simpleperf.demo.java_api', apk_name,
+                          ['simpleperf.demo.java_api.MainActivity', 'java.lang.Thread.run'],
+                          min_android_version)
+
+    def test_java_api_on_a_debuggable_app_targeting_prev_q(self):
+        # The source code of the apk is in simpleperf/demo/JavaApi (with a small change to exit
+        # after recording).
+        self.run_java_api_test('java_api-debug_prev_Q.apk', 'P')
+
+    def test_java_api_on_a_debuggable_app_targeting_q(self):
+        self.run_java_api_test('java_api-debug_Q.apk', 'P')
+
+    def test_java_api_on_a_profileable_app_targeting_prev_q(self):
+        # a release apk with <profileable android:shell="true" />
+        self.run_java_api_test('java_api-profile_prev_Q.apk', 'Q')
+
+    def test_java_api_on_a_profileable_app_targeting_q(self):
+        self.run_java_api_test('java_api-profile_Q.apk', 'Q')
diff --git a/test/app_profiler_test.py b/test/app_profiler_test.py
new file mode 100644
index 0000000..7b897ff
--- /dev/null
+++ b/test/app_profiler_test.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from app_profiler import NativeLibDownloader
+import shutil
+from simpleperf_utils import str_to_bytes, bytes_to_str, remove
+from . test_utils import TestBase, TEST_HELPER, INFERNO_SCRIPT
+
+
+class TestNativeProfiling(TestBase):
+    def setUp(self):
+        super(TestNativeProfiling, self).setUp()
+        self.is_rooted_device = TEST_HELPER.adb.switch_to_root()
+
+    def test_profile_cmd(self):
+        self.run_cmd(["app_profiler.py", "-cmd", "pm -l", "--disable_adb_root"])
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+
+    def test_profile_native_program(self):
+        if not self.is_rooted_device:
+            return
+        self.run_cmd(["app_profiler.py", "-np", "surfaceflinger"])
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.run_cmd([INFERNO_SCRIPT, "-np", "surfaceflinger"])
+
+    def test_profile_pids(self):
+        if not self.is_rooted_device:
+            return
+        pid = int(TEST_HELPER.adb.check_run_and_return_output(['shell', 'pidof', 'system_server']))
+        self.run_cmd(['app_profiler.py', '--pid', str(pid), '-r', '--duration 1'])
+        self.run_cmd(['app_profiler.py', '--pid', str(pid), str(pid), '-r', '--duration 1'])
+        self.run_cmd(['app_profiler.py', '--tid', str(pid), '-r', '--duration 1'])
+        self.run_cmd(['app_profiler.py', '--tid', str(pid), str(pid), '-r', '--duration 1'])
+        self.run_cmd([INFERNO_SCRIPT, '--pid', str(pid), '-t', '1'])
+
+    def test_profile_system_wide(self):
+        if not self.is_rooted_device:
+            return
+        self.run_cmd(['app_profiler.py', '--system_wide', '-r', '--duration 1'])
+
+
+class TestNativeLibDownloader(TestBase):
+    def setUp(self):
+        super(TestNativeLibDownloader, self).setUp()
+        self.adb = TEST_HELPER.adb
+        self.adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
+        self.ndk_path = TEST_HELPER.ndk_path
+
+    def tearDown(self):
+        self.adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
+        super(TestNativeLibDownloader, self).tearDown()
+
+    def list_lib_on_device(self, path):
+        result, output = self.adb.run_and_return_output(
+            ['shell', 'ls', '-llc', path], log_output=False)
+        return output if result else ''
+
+    def test_smoke(self):
+        # Sync all native libs on device.
+        downloader = NativeLibDownloader(self.ndk_path, 'arm64', self.adb)
+        downloader.collect_native_libs_on_host(TEST_HELPER.testdata_path(
+            'SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling'))
+        self.assertEqual(len(downloader.host_build_id_map), 2)
+        for entry in downloader.host_build_id_map.values():
+            self.assertEqual(entry.score, 3)
+        downloader.collect_native_libs_on_device()
+        self.assertEqual(len(downloader.device_build_id_map), 0)
+
+        lib_list = list(downloader.host_build_id_map.items())
+        for sync_count in [0, 1, 2]:
+            build_id_map = {}
+            for i in range(sync_count):
+                build_id_map[lib_list[i][0]] = lib_list[i][1]
+            downloader.host_build_id_map = build_id_map
+            downloader.sync_native_libs_on_device()
+            downloader.collect_native_libs_on_device()
+            self.assertEqual(len(downloader.device_build_id_map), sync_count)
+            for i, item in enumerate(lib_list):
+                build_id = item[0]
+                name = item[1].name
+                if i < sync_count:
+                    self.assertTrue(build_id in downloader.device_build_id_map)
+                    self.assertEqual(name, downloader.device_build_id_map[build_id])
+                    self.assertTrue(self.list_lib_on_device(downloader.dir_on_device + name))
+                else:
+                    self.assertTrue(build_id not in downloader.device_build_id_map)
+                    self.assertFalse(self.list_lib_on_device(downloader.dir_on_device + name))
+            if sync_count == 1:
+                self.adb.run(['pull', '/data/local/tmp/native_libs/build_id_list',
+                              'build_id_list'])
+                with open('build_id_list', 'rb') as fh:
+                    self.assertEqual(bytes_to_str(fh.read()),
+                                     '{}={}\n'.format(lib_list[0][0], lib_list[0][1].name))
+                remove('build_id_list')
+
+    def test_handle_wrong_build_id_list(self):
+        with open('build_id_list', 'wb') as fh:
+            fh.write(str_to_bytes('fake_build_id=binary_not_exist\n'))
+        self.adb.check_run(['shell', 'mkdir', '-p', '/data/local/tmp/native_libs'])
+        self.adb.check_run(['push', 'build_id_list', '/data/local/tmp/native_libs'])
+        remove('build_id_list')
+        downloader = NativeLibDownloader(self.ndk_path, 'arm64', self.adb)
+        downloader.collect_native_libs_on_device()
+        self.assertEqual(len(downloader.device_build_id_map), 0)
+
+    def test_download_file_without_build_id(self):
+        downloader = NativeLibDownloader(self.ndk_path, 'x86_64', self.adb)
+        name = 'elf.so'
+        shutil.copyfile(TEST_HELPER.testdata_path('data/symfs_without_build_id/elf'), name)
+        downloader.collect_native_libs_on_host('.')
+        downloader.collect_native_libs_on_device()
+        self.assertIn(name, downloader.no_build_id_file_map)
+        # Check if file without build id can be downloaded.
+        downloader.sync_native_libs_on_device()
+        target_file = downloader.dir_on_device + name
+        target_file_stat = self.list_lib_on_device(target_file)
+        self.assertTrue(target_file_stat)
+
+        # No need to re-download if file size doesn't change.
+        downloader.sync_native_libs_on_device()
+        self.assertEqual(target_file_stat, self.list_lib_on_device(target_file))
+
+        # Need to re-download if file size changes.
+        self.adb.check_run(['shell', 'truncate', '-s', '0', target_file])
+        target_file_stat = self.list_lib_on_device(target_file)
+        downloader.sync_native_libs_on_device()
+        self.assertNotEqual(target_file_stat, self.list_lib_on_device(target_file))
diff --git a/test/app_test.py b/test/app_test.py
new file mode 100644
index 0000000..5a9e5d1
--- /dev/null
+++ b/test/app_test.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+import shutil
+import subprocess
+from simpleperf_utils import remove
+from . test_utils import TestBase, TEST_HELPER, AdbHelper, TEST_LOGGER, INFERNO_SCRIPT
+
+
+class TestExampleBase(TestBase):
+    @classmethod
+    def prepare(cls, example_name, package_name, activity_name, abi=None, adb_root=False):
+        cls.adb = AdbHelper(enable_switch_to_root=adb_root)
+        cls.example_path = TEST_HELPER.testdata_path(example_name)
+        if not os.path.isdir(cls.example_path):
+            log_fatal("can't find " + cls.example_path)
+        for root, _, files in os.walk(cls.example_path):
+            if 'app-profiling.apk' in files:
+                cls.apk_path = os.path.join(root, 'app-profiling.apk')
+                break
+        if not hasattr(cls, 'apk_path'):
+            log_fatal("can't find app-profiling.apk under " + cls.example_path)
+        cls.package_name = package_name
+        cls.activity_name = activity_name
+        args = ["install", "-r"]
+        if abi:
+            args += ["--abi", abi]
+        args.append(cls.apk_path)
+        cls.adb.check_run(args)
+        cls.adb_root = adb_root
+        cls.has_perf_data_for_report = False
+        # On Android >= P (version 9), we can profile JITed and interpreted Java code.
+        # So only compile Java code on Android <= O (version 8).
+        cls.use_compiled_java_code = TEST_HELPER.android_version <= 8
+        cls.testcase_dir = TEST_HELPER.test_dir(cls.__name__)
+
+    @classmethod
+    def tearDownClass(cls):
+        remove(cls.testcase_dir)
+        if hasattr(cls, 'package_name'):
+            cls.adb.check_run(["uninstall", cls.package_name])
+
+    def setUp(self):
+        super(TestExampleBase, self).setUp()
+        if 'TraceOffCpu' in self.id() and not TEST_HELPER.is_trace_offcpu_supported():
+            self.skipTest('trace-offcpu is not supported on device')
+        # Use testcase_dir to share a common perf.data for reporting. So we don't need to
+        # generate it for each test.
+        if not os.path.isdir(self.testcase_dir):
+            os.makedirs(self.testcase_dir)
+            os.chdir(self.testcase_dir)
+            self.run_app_profiler(compile_java_code=self.use_compiled_java_code)
+            os.chdir(self.test_dir)
+
+        for name in os.listdir(self.testcase_dir):
+            path = os.path.join(self.testcase_dir, name)
+            if os.path.isfile(path):
+                shutil.copy(path, self.test_dir)
+            elif os.path.isdir(path):
+                shutil.copytree(path, os.path.join(self.test_dir, name))
+
+    def run(self, result=None):
+        self.__class__.test_result = result
+        super(TestExampleBase, self).run(result)
+
+    def run_app_profiler(self, record_arg="-g --duration 10", build_binary_cache=True,
+                         start_activity=True, compile_java_code=False):
+        args = ['app_profiler.py', '--app', self.package_name, '-r', record_arg, '-o', 'perf.data']
+        if not build_binary_cache:
+            args.append("-nb")
+        if compile_java_code:
+            args.append('--compile_java_code')
+        if start_activity:
+            args += ["-a", self.activity_name]
+        args += ["-lib", self.example_path]
+        if not self.adb_root:
+            args.append("--disable_adb_root")
+        self.run_cmd(args)
+        self.check_exist(filename="perf.data")
+        if build_binary_cache:
+            self.check_exist(dirname="binary_cache")
+
+    def check_file_under_dir(self, dirname, filename):
+        self.check_exist(dirname=dirname)
+        for _, _, files in os.walk(dirname):
+            for f in files:
+                if f == filename:
+                    return
+        self.fail("Failed to call check_file_under_dir(dir=%s, file=%s)" % (dirname, filename))
+
+    def check_annotation_summary(self, summary_file, check_entries):
+        """ check_entries is a list of (name, accumulated_period, period).
+            This function checks for each entry, if the line containing [name]
+            has at least required accumulated_period and period.
+        """
+        self.check_exist(filename=summary_file)
+        with open(summary_file, 'r') as fh:
+            summary = fh.read()
+        fulfilled = [False for x in check_entries]
+        summary_check_re = re.compile(r'accumulated_period:\s*([\d.]+)%.*period:\s*([\d.]+)%')
+        for line in summary.split('\n'):
+            for i, (name, need_acc_period, need_period) in enumerate(check_entries):
+                if not fulfilled[i] and name in line:
+                    m = summary_check_re.search(line)
+                    if m:
+                        acc_period = float(m.group(1))
+                        period = float(m.group(2))
+                        if acc_period >= need_acc_period and period >= need_period:
+                            fulfilled[i] = True
+
+        self.check_fulfilled_entries(fulfilled, check_entries)
+
+    def check_inferno_report_html(self, check_entries, filename="report.html"):
+        self.check_exist(filename=filename)
+        with open(filename, 'r') as fh:
+            data = fh.read()
+        fulfilled = [False for _ in check_entries]
+        for line in data.split('\n'):
+            # each entry is a (function_name, min_percentage) pair.
+            for i, entry in enumerate(check_entries):
+                if fulfilled[i] or line.find(entry[0]) == -1:
+                    continue
+                m = re.search(r'(\d+\.\d+)%', line)
+                if m and float(m.group(1)) >= entry[1]:
+                    fulfilled[i] = True
+                    break
+        self.check_fulfilled_entries(fulfilled, check_entries)
+
+    def common_test_app_profiler(self):
+        self.run_cmd(["app_profiler.py", "-h"])
+        remove("binary_cache")
+        self.run_app_profiler(build_binary_cache=False)
+        self.assertFalse(os.path.isdir("binary_cache"))
+        args = ["binary_cache_builder.py"]
+        if not self.adb_root:
+            args.append("--disable_adb_root")
+        self.run_cmd(args)
+        self.check_exist(dirname="binary_cache")
+        remove("binary_cache")
+        self.run_app_profiler(build_binary_cache=True)
+        self.run_app_profiler()
+        self.run_app_profiler(start_activity=False)
+
+    def common_test_report(self):
+        self.run_cmd(["report.py", "-h"])
+        self.run_cmd(["report.py"])
+        self.run_cmd(["report.py", "-i", "perf.data"])
+        self.run_cmd(["report.py", "-g"])
+        self.run_cmd(["report.py", "--self-kill-for-testing", "-g", "--gui"])
+
+    def common_test_annotate(self):
+        self.run_cmd(["annotate.py", "-h"])
+        remove("annotated_files")
+        self.run_cmd(["annotate.py", "-s", self.example_path])
+        self.check_exist(dirname="annotated_files")
+
+    def common_test_report_sample(self, check_strings):
+        self.run_cmd(["report_sample.py", "-h"])
+        self.run_cmd(["report_sample.py"])
+        output = self.run_cmd(["report_sample.py", "perf.data"], return_output=True)
+        self.check_strings_in_content(output, check_strings)
+
+    def common_test_pprof_proto_generator(self, check_strings_with_lines,
+                                          check_strings_without_lines):
+        self.run_cmd(["pprof_proto_generator.py", "-h"])
+        self.run_cmd(["pprof_proto_generator.py"])
+        remove("pprof.profile")
+        self.run_cmd(["pprof_proto_generator.py", "-i", "perf.data", "-o", "pprof.profile"])
+        self.check_exist(filename="pprof.profile")
+        self.run_cmd(["pprof_proto_generator.py", "--show"])
+        output = self.run_cmd(["pprof_proto_generator.py", "--show", "pprof.profile"],
+                              return_output=True)
+        self.check_strings_in_content(output, check_strings_with_lines + ["has_line_numbers: True"])
+        remove("binary_cache")
+        self.run_cmd(["pprof_proto_generator.py"])
+        output = self.run_cmd(["pprof_proto_generator.py", "--show", "pprof.profile"],
+                              return_output=True)
+        self.check_strings_in_content(output, check_strings_without_lines +
+                                      ["has_line_numbers: False"])
+
+    def common_test_inferno(self):
+        self.run_cmd([INFERNO_SCRIPT, "-h"])
+        remove("perf.data")
+        append_args = [] if self.adb_root else ["--disable_adb_root"]
+        self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-t", "3"] + append_args)
+        self.check_exist(filename="perf.data")
+        self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-f", "1000", "-du", "-t", "1"] +
+                     append_args)
+        self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-e", "100000 cpu-cycles",
+                      "-t", "1"] + append_args)
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+
+    def common_test_report_html(self):
+        self.run_cmd(['report_html.py', '-h'])
+        self.run_cmd(['report_html.py'])
+        self.run_cmd(['report_html.py', '--add_source_code', '--source_dirs', 'testdata'])
+        self.run_cmd(['report_html.py', '--add_disassembly'])
+        # Test with multiple perf.data.
+        shutil.move('perf.data', 'perf2.data')
+        self.run_app_profiler(record_arg='-g -f 1000 --duration 3 -e task-clock:u')
+        self.run_cmd(['report_html.py', '-i', 'perf.data', 'perf2.data'])
+
+
+class TestRecordingRealApps(TestBase):
+    def setUp(self):
+        super(TestRecordingRealApps, self).setUp()
+        self.adb = TEST_HELPER.adb
+        self.installed_packages = []
+
+    def tearDown(self):
+        for package in self.installed_packages:
+            self.adb.run(['shell', 'pm', 'uninstall', package])
+        super(TestRecordingRealApps, self).tearDown()
+
+    def install_apk(self, apk_path, package_name):
+        self.adb.run(['uninstall', package_name])
+        self.adb.run(['install', '-t', apk_path])
+        self.installed_packages.append(package_name)
+
+    def start_app(self, start_cmd):
+        print('start app %s' % start_cmd)
+        subprocess.Popen(self.adb.adb_path + ' ' + start_cmd, shell=True,
+                         stdout=TEST_LOGGER.log_fh, stderr=TEST_LOGGER.log_fh)
+
+    def record_data(self, package_name, record_arg):
+        self.run_cmd(['app_profiler.py', '--app', package_name, '-r', record_arg])
+
+    def check_symbol_in_record_file(self, symbol_name):
+        self.run_cmd(['report.py', '--children', '-o', 'report.txt'])
+        self.check_strings_in_file('report.txt', [symbol_name])
+
+    def test_recording_displaybitmaps(self):
+        self.install_apk(TEST_HELPER.testdata_path('DisplayBitmaps.apk'),
+                         'com.example.android.displayingbitmaps')
+        self.install_apk(TEST_HELPER.testdata_path('DisplayBitmapsTest.apk'),
+                         'com.example.android.displayingbitmaps.test')
+        self.start_app('shell am instrument -w -r -e debug false -e class ' +
+                       'com.example.android.displayingbitmaps.tests.GridViewTest ' +
+                       'com.example.android.displayingbitmaps.test/' +
+                       'androidx.test.runner.AndroidJUnitRunner')
+        self.record_data('com.example.android.displayingbitmaps', '-e cpu-clock -g --duration 10')
+        if TEST_HELPER.android_version >= 9:
+            self.check_symbol_in_record_file('androidx.test.espresso')
+
+    def test_recording_endless_tunnel(self):
+        self.install_apk(TEST_HELPER.testdata_path(
+            'EndlessTunnel.apk'), 'com.google.sample.tunnel')
+        self.start_app('shell am start -n com.google.sample.tunnel/android.app.NativeActivity -a ' +
+                       'android.intent.action.MAIN -c android.intent.category.LAUNCHER')
+        self.record_data('com.google.sample.tunnel', '-e cpu-clock -g --duration 10')
+        self.check_symbol_in_record_file('PlayScene::DoFrame')
diff --git a/test/binary_cache_builder_test.py b/test/binary_cache_builder_test.py
new file mode 100644
index 0000000..d79a36a
--- /dev/null
+++ b/test/binary_cache_builder_test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import filecmp
+import os
+import shutil
+from binary_cache_builder import BinaryCacheBuilder
+from simpleperf_utils import ReadElf, remove, find_tool_path
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestBinaryCacheBuilder(TestBase):
+    def test_copy_binaries_from_symfs_dirs(self):
+        readelf = ReadElf(TEST_HELPER.ndk_path)
+        strip = find_tool_path('strip', arch='arm')
+        self.assertIsNotNone(strip)
+        symfs_dir = os.path.join(self.test_dir, 'symfs_dir')
+        remove(symfs_dir)
+        os.mkdir(symfs_dir)
+        filename = 'simpleperf_runtest_two_functions_arm'
+        origin_file = TEST_HELPER.testdata_path(filename)
+        source_file = os.path.join(symfs_dir, filename)
+        target_file = os.path.join('binary_cache', filename)
+        expected_build_id = readelf.get_build_id(origin_file)
+        binary_cache_builder = BinaryCacheBuilder(TEST_HELPER.ndk_path, False)
+        binary_cache_builder.binaries['simpleperf_runtest_two_functions_arm'] = expected_build_id
+
+        # Copy binary if target file doesn't exist.
+        remove(target_file)
+        self.run_cmd([strip, '--strip-all', '-o', source_file, origin_file])
+        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
+        self.assertTrue(filecmp.cmp(target_file, source_file))
+
+        # Copy binary if target file doesn't have .symtab and source file has .symtab.
+        self.run_cmd([strip, '--strip-debug', '-o', source_file, origin_file])
+        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
+        self.assertTrue(filecmp.cmp(target_file, source_file))
+
+        # Copy binary if target file doesn't have .debug_line and source_files has .debug_line.
+        shutil.copy(origin_file, source_file)
+        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
+        self.assertTrue(filecmp.cmp(target_file, source_file))
+
+    def test_copy_elf_without_build_id_from_symfs_dir(self):
+        binary_cache_builder = BinaryCacheBuilder(TEST_HELPER.ndk_path, False)
+        binary_cache_builder.binaries['elf'] = ''
+        symfs_dir = TEST_HELPER.testdata_path('data/symfs_without_build_id')
+        source_file = os.path.join(symfs_dir, 'elf')
+        target_file = os.path.join('binary_cache', 'elf')
+        binary_cache_builder.copy_binaries_from_symfs_dirs([symfs_dir])
+        self.assertTrue(filecmp.cmp(target_file, source_file))
+        binary_cache_builder.pull_binaries_from_device()
+        self.assertTrue(filecmp.cmp(target_file, source_file))
diff --git a/test/cpp_app_test.py b/test/cpp_app_test.py
new file mode 100644
index 0000000..42cb936
--- /dev/null
+++ b/test/cpp_app_test.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from simpleperf_utils import remove
+from . app_test import TestExampleBase
+from . test_utils import INFERNO_SCRIPT, TEST_HELPER
+
+
+class TestExampleWithNative(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".MainActivity")
+
+    def test_app_profiler(self):
+        self.common_test_app_profiler()
+
+    def test_app_profiler_profile_from_launch(self):
+        self.run_app_profiler(start_activity=True, build_binary_cache=False)
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
+
+    def test_report(self):
+        self.common_test_report()
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
+
+    def test_annotate(self):
+        self.common_test_annotate()
+        self.check_file_under_dir("annotated_files", "native-lib.cpp")
+        summary_file = os.path.join("annotated_files", "summary")
+        self.check_annotation_summary(summary_file, [
+            ("native-lib.cpp", 20, 0),
+            ("BusyLoopThread", 20, 0),
+            ("line 46", 20, 0)])
+
+    def test_report_sample(self):
+        self.common_test_report_sample(
+            ["BusyLoopThread",
+             "__start_thread"])
+
+    def test_pprof_proto_generator(self):
+        check_strings_with_lines = [
+            "native-lib.cpp",
+            "BusyLoopThread",
+            # Check if dso name in perf.data is replaced by binary path in binary_cache.
+            'filename: binary_cache']
+        self.common_test_pprof_proto_generator(
+            check_strings_with_lines,
+            check_strings_without_lines=["BusyLoopThread"])
+
+    def test_inferno(self):
+        self.common_test_inferno()
+        self.run_app_profiler()
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.check_inferno_report_html([('BusyLoopThread', 20)])
+
+    def test_report_html(self):
+        self.common_test_report_html()
+        self.run_cmd(['report_html.py', '--add_source_code', '--source_dirs', 'testdata',
+                      '--add_disassembly', '--binary_filter', "libnative-lib.so"])
+
+
+class TestExampleWithNativeRoot(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".MainActivity",
+                    adb_root=True)
+
+    def test_app_profiler(self):
+        self.common_test_app_profiler()
+
+
+class TestExampleWithNativeTraceOffCpu(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".SleepActivity")
+
+    def test_smoke(self):
+        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
+        self.run_cmd(["report.py", "-g", "--comms", "SleepThread", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "SleepThread(void*)",
+            "RunFunction()",
+            "SleepFunction(unsigned long long)"])
+        remove("annotated_files")
+        self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "SleepThread"])
+        self.check_exist(dirname="annotated_files")
+        self.check_file_under_dir("annotated_files", "native-lib.cpp")
+        summary_file = os.path.join("annotated_files", "summary")
+        self.check_annotation_summary(summary_file, [
+            ("native-lib.cpp", 80, 20),
+            ("SleepThread", 80, 0),
+            ("RunFunction", 20, 20),
+            ("SleepFunction", 20, 0),
+            ("line 73", 20, 0),
+            ("line 83", 20, 0)])
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.check_inferno_report_html([('SleepThread', 80),
+                                        ('RunFunction', 20),
+                                        ('SleepFunction', 20)])
+
+
+class TestExampleWithNativeJniCall(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".MixActivity")
+
+    def test_smoke(self):
+        self.run_app_profiler()
+        self.run_cmd(["report.py", "-g", "--comms", "BusyThread", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run",
+            "Java_com_example_simpleperf_simpleperfexamplewithnative_MixActivity_callFunction"])
+        remove("annotated_files")
+        self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "BusyThread"])
+        self.check_exist(dirname="annotated_files")
+        self.check_file_under_dir("annotated_files", "native-lib.cpp")
+        summary_file = os.path.join("annotated_files", "summary")
+        self.check_annotation_summary(summary_file, [("native-lib.cpp", 5, 0), ("line 40", 5, 0)])
+        if self.use_compiled_java_code:
+            self.check_file_under_dir("annotated_files", "MixActivity.java")
+            self.check_annotation_summary(summary_file, [
+                ("MixActivity.java", 80, 0),
+                ("run", 80, 0),
+                ("line 26", 20, 0),
+                ("native-lib.cpp", 5, 0),
+                ("line 40", 5, 0)])
+
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+
+
+class TestExampleWithNativeForce32Bit(TestExampleWithNative):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".MainActivity",
+                    abi=TEST_HELPER.get_32bit_abi())
+
+
+class TestExampleWithNativeRootForce32Bit(TestExampleWithNativeRoot):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".MainActivity",
+                    abi=TEST_HELPER.get_32bit_abi(),
+                    adb_root=False)
+
+
+class TestExampleWithNativeTraceOffCpuForce32Bit(TestExampleWithNativeTraceOffCpu):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleWithNative",
+                    "com.example.simpleperf.simpleperfexamplewithnative",
+                    ".SleepActivity",
+                    abi=TEST_HELPER.get_32bit_abi())
diff --git a/test/debug_unwind_reporter_test.py b/test/debug_unwind_reporter_test.py
new file mode 100644
index 0000000..2a7c3ac
--- /dev/null
+++ b/test/debug_unwind_reporter_test.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typing import List
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestDebugUnwindReporter(TestBase):
+    def run_reporter(self, options: List[str]) -> str:
+        report_file = TEST_HELPER.testdata_dir_p / 'debug_unwind_report.txt'
+        return self.run_cmd(['debug_unwind_reporter.py', '-i',
+                             str(report_file)] + options, return_output=True)
+
+    def test_show_callchain_fixed_by_joiner_option(self):
+        output = self.run_reporter([])
+        self.assertFalse('__start_thread' in output)
+        output = self.run_reporter(['--show-callchain-fixed-by-joiner'])
+        self.assertTrue('__start_thread' in output)
+
+    def test_summary_option(self):
+        output = self.run_reporter(['--summary'])
+        self.assertTrue('Error Code' in output)
+
+    def test_error_code_filter_options(self):
+        output = self.run_reporter(['--exclude-error-code', '1'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        output = self.run_reporter(
+            ['--include-error-code', '4', '--show-callchain-fixed-by-joiner'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        self.assertTrue('sample_time: 626970513562864' in output)
+
+    def test_end_dso_filter_options(self):
+        output = self.run_reporter(
+            ['--exclude-end-dso', '/apex/com.android.runtime/lib64/bionic/libc.so'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        output = self.run_reporter(
+            ['--include-end-dso', '/apex/com.android.runtime/lib64/bionic/libc.so'])
+        self.assertTrue('sample_time: 626968109563718' in output)
+
+    def test_end_symbol_filter_options(self):
+        output = self.run_reporter(['--exclude-end-symbol', 'clone'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        output = self.run_reporter(
+            ['--include-end-symbol', '__start_thread', '--show-callchain-fixed-by-joiner'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        self.assertTrue('sample_time: 626970513562864' in output)
+
+    def test_sample_time_filter_options(self):
+        output = self.run_reporter(['--exclude-sample-time', '626968109563718'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        output = self.run_reporter(
+            ['--include-sample-time', '626970513562864', '--show-callchain-fixed-by-joiner'])
+        self.assertFalse('sample_time: 626968109563718' in output)
+        self.assertTrue('sample_time: 626970513562864' in output)
diff --git a/test/do_test.py b/test/do_test.py
new file mode 100755
index 0000000..8cde348
--- /dev/null
+++ b/test/do_test.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""test.py: Tests for simpleperf python scripts.
+
+These are smoke tests Using examples to run python scripts.
+For each example, we go through the steps of running each python script.
+Examples are collected from simpleperf/demo, which includes:
+  SimpleperfExamplePureJava
+  SimpleperfExampleWithNative
+  SimpleperfExampleOfKotlin
+
+Tested python scripts include:
+  app_profiler.py
+  report.py
+  annotate.py
+  report_sample.py
+  pprof_proto_generator.py
+  report_html.py
+
+Test using both `adb root` and `adb unroot`.
+
+"""
+import argparse
+import fnmatch
+import inspect
+import re
+from simpleperf_utils import extant_dir, log_exit, remove
+import sys
+import types
+import unittest
+
+from . api_profiler_test import *
+from . app_profiler_test import *
+from . app_test import *
+from . binary_cache_builder_test import *
+from . cpp_app_test import *
+from . debug_unwind_reporter_test import *
+from . java_app_test import *
+from . kotlin_app_test import *
+from . pprof_proto_generator_test import *
+from . report_html_test import *
+from . report_lib_test import *
+from . run_simpleperf_on_device_test import *
+from . tools_test import *
+from . test_utils import TEST_LOGGER, TEST_HELPER
+
+
+def get_all_tests():
+    tests = []
+    for name, value in globals().items():
+        if isinstance(value, type) and issubclass(value, unittest.TestCase):
+            for member_name, member in inspect.getmembers(value):
+                if isinstance(member, (types.MethodType, types.FunctionType)):
+                    if member_name.startswith('test'):
+                        tests.append(name + '.' + member_name)
+    return sorted(tests)
+
+
+def run_tests(tests):
+    TEST_HELPER.build_testdata()
+    argv = [sys.argv[0]] + tests
+    test_runner = unittest.TextTestRunner(stream=TEST_LOGGER, verbosity=0)
+    test_program = unittest.main(argv=argv, testRunner=test_runner,
+                                 exit=False, verbosity=0, module='test.do_test')
+    result = test_program.result.wasSuccessful()
+    remove(TEST_HELPER.testdata_dir)
+    return result
+
+
+def main():
+    parser = argparse.ArgumentParser(description='Test simpleperf scripts')
+    parser.add_argument('--list-tests', action='store_true', help='List all tests.')
+    parser.add_argument('--test-from', nargs=1, help='Run left tests from the selected test.')
+    parser.add_argument('--browser', action='store_true', help='pop report html file in browser.')
+    parser.add_argument('--progress-file', help='write test progress file')
+    parser.add_argument('--ndk-path', type=extant_dir, help='Set the path of a ndk release')
+    parser.add_argument('pattern', nargs='*', help='Run tests matching the selected pattern.')
+    args = parser.parse_args()
+    tests = get_all_tests()
+    if args.list_tests:
+        print('\n'.join(tests))
+        return True
+    if args.test_from:
+        start_pos = 0
+        while start_pos < len(tests) and tests[start_pos] != args.test_from[0]:
+            start_pos += 1
+        if start_pos == len(tests):
+            log_exit("Can't find test %s" % args.test_from[0])
+        tests = tests[start_pos:]
+    if args.pattern:
+        patterns = [re.compile(fnmatch.translate(x)) for x in args.pattern]
+        tests = [t for t in tests if any(pattern.match(t) for pattern in patterns)]
+        if not tests:
+            log_exit('No tests are matched.')
+
+    if TEST_HELPER.android_version < 7:
+        print("Skip tests on Android version < N.", file=TEST_LOGGER)
+        return False
+
+    TEST_HELPER.ndk_path = args.ndk_path
+
+    remove(TEST_HELPER.test_base_dir)
+
+    if not args.browser:
+        TEST_HELPER.browser_option = ['--no_browser']
+
+    if args.progress_file:
+        TEST_HELPER.progress_fh = open(args.progress_file, 'w')
+
+    result = run_tests(tests)
+    if not result:
+        print('Tests failed, see %s for details.' % TEST_LOGGER.log_file, file=TEST_LOGGER)
+    TEST_HELPER.write_progress('Test end')
+    return result
diff --git a/test/java_app_test.py b/test/java_app_test.py
new file mode 100644
index 0000000..306e4aa
--- /dev/null
+++ b/test/java_app_test.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import signal
+import subprocess
+import sys
+import time
+from simpleperf_utils import is_windows, remove
+from . app_test import TestExampleBase
+from . test_utils import TEST_HELPER, INFERNO_SCRIPT
+
+
+class TestExamplePureJava(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExamplePureJava",
+                    "com.example.simpleperf.simpleperfexamplepurejava",
+                    ".MainActivity")
+
+    def test_app_profiler(self):
+        self.common_test_app_profiler()
+
+    def test_app_profiler_profile_from_launch(self):
+        self.run_app_profiler(start_activity=True, build_binary_cache=False)
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+            "__start_thread"])
+
+    def test_app_profiler_multiprocesses(self):
+        self.adb.check_run(['shell', 'am', 'force-stop', self.package_name])
+        self.adb.check_run(['shell', 'am', 'start', '-n',
+                            self.package_name + '/.MultiProcessActivity'])
+        # Wait until both MultiProcessActivity and MultiProcessService set up.
+        time.sleep(3)
+        self.run_app_profiler(start_activity=False)
+        self.run_cmd(["report.py", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", ["BusyService", "BusyThread"])
+
+    def test_app_profiler_with_ctrl_c(self):
+        if is_windows():
+            return
+        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
+        time.sleep(1)
+        args = [sys.executable, TEST_HELPER.script_path("app_profiler.py"),
+                "--app", self.package_name, "-r", "--duration 10000", "--disable_adb_root"]
+        subproc = subprocess.Popen(args)
+        time.sleep(3)
+
+        subproc.send_signal(signal.SIGINT)
+        subproc.wait()
+        self.assertEqual(subproc.returncode, 0)
+        self.run_cmd(["report.py"])
+
+    def test_app_profiler_stop_after_app_exit(self):
+        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
+        time.sleep(1)
+        subproc = subprocess.Popen(
+            [sys.executable, TEST_HELPER.script_path('app_profiler.py'),
+             '--app', self.package_name, '-r', '--duration 10000', '--disable_adb_root'])
+        time.sleep(3)
+        self.adb.check_run(['shell', 'am', 'force-stop', self.package_name])
+        subproc.wait()
+        self.assertEqual(subproc.returncode, 0)
+        self.run_cmd(["report.py"])
+
+    def test_app_profiler_with_ndk_path(self):
+        # Although we pass an invalid ndk path, it should be able to find tools in default ndk path.
+        self.run_cmd(['app_profiler.py', '--app', self.package_name, '-a', self.activity_name,
+                      '--ndk_path', '.'])
+
+    def test_report(self):
+        self.common_test_report()
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+            "__start_thread"])
+
+    def test_profile_with_process_id(self):
+        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
+        time.sleep(1)
+        pid = self.adb.check_run_and_return_output([
+            'shell', 'pidof', 'com.example.simpleperf.simpleperfexamplepurejava']).strip()
+        self.run_app_profiler(start_activity=False, record_arg='-g --duration 10 -p ' + pid)
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+            "__start_thread"])
+
+    def test_annotate(self):
+        self.common_test_annotate()
+        if not self.use_compiled_java_code:
+            # Currently annotating Java code is only supported when the Java code is compiled.
+            return
+        self.check_file_under_dir("annotated_files", "MainActivity.java")
+        summary_file = os.path.join("annotated_files", "summary")
+        self.check_annotation_summary(summary_file, [
+            ("MainActivity.java", 80, 80),
+            ("run", 80, 0),
+            ("callFunction", 0, 0),
+            ("line 23", 80, 0)])
+
+    def test_report_sample(self):
+        self.common_test_report_sample(
+            ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+             "__start_thread"])
+
+    def test_pprof_proto_generator(self):
+        check_strings_with_lines = []
+        if self.use_compiled_java_code:
+            check_strings_with_lines = [
+                "com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java",
+                "run"]
+        self.common_test_pprof_proto_generator(
+            check_strings_with_lines=check_strings_with_lines,
+            check_strings_without_lines=[
+                "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run"])
+
+    def test_inferno(self):
+        self.common_test_inferno()
+        self.run_app_profiler()
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.check_inferno_report_html(
+            [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)])
+        self.run_cmd([INFERNO_SCRIPT, "-sc", "-o", "report2.html"])
+        self.check_inferno_report_html(
+            [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)],
+            "report2.html")
+
+    def test_inferno_in_another_dir(self):
+        test_dir = 'inferno_testdir'
+        os.mkdir(test_dir)
+        os.chdir(test_dir)
+        self.run_cmd(['app_profiler.py', '--app', self.package_name,
+                      '-r', '-e task-clock:u -g --duration 3'])
+        self.check_exist(filename="perf.data")
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+
+    def test_report_html(self):
+        self.common_test_report_html()
+
+    def test_run_simpleperf_without_usb_connection(self):
+        self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
+        self.run_cmd(['run_simpleperf_without_usb_connection.py', 'start', '-p',
+                      self.package_name, '--size_limit', '1M'])
+        self.adb.check_run(['kill-server'])
+        time.sleep(3)
+        # Start adb process outside self.test_dir. Because it will be removed after testing.
+        os.chdir(self.saved_cwd)
+        self.adb.check_run(['devices'])
+        os.chdir(self.test_dir)
+        self.run_cmd(['run_simpleperf_without_usb_connection.py', 'stop'])
+        self.check_exist(filename="perf.data")
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+
+
+class TestExamplePureJavaRoot(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExamplePureJava",
+                    "com.example.simpleperf.simpleperfexamplepurejava",
+                    ".MainActivity",
+                    adb_root=True)
+
+    def test_app_profiler(self):
+        self.common_test_app_profiler()
+
+
+class TestExamplePureJavaTraceOffCpu(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExamplePureJava",
+                    "com.example.simpleperf.simpleperfexamplepurejava",
+                    ".SleepActivity")
+
+    def test_smoke(self):
+        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run",
+            "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction",
+            "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction"
+        ])
+        remove("annotated_files")
+        self.run_cmd(["annotate.py", "-s", self.example_path])
+        self.check_exist(dirname="annotated_files")
+        if self.use_compiled_java_code:
+            self.check_file_under_dir("annotated_files", "SleepActivity.java")
+            summary_file = os.path.join("annotated_files", "summary")
+            self.check_annotation_summary(summary_file, [
+                ("SleepActivity.java", 80, 20),
+                ("run", 80, 0),
+                ("RunFunction", 20, 20),
+                ("SleepFunction", 20, 0),
+                ("line 24", 1, 0),
+                ("line 32", 20, 0)])
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.check_inferno_report_html(
+            [('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run', 80),
+             ('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction',
+              20),
+             ('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction',
+              20)])
diff --git a/test/kotlin_app_test.py b/test/kotlin_app_test.py
new file mode 100644
index 0000000..f317656
--- /dev/null
+++ b/test/kotlin_app_test.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from simpleperf_utils import remove
+from . app_test import TestExampleBase
+from . test_utils import INFERNO_SCRIPT
+
+
+class TestExampleOfKotlin(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleOfKotlin",
+                    "com.example.simpleperf.simpleperfexampleofkotlin",
+                    ".MainActivity")
+
+    def test_app_profiler(self):
+        self.common_test_app_profiler()
+
+    def test_app_profiler_profile_from_launch(self):
+        self.run_app_profiler(start_activity=True, build_binary_cache=False)
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
+            "run", "__start_thread"])
+
+    def test_report(self):
+        self.common_test_report()
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        self.check_strings_in_file("report.txt", [
+            "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
+            "run", "__start_thread"])
+
+    def test_annotate(self):
+        if not self.use_compiled_java_code:
+            return
+        self.common_test_annotate()
+        self.check_file_under_dir("annotated_files", "MainActivity.kt")
+        summary_file = os.path.join("annotated_files", "summary")
+        self.check_annotation_summary(summary_file, [
+            ("MainActivity.kt", 80, 80),
+            ("run", 80, 0),
+            ("callFunction", 0, 0),
+            ("line 19", 80, 0),
+            ("line 25", 0, 0)])
+
+    def test_report_sample(self):
+        self.common_test_report_sample([
+            "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
+            "run", "__start_thread"])
+
+    def test_pprof_proto_generator(self):
+        check_strings_with_lines = []
+        if self.use_compiled_java_code:
+            check_strings_with_lines = [
+                "com/example/simpleperf/simpleperfexampleofkotlin/MainActivity.kt",
+                "run"]
+        self.common_test_pprof_proto_generator(
+            check_strings_with_lines=check_strings_with_lines,
+            check_strings_without_lines=["com.example.simpleperf.simpleperfexampleofkotlin." +
+                                         "MainActivity$createBusyThread$1.run"])
+
+    def test_inferno(self):
+        self.common_test_inferno()
+        self.run_app_profiler()
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.check_inferno_report_html([('com.example.simpleperf.simpleperfexampleofkotlin.' +
+                                         'MainActivity$createBusyThread$1.run', 80)])
+
+    def test_report_html(self):
+        self.common_test_report_html()
+
+
+class TestExampleOfKotlinRoot(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleOfKotlin",
+                    "com.example.simpleperf.simpleperfexampleofkotlin",
+                    ".MainActivity",
+                    adb_root=True)
+
+    def test_app_profiler(self):
+        self.common_test_app_profiler()
+
+
+class TestExampleOfKotlinTraceOffCpu(TestExampleBase):
+    @classmethod
+    def setUpClass(cls):
+        cls.prepare("SimpleperfExampleOfKotlin",
+                    "com.example.simpleperf.simpleperfexampleofkotlin",
+                    ".SleepActivity")
+
+    def test_smoke(self):
+        self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
+        self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+        function_prefix = "com.example.simpleperf.simpleperfexampleofkotlin." + \
+                          "SleepActivity$createRunSleepThread$1."
+        self.check_strings_in_file("report.txt", [
+            function_prefix + "run",
+            function_prefix + "RunFunction",
+            function_prefix + "SleepFunction"
+        ])
+        if self.use_compiled_java_code:
+            remove("annotated_files")
+            self.run_cmd(["annotate.py", "-s", self.example_path])
+            self.check_exist(dirname="annotated_files")
+            self.check_file_under_dir("annotated_files", "SleepActivity.kt")
+            summary_file = os.path.join("annotated_files", "summary")
+            self.check_annotation_summary(summary_file, [
+                ("SleepActivity.kt", 80, 20),
+                ("run", 80, 0),
+                ("RunFunction", 20, 20),
+                ("SleepFunction", 20, 0),
+                ("line 24", 20, 0),
+                ("line 32", 20, 0)])
+
+        self.run_cmd([INFERNO_SCRIPT, "-sc"])
+        self.check_inferno_report_html([
+            (function_prefix + 'run', 80),
+            (function_prefix + 'RunFunction', 20),
+            (function_prefix + 'SleepFunction', 20)])
diff --git a/test/pprof_proto_generator_test.py b/test/pprof_proto_generator_test.py
new file mode 100644
index 0000000..1ea963c
--- /dev/null
+++ b/test/pprof_proto_generator_test.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import google.protobuf
+from pprof_proto_generator import load_pprof_profile
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestPprofProtoGenerator(TestBase):
+    def run_generator(self, options=None, testdata_file='perf_with_interpreter_frames.data'):
+        testdata_path = TEST_HELPER.testdata_path(testdata_file)
+        options = options or []
+        self.run_cmd(['pprof_proto_generator.py', '-i', testdata_path] + options)
+        return self.run_cmd(['pprof_proto_generator.py', '--show'], return_output=True)
+
+    def generate_profile(self, options, testdata_files):
+        testdata_paths = [TEST_HELPER.testdata_path(f) for f in testdata_files]
+        options = options or []
+        self.run_cmd(['pprof_proto_generator.py', '-i'] + testdata_paths + options)
+        return load_pprof_profile('pprof.profile')
+
+    def test_show_art_frames(self):
+        art_frame_str = 'art::interpreter::DoCall'
+        # By default, don't show art frames.
+        self.assertNotIn(art_frame_str, self.run_generator())
+        # Use --show_art_frames to show art frames.
+        self.assertIn(art_frame_str, self.run_generator(['--show_art_frames']))
+
+    def test_pid_filter(self):
+        key = 'PlayScene::DoFrame()'  # function in process 10419
+        self.assertIn(key, self.run_generator())
+        self.assertIn(key, self.run_generator(['--pid', '10419']))
+        self.assertIn(key, self.run_generator(['--pid', '10419', '10416']))
+        self.assertNotIn(key, self.run_generator(['--pid', '10416']))
+
+    def test_tid_filter(self):
+        key1 = 'art::ProfileSaver::Run()'  # function in thread 10459
+        key2 = 'PlayScene::DoFrame()'  # function in thread 10463
+        for options in ([], ['--tid', '10459', '10463']):
+            output = self.run_generator(options)
+            self.assertIn(key1, output)
+            self.assertIn(key2, output)
+        output = self.run_generator(['--tid', '10459'])
+        self.assertIn(key1, output)
+        self.assertNotIn(key2, output)
+        output = self.run_generator(['--tid', '10463'])
+        self.assertNotIn(key1, output)
+        self.assertIn(key2, output)
+
+    def test_comm_filter(self):
+        key1 = 'art::ProfileSaver::Run()'  # function in thread 'Profile Saver'
+        key2 = 'PlayScene::DoFrame()'  # function in thread 'e.sample.tunnel'
+        for options in ([], ['--comm', 'Profile Saver', 'e.sample.tunnel']):
+            output = self.run_generator(options)
+            self.assertIn(key1, output)
+            self.assertIn(key2, output)
+        output = self.run_generator(['--comm', 'Profile Saver'])
+        self.assertIn(key1, output)
+        self.assertNotIn(key2, output)
+        output = self.run_generator(['--comm', 'e.sample.tunnel'])
+        self.assertNotIn(key1, output)
+        self.assertIn(key2, output)
+
+    def test_build_id(self):
+        """ Test the build ids generated are not padded with zeros. """
+        self.assertIn('build_id: e3e938cc9e40de2cfe1a5ac7595897de(', self.run_generator())
+
+    def test_location_address(self):
+        """ Test if the address of a location is within the memory range of the corresponding
+            mapping.
+        """
+        profile = self.generate_profile(None, ['perf_with_interpreter_frames.data'])
+        # pylint: disable=no-member
+        for location in profile.location:
+            mapping = profile.mapping[location.mapping_id - 1]
+            self.assertLessEqual(mapping.memory_start, location.address)
+            self.assertGreaterEqual(mapping.memory_limit, location.address)
+
+    def test_multiple_perf_data(self):
+        """ Test reporting multiple recording file. """
+        profile1 = self.generate_profile(None, ['aggregatable_perf1.data'])
+        profile2 = self.generate_profile(None, ['aggregatable_perf2.data'])
+        profile_both = self.generate_profile(
+            None, ['aggregatable_perf1.data', 'aggregatable_perf2.data'])
+        # pylint: disable=no-member
+        self.assertGreater(len(profile_both.sample), len(profile1.sample))
+        self.assertGreater(len(profile_both.sample), len(profile2.sample))
diff --git a/test/report_html_test.py b/test/report_html_test.py
new file mode 100644
index 0000000..41b2ac7
--- /dev/null
+++ b/test/report_html_test.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import collections
+import json
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestReportHtml(TestBase):
+    def test_long_callchain(self):
+        self.run_cmd(['report_html.py', '-i',
+                      TEST_HELPER.testdata_path('perf_with_long_callchain.data')])
+
+    def test_aggregated_by_thread_name(self):
+        # Calculate event_count for each thread name before aggregation.
+        event_count_for_thread_name = collections.defaultdict(lambda: 0)
+        # use "--min_func_percent 0" to avoid cutting any thread.
+        self.run_cmd(['report_html.py', '--min_func_percent', '0', '-i',
+                      TEST_HELPER.testdata_path('aggregatable_perf1.data'),
+                      TEST_HELPER.testdata_path('aggregatable_perf2.data')])
+        record_data = self._load_record_data_in_html('report.html')
+        event = record_data['sampleInfo'][0]
+        for process in event['processes']:
+            for thread in process['threads']:
+                thread_name = record_data['threadNames'][str(thread['tid'])]
+                event_count_for_thread_name[thread_name] += thread['eventCount']
+
+        # Check event count for each thread after aggregation.
+        self.run_cmd(['report_html.py', '--aggregate-by-thread-name',
+                      '--min_func_percent', '0', '-i',
+                      TEST_HELPER.testdata_path('aggregatable_perf1.data'),
+                      TEST_HELPER.testdata_path('aggregatable_perf2.data')])
+        record_data = self._load_record_data_in_html('report.html')
+        event = record_data['sampleInfo'][0]
+        hit_count = 0
+        for process in event['processes']:
+            for thread in process['threads']:
+                thread_name = record_data['threadNames'][str(thread['tid'])]
+                self.assertEqual(thread['eventCount'],
+                                 event_count_for_thread_name[thread_name])
+                hit_count += 1
+        self.assertEqual(hit_count, len(event_count_for_thread_name))
+
+    def test_no_empty_process(self):
+        """ Test not showing a process having no threads. """
+        perf_data = TEST_HELPER.testdata_path('two_process_perf.data')
+        self.run_cmd(['report_html.py', '-i', perf_data])
+        record_data = self._load_record_data_in_html('report.html')
+        processes = record_data['sampleInfo'][0]['processes']
+        self.assertEqual(len(processes), 2)
+
+        # One process is removed because all its threads are removed for not
+        # reaching the min_func_percent limit.
+        self.run_cmd(['report_html.py', '-i', perf_data, '--min_func_percent', '20'])
+        record_data = self._load_record_data_in_html('report.html')
+        processes = record_data['sampleInfo'][0]['processes']
+        self.assertEqual(len(processes), 1)
+
+    def _load_record_data_in_html(self, html_file):
+        with open(html_file, 'r') as fh:
+            data = fh.read()
+        start_str = 'type="application/json"'
+        end_str = '</script>'
+        start_pos = data.find(start_str)
+        self.assertNotEqual(start_pos, -1)
+        start_pos = data.find('>', start_pos)
+        self.assertNotEqual(start_pos, -1)
+        start_pos += 1
+        end_pos = data.find(end_str, start_pos)
+        self.assertNotEqual(end_pos, -1)
+        json_data = data[start_pos:end_pos]
+        return json.loads(json_data)
diff --git a/test/report_lib_test.py b/test/report_lib_test.py
new file mode 100644
index 0000000..3673220
--- /dev/null
+++ b/test/report_lib_test.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from simpleperf_report_lib import ReportLib
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestReportLib(TestBase):
+    def setUp(self):
+        super(TestReportLib, self).setUp()
+        self.report_lib = ReportLib()
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_symbols.data'))
+
+    def tearDown(self):
+        self.report_lib.Close()
+        super(TestReportLib, self).tearDown()
+
+    def test_build_id(self):
+        build_id = self.report_lib.GetBuildIdForPath('/data/t2')
+        self.assertEqual(build_id, '0x70f1fe24500fc8b0d9eb477199ca1ca21acca4de')
+
+    def test_symbol(self):
+        found_func2 = False
+        while self.report_lib.GetNextSample():
+            symbol = self.report_lib.GetSymbolOfCurrentSample()
+            if symbol.symbol_name == 'func2(int, int)':
+                found_func2 = True
+                self.assertEqual(symbol.symbol_addr, 0x4004ed)
+                self.assertEqual(symbol.symbol_len, 0x14)
+        self.assertTrue(found_func2)
+
+    def test_sample(self):
+        found_sample = False
+        while self.report_lib.GetNextSample():
+            sample = self.report_lib.GetCurrentSample()
+            if sample.ip == 0x4004ff and sample.time == 7637889424953:
+                found_sample = True
+                self.assertEqual(sample.pid, 15926)
+                self.assertEqual(sample.tid, 15926)
+                self.assertEqual(sample.thread_comm, 't2')
+                self.assertEqual(sample.cpu, 5)
+                self.assertEqual(sample.period, 694614)
+                event = self.report_lib.GetEventOfCurrentSample()
+                self.assertEqual(event.name, 'cpu-cycles')
+                callchain = self.report_lib.GetCallChainOfCurrentSample()
+                self.assertEqual(callchain.nr, 0)
+        self.assertTrue(found_sample)
+
+    def test_meta_info(self):
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
+        meta_info = self.report_lib.MetaInfo()
+        self.assertTrue("simpleperf_version" in meta_info)
+        self.assertEqual(meta_info["system_wide_collection"], "false")
+        self.assertEqual(meta_info["trace_offcpu"], "true")
+        self.assertEqual(meta_info["event_type_info"], "cpu-cycles,0,0\nsched:sched_switch,2,47")
+        self.assertTrue("product_props" in meta_info)
+
+    def test_event_name_from_meta_info(self):
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_tracepoint_event.data'))
+        event_names = set()
+        while self.report_lib.GetNextSample():
+            event_names.add(self.report_lib.GetEventOfCurrentSample().name)
+        self.assertTrue('sched:sched_switch' in event_names)
+        self.assertTrue('cpu-cycles' in event_names)
+
+    def test_record_cmd(self):
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
+        self.assertEqual(self.report_lib.GetRecordCmd(),
+                         "/data/local/tmp/simpleperf record --trace-offcpu --duration 2 -g " +
+                         "./simpleperf_runtest_run_and_sleep64")
+
+    def test_offcpu(self):
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_trace_offcpu.data'))
+        total_period = 0
+        sleep_function_period = 0
+        sleep_function_name = "SleepFunction(unsigned long long)"
+        while self.report_lib.GetNextSample():
+            sample = self.report_lib.GetCurrentSample()
+            total_period += sample.period
+            if self.report_lib.GetSymbolOfCurrentSample().symbol_name == sleep_function_name:
+                sleep_function_period += sample.period
+                continue
+            callchain = self.report_lib.GetCallChainOfCurrentSample()
+            for i in range(callchain.nr):
+                if callchain.entries[i].symbol.symbol_name == sleep_function_name:
+                    sleep_function_period += sample.period
+                    break
+            self.assertEqual(self.report_lib.GetEventOfCurrentSample().name, 'cpu-cycles')
+        sleep_percentage = float(sleep_function_period) / total_period
+        self.assertGreater(sleep_percentage, 0.30)
+
+    def test_show_art_frames(self):
+        def has_art_frame(report_lib):
+            report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_interpreter_frames.data'))
+            result = False
+            while report_lib.GetNextSample():
+                callchain = report_lib.GetCallChainOfCurrentSample()
+                for i in range(callchain.nr):
+                    if callchain.entries[i].symbol.symbol_name == 'artMterpAsmInstructionStart':
+                        result = True
+                        break
+            report_lib.Close()
+            return result
+
+        report_lib = ReportLib()
+        self.assertFalse(has_art_frame(report_lib))
+        report_lib = ReportLib()
+        report_lib.ShowArtFrames(False)
+        self.assertFalse(has_art_frame(report_lib))
+        report_lib = ReportLib()
+        report_lib.ShowArtFrames(True)
+        self.assertTrue(has_art_frame(report_lib))
+
+    def test_merge_java_methods(self):
+        def parse_dso_names(report_lib):
+            dso_names = set()
+            report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_interpreter_frames.data'))
+            while report_lib.GetNextSample():
+                dso_names.add(report_lib.GetSymbolOfCurrentSample().dso_name)
+                callchain = report_lib.GetCallChainOfCurrentSample()
+                for i in range(callchain.nr):
+                    dso_names.add(callchain.entries[i].symbol.dso_name)
+            report_lib.Close()
+            has_jit_symfiles = any('TemporaryFile-' in name for name in dso_names)
+            has_jit_cache = '[JIT cache]' in dso_names
+            return has_jit_symfiles, has_jit_cache
+
+        report_lib = ReportLib()
+        self.assertEqual(parse_dso_names(report_lib), (False, True))
+
+        report_lib = ReportLib()
+        report_lib.MergeJavaMethods(True)
+        self.assertEqual(parse_dso_names(report_lib), (False, True))
+
+        report_lib = ReportLib()
+        report_lib.MergeJavaMethods(False)
+        self.assertEqual(parse_dso_names(report_lib), (True, False))
+
+    def test_jited_java_methods(self):
+        report_lib = ReportLib()
+        report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_jit_symbol.data'))
+        has_jit_cache = False
+        while report_lib.GetNextSample():
+            if report_lib.GetSymbolOfCurrentSample().dso_name == '[JIT app cache]':
+                has_jit_cache = True
+            callchain = report_lib.GetCallChainOfCurrentSample()
+            for i in range(callchain.nr):
+                if callchain.entries[i].symbol.dso_name == '[JIT app cache]':
+                    has_jit_cache = True
+        report_lib.Close()
+        self.assertTrue(has_jit_cache)
+
+    def test_tracing_data(self):
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path('perf_with_tracepoint_event.data'))
+        has_tracing_data = False
+        while self.report_lib.GetNextSample():
+            event = self.report_lib.GetEventOfCurrentSample()
+            tracing_data = self.report_lib.GetTracingDataOfCurrentSample()
+            if event.name == 'sched:sched_switch':
+                self.assertIsNotNone(tracing_data)
+                self.assertIn('prev_pid', tracing_data)
+                self.assertIn('next_comm', tracing_data)
+                if tracing_data['prev_pid'] == 9896 and tracing_data['next_comm'] == 'swapper/4':
+                    has_tracing_data = True
+            else:
+                self.assertIsNone(tracing_data)
+        self.assertTrue(has_tracing_data)
+
+    def test_dynamic_field_in_tracing_data(self):
+        self.report_lib.SetRecordFile(TEST_HELPER.testdata_path(
+            'perf_with_tracepoint_event_dynamic_field.data'))
+        has_dynamic_field = False
+        while self.report_lib.GetNextSample():
+            event = self.report_lib.GetEventOfCurrentSample()
+            tracing_data = self.report_lib.GetTracingDataOfCurrentSample()
+            if event.name == 'kprobes:myopen':
+                self.assertIsNotNone(tracing_data)
+                self.assertIn('name', tracing_data)
+                if tracing_data['name'] == '/sys/kernel/debug/tracing/events/kprobes/myopen/format':
+                    has_dynamic_field = True
+            else:
+                self.assertIsNone(tracing_data)
+        self.assertTrue(has_dynamic_field)
diff --git a/test/run_simpleperf_on_device_test.py b/test/run_simpleperf_on_device_test.py
new file mode 100644
index 0000000..2de7422
--- /dev/null
+++ b/test/run_simpleperf_on_device_test.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from . test_utils import TestBase
+
+
+class TestRunSimpleperfOnDevice(TestBase):
+    def test_smoke(self):
+        self.run_cmd(['run_simpleperf_on_device.py', 'list', '--show-features'])
diff --git a/test/test.py b/test/test.py
new file mode 100755
index 0000000..6c5a812
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from pathlib import Path
+import sys
+
+# fmt: off
+sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
+import test
+# fmt: on
+
+sys.exit(0 if test.main() else 1)
diff --git a/test_monitor.py b/test/test_monitor.py
similarity index 100%
rename from test_monitor.py
rename to test/test_monitor.py
diff --git a/test/test_utils.py b/test/test_utils.py
new file mode 100644
index 0000000..0b5c0fb
--- /dev/null
+++ b/test/test_utils.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""test_utils.py: utils for testing.
+"""
+
+import logging
+import os
+from pathlib import Path
+import shutil
+import sys
+from simpleperf_utils import remove, get_script_dir, AdbHelper, is_windows, bytes_to_str
+import subprocess
+import time
+import unittest
+
+INFERNO_SCRIPT = str(Path(__file__).parents[1] / ('inferno.bat' if is_windows() else 'inferno.sh'))
+
+
+class TestLogger:
+    """ Write test progress in sys.stderr and keep verbose log in log file. """
+
+    def __init__(self):
+        self.log_file = 'test.log'
+        remove(self.log_file)
+        # Logs can come from multiple processes. So use append mode to avoid overwrite.
+        self.log_fh = open(self.log_file, 'a')
+        logging.basicConfig(filename=self.log_file)
+
+    def writeln(self, s):
+        return self.write(s + '\n')
+
+    def write(self, s):
+        sys.stderr.write(s)
+        self.log_fh.write(s)
+        # Child processes can also write to log file, so flush it immediately to keep the order.
+        self.flush()
+
+    def flush(self):
+        self.log_fh.flush()
+
+
+TEST_LOGGER = TestLogger()
+
+
+class TestHelper:
+    """ Keep global test info. """
+
+    def __init__(self):
+        #self.script_dir = os.path.abspath(get_script_dir())
+        self.script_test_dir = Path(__file__).resolve().parent
+        self.script_dir = self.script_test_dir.parent
+        self.cur_dir = os.getcwd()
+        self.testdata_dir = os.path.join(self.cur_dir, 'testdata')
+        self.testdata_dir_p = Path(self.testdata_dir)
+        self.test_base_dir = os.path.join(self.cur_dir, 'test_results')
+        self.adb = AdbHelper(enable_switch_to_root=True)
+        self.android_version = self.adb.get_android_version()
+        self.device_features = None
+        self.browser_option = []
+        self.progress_fh = None
+        self.ndk_path = None
+
+    def testdata_path(self, testdata_name):
+        """ Return the path of a test data. """
+        return os.path.join(self.testdata_dir, testdata_name.replace('/', os.sep))
+
+    def test_dir(self, test_name):
+        """ Return the dir to run a test. """
+        return os.path.join(self.test_base_dir, test_name)
+
+    def script_path(self, script_name):
+        """ Return the dir of python scripts. """
+        return os.path.join(self.script_dir, script_name)
+
+    def get_device_features(self):
+        if self.device_features is None:
+            args = [sys.executable, self.script_path(
+                'run_simpleperf_on_device.py'), 'list', '--show-features']
+            output = subprocess.check_output(args, stderr=TEST_LOGGER.log_fh)
+            output = bytes_to_str(output)
+            self.device_features = output.split()
+        return self.device_features
+
+    def is_trace_offcpu_supported(self):
+        return 'trace-offcpu' in self.get_device_features()
+
+    def build_testdata(self):
+        """ Collect testdata in self.testdata_dir.
+            In system/extras/simpleperf/scripts, testdata comes from:
+                <script_dir>/../testdata, <script_dir>/test/script_testdata, <script_dir>/../demo
+            In prebuilts/simpleperf, testdata comes from:
+                <script_dir>/testdata
+        """
+        if os.path.isdir(self.testdata_dir):
+            return  # already built
+        os.makedirs(self.testdata_dir)
+
+        source_dirs = [
+            self.script_test_dir / 'script_testdata',
+            self.script_dir.parent / 'testdata',
+            self.script_dir.parent / 'demo',
+            self.script_dir / 'testdata',
+        ]
+
+        for source_dir in source_dirs:
+            if not source_dir.is_dir():
+                continue
+            for src_path in source_dir.iterdir():
+                dest_path = Path(self.testdata_dir) / src_path.name
+                if dest_path.exists():
+                    continue
+                if src_path.is_file():
+                    shutil.copyfile(src_path, dest_path)
+                elif src_path.is_dir():
+                    shutil.copytree(src_path, dest_path)
+
+    def get_32bit_abi(self):
+        return self.adb.get_property('ro.product.cpu.abilist32').strip().split(',')[0]
+
+    def write_progress(self, progress):
+        if self.progress_fh:
+            self.progress_fh.write(progress + '\n')
+            self.progress_fh.flush()
+
+
+TEST_HELPER = TestHelper()
+
+
+class TestBase(unittest.TestCase):
+    def setUp(self):
+        """ Run each test in a separate dir. """
+        self.test_dir = TEST_HELPER.test_dir('%s.%s' % (
+            self.__class__.__name__, self._testMethodName))
+        os.makedirs(self.test_dir)
+        self.saved_cwd = os.getcwd()
+        os.chdir(self.test_dir)
+        TEST_LOGGER.writeln('begin test %s.%s' % (self.__class__.__name__, self._testMethodName))
+        self.start_time = time.time()
+
+    def run(self, result=None):
+        ret = super(TestBase, self).run(result)
+        if result.errors and result.errors[-1][0] == self:
+            status = 'FAILED'
+            err_info = result.errors[-1][1]
+        elif result.failures and result.failures[-1][0] == self:
+            status = 'FAILED'
+            err_info = result.failures[-1][1]
+        else:
+            status = 'OK'
+
+        time_taken = time.time() - self.start_time
+        TEST_LOGGER.writeln(
+            'end test %s.%s %s (%.3fs)' %
+            (self.__class__.__name__, self._testMethodName, status, time_taken))
+        if status != 'OK':
+            TEST_LOGGER.writeln(err_info)
+
+        # Remove test data for passed tests to save space.
+        os.chdir(self.saved_cwd)
+        if status == 'OK':
+            shutil.rmtree(self.test_dir)
+        TEST_HELPER.write_progress(
+            '%s.%s  %s' % (self.__class__.__name__, self._testMethodName, status))
+        return ret
+
+    def run_cmd(self, args: List[str], return_output=False, drop_output=True) -> str:
+        if args[0] == 'report_html.py' or args[0] == INFERNO_SCRIPT:
+            args += TEST_HELPER.browser_option
+        if TEST_HELPER.ndk_path:
+            if args[0] in ['app_profiler.py', 'binary_cache_builder.py', 'pprof_proto_generator.py',
+                           'report_html.py']:
+                args += ['--ndk_path', TEST_HELPER.ndk_path]
+        if args[0].endswith('.py'):
+            args = [sys.executable, TEST_HELPER.script_path(args[0])] + args[1:]
+        use_shell = args[0].endswith('.bat')
+        try:
+            if return_output:
+                stdout_fd = subprocess.PIPE
+                drop_output = False
+            elif drop_output:
+                stdout_fd = subprocess.DEVNULL
+            else:
+                stdout_fd = None
+
+            subproc = subprocess.Popen(args, stdout=stdout_fd,
+                                       stderr=TEST_LOGGER.log_fh, shell=use_shell)
+            stdout_data, _ = subproc.communicate()
+            output_data = bytes_to_str(stdout_data)
+            returncode = subproc.returncode
+
+        except OSError:
+            returncode = None
+        self.assertEqual(returncode, 0, msg="failed to run cmd: %s" % args)
+        if return_output:
+            return output_data
+        return ''
+
+    def check_strings_in_file(self, filename, strings):
+        self.check_exist(filename=filename)
+        with open(filename, 'r') as fh:
+            self.check_strings_in_content(fh.read(), strings)
+
+    def check_exist(self, filename=None, dirname=None):
+        if filename:
+            self.assertTrue(os.path.isfile(filename), filename)
+        if dirname:
+            self.assertTrue(os.path.isdir(dirname), dirname)
+
+    def check_strings_in_content(self, content, strings):
+        fulfilled = [content.find(s) != -1 for s in strings]
+        self.check_fulfilled_entries(fulfilled, strings)
+
+    def check_fulfilled_entries(self, fulfilled, entries):
+        failed_entries = []
+        for ok, entry in zip(fulfilled, entries):
+            if not ok:
+                failed_entries.append(entry)
+
+        if failed_entries:
+            self.fail('failed in below entries: %s' % (failed_entries,))
diff --git a/test/testdata/CppApi/app/build.gradle b/test/testdata/CppApi/app/build.gradle
new file mode 100644
index 0000000..4686696
--- /dev/null
+++ b/test/testdata/CppApi/app/build.gradle
@@ -0,0 +1,39 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 28
+    defaultConfig {
+        applicationId "simpleperf.demo.cpp_api"
+        // Simpleperf suggests running on Android >= N.
+        // (https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.md#why-we-suggest-profiling-on-android-n-devices)
+        minSdkVersion 24
+        targetSdkVersion 28
+        versionCode 1
+        versionName "1.0"
+        externalNativeBuild {
+            cmake {
+                cppFlags "-std=c++14"
+            }
+        }
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "src/main/cpp/CMakeLists.txt"
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'com.android.support:appcompat-v7:27.1.1'
+    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'com.android.support.test:runner:1.0.2'
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}
diff --git a/test/testdata/CppApi/app/proguard-rules.pro b/test/testdata/CppApi/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/test/testdata/CppApi/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/test/testdata/CppApi/app/src/main/AndroidManifest.xml b/test/testdata/CppApi/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..26b51b3
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="simpleperf.demo.cpp_api">
+
+    <application android:allowBackup="true"
+         android:icon="@mipmap/ic_launcher"
+         android:label="@string/app_name"
+         android:roundIcon="@mipmap/ic_launcher_round"
+         android:supportsRtl="true"
+         android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/test/testdata/CppApi/app/src/main/cpp/CMakeLists.txt b/test/testdata/CppApi/app/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..739b569
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.4.1)
+project(CppApiDemo LANGUAGES CXX)
+
+add_library(
+        native-lib
+        SHARED
+        native-lib.cpp
+        ../../../../../../app_api/cpp/simpleperf.cpp)
+
+target_include_directories(native-lib
+        PRIVATE
+        ../../../../../../app_api/cpp/)
+
+find_library(
+        log-lib
+        log)
+
+target_link_libraries(
+        native-lib
+        PRIVATE
+        ${log-lib})
\ No newline at end of file
diff --git a/testdata/CppApi/app/src/main/cpp/native-lib.cpp b/test/testdata/CppApi/app/src/main/cpp/native-lib.cpp
similarity index 100%
rename from testdata/CppApi/app/src/main/cpp/native-lib.cpp
rename to test/testdata/CppApi/app/src/main/cpp/native-lib.cpp
diff --git a/testdata/CppApi/app/src/main/java/simpleperf/demo/cpp_api/MainActivity.java b/test/testdata/CppApi/app/src/main/java/simpleperf/demo/cpp_api/MainActivity.java
similarity index 100%
rename from testdata/CppApi/app/src/main/java/simpleperf/demo/cpp_api/MainActivity.java
rename to test/testdata/CppApi/app/src/main/java/simpleperf/demo/cpp_api/MainActivity.java
diff --git a/test/testdata/CppApi/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/test/testdata/CppApi/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
diff --git a/test/testdata/CppApi/app/src/main/res/drawable/ic_launcher_background.xml b/test/testdata/CppApi/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#008577"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/test/testdata/CppApi/app/src/main/res/layout/activity_main.xml b/test/testdata/CppApi/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..19f5e7d
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <TextView
+        android:id="@+id/textView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Hello World!"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/test/testdata/CppApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/test/testdata/CppApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test/testdata/CppApi/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/test/testdata/CppApi/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-mdpi/ic_launcher.png b/test/testdata/CppApi/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/test/testdata/CppApi/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test/testdata/CppApi/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/test/testdata/CppApi/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test/testdata/CppApi/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/test/testdata/CppApi/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test/testdata/CppApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test/testdata/CppApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/CppApi/app/src/main/res/values/colors.xml b/test/testdata/CppApi/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#008577</color>
+    <color name="colorPrimaryDark">#00574B</color>
+    <color name="colorAccent">#D81B60</color>
+</resources>
diff --git a/test/testdata/CppApi/app/src/main/res/values/strings.xml b/test/testdata/CppApi/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9680775
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">CppApi</string>
+</resources>
diff --git a/test/testdata/CppApi/app/src/main/res/values/styles.xml b/test/testdata/CppApi/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/test/testdata/CppApi/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/test/testdata/CppApi/build.gradle b/test/testdata/CppApi/build.gradle
new file mode 100644
index 0000000..9ce834a
--- /dev/null
+++ b/test/testdata/CppApi/build.gradle
@@ -0,0 +1,20 @@
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.3.1'
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/test/testdata/CppApi/gradle.properties b/test/testdata/CppApi/gradle.properties
new file mode 100644
index 0000000..82618ce
--- /dev/null
+++ b/test/testdata/CppApi/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+
diff --git a/test/testdata/CppApi/gradle/wrapper/gradle-wrapper.jar b/test/testdata/CppApi/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
--- /dev/null
+++ b/test/testdata/CppApi/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/test/testdata/CppApi/gradle/wrapper/gradle-wrapper.properties b/test/testdata/CppApi/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..a677278
--- /dev/null
+++ b/test/testdata/CppApi/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Feb 14 15:10:26 PST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/test/testdata/CppApi/gradlew b/test/testdata/CppApi/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/test/testdata/CppApi/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/test/testdata/CppApi/gradlew.bat b/test/testdata/CppApi/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/test/testdata/CppApi/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/test/testdata/CppApi/settings.gradle b/test/testdata/CppApi/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/test/testdata/CppApi/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/test/testdata/DisplayBitmaps.apk b/test/testdata/DisplayBitmaps.apk
new file mode 100644
index 0000000..aace1ae
--- /dev/null
+++ b/test/testdata/DisplayBitmaps.apk
Binary files differ
diff --git a/test/testdata/DisplayBitmapsTest.apk b/test/testdata/DisplayBitmapsTest.apk
new file mode 100644
index 0000000..505b32f
--- /dev/null
+++ b/test/testdata/DisplayBitmapsTest.apk
Binary files differ
diff --git a/test/testdata/EndlessTunnel.apk b/test/testdata/EndlessTunnel.apk
new file mode 100644
index 0000000..09afd7f
--- /dev/null
+++ b/test/testdata/EndlessTunnel.apk
Binary files differ
diff --git a/test/testdata/JavaApi/app/build.gradle b/test/testdata/JavaApi/app/build.gradle
new file mode 100644
index 0000000..e53f7da
--- /dev/null
+++ b/test/testdata/JavaApi/app/build.gradle
@@ -0,0 +1,33 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 29
+    defaultConfig {
+        applicationId "simpleperf.demo.java_api"
+        // Simpleperf profiles interpreted/jitted Java code on Android >= P.
+        // https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.md#prepare-an-android-application
+        minSdkVersion 28
+        targetSdkVersion 29
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    sourceSets {
+        main.java.srcDirs += '../../../app_api/java'
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'com.android.support:appcompat-v7:27.1.1'
+    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'com.android.support.test:runner:1.0.2'
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}
diff --git a/test/testdata/JavaApi/app/proguard-rules.pro b/test/testdata/JavaApi/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/test/testdata/JavaApi/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/test/testdata/JavaApi/app/src/main/AndroidManifest.xml b/test/testdata/JavaApi/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f89708e
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="simpleperf.demo.java_api">
+
+    <application android:allowBackup="true"
+         android:icon="@mipmap/ic_launcher"
+         android:label="@string/app_name"
+         android:roundIcon="@mipmap/ic_launcher_round"
+         android:supportsRtl="true"
+         android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/testdata/JavaApi/app/src/main/java/simpleperf/demo/java_api/MainActivity.java b/test/testdata/JavaApi/app/src/main/java/simpleperf/demo/java_api/MainActivity.java
similarity index 100%
rename from testdata/JavaApi/app/src/main/java/simpleperf/demo/java_api/MainActivity.java
rename to test/testdata/JavaApi/app/src/main/java/simpleperf/demo/java_api/MainActivity.java
diff --git a/test/testdata/JavaApi/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/test/testdata/JavaApi/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
diff --git a/test/testdata/JavaApi/app/src/main/res/drawable/ic_launcher_background.xml b/test/testdata/JavaApi/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#008577"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/test/testdata/JavaApi/app/src/main/res/layout/activity_main.xml b/test/testdata/JavaApi/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..83d2102
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Hello World!"
+        android:id="@+id/textView"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/test/testdata/JavaApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/test/testdata/JavaApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test/testdata/JavaApi/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/test/testdata/JavaApi/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-mdpi/ic_launcher.png b/test/testdata/JavaApi/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/test/testdata/JavaApi/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test/testdata/JavaApi/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/test/testdata/JavaApi/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test/testdata/JavaApi/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/test/testdata/JavaApi/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test/testdata/JavaApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test/testdata/JavaApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/JavaApi/app/src/main/res/values/colors.xml b/test/testdata/JavaApi/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#008577</color>
+    <color name="colorPrimaryDark">#00574B</color>
+    <color name="colorAccent">#D81B60</color>
+</resources>
diff --git a/test/testdata/JavaApi/app/src/main/res/values/strings.xml b/test/testdata/JavaApi/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..38d07e8
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">JavaApi</string>
+</resources>
diff --git a/test/testdata/JavaApi/app/src/main/res/values/styles.xml b/test/testdata/JavaApi/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/test/testdata/JavaApi/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/test/testdata/JavaApi/build.gradle b/test/testdata/JavaApi/build.gradle
new file mode 100644
index 0000000..9ce834a
--- /dev/null
+++ b/test/testdata/JavaApi/build.gradle
@@ -0,0 +1,20 @@
+buildscript {
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.3.1'
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/test/testdata/JavaApi/gradle.properties b/test/testdata/JavaApi/gradle.properties
new file mode 100644
index 0000000..82618ce
--- /dev/null
+++ b/test/testdata/JavaApi/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+
diff --git a/test/testdata/JavaApi/gradle/wrapper/gradle-wrapper.jar b/test/testdata/JavaApi/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
--- /dev/null
+++ b/test/testdata/JavaApi/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/test/testdata/JavaApi/gradle/wrapper/gradle-wrapper.properties b/test/testdata/JavaApi/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3e897fb
--- /dev/null
+++ b/test/testdata/JavaApi/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Feb 14 12:43:19 PST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/test/testdata/JavaApi/gradlew b/test/testdata/JavaApi/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/test/testdata/JavaApi/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/test/testdata/JavaApi/gradlew.bat b/test/testdata/JavaApi/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/test/testdata/JavaApi/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/test/testdata/JavaApi/settings.gradle b/test/testdata/JavaApi/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/test/testdata/JavaApi/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/test/testdata/README.md b/test/testdata/README.md
new file mode 100644
index 0000000..2005fa2
--- /dev/null
+++ b/test/testdata/README.md
@@ -0,0 +1,182 @@
+# Examples of using simpleperf to profile Android applications
+
+## Table of Contents
+
+- [Examples of using simpleperf to profile Android applications](#examples-of-using-simpleperf-to-profile-android-applications)
+  - [Table of Contents](#table-of-contents)
+  - [Introduction](#introduction)
+  - [Profile a Java application](#profile-a-java-application)
+  - [Profile a Java/C++ application](#profile-a-javac-application)
+  - [Profile a Kotlin application](#profile-a-kotlin-application)
+- [Profile via app_api](#profile-via-app_api)
+
+## Introduction
+
+Simpleperf is a native profiler used on Android platform. It can be used to profile Android
+applications. Its documentation is [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.md).
+Instructions of preparing your Android application for profiling are [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.md#Android-application-profiling).
+This directory is to show examples of using simpleperf to profile Android applications. The
+meaning of each directory is as below:
+
+    ../scripts/                  -- contain simpleperf binaries and scripts.
+    SimpleperfExamplePureJava/   -- contains an Android Studio project using only Java code.
+    SimpleperfExampleWithNative/ -- contains an Android Studio project using both Java and C++ code.
+    SimpleperfExampleOfKotlin/   -- contains an Android Studio project using Kotlin code.
+    CppApi/                      -- contains an Android Studio project using c++ app_api to record.
+    JavaApi/                     -- contains an Android Studio project using Java app_api to record.
+
+It can be downloaded as below:
+
+```sh
+$ git clone https://android.googlesource.com/platform/system/extras
+$ cd extras/simpleperf/demo
+```
+
+The testing environment:
+
+```
+Android Studio 3.2
+test device: Android O (Google Pixel 2)
+test device: Android N (Google Nexus 6P)
+Please make sure your device having Android version >= N.
+```
+
+## Profile a Java application
+
+Android Studio project: SimpleExamplePureJava
+
+steps:
+1. Build and install the application:
+
+```sh
+# Open SimpleperfExamplesPureJava project with Android Studio,
+# and build this project successfully, otherwise the `./gradlew` command below will fail.
+$ cd SimpleperfExamplePureJava
+
+# On windows, use "gradlew" instead.
+$ ./gradlew clean assemble
+$ adb install -r app/build/outputs/apk/app-profiling.apk
+```
+
+2. Record profiling data:
+
+```sh
+$ cd ../../scripts/
+# app_profiler.py collects profiling data in perf.data, and binaries on device in binary_cache/.
+$ python app_profiler.py -p com.example.simpleperf.simpleperfexamplepurejava
+```
+
+3. Show profiling data:
+
+```sh
+# report_html.py generates profiling result in report.html.
+$ python report_html.py --add_source_code --source_dirs ../demo --add_disassembly
+```
+
+## Profile a Java/C++ application
+
+Android Studio project: SimpleExampleWithNative
+
+steps:
+1. Build and install the application:
+
+```sh
+# Open SimpleperfExamplesWithNative project with Android Studio,
+# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
+$ cd SimpleperfExampleWithNative
+
+# On windows, use "gradlew" instead.
+$ ./gradlew clean assemble
+$ adb install -r app/build/outputs/apk/profiling/app-profiling.apk
+```
+
+2. Record profiling data:
+
+```sh
+$ cd ../../scripts/
+# app_profiler.py collects profiling data in perf.data, and binaries on device in binary_cache/.
+$ python app_profiler.py -p com.example.simpleperf.simpleperfexamplewithnative
+```
+
+3. Show profiling data:
+
+```sh
+# report_html.py generates profiling result in report.html.
+$ python report_html.py --add_source_code --source_dirs ../demo --add_disassembly
+```
+
+## Profile a Kotlin application
+
+Android Studio project: SimpleExampleOfKotlin
+
+steps:
+1. Build and install the application:
+
+```sh
+# Open SimpleperfExamplesOfKotlin project with Android Studio,
+# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
+$ cd SimpleperfExampleOfKotlin
+
+# On windows, use "gradlew" instead.
+$ ./gradlew clean assemble
+$ adb install -r app/build/outputs/apk/profiling/app-profiling.apk
+```
+
+2. Record profiling data:
+
+```sh
+$ cd ../../scripts/
+# app_profiler.py collects profiling data in perf.data, and binaries on device in binary_cache/.
+$ python app_profiler.py -p com.example.simpleperf.simpleperfexampleofkotlin
+```
+
+3. Show profiling data:
+
+```sh
+# report_html.py generates profiling result in report.html.
+$ python report_html.py --add_source_code --source_dirs ../demo --add_disassembly
+```
+
+# Profile via app_api
+
+Android Studio project: CppApi and JavaApi
+
+steps:
+1. Build and install the application:
+
+```sh
+# Open CppApi project with Android Studio,
+# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
+$ cd CppApi
+
+# On windows, use "gradlew" instead.
+$ ./gradlew clean assemble
+$ adb install -r app/build/outputs/apk/debug/app-debug.apk
+```
+
+2. Prepare recording environment.
+
+```sh
+$ cd ../../scripts/
+$ python api_profiler.py prepare
+```
+
+3. Run the CppApi app.
+
+```sh
+# launch the app via cmdline, can also launch it on device.
+# A profiling file is generated each time running the app.
+$ adb shell am start simpleperf.demo.cpp_api/.MainActivity
+```
+
+4. Collect profiling data.
+
+```sh
+$ python api_profiler.py collect -p simpleperf.demo.cpp_api
+```
+
+5. Report profiling data.
+
+```sh
+$ python report_html.py -i simpleperf_data/* --aggregate-by-thread-name
+```
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/build.gradle b/test/testdata/SimpleperfExampleOfKotlin/app/build.gradle
new file mode 100644
index 0000000..132e64b
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/build.gradle
@@ -0,0 +1,37 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+apply from: 'profiling.gradle'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion '27.0.3'
+    defaultConfig {
+        applicationId "com.example.simpleperf.simpleperfexampleofkotlin"
+        minSdkVersion 15
+        targetSdkVersion 26
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+    implementation 'com.android.support:appcompat-v7:25.4.0'
+    testImplementation 'junit:junit:4.12'
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+}
diff --git a/testdata/SimpleperfExampleOfKotlin/app/build/outputs/apk/profiling/app-profiling.apk b/test/testdata/SimpleperfExampleOfKotlin/app/build/outputs/apk/profiling/app-profiling.apk
similarity index 100%
rename from testdata/SimpleperfExampleOfKotlin/app/build/outputs/apk/profiling/app-profiling.apk
rename to test/testdata/SimpleperfExampleOfKotlin/app/build/outputs/apk/profiling/app-profiling.apk
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling.gradle b/test/testdata/SimpleperfExampleOfKotlin/app/profiling.gradle
new file mode 100644
index 0000000..aa23c8d
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling.gradle
@@ -0,0 +1,58 @@
+
+// Set when building only part of the abis in the apk.
+def abiFiltersForWrapScript = []
+
+android {
+    buildTypes {
+        profiling {
+            initWith debug
+            externalNativeBuild {
+                cmake {
+                    // cmake Debug build type uses -O0, which makes the code slow.
+                    arguments "-DCMAKE_BUILD_TYPE=Release"
+                }
+            }
+            packagingOptions {
+
+                // Exclude wrap.sh for architectures not built.
+                if (abiFiltersForWrapScript) {
+                    def exclude_abis = ["armeabi", "armeabi-v7a", "arm64-v8a",
+                                        "x86", "x86_64", "mips", "mips64"]
+                            .findAll{ !(it in abiFiltersForWrapScript) }
+                            .collect{ "**/" + it + "/wrap.sh" }
+                    excludes += exclude_abis
+                }
+            }
+
+            // Add lib/xxx/wrap.sh in the apk. This is to enable java profiling on Android O
+            // devices.
+            sourceSets {
+                profiling {
+                    resources {
+                        srcDir {
+                            "profiling_apk_add_dir"
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+def writeWrapScriptToFullyCompileJavaApp(wrapFile) {
+    wrapFile.withWriter { writer ->
+        writer.write('#!/system/bin/sh\n')
+        writer.write('\$@\n')
+    }
+}
+
+task createProfilingApkAddDir {
+    for (String abi : ["armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"]) {
+        def dir = new File("app/profiling_apk_add_dir/lib/" + abi)
+        dir.mkdirs()
+        def wrapFile = new File(dir, "wrap.sh")
+        writeWrapScriptToFullyCompileJavaApp(wrapFile)
+        println "write file " + wrapFile.path
+    }
+}
+
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/armeabi/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/mips/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/mips/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/mips/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/mips64/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/mips64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/mips64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/x86/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/x86/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/x86/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/x86_64/wrap.sh b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/proguard-rules.pro b/test/testdata/SimpleperfExampleOfKotlin/app/proguard-rules.pro
new file mode 100644
index 0000000..bd13885
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/google/home/yabinc/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/testdata/SimpleperfExampleOfKotlin/app/src/androidTest/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleInstrumentedTest.kt b/test/testdata/SimpleperfExampleOfKotlin/app/src/androidTest/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleInstrumentedTest.kt
similarity index 100%
rename from testdata/SimpleperfExampleOfKotlin/app/src/androidTest/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleInstrumentedTest.kt
rename to test/testdata/SimpleperfExampleOfKotlin/app/src/androidTest/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleInstrumentedTest.kt
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/AndroidManifest.xml b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8cb4074
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="com.example.simpleperf.simpleperfexampleofkotlin">
+
+    <application android:allowBackup="true"
+         android:icon="@mipmap/ic_launcher"
+         android:label="@string/app_name"
+         android:roundIcon="@mipmap/ic_launcher_round"
+         android:supportsRtl="true"
+         android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".SleepActivity"
+             android:exported="true">
+
+        </activity>
+    </application>
+
+</manifest>
diff --git a/testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/MainActivity.kt b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/MainActivity.kt
similarity index 100%
rename from testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/MainActivity.kt
rename to test/testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/MainActivity.kt
diff --git a/testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/SleepActivity.kt b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/SleepActivity.kt
similarity index 100%
rename from testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/SleepActivity.kt
rename to test/testdata/SimpleperfExampleOfKotlin/app/src/main/java/com/example/simpleperf/simpleperfexampleofkotlin/SleepActivity.kt
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/layout/activity_main.xml b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..4c7edcf
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexampleofkotlin.MainActivity">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Hello World!"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/layout/activity_sleep.xml b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/layout/activity_sleep.xml
new file mode 100644
index 0000000..7043eb1
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/layout/activity_sleep.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity">
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5507303
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8fab6a3
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6bc7fcd
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1eecc0e
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..ec87dce
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..05ca079
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6f67f21
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8bac0f2
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..0327e13
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..bacd3e7
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/colors.xml b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/strings.xml b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..7972edf
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">SimpleperfExampleOfKotlin</string>
+</resources>
diff --git a/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/styles.xml b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/testdata/SimpleperfExampleOfKotlin/app/src/test/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleUnitTest.kt b/test/testdata/SimpleperfExampleOfKotlin/app/src/test/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleUnitTest.kt
similarity index 100%
rename from testdata/SimpleperfExampleOfKotlin/app/src/test/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleUnitTest.kt
rename to test/testdata/SimpleperfExampleOfKotlin/app/src/test/java/com/example/simpleperf/simpleperfexampleofkotlin/ExampleUnitTest.kt
diff --git a/test/testdata/SimpleperfExampleOfKotlin/build.gradle b/test/testdata/SimpleperfExampleOfKotlin/build.gradle
new file mode 100644
index 0000000..ba06bb9
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/build.gradle
@@ -0,0 +1,28 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    ext.kotlin_version = '1.1.2-4'
+    repositories {
+        google()
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.2.0-alpha09'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+        mavenCentral()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/test/testdata/SimpleperfExampleOfKotlin/gradle.properties b/test/testdata/SimpleperfExampleOfKotlin/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/test/testdata/SimpleperfExampleOfKotlin/gradle/wrapper/gradle-wrapper.jar b/test/testdata/SimpleperfExampleOfKotlin/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/test/testdata/SimpleperfExampleOfKotlin/gradle/wrapper/gradle-wrapper.properties b/test/testdata/SimpleperfExampleOfKotlin/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..be54b8d
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Apr 10 15:23:21 PDT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/test/testdata/SimpleperfExampleOfKotlin/gradlew b/test/testdata/SimpleperfExampleOfKotlin/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/test/testdata/SimpleperfExampleOfKotlin/gradlew.bat b/test/testdata/SimpleperfExampleOfKotlin/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/test/testdata/SimpleperfExampleOfKotlin/settings.gradle b/test/testdata/SimpleperfExampleOfKotlin/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/test/testdata/SimpleperfExampleOfKotlin/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/test/testdata/SimpleperfExamplePureJava/app/build.gradle b/test/testdata/SimpleperfExamplePureJava/app/build.gradle
new file mode 100644
index 0000000..0dcc199
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+
+apply from: 'profiling.gradle'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion '27.0.3'
+    defaultConfig {
+        applicationId "com.example.simpleperf.simpleperfexamplepurejava"
+        minSdkVersion 15
+        targetSdkVersion 25
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    implementation 'com.android.support:appcompat-v7:25.3.1'
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+    testImplementation 'junit:junit:4.12'
+}
diff --git a/testdata/SimpleperfExamplePureJava/app/build/outputs/apk/profiling/app-profiling.apk b/test/testdata/SimpleperfExamplePureJava/app/build/outputs/apk/profiling/app-profiling.apk
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/build/outputs/apk/profiling/app-profiling.apk
rename to test/testdata/SimpleperfExamplePureJava/app/build/outputs/apk/profiling/app-profiling.apk
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling.gradle b/test/testdata/SimpleperfExamplePureJava/app/profiling.gradle
new file mode 100644
index 0000000..aa23c8d
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling.gradle
@@ -0,0 +1,58 @@
+
+// Set when building only part of the abis in the apk.
+def abiFiltersForWrapScript = []
+
+android {
+    buildTypes {
+        profiling {
+            initWith debug
+            externalNativeBuild {
+                cmake {
+                    // cmake Debug build type uses -O0, which makes the code slow.
+                    arguments "-DCMAKE_BUILD_TYPE=Release"
+                }
+            }
+            packagingOptions {
+
+                // Exclude wrap.sh for architectures not built.
+                if (abiFiltersForWrapScript) {
+                    def exclude_abis = ["armeabi", "armeabi-v7a", "arm64-v8a",
+                                        "x86", "x86_64", "mips", "mips64"]
+                            .findAll{ !(it in abiFiltersForWrapScript) }
+                            .collect{ "**/" + it + "/wrap.sh" }
+                    excludes += exclude_abis
+                }
+            }
+
+            // Add lib/xxx/wrap.sh in the apk. This is to enable java profiling on Android O
+            // devices.
+            sourceSets {
+                profiling {
+                    resources {
+                        srcDir {
+                            "profiling_apk_add_dir"
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+def writeWrapScriptToFullyCompileJavaApp(wrapFile) {
+    wrapFile.withWriter { writer ->
+        writer.write('#!/system/bin/sh\n')
+        writer.write('\$@\n')
+    }
+}
+
+task createProfilingApkAddDir {
+    for (String abi : ["armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"]) {
+        def dir = new File("app/profiling_apk_add_dir/lib/" + abi)
+        dir.mkdirs()
+        def wrapFile = new File(dir, "wrap.sh")
+        writeWrapScriptToFullyCompileJavaApp(wrapFile)
+        println "write file " + wrapFile.path
+    }
+}
+
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips64/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86_64/wrap.sh b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExamplePureJava/app/proguard-rules.pro b/test/testdata/SimpleperfExamplePureJava/app/proguard-rules.pro
new file mode 100644
index 0000000..b9d149a
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/yabinc/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/testdata/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java b/test/testdata/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java
rename to test/testdata/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/AndroidManifest.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ee42fea
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="com.example.simpleperf.simpleperfexamplepurejava">
+
+    <application android:allowBackup="true"
+         android:icon="@mipmap/ic_launcher"
+         android:label="@string/app_name"
+         android:roundIcon="@mipmap/ic_launcher_round"
+         android:supportsRtl="true"
+         android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".SleepActivity"
+             android:exported="true"/>
+        <activity android:name=".MultiProcessActivity"
+             android:exported="true"/>
+
+        <service android:name=".MultiProcessService"
+             android:process=":multiprocess_service"/>
+    </application>
+
+</manifest>
diff --git a/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java b/test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java
rename to test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java
diff --git a/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessActivity.java b/test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessActivity.java
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessActivity.java
rename to test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessActivity.java
diff --git a/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessService.java b/test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessService.java
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessService.java
rename to test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MultiProcessService.java
diff --git a/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/SleepActivity.java b/test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/SleepActivity.java
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/SleepActivity.java
rename to test/testdata/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/SleepActivity.java
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_main.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..4a09b1a
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexamplepurejava.MainActivity">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="MainActivity"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_multi_process.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_multi_process.xml
new file mode 100644
index 0000000..f97b72e
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_multi_process.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexamplepurejava.MultiProcessActivity">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="MultiProcessActivity"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_sleep.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_sleep.xml
new file mode 100644
index 0000000..f732f77
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/layout/activity_sleep.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexamplepurejava.SleepActivity">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="SleepActivity"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/colors.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/strings.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9cb14df
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">SimpleperfExamplePureJava</string>
+</resources>
diff --git a/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/styles.xml b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/testdata/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java b/test/testdata/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java
similarity index 100%
rename from testdata/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java
rename to test/testdata/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java
diff --git a/test/testdata/SimpleperfExamplePureJava/build.gradle b/test/testdata/SimpleperfExamplePureJava/build.gradle
new file mode 100644
index 0000000..5af83b4
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        jcenter()
+        google()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.2.0-alpha09'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/test/testdata/SimpleperfExamplePureJava/gradle.properties b/test/testdata/SimpleperfExamplePureJava/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/test/testdata/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.jar b/test/testdata/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/test/testdata/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.properties b/test/testdata/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..275de5d
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Apr 10 14:48:08 PDT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/test/testdata/SimpleperfExamplePureJava/gradlew b/test/testdata/SimpleperfExamplePureJava/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/test/testdata/SimpleperfExamplePureJava/gradlew.bat b/test/testdata/SimpleperfExamplePureJava/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/test/testdata/SimpleperfExamplePureJava/settings.gradle b/test/testdata/SimpleperfExamplePureJava/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/test/testdata/SimpleperfExamplePureJava/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/test/testdata/SimpleperfExampleWithNative/app/CMakeLists.txt b/test/testdata/SimpleperfExampleWithNative/app/CMakeLists.txt
new file mode 100644
index 0000000..f8e6e8b
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/CMakeLists.txt
@@ -0,0 +1,44 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.4.1)
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+add_library( # Sets the name of the library.
+             native-lib
+
+             # Sets the library as a shared library.
+             SHARED
+
+             # Provides a relative path to your source file(s).
+             src/main/cpp/native-lib.cpp )
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+find_library( # Sets the name of the path variable.
+              log-lib
+
+              # Specifies the name of the NDK library that
+              # you want CMake to locate.
+              log )
+
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+target_link_libraries( # Specifies the target library.
+                       native-lib
+
+                       # Links the target library to the log library
+                       # included in the NDK.
+                       ${log-lib} )
\ No newline at end of file
diff --git a/test/testdata/SimpleperfExampleWithNative/app/build.gradle b/test/testdata/SimpleperfExampleWithNative/app/build.gradle
new file mode 100644
index 0000000..4636e64
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/build.gradle
@@ -0,0 +1,43 @@
+apply plugin: 'com.android.application'
+
+apply from: 'profiling.gradle'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion '26.0.2'
+    defaultConfig {
+        applicationId "com.example.simpleperf.simpleperfexamplewithnative"
+        minSdkVersion 15
+        targetSdkVersion 25
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        externalNativeBuild {
+            cmake {
+                cppFlags "-std=c++11"
+            }
+        }
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "CMakeLists.txt"
+        }
+    }
+}
+
+dependencies {
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    implementation 'com.android.support:appcompat-v7:25.3.1'
+    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+    testImplementation 'junit:junit:4.12'
+}
diff --git a/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/arm64-v8a/libnative-lib.so b/test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/arm64-v8a/libnative-lib.so
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/arm64-v8a/libnative-lib.so
rename to test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/arm64-v8a/libnative-lib.so
Binary files differ
diff --git a/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/armeabi-v7a/libnative-lib.so b/test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/armeabi-v7a/libnative-lib.so
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/armeabi-v7a/libnative-lib.so
rename to test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/armeabi-v7a/libnative-lib.so
Binary files differ
diff --git a/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86/libnative-lib.so b/test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86/libnative-lib.so
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86/libnative-lib.so
rename to test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86/libnative-lib.so
Binary files differ
diff --git a/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86_64/libnative-lib.so b/test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86_64/libnative-lib.so
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86_64/libnative-lib.so
rename to test/testdata/SimpleperfExampleWithNative/app/build/intermediates/cmake/profiling/obj/x86_64/libnative-lib.so
Binary files differ
diff --git a/testdata/SimpleperfExampleWithNative/app/build/outputs/apk/profiling/app-profiling.apk b/test/testdata/SimpleperfExampleWithNative/app/build/outputs/apk/profiling/app-profiling.apk
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/build/outputs/apk/profiling/app-profiling.apk
rename to test/testdata/SimpleperfExampleWithNative/app/build/outputs/apk/profiling/app-profiling.apk
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling.gradle b/test/testdata/SimpleperfExampleWithNative/app/profiling.gradle
new file mode 100644
index 0000000..f4c05d1
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling.gradle
@@ -0,0 +1,57 @@
+
+// Set when building only part of the abis in the apk.
+def abiFiltersForWrapScript = []
+
+android {
+    buildTypes {
+        profiling {
+            initWith debug
+            externalNativeBuild {
+                cmake {
+                    // cmake Debug build type uses -O0, which makes the code slow.
+                    arguments "-DCMAKE_BUILD_TYPE=Release"
+                }
+            }
+            packagingOptions {
+                // Exclude wrap.sh for architectures not built.
+                if (abiFiltersForWrapScript) {
+                    def exclude_abis = ["armeabi", "armeabi-v7a", "arm64-v8a",
+                                        "x86", "x86_64", "mips", "mips64"]
+                            .findAll{ !(it in abiFiltersForWrapScript) }
+                            .collect{ "**/" + it + "/wrap.sh" }
+                    excludes += exclude_abis
+                }
+            }
+
+            // Add lib/xxx/wrap.sh in the apk. This is to enable java profiling on Android O
+            // devices.
+            sourceSets {
+                profiling {
+                    resources {
+                        srcDir {
+                            "profiling_apk_add_dir"
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+def writeWrapScriptToFullyCompileJavaApp(wrapFile) {
+    wrapFile.withWriter { writer ->
+        writer.write('#!/system/bin/sh\n')
+        writer.write('\$@\n')
+    }
+}
+
+task createProfilingApkAddDir {
+    for (String abi : ["armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"]) {
+        def dir = new File("app/profiling_apk_add_dir/lib/" + abi)
+        dir.mkdirs()
+        def wrapFile = new File(dir, "wrap.sh")
+        writeWrapScriptToFullyCompileJavaApp(wrapFile)
+        println "write file " + wrapFile.path
+    }
+}
+
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips64/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86_64/wrap.sh b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/test/testdata/SimpleperfExampleWithNative/app/proguard-rules.pro b/test/testdata/SimpleperfExampleWithNative/app/proguard-rules.pro
new file mode 100644
index 0000000..b9d149a
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/yabinc/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/testdata/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java b/test/testdata/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java
rename to test/testdata/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/AndroidManifest.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..de96467
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="com.example.simpleperf.simpleperfexamplewithnative">
+
+    <application android:allowBackup="true"
+         android:icon="@mipmap/ic_launcher"
+         android:label="@string/app_name"
+         android:roundIcon="@mipmap/ic_launcher_round"
+         android:supportsRtl="true"
+         android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".SleepActivity"
+             android:exported="true"/>
+        <activity android:name=".MixActivity"
+             android:exported="true">
+
+        </activity>
+    </application>
+
+</manifest>
diff --git a/testdata/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp b/test/testdata/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp
rename to test/testdata/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp
diff --git a/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java b/test/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java
rename to test/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java
diff --git a/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MixActivity.java b/test/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MixActivity.java
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MixActivity.java
rename to test/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MixActivity.java
diff --git a/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/SleepActivity.java b/test/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/SleepActivity.java
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/SleepActivity.java
rename to test/testdata/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/SleepActivity.java
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_main.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..9b06408
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexamplewithnative.MainActivity">
+
+    <TextView
+        android:id="@+id/sample_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Hello World!"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_mix.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_mix.xml
new file mode 100644
index 0000000..467dd77
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_mix.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexamplewithnative.MixActivity">
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_sleep.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_sleep.xml
new file mode 100644
index 0000000..8eeab2e
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/layout/activity_sleep.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.simpleperf.simpleperfexamplewithnative.SleepActivity">
+
+</android.support.constraint.ConstraintLayout>
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/colors.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/strings.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..1ac079d
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">SimpleperfExampleWithNative</string>
+</resources>
diff --git a/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/styles.xml b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>
diff --git a/testdata/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java b/test/testdata/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java
similarity index 100%
rename from testdata/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java
rename to test/testdata/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java
diff --git a/test/testdata/SimpleperfExampleWithNative/build.gradle b/test/testdata/SimpleperfExampleWithNative/build.gradle
new file mode 100644
index 0000000..82a28ae
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        jcenter()
+        maven { url 'https://maven.google.com' }
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:3.0.0'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/test/testdata/SimpleperfExampleWithNative/gradle.properties b/test/testdata/SimpleperfExampleWithNative/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/test/testdata/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.jar b/test/testdata/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/test/testdata/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.properties b/test/testdata/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..03bf1f6
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Oct 27 17:46:02 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/test/testdata/SimpleperfExampleWithNative/gradlew b/test/testdata/SimpleperfExampleWithNative/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/test/testdata/SimpleperfExampleWithNative/gradlew.bat b/test/testdata/SimpleperfExampleWithNative/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/test/testdata/SimpleperfExampleWithNative/settings.gradle b/test/testdata/SimpleperfExampleWithNative/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/test/testdata/SimpleperfExampleWithNative/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/testdata/aggregatable_perf1.data b/test/testdata/aggregatable_perf1.data
similarity index 100%
rename from testdata/aggregatable_perf1.data
rename to test/testdata/aggregatable_perf1.data
Binary files differ
diff --git a/testdata/aggregatable_perf2.data b/test/testdata/aggregatable_perf2.data
similarity index 100%
rename from testdata/aggregatable_perf2.data
rename to test/testdata/aggregatable_perf2.data
Binary files differ
diff --git a/test/testdata/base.vdex b/test/testdata/base.vdex
new file mode 100644
index 0000000..b0ea018
--- /dev/null
+++ b/test/testdata/base.vdex
Binary files differ
diff --git a/testdata/cpp_api-debug_Q.apk b/test/testdata/cpp_api-debug_Q.apk
similarity index 100%
rename from testdata/cpp_api-debug_Q.apk
rename to test/testdata/cpp_api-debug_Q.apk
Binary files differ
diff --git a/testdata/cpp_api-debug_prev_Q.apk b/test/testdata/cpp_api-debug_prev_Q.apk
similarity index 100%
rename from testdata/cpp_api-debug_prev_Q.apk
rename to test/testdata/cpp_api-debug_prev_Q.apk
Binary files differ
diff --git a/testdata/cpp_api-profile_Q.apk b/test/testdata/cpp_api-profile_Q.apk
similarity index 100%
rename from testdata/cpp_api-profile_Q.apk
rename to test/testdata/cpp_api-profile_Q.apk
Binary files differ
diff --git a/testdata/cpp_api-profile_prev_Q.apk b/test/testdata/cpp_api-profile_prev_Q.apk
similarity index 100%
rename from testdata/cpp_api-profile_prev_Q.apk
rename to test/testdata/cpp_api-profile_prev_Q.apk
Binary files differ
diff --git a/test/testdata/cpp_api.apk b/test/testdata/cpp_api.apk
new file mode 100644
index 0000000..fddbc26
--- /dev/null
+++ b/test/testdata/cpp_api.apk
Binary files differ
diff --git a/test/testdata/data/app/com.example.hellojni-1/base.apk b/test/testdata/data/app/com.example.hellojni-1/base.apk
new file mode 100644
index 0000000..95ea93a
--- /dev/null
+++ b/test/testdata/data/app/com.example.hellojni-1/base.apk
Binary files differ
diff --git a/test/testdata/data/app/simpleperf.demo.cpp_api/base.apk b/test/testdata/data/app/simpleperf.demo.cpp_api/base.apk
new file mode 100644
index 0000000..0b2d530
--- /dev/null
+++ b/test/testdata/data/app/simpleperf.demo.cpp_api/base.apk
Binary files differ
diff --git a/test/testdata/data/correct_symfs_for_build_id_check/elf_for_build_id_check b/test/testdata/data/correct_symfs_for_build_id_check/elf_for_build_id_check
new file mode 100644
index 0000000..5c1a9dd
--- /dev/null
+++ b/test/testdata/data/correct_symfs_for_build_id_check/elf_for_build_id_check
Binary files differ
diff --git a/test/testdata/data/symfs_for_no_symbol_table_warning/elf b/test/testdata/data/symfs_for_no_symbol_table_warning/elf
new file mode 100644
index 0000000..a92e41f
--- /dev/null
+++ b/test/testdata/data/symfs_for_no_symbol_table_warning/elf
Binary files differ
diff --git a/test/testdata/data/symfs_for_read_elf_file_warning/elf b/test/testdata/data/symfs_for_read_elf_file_warning/elf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/testdata/data/symfs_for_read_elf_file_warning/elf
diff --git a/test/testdata/data/symfs_with_build_id_list/build_id_list b/test/testdata/data/symfs_with_build_id_list/build_id_list
new file mode 100644
index 0000000..9b80e91
--- /dev/null
+++ b/test/testdata/data/symfs_with_build_id_list/build_id_list
@@ -0,0 +1 @@
+0x91b1c10fdd9fe2221dfec525497637f2229bfdbb=elf_for_build_id_check
diff --git a/test/testdata/data/symfs_with_build_id_list/elf_for_build_id_check b/test/testdata/data/symfs_with_build_id_list/elf_for_build_id_check
new file mode 100644
index 0000000..5c1a9dd
--- /dev/null
+++ b/test/testdata/data/symfs_with_build_id_list/elf_for_build_id_check
Binary files differ
diff --git a/test/testdata/data/symfs_with_wrong_build_id_list/build_id_list b/test/testdata/data/symfs_with_wrong_build_id_list/build_id_list
new file mode 100644
index 0000000..4487061
--- /dev/null
+++ b/test/testdata/data/symfs_with_wrong_build_id_list/build_id_list
@@ -0,0 +1 @@
+0x91b1c10fdd9fe2221dfec525497637f2229bfdbb=elf_for_build_id_list
diff --git a/test/testdata/data/symfs_without_build_id/elf b/test/testdata/data/symfs_without_build_id/elf
new file mode 100644
index 0000000..590c736
--- /dev/null
+++ b/test/testdata/data/symfs_without_build_id/elf
Binary files differ
diff --git a/test/testdata/data/t2 b/test/testdata/data/t2
new file mode 100644
index 0000000..bc7a505
--- /dev/null
+++ b/test/testdata/data/t2
Binary files differ
diff --git a/test/testdata/data/wrong_symfs_for_build_id_check/elf_for_build_id_check b/test/testdata/data/wrong_symfs_for_build_id_check/elf_for_build_id_check
new file mode 100644
index 0000000..0489a22
--- /dev/null
+++ b/test/testdata/data/wrong_symfs_for_build_id_check/elf_for_build_id_check
Binary files differ
diff --git a/test/testdata/debug_unwind_report.txt b/test/testdata/debug_unwind_report.txt
new file mode 100644
index 0000000..b5f36ce
--- /dev/null
+++ b/test/testdata/debug_unwind_report.txt
@@ -0,0 +1,760 @@
+sample_time: 626968109563718
+unwinding_used_time: 2.292 us
+unwinding_error_code: 1
+unwinding_error_addr: 0x71bf509e50
+stack_start: 0x71bf401ca0
+stack_end: 0x71bf402fd0
+ip_1: 0x746ac93ecc
+map_1: [0x746ac86000-0x746ad04000], pgoff 0x3c000
+dso_1: /apex/com.android.runtime/lib64/bionic/libc.so
+vaddr_in_file_1: 0x49ecc
+symbol_1: __bionic_clone
+ip_2: 0x746ac99894
+map_2: [0x746ac86000-0x746ad04000], pgoff 0x3c000
+dso_2: /apex/com.android.runtime/lib64/bionic/libc.so
+vaddr_in_file_2: 0x4f894
+symbol_2: clone
+reg_r0: 0x0
+reg_r1: 0x71bf401ca0
+reg_r2: 0x71bf401cc0
+reg_r3: 0x71bf402000
+reg_r4: 0x71bf401cc0
+reg_r5: 0x746acf955c
+reg_r6: 0x71bf401cb0
+reg_r7: 0xacd979ce
+reg_r8: 0xdc
+reg_r9: 0x71bf401cb0
+reg_r10: 0x71bf401cb0
+reg_r11: 0x746acf955c
+reg_r12: 0x4100
+reg_r13: 0x0
+reg_r14: 0x71d3878780
+reg_r15: 0x0
+reg_r16: 0x746ad07e30
+reg_r17: 0x746ac996ec
+reg_r18: 0x7158d8e000
+reg_r19: 0x71bf50bfb0
+reg_r20: 0x71bf50c000
+reg_r21: 0x71bf50bcb0
+reg_r22: 0x380d
+reg_r23: 0x3427
+reg_r24: 0x71bf401cb0
+reg_r25: 0x71bf401cb0
+reg_r26: 0x71bf401ff8
+reg_r27: 0x108000
+reg_r28: 0x71bf2fd000
+reg_r29: 0x71bf509e50
+reg_lr: 0x746ac99898
+reg_sp: 0x71bf401ca0
+reg_pc: 0x746ac93ecc
+stack_71bf401ca0: 000000746acf955c 00000071bf401cb0 00000071bf50bcb0 0000000000000000
+stack_71bf401cc0: 0000380d00003428 0000000000000001 00000071bf2fc000 0000000000105cb0
+stack_71bf401ce0: 0000000000001000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401d00: 0000000000000003 0000000000000000 00000071d38af76c 0000007346370dc0
+stack_71bf401d20: 0000000000000000 0000000080001204 0000000000000000 0000000000000000
+stack_71bf401d40: 00000071bf401cb0 0000000000000000 0000000000000000 00000071bf2fc000
+stack_71bf401d60: 000000000010a000 00000071bf2fd000 0000000000108000 0000000000000000
+stack_71bf401d80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401da0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401dc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401de0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401ea0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401ec0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401ee0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401fa0: 0000000000000000 00000071bf402040 0000000000000000 0000000000000000
+stack_71bf401fc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401fe0: 0000000000000000 0000000000000000 0000000000000000 00000071bf402040
+stack_71bf402000: 000000746ac6d188 00000071bf401cb0 0000000000000000 0000000000000000
+stack_71bf402020: 0000000000000000 d31f8b8761d5c565 0000000000000000 0000000000000000
+stack_71bf402040: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402060: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402080: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4020a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4020c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4020e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402100: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402120: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402140: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402160: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402180: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4021a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4021c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4021e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402200: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402220: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402240: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402260: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402280: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4022a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4022c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4022e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402300: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402320: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402340: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402360: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402380: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4023a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4023c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4023e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402400: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402420: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402440: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402460: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402480: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4024a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4024c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4024e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402500: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402520: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402540: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402560: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402580: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4025a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4025c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4025e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402600: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402620: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402640: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402660: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402680: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4026a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4026c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4026e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402700: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402720: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402740: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402760: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402780: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4027a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4027c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4027e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402800: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402820: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402840: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402860: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402880: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4028a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4028c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4028e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402900: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402920: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402940: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402960: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402980: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4029a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4029c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4029e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402aa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ac0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ae0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ba0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402bc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402be0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ca0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402cc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ce0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402da0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402dc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402de0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ea0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ec0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ee0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402fa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402fc0: 0000000000000000 0000000000000000
+
+sample_time: 626970513562864
+unwinding_used_time: 12.448 us
+unwinding_error_code: 4
+unwinding_error_addr: 0x0
+stack_start: 0x71bf400680
+stack_end: 0x71bf402fd0
+ip_1: 0x71d38c4250
+map_1: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_1: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_1: 0x2b1250
+symbol_1: artQuickToInterpreterBridge
+ip_2: 0x71d3881f68
+map_2: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_2: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_2: 0x26ef68
+symbol_2: art_quick_to_interpreter_bridge
+ip_3: 0x71d376e348
+map_3: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_3: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_3: 0x15b348
+symbol_3: NterpCommonInvokeInstance
+ip_4: 0x715b9550fc
+map_4: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_4: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_4: 0x45b0fc
+symbol_4: com.google.android.gms.measurement.internal.zzer.getWritableDatabase
+ip_5: 0x71d376dd64
+map_5: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_5: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_5: 0x15ad64
+symbol_5: NterpCommonInvokeInstance
+ip_6: 0x715b952da8
+map_6: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_6: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_6: 0x458da8
+symbol_6: com.google.android.gms.measurement.internal.zzeo.zzae
+ip_7: 0x71d376e390
+map_7: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_7: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_7: 0x15b390
+symbol_7: NterpCommonInvokeInstanceRange
+ip_8: 0x715b952eee
+map_8: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_8: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_8: 0x458eee
+symbol_8: com.google.android.gms.measurement.internal.zzeo.zza
+ip_9: 0x71d376dd64
+map_9: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_9: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_9: 0x15ad64
+symbol_9: NterpCommonInvokeInstance
+ip_10: 0x715b952dda
+map_10: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_10: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_10: 0x458dda
+symbol_10: com.google.android.gms.measurement.internal.zzeo.zza
+ip_11: 0x71d376dd64
+map_11: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_11: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_11: 0x15ad64
+symbol_11: NterpCommonInvokeInstance
+ip_12: 0x715b964204
+map_12: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_12: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_12: 0x46a204
+symbol_12: com.google.android.gms.measurement.internal.zzil.zza
+ip_13: 0x9beff0f0
+map_13: [0x9befb5c0-0x9beffacc], pgoff 0x35a48
+dso_13: perf.data_jit_app_cache:219720-223168
+vaddr_in_file_13: 0x9beff0f0
+symbol_13: com.google.android.gms.measurement.internal.zzhb.zza
+ip_14: 0x71d3878564
+map_14: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_14: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_14: 0x265564
+symbol_14: art_quick_invoke_stub
+ip_15: 0x71d38abca0
+map_15: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_15: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_15: 0x298ca0
+symbol_15: art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)
+ip_16: 0x71d3a18634
+map_16: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_16: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_16: 0x405634
+symbol_16: bool art::interpreter::DoCall<true, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)
+ip_17: 0x71d3c6a13c
+map_17: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_17: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_17: 0x65713c
+symbol_17: MterpInvokeVirtualRange
+ip_18: 0x71d3903194
+map_18: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_18: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_18: 0x2f0194
+symbol_18: mterp_op_invoke_virtual_range
+ip_19: 0x715b960a08
+map_19: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_19: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_19: 0x466a08
+symbol_19: com.google.android.gms.measurement.internal.zzhe.run
+ip_20: 0x71d38c5038
+map_20: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_20: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_20: 0x2b2038
+symbol_20: art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.4927020788110626733)
+ip_21: 0x71d38ac1f8
+map_21: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_21: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_21: 0x2991f8
+symbol_21: art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)
+ip_22: 0x71d38ab9d0
+map_22: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_22: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_22: 0x2989d0
+symbol_22: bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)
+ip_23: 0x71d3c6da90
+map_23: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_23: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_23: 0x65aa90
+symbol_23: MterpInvokeInterface
+ip_24: 0x71d3903094
+map_24: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_24: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_24: 0x2f0094
+symbol_24: mterp_op_invoke_interface
+ip_25: 0x71d3335db8
+map_25: [0x71d313a000-0x71d3613000], pgoff 0x0
+dso_25: /apex/com.android.art/javalib/core-oj.jar
+vaddr_in_file_25: 0x1fbdb8
+symbol_25: java.util.concurrent.Executors$RunnableAdapter.call
+ip_26: 0x71d38c5038
+map_26: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_26: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_26: 0x2b2038
+symbol_26: art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.4927020788110626733)
+ip_27: 0x71d38c4654
+map_27: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_27: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_27: 0x2b1654
+symbol_27: artQuickToInterpreterBridge
+ip_28: 0x71d3881f68
+map_28: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_28: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_28: 0x26ef68
+symbol_28: art_quick_to_interpreter_bridge
+ip_29: 0x9bfe981c
+map_29: [0x9bfe9700-0x9bfe9a74], pgoff 0x10b38
+dso_29: perf.data_jit_app_cache:68408-84336
+vaddr_in_file_29: 0x9bfe981c
+symbol_29: java.util.concurrent.FutureTask.run
+ip_30: 0x71d376e348
+map_30: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_30: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_30: 0x15b348
+symbol_30: NterpCommonInvokeInstance
+ip_31: 0x715b95bdd0
+map_31: [0x715b4fa000-0x715cd03000], pgoff 0x0
+dso_31: /data/app/~~d9GU08QC_9TZAfKCecJBXg==/com.google.samples.apps.iosched-dJv39H5oeU5_UxPPstEYAw==/oat/arm64/base.vdex
+vaddr_in_file_31: 0x461dd0
+symbol_31: com.google.android.gms.measurement.internal.zzfx.run
+ip_32: 0x71d3878564
+map_32: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_32: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_32: 0x265564
+symbol_32: art_quick_invoke_stub
+ip_33: 0x71d386776c
+map_33: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_33: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_33: 0x25476c
+symbol_33: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
+ip_34: 0x71d38b0e18
+map_34: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_34: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_34: 0x29de18
+symbol_34: art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)
+ip_35: 0x71d38afb4c
+map_35: [0x71d3764000-0x71d3cc0000], pgoff 0x151000
+dso_35: /apex/com.android.art/lib64/libart.so
+vaddr_in_file_35: 0x29cb4c
+symbol_35: art::Thread::CreateCallback(void*)
+ip_36: 0x746acf959c
+map_36: [0x746ac86000-0x746ad04000], pgoff 0x3c000
+dso_36: /apex/com.android.runtime/lib64/bionic/libc.so
+vaddr_in_file_36: 0xaf59c
+symbol_36: __pthread_start(void*)
+ip_37: 0x746ac996e4
+map_37: [0x746ac86000-0x746ad04000], pgoff 0x3c000
+dso_37: /apex/com.android.runtime/lib64/bionic/libc.so
+vaddr_in_file_37: 0x4f6e4
+symbol_37: __start_thread
+reg_r0: 0x71ab69f960
+reg_r1: 0x7346370dc0
+reg_r2: 0x71bf4006e0
+reg_r3: 0x9be86f90
+reg_r4: 0x705afabc
+reg_r5: 0x11c7
+reg_r6: 0x1445fbd0
+reg_r7: 0x10
+reg_r8: 0x715bb131c2
+reg_r9: 0x715bb131c5
+reg_r10: 0x0
+reg_r11: 0x0
+reg_r12: 0x71d3878454
+reg_r13: 0x71d387849c
+reg_r14: 0x71bf4007e0
+reg_r15: 0x1
+reg_r16: 0x71bf4006e0
+reg_r17: 0x46e
+reg_r18: 0x7157bd6000
+reg_r19: 0x7346370dc0
+reg_r20: 0x0
+reg_r21: 0x4
+reg_r22: 0x715b951f68
+reg_r23: 0x715bb131c3
+reg_r24: 0x71d3764780
+reg_r25: 0x71bf4007f8
+reg_r26: 0x10080011
+reg_r27: 0x11209
+reg_r28: 0x71bf400810
+reg_r29: 0x71bf400800
+reg_lr: 0x71d3881f6c
+reg_sp: 0x71bf400680
+reg_pc: 0x71d38c4250
+stack_71bf400680: 00000071bf400800 00000071d3881f6c 00000071bf400810 0000000000011209
+stack_71bf4006a0: 0000000010080011 00000071bf4007f8 00000071d3764780 000000715bb131c3
+stack_71bf4006c0: 000000715b951fbc 0000000000000004 0000000000000000 0000007346370dc0
+stack_71bf4006e0: 0000000070124080 13f1512013f15158 0000000000000000 507465670f00656d
+stack_71bf400700: 7465670d0073656d 000000000000001c fffffffffffffff4 4010040140100401
+stack_71bf400720: 1004010101004000 0000000000000000 0000000013f22900 00000071d3764090
+stack_71bf400740: 000000009be86f90 00000000705afabc 00000000000011c7 000000001445fbd0
+stack_71bf400760: 0000000000000010 0000000000000000 0000000000000004 000000715b951f68
+stack_71bf400780: 000000715bb131c3 00000071d3764780 00000071bf4007f8 0000000010080011
+stack_71bf4007a0: 0000000000011209 00000071bf400810 00000071bf400800 000000009be86fdc
+stack_71bf4007c0: 00000071b186f410 00000071bf400810 0000000000000004 00000071d376d6ac
+stack_71bf4007e0: 00000071b1602740 000000715b951f68 00000071bf400810 13f2290000000000
+stack_71bf400800: 13f2290070015758 000000009be955a8 0000000000000000 0000000000000000
+stack_71bf400820: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf400840: 0000000000000000 0000000000000000 0000007346370dc0 0000000000000000
+stack_71bf400860: 0000000013f1f680 000000001301c310 000000001445fa10 0000000013f1fb80
+stack_71bf400880: 0000000013f22900 0000000013080ea0 0000000000011209 0000000012f6d8e0
+stack_71bf4008a0: 0000000000006591 000000009bef4238 00000071b1870350 00000071d376dd68
+stack_71bf4008c0: 1445fa101301c310 6ff0a02013f1fb80 13f1ae8813f1ae88 00000071bf4008f0
+stack_71bf4008e0: 000000001308a6a0 0000000000000000 0000000013f1f680 0000000012f56508
+stack_71bf400900: 0000000012fd2bc8 000000009be98c44 00000071b185da40 0000000013f1f680
+stack_71bf400920: 0000000000000000 0000000000000000 000000001308a6a0 0000000013f1f680
+stack_71bf400940: 0000000000000000 0000000012f56508 0000000012fd2bc8 000000009bef93b4
+stack_71bf400960: 00000071b185d920 0000000013080ea0 0000000000011209 0000017788d41bdc
+stack_71bf400980: 000000001308a8f8 000000009bfd6c34 00000071b186c0f8 12f7507013edc0c0
+stack_71bf4009a0: 0000007100000000 00000071bf400a10 00000071bf4009f4 00000071d376dd68
+stack_71bf4009c0: 00000071b185f380 0000000000000000 000000715b955884 00000071bf400a10
+stack_71bf4009e0: 0000000000000000 0000000000000000 000000001308a738 00000071d3772c54
+stack_71bf400a00: 1308a738bf400af0 00000001bf400ad0 13febba800000000 1445c49000000000
+stack_71bf400a20: 0000000100000001 000000001308a6a0 13f1f68000000000 0000000000000000
+stack_71bf400a40: 0000000d00000000 0000000000000000 0000007346370dc0 0000000000000000
+stack_71bf400a60: 0000000000000020 000000715b963f52 000000715bb14219 00000071d3764780
+stack_71bf400a80: 00000071bf400ad0 00000071bf400adc 00000071bf400ad0 00000071bf400af0
+stack_71bf400aa0: 00000071bf400adc 00000071d376e34c 00000071b186d220 000000005b952e14
+stack_71bf400ac0: 000000715b963f52 00000071bf400af0 1308a8981308a8f8 1308a8f800000000
+stack_71bf400ae0: 000000001308a898 0000000012f5ace0 0000000000000000 0000000000000000
+stack_71bf400b00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf400b20: 0000000000000000 0000000000000000 0000007346370dc0 0000000000000000
+stack_71bf400b40: 0000000000000020 000000715b964204 0000000000002070 00000071d3764780
+stack_71bf400b60: 00000071bf400bc8 0000000010080014 0000000012f5ace0 00000071bf400c24
+stack_71bf400b80: 00000071bf400bf4 00000071d376dd68 00000071b186d460 0000000000000000
+stack_71bf400ba0: 0000000000000004 000000715b95e0a8 000000000000106f 000000715b964204
+stack_71bf400bc0: 00000071bf400c20 0000000000000000 0000000000000000 0000000000000000
+stack_71bf400be0: 0000000000000000 14459e201308a898 0000000100000000 0000000100000001
+stack_71bf400c00: 0000007100000001 00000071bf400c20 1308a8981308a898 0000000014459e20
+stack_71bf400c20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf400c40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf400c60: 0000007346370dc0 0000000000000000 0000000012f62bb0 000000001308a820
+stack_71bf400c80: 0000000000000000 0000000000000000 00000000144598f0 000000001308a898
+stack_71bf400ca0: 0000000012f5ace0 0000000014457d00 0000000000000001 000000009beff0f4
+stack_71bf400cc0: 00000071b1861f68 12f5caa814457d00 0000000000000000 d31f8b8761d5c565
+stack_71bf400ce0: 00000001bf400d80 12f626e814457b20 14459d3012f62bb0 14459e2014459d30
+stack_71bf400d00: 1445985814459e40 00000071144598f0 0f963fa4d38ff780 00000000ce8c50f3
+stack_71bf400d20: 0000007346370dc0 00000071bf400f10 000000715b964414 00000071bf400ed0
+stack_71bf400d40: 0000000000000036 00000071d3cd7000 00000071b1861f68 0000000000000000
+stack_71bf400d60: 0000007346370e70 00000071b1861f68 000000000000000a 00000071bf402000
+stack_71bf400d80: 00000071d3cd7000 0000000000000000 00000071bf400dd0 00000071d3878568
+stack_71bf400da0: 0000000000000000 70951ba81308a820 fa9ecaf712f62bb0 1334ae4800000177
+stack_71bf400dc0: 0000000100000001 0000000000000001 00000071bf401130 000000715bbd2673
+stack_71bf400de0: 00000071bf401130 0000007346370dc0 00000071bf400e60 00000071d38abca4
+stack_71bf400e00: 0000000000000001 00000071bf402000 0000000000000018 00000071d3cd7000
+stack_71bf400e20: 0000000000000000 00000071bf402000 0000000000000000 00000071bf401690
+stack_71bf400e40: 00000071bf401270 0000007346370dc0 00000071bf401102 d31f8b8761d5c565
+stack_71bf400e60: 00000071bf400fa0 00000071d3a18638 000000000000000a d31f8b8761d5c565
+stack_71bf400e80: 00000071bf401270 0000000000000000 00000071bf400ec0 0000007346370dc0
+stack_71bf400ea0: 0000000000000000 00000071bf401130 00000071bf402000 0000000000000001
+stack_71bf400ec0: 00000071bf401270 00000071b1861f68 0000000000000000 0000000000000000
+stack_71bf400ee0: 0000000000000000 0000000000000000 000000000000000a 0000000000000000
+stack_71bf400f00: 70951ba81308a820 fa9ecaf712f62bb0 1334ae4800000177 0000000100000001
+stack_71bf400f20: 0000000000000001 70951ba81308a820 0000000012f62bb0 1334ae4800000000
+stack_71bf400f40: 0000000000000000 0000000000000000 00000071bf400f30 0000000000000000
+stack_71bf400f60: 0000000146370dc0 0000007346370dc0 00000071bf401130 00000071bf402000
+stack_71bf400f80: 00000000000005cd 000000715b95ef18 00040007000a0026 d31f8b8761d5c565
+stack_71bf400fa0: 00000071bf401080 00000071d3c6a140 0000000000000000 00000071bf402000
+stack_71bf400fc0: 00000071d3cd7000 b4000072b62a34e0 000000715b960a08 00000071b1861f68
+stack_71bf400fe0: 00000071b1861f6c 00000071bf401270 0000007346370dc0 00000071bf402000
+stack_71bf401000: 0000007346370dc0 000000000000206e 0000000000000000 00000a74762a9bd0
+stack_71bf401020: 00000071bf401130 00000071d3c71e8c 00000071bf401150 00000071bf402000
+stack_71bf401040: 00000071d3cc0b60 00000071bf401010 00000071bf402000 d31f8b8761d5c565
+stack_71bf401060: 00000071bf4010b0 00000071d3c7e258 0000000000001115 d31f8b8761d5c565
+stack_71bf401080: 00000071bf401120 00000071d3903198 000000000000000b 00000071d3cd7000
+stack_71bf4010a0: 0000000000001115 00000071bf4012dc 00000071d38ff780 0000000000000a74
+stack_71bf4010c0: 0000007346370dc0 00000071bf4012b0 000000715b960a08 00000071bf401270
+stack_71bf4010e0: 00000000000002eb 00000071d3cd7000 000000714243f5c8 00000071bf402000
+stack_71bf401100: 000000714243f5c8 000000714243f5c8 0000007346370dc0 00000071bf401358
+stack_71bf401120: 00000071bf401190 00000071d38c503c 0000000000000000 d31f8b8761d5c565
+stack_71bf401140: 00000071bf4011c0 00000071d3822108 0000000000000bd0 b4000072762a9bd0
+stack_71bf401160: 0000000000000bd0 00000071d31905e8 b4000072762a9bd0 00000071bf402000
+stack_71bf401180: 0000000000000003 d31f8b8761d5c565 00000071bf401220 00000071d38ac1fc
+stack_71bf4011a0: 0000000000000001 b4000072762a9bd0 0000000000000058 00000071d3cd7000
+stack_71bf4011c0: 0000000000000000 00000071bf402000 00000071bf401358 00000071bf401270
+stack_71bf4011e0: 00000071bf401530 0000007346370dc0 0000000000000000 000000006feeda38
+stack_71bf401200: 000000006feea410 0000000000000bd0 0000000000000000 d31f8b8761d5c565
+stack_71bf401220: 00000071bf401390 00000071d38ab9d4 000000000000000a 0000000000010000
+stack_71bf401240: 00000071bf401270 000000714243f5c8 0000000000000000 00000071bf4015f0
+stack_71bf401260: 00000071bf401530 0000007346370dc0 00000071bf4015f0 000000714243f5c8
+stack_71bf401280: 00000071bf401130 000000715b960a08 000000715b9609e4 0000000000000000
+stack_71bf4012a0: 000000000000000b 0000000011151115 70951ba81308a820 fa9ecaf712f62bb0
+stack_71bf4012c0: 1334ae4800000177 0000000100000001 0000000000000001 1308a8201334af08
+stack_71bf4012e0: 12f62bb070951ba8 0000000000000000 000000001334ae48 0000000000000000
+stack_71bf401300: 1334af0800000000 00000071d38ab15c 000000000000028a 00000071d3cd8000
+stack_71bf401320: 00000071bf401374 00000000bf402000 00000071bf401310 00000071bf401530
+stack_71bf401340: 0000007346370dc0 00000071bf402000 0000000170052d90 0000000000000016
+stack_71bf401360: 000000715b9609e4 0000000a0001000b 0000000000000000 0000000000000000
+stack_71bf401380: 0000007300000000 d31f8b8761d5c565 00000071bf401480 00000071d3c6da94
+stack_71bf4013a0: 0000007346370dc0 000000001334af08 b4000072b62a34e0 000000714243f5c8
+stack_71bf4013c0: 0000000070052d90 00000071d3335db8 0000000013020618 00000071bf4015f0
+stack_71bf4013e0: 0000000000000008 000000714243f5cc 00000071d3cd8000 00000071bf401444
+stack_71bf401400: 00001072bf402000 0000007346370dc0 00000071bf401530 00000071bf402000
+stack_71bf401420: 0000000000000000 0000000000001c8c 000000020004000b 0000000000000000
+stack_71bf401440: 6feeda3800000002 0000000200000000 0000007346370dc0 d31f8b8761d5c565
+stack_71bf401460: 00000071bf4014b0 00000071d3c7e258 0000000000001175 d31f8b8761d5c565
+stack_71bf401480: 00000071bf401520 00000071d3903098 000000000000028a 00000071d3cd7000
+stack_71bf4014a0: 0000000000001175 00000071bf401638 00000071d38ff780 0000000000001072
+stack_71bf4014c0: 0000007346370dc0 00000071bf401630 00000071d3335db8 00000071bf4015f0
+stack_71bf4014e0: 000000000000028b 00000071d3cd7000 0000000070052d90 00000071bf402000
+stack_71bf401500: 0000000070052d90 0000000070052d90 0000007346370dc0 00000071bf401678
+stack_71bf401520: 00000071bf401590 00000071d38c503c 0000000000000000 000000001334af30
+stack_71bf401540: 00000071bf401750 00000071d38c4690 0000000000001ea0 00000071d3cd7000
+stack_71bf401560: 00000071bf401620 00000071d3825c58 0000000070075fe8 d31f8b8761d5c565
+stack_71bf401580: 000000006ff1f5c0 d31f8b8761d5c565 00000071bf401750 00000071d38c4658
+stack_71bf4015a0: 00000071d3cd7000 00000071d3cd7000 00000071d3cd7000 b4000072b62a34e0
+stack_71bf4015c0: 0000000070052d90 00000071bf401618 00000071bf4015f0 00000071bf4017b0
+stack_71bf4015e0: 0000000070052d90 0000007346370dc0 0000000000000000 0000000070052d90
+stack_71bf401600: 00000071bf401530 00000071d3335db8 00000071d3335db4 0000000000000000
+stack_71bf401620: 0000000000000002 0000000011751175 1334af601334af08 1334af601334af08
+stack_71bf401640: 1444a8501334af30 0000000013edbb10 13edbd9000000000 00000071bf402000
+stack_71bf401660: 00000071d34e18ef 000000715bc492b5 0000000000000000 0000000000000008
+stack_71bf401680: 00000071d3335db4 0000000100010002 00000071bf4017b0 00000071bf401a60
+stack_71bf4016a0: 0000000000000000 000000000000001f 00000071d3340e84 0000000500010007
+stack_71bf4016c0: 00000071bf4017e0 00000071bf401a60 00000071d3ccd120 0000000000000000
+stack_71bf4016e0: 00000071d34e18ef 0000000000000001 00000071bf401800 00000071bf4017c0
+stack_71bf401700: 00000071bf401898 0000000000000001 0000000100000000 0000000000000000
+stack_71bf401720: 00000071bf4015f0 0000000000000002 00000071bf4018c8 d31f8b8761d5c565
+stack_71bf401740: 0000000100000000 0000000000000000 00000071bf401930 00000071d3881f6c
+stack_71bf401760: 00000071bf401950 0000000000000000 0000000070075fe8 000000001334af30
+stack_71bf401780: 0000000000000000 000000001334af60 000000001334a270 0000000000000000
+stack_71bf4017a0: 0000000000000000 0000007346370dc0 0000000070124080 d31f8b8761d5c565
+stack_71bf4017c0: 000000001334af30 646e61680b007470 54656c646e61680a 0000000000000000
+stack_71bf4017e0: 0000000000000000 4010040140100401 0000000000000000 0000000000000000
+stack_71bf401800: 000000001334af60 0000000000000000 000000006ff6eb78 000000006fef61e8
+stack_71bf401820: 0000000000000000 0080000000000000 607560694b1aff3a 0000000000000000
+stack_71bf401840: 0000000000000000 000000001334a270 000000001334af60 0000000000000000
+stack_71bf401860: 000000001334af30 0000000070075fe8 0000000000000000 00000071bf401950
+stack_71bf401880: 00000071bf401930 000000009bfe9820 0000000070079040 0000000000000000
+stack_71bf4018a0: 0000000000000014 000000715b95bdd0 1334af601334a270 00000071d3764780
+stack_71bf4018c0: 0000000000000014 000000715b95bdd0 00000071d3531f47 00000071d3764780
+stack_71bf4018e0: 00000071bf401918 00000071d376e34c 00000071b1865730 000000001334af30
+stack_71bf401900: 00000071bf401a70 000000715b95bdd0 00000071bf401950 1334af3000000000
+stack_71bf401920: 0000000000000000 1334a27000000000 1334af3000000000 000075300000000a
+stack_71bf401940: 1334a27000000000 d31f8b8761d5c565 0000000000000000 0000000000000000
+stack_71bf401960: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401980: 0000000000000000 0000000000000000 0000007346370dc0 0000000000000000
+stack_71bf4019a0: 0000007346370dc0 00000071bf402000 0000007346370e70 000000001334a270
+stack_71bf4019c0: 00000071bf401ae0 00000071bf402000 0000000000000000 0000000000000001
+stack_71bf4019e0: 00000071bf401a00 00000071d3878568 0000000000000000 d31f8b871334a270
+stack_71bf401a00: 00000071bf401ac0 000000715bbd16e6 00000071bf401ac0 00000071b1865730
+stack_71bf401a20: 00000071bf401a80 00000071d3867770 00000071d3cd7000 00000071bf402000
+stack_71bf401a40: 0000000000000000 0000000000000000 00000071bf401ab0 d31f8b8761d5c565
+stack_71bf401a60: 0000000000000000 0000000000000000 0000000000000000 d31f8b8761d5c565
+stack_71bf401a80: 00000071bf401b30 00000071d38b0e1c 000000001334a270 000000715bbd16e6
+stack_71bf401aa0: 00000071b1865730 0000000000000000 0000000000000005 00000071bf401bc0
+stack_71bf401ac0: 0000000000000000 000000715bbd16e6 0000000400000001 00000071bf401ae0
+stack_71bf401ae0: 000000001334a270 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401b00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401b20: 0000000000000000 d31f8b8761d5c565 00000071bf401c00 00000071d38afb50
+stack_71bf401b40: 00000071bf2fd000 0000000000108000 00000071bf401ba8 00000071d3cd5000
+stack_71bf401b60: 00000071d3cd7000 00000071bf402000 0000000000000005 00000072962afc50
+stack_71bf401b80: 00000000700bb3a8 0000007346370dc0 00000071bf401cb0 d31f8b87005c0000
+stack_71bf401ba0: 00000071bf401bd0 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401bc0: 0000007346370dc0 00000072962afc50 b4000072a62a5150 0000007346370dc0
+stack_71bf401be0: 0000005c00000043 0000000000000000 00000071bf401c30 d31f8b8761d5c565
+stack_71bf401c00: 00000071bf401c60 000000746acf95a0 0000000000108000 0000000000000000
+stack_71bf401c20: 00000071bf401ff8 00000071bf401cb0 00000071bf401cb0 0000000000003427
+stack_71bf401c40: 000000000000380d 00000071bf401cb0 000000746acf955c 00000071bf401cb0
+stack_71bf401c60: 00000071bf401c80 000000746ac996e8 00000071bf401cb0 0000000000000000
+stack_71bf401c80: 0000000000000000 0000000000000000 00000071bf50bcb0 0000000000000000
+stack_71bf401ca0: 00000071bf50c000 00000071bf50bfb0 00000071bf50bcb0 00000071bf1edcb0
+stack_71bf401cc0: 0000380d00003428 0000000000000001 00000071bf2fc000 0000000000105cb0
+stack_71bf401ce0: 0000000000001000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401d00: 0000000000000003 0000000000000000 00000071d38af76c 0000007346370dc0
+stack_71bf401d20: 0000000000000000 0000000080001204 0000007473c00000 00000071570e6000
+stack_71bf401d40: 00000071bf401cb0 0000000100000000 0000000000000000 00000071bf2fc000
+stack_71bf401d60: 000000000010a000 00000071bf2fd000 0000000000108000 6e615f6b63617473
+stack_71bf401d80: 33313a736c745f64 0000000000323533 0000000000000000 0000000000000000
+stack_71bf401da0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401dc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401de0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401e80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401ea0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401ec0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401ee0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401f80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401fa0: 0000000000000000 00000071bf402040 0000000000000000 0000000000000000
+stack_71bf401fc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf401fe0: 0000000000000000 0000000000000000 0000000000000000 00000071bf402040
+stack_71bf402000: 000000746ac6d188 00000071bf401cb0 0000000000000000 0000000000000000
+stack_71bf402020: 0000000000000000 d31f8b8761d5c565 000000746ad1c140 0000007346370dc0
+stack_71bf402040: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402060: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402080: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4020a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4020c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4020e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402100: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402120: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402140: 0000000000000000 0000000000000000 0000000000000001 00000072b62e0710
+stack_71bf402160: 0000000000000000 0000000000000000 0000000000000001 00000071f6354be8
+stack_71bf402180: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4021a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4021c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4021e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402200: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402220: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402240: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402260: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402280: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4022a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4022c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4022e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402300: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402320: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402340: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402360: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402380: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4023a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4023c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4023e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402400: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402420: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402440: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402460: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402480: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4024a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4024c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4024e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402500: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402520: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402540: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402560: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402580: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4025a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4025c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4025e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402600: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402620: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402640: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402660: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402680: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4026a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4026c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4026e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402700: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402720: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402740: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402760: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402780: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4027a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4027c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4027e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402800: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402820: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402840: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402860: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402880: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4028a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4028c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4028e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402900: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402920: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402940: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402960: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402980: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4029a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4029c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf4029e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402a80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402aa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ac0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ae0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402b80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ba0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402bc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402be0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402c80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ca0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402cc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ce0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402d80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402da0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402dc0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402de0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402e80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ea0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ec0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402ee0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402f80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402fa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
+stack_71bf402fc0: 0000000000000000 0000000000000000
+
diff --git a/test/testdata/elf b/test/testdata/elf
new file mode 100644
index 0000000..f63c25c
--- /dev/null
+++ b/test/testdata/elf
Binary files differ
diff --git a/test/testdata/elf_file_source.cpp b/test/testdata/elf_file_source.cpp
new file mode 100644
index 0000000..3cfd00b
--- /dev/null
+++ b/test/testdata/elf_file_source.cpp
@@ -0,0 +1,20 @@
+#include <pthread.h>
+
+volatile int GlobalVar;
+
+extern "C" void CalledFunc() {
+  GlobalVar++;
+}
+
+extern "C" void GlobalFunc() {
+  for (int i = 0; i < 1000000; ++i) {
+    CalledFunc();
+  }
+}
+
+int main() {
+  while (true) {
+    GlobalFunc();
+  }
+  return 0;
+}
diff --git a/test/testdata/elf_with_mini_debug_info b/test/testdata/elf_with_mini_debug_info
new file mode 100644
index 0000000..b3aa967
--- /dev/null
+++ b/test/testdata/elf_with_mini_debug_info
Binary files differ
diff --git a/test/testdata/etm/etm_test_loop b/test/testdata/etm/etm_test_loop
new file mode 100644
index 0000000..ec715f1
--- /dev/null
+++ b/test/testdata/etm/etm_test_loop
Binary files differ
diff --git a/test/testdata/etm/perf.data b/test/testdata/etm/perf.data
new file mode 100644
index 0000000..10481f5
--- /dev/null
+++ b/test/testdata/etm/perf.data
Binary files differ
diff --git a/test/testdata/etm/perf_inject.data b/test/testdata/etm/perf_inject.data
new file mode 100644
index 0000000..4c121a3
--- /dev/null
+++ b/test/testdata/etm/perf_inject.data
@@ -0,0 +1,24 @@
+10
+1000-1004:1
+100c-1050:1
+1054-106c:1
+105c-106c:100
+1070-1070:1
+1074-1080:100
+1084-1088:1
+108c-10a0:1
+10a4-10b0:1
+10e0-10ec:1
+0
+9
+1004->100c:1
+1050->10e0:1
+106c->1074:100
+1070->1084:1
+1080->105c:100
+1088->0:1
+10a0->1054:1
+10b0->0:1
+10ec->0:1
+// /data/local/tmp/etm_test_loop
+
diff --git a/test/testdata/etm/perf_with_recording_process.data b/test/testdata/etm/perf_with_recording_process.data
new file mode 100644
index 0000000..92293bd
--- /dev/null
+++ b/test/testdata/etm/perf_with_recording_process.data
Binary files differ
diff --git a/test/testdata/generated_by_linux_perf.data b/test/testdata/generated_by_linux_perf.data
new file mode 100644
index 0000000..da62584
--- /dev/null
+++ b/test/testdata/generated_by_linux_perf.data
Binary files differ
diff --git a/test/testdata/has_embedded_native_libs_apk_perf.data b/test/testdata/has_embedded_native_libs_apk_perf.data
new file mode 100644
index 0000000..fafbbbc
--- /dev/null
+++ b/test/testdata/has_embedded_native_libs_apk_perf.data
Binary files differ
diff --git a/test/testdata/invalid_perf.data b/test/testdata/invalid_perf.data
new file mode 100644
index 0000000..06d7405
--- /dev/null
+++ b/test/testdata/invalid_perf.data
Binary files differ
diff --git a/testdata/java_api-debug_Q.apk b/test/testdata/java_api-debug_Q.apk
similarity index 100%
rename from testdata/java_api-debug_Q.apk
rename to test/testdata/java_api-debug_Q.apk
Binary files differ
diff --git a/testdata/java_api-debug_prev_Q.apk b/test/testdata/java_api-debug_prev_Q.apk
similarity index 100%
rename from testdata/java_api-debug_prev_Q.apk
rename to test/testdata/java_api-debug_prev_Q.apk
Binary files differ
diff --git a/testdata/java_api-profile_Q.apk b/test/testdata/java_api-profile_Q.apk
similarity index 100%
rename from testdata/java_api-profile_Q.apk
rename to test/testdata/java_api-profile_Q.apk
Binary files differ
diff --git a/testdata/java_api-profile_prev_Q.apk b/test/testdata/java_api-profile_prev_Q.apk
similarity index 100%
rename from testdata/java_api-profile_prev_Q.apk
rename to test/testdata/java_api-profile_prev_Q.apk
Binary files differ
diff --git a/test/testdata/java_api.apk b/test/testdata/java_api.apk
new file mode 100644
index 0000000..73972ee
--- /dev/null
+++ b/test/testdata/java_api.apk
Binary files differ
diff --git a/test/testdata/kallsyms b/test/testdata/kallsyms
new file mode 100644
index 0000000..77d185f
--- /dev/null
+++ b/test/testdata/kallsyms
@@ -0,0 +1 @@
+ffffffc000080000 T FakeKernelSymbol
\ No newline at end of file
diff --git a/test/testdata/libc.so b/test/testdata/libc.so
new file mode 100644
index 0000000..6774ac0
--- /dev/null
+++ b/test/testdata/libc.so
Binary files differ
diff --git a/test/testdata/libsgmainso-6.4.36.so b/test/testdata/libsgmainso-6.4.36.so
new file mode 100644
index 0000000..b243f40
--- /dev/null
+++ b/test/testdata/libsgmainso-6.4.36.so
Binary files differ
diff --git a/test/testdata/perf.data b/test/testdata/perf.data
new file mode 100644
index 0000000..64a59da
--- /dev/null
+++ b/test/testdata/perf.data
Binary files differ
diff --git a/test/testdata/perf_b.data b/test/testdata/perf_b.data
new file mode 100644
index 0000000..e514944
--- /dev/null
+++ b/test/testdata/perf_b.data
Binary files differ
diff --git a/test/testdata/perf_display_bitmaps.data b/test/testdata/perf_display_bitmaps.data
new file mode 100644
index 0000000..f1c2780
--- /dev/null
+++ b/test/testdata/perf_display_bitmaps.data
Binary files differ
diff --git a/test/testdata/perf_for_build_id_check.data b/test/testdata/perf_for_build_id_check.data
new file mode 100644
index 0000000..1012d4b
--- /dev/null
+++ b/test/testdata/perf_for_build_id_check.data
Binary files differ
diff --git a/test/testdata/perf_g_fp.data b/test/testdata/perf_g_fp.data
new file mode 100644
index 0000000..de9cf53
--- /dev/null
+++ b/test/testdata/perf_g_fp.data
Binary files differ
diff --git a/test/testdata/perf_merge1.data b/test/testdata/perf_merge1.data
new file mode 100644
index 0000000..9b0b8df
--- /dev/null
+++ b/test/testdata/perf_merge1.data
Binary files differ
diff --git a/test/testdata/perf_merge2.data b/test/testdata/perf_merge2.data
new file mode 100644
index 0000000..a761b32
--- /dev/null
+++ b/test/testdata/perf_merge2.data
Binary files differ
diff --git a/test/testdata/perf_no_unwind.data b/test/testdata/perf_no_unwind.data
new file mode 100644
index 0000000..473f7f2
--- /dev/null
+++ b/test/testdata/perf_no_unwind.data
Binary files differ
diff --git a/test/testdata/perf_sched_stat_runtime.data b/test/testdata/perf_sched_stat_runtime.data
new file mode 100644
index 0000000..bb9219d
--- /dev/null
+++ b/test/testdata/perf_sched_stat_runtime.data
Binary files differ
diff --git a/test/testdata/perf_test_max_stack_and_percent_limit.data b/test/testdata/perf_test_max_stack_and_percent_limit.data
new file mode 100644
index 0000000..b3fc225
--- /dev/null
+++ b/test/testdata/perf_test_max_stack_and_percent_limit.data
Binary files differ
diff --git a/test/testdata/perf_unwind_embedded_lib_in_apk.data b/test/testdata/perf_unwind_embedded_lib_in_apk.data
new file mode 100644
index 0000000..8a7c54e
--- /dev/null
+++ b/test/testdata/perf_unwind_embedded_lib_in_apk.data
Binary files differ
diff --git a/test/testdata/perf_with_app_package_name.data b/test/testdata/perf_with_app_package_name.data
new file mode 100644
index 0000000..c9c61de
--- /dev/null
+++ b/test/testdata/perf_with_app_package_name.data
Binary files differ
diff --git a/test/testdata/perf_with_big_trace_data.data b/test/testdata/perf_with_big_trace_data.data
new file mode 100644
index 0000000..5134ec5
--- /dev/null
+++ b/test/testdata/perf_with_big_trace_data.data
Binary files differ
diff --git a/test/testdata/perf_with_callchain_record.data b/test/testdata/perf_with_callchain_record.data
new file mode 100644
index 0000000..5318421
--- /dev/null
+++ b/test/testdata/perf_with_callchain_record.data
Binary files differ
diff --git a/test/testdata/perf_with_failed_unwinding_debug_info.data b/test/testdata/perf_with_failed_unwinding_debug_info.data
new file mode 100644
index 0000000..aedcb0b
--- /dev/null
+++ b/test/testdata/perf_with_failed_unwinding_debug_info.data
Binary files differ
diff --git a/test/testdata/perf_with_generic_git_symbols.data b/test/testdata/perf_with_generic_git_symbols.data
new file mode 100644
index 0000000..dc5e45a
--- /dev/null
+++ b/test/testdata/perf_with_generic_git_symbols.data
Binary files differ
diff --git a/testdata/perf_with_interpreter_frames.data b/test/testdata/perf_with_interpreter_frames.data
similarity index 100%
rename from testdata/perf_with_interpreter_frames.data
rename to test/testdata/perf_with_interpreter_frames.data
Binary files differ
diff --git a/test/testdata/perf_with_ip_zero_in_callchain.data b/test/testdata/perf_with_ip_zero_in_callchain.data
new file mode 100644
index 0000000..37e7eed
--- /dev/null
+++ b/test/testdata/perf_with_ip_zero_in_callchain.data
Binary files differ
diff --git a/test/testdata/perf_with_jit_symbol.data b/test/testdata/perf_with_jit_symbol.data
new file mode 100644
index 0000000..5f13920
--- /dev/null
+++ b/test/testdata/perf_with_jit_symbol.data
Binary files differ
diff --git a/test/testdata/perf_with_kernel_symbol.data b/test/testdata/perf_with_kernel_symbol.data
new file mode 100644
index 0000000..8b1fda1
--- /dev/null
+++ b/test/testdata/perf_with_kernel_symbol.data
Binary files differ
diff --git a/test/testdata/perf_with_kernel_symbols_available_false.data b/test/testdata/perf_with_kernel_symbols_available_false.data
new file mode 100644
index 0000000..5fdc804
--- /dev/null
+++ b/test/testdata/perf_with_kernel_symbols_available_false.data
Binary files differ
diff --git a/test/testdata/perf_with_kernel_symbols_available_true.data b/test/testdata/perf_with_kernel_symbols_available_true.data
new file mode 100644
index 0000000..eb1c19b
--- /dev/null
+++ b/test/testdata/perf_with_kernel_symbols_available_true.data
Binary files differ
diff --git a/test/testdata/perf_with_kmem_slab_callgraph.data b/test/testdata/perf_with_kmem_slab_callgraph.data
new file mode 100644
index 0000000..cdb691f
--- /dev/null
+++ b/test/testdata/perf_with_kmem_slab_callgraph.data
Binary files differ
diff --git a/testdata/perf_with_long_callchain.data b/test/testdata/perf_with_long_callchain.data
similarity index 100%
rename from testdata/perf_with_long_callchain.data
rename to test/testdata/perf_with_long_callchain.data
Binary files differ
diff --git a/test/testdata/perf_with_mini_debug_info.data b/test/testdata/perf_with_mini_debug_info.data
new file mode 100644
index 0000000..0b02b3b
--- /dev/null
+++ b/test/testdata/perf_with_mini_debug_info.data
Binary files differ
diff --git a/test/testdata/perf_with_multiple_pids_and_tids.data b/test/testdata/perf_with_multiple_pids_and_tids.data
new file mode 100644
index 0000000..ef4f0d4
--- /dev/null
+++ b/test/testdata/perf_with_multiple_pids_and_tids.data
Binary files differ
diff --git a/testdata/perf_with_symbols.data b/test/testdata/perf_with_symbols.data
similarity index 100%
rename from testdata/perf_with_symbols.data
rename to test/testdata/perf_with_symbols.data
Binary files differ
diff --git a/test/testdata/perf_with_symbols_for_nonzero_minvaddr_dso.data b/test/testdata/perf_with_symbols_for_nonzero_minvaddr_dso.data
new file mode 100644
index 0000000..b5fb92d
--- /dev/null
+++ b/test/testdata/perf_with_symbols_for_nonzero_minvaddr_dso.data
Binary files differ
diff --git a/testdata/perf_with_trace_offcpu.data b/test/testdata/perf_with_trace_offcpu.data
similarity index 100%
rename from testdata/perf_with_trace_offcpu.data
rename to test/testdata/perf_with_trace_offcpu.data
Binary files differ
diff --git a/testdata/perf_with_tracepoint_event.data b/test/testdata/perf_with_tracepoint_event.data
similarity index 100%
rename from testdata/perf_with_tracepoint_event.data
rename to test/testdata/perf_with_tracepoint_event.data
Binary files differ
diff --git a/test/testdata/perf_with_tracepoint_event_dynamic_field.data b/test/testdata/perf_with_tracepoint_event_dynamic_field.data
new file mode 100644
index 0000000..24e3d90
--- /dev/null
+++ b/test/testdata/perf_with_tracepoint_event_dynamic_field.data
Binary files differ
diff --git a/test/testdata/perf_with_two_event_types.data b/test/testdata/perf_with_two_event_types.data
new file mode 100644
index 0000000..ba9a606
--- /dev/null
+++ b/test/testdata/perf_with_two_event_types.data
Binary files differ
diff --git a/testdata/simpleperf_runtest_two_functions_arm b/test/testdata/simpleperf_runtest_two_functions_arm
similarity index 100%
rename from testdata/simpleperf_runtest_two_functions_arm
rename to test/testdata/simpleperf_runtest_two_functions_arm
Binary files differ
diff --git a/testdata/simpleperf_runtest_two_functions_arm64 b/test/testdata/simpleperf_runtest_two_functions_arm64
similarity index 100%
rename from testdata/simpleperf_runtest_two_functions_arm64
rename to test/testdata/simpleperf_runtest_two_functions_arm64
Binary files differ
diff --git a/testdata/simpleperf_runtest_two_functions_x86 b/test/testdata/simpleperf_runtest_two_functions_x86
similarity index 100%
rename from testdata/simpleperf_runtest_two_functions_x86
rename to test/testdata/simpleperf_runtest_two_functions_x86
Binary files differ
diff --git a/testdata/simpleperf_runtest_two_functions_x86_64 b/test/testdata/simpleperf_runtest_two_functions_x86_64
similarity index 100%
rename from testdata/simpleperf_runtest_two_functions_x86_64
rename to test/testdata/simpleperf_runtest_two_functions_x86_64
Binary files differ
diff --git a/test/testdata/sysfs/module/fake_kernel_module/notes/note.gnu.build-id b/test/testdata/sysfs/module/fake_kernel_module/notes/note.gnu.build-id
new file mode 100644
index 0000000..5a4109c
--- /dev/null
+++ b/test/testdata/sysfs/module/fake_kernel_module/notes/note.gnu.build-id
Binary files differ
diff --git a/testdata/two_process_perf.data b/test/testdata/two_process_perf.data
similarity index 100%
rename from testdata/two_process_perf.data
rename to test/testdata/two_process_perf.data
Binary files differ
diff --git a/test/testdata/wrong_ip_callchain_perf.data b/test/testdata/wrong_ip_callchain_perf.data
new file mode 100644
index 0000000..633f2d1
--- /dev/null
+++ b/test/testdata/wrong_ip_callchain_perf.data
Binary files differ
diff --git a/test/tools_test.py b/test/tools_test.py
new file mode 100644
index 0000000..bd093b2
--- /dev/null
+++ b/test/tools_test.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from simpleperf_utils import (is_elf_file, Addr2Nearestline, Objdump, ReadElf,
+                              SourceFileSearcher, is_windows, remove)
+from . test_utils import TestBase, TEST_HELPER
+
+
+class TestTools(TestBase):
+    def test_addr2nearestline(self):
+        self.run_addr2nearestline_test(True)
+        self.run_addr2nearestline_test(False)
+
+    def run_addr2nearestline_test(self, with_function_name):
+        binary_cache_path = TEST_HELPER.testdata_dir
+        test_map = {
+            '/simpleperf_runtest_two_functions_arm64': [
+                {
+                    'func_addr': 0x668,
+                    'addr': 0x668,
+                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:20',
+                    'function': 'main',
+                },
+                {
+                    'func_addr': 0x668,
+                    'addr': 0x6a4,
+                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:7
+                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
+                    'function': """Function1()
+                                   main""",
+                },
+            ],
+            '/simpleperf_runtest_two_functions_arm': [
+                {
+                    'func_addr': 0x784,
+                    'addr': 0x7b0,
+                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:14
+                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
+                    'function': """Function2()
+                                   main""",
+                },
+                {
+                    'func_addr': 0x784,
+                    'addr': 0x7d0,
+                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:15
+                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
+                    'function': """Function2()
+                                   main""",
+                }
+            ],
+            '/simpleperf_runtest_two_functions_x86_64': [
+                {
+                    'func_addr': 0x840,
+                    'addr': 0x840,
+                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:7',
+                    'function': 'Function1()',
+                },
+                {
+                    'func_addr': 0x920,
+                    'addr': 0x94a,
+                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:7
+                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
+                    'function': """Function1()
+                                   main""",
+                }
+            ],
+            '/simpleperf_runtest_two_functions_x86': [
+                {
+                    'func_addr': 0x6d0,
+                    'addr': 0x6da,
+                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:14',
+                    'function': 'Function2()',
+                },
+                {
+                    'func_addr': 0x710,
+                    'addr': 0x749,
+                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:8
+                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
+                    'function': """Function1()
+                                   main""",
+                }
+            ],
+        }
+        addr2line = Addr2Nearestline(TEST_HELPER.ndk_path, binary_cache_path, with_function_name)
+        for dso_path in test_map:
+            test_addrs = test_map[dso_path]
+            for test_addr in test_addrs:
+                addr2line.add_addr(dso_path, test_addr['func_addr'], test_addr['addr'])
+        addr2line.convert_addrs_to_lines()
+        for dso_path in test_map:
+            dso = addr2line.get_dso(dso_path)
+            self.assertIsNotNone(dso, dso_path)
+            test_addrs = test_map[dso_path]
+            for test_addr in test_addrs:
+                expected_files = []
+                expected_lines = []
+                expected_functions = []
+                for line in test_addr['source'].split('\n'):
+                    items = line.split(':')
+                    expected_files.append(items[0].strip())
+                    expected_lines.append(int(items[1]))
+                for line in test_addr['function'].split('\n'):
+                    expected_functions.append(line.strip())
+                self.assertEqual(len(expected_files), len(expected_functions))
+
+                if with_function_name:
+                    expected_source = list(zip(expected_files, expected_lines, expected_functions))
+                else:
+                    expected_source = list(zip(expected_files, expected_lines))
+
+                actual_source = addr2line.get_addr_source(dso, test_addr['addr'])
+                if is_windows():
+                    self.assertIsNotNone(actual_source, 'for %s:0x%x' %
+                                         (dso_path, test_addr['addr']))
+                    for i, source in enumerate(actual_source):
+                        new_source = list(source)
+                        new_source[0] = new_source[0].replace('\\', '/')
+                        actual_source[i] = tuple(new_source)
+
+                self.assertEqual(actual_source, expected_source,
+                                 'for %s:0x%x, expected source %s, actual source %s' %
+                                 (dso_path, test_addr['addr'], expected_source, actual_source))
+
+    def test_objdump(self):
+        binary_cache_path = TEST_HELPER.testdata_dir
+        test_map = {
+            '/simpleperf_runtest_two_functions_arm64': {
+                'start_addr': 0x668,
+                'len': 116,
+                'expected_items': [
+                    ('main():', 0),
+                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
+                    ('694:      	add	x20, x20, #1758', 0x694),
+                ],
+            },
+            '/simpleperf_runtest_two_functions_arm': {
+                'start_addr': 0x784,
+                'len': 80,
+                'expected_items': [
+                    ('main():', 0),
+                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
+                    ('7ae:	bne.n	7a6 <main+0x22>', 0x7ae),
+                ],
+            },
+            '/simpleperf_runtest_two_functions_x86_64': {
+                'start_addr': 0x920,
+                'len': 201,
+                'expected_items': [
+                    ('main():', 0),
+                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
+                    ('96e:      	movl	%edx, (%rbx,%rax,4)', 0x96e),
+                ],
+            },
+            '/simpleperf_runtest_two_functions_x86': {
+                'start_addr': 0x710,
+                'len': 98,
+                'expected_items': [
+                    ('main():', 0),
+                    ('system/extras/simpleperf/runtest/two_functions.cpp:20', 0),
+                    ('748:      	cmpl	$100000000, %ebp', 0x748),
+                ],
+            },
+        }
+        objdump = Objdump(TEST_HELPER.ndk_path, binary_cache_path)
+        for dso_path in test_map:
+            dso = test_map[dso_path]
+            dso_info = objdump.get_dso_info(dso_path)
+            self.assertIsNotNone(dso_info, dso_path)
+            disassemble_code = objdump.disassemble_code(dso_info, dso['start_addr'], dso['len'])
+            self.assertTrue(disassemble_code, dso_path)
+            i = 0
+            for expected_line, expected_addr in dso['expected_items']:
+                found = False
+                while i < len(disassemble_code):
+                    line, addr = disassemble_code[i]
+                    if addr == expected_addr and expected_line in line:
+                        found = True
+                        i += 1
+                        break
+                    i += 1
+                if not found:
+                    s = '\n'.join('%s:0x%x' % item for item in disassemble_code)
+                    self.fail('for %s, %s:0x%x not found in disassemble code:\n%s' %
+                              (dso_path, expected_line, expected_addr, s))
+
+    def test_readelf(self):
+        test_map = {
+            'simpleperf_runtest_two_functions_arm64': {
+                'arch': 'arm64',
+                'build_id': '0xe8ecb3916d989dbdc068345c30f0c24300000000',
+                'sections': ['.interp', '.note.android.ident', '.note.gnu.build-id', '.dynsym',
+                             '.dynstr', '.gnu.hash', '.gnu.version', '.gnu.version_r', '.rela.dyn',
+                             '.rela.plt', '.plt', '.text', '.rodata', '.eh_frame', '.eh_frame_hdr',
+                             '.preinit_array', '.init_array', '.fini_array', '.dynamic', '.got',
+                             '.got.plt', '.data', '.bss', '.comment', '.debug_str', '.debug_loc',
+                             '.debug_abbrev', '.debug_info', '.debug_ranges', '.debug_macinfo',
+                             '.debug_pubnames', '.debug_pubtypes', '.debug_line',
+                             '.note.gnu.gold-version', '.symtab', '.strtab', '.shstrtab'],
+            },
+            'simpleperf_runtest_two_functions_arm': {
+                'arch': 'arm',
+                'build_id': '0x718f5b36c4148ee1bd3f51af89ed2be600000000',
+            },
+            'simpleperf_runtest_two_functions_x86_64': {
+                'arch': 'x86_64',
+            },
+            'simpleperf_runtest_two_functions_x86': {
+                'arch': 'x86',
+            }
+        }
+        readelf = ReadElf(TEST_HELPER.ndk_path)
+        for dso_path in test_map:
+            dso_info = test_map[dso_path]
+            path = os.path.join(TEST_HELPER.testdata_dir, dso_path)
+            self.assertEqual(dso_info['arch'], readelf.get_arch(path))
+            if 'build_id' in dso_info:
+                self.assertEqual(dso_info['build_id'], readelf.get_build_id(path), dso_path)
+            if 'sections' in dso_info:
+                self.assertEqual(dso_info['sections'], readelf.get_sections(path), dso_path)
+        self.assertEqual(readelf.get_arch('not_exist_file'), 'unknown')
+        self.assertEqual(readelf.get_build_id('not_exist_file'), '')
+        self.assertEqual(readelf.get_sections('not_exist_file'), [])
+
+    def test_source_file_searcher(self):
+        searcher = SourceFileSearcher(
+            [TEST_HELPER.testdata_path('SimpleperfExampleWithNative'),
+             TEST_HELPER.testdata_path('SimpleperfExampleOfKotlin')])
+
+        def format_path(path):
+            return os.path.join(TEST_HELPER.testdata_dir, path.replace('/', os.sep))
+        # Find a C++ file with pure file name.
+        self.assertEqual(
+            format_path('SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
+            searcher.get_real_path('native-lib.cpp'))
+        # Find a C++ file with an absolute file path.
+        self.assertEqual(
+            format_path('SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp'),
+            searcher.get_real_path('/data/native-lib.cpp'))
+        # Find a Java file.
+        self.assertEqual(
+            format_path('SimpleperfExampleWithNative/app/src/main/java/com/example/' +
+                        'simpleperf/simpleperfexamplewithnative/MainActivity.java'),
+            searcher.get_real_path('simpleperfexamplewithnative/MainActivity.java'))
+        # Find a Kotlin file.
+        self.assertEqual(
+            format_path('SimpleperfExampleOfKotlin/app/src/main/java/com/example/' +
+                        'simpleperf/simpleperfexampleofkotlin/MainActivity.kt'),
+            searcher.get_real_path('MainActivity.kt'))
+
+    def test_is_elf_file(self):
+        self.assertTrue(is_elf_file(TEST_HELPER.testdata_path(
+            'simpleperf_runtest_two_functions_arm')))
+        with open('not_elf', 'wb') as fh:
+            fh.write(b'\x90123')
+        try:
+            self.assertFalse(is_elf_file('not_elf'))
+        finally:
+            remove('not_elf')