Merge "Use std::cout for dexanalyze logging"
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 9e5cd80..492f9ce 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -1067,18 +1067,12 @@
     }
     if (method == nullptr || i < stored_index) {
       if (last_class != nullptr) {
-        const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
-        Signature signature = dex_file.GetMethodSignature(method_id);
-        if (last_class->IsInterface()) {
-          method = last_class->FindInterfaceMethod(name, signature, target_ptr_size_);
-        } else {
-          method = last_class->FindClassMethod(name, signature, target_ptr_size_);
-        }
-        if (method != nullptr) {
-          // If the referenced class is in the image, the defining class must also be there.
-          DCHECK(KeepClass(method->GetDeclaringClass()));
-          dex_cache->SetResolvedMethod(i, method, target_ptr_size_);
-        }
+        // Try to resolve the method with the class linker, which will insert
+        // it into the dex cache if successful.
+        method = class_linker->FindResolvedMethod(last_class, dex_cache, class_loader, i);
+        // If the referenced class is in the image, the defining class must also be there.
+        DCHECK(method == nullptr || KeepClass(method->GetDeclaringClass()));
+        DCHECK(method == nullptr || dex_cache->GetResolvedMethod(i, target_ptr_size_) == method);
       }
     } else {
       DCHECK_EQ(i, stored_index);
@@ -1112,14 +1106,10 @@
     }
     if (field == nullptr || i < stored_index) {
       if (last_class != nullptr) {
-        const char* name = dex_file.StringDataByIdx(field_id.name_idx_);
-        const char* type = dex_file.StringByTypeIdx(field_id.type_idx_);
-        field = mirror::Class::FindField(Thread::Current(), last_class, name, type);
-        if (field != nullptr) {
-          // If the referenced class is in the image, the defining class must also be there.
-          DCHECK(KeepClass(field->GetDeclaringClass()));
-          dex_cache->SetResolvedField(i, field, target_ptr_size_);
-        }
+        field = class_linker->FindResolvedFieldJLS(last_class, dex_cache, class_loader, i);
+        // If the referenced class is in the image, the defining class must also be there.
+        DCHECK(field == nullptr || KeepClass(field->GetDeclaringClass()));
+        DCHECK(field == nullptr || dex_cache->GetResolvedField(i, target_ptr_size_) == field);
       }
     } else {
       DCHECK_EQ(i, stored_index);
@@ -1208,7 +1198,9 @@
     }
   }
   for (ObjPtr<mirror::DexCache> dex_cache : dex_caches) {
-    PruneAndPreloadDexCache(dex_cache, class_loader);
+    // Pass the class loader associated with the DexCache. This can either be
+    // the app's `class_loader` or `nullptr` if boot class loader.
+    PruneAndPreloadDexCache(dex_cache, IsInBootImage(dex_cache.Ptr()) ? nullptr : class_loader);
   }
 
   // Drop the array class cache in the ClassLinker, as these are roots holding those classes live.
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 50abdd3..c8a06ed 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -19,11 +19,13 @@
     defaults: ["art_defaults"],
     host_supported: true,
     srcs: [
+        "arch/instruction_set.cc",
         "base/allocator.cc",
         "base/arena_allocator.cc",
         "base/arena_bit_vector.cc",
         "base/bit_vector.cc",
         "base/file_magic.cc",
+        "base/file_utils.cc",
         "base/hex_dump.cc",
         "base/logging.cc",
         "base/malloc_arena_pool.cc",
@@ -62,7 +64,6 @@
     generated_sources: ["art_libartbase_operator_srcs"],
     cflags: ["-DBUILDING_LIBART=1"],
     shared_libs: [
-        "libbacktrace",
         "liblog",
 	// For ashmem.
         "libcutils",
@@ -81,6 +82,7 @@
     cmd: "$(location generate_operator_out) art/libartbase $(in) > $(out)",
     tools: ["generate_operator_out"],
     srcs: [
+        "arch/instruction_set.h",
         "base/allocator.h",
         "base/callee_save_type.h",
         "base/unix_file/fd_file.h",
@@ -142,12 +144,14 @@
         "art_gtest_defaults",
     ],
     srcs: [
+        "arch/instruction_set_test.cc",
         "base/arena_allocator_test.cc",
         "base/bit_field_test.cc",
         "base/bit_string_test.cc",
         "base/bit_struct_test.cc",
         "base/bit_utils_test.cc",
         "base/bit_vector_test.cc",
+        "base/file_utils_test.cc",
         "base/hash_set_test.cc",
         "base/hex_dump_test.cc",
         "base/histogram_test.cc",
diff --git a/runtime/arch/instruction_set.cc b/libartbase/arch/instruction_set.cc
similarity index 88%
rename from runtime/arch/instruction_set.cc
rename to libartbase/arch/instruction_set.cc
index b848eb2..a187663 100644
--- a/runtime/arch/instruction_set.cc
+++ b/libartbase/arch/instruction_set.cc
@@ -16,8 +16,6 @@
 
 #include "instruction_set.h"
 
-// Explicitly include our own elf.h to avoid Linux and other dependencies.
-#include "../elf.h"
 #include "android-base/logging.h"
 #include "base/bit_utils.h"
 #include "base/globals.h"
@@ -83,29 +81,6 @@
   return InstructionSet::kNone;
 }
 
-InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags) {
-  switch (e_machine) {
-    case EM_ARM:
-      return InstructionSet::kArm;
-    case EM_AARCH64:
-      return InstructionSet::kArm64;
-    case EM_386:
-      return InstructionSet::kX86;
-    case EM_X86_64:
-      return InstructionSet::kX86_64;
-    case EM_MIPS: {
-      if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
-          (e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
-        return InstructionSet::kMips;
-      } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
-        return InstructionSet::kMips64;
-      }
-      break;
-    }
-  }
-  return InstructionSet::kNone;
-}
-
 size_t GetInstructionSetAlignment(InstructionSet isa) {
   switch (isa) {
     case InstructionSet::kArm:
diff --git a/runtime/arch/instruction_set.h b/libartbase/arch/instruction_set.h
similarity index 97%
rename from runtime/arch/instruction_set.h
rename to libartbase/arch/instruction_set.h
index 6434005..06bd53a 100644
--- a/runtime/arch/instruction_set.h
+++ b/libartbase/arch/instruction_set.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
-#define ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
+#ifndef ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_
+#define ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_
 
 #include <iosfwd>
 #include <string>
@@ -89,8 +89,6 @@
 // Note: Returns kNone when the string cannot be parsed to a known value.
 InstructionSet GetInstructionSetFromString(const char* instruction_set);
 
-InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags);
-
 // Fatal logging out of line to keep the header clean of logging.h.
 NO_RETURN void InstructionSetAbort(InstructionSet isa);
 
@@ -299,4 +297,4 @@
 
 }  // namespace art
 
