Merge "Add support for analysis of OTA package."
diff --git a/python-packages/gdbrunner/__init__.py b/python-packages/gdbrunner/__init__.py
index b69069d..4446fcb 100644
--- a/python-packages/gdbrunner/__init__.py
+++ b/python-packages/gdbrunner/__init__.py
@@ -197,7 +197,7 @@
gdbserver_output_path = os.path.join(tempfile.gettempdir(),
"gdbclient.log")
print("Redirecting gdbserver output to {}".format(gdbserver_output_path))
- gdbserver_output = file(gdbserver_output_path, 'w')
+ gdbserver_output = open(gdbserver_output_path, 'w')
return device.shell_popen(gdbserver_cmd, stdout=gdbserver_output,
stderr=gdbserver_output)
@@ -275,7 +275,7 @@
for path, found_locally in generate_files():
if os.path.isfile(path):
- return (open(path, "r"), found_locally)
+ return (open(path, "rb"), found_locally)
raise RuntimeError('Could not find executable {}'.format(executable_path))
def find_executable_path(device, executable_name, run_as_cmd=None):
@@ -318,14 +318,14 @@
binary = binary_file.read(0x14)
except IOError:
raise RuntimeError("failed to read binary file")
- ei_class = ord(binary[0x4]) # 1 = 32-bit, 2 = 64-bit
- ei_data = ord(binary[0x5]) # Endianness
+ ei_class = binary[0x4] # 1 = 32-bit, 2 = 64-bit
+ ei_data = binary[0x5] # Endianness
assert ei_class == 1 or ei_class == 2
if ei_data != 1:
raise RuntimeError("binary isn't little-endian?")
- e_machine = ord(binary[0x13]) << 8 | ord(binary[0x12])
+ e_machine = binary[0x13] << 8 | binary[0x12]
if e_machine == 0x28:
assert ei_class == 1
return "arm"
@@ -338,11 +338,6 @@
elif e_machine == 0x3E:
assert ei_class == 2
return "x86_64"
- elif e_machine == 0x08:
- if ei_class == 1:
- return "mips"
- else:
- return "mips64"
else:
raise RuntimeError("unknown architecture: 0x{:x}".format(e_machine))
@@ -368,7 +363,7 @@
# Windows disallows opening the file while it's open for writing.
script_fd, script_path = tempfile.mkstemp()
- os.write(script_fd, gdb_commands)
+ os.write(script_fd, gdb_commands.encode())
os.close(script_fd)
if lldb:
script_parameter = "--source"
diff --git a/samples/ApiDemos/Android.bp b/samples/ApiDemos/Android.bp
new file mode 100644
index 0000000..32ae196
--- /dev/null
+++ b/samples/ApiDemos/Android.bp
@@ -0,0 +1,21 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "ApiDemos",
+ // Only compile source java files in this apk.
+ srcs: [
+ "src/**/*.java",
+ "src/com/example/android/apis/app/IRemoteService.aidl",
+ "src/com/example/android/apis/app/IRemoteServiceCallback.aidl",
+ "src/com/example/android/apis/app/ISecondary.aidl",
+ ],
+ static_libs: ["androidx.legacy_legacy-support-v4"],
+ sdk_version: "current",
+ dex_preopt: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+}
diff --git a/samples/ApiDemos/Android.mk b/samples/ApiDemos/Android.mk
deleted file mode 100644
index 9bc1ba0..0000000
--- a/samples/ApiDemos/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := samples tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- src/com/example/android/apis/app/IRemoteService.aidl \
- src/com/example/android/apis/app/IRemoteServiceCallback.aidl \
- src/com/example/android/apis/app/ISecondary.aidl \
-
-LOCAL_STATIC_ANDROID_LIBRARIES += \
- androidx.legacy_legacy-support-v4
-
-LOCAL_USE_AAPT2 := true
-
-LOCAL_PACKAGE_NAME := ApiDemos
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
-
-# Use the folloing include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/ApiDemos/tests/Android.bp b/samples/ApiDemos/tests/Android.bp
new file mode 100644
index 0000000..abb7fd7
--- /dev/null
+++ b/samples/ApiDemos/tests/Android.bp
@@ -0,0 +1,21 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "ApiDemosTests",
+ // We only want this apk build for tests.
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+ static_libs: ["junit"],
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ // Notice that we don't have to include the src files of ApiDemos because, by
+ // running the tests using an instrumentation targeting ApiDemos, we
+ // automatically get all of its classes loaded into our environment.
+ instrumentation_for: "ApiDemos",
+ sdk_version: "current",
+}
diff --git a/samples/ApiDemos/tests/Android.mk b/samples/ApiDemos/tests/Android.mk
deleted file mode 100644
index ed37fbe..0000000
--- a/samples/ApiDemos/tests/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Notice that we don't have to include the src files of ApiDemos because, by
-# running the tests using an instrumentation targeting ApiDemos, we
-# automatically get all of its classes loaded into our environment.
-
-LOCAL_PACKAGE_NAME := ApiDemosTests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-
-LOCAL_INSTRUMENTATION_FOR := ApiDemos
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index a3fb2c7..143fdfd 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -24,17 +24,6 @@
}
python_test_host {
- name: "python-native_heapdump_viewer_test",
- main: "native_heapdump_viewer_tests.py",
- srcs: [
- "native_heapdump_viewer.py",
- "native_heapdump_viewer_tests.py",
- ],
- test_config: "native_heapdump_viewer-tests.xml",
- test_suites: ["general-tests"],
-}
-
-python_test_host {
name: "python-symbol_test",
main: "symbol.py",
// Would be nice to use the library above, but as it's single-source
diff --git a/scripts/TEST_MAPPING b/scripts/TEST_MAPPING
index 1d2b9d0..b052da9 100644
--- a/scripts/TEST_MAPPING
+++ b/scripts/TEST_MAPPING
@@ -1,9 +1,6 @@
{
"presubmit": [
{
- "name": "python-native_heapdump_viewer_test"
- },
- {
"name": "python-symbol_test"
}
]
diff --git a/scripts/gdb/dalvik.gdb b/scripts/gdb/dalvik.gdb
deleted file mode 100644
index 0bedf64..0000000
--- a/scripts/gdb/dalvik.gdb
+++ /dev/null
@@ -1,72 +0,0 @@
-#
-# Copyright (C) 2014 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.
-
-# ART debugging. ART uses SIGSEGV signals for internal purposes. To allow
-# gdb to debug programs using ART we need to treat this signal specially. We
-# also set a breakpoint in a libart.so function to stop when the program
-# hits an unexpected breakpoint
-set $art_debug_enabled = 0
-define art-on
- if $art_debug_enabled == 0
- # deal with SIGSEGV signals
- handle SIGSEGV noprint nostop pass
-
- # set a breakpoint and record its number
- set breakpoint pending on
- break art_sigsegv_fault
- set $art_bpnum = $bpnum
- commands $art_bpnum
- silent
- printf "Caught SIGSEGV in user program\n"
- end
- set breakpoint pending auto
-
- printf "ART debugging mode is enabled.\n"
- printf "If you are debugging a native only process, you need to\n"
- printf "re-enable normal SIGSEGV handling using this command:\n"
- printf " handle SIGSEGV print stop\n"
- set $art_debug_enabled = 1
- else
- printf "ART debugging mode is already enabled.\n"
- end
-end
-
-document art-on
- Enter ART debugging mode. In ART debugging mode, SIGSEGV signals are ignored
- by gdb unless they are not handled by ART itself. A breakpoint is
- set to stop the program when an unexpected SIGSEGV signal is
- encountered.
-
- To switch ART debugging mode off, use "art-off"
-end
-
-define art-off
- if $art_debug_enabled == 1
- # restore SIGSEGV to its default
- handle SIGSEGV print stop pass
-
- # delete our breakpoint
- delete $art_bpnum
-
- set $art_debug_enabled = 0
- printf "ART debugging mode is disabled.\n"
- end
-end
-
-document art-off
- Leave ART debugging mode. Signal handling is restored to default settings.
-
- Use the command "art-on" to enable ART debugging mode.
-end
diff --git a/scripts/gdbclient.py b/scripts/gdbclient.py
index 61fac40..5d4475a 100755
--- a/scripts/gdbclient.py
+++ b/scripts/gdbclient.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (C) 2015 The Android Open Source Project
#
diff --git a/scripts/native_heapdump_viewer-tests.xml b/scripts/native_heapdump_viewer-tests.xml
deleted file mode 100644
index 25d5623..0000000
--- a/scripts/native_heapdump_viewer-tests.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<configuration description="Config for python tradefed symbol test">
- <option name="test-suite-tag" value="python-native_heapdump_viewer_test" />
- <test class="com.android.tradefed.testtype.python.PythonBinaryHostTest" >
- <option name="par-file-name" value="python-native_heapdump_viewer_test" />
- <option name="test-timeout" value="2m" />
- </test>
-</configuration>
diff --git a/scripts/native_heapdump_viewer.py b/scripts/native_heapdump_viewer.py
deleted file mode 100755
index 9b2a6e5..0000000
--- a/scripts/native_heapdump_viewer.py
+++ /dev/null
@@ -1,482 +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.
-
-"""Generates a human-interpretable view of a native heap dump from 'am dumpheap -n'."""
-
-import logging
-import os
-import os.path
-import re
-import subprocess
-import sys
-import zipfile
-
-class Args:
- _usage = """
-Usage:
-1. Collect a native heap dump from the device. For example:
- $ adb shell stop
- $ adb shell setprop libc.debug.malloc.program app_process
- $ adb shell setprop libc.debug.malloc.options backtrace=64
- $ adb shell start
- (launch and use app)
- $ adb shell am dumpheap -n <pid> /data/local/tmp/native_heap.txt
- $ adb pull /data/local/tmp/native_heap.txt
-
-2. Run the viewer:
- $ python native_heapdump_viewer.py [options] native_heap.txt
- [--verbose]: verbose output
- [--html]: interactive html output
- [--reverse]: reverse the backtraces (start the tree from the leaves)
- [--symbols SYMBOL_DIR] SYMBOL_DIR is the directory containing the .so files with symbols.
- Defaults to $ANDROID_PRODUCT_OUT/symbols
- [--app-symbols SYMBOL_DIR] SYMBOL_DIR is the directory containing the app APK and so files.
- Defaults to the current directory.
- This outputs a file with lines of the form:
-
- 5831776 29.09% 100.00% 10532 71b07bc0b0 /system/lib64/libandroid_runtime.so Typeface_createFromArray frameworks/base/core/jni/android/graphics/Typeface.cpp:68
-
- 5831776 is the total number of bytes allocated at this stack frame, which
- is 29.09% of the total number of bytes allocated and 100.00% of the parent
- frame's bytes allocated. 10532 is the total number of allocations at this
- stack frame. 71b07bc0b0 is the address of the stack frame.
-"""
-
- def __init__(self):
- self.verbose = False
- self.html_output = False
- self.reverse_frames = False
- product_out = os.getenv("ANDROID_PRODUCT_OUT")
- if product_out:
- self.symboldir = product_out + "/symbols"
- else:
- self.symboldir = "./symbols"
- self.app_symboldir = ""
-
- i = 1
- extra_args = []
- while i < len(sys.argv):
- if sys.argv[i] == "--symbols":
- i += 1
- self.symboldir = sys.argv[i] + "/"
- elif sys.argv[i] == "--app-symbols":
- i += 1
- self.app_symboldir = sys.argv[i] + "/"
- elif sys.argv[i] == "--verbose":
- self.verbose = True
- elif sys.argv[i] == "--html":
- self.html_output = True
- elif sys.argv[i] == "--reverse":
- self.reverse_frames = True
- elif sys.argv[i][0] == '-':
- print("Invalid option %s" % (sys.argv[i]))
- else:
- extra_args.append(sys.argv[i])
- i += 1
-
- if len(extra_args) != 1:
- print(self._usage)
- sys.exit(1)
-
- self.native_heap = extra_args[0]
-
-class Backtrace:
- def __init__(self, is_zygote, size, num_allocs, frames):
- self.is_zygote = is_zygote
- self.size = size
- self.num_allocs = num_allocs
- self.frames = frames
-
-class Mapping:
- def __init__(self, start, end, offset, name):
- self.start = start
- self.end = end
- self.offset = offset
- self.name = name
-
-class FrameDescription:
- def __init__(self, function, location, library):
- self.function = function
- self.location = location
- self.library = library
-
-def GetVersion(native_heap):
- """Get the version of the native heap dump."""
-
- re_line = re.compile("Android\s+Native\s+Heap\s+Dump\s+(?P<version>v\d+\.\d+)\s*$")
- matched = 0
- with open(native_heap, "r") as f:
- for line in f:
- m = re_line.match(line)
- if m:
- return m.group('version')
- return None
-
-def GetNumFieldValidByParsingLines(native_heap):
- """Determine if the num field is valid by parsing the backtrace lines.
-
- Malloc debug for N incorrectly set the num field to the number of
- backtraces instead of the number of allocations with the same size and
- backtrace. Read the file and if at least three lines all have the field
- set to the number of backtraces values, then consider this generated by
- the buggy malloc debug and indicate the num field is not valid.
-
- Returns:
- True if the num field is valid.
- False if the num field is not valid and should be ignored.
- """
-
- re_backtrace = re.compile("Backtrace\s+size:\s+(?P<backtrace_size>\d+)")
-
- re_line = re.compile("z\s+(?P<zygote>\d+)\s+sz\s+(?P<size>\d+)\s+num\s+(?P<num_allocations>\d+)")
- matched = 0
- backtrace_size = 0
- with open(native_heap, "r") as f:
- for line in f:
- if backtrace_size == 0:
- m = re_backtrace.match(line)
- if m:
- backtrace_size = int(m.group('backtrace_size'))
- parts = line.split()
- if len(parts) > 7 and parts[0] == "z" and parts[2] == "sz":
- m = re_line.match(line)
- if m:
- num_allocations = int(m.group('num_allocations'))
- if num_allocations == backtrace_size:
- # At least three lines must match this pattern before
- # considering this the old buggy version of malloc debug.
- matched += 1
- if matched == 3:
- return False
- else:
- return True
- return matched == 0
-
-def GetNumFieldValid(native_heap):
- version = GetVersion(native_heap)
- if not version or version == "v1.0":
- # Version v1.0 was produced by a buggy version of malloc debug where the
- # num field was set incorrectly.
- # Unfortunately, Android P produced a v1.0 version that does set the
- # num field. Do one more check to see if this is the broken version.
- return GetNumFieldValidByParsingLines(native_heap)
- else:
- return True
-
-def GetMappingFromOffset(mapping, app_symboldir):
- """
- If the input mapping is a zip file, translate the contained uncompressed files and add mapping
- entries.
-
- This is done to handle symbols for the uncompressed .so files inside APKs. With the replaced
- mappings, the script looks up the .so files as separate files.
- """
- basename = os.path.basename(mapping.name)
- zip_name = app_symboldir + basename
- if os.path.isfile(zip_name):
- opened_zip = zipfile.ZipFile(zip_name)
- if opened_zip:
- # For all files in the zip, add mappings for the internal files.
- for file_info in opened_zip.infolist():
- # Only add stored files since it doesn't make sense to have PC into compressed ones.
- if file_info.compress_type == zipfile.ZIP_STORED:
- zip_header_entry_size = 30
- data_offset = (file_info.header_offset
- + zip_header_entry_size
- + len(file_info.filename)
- + len(file_info.extra)
- + len(file_info.comment))
- end_offset = data_offset + file_info.file_size
- if mapping.offset >= data_offset and mapping.offset < end_offset:
- # Round up the data_offset to the nearest page since the .so must be aligned.
- so_file_alignment = 4096
- data_offset += so_file_alignment - 1;
- data_offset -= data_offset % so_file_alignment;
- mapping.name = file_info.filename
- mapping.offset -= data_offset
- break
- return mapping
-
-def ParseNativeHeap(native_heap, reverse_frames, num_field_valid, app_symboldir):
- """Parse the native heap into backtraces, maps.
-
- Returns two lists, the first is a list of all of the backtraces, the
- second is the sorted list of maps.
- """
-
- backtraces = []
- mappings = []
-
- re_map = re.compile("(?P<start>[0-9a-f]+)-(?P<end>[0-9a-f]+) .... (?P<offset>[0-9a-f]+) [0-9a-f]+:[0-9a-f]+ [0-9]+ +(?P<name>.*)")
-
- with open(native_heap, "r") as f:
- for line in f:
- # Format of line:
- # z 0 sz 50 num 1 bt 000000000000a100 000000000000b200
- parts = line.split()
- if len(parts) > 7 and parts[0] == "z" and parts[2] == "sz":
- is_zygote = parts[1] != "1"
- size = int(parts[3])
- if num_field_valid:
- num_allocs = int(parts[5])
- else:
- num_allocs = 1
- frames = list(map(lambda x: int(x, 16), parts[7:]))
- if reverse_frames:
- frames = list(reversed(frames))
- backtraces.append(Backtrace(is_zygote, size, num_allocs, frames))
- else:
- # Parse map line:
- # 720de01000-720ded7000 r-xp 00000000 fd:00 495 /system/lib64/libc.so
- m = re_map.match(line)
- if m:
- # Offset of mapping start
- start = int(m.group('start'), 16)
- # Offset of mapping end
- end = int(m.group('end'), 16)
- # Offset within file that is mapped
- offset = int(m.group('offset'), 16)
- name = m.group('name')
- mappings.append(GetMappingFromOffset(Mapping(start, end, offset, name), app_symboldir))
- return backtraces, mappings
-
-def FindMapping(mappings, addr):
- """Find the mapping given addr.
-
- Returns the mapping that contains addr.
- Returns None if there is no such mapping.
- """
-
- min = 0
- max = len(mappings) - 1
- while True:
- if max < min:
- return None
- mid = (min + max) // 2
- if mappings[mid].end <= addr:
- min = mid + 1
- elif mappings[mid].start > addr:
- max = mid - 1
- else:
- return mappings[mid]
-
-
-def ResolveAddrs(html_output, symboldir, app_symboldir, backtraces, mappings):
- """Resolve address libraries and offsets.
-
- addr_offsets maps addr to .so file offset
- addrs_by_lib maps library to list of addrs from that library
- Resolved addrs maps addr to FrameDescription
-
- Returns the resolved_addrs hash.
- """
-
- addr_offsets = {}
- addrs_by_lib = {}
- resolved_addrs = {}
- empty_frame_description = FrameDescription("???", "???", "???")
- for backtrace in backtraces:
- for addr in backtrace.frames:
- if addr in addr_offsets:
- continue
- mapping = FindMapping(mappings, addr)
- if mapping:
- addr_offsets[addr] = addr - mapping.start + mapping.offset
- if not (mapping.name in addrs_by_lib):
- addrs_by_lib[mapping.name] = []
- addrs_by_lib[mapping.name].append(addr)
- else:
- resolved_addrs[addr] = empty_frame_description
-
- # Resolve functions and line numbers.
- if html_output == False:
- print("Resolving symbols using directory %s..." % symboldir)
-
- for lib in addrs_by_lib:
- sofile = app_symboldir + lib
- if not os.path.isfile(sofile):
- sofile = symboldir + lib
- if os.path.isfile(sofile):
- file_offset = 0
- result = subprocess.check_output(["objdump", "-w", "-j", ".text", "-h", sofile])
- for line in result.split("\n"):
- splitted = line.split()
- if len(splitted) > 5 and splitted[1] == ".text":
- file_offset = int(splitted[5], 16)
- break
-
- input_addrs = ""
- for addr in addrs_by_lib[lib]:
- input_addrs += "%s\n" % hex(addr_offsets[addr] - file_offset)
-
- p = subprocess.Popen(["addr2line", "-C", "-j", ".text", "-e", sofile, "-f"], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
- result = p.communicate(input_addrs)[0]
- addr2line_rc = p.returncode
- if addr2line_rc and (addr2line_rc < 0):
- logging.warn("addr2line on " + sofile + " terminated by signal " + str(-1 * addr2line_rc))
- splitted = result.split("\n")
- for x in range(0, len(addrs_by_lib[lib])):
- try:
- function = splitted[2*x];
- location = splitted[2*x+1];
- resolved_addrs[addrs_by_lib[lib][x]] = FrameDescription(function, location, lib)
- except Exception:
- logging.warn("exception while resolving symbols", exc_info=True)
- resolved_addrs[addrs_by_lib[lib][x]] = FrameDescription("---", "---", lib)
- else:
- if html_output == False:
- print("%s not found for symbol resolution" % lib)
-
- fd = FrameDescription("???", "???", lib)
- for addr in addrs_by_lib[lib]:
- resolved_addrs[addr] = fd
-
- return resolved_addrs
-
-def Addr2Line(resolved_addrs, addr):
- if addr == "ZYGOTE" or addr == "APP":
- return FrameDescription("", "", "")
-
- return resolved_addrs[int(addr, 16)]
-
-class AddrInfo:
- def __init__(self, addr):
- self.addr = addr
- self.size = 0
- self.number = 0
- self.num_allocs = 0
- self.children = {}
-
- def addStack(self, size, num_allocs, stack):
- self.size += size * num_allocs
- self.number += num_allocs
- if len(stack) > 0:
- child = stack[0]
- if not (child.addr in self.children):
- self.children[child.addr] = child
- self.children[child.addr].addStack(size, num_allocs, stack[1:])
-
-def Display(resolved_addrs, indent, total, parent_total, node):
- fd = Addr2Line(resolved_addrs, node.addr)
- total_percent = 0
- if total != 0:
- total_percent = 100 * node.size / float(total)
- parent_percent = 0
- if parent_total != 0:
- parent_percent = 100 * node.size / float(parent_total)
- print("%9d %6.2f%% %6.2f%% %8d %s%s %s %s %s" % (node.size, total_percent, parent_percent, node.number, indent, node.addr, fd.library, fd.function, fd.location))
- children = sorted(node.children.values(), key=lambda x: x.size, reverse=True)
- for child in children:
- Display(resolved_addrs, indent + " ", total, node.size, child)
-
-def DisplayHtml(verbose, resolved_addrs, total, node, extra, label_count):
- fd = Addr2Line(resolved_addrs, node.addr)
- if verbose:
- lib = fd.library
- else:
- lib = os.path.basename(fd.library)
- total_percent = 0
- if total != 0:
- total_percent = 100 * node.size / float(total)
- label = "%d %6.2f%% %6d %s%s %s %s" % (node.size, total_percent, node.number, extra, lib, fd.function, fd.location)
- label = label.replace("&", "&")
- label = label.replace("'", "'")
- label = label.replace('"', """)
- label = label.replace("<", "<")
- label = label.replace(">", ">")
- children = sorted(node.children.values(), key=lambda x: x.size, reverse=True)
- print('<li>')
- if len(children) > 0:
- print('<label for="' + str(label_count) + '">' + label + '</label>')
- print('<input type="checkbox" id="' + str(label_count) + '"/>')
- print('<ol>')
- label_count += 1
- for child in children:
- label_count = DisplayHtml(verbose, resolved_addrs, total, child, "", label_count)
- print('</ol>')
- else:
- print(label)
- print('</li>')
-
- return label_count
-
-def CreateHtml(verbose, app, zygote, resolved_addrs):
- print("""
-<!DOCTYPE html>
-<html><head><style>
-li input {
- display: none;
-}
-li input:checked + ol > li {
- display: block;
-}
-li input + ol > li {
- display: none;
-}
-li {
- font-family: Roboto Mono,monospace;
-}
-label {
- font-family: Roboto Mono,monospace;
- cursor: pointer
-}
-</style></head><body>Native allocation HTML viewer<br><br>
-Click on an individual line to expand/collapse to see the details of the
-allocation data<ol>
-""")
-
- label_count = 0
- label_count = DisplayHtml(verbose, resolved_addrs, app.size, app, "app ", label_count)
- if zygote.size > 0:
- DisplayHtml(verbose, resolved_addrs, zygote.size, zygote, "zygote ", label_count)
- print("</ol></body></html>")
-
-def main():
- args = Args()
-
- num_field_valid = GetNumFieldValid(args.native_heap)
-
- backtraces, mappings = ParseNativeHeap(args.native_heap, args.reverse_frames, num_field_valid,
- args.app_symboldir)
- # Resolve functions and line numbers
- resolved_addrs = ResolveAddrs(args.html_output, args.symboldir, args.app_symboldir, backtraces,
- mappings)
-
- app = AddrInfo("APP")
- zygote = AddrInfo("ZYGOTE")
-
- for backtrace in backtraces:
- stack = []
- for addr in backtrace.frames:
- stack.append(AddrInfo("%x" % addr))
- stack.reverse()
- if backtrace.is_zygote:
- zygote.addStack(backtrace.size, backtrace.num_allocs, stack)
- else:
- app.addStack(backtrace.size, backtrace.num_allocs, stack)
-
- if args.html_output:
- CreateHtml(args.verbose, app, zygote, resolved_addrs)
- else:
- print("")
- print("%9s %6s %6s %8s %s %s %s %s" % ("BYTES", "%TOTAL", "%PARENT", "COUNT", "ADDR", "LIBRARY", "FUNCTION", "LOCATION"))
- Display(resolved_addrs, "", app.size, app.size + zygote.size, app)
- print("")
- Display(resolved_addrs, "", zygote.size, app.size + zygote.size, zygote)
- print("")
-
-if __name__ == '__main__':
- main()
diff --git a/scripts/native_heapdump_viewer_tests.py b/scripts/native_heapdump_viewer_tests.py
deleted file mode 100755
index 423d1c8..0000000
--- a/scripts/native_heapdump_viewer_tests.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 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.
-
-"""Tests for the native_heapdump_viewer script."""
-
-import native_heapdump_viewer
-import os
-import sys
-import tempfile
-import unittest
-
-class NativeHeapdumpViewerTest(unittest.TestCase):
- _tmp_file_name = None
-
- def CreateTmpFile(self, contents):
- fd, self._tmp_file_name = tempfile.mkstemp()
- os.write(fd, contents.encode())
- os.close(fd)
- return self._tmp_file_name
-
- def tearDown(self):
- if self._tmp_file_name:
- try:
- os.unlink(self._tmp_file_name)
- except Exception:
- print("Failed to delete %s" % (heap))
-
-class GetNumFieldValidTest(NativeHeapdumpViewerTest):
- _map_data = """
-MAPS
-1000-10000 r-xp 00000000 fd:00 495 /data/does_not_exist.so
-END
-"""
-
- _heap_num_field_valid_version10 = """
-Android Native Heap Dump v1.0
-
-Total memory: 33800
-Allocation records: 13
-Backtrace size: 16
-
-z 1 sz 1000 num 4 bt 1000 2000 3000
-z 1 sz 2000 num 6 bt 1100 2100 3100
-z 0 sz 1200 num 1 bt 1200 2200 3200
-z 0 sz 8300 num 2 bt 1300 2300 3300
-"""
-
- _heap_num_field_invalid_version10 = """
-Android Native Heap Dump v1.0
-
-Total memory: 12500
-Allocation records: 4
-Backtrace size: 16
-
-z 1 sz 1000 num 16 bt 1000 2000 3000
-z 1 sz 2000 num 16 bt 1100 2100 3100
-z 0 sz 1200 num 16 bt 1200 2200 3200
-z 0 sz 8300 num 16 bt 1300 2300 3300
-"""
-
- _heap_data = """
-
-Total memory: 200000
-Allocation records: 64
-Backtrace size: 16
-
-z 1 sz 1000 num 16 bt 1000 2000 3000
-z 1 sz 2000 num 16 bt 1100 2100 3100
-z 0 sz 1200 num 16 bt 1200 2200 3200
-z 0 sz 8300 num 16 bt 1300 2300 3300
-"""
-
- def test_version10_valid(self):
- heap = self.CreateTmpFile(self._heap_num_field_valid_version10 + self._map_data)
- self.assertTrue(native_heapdump_viewer.GetNumFieldValid(heap))
-
- def test_version10_invalid(self):
- heap = self.CreateTmpFile(self._heap_num_field_invalid_version10 + self._map_data)
- self.assertFalse(native_heapdump_viewer.GetNumFieldValid(heap))
-
- def test_version11_valid(self):
- heap = self.CreateTmpFile("Android Native Heap Dump v1.1" + self._heap_data + self._map_data)
- self.assertTrue(native_heapdump_viewer.GetNumFieldValid(heap))
-
- def test_version12_valid(self):
- heap = self.CreateTmpFile("Android Native Heap Dump v1.2" + self._heap_data + self._map_data)
- self.assertTrue(native_heapdump_viewer.GetNumFieldValid(heap))
-
-class ParseNativeHeapTest(NativeHeapdumpViewerTest):
- _backtrace_data = """
-z 1 sz 1000 num 4 bt 1000 2000 3000
-z 0 sz 8300 num 5 bt 1300 2300 3300
-"""
-
-
- def test_backtrace_num_field_valid(self):
- heap = self.CreateTmpFile(self._backtrace_data)
- backtraces, mapppings = native_heapdump_viewer.ParseNativeHeap(heap, False, True, "")
- self.assertTrue(backtraces)
- self.assertEqual(2, len(backtraces))
-
- self.assertFalse(backtraces[0].is_zygote)
- self.assertEqual(1000, backtraces[0].size)
- self.assertEqual(4, backtraces[0].num_allocs)
- self.assertEqual([0x1000, 0x2000, 0x3000], backtraces[0].frames)
-
- self.assertTrue(backtraces[1].is_zygote)
- self.assertEqual(8300, backtraces[1].size)
- self.assertEqual(5, backtraces[1].num_allocs)
- self.assertEqual([0x1300, 0x2300, 0x3300], backtraces[1].frames)
-
- def test_backtrace_num_field_invalid(self):
- heap = self.CreateTmpFile(self._backtrace_data)
- backtraces, mapppings = native_heapdump_viewer.ParseNativeHeap(heap, False, False, "")
- self.assertTrue(backtraces)
- self.assertEqual(2, len(backtraces))
-
- self.assertFalse(backtraces[0].is_zygote)
- self.assertEqual(1000, backtraces[0].size)
- self.assertEqual(1, backtraces[0].num_allocs)
- self.assertEqual([0x1000, 0x2000, 0x3000], backtraces[0].frames)
-
- self.assertTrue(backtraces[1].is_zygote)
- self.assertEqual(8300, backtraces[1].size)
- self.assertEqual(1, backtraces[1].num_allocs)
- self.assertEqual([0x1300, 0x2300, 0x3300], backtraces[1].frames)
-
- def test_backtrace_reverse_field_valid(self):
- heap = self.CreateTmpFile(self._backtrace_data)
- backtraces, mapppings = native_heapdump_viewer.ParseNativeHeap(heap, True, True, "")
- self.assertTrue(backtraces)
- self.assertEqual(2, len(backtraces))
-
- self.assertFalse(backtraces[0].is_zygote)
- self.assertEqual(1000, backtraces[0].size)
- self.assertEqual(4, backtraces[0].num_allocs)
- self.assertEqual([0x3000, 0x2000, 0x1000], backtraces[0].frames)
-
- self.assertTrue(backtraces[1].is_zygote)
- self.assertEqual(8300, backtraces[1].size)
- self.assertEqual(5, backtraces[1].num_allocs)
- self.assertEqual([0x3300, 0x2300, 0x1300], backtraces[1].frames)
-
- def test_mappings(self):
- map_data = """
-MAPS
-1000-4000 r-xp 00000000 fd:00 495 /system/lib64/libc.so
-6000-8000 r-xp 00000000 fd:00 495
-a000-f000 r-xp 0000b000 fd:00 495 /system/lib64/libutils.so
-END
-"""
-
- heap = self.CreateTmpFile(map_data)
- backtraces, mappings = native_heapdump_viewer.ParseNativeHeap(heap, True, True, "")
-
- self.assertTrue(mappings)
- self.assertEqual(2, len(mappings))
-
- self.assertEqual(0x1000, mappings[0].start)
- self.assertEqual(0x4000, mappings[0].end)
- self.assertEqual(0, mappings[0].offset)
- self.assertEqual("/system/lib64/libc.so", mappings[0].name)
-
- self.assertEqual(0xa000, mappings[1].start)
- self.assertEqual(0xf000, mappings[1].end)
- self.assertEqual(0xb000, mappings[1].offset)
- self.assertEqual("/system/lib64/libutils.so", mappings[1].name)
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/scripts/symbol.py b/scripts/symbol.py
index 821da8e..d74d506 100755
--- a/scripts/symbol.py
+++ b/scripts/symbol.py
@@ -438,8 +438,8 @@
if not _CACHED_CXX_FILT:
toolchains = None
# TODO(b/187231324) do not hard-code prebuilt version number below
- if os.path.exists('./clang-r416183b/bin/llvm-cxxfilt'):
- toolchains = ["./clang-r416183b/bin/llvm-cxxfilt"]
+ if os.path.exists('./clang-r416183b1/bin/llvm-cxxfilt'):
+ toolchains = ["./clang-r416183b1/bin/llvm-cxxfilt"]
if not toolchains:
raise Exception("Could not find llvm-cxxfilt tool")
_CACHED_CXX_FILT = sorted(toolchains)[-1]
diff --git a/sdk/plat_tools_source.prop_template b/sdk/plat_tools_source.prop_template
index cdbfd93..ae94420 100644
--- a/sdk/plat_tools_source.prop_template
+++ b/sdk/plat_tools_source.prop_template
@@ -1,2 +1,2 @@
Pkg.UserSrc=false
-Pkg.Revision=31.0.2
+Pkg.Revision=31.0.3