Merge "hiddenapi: Fix class hierarchy traversal"
diff --git a/Android.mk b/Android.mk
index 1a5daff..526cd59 100644
--- a/Android.mk
+++ b/Android.mk
@@ -483,6 +483,28 @@
 build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUTS)
 
 ########################################################################
+# Workaround for not using symbolic links for linker and bionic libraries
+# in a minimal setup (eg buildbot or golem).
+########################################################################
+
+PRIVATE_BIONIC_FILES := \
+  bin/bootstrap/linker \
+  bin/bootstrap/linker64 \
+  lib/bootstrap/libc.so \
+  lib/bootstrap/libm.so \
+  lib/bootstrap/libdl.so \
+  lib64/bootstrap/libc.so \
+  lib64/bootstrap/libm.so \
+  lib64/bootstrap/libdl.so 
+
+.PHONY: art-bionic-files
+art-bionic-files: libc.bootstrap libdl.bootstrap libm.bootstrap linker
+	for f in $(PRIVATE_BIONIC_FILES); do \
+	  tf=$(TARGET_OUT)/$$f; \
+	  if [ -f $$tf ]; then cp -f $$tf $$(echo $$tf | sed 's,bootstrap/,,'); fi; \
+	done
+
+########################################################################
 # Phony target for only building what go/lem requires for pushing ART on /data.
 
 .PHONY: build-art-target-golem
@@ -514,7 +536,8 @@
                         $(TARGET_CORE_IMG_OUT_BASE).art \
                         $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art \
                         libc.bootstrap libdl.bootstrap libm.bootstrap \
-                        icu-data-art-test
+                        icu-data-art-test \
+                        art-bionic-files
 	# remove debug libraries from public.libraries.txt because golem builds
 	# won't have it.
 	sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index b6d6600..e1b5b62 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -28,7 +28,7 @@
 #include "jni/java_vm_ext.h"
 #include "jni/jni_env_ext.h"
 #include "mirror/throwable.h"
-#include "nativehelper/ScopedLocalRef.h"
+#include "nativehelper/scoped_local_ref.h"
 #include "runtime-inl.h"
 #include "runtime_callbacks.h"
 #include "scoped_thread_state_change-inl.h"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index eac3511..21eee7a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -385,6 +385,7 @@
     art_hiddenapi_tests \
     art_imgdiag_tests \
     art_libartbase_tests \
+    art_libartpalette_tests \
     art_libdexfile_external_tests \
     art_libdexfile_support_tests \
     art_libdexfile_tests \
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index d53a7f2..4a6637b 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -29,10 +29,16 @@
 ]
 // - Debug variants (binaries for which a 32-bit version is preferred).
 art_runtime_debug_binaries_prefer32 = [
-    "dex2oatd",
     "dexoptanalyzerd",
     "profmand",
 ]
+art_runtime_debug_binaries_prefer32_device = [
+    "dex2oatd",
+]
+art_runtime_debug_binaries_both_host = [
+    "dex2oatd",
+]
+
 // - Debug variants (libraries).
 art_runtime_debug_native_shared_libs = [
     "libartd",
@@ -165,7 +171,8 @@
         },
         prefer32: {
             binaries: art_runtime_base_binaries_prefer32
-                + art_runtime_debug_binaries_prefer32,
+                + art_runtime_debug_binaries_prefer32
+                + art_runtime_debug_binaries_prefer32_device,
         },
         first: {
             binaries: art_tools_device_binaries,
@@ -188,6 +195,8 @@
     host_supported: true,
     device_supported: false,
     manifest: "manifest.json",
+    java_libs: libcore_target_java_libs,
+    ignore_system_library_special_case: true,
     native_shared_libs: art_runtime_base_native_shared_libs
         + art_runtime_debug_native_shared_libs
         + libcore_native_shared_libs
@@ -196,7 +205,8 @@
         both: {
             // TODO: Add logic to create a `dalvikvm` symlink to `dalvikvm32` or `dalvikvm64`
             // (see `symlink_preferred_arch` in art/dalvikvm/Android.bp).
-            binaries: art_runtime_base_binaries_both,
+            binaries: art_runtime_base_binaries_both
+                + art_runtime_debug_binaries_both_host,
         },
         first: {
             binaries: art_tools_host_binaries
@@ -209,5 +219,14 @@
         darwin: {
             enabled: false,
         },
+        linux_bionic: {
+            enabled: true,
+            multilib: {
+                both: {
+                    native_shared_libs: bionic_native_shared_libs,
+                    binaries: bionic_binaries_both,
+                }
+            }
+        },
     },
 }
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
new file mode 100755
index 0000000..1abc466
--- /dev/null
+++ b/build/apex/art_apex_test.py
@@ -0,0 +1,656 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2019 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 argparse
+import logging
+import os
+import subprocess
+import sys
+import zipfile
+
+logging.basicConfig(format='%(message)s')
+
+class FSObject:
+  def __init__(self, name, is_dir, is_exec, is_symlink):
+    self.name = name
+    self.is_dir = is_dir
+    self.is_exec = is_exec
+    self.is_symlink = is_symlink
+  def __str__(self):
+    return '%s(dir=%r,exec=%r,symlink=%r)' % (self.name, self.is_dir, self.is_exec, self.is_symlink)
+
+class TargetApexProvider:
+  def __init__(self, apex, tmpdir, debugfs):
+    self._tmpdir = tmpdir
+    self._debugfs = debugfs
+    self._folder_cache = {}
+    self._payload = os.path.join(self._tmpdir, 'apex_payload.img')
+    # Extract payload to tmpdir.
+    zip = zipfile.ZipFile(apex)
+    zip.extract('apex_payload.img', tmpdir)
+
+  def __del__(self):
+    # Delete temps.
+    if os.path.exists(self._payload):
+      os.remove(self._payload)
+
+  def get(self, path):
+    dir, name = os.path.split(path)
+    if len(dir) == 0:
+      dir = '.'
+    map = self.read_dir(dir)
+    return map[name] if name in map else None
+
+  def read_dir(self, dir):
+    if dir in self._folder_cache:
+      return self._folder_cache[dir]
+    # Cannot use check_output as it will annoy with stderr.
+    process = subprocess.Popen([self._debugfs, '-R', 'ls -l -p %s' % (dir), self._payload],
+                               stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                               universal_newlines=True)
+    stdout, stderr = process.communicate()
+    res = str(stdout)
+    map = {}
+    # Debugfs output looks like this:
+    #   debugfs 1.44.4 (18-Aug-2018)
+    #   /12/040755/0/2000/.//
+    #   /2/040755/1000/1000/..//
+    #   /13/100755/0/2000/dalvikvm32/28456/
+    #   /14/100755/0/2000/dexoptanalyzer/20396/
+    #   /15/100755/0/2000/linker/1152724/
+    #   /16/100755/0/2000/dex2oat/563508/
+    #   /17/100755/0/2000/linker64/1605424/
+    #   /18/100755/0/2000/profman/85304/
+    #   /19/100755/0/2000/dalvikvm64/28576/
+    #    |     |   |   |       |        |
+    #    |     |   |   #- gid  #- name  #- size
+    #    |     |   #- uid
+    #    |     #- type and permission bits
+    #    #- inode nr (?)
+    #
+    # Note: could break just on '/' to avoid names with newlines.
+    for line in res.split("\n"):
+      if not line:
+        continue
+      comps = line.split('/')
+      if len(comps) != 8:
+        logging.warn('Could not break and parse line \'%s\'', line)
+        continue
+      bits = comps[2]
+      name = comps[5]
+      if len(bits) != 6:
+        logging.warn('Dont understand bits \'%s\'', bits)
+        continue
+      is_dir = True if bits[1] == '4' else False
+      def is_exec_bit(ch):
+        return True if int(ch) & 1 == 1 else False
+      is_exec = is_exec_bit(bits[3]) and is_exec_bit(bits[4]) and is_exec_bit(bits[5])
+      is_symlink = True if bits[1] == '2' else False
+      map[name] = FSObject(name, is_dir, is_exec, is_symlink)
+    self._folder_cache[dir] = map
+    return map
+
+class HostApexProvider:
+  def __init__(self, apex, tmpdir):
+    self._tmpdir = tmpdir
+    self._folder_cache = {}
+    self._payload = os.path.join(self._tmpdir, 'apex_payload.zip')
+    # Extract payload to tmpdir.
+    zip = zipfile.ZipFile(apex)
+    zip.extract('apex_payload.zip', tmpdir)
+
+  def __del__(self):
+    # Delete temps.
+    if os.path.exists(self._payload):
+      os.remove(self._payload)
+
+  def get(self, path):
+    dir, name = os.path.split(path)
+    if len(dir) == 0:
+      dir = ''
+    map = self.read_dir(dir)
+    return map[name] if name in map else None
+
+  def read_dir(self, dir):
+    if dir in self._folder_cache:
+      return self._folder_cache[dir]
+    if not self._folder_cache:
+      self.parse_zip()
+    if dir in self._folder_cache:
+      return self._folder_cache[dir]
+    return {}
+
+  def parse_zip(self):
+    zip = zipfile.ZipFile(self._payload)
+    infos = zip.infolist()
+    for zipinfo in infos:
+      path = zipinfo.filename
+
+      # Assume no empty file is stored.
+      assert path
+
+      def get_octal(val, index):
+        return (val >> (index * 3)) & 0x7;
+      def bits_is_exec(val):
+        # TODO: Enforce group/other, too?
+        return get_octal(val, 2) & 1 == 1
+
+      is_zipinfo = True
+      while path:
+        dir, base = os.path.split(path)
+        # TODO: If directories are stored, base will be empty.
+
+        if not dir in self._folder_cache:
+          self._folder_cache[dir] = {}
+        dir_map = self._folder_cache[dir]
+        if not base in dir_map:
+          if is_zipinfo:
+            bits = (zipinfo.external_attr >> 16) & 0xFFFF
+            is_dir = get_octal(bits, 4) == 4
+            is_symlink = get_octal(bits, 4) == 2
+            is_exec = bits_is_exec(bits)
+          else:
+            is_exec = False  # Seems we can't get this easily?
+            is_symlink = False
+            is_dir = True
+          dir_map[base] = FSObject(base, is_dir, is_exec, is_symlink)
+        is_zipinfo = False
+        path = dir
+
+# DO NOT USE DIRECTLY! This is an "abstract" base class.
+class Checker:
+  def __init__(self, provider):
+    self._provider = provider
+    self._errors = 0
+
+  def fail(self, msg, *args):
+    self._errors += 1
+    logging.error(msg, args)
+
+  def error_count(self):
+    return self._errors
+  def reset_errors(self):
+    self._errors = 0
+
+  def is_file(self, file):
+    fs_object = self._provider.get(file)
+    if fs_object is None:
+      return (False, 'Could not find %s')
+    if fs_object.is_dir:
+      return (False, '%s is a directory')
+    return (True, '')
+
+  def check_file(self, file):
+    chk = self.is_file(file)
+    if not chk[0]:
+      self.fail(chk[1], file)
+    return chk[0]
+  def check_no_file(self, file):
+    chk = self.is_file(file)
+    if chk[0]:
+      self.fail('File %s does exist', file)
+    return not chk[0]
+
+  def check_binary(self, file):
+    path = 'bin/%s' % (file)
+    if not self.check_file(path):
+      return False
+    if not self._provider.get(path).is_exec:
+      self.fail('%s is not executable', path)
+      return False
+    return True
+
+  def check_binary_symlink(self, file):
+    path = 'bin/%s' % (file)
+    fs_object = self._provider.get(path)
+    if fs_object is None:
+      self.fail('Could not find %s', path)
+      return False
+    if fs_object.is_dir:
+      self.fail('%s is a directory', path)
+      return False
+    if not fs_object.is_symlink:
+      self.fail('%s is not a symlink', path)
+      return False
+    return True
+
+  def check_single_library(self, file):
+    res1 = self.is_file('lib/%s' % (file))
+    res2 = self.is_file('lib64/%s' % (file))
+    if not res1[0] and not res2[0]:
+      self.fail('Library missing: %s', file)
+      return False
+    return True
+
+  def check_no_library(self, file):
+    res1 = self.is_file('lib/%s' % (file))
+    res2 = self.is_file('lib64/%s' % (file))
+    if res1[0] or res2[0]:
+      self.fail('Library exists: %s', file)
+      return False
+    return True
+
+  def check_java_library(self, file):
+    return self.check_file('javalib/%s' % (file))
+
+  # Just here for docs purposes, even if it isn't good Python style.
+
+  def check_library(self, file):
+    raise NotImplementedError
+
+  def check_first_library(self, file):
+    raise NotImplementedError
+
+  def check_multilib_binary(self, file):
+    raise NotImplementedError
+
+  def check_prefer32_binary(self, file):
+    raise NotImplementedError
+
+
+class Arch32Checker(Checker):
+  def __init__(self, provider):
+    super().__init__(provider)
+
+  def check_multilib_binary(self, file):
+    return all([self.check_binary('%s32' % (file)),
+                self.check_no_file('bin/%s64' % (file)),
+                self.check_binary_symlink(file)])
+
+  def check_library(self, file):
+    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
+    # the precision of this test?
+    return all([self.check_file('lib/%s' % (file)), self.check_no_file('lib64/%s' % (file))])
+
+  def check_first_library(self, file):
+    return self.check_library(file)
+
+  def check_prefer32_binary(self, file):
+    return self.check_binary('%s32' % (file))
+
+
+class Arch64Checker(Checker):
+  def __init__(self, provider):
+    super().__init__(provider)
+
+  def check_multilib_binary(self, file):
+    return all([self.check_no_file('bin/%s32' % (file)),
+                self.check_binary('%s64' % (file)),
+                self.check_binary_symlink(file)])
+
+  def check_library(self, file):
+    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
+    # the precision of this test?
+    return all([self.check_no_file('lib/%s' % (file)), self.check_file('lib64/%s' % (file))])
+
+  def check_first_library(self, file):
+    return self.check_library(file)
+
+  def check_prefer32_binary(self, file):
+    return self.check_binary('%s64' % (file))
+
+
+class MultilibChecker(Checker):
+  def __init__(self, provider):
+    super().__init__(provider)
+
+  def check_multilib_binary(self, file):
+    return all([self.check_binary('%s32' % (file)),
+                self.check_binary('%s64' % (file)),
+                self.check_binary_symlink(file)])
+
+  def check_library(self, file):
+    # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
+    # the precision of this test?
+    return all([self.check_file('lib/%s' % (file)), self.check_file('lib64/%s' % (file))])
+
+  def check_first_library(self, file):
+    return all([self.check_no_file('lib/%s' % (file)), self.check_file('lib64/%s' % (file))])
+
+  def check_prefer32_binary(self, file):
+    return self.check_binary('%s32' % (file))
+
+
+class ReleaseChecker:
+  def __init__(self, checker):
+    self._checker = checker
+  def __str__(self):
+    return 'Release Checker'
+
+  def run(self):
+    # Check that the mounted image contains an APEX manifest.
+    self._checker.check_file('apex_manifest.json')
+
+    # Check that the mounted image contains ART base binaries.
+    self._checker.check_multilib_binary('dalvikvm')
+    self._checker.check_binary('dex2oat')
+    self._checker.check_binary('dexoptanalyzer')
+    self._checker.check_binary('profman')
+
+    # oatdump is only in device apex's due to build rules
+    # TODO: Check for it when it is also built for host.
+    # self._checker.check_binary('oatdump')
+
+    # Check that the mounted image contains Android Runtime libraries.
+    self._checker.check_library('libart-compiler.so')
+    self._checker.check_library('libart-dexlayout.so')
+    self._checker.check_library('libart.so')
+    self._checker.check_library('libartbase.so')
+    self._checker.check_library('libartpalette.so')
+    self._checker.check_no_library('libartpalette-system.so')
+    self._checker.check_library('libdexfile.so')
+    self._checker.check_library('libopenjdkjvm.so')
+    self._checker.check_library('libopenjdkjvmti.so')
+    self._checker.check_library('libprofile.so')
+    # Check that the mounted image contains Android Core libraries.
+    # Note: host vs target libs are checked elsewhere.
+    self._checker.check_library('libjavacore.so')
+    self._checker.check_library('libopenjdk.so')
+    self._checker.check_library('libziparchive.so')
+    # Check that the mounted image contains additional required libraries.
+    self._checker.check_library('libadbconnection.so')
+
+    # TODO: Should we check for other libraries, such as:
+    #
+    #   libbacktrace.so
+    #   libbase.so
+    #   liblog.so
+    #   libsigchain.so
+    #   libtombstoned_client.so
+    #   libunwindstack.so
+    #   libvixl.so
+    #   libvixld.so
+    #   ...
+    #
+    # ?
+
+    self._checker.check_java_library('core-oj.jar')
+    self._checker.check_java_library('core-libart.jar')
+    self._checker.check_java_library('okhttp.jar')
+    self._checker.check_java_library('bouncycastle.jar')
+    self._checker.check_java_library('apache-xml.jar')
+
+class ReleaseTargetChecker:
+  def __init__(self, checker):
+    self._checker = checker
+  def __str__(self):
+    return 'Release (Target) Checker'
+
+  def run(self):
+    # Check that the mounted image contains Android Core libraries.
+    self._checker.check_library('libexpat.so')
+    self._checker.check_library('libz.so')
+
+class ReleaseHostChecker:
+  def __init__(self, checker):
+    self._checker = checker;
+  def __str__(self):
+    return 'Release (Host) Checker'
+
+  def run(self):
+    # Check that the mounted image contains Android Core libraries.
+    self._checker.check_library('libexpat-host.so')
+    self._checker.check_library('libz-host.so')
+
+class DebugChecker:
+  def __init__(self, checker):
+    self._checker = checker
+  def __str__(self):
+    return 'Debug Checker'
+
+  def run(self):
+    # Check that the mounted image contains ART tools binaries.
+    self._checker.check_binary('dexdiag')
+    self._checker.check_binary('dexdump')
+    self._checker.check_binary('dexlist')
+
+    # Check that the mounted image contains ART debug binaries.
+    self._checker.check_binary('dex2oatd')
+    self._checker.check_binary('dexoptanalyzerd')
+    self._checker.check_binary('profmand')
+
+    # Check that the mounted image contains Android Runtime debug libraries.
+    self._checker.check_library('libartbased.so')
+    self._checker.check_library('libartd-compiler.so')
+    self._checker.check_library('libartd-dexlayout.so')
+    self._checker.check_library('libartd.so')
+    self._checker.check_library('libdexfiled.so')
+    self._checker.check_library('libopenjdkjvmd.so')
+    self._checker.check_library('libopenjdkjvmtid.so')
+    self._checker.check_library('libprofiled.so')
+    # Check that the mounted image contains Android Core debug libraries.
+    self._checker.check_library('libopenjdkd.so')
+    # Check that the mounted image contains additional required debug libraries.
+    self._checker.check_library('libadbconnectiond.so')
+
+class DebugTargetChecker:
+  def __init__(self, checker):
+    self._checker = checker
+  def __str__(self):
+    return 'Debug (Target) Checker'
+
+  def run(self):
+    # Check for files pulled in from debug target-only oatdump.
+    self._checker.check_binary('oatdump')
+    self._checker.check_first_library('libart-disassembler.so')
+
+def print_list(provider):
+    def print_list_impl(provider, path):
+      map = provider.read_dir(path)
+      if map is None:
+        return
+      map = dict(map)
+      if '.' in map:
+        del map['.']
+      if '..' in map:
+        del map['..']
+      for (_, val) in sorted(map.items()):
+        new_path = os.path.join(path, val.name)
+        print(new_path)
+        if val.is_dir:
+          print_list_impl(provider, new_path)
+    print_list_impl(provider, '')
+
+def print_tree(provider, title):
+    def get_vertical(has_next_list):
+      str = ''
+      for v in has_next_list:
+        str += '%s   ' % ('│' if v else ' ')
+      return str
+    def get_last_vertical(last):
+      return '└── ' if last else '├── ';
+    def print_tree_impl(provider, path, has_next_list):
+      map = provider.read_dir(path)
+      if map is None:
+        return
+      map = dict(map)
+      if '.' in map:
+        del map['.']
+      if '..' in map:
+        del map['..']
+      key_list = list(sorted(map.keys()))
+      for i in range(0, len(key_list)):
+        val = map[key_list[i]]
+        prev = get_vertical(has_next_list)
+        last = get_last_vertical(i == len(key_list) - 1)
+        print('%s%s%s' % (prev, last, val.name))
+        if val.is_dir:
+          has_next_list.append(i < len(key_list) - 1)
+          print_tree_impl(provider, os.path.join(path, val.name), has_next_list)
+          has_next_list.pop()
+    print('%s' % (title))
+    print_tree_impl(provider, '', [])
+
+# Note: do not sys.exit early, for __del__ cleanup.
+def artApexTestMain(args):
+  if args.tree and args.debug:
+    logging.error("Both of --tree and --debug set")
+    return 1
+  if args.list and args.debug:
+    logging.error("Both of --list and --debug set")
+    return 1
+  if args.list and args.tree:
+    logging.error("Both of --list and --tree set")
+    return 1
+  if not args.tmpdir:
+    logging.error("Need a tmpdir.")
+    return 1
+  if not args.host and not args.debugfs:
+    logging.error("Need debugfs.")
+    return 1
+  if args.bitness not in ['32', '64', 'multilib', 'auto']:
+    logging.error('--bitness needs to be one of 32|64|multilib|auto')
+
+  try:
+    if args.host:
+      apex_provider = HostApexProvider(args.apex, args.tmpdir)
+    else:
+      apex_provider = TargetApexProvider(args.apex, args.tmpdir, args.debugfs)
+  except Exception as e:
+    logging.error('Failed to create provider: %s', e)
+    return 1
+
+  if args.tree:
+    print_tree(apex_provider, args.apex)
+    return 0
+  if args.list:
+    print_list(apex_provider)
+    return 0
+
+  checkers = []
+  if args.bitness == 'auto':
+    logging.warn('--bitness=auto, trying to autodetect. This may be incorrect!')
+    has_32 = apex_provider.get('lib') is not None
+    has_64 = apex_provider.get('lib64') is not None
+    if has_32 and has_64:
+      logging.warn('  Detected multilib')
+      args.bitness = 'multilib'
+    elif has_32:
+      logging.warn('  Detected 32-only')
+      args.bitness = '32'
+    elif has_64:
+      logging.warn('  Detected 64-only')
+      args.bitness = '64'
+    else:
+      logging.error('  Could not detect bitness, neither lib nor lib64 contained.')
+      print('%s' % (apex_provider._folder_cache))
+      return 1
+
+  if args.bitness == '32':
+    base_checker = Arch32Checker(apex_provider)
+  elif args.bitness == '64':
+    base_checker = Arch64Checker(apex_provider)
+  else:
+    assert args.bitness == 'multilib'
+    base_checker = MultilibChecker(apex_provider)
+
+  checkers.append(ReleaseChecker(base_checker))
+  if args.host:
+    checkers.append(ReleaseHostChecker(base_checker))
+  else:
+    checkers.append(ReleaseTargetChecker(base_checker))
+  if args.debug:
+    checkers.append(DebugChecker(base_checker))
+  if args.debug and not args.host:
+    checkers.append(DebugTargetChecker(base_checker))
+
+  failed = False
+  for checker in checkers:
+    logging.info('%s...', checker)
+    checker.run()
+    if base_checker.error_count() > 0:
+      logging.error('%s FAILED', checker)
+      failed = True
+    else:
+      logging.info('%s SUCCEEDED', checker)
+    base_checker.reset_errors()
+
+  return 1 if failed else 0
+
+def artApexTestDefault(parser):
+  if not 'ANDROID_PRODUCT_OUT' in os.environ:
+    logging.error('No-argument use requires ANDROID_PRODUCT_OUT')
+    sys.exit(1)
+  product_out = os.environ['ANDROID_PRODUCT_OUT']
+  if not 'ANDROID_HOST_OUT' in os.environ:
+    logging.error('No-argument use requires ANDROID_HOST_OUT')
+    sys.exit(1)
+  host_out = os.environ['ANDROID_HOST_OUT']
+
+  args = parser.parse_args(['dummy'])  # For consistency.
+  args.debugfs = '%s/bin/debugfs' % (host_out)
+  args.tmpdir = '.'
+  args.tree = False
+  args.list = False
+  args.bitness = 'auto'
+  failed = False
+
+  if not os.path.exists(args.debugfs):
+    logging.error("Cannot find debugfs (default path %s). Please build it, e.g., m debugfs",
+                  args.debugfs)
+    sys.exit(1)
+
+  # TODO: Add host support
+  configs= [
+    {'name': 'com.android.runtime.release', 'debug': False, 'host': False},
+    {'name': 'com.android.runtime.debug', 'debug': True, 'host': False},
+  ]
+
+  for config in configs:
+    logging.info(config['name'])
+    # TODO: Host will need different path.
+    args.apex = '%s/system/apex/%s.apex' % (product_out, config['name'])
+    if not os.path.exists(args.apex):
+      failed = True
+      logging.error("Cannot find APEX %s. Please build it first.", args.apex)
+      continue
+    args.debug = config['debug']
+    args.host = config['host']
+    exit_code = artApexTestMain(args)
+    if exit_code != 0:
+      failed = True
+
+  if failed:
+    sys.exit(1)
+
+if __name__ == "__main__":
+  parser = argparse.ArgumentParser(description='Check integrity of a Runtime APEX.')
+
+  parser.add_argument('apex', help='apex file input')
+
+  parser.add_argument('--host', help='Check as host apex', action='store_true')
+
+  parser.add_argument('--debug', help='Check as debug apex', action='store_true')
+
+  parser.add_argument('--list', help='List all files', action='store_true')
+  parser.add_argument('--tree', help='Print directory tree', action='store_true')
+
+  parser.add_argument('--tmpdir', help='Directory for temp files')
+  parser.add_argument('--debugfs', help='Path to debugfs')
+
+  parser.add_argument('--bitness', help='Bitness to check, 32|64|multilib|auto', default='auto')
+
+  if len(sys.argv) == 1:
+    artApexTestDefault(parser)
+  else:
+    args = parser.parse_args()
+
+    if args is None:
+      sys.exit(1)
+
+    exit_code = artApexTestMain(args)
+    sys.exit(exit_code)
diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt
index b2637a9..9bf2ae5 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -33,6 +33,17 @@
 namespace.platform.link.default.shared_libs += libnativebridge.so
 namespace.platform.link.default.shared_libs += libnativehelper.so
 namespace.platform.link.default.shared_libs += libnativeloader.so