-#endif  // ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
+#endif  // ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_
diff --git a/runtime/arch/instruction_set_test.cc b/libartbase/arch/instruction_set_test.cc
similarity index 100%
rename from runtime/arch/instruction_set_test.cc
rename to libartbase/arch/instruction_set_test.cc
diff --git a/runtime/base/file_utils.cc b/libartbase/base/file_utils.cc
similarity index 98%
rename from runtime/base/file_utils.cc
rename to libartbase/base/file_utils.cc
index 537216c..9450e1e 100644
--- a/runtime/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -47,7 +47,6 @@
 #include "base/os.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
-#include "dex/dex_file_loader.h"
 
 #if defined(__APPLE__)
 #include <crt_externs.h>
@@ -64,6 +63,8 @@
 using android::base::StringAppendF;
 using android::base::StringPrintf;
 
+static constexpr const char* kClassesDex = "classes.dex";
+
 bool ReadFileToString(const std::string& file_name, std::string* result) {
   File file(file_name, O_RDONLY, false);
   if (!file.IsOpened()) {
@@ -224,7 +225,7 @@
       !android::base::EndsWith(location, ".art") &&
       !android::base::EndsWith(location, ".oat")) {
     cache_file += "/";
-    cache_file += DexFileLoader::kClassesDex;
+    cache_file += kClassesDex;
   }
   std::replace(cache_file.begin(), cache_file.end(), '/', '@');
   *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str());
