Merge "Ensure the correctness of fast verify"
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 67d85c1..bd306b6 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -384,6 +384,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..47a1e4b 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -13,11 +13,12 @@
 ]
 // - Base requirements (libraries).
 art_runtime_base_native_shared_libs = [
+    "libadbconnection",
     "libart",
     "libart-compiler",
+    "libdexfile_external",
     "libopenjdkjvm",
     "libopenjdkjvmti",
-    "libadbconnection",
 ]
 bionic_native_shared_libs = [
     "libc",
@@ -29,17 +30,23 @@
 ]
 // - 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 = [
+    "libadbconnectiond",
     "libartd",
     "libartd-compiler",
     "libopenjdkjvmd",
     "libopenjdkjvmtid",
-    "libadbconnectiond",
 ]
 libcore_debug_native_shared_libs = [
     "libopenjdkd",
@@ -165,7 +172,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 +196,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 +206,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 +220,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..a8b104f
--- /dev/null
+++ b/build/apex/art_apex_test.py
@@ -0,0 +1,657 @@
+#!/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('libdexfile_external.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 d0145e4..3cfda65 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -30,9 +30,21 @@
 namespace.platform.asan.search.paths = /data/asan/system/${LIB}
 namespace.platform.links = default
 namespace.platform.link.default.shared_libs  = libart.so:libartd.so
+namespace.platform.link.default.shared_libs += libdexfile_external.so
 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 +62,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
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/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/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/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..8c17057
--- /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_LOCAL | 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..feb5e38 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",
@@ -232,28 +228,9 @@
         "libdexfile",
     ],
 
-    // TODO(b/120670568): Enable this when linking bug is fixed.
-    // stubs: {
-    //     symbol_file: "external/libdexfile_external.map.txt",
-    //     versions: ["1"],
-    // },
-
-    // Hide symbols using version scripts for targets that support it, i.e. all
-    // but Darwin.
-    // TODO(b/120670568): Clean this up when stubs above is enabled.
-    target: {
-        android: {
-            version_script: "external/libdexfile_external.map.txt",
-        },
-        linux_bionic: {
-            version_script: "external/libdexfile_external.map.txt",
-        },
-        linux_glibc: {
-            version_script: "external/libdexfile_external.map.txt",
-        },
-        windows: {
-            version_script: "external/libdexfile_external.map.txt",
-        },
+    stubs: {
+        symbol_file: "external/libdexfile_external.map.txt",
+        versions: ["1"],
     },
 }
 
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..f56265c 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",
     ],
+    // TODO(b/122885634): This is necessary for the static lib ordering bug with
+    // APEX stubs.
+    group_static_libs: true,
 }
 
 art_cc_binary {
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..079cd98 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -87,7 +87,8 @@
   }
 }
 
-std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original,
+std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(jobject class_loader,
+                                                       const art::DexFile& original,
                                                        const char* descriptor) {
   // Copy the data into mutable memory.
   std::vector<unsigned char> data;
@@ -100,9 +101,11 @@
   // property from `original` to `new_dex_file`.
   const art::DexFileLoader dex_file_loader;
 
-  if (original.IsCompactDexFile()) {
+  if (original.IsCompactDexFile() || class_loader == nullptr) {
     // 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 boot classpath dex files, as they contain hidden API flags which
+    // we want to remove.
     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/fixed_up_dex_file.h b/openjdkjvmti/fixed_up_dex_file.h
index 594e8a7..e09d70b 100644
--- a/openjdkjvmti/fixed_up_dex_file.h
+++ b/openjdkjvmti/fixed_up_dex_file.h
@@ -49,7 +49,8 @@
 // are running on.
 class FixedUpDexFile {
  public:
-  static std::unique_ptr<FixedUpDexFile> Create(const art::DexFile& original,
+  static std::unique_ptr<FixedUpDexFile> Create(jobject class_loader,
+                                                const art::DexFile& original,
                                                 const char* descriptor);
 
   const art::DexFile& GetDexFile() {
diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc
index 795a68a..2345a0a 100644
--- a/openjdkjvmti/ti_class_definition.cc
+++ b/openjdkjvmti/ti_class_definition.cc
@@ -57,7 +57,7 @@
 
   std::string desc = std::string("L") + name_ + ";";
   std::unique_ptr<FixedUpDexFile>
-      fixed_dex_file(FixedUpDexFile::Create(*initial_dex_file_unquickened_, desc.c_str()));
+      fixed_dex_file(FixedUpDexFile::Create(loader_, *initial_dex_file_unquickened_, desc.c_str()));
   CHECK(fixed_dex_file.get() != nullptr);
   CHECK_LE(fixed_dex_file->Size(), temp_mmap_.Size());
   CHECK_EQ(temp_mmap_.Size(), dex_data_mmap_.Size());
@@ -132,17 +132,20 @@
   return OK;
 }
 
-static void DequickenDexFile(const art::DexFile* dex_file,
+static void DequickenDexFile(jobject class_loader,
+                             const art::DexFile* dex_file,
                              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(class_loader, *dex_file, descriptor));
   dex_data->resize(fixed_dex_file->Size());
   memcpy(dex_data->data(), fixed_dex_file->Begin(), fixed_dex_file->Size());
 }
 
 // Gets the data surrounding the given class.
-static void GetDexDataForRetransformation(art::Handle<art::mirror::Class> klass,
+static void GetDexDataForRetransformation(art::ScopedObjectAccess& soa,
+                                          art::Handle<art::mirror::Class> klass,
                                           /*out*/std::vector<unsigned char>* dex_data)
     REQUIRES_SHARED(art::Locks::mutator_lock_) {
   art::StackHandleScope<3> hs(art::Thread::Current());
@@ -179,7 +182,8 @@
     dex_file = &klass->GetDexFile();
   }
   std::string storage;
-  DequickenDexFile(dex_file, klass->GetDescriptor(&storage), dex_data);
+  jobject loader = soa.AddLocalReference<jobject>(klass->GetClassLoader());
+  DequickenDexFile(loader, dex_file, klass->GetDescriptor(&storage), dex_data);
 }
 
 static bool DexNeedsDequickening(art::Handle<art::mirror::Class> klass,
@@ -332,7 +336,7 @@
   const art::DexFile* quick_dex = GetQuickenedDexFile(m_klass);
   auto get_original = [&](/*out*/std::vector<unsigned char>* dex_data)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    GetDexDataForRetransformation(m_klass, dex_data);
+    GetDexDataForRetransformation(soa, m_klass, dex_data);
   };
   InitWithDex(get_original, quick_dex);
   return OK;
@@ -365,7 +369,7 @@
   protection_domain_ = nullptr;
   auto get_original = [&](/*out*/std::vector<unsigned char>* dex_data)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    DequickenDexFile(&dex_file, descriptor, dex_data);
+    DequickenDexFile(loader_, &dex_file, descriptor, dex_data);
   };
   InitWithDex(get_original, &dex_file);
 }
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/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/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/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/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/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/etc/run-test-jar b/test/etc/run-test-jar
index 50d5fee..8407b49 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 -f -u ${zip_options} ${ZIPAPEX_LOC} apex_payload.zip -d ${DEX_LOCATION}"
+  installapex_cmdline="unzip -o -f -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 b97b4c1..8de9574 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1173,6 +1173,11 @@
         "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",
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/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;