+# /system/lib/libc.so, etc are symlinks to /bionic/lib/libc.so, etc.
+# Add /bionic/lib to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib. We could add this to search.paths
+# instead but that makes the resolution of bionic libs be dependent on
+# the order of /system/lib and /bionic/lib in search.paths. If /bionic/lib
+# is after /system/lib, then /bionic/lib is never tried because libc.so
+# is always found in /system/lib but fails to pass the accessibility test
+# because of its realpath.  It's better to not depend on the ordering if
+# possible.
+namespace.platform.permitted.paths = /bionic/${LIB}
+namespace.platform.asan.permitted.paths = /bionic/${LIB}
 
 # Note that we don't need to link the default namespace with conscrypt:
 # the runtime Java code and binaries do not explicitly load native libraries
@@ -50,7 +61,8 @@
 
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = platform
+namespace.conscrypt.links = runtime,platform
+namespace.conscrypt.link.runtime.shared_libs   = libjavacore.so
 namespace.conscrypt.link.platform.shared_libs  = libc.so
 namespace.conscrypt.link.platform.shared_libs += libm.so
 namespace.conscrypt.link.platform.shared_libs += libdl.so
@@ -64,6 +76,6 @@
 namespace.runtime.visible = true
 namespace.runtime.links = default
 namespace.runtime.link.default.allow_all_shared_libs = true
-namespace.runtime.links = platform
+namespace.runtime.links += platform
 # TODO(b/119867084): Restrict fallback to platform namespace to PALette library.
 namespace.runtime.link.platform.allow_all_shared_libs = true
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index 84c0f4f..95c1de9 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -17,6 +17,8 @@
 
 # Run Android Runtime APEX tests.
 
+SCRIPT_DIR=$(dirname $0)
+
 # Status of whole test script.
 exit_status=0
 # Status of current test suite.
@@ -31,17 +33,17 @@
   exit 1
 }
 
-which guestmount >/dev/null && which guestunmount >/dev/null && which virt-filesystems >/dev/null \
-  || die "This script requires 'guestmount', 'guestunmount',
-and 'virt-filesystems' from libguestfs. On Debian-based systems, these tools
-can be installed with:
-
-   sudo apt-get install libguestfs-tools
-"
-
 [[ -n "$ANDROID_PRODUCT_OUT" ]] \
   || die "You need to source and lunch before you can use this script."
 
+[[ -n "$ANDROID_HOST_OUT" ]] \
+  || die "You need to source and lunch before you can use this script."
+
+if [ ! -e "$ANDROID_HOST_OUT/bin/debugfs" ] ; then
+  say "Could not find debugfs, building now."
+  make debugfs-host || die "Cannot build debugfs"
+fi
+
 # Fail early.
 set -e
 
@@ -75,15 +77,6 @@
   shift
 done
 
-if $print_image_tree_p; then
-  which tree >/dev/null || die "This script requires the 'tree' tool.
-On Debian-based systems, this can be installed with:
-
-   sudo apt-get install tree
-"
-fi
-
-
 # build_apex APEX_MODULE
 # ----------------------
 # Build APEX package APEX_MODULE.
@@ -94,21 +87,22 @@
   fi
 }
 
-# maybe_list_apex_contents MOUNT_POINT
-# ------------------------------------
-# If any listing/printing option was used, honor them and display the contents
-# of the APEX payload at MOUNT_POINT.
-function maybe_list_apex_contents {
-  local mount_point=$1
+# maybe_list_apex_contents_apex APEX TMPDIR [other]
+function maybe_list_apex_contents_apex {
+  local apex=$1
+  local tmpdir=$2
+  shift 2
 
-  # List the contents of the mounted image using `find` (optional).
+  # List the contents of the apex in list form.
   if $list_image_files_p; then
-    say "Listing image files" && find "$mount_point"
+    say "Listing image files"
+    $SCRIPT_DIR/art_apex_test.py --list --tmpdir "$tmpdir" $@ $apex
   fi
 
-  # List the contents of the mounted image using `tree` (optional).
+  # List the contents of the apex in tree form.
   if $print_image_tree_p; then
-    say "Printing image tree" && ls -ld "$mount_point" && tree -aph --du "$mount_point"
+    say "Printing image tree"
+    $SCRIPT_DIR/art_apex_test.py --tree --tmpdir "$tmpdir" $@ $apex
   fi
 }
 
@@ -118,129 +112,11 @@
   exit_status=1
 }
 
-function check_file {
-  [[ -f "$mount_point/$1" ]] || fail_check "Cannot find file '$1' in mounted image"
-}
-
-function check_binary {
-  [[ -x "$mount_point/bin/$1" ]] || fail_check "Cannot find binary '$1' in mounted image"
-}
-
-function check_multilib_binary {
-  # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
-  # the precision of this test?
-  [[ -x "$mount_point/bin/${1}32" ]] || [[ -x "$mount_point/bin/${1}64" ]] \
-    || fail_check "Cannot find binary '$1' in mounted image"
-}
-
-function check_binary_symlink {
-  [[ -h "$mount_point/bin/$1" ]] || fail_check "Cannot find symbolic link '$1' in mounted image"
-}
-
-function check_library {
-  # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
-  # the precision of this test?
-  [[ -f "$mount_point/lib/$1" ]] || [[ -f "$mount_point/lib64/$1" ]] \
-    || fail_check "Cannot find library '$1' in mounted image"
-}
-
-function check_java_library {
-  [[ -x "$mount_point/javalib/$1" ]] || fail_check "Cannot find java library '$1' in mounted image"
-}
-
-# Check contents of APEX payload located in `$mount_point`.
-function check_release_contents {
-  # Check that the mounted image contains an APEX manifest.
-  check_file apex_manifest.json
-
-  # Check that the mounted image contains ART base binaries.
-  check_multilib_binary dalvikvm
-  # TODO: Does not work yet (b/119942078).
-  : check_binary_symlink dalvikvm
-  check_binary dex2oat
-  check_binary dexoptanalyzer
-  check_binary profman
-
-  # oatdump is only in device apex's due to build rules
-  # TODO: Check for it when it is also built for host.
-  : check_binary oatdump
-
-  # Check that the mounted image contains Android Runtime libraries.
-  check_library libart-compiler.so
-  check_library libart-dexlayout.so
-  check_library libart.so
-  check_library libartbase.so
-  check_library libdexfile.so
-  check_library libopenjdkjvm.so
-  check_library libopenjdkjvmti.so
-  check_library libprofile.so
-  # Check that the mounted image contains Android Core libraries.
-  check_library "libexpat${host_suffix}.so"
-  check_library libjavacore.so
-  check_library libjavacrypto.so
-  check_library libopenjdk.so
-  check_library "libz${host_suffix}.so"
-  check_library libziparchive.so
-  # Check that the mounted image contains additional required libraries.
-  check_library libadbconnection.so
-
-  # TODO: Should we check for other libraries, such as:
-  #
-  #   libbacktrace.so
-  #   libbase.so
-  #   liblog.so
-  #   libsigchain.so
-  #   libtombstoned_client.so
-  #   libunwindstack.so
-  #   libvixl.so
-  #   libvixld.so
-  #   ...
-  #
-  # ?
-
-  # TODO: Enable for host
-  if [ $1 != "com.android.runtime.host" ]; then
-    check_java_library core-oj.jar
-    check_java_library core-libart.jar
-    check_java_library okhttp.jar
-    check_java_library bouncycastle.jar
-    check_java_library apache-xml.jar
-  fi
-}
-
-# Check debug contents of APEX payload located in `$mount_point`.
-function check_debug_contents {
-  # Check that the mounted image contains ART tools binaries.
-  check_binary dexdiag
-  check_binary dexdump
-  check_binary dexlist
-
-  # Check that the mounted image contains ART debug binaries.
-  check_binary dex2oatd
-  check_binary dexoptanalyzerd
-  check_binary profmand
-
-  # Check that the mounted image contains Android Runtime debug libraries.
-  check_library libartbased.so
-  check_library libartd-compiler.so
-  check_library libartd-dexlayout.so
-  check_library libartd.so
-  check_library libdexfiled.so
-  check_library libopenjdkjvmd.so
-  check_library libopenjdkjvmtid.so
-  check_library libprofiled.so
-  # Check that the mounted image contains Android Core debug libraries.
-  check_library libopenjdkd.so
-  # Check that the mounted image contains additional required debug libraries.
-  check_library libadbconnectiond.so
-}
-
 # Testing target (device) APEX packages.
 # ======================================
 
 # Clean-up.
 function cleanup_target {
-  guestunmount "$mount_point"
   rm -rf "$work_dir"
 }
 
@@ -251,34 +127,6 @@
   cleanup_target
 }
 
-# setup_target_apex APEX_MODULE MOUNT_POINT
-# -----------------------------------------
-# Extract image from target APEX_MODULE and mount it in MOUNT_POINT.
-function setup_target_apex {
-  local apex_module=$1
-  local mount_point=$2
-  local system_apexdir="$ANDROID_PRODUCT_OUT/system/apex"
-  local apex_package="$system_apexdir/$apex_module.apex"
-
-  say "Extracting and mounting image"
-
-  # Extract the payload from the Android Runtime APEX.
-  local image_filename="apex_payload.img"
-  unzip -q "$apex_package" "$image_filename" -d "$work_dir"
-  mkdir "$mount_point"
-  local image_file="$work_dir/$image_filename"
-
-  # Check filesystems in the image.
-  local image_filesystems="$work_dir/image_filesystems"
-  virt-filesystems -a "$image_file" >"$image_filesystems"
-  # We expect a single partition (/dev/sda) in the image.
-  local partition="/dev/sda"
-  echo "$partition" | cmp "$image_filesystems" -
-
-  # Mount the image from the Android Runtime APEX.
-  guestmount -a "$image_file" -m "$partition" --ro "$mount_point"
-}
-
 # Testing release APEX package (com.android.runtime.release).
 # -----------------------------------------------------------
 
@@ -288,23 +136,23 @@
 say "Processing APEX package $apex_module"
 
 work_dir=$(mktemp -d)
-mount_point="$work_dir/image"
-host_suffix=""
 
 trap finish_target EXIT
 
 # Build the APEX package (optional).
 build_apex "$apex_module"
-
-# Set up APEX package.
-setup_target_apex "$apex_module" "$mount_point"
+apex_path="$ANDROID_PRODUCT_OUT/system/apex/${apex_module}.apex"
 
 # List the contents of the APEX image (optional).
-maybe_list_apex_contents "$mount_point"
+maybe_list_apex_contents_apex $apex_path $work_dir --debugfs $ANDROID_HOST_OUT/bin/debugfs
 
 # Run tests on APEX package.
 say "Checking APEX package $apex_module"
-check_release_contents "$apex_module"
+$SCRIPT_DIR/art_apex_test.py \
+  --tmpdir $work_dir \
+  --debugfs $ANDROID_HOST_OUT/bin/debugfs \
+  $apex_path \
+    || fail_check "Release checks failed"
 
 # Clean up.
 trap - EXIT
@@ -322,27 +170,24 @@
 say "Processing APEX package $apex_module"
 
 work_dir=$(mktemp -d)
-mount_point="$work_dir/image"
-host_suffix=""
 
 trap finish_target EXIT
 
 # Build the APEX package (optional).
 build_apex "$apex_module"
-
-# Set up APEX package.
-setup_target_apex "$apex_module" "$mount_point"
+apex_path="$ANDROID_PRODUCT_OUT/system/apex/${apex_module}.apex"
 
 # List the contents of the APEX image (optional).