diff --git a/runtime/base/file_utils.h b/libartbase/base/file_utils.h
similarity index 95%
rename from runtime/base/file_utils.h
rename to libartbase/base/file_utils.h
index d4f6c57..063393b 100644
--- a/runtime/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_BASE_FILE_UTILS_H_
-#define ART_RUNTIME_BASE_FILE_UTILS_H_
+#ifndef ART_LIBARTBASE_BASE_FILE_UTILS_H_
+#define ART_LIBARTBASE_BASE_FILE_UTILS_H_
 
 #include <stdlib.h>
 
@@ -46,6 +46,7 @@
 // Returns the dalvik-cache location, with subdir appended. Returns the empty string if the cache
 // could not be found.
 std::string GetDalvikCache(const char* subdir);
+
 // Return true if we found the dalvik cache and stored it in the dalvik_cache argument.
 // have_android_data will be set to true if we have an ANDROID_DATA that exists,
 // dalvik_cache_exists will be true if there is a dalvik-cache directory that is present.
@@ -79,4 +80,4 @@
 
 }  // namespace art
 
-#endif  // ART_RUNTIME_BASE_FILE_UTILS_H_
+#endif  // ART_LIBARTBASE_BASE_FILE_UTILS_H_
diff --git a/runtime/base/file_utils_test.cc b/libartbase/base/file_utils_test.cc
similarity index 100%
rename from runtime/base/file_utils_test.cc
rename to libartbase/base/file_utils_test.cc
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index 9a1392c..c455fed 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -29,7 +29,6 @@
 
 #include "android-base/stringprintf.h"
 #include "android-base/unique_fd.h"
-#include "backtrace/BacktraceMap.h"
 #include "cutils/ashmem.h"
 
 #include "allocator.h"
@@ -57,21 +56,6 @@
 // All the non-empty MemMaps. Use a multimap as we do a reserve-and-divide (eg ElfMap::Load()).
 static Maps* gMaps GUARDED_BY(MemMap::GetMemMapsLock()) = nullptr;
 
-static std::ostream& operator<<(
-    std::ostream& os,
-    std::pair<BacktraceMap::iterator, BacktraceMap::iterator> iters) {
-  for (BacktraceMap::iterator it = iters.first; it != iters.second; ++it) {
-    const backtrace_map_t* entry = *it;
-    os << StringPrintf("0x%08x-0x%08x %c%c%c %s\n",
-                       static_cast<uint32_t>(entry->start),
-                       static_cast<uint32_t>(entry->end),
-                       (entry->flags & PROT_READ) ? 'r' : '-',
-                       (entry->flags & PROT_WRITE) ? 'w' : '-',
-                       (entry->flags & PROT_EXEC) ? 'x' : '-', entry->name.c_str());
-  }
-  return os;
-}
-
 std::ostream& operator<<(std::ostream& os, const Maps& mem_maps) {
   os << "MemMap:" << std::endl;
   for (auto it = mem_maps.begin(); it != mem_maps.end(); ++it) {
@@ -149,8 +133,6 @@
   uintptr_t begin = reinterpret_cast<uintptr_t>(ptr);
   uintptr_t end = begin + size;
 
-  // There is a suspicion that BacktraceMap::Create is occasionally missing maps. TODO: Investigate
-  // further.
   {
     std::lock_guard<std::mutex> mu(*mem_maps_lock_);
     for (auto& pair : *gMaps) {
@@ -162,22 +144,6 @@
     }
   }
 
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
-  if (map == nullptr) {
-    if (error_msg != nullptr) {
-      *error_msg = StringPrintf("Failed to build process map");
-    }
-    return false;
-  }
-
-  ScopedBacktraceMapIteratorLock lock(map.get());
-  for (BacktraceMap::iterator it = map->begin(); it != map->end(); ++it) {
-    const backtrace_map_t* entry = *it;
-    if ((begin >= entry->start && begin < entry->end)     // start of new within old
-        && (end > entry->start && end <= entry->end)) {   // end of new within old
-      return true;
-    }
-  }
   if (error_msg != nullptr) {
     PrintFileToLog("/proc/self/maps", LogSeverity::ERROR);
     *error_msg = StringPrintf("Requested region 0x%08" PRIxPTR "-0x%08" PRIxPTR " does not overlap "
@@ -186,36 +152,6 @@
   return false;
 }
 
-// Return true if the address range does not conflict with any /proc/self/maps entry.
-static bool CheckNonOverlapping(uintptr_t begin,
-                                uintptr_t end,
-                                std::string* error_msg) {
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
-  if (map.get() == nullptr) {
-    *error_msg = StringPrintf("Failed to build process map");
-    return false;
-  }
-  ScopedBacktraceMapIteratorLock lock(map.get());
-  for (BacktraceMap::iterator it = map->begin(); it != map->end(); ++it) {
-    const backtrace_map_t* entry = *it;
-    if ((begin >= entry->start && begin < entry->end)      // start of new within old
-        || (end > entry->start && end < entry->end)        // end of new within old
-        || (begin <= entry->start && end > entry->end)) {  // start/end of new includes all of old
-      std::ostringstream map_info;
-      map_info << std::make_pair(it, map->end());
-      *error_msg = StringPrintf("Requested region 0x%08" PRIxPTR "-0x%08" PRIxPTR " overlaps with "
-                                "existing map 0x%08" PRIxPTR "-0x%08" PRIxPTR " (%s)\n%s",
-                                begin, end,
-                                static_cast<uintptr_t>(entry->start),
-                                static_cast<uintptr_t>(entry->end),
-                                entry->name.c_str(),
-                                map_info.str().c_str());
-      return false;
-    }
-  }
-  return true;
-}
-
 // CheckMapRequest to validate a non-MAP_FAILED mmap result based on
 // the expected value, calling munmap if validation fails, giving the
 // reason in error_msg.
@@ -236,7 +172,6 @@
 
   uintptr_t actual = reinterpret_cast<uintptr_t>(actual_ptr);
   uintptr_t expected = reinterpret_cast<uintptr_t>(expected_ptr);
-  uintptr_t limit = expected + byte_count;
 
   if (expected_ptr == actual_ptr) {
     return true;
@@ -256,15 +191,16 @@
     //   true, even if there is no overlap
     // - There might have been an overlap at the point of mmap, but the
     //   overlapping region has since been unmapped.
-    std::string error_detail;
-    CheckNonOverlapping(expected, limit, &error_detail);
+
+    // Tell the client the mappings that were in place at the time.
+    if (kIsDebugBuild) {
+      PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+    }
+
     std::ostringstream os;
     os <<  StringPrintf("Failed to mmap at expected address, mapped at "
                         "0x%08" PRIxPTR " instead of 0x%08" PRIxPTR,
                         actual, expected);
-    if (!error_detail.empty()) {
-      os << " : " << error_detail;
-    }
     *error_msg = os.str();
   }
   return false;
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index b2c041c..9d49f37 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -55,6 +55,7 @@
     },
     generated_sources: ["dexfile_operator_srcs"],
     shared_libs: [
+        "libartbase",
         // Important note: relying on libartbase's header_lib is perfectly acceptable.
         // However, relying on the libartbase shared library introduces further, possibly cyclic,
 	// dependencies for clients outside of ART.
diff --git a/patchoat/Android.bp b/patchoat/Android.bp
index 0e8e517..1e2f328 100644
--- a/patchoat/Android.bp
+++ b/patchoat/Android.bp
@@ -25,6 +25,7 @@
         },
     },
     shared_libs: [
+        "libartbase",
         "libbase",
         "libcrypto", // For computing the digest of image file
     ],
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 64e6796..472f8ce 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -32,7 +32,6 @@
         "art_field.cc",
         "art_method.cc",
         "barrier.cc",
-        "base/file_utils.cc",
         "base/mem_map_arena_pool.cc",
         "base/mutex.cc",
         "base/quasi_atomic.cc",
@@ -207,7 +206,6 @@
         "well_known_classes.cc",
 
         "arch/context.cc",
-        "arch/instruction_set.cc",
         "arch/instruction_set_features.cc",
         "arch/memcmp16.cc",
         "arch/arm/instruction_set_features_arm.cc",
@@ -420,7 +418,6 @@
     cmd: "$(location generate_operator_out) art/runtime $(in) > $(out)",
     tools: ["generate_operator_out"],
     srcs: [
-        "arch/instruction_set.h",
         "base/mutex.h",
         "class_loader_context.h",
         "class_status.h",
@@ -531,7 +528,6 @@
     ],
     srcs: [
         "arch/arch_test.cc",
-        "arch/instruction_set_test.cc",
         "arch/instruction_set_features_test.cc",
         "arch/memcmp16_test.cc",
         "arch/stub_test.cc",
@@ -542,7 +538,6 @@
         "arch/x86/instruction_set_features_x86_test.cc",
         "arch/x86_64/instruction_set_features_x86_64_test.cc",
         "barrier_test.cc",
-        "base/file_utils_test.cc",
         "base/mutex_test.cc",
         "base/timing_logger_test.cc",
         "cha_test.cc",
diff --git a/runtime/arch/code_offset.h b/runtime/arch/code_offset.h
index 8e8dde4..f0c6d22 100644
--- a/runtime/arch/code_offset.h
+++ b/runtime/arch/code_offset.h
@@ -21,9 +21,9 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "base/bit_utils.h"
 #include "base/macros.h"
-#include "instruction_set.h"
 
 namespace art {
 
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
index 5f1a507..c31c927 100644
--- a/runtime/arch/instruction_set_features.h
+++ b/runtime/arch/instruction_set_features.h
@@ -21,8 +21,8 @@
 #include <ostream>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
-#include "instruction_set.h"
 
 namespace art {
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4141a37..9c8b438 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4850,6 +4850,9 @@
       const uint32_t field_idx = field->GetDexFieldIndex();
       ArtField* resolved_field = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
       if (resolved_field == nullptr) {
+        // Populating cache of a dex file which defines `klass` should always be allowed.
+        DCHECK_EQ(hiddenapi::GetMemberAction(
+            field, class_loader.Get(), dex_cache.Get(), hiddenapi::kNone), hiddenapi::kAllow);
         dex_cache->SetResolvedField(field_idx, field, image_pointer_size_);
       } else {
         DCHECK_EQ(field, resolved_field);
@@ -8053,26 +8056,8 @@
     return nullptr;
   }
   DCHECK(klass->IsResolved());
-  Thread* self = is_static ? Thread::Current() : nullptr;
 
-  // First try to find a field declared directly by `klass` by the field index.
-  ArtField* resolved_field = is_static
-      ? mirror::Class::FindStaticField(self, klass, dex_cache, field_idx)
-      : klass->FindInstanceField(dex_cache, field_idx);
-
-  if (resolved_field == nullptr) {
-    // If not found in `klass` by field index, search the class hierarchy using the name and type.
-    const char* name = dex_file.GetFieldName(field_id);
-    const char* type = dex_file.GetFieldTypeDescriptor(field_id);
-    resolved_field = is_static
-        ? mirror::Class::FindStaticField(self, klass, name, type)
-        : klass->FindInstanceField(name, type);
-  }
-
-  if (resolved_field != nullptr) {
-    dex_cache->SetResolvedField(field_idx, resolved_field, image_pointer_size_);
-  }
-  return resolved_field;
+  return FindResolvedField(klass, dex_cache, class_loader, field_idx, is_static);
 }
 
 ArtField* ClassLinker::ResolveField(uint32_t field_idx,
@@ -8087,39 +8072,18 @@
   }
   const DexFile& dex_file = *dex_cache->GetDexFile();
   const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
-  Thread* const self = Thread::Current();
   ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
   if (klass == nullptr) {
     DCHECK(Thread::Current()->IsExceptionPending());
     return nullptr;
   }
 
-  if (is_static) {
-    resolved = mirror::Class::FindStaticField(self, klass, dex_cache.Get(), field_idx);
-  } else {
-    resolved = klass->FindInstanceField(dex_cache.Get(), field_idx);
-  }
-
+  resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static);
   if (resolved == nullptr) {
     const char* name = dex_file.GetFieldName(field_id);
     const char* type = dex_file.GetFieldTypeDescriptor(field_id);
-    if (is_static) {
-      resolved = mirror::Class::FindStaticField(self, klass, name, type);
-    } else {
-      resolved = klass->FindInstanceField(name, type);
-    }
-  }
-
-  if (resolved == nullptr ||
-      hiddenapi::GetMemberAction(
-          resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking) == hiddenapi::kDeny) {
-    const char* name = dex_file.GetFieldName(field_id);
-    const char* type = dex_file.GetFieldTypeDescriptor(field_id);
     ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
-    return nullptr;
   }
-
-  dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_);
   return resolved;
 }
 