-maybe_list_apex_contents "$mount_point"
+maybe_list_apex_contents_apex $apex_path $work_dir --debugfs $ANDROID_HOST_OUT/bin/debugfs
 
 # Run tests on APEX package.
 say "Checking APEX package $apex_module"
-check_release_contents "$apex_module"
-check_debug_contents
-# Check for files pulled in from debug target-only oatdump.
-check_binary oatdump
-check_library libart-disassembler.so
+$SCRIPT_DIR/art_apex_test.py \
+  --tmpdir $work_dir \
+  --debugfs $ANDROID_HOST_OUT/bin/debugfs \
+  --debug \
+  $apex_path \
+    || fail_check "Debug checks failed"
 
 # Clean up.
 trap - EXIT
@@ -367,51 +212,30 @@
   cleanup_host
 }
 
-# setup_host_apex APEX_MODULE MOUNT_POINT
-# ---------------------------------------
-# Extract Zip file from host APEX_MODULE and extract it in MOUNT_POINT.
-function setup_host_apex {
-  local apex_module=$1
-  local mount_point=$2
-  local system_apexdir="$ANDROID_HOST_OUT/apex"
-  local apex_package="$system_apexdir/$apex_module.zipapex"
-
-  say "Extracting payload"
-
-  # Extract the payload from the Android Runtime APEX.
-  local image_filename="apex_payload.zip"
-  unzip -q "$apex_package" "$image_filename" -d "$work_dir"
-  mkdir "$mount_point"
-  local image_file="$work_dir/$image_filename"
-
-  # Unzipping the payload
-  unzip -q "$image_file" -d "$mount_point"
-}
-
 apex_module="com.android.runtime.host"
 test_status=0
 
 say "Processing APEX package $apex_module"
 
 work_dir=$(mktemp -d)
-mount_point="$work_dir/zip"
-host_suffix="-host"
 
 trap finish_host EXIT
 
 # Build the APEX package (optional).
 build_apex "$apex_module"
-
-# Set up APEX package.
-setup_host_apex "$apex_module" "$mount_point"
+apex_path="$ANDROID_HOST_OUT/apex/${apex_module}.zipapex"
 
 # List the contents of the APEX image (optional).
-maybe_list_apex_contents "$mount_point"
+maybe_list_apex_contents_apex $apex_path $work_dir --host
 
 # Run tests on APEX package.
 say "Checking APEX package $apex_module"
-check_release_contents "$apex_module"
-check_debug_contents
+$SCRIPT_DIR/art_apex_test.py \
+  --tmpdir $work_dir \
+  --host \
+  --debug \
+  $apex_path \
+    || fail_check "Debug checks failed"
 
 # Clean up.
 trap - EXIT
diff --git a/build/art.go b/build/art.go
index 22f6410..5236e31 100644
--- a/build/art.go
+++ b/build/art.go
@@ -348,26 +348,7 @@
 func libartDefaultsFactory() android.Module {
 	c := &codegenProperties{}
 	module := cc.DefaultsFactory(c)
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		codegen(ctx, c, true)
-
-		type props struct {
-			Target struct {
-				Android struct {
-					Shared_libs []string
-				}
-			}
-		}
-
-		p := &props{}
-		// TODO: express this in .bp instead b/79671158
-		if !envTrue(ctx, "ART_TARGET_LINUX") {
-			p.Target.Android.Shared_libs = []string{
-				"libmetricslogger",
-			}
-		}
-		ctx.AppendProperties(p)
-	})
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
 
 	return module
 }
@@ -375,27 +356,7 @@
 func libartStaticDefaultsFactory() android.Module {
 	c := &codegenProperties{}
 	module := cc.DefaultsFactory(c)
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		codegen(ctx, c, true)
-
-		type props struct {
-			Target struct {
-				Android struct {
-					Static_libs []string
-				}
-			}
-		}
-
-		p := &props{}
-		// TODO: express this in .bp instead b/79671158
-		if !envTrue(ctx, "ART_TARGET_LINUX") {
-			p.Target.Android.Static_libs = []string{
-				"libmetricslogger",
-				"libstatssocket",
-			}
-		}
-		ctx.AppendProperties(p)
-	})
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {	codegen(ctx, c, true) })
 
 	return module
 }
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 0d92b05..0ebaa5f 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -182,7 +182,6 @@
     generated_sources: ["art_compiler_operator_srcs"],
     shared_libs: [
         "libbase",
-        "libcutils",  // for atrace.
     ],
     include_dirs: ["art/disassembler"],
     header_libs: [
@@ -197,7 +196,6 @@
     name: "libart-compiler_static_base_defaults",
     static_libs: [
         "libbase",
-        "libcutils",
     ],
 }
 
@@ -256,9 +254,10 @@
     },
     shared_libs: [
         "libart",
+        "libartbase",
+        "libartpalette",
         "libprofile",
         "libdexfile",
-        "libartbase",
     ],
 
     target: {
@@ -317,10 +316,11 @@
         },
     },
     shared_libs: [
+        "libartbased",
         "libartd",
+        "libartpalette",
         "libprofiled",
         "libdexfiled",
-        "libartbased",
     ],
 }
 
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index e440eec..d46cffb 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1765,6 +1765,42 @@
   }
 }
 
+// Returns true if any of the given dex files define a class from the boot classpath.
+static bool DexFilesRedefineBootClasses(
+    const std::vector<const DexFile*>& dex_files,
+    TimingLogger* timings) {
+  TimingLogger::ScopedTiming t("Fast Verify: Boot Class Redefinition Check", timings);
+
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+
+  bool foundRedefinition = false;
+  for (const DexFile* dex_file : dex_files) {
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      const char* descriptor = accessor.GetDescriptor();
+      StackHandleScope<1> hs_class(self);
+      Handle<mirror::Class> klass =
+          hs_class.NewHandle(class_linker->FindSystemClass(self, descriptor));
+      if (klass == nullptr) {
+        self->ClearException();
+      } else {
+        LOG(WARNING) << "Redefinition of boot class " << descriptor
+            << " App dex file: " <<  accessor.GetDexFile().GetLocation()
+            << " Boot dex file: " << klass->GetDexFile().GetLocation();
+        foundRedefinition = true;
+        if (!VLOG_IS_ON(verifier)) {
+          // If we are not in verbose mode, return early.
+          // Otherwise continue and log all the collisions for easier debugging.
+          return true;
+        }
+      }
+    }
+  }
+
+  return foundRedefinition;
+}
+
 bool CompilerDriver::FastVerify(jobject jclass_loader,
                                 const std::vector<const DexFile*>& dex_files,
                                 TimingLogger* timings,
@@ -1776,6 +1812,17 @@
     return false;
   }
   TimingLogger::ScopedTiming t("Fast Verify", timings);
+
+  // We cannot do fast verification if the app redefines classes from the boot classpath.
+  // Vdex does not record resolution chains for boot classes and we might wrongfully
+  // resolve a class to the app when it should have been resolved to the boot classpath
+  // (e.g. if we verified against the SDK and the app redefines a boot class which is not
+  // in the SDK.)
+  if (DexFilesRedefineBootClasses(dex_files, timings)) {
+    LOG(WARNING) << "Found redefinition of boot classes. Not doing fast verification.";
+    return false;
+  }
+
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::ClassLoader> class_loader(
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 54a1ae9..e35d502 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -845,8 +845,10 @@
           // make one more attempt to get a constant in the array range.
           ValueRange* existing_range = LookupValueRange(array_length, block);
           if (existing_range != nullptr &&
-              existing_range->IsConstantValueRange()) {
-            ValueRange constant_array_range(&allocator_, lower, existing_range->GetLower());
+              existing_range->IsConstantValueRange() &&
+              existing_range->GetLower().GetConstant() > 0) {
+            ValueBound constant_upper(nullptr, existing_range->GetLower().GetConstant() - 1);
+            ValueRange constant_array_range(&allocator_, lower, constant_upper);
             if (index_range->FitsIn(&constant_array_range)) {
               ReplaceInstruction(bounds_check, index);
               return;
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 8440e9a..96d6d2a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1789,6 +1789,14 @@
     invoke_type = kVirtual;
   }
 
+  bool caller_dead_reference_safe = graph_->IsDeadReferenceSafe();
+  const dex::ClassDef& callee_class = resolved_method->GetClassDef();
+  // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
+  // is currently rarely true.
+  bool callee_dead_reference_safe =
+      annotations::HasDeadReferenceSafeAnnotation(callee_dex_file, callee_class)
+      && !annotations::MethodContainsRSensitiveAccess(callee_dex_file, callee_class, method_index);
+
   const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId();
   HGraph* callee_graph = new (graph_->GetAllocator()) HGraph(
       graph_->GetAllocator(),
@@ -1797,6 +1805,7 @@
       method_index,
       codegen_->GetCompilerOptions().GetInstructionSet(),
       invoke_type,
+      callee_dead_reference_safe,
       graph_->IsDebuggable(),
       /* osr= */ false,
       caller_instruction_counter);
@@ -2023,6 +2032,13 @@
     inline_stats_->AddTo(stats_);
   }
 
+  if (caller_dead_reference_safe && !callee_dead_reference_safe) {
+    // Caller was dead reference safe, but is not anymore, since we inlined dead
+    // reference unsafe code. Prior transformations remain valid, since they did not
+    // affect the inlined code.
+    graph_->MarkDeadReferenceUnsafe();
+  }
+
   return true;
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 48fb611..c70674b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -317,6 +317,7 @@
          uint32_t method_idx,
          InstructionSet instruction_set,
          InvokeType invoke_type = kInvalidInvokeType,
+         bool dead_reference_safe = false,
          bool debuggable = false,
          bool osr = false,
          int start_instruction_id = 0)
@@ -336,6 +337,7 @@
         has_simd_(false),
         has_loops_(false),
         has_irreducible_loops_(false),
+        dead_reference_safe_(dead_reference_safe),
         debuggable_(debuggable),
         current_instruction_id_(start_instruction_id),
         dex_file_(dex_file),
@@ -526,6 +528,12 @@
     has_bounds_checks_ = value;
   }
 
+  // Is the code known to be robust against eliminating dead references
+  // and the effects of early finalization?
+  bool IsDeadReferenceSafe() const { return dead_reference_safe_; }
+
+  void MarkDeadReferenceUnsafe() { dead_reference_safe_ = false; }
+
   bool IsDebuggable() const { return debuggable_; }
 
   // Returns a constant of the given type and value. If it does not exist
@@ -704,6 +712,14 @@
   // so there might be false positives.
   bool has_irreducible_loops_;
 
+  // Is the code known to be robust against eliminating dead references
+  // and the effects of early finalization? If false, dead reference variables
+  // are kept if they might be visible to the garbage collector.
+  // Currently this means that the class was declared to be dead-reference-safe,
+  // the method accesses no reachability-sensitive fields or data, and the same
+  // is true for any methods that were inlined into the current one.
+  bool dead_reference_safe_;
+
   // Indicates whether the graph should be compiled in a way that
   // ensures full debuggability. If false, we can apply more
   // aggressive optimizations that may limit the level of debugging.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 42dbc77..e8f8d32 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -828,6 +828,29 @@
   }
 
   CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item, method_idx);
+
+  bool dead_reference_safe;
+  ArrayRef<const uint8_t> interpreter_metadata;
+  // For AOT compilation, we may not get a method, for example if its class is erroneous,
+  // possibly due to an unavailable superclass.  JIT should always have a method.
+  DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
+  if (method != nullptr) {
+    const dex::ClassDef* containing_class;
+    {
+      ScopedObjectAccess soa(Thread::Current());
+      containing_class = &method->GetClassDef();
+      interpreter_metadata = method->GetQuickenedInfo();
+    }
+    // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
+    // is currently rarely true.
+    dead_reference_safe =
+        annotations::HasDeadReferenceSafeAnnotation(dex_file, *containing_class)
+        && !annotations::MethodContainsRSensitiveAccess(dex_file, *containing_class, method_idx);
+  } else {
+    // If we could not resolve the class, conservatively assume it's dead-reference unsafe.
+    dead_reference_safe = false;
+  }
+
   HGraph* graph = new (allocator) HGraph(
       allocator,
       arena_stack,
@@ -835,17 +858,12 @@
       method_idx,
       compiler_options.GetInstructionSet(),
       kInvalidInvokeType,
+      dead_reference_safe,
       compiler_driver->GetCompilerOptions().GetDebuggable(),
-      osr);
+      /* osr= */ osr);
 
-  ArrayRef<const uint8_t> interpreter_metadata;
-  // For AOT compilation, we may not get a method, for example if its class is erroneous.
-  // JIT should always have a method.
-  DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
   if (method != nullptr) {
     graph->SetArtMethod(method);
-    ScopedObjectAccess soa(Thread::Current());
-    interpreter_metadata = method->GetQuickenedInfo();
   }
 
   std::unique_ptr<CodeGenerator> codegen(
@@ -963,6 +981,7 @@
       method_idx,
       compiler_options.GetInstructionSet(),
       kInvalidInvokeType,
+      /* dead_reference_safe= */ true,  // Intrinsics don't affect dead reference safety.
       compiler_options.GetDebuggable(),
       /* osr= */ false);
 
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 92d0b08..c883907 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -1155,10 +1155,11 @@
  *
  * (a) Non-environment uses of an instruction always make
  *     the instruction live.
- * (b) Environment uses of an instruction whose type is
- *     object (that is, non-primitive), make the instruction live.
- *     This is due to having to keep alive objects that have
- *     finalizers deleting native objects.
+ * (b) Environment uses of an instruction whose type is object (that is, non-primitive), make the
+ *     instruction live, unless the class has an @DeadReferenceSafe annotation.
+ *     This avoids unexpected premature reference enqueuing or finalization, which could
+ *     result in premature deletion of native objects.  In the presence of @DeadReferenceSafe,
+ *     object references are treated like primitive types.
  * (c) When the graph has the debuggable property, environment uses
  *     of an instruction that has a primitive type make the instruction live.
  *     If the graph does not have the debuggable property, the environment
@@ -1287,6 +1288,7 @@
     // When compiling in OSR mode, all loops in the compiled method may be entered
     // from the interpreter via SuspendCheck; thus we need to preserve the environment.
     if (env_holder->IsSuspendCheck() && graph->IsCompilingOsr()) return true;