@@ -8134,29 +8098,80 @@
   }
   const DexFile& dex_file = *dex_cache->GetDexFile();
   const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
-  Thread* self = Thread::Current();
   ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
   if (klass == nullptr) {
     DCHECK(Thread::Current()->IsExceptionPending());
     return nullptr;
   }
 
-  StringPiece name(dex_file.GetFieldName(field_id));
-  StringPiece type(dex_file.GetFieldTypeDescriptor(field_id));
-  resolved = mirror::Class::FindField(self, klass, name, type);
-  if (resolved != nullptr &&
-      hiddenapi::GetMemberAction(
-          resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking) == hiddenapi::kDeny) {
-    resolved = nullptr;
-  }
-  if (resolved != nullptr) {
-    dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_);
-  } else {
+  resolved = FindResolvedFieldJLS(klass, dex_cache.Get(), class_loader.Get(), field_idx);
+  if (resolved == nullptr) {
+    const char* name = dex_file.GetFieldName(field_id);
+    const char* type = dex_file.GetFieldTypeDescriptor(field_id);
     ThrowNoSuchFieldError("", klass, type, name);
   }
   return resolved;
 }
 
+ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass,
+                                         ObjPtr<mirror::DexCache> dex_cache,
+                                         ObjPtr<mirror::ClassLoader> class_loader,
+                                         uint32_t field_idx,
+                                         bool is_static) {
+  ArtField* resolved = nullptr;
+  Thread* self = is_static ? Thread::Current() : nullptr;
+  const DexFile& dex_file = *dex_cache->GetDexFile();
+
+  resolved = is_static ? mirror::Class::FindStaticField(self, klass, dex_cache, field_idx)
+                       : klass->FindInstanceField(dex_cache, field_idx);
+
+  if (resolved == nullptr) {
+    const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+    const char* name = dex_file.GetFieldName(field_id);
+    const char* type = dex_file.GetFieldTypeDescriptor(field_id);
+    resolved = is_static ? mirror::Class::FindStaticField(self, klass, name, type)
+                         : klass->FindInstanceField(name, type);
+  }
+
+  if (resolved != nullptr &&
+      hiddenapi::GetMemberAction(
+          resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+    resolved = nullptr;
+  }
+
+  if (resolved != nullptr) {
+    dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_);
+  }
+
+  return resolved;
+}
+
+ArtField* ClassLinker::FindResolvedFieldJLS(ObjPtr<mirror::Class> klass,
+                                            ObjPtr<mirror::DexCache> dex_cache,
+                                            ObjPtr<mirror::ClassLoader> class_loader,
+                                            uint32_t field_idx) {
+  ArtField* resolved = nullptr;
+  Thread* self = Thread::Current();
+  const DexFile& dex_file = *dex_cache->GetDexFile();
+  const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+
+  const char* name = dex_file.GetFieldName(field_id);
+  const char* type = dex_file.GetFieldTypeDescriptor(field_id);
+  resolved = mirror::Class::FindField(self, klass, name, type);
+
+  if (resolved != nullptr &&
+      hiddenapi::GetMemberAction(
+          resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+    resolved = nullptr;
+  }
+
+  if (resolved != nullptr) {
+    dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_);
+  }
+
+  return resolved;
+}
+
 ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
     Thread* self,
     uint32_t proto_idx,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index e935d1d..60cff9e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -392,6 +392,27 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
 
+  // Find a field with a given ID from the DexFile associated with the given DexCache
+  // and ClassLoader, storing the result in DexCache. The declaring class is assumed
+  // to have been already resolved into `klass`. The `is_static` argument is used to
+  // determine if we are resolving a static or non-static field.
+  ArtField* FindResolvedField(ObjPtr<mirror::Class> klass,
+                              ObjPtr<mirror::DexCache> dex_cache,
+                              ObjPtr<mirror::ClassLoader> class_loader,
+                              uint32_t field_idx,
+                              bool is_static)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Find a field with a given ID from the DexFile associated with the given DexCache
+  // and ClassLoader, storing the result in DexCache. The declaring class is assumed
+  // to have been already resolved into `klass`. No is_static argument is provided
+  // so that Java field resolution semantics are followed.
+  ArtField* FindResolvedFieldJLS(ObjPtr<mirror::Class> klass,
+                                 ObjPtr<mirror::DexCache> dex_cache,
+                                 ObjPtr<mirror::ClassLoader> class_loader,
+                                 uint32_t field_idx)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Resolve a method type with a given ID from the DexFile associated with a given DexCache
   // and ClassLoader, storing the result in the DexCache.
   ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 719b4af..026b5da 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1073,6 +1073,29 @@
   return true;
 }
 