+    if (graph -> IsDeadReferenceSafe()) return false;
     return instruction->GetType() == DataType::Type::kReference;
   }
 
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 6a4a88e..20d41b4 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -64,8 +64,6 @@
 
     target: {
         android: {
-            // For atrace.
-            shared_libs: ["libcutils"],
             static_libs: [
                 "libz",
             ],
@@ -93,11 +91,6 @@
 
 cc_defaults {
     name: "libart-dex2oat_static_base_defaults",
-    target: {
-        android: {
-            static_libs: ["libcutils"],
-        },
-    },
     static_libs: [
         "libbase",
         "libz",
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 35af918..808ad6c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1367,6 +1367,7 @@
           LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg;
         } else {
           input_vdex_file_ = std::make_unique<VdexFile>(std::move(input_file));
+          VLOG(verifier) << "Doing fast verification with vdex from DexMetadata archive";
         }
       }
     }
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 5aa8236..838510b 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -29,16 +29,18 @@
     target: {
         android: {
             shared_libs: [
-                "libdexfile",
                 "libartbase",
+                "libartpalette",
+                "libdexfile",
                 "libprofile",
                 "libbase",
             ],
         },
         not_windows: {
             shared_libs: [
-                "libdexfile",
                 "libartbase",
+                "libartpalette",
+                "libdexfile",
                 "libprofile",
                 "libbase",
             ],
@@ -46,8 +48,9 @@
         windows: {
             cflags: ["-Wno-thread-safety"],
             static_libs: [
-                "libdexfile",
                 "libartbase",
+                "libartpalette",
+                "libdexfile",
                 "libprofile",
                 "libbase",
             ],
diff --git a/imgdiag/Android.bp b/imgdiag/Android.bp
index 972c8f7..39720a0 100644
--- a/imgdiag/Android.bp
+++ b/imgdiag/Android.bp
@@ -31,9 +31,6 @@
         "libbase",
     ],
     target: {
-        android: {
-            shared_libs: ["libcutils"],
-        },
         host: {
             shared_libs: ["libziparchive"],
         },
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 509b072..1ca7011 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -61,7 +61,7 @@
             shared_libs: [
                 "liblog",
                 // For ashmem.
-                "libcutils",
+                "libartpalette",
                 // For common macros.
                 "libbase",
             ],
@@ -80,7 +80,7 @@
                 "libz",
                 "liblog",
                 // For ashmem.
-                "libcutils",
+                "libartpalette",
                 // For common macros.
                 "libbase",
             ],
@@ -99,7 +99,7 @@
                 "libz",
                 "liblog",
                 // For ashmem.
-                "libcutils",
+                "libartpalette",
                 // For common macros.
                 "libbase",
             ],
@@ -128,7 +128,7 @@
     name: "libartbase_static_base_defaults",
     static_libs: [
         "libbase",
-        "libcutils",
+        "libartpalette",
         "liblog",
         "libz",
         "libziparchive",
diff --git a/libartbase/base/systrace.h b/libartbase/base/systrace.h
index d995dce..30bba49 100644
--- a/libartbase/base/systrace.h
+++ b/libartbase/base/systrace.h
@@ -17,33 +17,52 @@
 #ifndef ART_LIBARTBASE_BASE_SYSTRACE_H_
 #define ART_LIBARTBASE_BASE_SYSTRACE_H_
 
-#define ATRACE_TAG ATRACE_TAG_DALVIK
-#include <cutils/trace.h>
-
 #include <sstream>
 #include <string>
 
 #include "android-base/stringprintf.h"
 #include "macros.h"
+#include "palette/palette.h"
 
 namespace art {
 
+inline bool ATraceEnabled() {
+  int enabled = 0;
+  if (UNLIKELY(PaletteTraceEnabled(&enabled) == PaletteStatus::kOkay && enabled != 0)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline void ATraceBegin(const char* name) {
+  PaletteTraceBegin(name);
+}
+
+inline void ATraceEnd() {
+  PaletteTraceEnd();
+}
+
+inline void ATraceIntegerValue(const char* name, int32_t value) {
+  PaletteTraceIntegerValue(name, value);
+}
+
 class ScopedTrace {
  public:
   explicit ScopedTrace(const char* name) {
-    ATRACE_BEGIN(name);
+    ATraceBegin(name);
   }
   template <typename Fn>
   explicit ScopedTrace(Fn fn) {
-    if (ATRACE_ENABLED()) {
-      ATRACE_BEGIN(fn().c_str());
+    if (UNLIKELY(ATraceEnabled())) {
+      ATraceBegin(fn().c_str());
     }
   }
 
   explicit ScopedTrace(const std::string& name) : ScopedTrace(name.c_str()) {}
 
   ~ScopedTrace() {
-    ATRACE_END();
+    ATraceEnd();
   }
 };
 
@@ -54,7 +73,7 @@
   }
 
   ~ScopedTraceNoStart() {
-    ATRACE_END();
+    ATraceEnd();
   }
 
   // Message helper for the macro. Do not use directly.
@@ -63,7 +82,7 @@
     ScopedTraceMessageHelper() {
     }
     ~ScopedTraceMessageHelper() {
-      ATRACE_BEGIN(buffer_.str().c_str());
+      ATraceBegin(buffer_.str().c_str());
     }
 
     std::ostream& stream() {
@@ -77,7 +96,7 @@
 
 #define SCOPED_TRACE \
   ::art::ScopedTraceNoStart APPEND_TOKENS_AFTER_EVAL(trace, __LINE__) ; \
-  (ATRACE_ENABLED()) && ::art::ScopedTraceNoStart::ScopedTraceMessageHelper().stream()
+  (ATraceEnabled()) && ::art::ScopedTraceNoStart::ScopedTraceMessageHelper().stream()
 
 }  // namespace art
 
diff --git a/libartpalette/Android.bp b/libartpalette/Android.bp
new file mode 100644
index 0000000..778109d
--- /dev/null
+++ b/libartpalette/Android.bp
@@ -0,0 +1,116 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_defaults {
+  name: "libartpalette_defaults",
+  defaults: ["art_defaults"],
+  host_supported: true,
+  export_include_dirs: ["include"],
+}
+
+// libartpalette-system is the implementation of the abstraction layer. It is
+// only available as a shared library on Android.
+art_cc_library {
+    name: "libartpalette-system",
+    defaults: ["libartpalette_defaults"],
+
+    target: {
+        android: {
+          srcs: ["system/palette_android.cc",],
+          header_libs: ["libbase_headers"],
+          shared_libs: [
+            "libcutils",
+            "liblog",
+            "libprocessgroup",
+          ],
+        },
+        host: {
+          header_libs: ["libbase_headers"],
+          srcs: ["system/palette_fake.cc",],
+        },
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+    },
+    static: {
+        enabled: false,
+    },
+    version_script: "libartpalette.map.txt",
+}
+
+// libartpalette is the dynamic loader of the platform abstraction
+// layer. It is only used on Android. For other targets, it just
+// implements a fake platform implementation.
+art_cc_library {
+    name: "libartpalette",
+    defaults: ["libartpalette_defaults"],
+    required: ["libartpalette-system"],  // libartpalette.so dlopen()'s libartpalette-system.
+    header_libs: ["libbase_headers"],
+    target: {
+        // Targets supporting dlopen build the client library which loads
+        // and binds the methods in the libartpalette-system library.
+        android: {
+            srcs: ["apex/palette.cc"],
+            shared: {
+                shared_libs: ["liblog"],
+            },
+            static: {
+                static_libs: ["liblog"],
+            },
+            version_script: "libartpalette.map.txt",
+        },
+        linux_bionic: {
+          header_libs: ["libbase_headers"],
+            srcs: ["system/palette_fake.cc"],
+            shared: {
+                shared_libs: ["liblog"],
+            },
+            version_script: "libartpalette.map.txt",
+        },
+        linux_glibc: {
+          header_libs: ["libbase_headers"],
+            srcs: ["system/palette_fake.cc"],
+            shared: {
+                shared_libs: ["liblog"],
+            },
+            version_script: "libartpalette.map.txt",
+        },
+        // Targets without support for dlopen just use the sources for
+        // the system library which actually implements functionality.
+        darwin: {
+            enabled: true,
+            header_libs: ["libbase_headers"],
+            srcs: ["system/palette_fake.cc"],
+        },
+        windows: {
+            enabled: true,
+            header_libs: ["libbase_headers"],
+            srcs: ["system/palette_fake.cc"],
+        },
+    }
+}
+
+art_cc_test {
+    name: "art_libartpalette_tests",
+    defaults: ["art_gtest_defaults"],
+    host_supported: true,
+    srcs: ["apex/palette_test.cc"],
+    shared_libs: ["libartpalette"],
+    test_per_src: true,
+}
diff --git a/libartpalette/apex/palette.cc b/libartpalette/apex/palette.cc
new file mode 100644
index 0000000..0b391f8
--- /dev/null
+++ b/libartpalette/apex/palette.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "palette/palette.h"
+
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include <android/log.h>
+#include <android-base/macros.h>
+
+namespace {
+
+// Logging tag.
+static constexpr const char* kLogTag = "libartpalette";
+
+// Name of the palette library present in the /system partition.
+static constexpr const char* kPaletteSystemLibrary = "libartpalette-system.so";
+
+// Generic method used when a dynamically loaded palette instance does not
+// support a method.
+enum PaletteStatus PaletteMethodNotSupported() {
+  return PaletteStatus::kNotSupported;
+}
+
+// Declare type aliases for pointers to each function in the interface.
+#define PALETTE_METHOD_TYPE_ALIAS(Name, ...) \
+  using Name ## Method = PaletteStatus(*)(__VA_ARGS__);
+PALETTE_METHOD_LIST(PALETTE_METHOD_TYPE_ALIAS)
+#undef PALETTE_METHOD_TYPE_ALIAS
+
+// Singleton class responsible for dynamically loading the palette library and
+// binding functions there to method pointers.
+class PaletteLoader {
+ public:
+  static PaletteLoader& Instance() {
+    static PaletteLoader instance;
+    return instance;
+  }
+
+  // Accessor methods to get instances of palette methods.
+#define PALETTE_LOADER_METHOD_ACCESSOR(Name, ...)                       \
+  Name ## Method Get ## Name ## Method() const { return Name ## Method ## _; }
+PALETTE_METHOD_LIST(PALETTE_LOADER_METHOD_ACCESSOR)
+#undef PALETTE_LOADER_METHOD_ACCESSOR
+
+ private:
+  PaletteLoader();
+
+  static void* OpenLibrary();
+  static void* GetMethod(void* palette_lib, const char* name);
+
+  // Handle to the palette library from dlopen().
+  void* palette_lib_;
+
+  // Fields to store pointers to palette methods.
+#define PALETTE_LOADER_METHOD_FIELD(Name, ...) \
+  const Name ## Method Name ## Method ## _;
+  PALETTE_METHOD_LIST(PALETTE_LOADER_METHOD_FIELD)
+#undef PALETTE_LOADER_METHOD_FIELD
+
+  DISALLOW_COPY_AND_ASSIGN(PaletteLoader);
+};
+
+void* PaletteLoader::OpenLibrary() {
+  void* handle = dlopen(kPaletteSystemLibrary, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
+  if (handle == nullptr) {
+    // dlerror message includes details of error and file being opened.
+    __android_log_assert(nullptr, kLogTag, "%s", dlerror());
+  }
+  return handle;
+}
+
+void* PaletteLoader::GetMethod(void* palette_lib, const char* name) {
+  void* method = nullptr;
+  if (palette_lib != nullptr) {
+    method = dlsym(palette_lib, name);
+  }
+  if (method == nullptr) {
+    return reinterpret_cast<void*>(PaletteMethodNotSupported);
+  }
+  // TODO(oth): consider new GetMethodSignature() in the Palette API which
+  // would allow sanity checking the type signatures.
+  return method;
+}
+
+PaletteLoader::PaletteLoader() :
+    palette_lib_(OpenLibrary())
+#define PALETTE_LOADER_BIND_METHOD(Name, ...)                           \
+    , Name ## Method ## _(reinterpret_cast<Name ## Method>(GetMethod(palette_lib_, #Name)))
+    PALETTE_METHOD_LIST(PALETTE_LOADER_BIND_METHOD)
+#undef PALETTE_LOADER_BIND_METHOD
+{
+}
+
+}  // namespace
+
+extern "C" {
+
+enum PaletteStatus PaletteGetVersion(/*out*/int32_t* version) {
+  PaletteGetVersionMethod m = PaletteLoader::Instance().GetPaletteGetVersionMethod();
+  return m(version);
+}
+
+enum PaletteStatus PaletteSchedSetPriority(int32_t tid, int32_t java_priority) {
+  PaletteSchedSetPriorityMethod m = PaletteLoader::Instance().GetPaletteSchedSetPriorityMethod();
+  return m(tid, java_priority);
+}
+
+enum PaletteStatus PaletteSchedGetPriority(int32_t tid, /*out*/int32_t* java_priority) {
+  PaletteSchedGetPriorityMethod m = PaletteLoader::Instance().GetPaletteSchedGetPriorityMethod();
+  return m(tid, java_priority);
+}
+
+enum PaletteStatus PaletteTraceEnabled(/*out*/int32_t* enabled) {
+  PaletteTraceEnabledMethod m = PaletteLoader::Instance().GetPaletteTraceEnabledMethod();
+  return m(enabled);
+}
+
+enum PaletteStatus PaletteTraceBegin(/*in*/const char* name) {
+  PaletteTraceBeginMethod m = PaletteLoader::Instance().GetPaletteTraceBeginMethod();
+  return m(name);
+}
+
+enum PaletteStatus PaletteTraceEnd() {
+  PaletteTraceEndMethod m = PaletteLoader::Instance().GetPaletteTraceEndMethod();
+  return m();
+}
+
+enum PaletteStatus PaletteTraceIntegerValue(/*in*/const char* name, int32_t value) {
+  PaletteTraceIntegerValueMethod m = PaletteLoader::Instance().GetPaletteTraceIntegerValueMethod();
+  return m(name, value);
+}
+
+}  // extern "C"
diff --git a/libartpalette/apex/palette_test.cc b/libartpalette/apex/palette_test.cc
new file mode 100644
index 0000000..8bbe0ee
--- /dev/null
+++ b/libartpalette/apex/palette_test.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "palette/palette.h"
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+pid_t GetTid() {
+#ifdef __BIONIC__
+  return gettid();
+#else  // __BIONIC__
+  return syscall(__NR_gettid);
+#endif  // __BIONIC__
+}
+
+}  // namespace
+
+class PaletteClientTest : public testing::Test {};
+
+TEST_F(PaletteClientTest, GetVersion) {
+  int32_t version = -1;
+  PaletteStatus status = PaletteGetVersion(&version);
+  ASSERT_EQ(PaletteStatus::kOkay, status);
+  ASSERT_GE(version, 1);
+}
+
+TEST_F(PaletteClientTest, SchedPriority) {
+  int32_t tid = GetTid();
+  int32_t saved_priority;
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteSchedGetPriority(tid, &saved_priority));
+
+  EXPECT_EQ(PaletteStatus::kInvalidArgument, PaletteSchedSetPriority(tid, /*java_priority=*/ 0));
+  EXPECT_EQ(PaletteStatus::kInvalidArgument, PaletteSchedSetPriority(tid, /*java_priority=*/ -1));
+  EXPECT_EQ(PaletteStatus::kInvalidArgument, PaletteSchedSetPriority(tid, /*java_priority=*/ 11));
+
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteSchedSetPriority(tid, /*java_priority=*/ 1));
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteSchedSetPriority(tid, saved_priority));
+}
+
+TEST_F(PaletteClientTest, Trace) {
+  int32_t enabled;
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteTraceEnabled(&enabled));
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteTraceBegin("Hello world!"));
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteTraceEnd());
+  EXPECT_EQ(PaletteStatus::kOkay, PaletteTraceIntegerValue("Beans", /*value=*/ 3));
+}
diff --git a/libartpalette/include/palette/palette.h b/libartpalette/include/palette/palette.h
new file mode 100644
index 0000000..1f58403
--- /dev/null
+++ b/libartpalette/include/palette/palette.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_H_
+#define ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_H_
+
+#include "palette_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+// Palette method signatures are defined in palette_method_list.h.
+
+#define PALETTE_METHOD_DECLARATION(Name, ...) \
+  enum PaletteStatus Name(__VA_ARGS__);
+#include "palette_method_list.h"
+PALETTE_METHOD_LIST(PALETTE_METHOD_DECLARATION)
+#undef PALETTE_METHOD_DECLARATION
+
+#ifdef __cplusplus
+}
+#endif  // __cplusplus
+
+#endif  // ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_H_
diff --git a/libartpalette/include/palette/palette_method_list.h b/libartpalette/include/palette/palette_method_list.h
new file mode 100644
index 0000000..dc4ec52
--- /dev/null
+++ b/libartpalette/include/palette/palette_method_list.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_METHOD_LIST_H_
+#define ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_METHOD_LIST_H_
+
+#include <stdint.h>
+
+// Methods in version 1 API
+#define PALETTE_METHOD_LIST(M)                                              \
+  M(PaletteGetVersion, /*out*/int32_t* version)                             \
+  M(PaletteSchedSetPriority, int32_t tid, int32_t java_priority)            \
+  M(PaletteSchedGetPriority, int32_t tid, /*out*/int32_t* java_priority)    \
+  M(PaletteTraceEnabled, /*out*/int32_t* enabled)                           \
+  M(PaletteTraceBegin, const char* name)                                    \
+  M(PaletteTraceEnd)                                                        \
+  M(PaletteTraceIntegerValue, const char* name, int32_t value)
+
+#endif  // ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_METHOD_LIST_H_
diff --git a/libartpalette/include/palette/palette_types.h b/libartpalette/include/palette/palette_types.h
new file mode 100644
index 0000000..837086e
--- /dev/null
+++ b/libartpalette/include/palette/palette_types.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_TYPES_H_
+#define ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_TYPES_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+// Return values for palette functions.
+enum PaletteStatus {
+  kOkay = 0,
+  kCheckErrno = 1,
+  kInvalidArgument = 2,
+  kNotSupported = 3,
+};
+
+#ifdef __cplusplus
+}
+#endif  // __cplusplus
+
+#endif  // ART_LIBARTPALETTE_INCLUDE_PALETTE_PALETTE_TYPES_H_
diff --git a/libartpalette/libartpalette.map.txt b/libartpalette/libartpalette.map.txt
new file mode 100644
index 0000000..0920835
--- /dev/null
+++ b/libartpalette/libartpalette.map.txt
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2019 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.
+#
+
+LIBARTPALETTE_1 {
+  global:
+    # --- VERSION 01 API ---
+    PaletteGetVersion;
+    PaletteSchedSetPriority;
+    PaletteSchedGetPriority;
+    PaletteTraceEnabled;
+    PaletteTraceBegin;
+    PaletteTraceEnd;
+    PaletteTraceIntegerValue;
+
+  local:
+    *;
+};
diff --git a/libartpalette/system/palette_android.cc b/libartpalette/system/palette_android.cc
new file mode 100644
index 0000000..aed3862
--- /dev/null
+++ b/libartpalette/system/palette_android.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
+#include "palette/palette.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/sched_policy.h>
+#include <cutils/trace.h>
+#include <log/event_tag_map.h>
+#include <utils/Thread.h>
+
+#include "palette_system.h"
+
+enum PaletteStatus PaletteGetVersion(int32_t* version) {
+  *version = art::palette::kPaletteVersion;
+  return PaletteStatus::kOkay;
+}
+
+// Conversion map for "nice" values.
+//
+// We use Android thread priority constants to be consistent with the rest
+// of the system.  In some cases adjacent entries may overlap.
+//
+static const int kNiceValues[art::palette::kNumManagedThreadPriorities] = {
+  ANDROID_PRIORITY_LOWEST,                // 1 (MIN_PRIORITY)
+  ANDROID_PRIORITY_BACKGROUND + 6,
+  ANDROID_PRIORITY_BACKGROUND + 3,
+  ANDROID_PRIORITY_BACKGROUND,
+  ANDROID_PRIORITY_NORMAL,                // 5 (NORM_PRIORITY)
+  ANDROID_PRIORITY_NORMAL - 2,
+  ANDROID_PRIORITY_NORMAL - 4,
+  ANDROID_PRIORITY_URGENT_DISPLAY + 3,
+  ANDROID_PRIORITY_URGENT_DISPLAY + 2,
+  ANDROID_PRIORITY_URGENT_DISPLAY         // 10 (MAX_PRIORITY)
+};
+
+enum PaletteStatus PaletteSchedSetPriority(int32_t tid, int32_t managed_priority) {
+  if (managed_priority < art::palette::kMinManagedThreadPriority ||
+      managed_priority > art::palette::kMaxManagedThreadPriority) {
+    return PaletteStatus::kInvalidArgument;
+  }
+  int new_nice = kNiceValues[managed_priority - art::palette::kMinManagedThreadPriority];
+
+  // TODO: b/18249098 The code below is broken. It uses getpriority() as a proxy for whether a
+  // thread is already in the SP_FOREGROUND cgroup. This is not necessarily true for background
+  // processes, where all threads are in the SP_BACKGROUND cgroup. This means that callers will
+  // have to call setPriority twice to do what they want :
+  //
+  //     Thread.setPriority(Thread.MIN_PRIORITY);  // no-op wrt to cgroups
+  //     Thread.setPriority(Thread.MAX_PRIORITY);  // will actually change cgroups.
+  if (new_nice >= ANDROID_PRIORITY_BACKGROUND) {
+    set_sched_policy(tid, SP_BACKGROUND);
+  } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+    set_sched_policy(tid, SP_FOREGROUND);
+  }
+
+  if (setpriority(PRIO_PROCESS, tid, new_nice) != 0) {
+    return PaletteStatus::kCheckErrno;
+  }
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteSchedGetPriority(int32_t tid, /*out*/int32_t* managed_priority) {
+  errno = 0;
+  int native_priority = getpriority(PRIO_PROCESS, tid);
+  if (native_priority == -1 && errno != 0) {
+    *managed_priority = art::palette::kNormalManagedThreadPriority;
+    return PaletteStatus::kCheckErrno;
+  }
+
+  for (int p = art::palette::kMinManagedThreadPriority;
+       p <= art::palette::kMaxManagedThreadPriority;
+       p = p + 1) {
+    int index = p - art::palette::kMinManagedThreadPriority;
+    if (native_priority >= kNiceValues[index]) {
+      *managed_priority = p;
+      return PaletteStatus::kOkay;
+    }
+  }
+  *managed_priority = art::palette::kMaxManagedThreadPriority;
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceEnabled(/*out*/int32_t* enabled) {
+  *enabled = (ATRACE_ENABLED() != 0) ? 1 : 0;
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceBegin(const char* name) {
+  ATRACE_BEGIN(name);
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceEnd() {
+  ATRACE_END();
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceIntegerValue(const char* name, int32_t value) {
+  ATRACE_INT(name, value);
+  return PaletteStatus::kOkay;
+}
diff --git a/libartpalette/system/palette_fake.cc b/libartpalette/system/palette_fake.cc
new file mode 100644
index 0000000..0961e77
--- /dev/null
+++ b/libartpalette/system/palette_fake.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "palette/palette.h"
+
+#include <map>
+#include <mutex>
+
+#include <android-base/macros.h>  // For ATTRIBUTE_UNUSED
+
+#include "palette_system.h"
+
+enum PaletteStatus PaletteGetVersion(int32_t* version) {
+  *version = art::palette::kPaletteVersion;
+  return PaletteStatus::kOkay;
+}
+
+// Cached thread priority for testing. No thread priorities are ever affected.
+static std::mutex g_tid_priority_map_mutex;
+static std::map<int32_t, int32_t> g_tid_priority_map;
+
+enum PaletteStatus PaletteSchedSetPriority(int32_t tid, int32_t priority) {
+  if (priority < art::palette::kMinManagedThreadPriority ||
+      priority > art::palette::kMaxManagedThreadPriority) {
+    return PaletteStatus::kInvalidArgument;
+  }
+  std::lock_guard guard(g_tid_priority_map_mutex);
+  g_tid_priority_map[tid] = priority;
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteSchedGetPriority(int32_t tid,
+                                           /*out*/int32_t* priority) {
+  std::lock_guard guard(g_tid_priority_map_mutex);
+  if (g_tid_priority_map.find(tid) == g_tid_priority_map.end()) {
+    g_tid_priority_map[tid] = art::palette::kNormalManagedThreadPriority;
+  }
+  *priority = g_tid_priority_map[tid];
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceEnabled(/*out*/int32_t* enabled) {
+  *enabled = 0;
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceBegin(const char* name ATTRIBUTE_UNUSED) {
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceEnd() {
+  return PaletteStatus::kOkay;
+}
+
+enum PaletteStatus PaletteTraceIntegerValue(const char* name ATTRIBUTE_UNUSED,
+                                            int32_t value ATTRIBUTE_UNUSED) {
+  return PaletteStatus::kOkay;
+}
diff --git a/libartpalette/system/palette_system.h b/libartpalette/system/palette_system.h
new file mode 100644
index 0000000..b28e00d
--- /dev/null
+++ b/libartpalette/system/palette_system.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef ART_LIBARTPALETTE_SYSTEM_PALETTE_SYSTEM_H_
+#define ART_LIBARTPALETTE_SYSTEM_PALETTE_SYSTEM_H_
+
+#include <stdint.h>
+
+namespace art {
+namespace palette {
+
+static constexpr int32_t kPaletteVersion = 1;
+
+// Managed thread definitions
+static constexpr int32_t kNormalManagedThreadPriority = 5;
+static constexpr int32_t kMinManagedThreadPriority = 1;
+static constexpr int32_t kMaxManagedThreadPriority = 10;
+static constexpr int32_t kNumManagedThreadPriorities =
+    kMaxManagedThreadPriority - kMinManagedThreadPriority + 1;
+
+}  // namespace palette
+}  // namespace art
+
+#endif  // ART_LIBARTPALETTE_SYSTEM_PALETTE_SYSTEM_H_
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 2f56a3d..f83f18c 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -47,9 +47,8 @@
             shared_libs: [
                  // For MemMap.
                  "libartbase",
+                 "libartpalette",
                  "liblog",
-                 // For atrace.
-                 "libcutils",
                  // For common macros.
                  "libbase",
             ],
@@ -64,9 +63,8 @@
                 "libz",
                  // For MemMap.
                  "libartbase",
+                 "libartpalette",
                  "liblog",
-                 // For atrace.
-                 "libcutils",
                  // For common macros.
                  "libbase",
             ],
@@ -81,9 +79,8 @@
                 "libz",
                  // For MemMap.
                  "libartbase",
+                 "libartpalette",
                  "liblog",
-                 // For atrace.
-                 "libcutils",
                  // For common macros.
                  "libbase",
             ],
@@ -102,7 +99,6 @@
     name: "libdexfile_static_base_defaults",
     static_libs: [
         "libbase",
-        "libcutils",
         "liblog",
         "libz",
         "libziparchive",
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index c7fbe78..8ea3c09 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -618,6 +618,10 @@
     return hiddenapi_class_data_;
   }
 
+  ALWAYS_INLINE bool HasHiddenapiClassData() const {
+    return hiddenapi_class_data_ != nullptr;
+  }
+
   const dex::AnnotationItem* GetAnnotationItem(const dex::AnnotationSetItem* set_item,
                                                uint32_t index) const {
     DCHECK_LE(index, set_item->size_);
diff --git a/libdexfile/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc
index 83663c5..f36a2aa 100644
--- a/libdexfile/dex/dex_instruction.cc
+++ b/libdexfile/dex/dex_instruction.cc
@@ -402,9 +402,9 @@
         case INVOKE_VIRTUAL_QUICK:
           if (file != nullptr) {
             os << opcode << " {";
-            uint32_t method_idx = VRegB_35c();
+            uint32_t vtable_offset = VRegB_35c();
             DumpArgs(VRegA_35c());
-            os << "},  // vtable@" << method_idx;
+            os << "},  // vtable@" << vtable_offset;
             break;
           }
           FALLTHROUGH_INTENDED;
diff --git a/libdexfile/dex/standard_dex_file.h b/libdexfile/dex/standard_dex_file.h
index 838d4e3..48671c9 100644
--- a/libdexfile/dex/standard_dex_file.h
+++ b/libdexfile/dex/standard_dex_file.h
@@ -84,7 +84,10 @@
   uint32_t GetCodeItemSize(const dex::CodeItem& item) const override;
 
   size_t GetDequickenedSize() const override {
-    return Size();
+    // JVMTI will run dex layout on standard dex files that have hidden API data,
+    // in order to remove that data. As dexlayout may increase the size of the dex file,
+    // be (very) conservative and add one MB to the size.
+    return Size() + (HasHiddenapiClassData() ? 1 * MB : 0);
   }
 
  private:
diff --git a/libprofile/Android.bp b/libprofile/Android.bp
index fd32c5f..986adce 100644
--- a/libprofile/Android.bp
+++ b/libprofile/Android.bp
@@ -25,10 +25,8 @@
         android: {
             shared_libs: [
                 "libartbase",
+                "libartpalette",
                 "libdexfile",
-                "libartbase",
-	        // For atrace.
-                "libcutils",
                 "libbase",
             ],
             static_libs: [
@@ -41,10 +39,8 @@
         not_windows: {
             shared_libs: [
                 "libartbase",
+                "libartpalette",
                 "libdexfile",
-                "libartbase",
-	        // For atrace.
-                "libcutils",
                 "libziparchive",
                 "libz",
                 "libbase",
@@ -55,10 +51,8 @@
 	    cflags: ["-Wno-thread-safety"],
             static_libs: [
                 "libartbase",
+                "libartpalette",
                 "libdexfile",
-                "libartbase",
-	        // For atrace.
-                "libcutils",
                 "libziparchive",
                 "libz",
                 "libbase",
@@ -78,7 +72,6 @@
     name: "libprofile_static_base_defaults",
     static_libs: [
         "libbase",
-        "libcutils",
         "libz",
         "libziparchive",
     ],
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index 45f853b..8849a7a 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -19,11 +19,6 @@
     defaults: ["art_defaults"],
     host_supported: true,
     srcs: ["oatdump.cc"],
-    target: {
-        android: {
-            shared_libs: ["libcutils"],
-        },
-    },
     // b/79417743, oatdump 32-bit tests failed with clang lld
     use_clang_lld: false,
     header_libs: [
@@ -102,6 +97,9 @@
         "libart-disassembler",
         "libvixl",
     ],
+    // We need this to resolve libartpalette symbols
+    // correctly. Multiple source libraries depend on it.
+    group_static_libs: true,
 }
 
 art_cc_binary {
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index e82cd97..b50aa1c 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -66,7 +66,12 @@
 .PHONY: dump-oat-boot-$(TARGET_ARCH)
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
 dump-oat-boot-$(TARGET_ARCH): $(DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME) $(OATDUMP)
-	$(OATDUMP) $(addprefix --image=,$(DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION)) \
+	$(OATDUMP) \
+	  --runtime-arg \
+	  -Xbootclasspath:$(call normalize-path-list, $(DEXPREOPT_BOOTCLASSPATH_DEX_FILES)) \
+	  --runtime-arg \
+	  -Xbootclasspath-locations:$(call normalize-path-list, $(DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS)) \
+	  $(addprefix --image=,$(DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION)) \
 	  --output=$(ART_DUMP_OAT_PATH)/boot.$(TARGET_ARCH).oatdump.txt --instruction-set=$(TARGET_ARCH)
 	@echo Output in $(ART_DUMP_OAT_PATH)/boot.$(TARGET_ARCH).oatdump.txt
 endif
@@ -74,7 +79,12 @@
 ifdef TARGET_2ND_ARCH
 .PHONY: dump-oat-boot-$(TARGET_2ND_ARCH)
 dump-oat-boot-$(TARGET_2ND_ARCH): $(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_FILENAME) $(OATDUMP)
-	$(OATDUMP) $(addprefix --image=,$(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION)) \
+	$(OATDUMP) \
+	  --runtime-arg \
+	  -Xbootclasspath:$(call normalize-path-list, $(DEXPREOPT_BOOTCLASSPATH_DEX_FILES)) \
+	  --runtime-arg \
+	  -Xbootclasspath-locations:$(call normalize-path-list, $(DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS)) \
+	  $(addprefix --image=,$(2ND_DEFAULT_DEX_PREOPT_BUILT_IMAGE_LOCATION)) \
 	  --output=$(ART_DUMP_OAT_PATH)/boot.$(TARGET_2ND_ARCH).oatdump.txt --instruction-set=$(TARGET_2ND_ARCH)
 	@echo Output in $(ART_DUMP_OAT_PATH)/boot.$(TARGET_2ND_ARCH).oatdump.txt
 endif
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index 7b1de01..8505b0c 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -92,7 +92,7 @@
   // Test is failing on target, b/77469384.
   TEST_DISABLED_FOR_TARGET();
   std::string error_msg;
-  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}));
+  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}));
   ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
   const std::string dex_location =
       tmp_dir_+ "/" + android::base::Basename(GetTestDexFileName(GetAppBaseName().c_str())) +
@@ -109,7 +109,7 @@
   TEST_DISABLED_FOR_ARM_AND_MIPS();
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
   std::string error_msg;
-  ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}));
+  ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}));
   ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
 }
 
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index a3e06e6..da7eef9 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -100,9 +100,11 @@
   // property from `original` to `new_dex_file`.
   const art::DexFileLoader dex_file_loader;
 
-  if (original.IsCompactDexFile()) {
+  if (original.IsCompactDexFile() || original.HasHiddenapiClassData()) {
     // Since we are supposed to return a standard dex, convert back using dexlayout. It's OK to do
     // this before unquickening.
+    // We also do dex layout for dex files that have hidden API data, as we want to remove that
+    // data.
     art::Options options;
     options.compact_dex_level_ = art::CompactDexLevel::kCompactDexLevelNone;
     // Add a filter to only include the class that has the matching descriptor.
diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc
index 795a68a..20feb78 100644
--- a/openjdkjvmti/ti_class_definition.cc
+++ b/openjdkjvmti/ti_class_definition.cc
@@ -136,7 +136,8 @@
                              const char* descriptor,
                              /*out*/std::vector<unsigned char>* dex_data)
     REQUIRES_SHARED(art::Locks::mutator_lock_) {
-  std::unique_ptr<FixedUpDexFile> fixed_dex_file(FixedUpDexFile::Create(*dex_file, descriptor));
+  std::unique_ptr<FixedUpDexFile> fixed_dex_file(
+      FixedUpDexFile::Create(*dex_file, descriptor));
   dex_data->resize(fixed_dex_file->Size());
   memcpy(dex_data->data(), fixed_dex_file->Begin(), fixed_dex_file->Size());
 }
diff --git a/runtime/Android.bp b/runtime/Android.bp
index a3081e9..a08ba70 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -392,14 +392,11 @@
         "jni_platform_headers",
     ],
     shared_libs: [
+        "libartpalette",
         "libnativebridge",
         "libnativeloader",
         "libbacktrace",
         "liblog",
-        // For atrace, properties, ashmem.
-        "libcutils",
-        // For set_sched_policy.
-        "libprocessgroup",
         // For common macros.
         "libbase",
     ],