+static InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags) {
+  switch (e_machine) {
+    case EM_ARM:
+      return InstructionSet::kArm;
+    case EM_AARCH64:
+      return InstructionSet::kArm64;
+    case EM_386:
+      return InstructionSet::kX86;
+    case EM_X86_64:
+      return InstructionSet::kX86_64;
+    case EM_MIPS: {
+      if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
+          (e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
+        return InstructionSet::kMips;
+      } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
+        return InstructionSet::kMips64;
+      }
+      break;
+    }
+  }
+  return InstructionSet::kNone;
+}
+
 template <typename ElfTypes>
 bool ElfFileImpl<ElfTypes>::Load(File* file,
                                  bool executable,
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 9445ae0..9354d72 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -158,10 +158,11 @@
 }
 
 void MemberSignature::LogAccessToEventLog(AccessMethod access_method, Action action_taken) {
-  if (access_method == kLinking) {
+  if (access_method == kLinking || access_method == kNone) {
     // Linking warnings come from static analysis/compilation of the bytecode
     // and can contain false positives (i.e. code that is never run). We choose
     // not to log these in the event log.
+    // None does not correspond to actual access, so should also be ignored.
     return;
   }
   ComplexEventLogger log_maker(ACTION_HIDDEN_API_ACCESSED);
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 371678d..ffbc26c 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -211,12 +211,12 @@
     return nullptr;
   }
 
+  ret->PreSetup(elf_filename);
+
   if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
     return nullptr;
   }
 
-  ret->PreSetup(elf_filename);
-
   if (!ret->Setup(zip_fd, abs_dex_location, error_msg)) {
     return nullptr;
   }
@@ -252,12 +252,12 @@
     return nullptr;
   }
 
+  ret->PreSetup(oat_location);
+
   if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
     return nullptr;
   }
 
-  ret->PreSetup(oat_location);
-
   if (!ret->Setup(zip_fd, abs_dex_location, error_msg)) {
     return nullptr;
   }
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 7d69927..c00e47f 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -860,6 +860,13 @@
   CHECK(oat_filename != nullptr);
   CHECK(error_msg != nullptr);
 
+  // If ANDROID_DATA is not set, return false instead of aborting.
+  // This can occur for preopt when using a class loader context.
+  if (GetAndroidDataSafe(error_msg) == nullptr) {
+    *error_msg = "GetAndroidDataSafe failed: " + *error_msg;
+    return false;
+  }
+
   std::string cache_dir = GetDalvikCache(GetInstructionSetString(isa));
   if (cache_dir.empty()) {
     *error_msg = "Dalvik cache directory does not exist";