@@ -424,9 +421,9 @@
         },
     },
     static_libs: [
+        "libartpalette",
         "libbacktrace",
         "libbase",
-        "libcutils",
         "libdexfile_external",  // libunwindstack dependency
         "libdexfile_support",  // libunwindstack dependency
         "liblog",
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index b0bed56..306c4eb 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1804,6 +1804,7 @@
     PUSH ESI
     PUSH EDX
     movl 16(%esp), %edi         // Load referrer.
+    movd %xmm7, %esi            // Get target method index stored in xmm7, remember it in ESI.
     // If the method is obsolete, just go through the dex cache miss slow path.
     // The obsolete flag is set with suspended threads, so we do not need an acquire operation here.
     testl LITERAL(ACC_OBSOLETE_METHOD), ART_METHOD_ACCESS_FLAGS_OFFSET(%edi)
@@ -1814,8 +1815,7 @@
     movl MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET(%edi), %edi  // Load the resolved methods.
     pushl ART_METHOD_JNI_OFFSET_32(%eax)  // Push ImtConflictTable.
     CFI_ADJUST_CFA_OFFSET(4)
-    movd %xmm7, %eax            // Get target method index stored in xmm7.
-    movl %eax, %esi             // Remember method index in ESI.
+    movl %esi, %eax             // Copy the method index from ESI.
     andl LITERAL(METHOD_DEX_CACHE_SIZE_MINUS_ONE), %eax  // Calculate DexCache method slot index.
     leal 0(%edi, %eax, 2 * __SIZEOF_POINTER__), %edi  // Load DexCache method slot address.
     mov %ecx, %edx              // Make EDX:EAX == ECX:EBX so that LOCK CMPXCHG8B makes no changes.
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index a8a648f..39bf6e8 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1654,7 +1654,7 @@
      * rdi is the conflict ArtMethod.
      * rax is a hidden argument that holds the target interface method's dex method index.
      *
-     * Note that this stub writes to r10 and rdi.
+     * Note that this stub writes to r10, r11, rax and rdi.
      */
 DEFINE_FUNCTION art_quick_imt_conflict_trampoline
 #if defined(__APPLE__)
@@ -1662,6 +1662,8 @@
     int3
 #else
     movq __SIZEOF_POINTER__(%rsp), %r10 // Load referrer.
+    mov %eax, %r11d             // Remember method index in R11.
+    PUSH rdx                    // Preserve RDX as we need to clobber it by LOCK CMPXCHG16B.
     // If the method is obsolete, just go through the dex cache miss slow path.
     // The obsolete flag is set with suspended threads, so we do not need an acquire operation here.
     testl LITERAL(ACC_OBSOLETE_METHOD), ART_METHOD_ACCESS_FLAGS_OFFSET(%r10)
@@ -1670,11 +1672,9 @@
     movl MIRROR_CLASS_DEX_CACHE_OFFSET(%r10), %r10d    // Load the DexCache (without read barrier).
     UNPOISON_HEAP_REF r10d
     movq MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET(%r10), %r10  // Load the resolved methods.
-    mov %eax, %r11d  // Remember method index in R11.
     andl LITERAL(METHOD_DEX_CACHE_SIZE_MINUS_ONE), %eax  // Calculate DexCache method slot index.
     shll LITERAL(1), %eax       // Multiply by 2 as entries have size 2 * __SIZEOF_POINTER__.
     leaq 0(%r10, %rax, __SIZEOF_POINTER__), %r10 // Load DexCache method slot address.
-    PUSH rdx                    // Preserve RDX as we need to clobber it by LOCK CMPXCHG16B.
     mov %rcx, %rdx              // Make RDX:RAX == RCX:RBX so that LOCK CMPXCHG16B makes no changes.
     mov %rbx, %rax              // (The actual value does not matter.)
     lock cmpxchg16b (%r10)      // Relaxed atomic load RDX:RAX from the dex cache slot.
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 07193b2..44b80df 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -547,11 +547,10 @@
 ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() {
   const DexFile& dex_file = *GetDexFile();
   const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
-  if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
+  if (oat_dex_file == nullptr) {
     return ArrayRef<const uint8_t>();
   }
-  return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf(dex_file,
-                                                                       GetDexMethodIndex());
+  return oat_dex_file->GetQuickenedInfoOf(dex_file, GetDexMethodIndex());
 }
 
 uint16_t ArtMethod::GetIndexFromQuickening(uint32_t dex_pc) {
diff --git a/runtime/base/locks.h b/runtime/base/locks.h
index 57719f1..b7d8e31 100644
--- a/runtime/base/locks.h
+++ b/runtime/base/locks.h
@@ -71,6 +71,7 @@
   kRosAllocGlobalLock,
   kRosAllocBracketLock,
   kRosAllocBulkFreeLock,
+  kAllocSpaceLock,
   kTaggingLockLevel,
   kTransactionLogLock,
   kCustomTlsLock,
@@ -84,7 +85,6 @@
   kReferenceQueueClearedReferencesLock,
   kReferenceProcessorLock,
   kJitDebugInterfaceLock,
-  kAllocSpaceLock,
   kBumpPointerSpaceBlockLock,
   kArenaPoolLock,
   kInternTableLock,
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 5a52818..7aec661 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -107,15 +107,15 @@
         blocked_tid_(kLogLockContentions ? blocked_tid : 0),
         owner_tid_(kLogLockContentions ? owner_tid : 0),
         start_nano_time_(kLogLockContentions ? NanoTime() : 0) {
-    if (ATRACE_ENABLED()) {
+    if (ATraceEnabled()) {
       std::string msg = StringPrintf("Lock contention on %s (owner tid: %" PRIu64 ")",
                                      mutex->GetName(), owner_tid);
-      ATRACE_BEGIN(msg.c_str());
+      ATraceBegin(msg.c_str());
     }
   }
 
   ~ScopedContentionRecorder() {
-    ATRACE_END();
+    ATraceEnd();
     if (kLogLockContentions) {
       uint64_t end_nano_time = NanoTime();
       mutex_->RecordContention(blocked_tid_, owner_tid_, end_nano_time - start_nano_time_);
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index 0a4cddd..bd39192 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -144,12 +144,12 @@
 void TimingLogger::StartTiming(const char* label) {
   DCHECK(label != nullptr);
   timings_.push_back(Timing(kind_, label));
-  ATRACE_BEGIN(label);
+  ATraceBegin(label);
 }
 
 void TimingLogger::EndTiming() {
   timings_.push_back(Timing(kind_, nullptr));
-  ATRACE_END();
+  ATraceEnd();
 }
 
 uint64_t TimingLogger::GetTotalNs() const {
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index e75baf8..050be4a 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -26,6 +26,7 @@
 #include "class_linker-inl.h"
 #include "class_root.h"
 #include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
 #include "jni/jni_internal.h"
 #include "jvalue-inl.h"
 #include "mirror/array-alloc-inl.h"
@@ -36,6 +37,7 @@
 #include "mirror/object_array-inl.h"
 #include "oat_file.h"
 #include "obj_ptr-inl.h"
+#include "quicken_info.h"
 #include "reflection.h"
 #include "thread.h"
 #include "well_known_classes.h"
@@ -146,32 +148,36 @@
   return actual == expected;
 }
 
-const AnnotationSetItem* FindAnnotationSetForField(ArtField* field)
+static const AnnotationSetItem* FindAnnotationSetForField(const DexFile& dex_file,
+                                                          const dex::ClassDef& class_def,
+                                                          uint32_t field_index)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile* dex_file = field->GetDexFile();
+  const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(class_def);
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const FieldAnnotationsItem* field_annotations = dex_file.GetFieldAnnotations(annotations_dir);
+  if (field_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t field_count = annotations_dir->fields_size_;
+  for (uint32_t i = 0; i < field_count; ++i) {
+    if (field_annotations[i].field_idx_ == field_index) {
+      return dex_file.GetFieldAnnotationSetItem(field_annotations[i]);
+    }
+  }
+  return nullptr;
+}
+
+static const AnnotationSetItem* FindAnnotationSetForField(ArtField* field)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
   ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
   const dex::ClassDef* class_def = klass->GetClassDef();
   if (class_def == nullptr) {
     DCHECK(klass->IsProxyClass());
     return nullptr;
   }
-  const AnnotationsDirectoryItem* annotations_dir = dex_file->GetAnnotationsDirectory(*class_def);
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  const FieldAnnotationsItem* field_annotations =
-      dex_file->GetFieldAnnotations(annotations_dir);
-  if (field_annotations == nullptr) {
-    return nullptr;
-  }
-  uint32_t field_index = field->GetDexFieldIndex();
-  uint32_t field_count = annotations_dir->fields_size_;
-  for (uint32_t i = 0; i < field_count; ++i) {
-    if (field_annotations[i].field_idx_ == field_index) {
-      return dex_file->GetFieldAnnotationSetItem(field_annotations[i]);
-    }
-  }
-  return nullptr;
+  return FindAnnotationSetForField(*field->GetDexFile(), *class_def, field->GetDexFieldIndex());
 }
 
 const AnnotationItem* SearchAnnotationSet(const DexFile& dex_file,
@@ -276,9 +282,9 @@
   return nullptr;
 }
 
-const AnnotationSetItem* FindAnnotationSetForMethod(const DexFile& dex_file,
-                                                    const dex::ClassDef& class_def,
-                                                    uint32_t method_index) {
+static const AnnotationSetItem* FindAnnotationSetForMethod(const DexFile& dex_file,
+                                                           const dex::ClassDef& class_def,
+                                                           uint32_t method_index) {
   const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(class_def);
   if (annotations_dir == nullptr) {
     return nullptr;
@@ -329,7 +335,7 @@
   return nullptr;
 }
 
-const AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass)
+static const AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile& dex_file = klass.GetDexFile();
   const dex::ClassDef* class_def = klass.GetClassDef();
@@ -1310,6 +1316,191 @@
   return access_flags;
 }
 
+bool FieldIsReachabilitySensitive(const DexFile& dex_file,
+                                  const dex::ClassDef& class_def,
+                                  uint32_t field_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const AnnotationSetItem* annotation_set =
+      FindAnnotationSetForField(dex_file, class_def, field_index);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set,
+      "Ldalvik/annotation/optimization/ReachabilitySensitive;", DexFile::kDexVisibilityRuntime);
+  // TODO: We're missing the equivalent of DCheckNativeAnnotation (not a DCHECK). Does it matter?
+  return annotation_item != nullptr;
+}
+
+bool MethodIsReachabilitySensitive(const DexFile& dex_file,
+                                   const dex::ClassDef& class_def,
+                                   uint32_t method_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const AnnotationSetItem* annotation_set =
+      FindAnnotationSetForMethod(dex_file, class_def, method_index);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set,
+      "Ldalvik/annotation/optimization/ReachabilitySensitive;", DexFile::kDexVisibilityRuntime);
+  return annotation_item != nullptr;
+}
+
+static bool MethodIsReachabilitySensitive(const DexFile& dex_file,
+                                               uint32_t method_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(method_index < dex_file.NumMethodIds());
+  const dex::MethodId& method_id = dex_file.GetMethodId(method_index);
+  dex::TypeIndex class_index = method_id.class_idx_;
+  const dex::ClassDef * class_def = dex_file.FindClassDef(class_index);
+  return class_def != nullptr
+         && MethodIsReachabilitySensitive(dex_file, *class_def, method_index);
+}
+
+bool MethodContainsRSensitiveAccess(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def,
+                                    uint32_t method_index)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // TODO: This is too slow to run very regularly. Currently this is only invoked in the
+  // presence of @DeadReferenceSafe, which will be rare. In the long run, we need to quickly
+  // check once whether a class has any @ReachabilitySensitive annotations. If not, we can
+  // immediately return false here for any method in that class.
+  uint32_t code_item_offset = dex_file.FindCodeItemOffset(class_def, method_index);
+  const dex::CodeItem* code_item = dex_file.GetCodeItem(code_item_offset);
+  CodeItemInstructionAccessor accessor(dex_file, code_item);
+  if (!accessor.HasCodeItem()) {
+    return false;
+  }
+  ArrayRef<const uint8_t> quicken_data;
+  const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
+  if (oat_dex_file != nullptr) {
+    quicken_data = oat_dex_file->GetQuickenedInfoOf(dex_file, method_index);
+  }
+  const QuickenInfoTable quicken_info(quicken_data);
+  uint32_t quicken_index = 0;
+  for (DexInstructionIterator iter = accessor.begin(); iter != accessor.end(); ++iter) {
+    switch (iter->Opcode()) {
+      case Instruction::IGET:
+      case Instruction::IGET_QUICK:
+      case Instruction::IGET_WIDE:
+      case Instruction::IGET_WIDE_QUICK:
+      case Instruction::IGET_OBJECT:
+      case Instruction::IGET_OBJECT_QUICK:
+      case Instruction::IGET_BOOLEAN:
+      case Instruction::IGET_BOOLEAN_QUICK:
+      case Instruction::IGET_BYTE:
+      case Instruction::IGET_BYTE_QUICK:
+      case Instruction::IGET_CHAR:
+      case Instruction::IGET_CHAR_QUICK:
+      case Instruction::IGET_SHORT:
+      case Instruction::IGET_SHORT_QUICK:
+      case Instruction::IPUT:
+      case Instruction::IPUT_QUICK:
+      case Instruction::IPUT_WIDE:
+      case Instruction::IPUT_WIDE_QUICK:
+      case Instruction::IPUT_OBJECT:
+      case Instruction::IPUT_OBJECT_QUICK:
+      case Instruction::IPUT_BOOLEAN:
+      case Instruction::IPUT_BOOLEAN_QUICK:
+      case Instruction::IPUT_BYTE:
+      case Instruction::IPUT_BYTE_QUICK:
+      case Instruction::IPUT_CHAR:
+      case Instruction::IPUT_CHAR_QUICK:
+      case Instruction::IPUT_SHORT:
+      case Instruction::IPUT_SHORT_QUICK:
+        {
+          uint32_t field_index;
+          if (iter->IsQuickened()) {
+            field_index = quicken_info.GetData(quicken_index);
+          } else {
+            field_index = iter->VRegC_22c();
+          }
+          DCHECK(field_index < dex_file.NumFieldIds());
+          // We only guarantee to pay attention to the annotation if it's in the same class,
+          // or a containing class, but it's OK to do so in other cases.
+          const dex::FieldId& field_id = dex_file.GetFieldId(field_index);
+          dex::TypeIndex class_index = field_id.class_idx_;
+          const dex::ClassDef * field_class_def = dex_file.FindClassDef(class_index);
+          // We do not handle the case in which the field is declared in a superclass, and
+          // don't claim to do so. The annotated field should normally be private.
+          if (field_class_def != nullptr
+              && FieldIsReachabilitySensitive(dex_file, *field_class_def, field_index)) {
+            return true;
+          }
+        }
+        break;
+      case Instruction::INVOKE_SUPER:
+        // Cannot call method in same class. TODO: Try an explicit superclass lookup for
+        // better "best effort"?
+        break;
+      case Instruction::INVOKE_INTERFACE:
+        // We handle an interface call just like a virtual call. We will find annotations
+        // on interface methods/fields visible to us, but not of the annotation is in a
+        // super-interface. Again, we could just ignore it.
+      case Instruction::INVOKE_VIRTUAL:
+      case Instruction::INVOKE_DIRECT:
+        {
+          uint32_t called_method_index = iter->VRegB_35c();
+          if (MethodIsReachabilitySensitive(dex_file, called_method_index)) {
+            return true;
+          }
+        }
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+      case Instruction::INVOKE_VIRTUAL_RANGE:
+      case Instruction::INVOKE_DIRECT_RANGE:
+        {
+          uint32_t called_method_index = iter->VRegB_3rc();
+          if (MethodIsReachabilitySensitive(dex_file, called_method_index)) {
+            return true;
+          }
+        }
+        break;
+      case Instruction::INVOKE_VIRTUAL_QUICK:
+      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+        {
+          uint32_t called_method_index = quicken_info.GetData(quicken_index);
+          if (MethodIsReachabilitySensitive(dex_file, called_method_index)) {
+            return true;
+          }
+        }
+        break;
+        // We explicitly do not handle indirect ReachabilitySensitive accesses through VarHandles,
+        // etc. Thus we ignore INVOKE_CUSTOM / INVOKE_CUSTOM_RANGE / INVOKE_POLYMORPHIC /
+        // INVOKE_POLYMORPHIC_RANGE.
+      default:
+        // There is no way to add an annotation to array elements, and so far we've encountered no
+        // need for that, so we ignore AGET and APUT.
+        // It's impractical or impossible to garbage collect a class while one of its methods is
+        // on the call stack. We allow ReachabilitySensitive annotations on static methods and
+        // fields, but they can be safely ignored.
+        break;
+    }
+    if (QuickenInfoTable::NeedsIndexForInstruction(&iter.Inst())) {
+      ++quicken_index;
+    }
+  }
+  return false;
+}
+
+bool HasDeadReferenceSafeAnnotation(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def)
+  // TODO: This should check outer classes as well.
+  // It's conservatively correct not to do so.
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const AnnotationsDirectoryItem* annotations_dir =
+      dex_file.GetAnnotationsDirectory(class_def);
+  if (annotations_dir == nullptr) {
+    return false;
+  }
+  const AnnotationSetItem* annotation_set = dex_file.GetClassAnnotationSet(annotations_dir);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set,
+      "Ldalvik/annotation/optimization/DeadReferenceSafe;", DexFile::kDexVisibilityRuntime);
+  return annotation_item != nullptr;
+}
+
 ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass,
                                              Handle<mirror::Class> annotation_class) {
   ClassData data(klass);
diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h
index 3625cee..018e87f 100644
--- a/runtime/dex/dex_file_annotations.h
+++ b/runtime/dex/dex_file_annotations.h
@@ -78,6 +78,7 @@
                                Handle<mirror::Class> annotation_class,
                                uint32_t visibility = DexFile::kDexVisibilityRuntime)
     REQUIRES_SHARED(Locks::mutator_lock_);
+
 // Check whether a method from the `dex_file` with the given `method_index`
 // is annotated with @dalvik.annotation.optimization.FastNative or
 // @dalvik.annotation.optimization.CriticalNative with build visibility.
@@ -85,6 +86,28 @@
 uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file,
                                               const dex::ClassDef& class_def,
                                               uint32_t method_index);
+// Is the field from the `dex_file` with the given `field_index`
+// annotated with @dalvik.annotation.optimization.ReachabilitySensitive?
+bool FieldIsReachabilitySensitive(const DexFile& dex_file,
+                                  const dex::ClassDef& class_def,
+                                  uint32_t field_index);
+// Is the method from the `dex_file` with the given `method_index`
+// annotated with @dalvik.annotation.optimization.ReachabilitySensitive?
+bool MethodIsReachabilitySensitive(const DexFile& dex_file,
+                                   const dex::ClassDef& class_def,
+                                   uint32_t method_index);
+// Does the method from the `dex_file` with the given `method_index` contain an access to a field
+// annotated with @dalvik.annotation.optimization.ReachabilitySensitive, or a call to a method
+// with that annotation?
+// Class_def is the class defining the method. We consider only accessses to classes or methods
+// declared in the static type of the corresponding object. We may overlook accesses to annotated
+// fields or methods that are in neither class_def nor a containing (outer) class.
+bool MethodContainsRSensitiveAccess(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def,
+                                    uint32_t method_index);
+// Is the given class annotated with @dalvik.annotation.optimization.DeadReferenceSafe?
+bool HasDeadReferenceSafeAnnotation(const DexFile& dex_file,
+                                    const dex::ClassDef& class_def);
 
 // Class annotations.
 ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5f62d75..d72003c 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2637,7 +2637,7 @@
 }
 
 void Heap::TraceHeapSize(size_t heap_size) {
-  ATRACE_INT("Heap size (KB)", heap_size / KB);
+  ATraceIntegerValue("Heap size (KB)", heap_size / KB);
 }
 
 size_t Heap::GetNativeBytes() {
@@ -2878,6 +2878,15 @@
   DCHECK_GE(now, last_update_time_gc_count_rate_histograms_);
   uint64_t time_since_last_update = now - last_update_time_gc_count_rate_histograms_;
   uint64_t num_of_windows = time_since_last_update / kGcCountRateHistogramWindowDuration;
+
+  // The computed number of windows can be incoherently high if NanoTime() is not monotonic.
+  // Setting a limit on its maximum value reduces the impact on CPU time in such cases.
+  if (num_of_windows > kGcCountRateHistogramMaxNumMissedWindows) {
+    LOG(WARNING) << "Reducing the number of considered missed Gc histogram windows from "
+                 << num_of_windows << " to " << kGcCountRateHistogramMaxNumMissedWindows;
+    num_of_windows = kGcCountRateHistogramMaxNumMissedWindows;
+  }
+
   if (time_since_last_update >= kGcCountRateHistogramWindowDuration) {
     // Record the first window.
     gc_count_rate_histogram_.AddValue(gc_count_last_window_ - 1);  // Exclude the current run.
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 4c5d896..6bdba12 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -1495,6 +1495,8 @@
   uint64_t blocking_gc_time_;
   // The duration of the window for the GC count rate histograms.
   static constexpr uint64_t kGcCountRateHistogramWindowDuration = MsToNs(10 * 1000);  // 10s.
+  // Maximum number of missed histogram windows for which statistics will be collected.
+  static constexpr uint64_t kGcCountRateHistogramMaxNumMissedWindows = 100;
   // The last time when the GC count rate histograms were updated.
   // This is rounded by kGcCountRateHistogramWindowDuration (a multiple of 10s).
   uint64_t last_update_time_gc_count_rate_histograms_;
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index af5e67a..1279997 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -29,15 +29,6 @@
 #include "thread-inl.h"
 #include "well_known_classes.h"
 
-#ifdef ART_TARGET_ANDROID
-#include <metricslogger/metrics_logger.h>
-using android::metricslogger::ComplexEventLogger;
-using android::metricslogger::ACTION_HIDDEN_API_ACCESSED;
-using android::metricslogger::FIELD_HIDDEN_API_ACCESS_METHOD;
-using android::metricslogger::FIELD_HIDDEN_API_ACCESS_DENIED;
-using android::metricslogger::FIELD_HIDDEN_API_SIGNATURE;
-#endif
-
 namespace art {
 namespace hiddenapi {
 
@@ -182,28 +173,6 @@
   return member_name_ == other.member_name_ && type_signature_ == other.type_signature_;
 }
 
-#ifdef ART_TARGET_ANDROID
-// Convert an AccessMethod enum to a value for logging from the proto enum.
-// This method may look odd (the enum values are current the same), but it
-// prevents coupling the internal enum to the proto enum (which should never
-// be changed) so that we are free to change the internal one if necessary in
-// future.
-inline static int32_t GetEnumValueForLog(AccessMethod access_method) {
-  switch (access_method) {
-    case AccessMethod::kNone:
-      return android::metricslogger::ACCESS_METHOD_NONE;
-    case AccessMethod::kReflection:
-      return android::metricslogger::ACCESS_METHOD_REFLECTION;
-    case AccessMethod::kJNI:
-      return android::metricslogger::ACCESS_METHOD_JNI;
-    case AccessMethod::kLinking:
-      return android::metricslogger::ACCESS_METHOD_LINKING;
-    default:
-      DCHECK(false);
-  }
-}
-#endif
-
 void MemberSignature::LogAccessToEventLog(AccessMethod access_method, bool access_denied) {
 #ifdef ART_TARGET_ANDROID
   if (access_method == AccessMethod::kLinking || access_method == AccessMethod::kNone) {
@@ -213,19 +182,32 @@
     // None does not correspond to actual access, so should also be ignored.
     return;
   }
-  ComplexEventLogger log_maker(ACTION_HIDDEN_API_ACCESSED);
-  log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_METHOD, GetEnumValueForLog(access_method));
-  if (access_denied) {
-    log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_DENIED, 1);
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsAotCompiler()) {
+    return;
   }
+  JNIEnvExt* env = Thread::Current()->GetJniEnv();
   const std::string& package_name = Runtime::Current()->GetProcessPackageName();
-  if (!package_name.empty()) {
-    log_maker.SetPackageName(package_name);
+  ScopedLocalRef<jstring> package_str(env, env->NewStringUTF(package_name.c_str()));
+  if (env->ExceptionCheck()) {
+    env->ExceptionClear();
+    LOG(ERROR) << "Unable to allocate string for package name which called hidden api";
   }
   std::ostringstream signature_str;
   Dump(signature_str);
-  log_maker.AddTaggedData(FIELD_HIDDEN_API_SIGNATURE, signature_str.str());
-  log_maker.Record();
+  ScopedLocalRef<jstring> signature_jstr(env,
+      env->NewStringUTF(signature_str.str().c_str()));
+  if (env->ExceptionCheck()) {
+    env->ExceptionClear();
+    LOG(ERROR) << "Unable to allocate string for hidden api method signature";
+  }
+  env->CallStaticVoidMethod(WellKnownClasses::dalvik_system_VMRuntime,
+      WellKnownClasses::dalvik_system_VMRuntime_hiddenApiUsed, package_str.get(),
+      signature_jstr.get(), static_cast<jint>(access_method), access_denied);
+  if (env->ExceptionCheck()) {
+    env->ExceptionClear();
+    LOG(ERROR) << "Unable to report hidden api usage";
+  }
 #else
   UNUSED(access_method);
   UNUSED(access_denied);
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 8bd59ea..e15e9f3 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -45,11 +45,13 @@
   return static_cast<EnforcementPolicy>(api_policy_int);
 }
 
+// Hidden API access method
+// Thist must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_*
 enum class AccessMethod {
-  kNone,  // internal test that does not correspond to an actual access by app
-  kReflection,
-  kJNI,
-  kLinking,
+  kNone = 0,  // internal test that does not correspond to an actual access by app
+  kReflection = 1,
+  kJNI = 2,
+  kLinking = 3,
 };
 
 // Represents the API domain of a caller/callee.
diff --git a/runtime/jni/java_vm_ext_test.cc b/runtime/jni/java_vm_ext_test.cc
index dfe50cf..4a7b1ca 100644
--- a/runtime/jni/java_vm_ext_test.cc
+++ b/runtime/jni/java_vm_ext_test.cc
@@ -109,6 +109,7 @@
 }
 
 TEST_F(JavaVmExtTest, AttachCurrentThread_SmallStack) {
+  TEST_DISABLED_FOR_MEMORY_TOOL();  // b/123500163
   pthread_t pthread;
   pthread_attr_t attr;
   const char* reason = __PRETTY_FUNCTION__;
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 7240357..6abc8d7 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -280,7 +280,7 @@
 // This function is inlined and just helps to not have the VLOG and ATRACE check at all the
 // potential tracing points.
 void Monitor::AtraceMonitorLock(Thread* self, mirror::Object* obj, bool is_wait) {
-  if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging) && ATRACE_ENABLED())) {
+  if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging) && ATraceEnabled())) {
     AtraceMonitorLockImpl(self, obj, is_wait);
   }
 }
@@ -338,12 +338,12 @@
       (obj == nullptr ? -1 : static_cast<int32_t>(reinterpret_cast<uintptr_t>(obj))),
       (filename != nullptr ? filename : "null"),
       line_number);
-  ATRACE_BEGIN(tmp.c_str());
+  ATraceBegin(tmp.c_str());
 }
 
 void Monitor::AtraceMonitorUnlock() {
   if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging))) {
-    ATRACE_END();
+    ATraceEnd();
   }
 }
 
@@ -431,7 +431,7 @@
     // If systrace logging is enabled, first look at the lock owner. Acquiring the monitor's
     // lock and then re-acquiring the mutator lock can deadlock.
     bool started_trace = false;
-    if (ATRACE_ENABLED()) {
+    if (ATraceEnabled()) {
       if (owner_ != nullptr) {  // Did the owner_ give the lock up?
         std::ostringstream oss;
         std::string name;
@@ -450,7 +450,7 @@
         oss << " blocking from "
             << ArtMethod::PrettyMethod(m) << "(" << (filename != nullptr ? filename : "null")
             << ":" << line_number << ")";
-        ATRACE_BEGIN(oss.str().c_str());
+        ATraceBegin(oss.str().c_str());
         started_trace = true;
       }
     }
@@ -581,7 +581,7 @@
       }
     }
     if (started_trace) {
-      ATRACE_END();
+      ATraceEnd();
     }
     self->SetMonitorEnterObject(nullptr);
     monitor_lock_.Lock(self);  // Reacquire locks in order.
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index 88adad0..00a0a39 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -63,6 +63,18 @@
 
 static constexpr bool kUseAddr2line = !kIsTargetBuild;
 
+std::string FindAddr2line() {
+  if (!kIsTargetBuild) {
+    constexpr const char* kAddr2linePrebuiltPath =
+      "/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8/bin/x86_64-linux-addr2line";
+    const char* env_value = getenv("ANDROID_BUILD_TOP");
+    if (env_value != nullptr) {
+      return std::string(env_value) + kAddr2linePrebuiltPath;
+    }
+  }
+  return std::string("/usr/bin/addr2line");
+}
+
 ALWAYS_INLINE
 static inline void WritePrefix(std::ostream& os, const char* prefix, bool odd) {
   if (prefix != nullptr) {
@@ -232,8 +244,9 @@
     }
     pipe->reset();  // Close early.
 
+    std::string addr2linePath = FindAddr2line();
     const char* args[7] = {
-        "/usr/bin/addr2line",
+        addr2linePath.c_str(),
         "--functions",
         "--inlines",
         "--demangle",
@@ -314,7 +327,7 @@
   if (kUseAddr2line) {
     // Try to run it to see whether we have it. Push an argument so that it doesn't assume a.out
     // and print to stderr.
-    use_addr2line = (gAborting > 0) && RunCommand("addr2line -h");
+    use_addr2line = (gAborting > 0) && RunCommand(FindAddr2line() + " -h");
   } else {
     use_addr2line = false;
   }
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index e433cbc..d179b80 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1836,6 +1836,16 @@
                            reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
 }
 
+ArrayRef<const uint8_t> OatDexFile::GetQuickenedInfoOf(const DexFile& dex_file,
+                                                       uint32_t dex_method_idx) const {
+  const OatFile* oat_file = GetOatFile();
+  if (oat_file == nullptr) {
+    return ArrayRef<const uint8_t>();
+  } else  {
+    return oat_file->GetVdexFile()->GetQuickenedInfoOf(dex_file, dex_method_idx);
+  }
+}
+
 const dex::ClassDef* OatDexFile::FindClassDef(const DexFile& dex_file,
                                               const char* descriptor,
                                               size_t hash) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 3e9c01f..1ba6e49 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -502,6 +502,9 @@
     return dex_file_pointer_;
   }
 
+  ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
+                                             uint32_t dex_method_idx) const;
+
   // Looks up a class definition by its class descriptor. Hash must be
   // ComputeModifiedUtf8Hash(descriptor).
   static const dex::ClassDef* FindClassDef(const DexFile& dex_file,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 309c04e..4828aae 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -16,10 +16,6 @@
 
 #include "thread.h"
 
-#if !defined(__APPLE__)
-#include <sched.h>
-#endif
-
 #include <pthread.h>
 #include <signal.h>
 #include <sys/resource.h>
@@ -95,6 +91,7 @@
 #include "oat_quick_method_header.h"
 #include "obj_ptr-inl.h"
 #include "object_lock.h"
+#include "palette/palette.h"
 #include "quick/quick_method_frame_info.h"
 #include "quick_exception_handler.h"
 #include "read_barrier-inl.h"
@@ -4233,6 +4230,7 @@
   Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
 }
 
+
 void Thread::ReleaseLongJumpContextInternal() {
   // Each QuickExceptionHandler gets a long jump context and uses
   // it for doing the long jump, after finding catch blocks/doing deoptimization.
@@ -4246,4 +4244,18 @@
   delete tlsPtr_.long_jump_context;
 }
 
+void Thread::SetNativePriority(int new_priority) {
+  // ART tests on JVM can reach this code path, use tid = 0 as shorthand for current thread.
+  PaletteStatus status = PaletteSchedSetPriority(0, new_priority);
+  CHECK(status == PaletteStatus::kOkay || status == PaletteStatus::kCheckErrno);
+}
+
+int Thread::GetNativePriority() {
+  int priority = 0;
+  // ART tests on JVM can reach this code path, use tid = 0 as shorthand for current thread.
+  PaletteStatus status = PaletteSchedGetPriority(0, &priority);
+  CHECK(status == PaletteStatus::kOkay || status == PaletteStatus::kCheckErrno);
+  return priority;
+}
+
 }  // namespace art
diff --git a/runtime/thread_android.cc b/runtime/thread_android.cc
index 24864f9..f333400 100644
--- a/runtime/thread_android.cc
+++ b/runtime/thread_android.cc
@@ -16,84 +16,8 @@
 
 #include "thread.h"
 
-#include <errno.h>
-#include <limits.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-
-#include <processgroup/sched_policy.h>
-#include <utils/threads.h>
-
-#include "base/macros.h"
-
 namespace art {
 
-// Conversion map for "nice" values.
-//
-// We use Android thread priority constants to be consistent with the rest
-// of the system.  In some cases adjacent entries may overlap.
-//
-static const int kNiceValues[10] = {
-  ANDROID_PRIORITY_LOWEST,                // 1 (MIN_PRIORITY)
-  ANDROID_PRIORITY_BACKGROUND + 6,
-  ANDROID_PRIORITY_BACKGROUND + 3,
-  ANDROID_PRIORITY_BACKGROUND,
-  ANDROID_PRIORITY_NORMAL,                // 5 (NORM_PRIORITY)
-  ANDROID_PRIORITY_NORMAL - 2,
-  ANDROID_PRIORITY_NORMAL - 4,
-  ANDROID_PRIORITY_URGENT_DISPLAY + 3,
-  ANDROID_PRIORITY_URGENT_DISPLAY + 2,
-  ANDROID_PRIORITY_URGENT_DISPLAY         // 10 (MAX_PRIORITY)
-};
-
-void Thread::SetNativePriority(int newPriority) {
-  if (newPriority < 1 || newPriority > 10) {
-    LOG(WARNING) << "bad priority " << newPriority;
-    newPriority = 5;
-  }
-
-  int newNice = kNiceValues[newPriority-1];
-  pid_t tid = GetTid();
-
-  // TODO: b/18249098 The code below is broken. It uses getpriority() as a proxy for whether a
-  // thread is already in the SP_FOREGROUND cgroup. This is not necessarily true for background
-  // processes, where all threads are in the SP_BACKGROUND cgroup. This means that callers will
-  // have to call setPriority twice to do what they want :
-  //
-  //     Thread.setPriority(Thread.MIN_PRIORITY);  // no-op wrt to cgroups
-  //     Thread.setPriority(Thread.MAX_PRIORITY);  // will actually change cgroups.
-  if (newNice >= ANDROID_PRIORITY_BACKGROUND) {
-    set_sched_policy(tid, SP_BACKGROUND);
-  } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
-    set_sched_policy(tid, SP_FOREGROUND);
-  }
-
-  if (setpriority(PRIO_PROCESS, tid, newNice) != 0) {
-    PLOG(INFO) << *this << " setPriority(PRIO_PROCESS, " << tid << ", " << newNice << ") failed";
-  }
-}
-
-int Thread::GetNativePriority() {
-  errno = 0;
-  int native_priority = getpriority(PRIO_PROCESS, 0);
-  if (native_priority == -1 && errno != 0) {
-    PLOG(WARNING) << "getpriority failed";
-    return kNormThreadPriority;
-  }
-
-  int managed_priority = kMinThreadPriority;
-  for (size_t i = 0; i < arraysize(kNiceValues); i++) {
-    if (native_priority >= kNiceValues[i]) {
-      break;
-    }
-    managed_priority++;
-  }
-  if (managed_priority > kMaxThreadPriority) {
-    managed_priority = kMaxThreadPriority;
-  }
-  return managed_priority;
-}
-
 void Thread::SetUpAlternateSignalStack() {
   // Bionic does this for us.
 }
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index d05fecf..3ed4276 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -23,14 +23,6 @@
 
 namespace art {
 
-void Thread::SetNativePriority(int) {
-  // Do nothing.
-}
-
-int Thread::GetNativePriority() {
-  return kNormThreadPriority;
-}
-
 static void SigAltStack(stack_t* new_stack, stack_t* old_stack) {
   if (sigaltstack(new_stack, old_stack) == -1) {
     PLOG(FATAL) << "sigaltstack failed";
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 1b3b037..a5406ea 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -683,7 +683,7 @@
       AssertThreadsAreSuspended(self, self);
     }
   }
-  ATRACE_BEGIN((std::string("Mutator threads suspended for ") + cause).c_str());
+  ATraceBegin((std::string("Mutator threads suspended for ") + cause).c_str());
 
   if (self != nullptr) {
     VLOG(threads) << *self << " SuspendAll complete";
@@ -811,7 +811,7 @@
     VLOG(threads) << "Thread[null] ResumeAll starting";
   }
 
-  ATRACE_END();
+  ATraceEnd();
 
   ScopedTrace trace("Resuming mutator threads");
 
@@ -855,8 +855,8 @@
 }
 
 bool ThreadList::Resume(Thread* thread, SuspendReason reason) {
-  // This assumes there was an ATRACE_BEGIN when we suspended the thread.
-  ATRACE_END();
+  // This assumes there was an ATraceBegin when we suspended the thread.
+  ATraceEnd();
 
   Thread* self = Thread::Current();
   DCHECK_NE(thread, self);
@@ -987,10 +987,10 @@
         // done.
         if (thread->IsSuspended()) {
           VLOG(threads) << "SuspendThreadByPeer thread suspended: " << *thread;
-          if (ATRACE_ENABLED()) {
+          if (ATraceEnabled()) {
             std::string name;
             thread->GetThreadName(name);
-            ATRACE_BEGIN(StringPrintf("SuspendThreadByPeer suspended %s for peer=%p", name.c_str(),
+            ATraceBegin(StringPrintf("SuspendThreadByPeer suspended %s for peer=%p", name.c_str(),
                                       peer).c_str());
           }
           return thread;
@@ -1097,10 +1097,10 @@
         // count, or else we've waited and it has self suspended) or is the current thread, we're
         // done.
         if (thread->IsSuspended()) {
-          if (ATRACE_ENABLED()) {
+          if (ATraceEnabled()) {
             std::string name;
             thread->GetThreadName(name);
-            ATRACE_BEGIN(StringPrintf("SuspendThreadByThreadId suspended %s id=%d",
+            ATraceBegin(StringPrintf("SuspendThreadByThreadId suspended %s id=%d",
                                       name.c_str(), thread_id).c_str());
           }
           VLOG(threads) << "SuspendThreadByThreadId thread suspended: " << *thread;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index f61faa3..955a455 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -84,6 +84,7 @@
 
 jmethodID WellKnownClasses::dalvik_system_BaseDexClassLoader_getLdLibraryPath;
 jmethodID WellKnownClasses::dalvik_system_VMRuntime_runFinalization;
+jmethodID WellKnownClasses::dalvik_system_VMRuntime_hiddenApiUsed;
 jmethodID WellKnownClasses::java_lang_Boolean_valueOf;
 jmethodID WellKnownClasses::java_lang_Byte_valueOf;
 jmethodID WellKnownClasses::java_lang_Character_valueOf;
@@ -344,6 +345,7 @@
 
   dalvik_system_BaseDexClassLoader_getLdLibraryPath = CacheMethod(env, dalvik_system_BaseDexClassLoader, false, "getLdLibraryPath", "()Ljava/lang/String;");
   dalvik_system_VMRuntime_runFinalization = CacheMethod(env, dalvik_system_VMRuntime, true, "runFinalization", "(J)V");
+  dalvik_system_VMRuntime_hiddenApiUsed = CacheMethod(env, dalvik_system_VMRuntime, true, "hiddenApiUsed", "(Ljava/lang/String;Ljava/lang/String;IZ)V");
   java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
   java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
 
@@ -486,6 +488,7 @@
 
   dalvik_system_BaseDexClassLoader_getLdLibraryPath = nullptr;
   dalvik_system_VMRuntime_runFinalization = nullptr;
+  dalvik_system_VMRuntime_hiddenApiUsed = nullptr;
   java_lang_Boolean_valueOf = nullptr;
   java_lang_Byte_valueOf = nullptr;
   java_lang_Character_valueOf = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index f0e98a8..872b562 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -93,6 +93,7 @@
 
   static jmethodID dalvik_system_BaseDexClassLoader_getLdLibraryPath;
   static jmethodID dalvik_system_VMRuntime_runFinalization;
+  static jmethodID dalvik_system_VMRuntime_hiddenApiUsed;
   static jmethodID java_lang_Boolean_valueOf;
   static jmethodID java_lang_Byte_valueOf;
   static jmethodID java_lang_Character_valueOf;
diff --git a/test/1339-dead-reference-safe/check b/test/1339-dead-reference-safe/check
new file mode 100644
index 0000000..795cfac
--- /dev/null
+++ b/test/1339-dead-reference-safe/check
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# DeadReferenceSafe result differs for interpreted mode. A real failure
+# will produce an extra line anyway.
+
+diff --ignore-matching-lines="DeadReferenceSafe count:" -q $1 $2
diff --git a/test/1339-dead-reference-safe/expected.txt b/test/1339-dead-reference-safe/expected.txt
new file mode 100644
index 0000000..abafce4
--- /dev/null
+++ b/test/1339-dead-reference-safe/expected.txt
@@ -0,0 +1,6 @@
+JNI_OnLoad called
+DeadReferenceUnsafe count: 5
+DeadReferenceSafe count: N
+ReachabilitySensitive count: 5
+ReachabilitySensitiveFun count: 5
+ReachabilityFence count: 5
diff --git a/test/1339-dead-reference-safe/info.txt b/test/1339-dead-reference-safe/info.txt
new file mode 100644
index 0000000..b6ad217
--- /dev/null
+++ b/test/1339-dead-reference-safe/info.txt
@@ -0,0 +1 @@
+Test that @DeadReferenceSafe and @ReachabilitySensitive have the intended effect.
diff --git a/test/1339-dead-reference-safe/src/DeadReferenceSafeTest.java b/test/1339-dead-reference-safe/src/DeadReferenceSafeTest.java
new file mode 100644
index 0000000..0c19084
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/DeadReferenceSafeTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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 dalvik.annotation.optimization.DeadReferenceSafe;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class DeadReferenceSafeTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  static boolean interpreted;
+  int n = 1;
+
+  private static void $noinline$loop() {
+    DeadReferenceSafeTest x;
+    // The loop allocates INNER_ITERS DeadReferenceSafeTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new DeadReferenceSafeTest();
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // With dead reference elimination, all 6 objects should have been finalized here.
+        // However the interpreter doesn't (yet?) play by the proper rules.
+        Main.$noinline$gcAndCheck(nFinalized, (interpreted ? 5 : 6), "DeadReferenceSafe",
+            "Failed to reclaim dead reference in @DeadReferenceSafe code!");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("DeadReferenceSafeTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      interpreted = !Main.ensureCompiled(DeadReferenceSafeTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("DeadReferenceSafeTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/DeadReferenceUnsafeTest.java b/test/1339-dead-reference-safe/src/DeadReferenceUnsafeTest.java
new file mode 100644
index 0000000..84774da
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/DeadReferenceUnsafeTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 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 java.util.concurrent.atomic.AtomicInteger;
+
+public final class DeadReferenceUnsafeTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  int n = 1;
+
+  private static void $noinline$loop() {
+    DeadReferenceUnsafeTest x;
+    // The loop allocates INNER_ITERS DeadReferenceUnsafeTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new DeadReferenceUnsafeTest();
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // Without dead reference elimination, the last object should be kept around,
+        // and only 5 objects should be relcaimed here.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "DeadReferenceUnsafe",
+            "Failed to keep dead reference live in unannotated code!");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("DeadReferenceUnsafeTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(DeadReferenceUnsafeTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("DeadReferenceUnsafeTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/Main.java b/test/1339-dead-reference-safe/src/Main.java
new file mode 100644
index 0000000..46b533a
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/Main.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 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 java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Main {
+
+  // Ensure that the "loop" method is compiled. Otherwise we currently have no real way to get rid
+  // of dead references. Return true if it looks like we succeeded.
+  public static boolean ensureCompiled(Class cls, String methodName) throws NoSuchMethodException {
+    Method m = cls.getDeclaredMethod(methodName);
+    if (isAotCompiled(cls, methodName)) {
+      return true;
+    } else {
+      ensureMethodJitCompiled(m);
+      if (hasJitCompiledEntrypoint(cls, methodName)) {
+        return true;
+      }
+      return false;
+    }
+  }
+
+  // Garbage collect and check that the atomic counter has the expected value.
+  // Exped value of -1 means don't care.
+  // Noinline because we don't want the inlining here to interfere with the ReachabilitySensitive
+  // analysis.
+  public static void $noinline$gcAndCheck(AtomicInteger counter, int expected, String label,
+                                          String msg) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    int count = counter.get();
+    System.out.println(label + " count: " + count);
+    if (counter.get() != expected && expected != -1) {
+      System.out.println(msg);
+    }
+  }
+
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+    // Run several variations of the same test with different reachability annotations, etc.
+    // Only the DeadReferenceSafeTest should finalize every previously allocated object.
+    DeadReferenceUnsafeTest.runTest();
+    DeadReferenceSafeTest.runTest();
+    ReachabilitySensitiveTest.runTest();
+    ReachabilitySensitiveFunTest.runTest();
+    ReachabilityFenceTest.runTest();
+  }
+  public static native void ensureMethodJitCompiled(Method meth);
+  public static native boolean hasJitCompiledEntrypoint(Class<?> cls, String methodName);
+  public static native boolean isAotCompiled(Class<?> cls, String methodName);
+}
diff --git a/test/1339-dead-reference-safe/src/ReachabilityFenceTest.java b/test/1339-dead-reference-safe/src/ReachabilityFenceTest.java
new file mode 100644
index 0000000..d4befde
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/ReachabilityFenceTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DeadReferenceSafeTest, but with a reachabilityFence.
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import java.lang.ref.Reference;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class ReachabilityFenceTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  int n = 1;
+
+  private static void $noinline$loop() {
+    ReachabilityFenceTest x;
+    // Each loop allocates INNER_ITERS ReachabilitySenstiveTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new ReachabilityFenceTest();
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // The rechabilityFence should keep the last allocated object reachable.
+        // Thus the last instance should not be finalized.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "ReachabilityFence",
+            "reachabilityFence failed to keep object live.");
+      }
+      Reference.reachabilityFence(x);
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("ReachabilityFenceTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(ReachabilityFenceTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("ReachabilityFenceTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/ReachabilitySensitiveFunTest.java b/test/1339-dead-reference-safe/src/ReachabilitySensitiveFunTest.java
new file mode 100644
index 0000000..2c66146
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/ReachabilitySensitiveFunTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DeadReferenceSafeTest, but with a ReachabilitySensitive annotation.
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class ReachabilitySensitiveFunTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  int n = 1;
+  @ReachabilitySensitive
+  int getN() {
+    return n;
+  }
+
+  private static void $noinline$loop() {
+    ReachabilitySensitiveFunTest x;
+    // The loop allocates INNER_ITERS ReachabilitySensitiveTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new ReachabilitySensitiveFunTest();
+      // ReachabilitySensitive reference.
+      count += x.getN();
+      // x is dead here.
+      if (i == 5) {
+        // Since there is a ReachabilitySensitive call, x should be kept live
+        // until it is reassigned. Thus the last instance should not be finalized.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "ReachabilitySensitiveFun",
+            "@ReachabilitySensitive call failed to keep object live.");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("ReachabilitySensitiveFunTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(ReachabilitySensitiveFunTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("ReachabilitySensitiveFunTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/1339-dead-reference-safe/src/ReachabilitySensitiveTest.java b/test/1339-dead-reference-safe/src/ReachabilitySensitiveTest.java
new file mode 100644
index 0000000..aff43b6
--- /dev/null
+++ b/test/1339-dead-reference-safe/src/ReachabilitySensitiveTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// DeadReferenceSafeTest, but with a ReachabilitySensitive annotation.
+
+import dalvik.annotation.optimization.DeadReferenceSafe;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@DeadReferenceSafe
+public final class ReachabilitySensitiveTest {
+  static AtomicInteger nFinalized = new AtomicInteger(0);
+  private static final int INNER_ITERS = 10;
+  static int count;
+  @ReachabilitySensitive
+  int n = 1;
+
+  private static void $noinline$loop() {
+    ReachabilitySensitiveTest x;
+    // The loop allocates INNER_ITERS ReachabilitySensitiveTest objects.
+    for (int i = 0; i < INNER_ITERS; ++i) {
+      // We've allocated i objects so far.
+      x = new ReachabilitySensitiveTest();
+      // ReachabilitySensitive reference.
+      count += x.n;
+      // x is dead here.
+      if (i == 5) {
+        // Since there is a ReachabilitySensitive reference to x.n, x should be kept live
+        // until it is reassigned. Thus the last instance should not be finalized.
+        Main.$noinline$gcAndCheck(nFinalized, 5, "ReachabilitySensitive",
+            "@ReachabilitySensitive failed to keep object live.");
+      }
+    }
+  }
+
+  private static void reset(int expected_count) {
+    Runtime.getRuntime().gc();
+    System.runFinalization();
+    if (nFinalized.get() != expected_count) {
+      System.out.println("ReachabilitySensitiveTest: Wrong number of finalized objects:"
+                         + nFinalized.get());
+    }
+    nFinalized.set(0);
+  }
+
+  protected void finalize() {
+    nFinalized.incrementAndGet();
+  }
+
+  public static void runTest() {
+    try {
+      Main.ensureCompiled(ReachabilitySensitiveTest.class, "$noinline$loop");
+    } catch (NoSuchMethodException e) {
+      System.out.println("Unexpectedly threw " + e);
+    }
+
+    $noinline$loop();
+
+    if (count != INNER_ITERS) {
+      System.out.println("ReachabilitySensitiveTest: Final count wrong: " + count);
+    }
+    reset(INNER_ITERS);
+  }
+}
diff --git a/test/622-checker-bce-regressions/src/Main.java b/test/622-checker-bce-regressions/src/Main.java
index 6ba2644..595ade8 100644
--- a/test/622-checker-bce-regressions/src/Main.java
+++ b/test/622-checker-bce-regressions/src/Main.java
@@ -42,8 +42,22 @@
     return j;
   }
 
+  static public void $noinline$regressionTest123284765(String str) {
+    try {
+      int l = str.length();
+      if (l == 34) {
+        str.charAt(l);
+        fail();
+      }
+    } catch (StringIndexOutOfBoundsException expected) {
+      expectEquals(34, str.length());
+    }
+  }
+
   public static void main(String[] args) {
     expectEquals(8, doNotVisitAfterForwardBCE(array));
+    $noinline$regressionTest123284765("0123456789012345678901234567890123");
+    $noinline$regressionTest123284765("012345678901");
     System.out.println("passed");
   }
 
@@ -52,4 +66,8 @@
       throw new Error("Expected: " + expected + ", found: " + result);
     }
   }
+
+  private static void fail() {
+    throw new Error("FAIL");
+  }
 }
diff --git a/test/719-dm-verify-redefinition/check b/test/719-dm-verify-redefinition/check
new file mode 100644
index 0000000..b5003bd
--- /dev/null
+++ b/test/719-dm-verify-redefinition/check
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# Search for the redefinition line and remove unnecessary tags.
+sed -e 's/^dex2oat[d]\?\(\|32\|64\)\ W.*\] Found redefinition of boot classes\. Not doing fast verification\./Found redefinition of boot classes\. Not doing fast verification\./g' "$2" > "$2.tmp1"
+# Remove all other dex2oat/dalvikvm log lines.
+grep -v dex2oat "$2.tmp1" | grep -v dalvikvm >> "$2.tmp2"
+
+./default-check "$1" "$2.tmp2"
diff --git a/test/719-dm-verify-redefinition/expected.txt b/test/719-dm-verify-redefinition/expected.txt
new file mode 100644
index 0000000..64fb4ea
--- /dev/null
+++ b/test/719-dm-verify-redefinition/expected.txt
@@ -0,0 +1,3 @@
+Found redefinition of boot classes. Not doing fast verification.
+Hello, world!
+Correct resolution of boot class.
diff --git a/test/719-dm-verify-redefinition/info.txt b/test/719-dm-verify-redefinition/info.txt
new file mode 100644
index 0000000..1229bdb
--- /dev/null
+++ b/test/719-dm-verify-redefinition/info.txt
@@ -0,0 +1,2 @@
+Verifies that the vdex file from a DexMetadata archive is discarded
+if the app redefines boot classes.
diff --git a/test/719-dm-verify-redefinition/run b/test/719-dm-verify-redefinition/run
new file mode 100644
index 0000000..8e568b5
--- /dev/null
+++ b/test/719-dm-verify-redefinition/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+export ANDROID_LOG_TAGS='*:w'
+exec ${RUN} --external-log-tags --dm "${@}"
diff --git a/test/719-dm-verify-redefinition/src/Main.java b/test/719-dm-verify-redefinition/src/Main.java
new file mode 100644
index 0000000..37575b6
--- /dev/null
+++ b/test/719-dm-verify-redefinition/src/Main.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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 java.util.BitSet;
+
+public class Main {
+  public static void main(String[] args) {
+    System.out.println("Hello, world!");
+    if (BitSet.class.getClassLoader().equals(String.class.getClassLoader())) {
+      System.out.println("Correct resolution of boot class.");
+    } else {
+      System.out.println("Bogus resolution of boot class.");
+    }
+  }
+}
diff --git a/test/719-dm-verify-redefinition/src/java/util/BitSet.java b/test/719-dm-verify-redefinition/src/java/util/BitSet.java
new file mode 100644
index 0000000..5d91fd8
--- /dev/null
+++ b/test/719-dm-verify-redefinition/src/java/util/BitSet.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package java.util;
+
+public class BitSet {
+}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 50d5fee..660c971 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -761,8 +761,8 @@
   if [ "$DEV_MODE" = "y" ]; then
     zip_options=""
   fi
-  setupapex_cmdline="unzip -u ${zip_options} ${ZIPAPEX_LOC} apex_payload.zip -d ${DEX_LOCATION}"
-  installapex_cmdline="unzip -u ${zip_options} ${DEX_LOCATION}/apex_payload.zip -d ${DEX_LOCATION}/zipapex"
+  setupapex_cmdline="unzip -o -u ${zip_options} ${ZIPAPEX_LOC} apex_payload.zip -d ${DEX_LOCATION}"
+  installapex_cmdline="unzip -o -u ${zip_options} ${DEX_LOCATION}/apex_payload.zip -d ${DEX_LOCATION}/zipapex"
   BIN_DIR=$DEX_LOCATION/zipapex/bin
 fi
 
@@ -1066,7 +1066,7 @@
 
     mkdir -p ${mkdir_locations} || exit 1
     $setupapex_cmdline || { echo "zipapex extraction failed." >&2 ; exit 2; }
-    $installapex_cmdline || { echo "zipapex install failed." >&2 ; exit 2; }
+    $installapex_cmdline || { echo "zipapex install failed. cmd was: ${installapex_cmdline}." >&2; find ${mkdir_locations} -type f >&2; exit 2; }
     $linkroot_cmdline || { echo "create symlink android-root failed." >&2 ; exit 2; }
     $linkroot_overlay_cmdline || { echo "overlay android-root failed." >&2 ; exit 2; }
     $profman_cmdline || { echo "Profman failed." >&2 ; exit 2; }
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 9c01ba9..a1a038a 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1088,6 +1088,7 @@
                   "999-redefine-hiddenapi",
                   "1000-non-moving-space-stress",
                   "1001-app-image-regions",
+                  "1339-dead-reference-safe",
                   "1951-monitor-enter-no-suspend",
                   "1957-error-ext"],
         "variant": "jvm",
@@ -1172,9 +1173,22 @@
         "description": ["Tests are expected to fail with baseline."]
     },
     {
+        "tests": ["1339-dead-reference-safe"],
+        "variant": "debuggable",
+        "description": [ "Fails to eliminate dead reference when debuggable." ]
+    },
+    {
         "tests": ["708-jit-cache-churn"],
         "variant": "jit-on-first-use",
         "bug": "b/120112467",
         "description": [ "Fails on Android Build hosts with uncaught std::bad_alloc." ]
+    },
+    {
+        "tests": ["719-dm-verify-redefinition"],
+        "variant": "jvm | speed-profile | interp-ac | target | no-prebuild",
+        "description": ["Doesn't run on RI because of boot class redefintion.",
+                        "Doesn't work with profiles because the run-test is not setup to",
+                        "support both. It also needs full verification, so no interp-ac.",
+                        "Requires zip, which isn't available on device"]
     }
 ]
diff --git a/test/testrunner/run_build_test_target.py b/test/testrunner/run_build_test_target.py
index 139d1af..19f03c3 100755
--- a/test/testrunner/run_build_test_target.py
+++ b/test/testrunner/run_build_test_target.py
@@ -28,6 +28,7 @@
 
 import argparse
 import os
+import pathlib
 import subprocess
 import sys
 
@@ -108,7 +109,10 @@
   run_test_command = [os.path.join(env.ANDROID_BUILD_TOP,
                                    'art/test/testrunner/testrunner.py')]
   test_flags = target.get('run-test', [])
-  run_test_command += list(map(lambda a: a.format(SOONG_OUT_DIR=env.SOONG_OUT_DIR), test_flags))
+  out_dir = pathlib.PurePath(env.SOONG_OUT_DIR)
+  if not out_dir.is_absolute():
+    out_dir = pathlib.PurePath(env.ANDROID_BUILD_TOP).joinpath(out_dir)
+  run_test_command += list(map(lambda a: a.format(SOONG_OUT_DIR=str(out_dir)), test_flags))
   # Let testrunner compute concurrency based on #cpus.
   # b/65822340
   # run_test_command += ['-j', str(n_threads)]
diff --git a/tools/build_linux_bionic.sh b/tools/build_linux_bionic.sh
index d3c1912..b401071 100755
--- a/tools/build_linux_bionic.sh
+++ b/tools/build_linux_bionic.sh
@@ -35,14 +35,22 @@
 # Soong needs a bunch of variables set and will not run if they are missing.
 # The default values of these variables is only contained in make, so use
 # nothing to create the variables then remove all the other artifacts.
-build/soong/soong_ui.bash --make-mode nothing
+
+# TODO(b/123645297) Move hiddenapi steps to soong.
+#
+# Currently hiddenapi relies on .mk to build some of it's configuration files.
+# This prevents us from just cleaning using soong and forces us to do this
+# hacky workaround where we build the targets without linux_bionic and delete
+# the build-config files before going around again. If we fix this issue we can
+# change to only building 'nothing' instead.
+build/soong/soong_ui.bash --make-mode "$@"
+
 if [ $? != 0 ]; then
   exit 1
 fi
 
 out_dir=$(get_build_var OUT_DIR)
 host_out=$(get_build_var HOST_OUT)
-mk_product_out=$(get_build_var PRODUCT_OUT)
 
 # TODO(b/31559095) Figure out a better way to do this.
 #
@@ -51,14 +59,17 @@
 tmp_soong_var=$(mktemp --tmpdir soong.variables.bak.XXXXXX)
 
 cat $out_dir/soong/soong.variables > ${tmp_soong_var}
-build/soong/soong_ui.bash --make-mode clean
-mkdir -p $out_dir/soong
-mkdir -p $mk_product_out
 
-# TODO(b/31559095) Soong will panic if this file isn't present. It contains
-# information from MAKE needed to let soong handle the invocation of dex2oat.
-# This would be great to have but for now isn't needed.
-echo "{}" > $mk_product_out/dexpreopt.config
+# See comment above about b/123645297 for why we cannot just do m clean. Clear
+# out all files except for intermediates and installed files.
+find $out_dir/ -maxdepth 1 -mindepth 1 \
+               -not -name soong        \
+               -not -name host         \
+               -not -name target | xargs -I '{}' rm -rf '{}'
+find $out_dir/soong/ -maxdepth 1 -mindepth 1   \
+                     -not -name .intermediates \
+                     -not -name host           \
+                     -not -name target | xargs -I '{}' rm -rf '{}'
 
 python3 <<END - ${tmp_soong_var} ${out_dir}/soong/soong.variables
 import json
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 755104b..6be243a 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -77,6 +77,7 @@
   make_command+=" debuggerd su"
   make_command+=" libstdc++ "
   make_command+=" ${ANDROID_PRODUCT_OUT#"${ANDROID_BUILD_TOP}/"}/system/etc/public.libraries.txt"
+  make_command+=" art-bionic-files"
   if [[ -n "$ART_TEST_CHROOT" ]]; then
     # These targets are needed for the chroot environment.
     make_command+=" crash_dump event-log-tags"
diff --git a/tools/dexanalyze/Android.bp b/tools/dexanalyze/Android.bp
index a85bf56..a232a1b 100644
--- a/tools/dexanalyze/Android.bp
+++ b/tools/dexanalyze/Android.bp
@@ -24,11 +24,6 @@
         "dexanalyze_experiments.cc",
         "dexanalyze_strings.cc",
     ],
-    target: {
-        android: {
-            shared_libs: ["libcutils"],
-        },
-    },
     header_libs: [
         "art_cmdlineparser_headers",
     ],
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 9b0873e..5177919 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -234,5 +234,12 @@
     "libcore.libcore.icu.TimeZoneIntegrationTest#testTimeZoneDebugInfo",
     "libcore.libcore.icu.TimeZoneIntegrationTest#testTzDataSetVersions"
   ]
+},
+{
+  description: "Expected networking failure on host / old systems: we expect 97 (EAFNOSUPPORT), but we get 22 (EINVAL)",
+  result: EXEC_FAILED,
+  names: [
+    "libcore.libcore.io.OsTest#testCrossFamilyBindConnectSendto"
+  ]
 }
 ]
diff --git a/tools/libcore_gcstress_debug_failures.txt b/tools/libcore_gcstress_debug_failures.txt
index 25a4c82..9009a4e 100644
--- a/tools/libcore_gcstress_debug_failures.txt
+++ b/tools/libcore_gcstress_debug_failures.txt
@@ -32,6 +32,12 @@
         ]
 },
 {
+  description: "Timeouts on host with gcstress and debug.",
+  result: EXEC_FAILED,
+  modes: [host],
+  names: ["jsr166.StampedLockTest#testWriteAfterReadLock"]
+},
+{
   description: "Sometimes times out with gcstress and debug.",
   result: EXEC_FAILED,
   bug: 78228743,
diff --git a/tools/timeout_dumper/timeout_dumper.cc b/tools/timeout_dumper/timeout_dumper.cc
index e04aefb..08d2f4c 100644
--- a/tools/timeout_dumper/timeout_dumper.cc
+++ b/tools/timeout_dumper/timeout_dumper.cc
@@ -93,7 +93,7 @@
 namespace addr2line {
 
 constexpr const char* kAddr2linePath =
-    "/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/bin/x86_64-linux-addr2line";
+    "/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8/bin/x86_64-linux-addr2line";
 
 std::unique_ptr<std::string> FindAddr2line() {
   const char* env_value = getenv("ANDROID_BUILD_TOP");
diff --git a/tools/tracefast-plugin/Android.bp b/tools/tracefast-plugin/Android.bp
index 1d7dd30..b7ae6c6 100644
--- a/tools/tracefast-plugin/Android.bp
+++ b/tools/tracefast-plugin/Android.bp
@@ -30,11 +30,6 @@
         "libbase",
     ],
     target: {
-        android: {
-            shared_libs: [
-                "libcutils",
-            ],
-        },
         darwin: {
             enabled: false,
         },
diff --git a/tools/veridex/hidden_api.cc b/tools/veridex/hidden_api.cc
index 1dae93a..efb01f7 100644
--- a/tools/veridex/hidden_api.cc
+++ b/tools/veridex/hidden_api.cc
@@ -37,7 +37,7 @@
     CHECK(success) << "Unknown ApiList flag: " << str;
     CHECK(membership.IsValid()) << "Invalid ApiList: " << membership;
 
-    if (sdk_uses_only != (membership == hiddenapi::ApiList::Whitelist())) {
+    if (sdk_uses_only != membership.Contains(hiddenapi::ApiList::Whitelist())) {
       // Either we want only SDK uses and this is not a whitelist entry,
       // or we want only non-SDK uses and this is a whitelist entry.
       continue;