[automerger skipped] Add SafetyNet logging to JNI::NewStringUTF. am: 4b56bb8ce2 am: a575d6f7e4 am: 90825620b4 -s ours am: 340de1c79a -s ours am: dbb1a04dfd -s ours

am skip reason: Change-Id I653db8be0c0a45302f0d1c54285c02d2d052a9f4 with SHA-1 69fc841b84 is in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/art/+/13184710

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I3c15894efefbe052fd1e92e9077592143f2af3f1
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 101e5c4..a70b34d 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -20,7 +20,6 @@
 
 #include "gtest/gtest.h"
 
-#include "base/mutex.h"
 #include "base/utils.h"
 #include "jdwp_provider.h"
 #include "experimental_flags.h"
@@ -578,4 +577,21 @@
   EXPECT_KEY_VALUE(map, M::MethodTrace, Unit{});
   EXPECT_KEY_VALUE(map, M::LargeObjectSpace, gc::space::LargeObjectSpaceType::kMap);
 }  //  TEST_F
+
+TEST_F(CmdlineParserTest, TypesNotInRuntime) {
+  CmdlineType<std::vector<int32_t>> ct;
+  auto success0 =
+      CmdlineParseResult<std::vector<int32_t>>::Success(std::vector<int32_t>({1, 2, 3, 4}));
+  EXPECT_EQ(success0, ct.Parse("1,2,3,4"));
+  auto success1 = CmdlineParseResult<std::vector<int32_t>>::Success(std::vector<int32_t>({0}));
+  EXPECT_EQ(success1, ct.Parse("1"));
+
+  EXPECT_FALSE(ct.Parse("").IsSuccess());
+  EXPECT_FALSE(ct.Parse(",").IsSuccess());
+  EXPECT_FALSE(ct.Parse("1,").IsSuccess());
+  EXPECT_FALSE(ct.Parse(",1").IsSuccess());
+  EXPECT_FALSE(ct.Parse("1a2").IsSuccess());
+  EXPECT_EQ(CmdlineResult::kOutOfRange, ct.Parse("1,10000000000000").GetStatus());
+  EXPECT_EQ(CmdlineResult::kOutOfRange, ct.Parse("-10000000000000,123").GetStatus());
+}  // TEST_F
 }  // namespace art
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index dd9221d..6f784b3 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -405,6 +405,39 @@
   static const char* Name() { return "ParseStringList<Separator>"; }
 };
 
+template <>
+struct CmdlineType<std::vector<int32_t>> : CmdlineTypeParser<std::vector<int32_t>> {
+  using Result = CmdlineParseResult<std::vector<int32_t>>;
+
+  Result Parse(const std::string& args) {
+    std::vector<int32_t> list;
+    const char* pos = args.c_str();
+    errno = 0;
+
+    while (true) {
+      char* end = nullptr;
+      int64_t value = strtol(pos, &end, 10);
+      if (pos == end ||  errno == EINVAL) {
+        return Result::Failure("Failed to parse integer from " + args);
+      } else if ((errno == ERANGE) ||  // NOLINT [runtime/int] [4]
+                 value < std::numeric_limits<int32_t>::min() ||
+                 value > std::numeric_limits<int32_t>::max()) {
+        return Result::OutOfRange("Failed to parse integer from " + args + "; out of range");
+      }
+      list.push_back(static_cast<int32_t>(value));
+      if (*end == '\0') {
+        break;
+      } else if (*end != ',') {
+        return Result::Failure(std::string("Unexpected character: ") + *end);
+      }
+      pos = end + 1;
+    }
+    return Result::Success(std::move(list));
+  }
+
+  static const char* Name() { return "std::vector<int32_t>"; }
+};
+
 static gc::CollectorType ParseCollectorType(const std::string& option) {
   if (option == "MS" || option == "nonconcurrent") {
     return gc::kCollectorTypeMS;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 3086882..a436b98 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -6227,12 +6227,20 @@
       CheckValidReg(holder_reg.GetCode());
       UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
       temps.Exclude(ip0, ip1);
-      // If base_reg differs from holder_reg, the offset was too large and we must have emitted
-      // an explicit null check before the load. Otherwise, for implicit null checks, we need to
-      // null-check the holder as we do not necessarily do that check before going to the thunk.
+      // In the case of a field load (with relaxed semantic), if `base_reg` differs from
+      // `holder_reg`, the offset was too large and we must have emitted (during the construction
+      // of the HIR graph, see `art::HInstructionBuilder::BuildInstanceFieldAccess`) and preserved
+      // (see `art::PrepareForRegisterAllocation::VisitNullCheck`) an explicit null check before
+      // the load. Otherwise, for implicit null checks, we need to null-check the holder as we do
+      // not necessarily do that check before going to the thunk.
+      //
+      // In the case of a field load with load-acquire semantics (where `base_reg` always differs
+      // from `holder_reg`), we also need an explicit null check when implicit null checks are
+      // allowed, as we do not emit one before going to the thunk.
       vixl::aarch64::Label throw_npe_label;
       vixl::aarch64::Label* throw_npe = nullptr;
-      if (GetCompilerOptions().GetImplicitNullChecks() && holder_reg.Is(base_reg)) {
+      if (GetCompilerOptions().GetImplicitNullChecks() &&
+          (holder_reg.Is(base_reg) || (kind == BakerReadBarrierKind::kAcquire))) {
         throw_npe = &throw_npe_label;
         __ Cbz(holder_reg.W(), throw_npe);
       }
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 6469c69..507c453 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -9357,9 +9357,12 @@
       BakerReadBarrierWidth width = BakerReadBarrierWidthField::Decode(encoded_data);
       UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
       temps.Exclude(ip);
-      // If base_reg differs from holder_reg, the offset was too large and we must have emitted
-      // an explicit null check before the load. Otherwise, for implicit null checks, we need to
-      // null-check the holder as we do not necessarily do that check before going to the thunk.
+      // In the case of a field load, if `base_reg` differs from
+      // `holder_reg`, the offset was too large and we must have emitted (during the construction
+      // of the HIR graph, see `art::HInstructionBuilder::BuildInstanceFieldAccess`) and preserved
+      // (see `art::PrepareForRegisterAllocation::VisitNullCheck`) an explicit null check before
+      // the load. Otherwise, for implicit null checks, we need to null-check the holder as we do
+      // not necessarily do that check before going to the thunk.
       vixl32::Label throw_npe_label;
       vixl32::Label* throw_npe = nullptr;
       if (GetCompilerOptions().GetImplicitNullChecks() && holder_reg.Is(base_reg)) {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 278523e..9961608 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -29,11 +29,15 @@
 #include <type_traits>
 #include <vector>
 
-#if defined(__linux__) && defined(__arm__)
+#if defined(__linux__)
+#include <sched.h>
+#if defined(__arm__)
 #include <sys/personality.h>
 #include <sys/utsname.h>
+#endif  // __arm__
 #endif
 
+#include "android-base/parseint.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
@@ -222,6 +226,10 @@
   UsageError("       host system.");
   UsageError("      Example: -j12");
   UsageError("");
+  UsageError("  --cpu-set=<set>: sets the cpu affinity to <set>. The <set> argument is a comma");
+  UsageError("    separated list of CPUs.");
+  UsageError("    Example: --cpu-set=0,1,2,3");
+  UsageError("");
   UsageError("  --dex-file=<dex-file>: specifies a .dex, .jar, or .apk file to compile.");
   UsageError("      Example: --dex-file=/system/framework/core.jar");
   UsageError("");
@@ -500,6 +508,36 @@
   exit(EXIT_FAILURE);
 }
 
+
+// Set CPU affinity from a string containing a comma-separated list of numeric CPU identifiers.
+static void SetCpuAffinity(const std::vector<int32_t>& cpu_list) {
+#ifdef __linux__
+  int cpu_count = sysconf(_SC_NPROCESSORS_CONF);
+  cpu_set_t target_cpu_set;
+  CPU_ZERO(&target_cpu_set);
+
+  for (int32_t cpu : cpu_list) {
+    if (cpu >= 0 && cpu < cpu_count) {
+      CPU_SET(cpu, &target_cpu_set);
+    } else {
+      // Argument error is considered fatal, suggests misconfigured system properties.
+      Usage("Invalid cpu \"d\" specified in --cpu-set argument (nprocessors = %d)",
+            cpu, cpu_count);
+    }
+  }
+
+  if (sched_setaffinity(getpid(), sizeof(target_cpu_set), &target_cpu_set) == -1) {
+    // Failure to set affinity may be outside control of requestor, log warning rather than
+    // treating as fatal.
+    PLOG(WARNING) << "Failed to set CPU affinity.";
+  }
+#else
+  LOG(WARNING) << "--cpu-set not supported on this platform.";
+#endif  // __linux__
+}
+
+
+
 // The primary goal of the watchdog is to prevent stuck build servers
 // during development when fatal aborts lead to a cascade of failures
 // that result in a deadlock.
@@ -929,6 +967,10 @@
       }
     }
 
+    if (!cpu_set_.empty()) {
+      SetCpuAffinity(cpu_set_);
+    }
+
     if (compiler_options_->inline_max_code_units_ == CompilerOptions::kUnsetInlineMaxCodeUnits) {
       compiler_options_->inline_max_code_units_ = CompilerOptions::kDefaultInlineMaxCodeUnits;
     }
@@ -1136,6 +1178,7 @@
     AssignIfExists(args, M::Threads, &thread_count_);
     AssignIfExists(args, M::ImageClasses, &image_classes_filename_);
     AssignIfExists(args, M::ImageClassesZip, &image_classes_zip_filename_);
+    AssignIfExists(args, M::CpuSet, &cpu_set_);
     AssignIfExists(args, M::Passes, &passes_to_run_filename_);
     AssignIfExists(args, M::BootImage, &parser_options->boot_image_filename);
     AssignIfExists(args, M::AndroidRoot, &android_root_);
@@ -2743,6 +2786,7 @@
   std::unique_ptr<ClassLoaderContext> stored_class_loader_context_;
 
   size_t thread_count_;
+  std::vector<int32_t> cpu_set_;
   uint64_t start_ns_;
   uint64_t start_cputime_ns_;
   std::unique_ptr<WatchDog> watchdog_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 4a19fb1..80c9a16 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -206,6 +206,9 @@
       .Define("-j_")
           .WithType<unsigned int>()
           .IntoKey(M::Threads)
+      .Define("--cpu-set=_")
+          .WithType<std::vector<int32_t>>()
+          .IntoKey(M::CpuSet)
       .Define("--android-root=_")
           .WithType<std::string>()
           .IntoKey(M::AndroidRoot)
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 0717e1a..8201c3c 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -53,6 +53,7 @@
 DEX2OAT_OPTIONS_KEY (bool,                           Watchdog)
 DEX2OAT_OPTIONS_KEY (int,                            WatchdogTimeout)
 DEX2OAT_OPTIONS_KEY (unsigned int,                   Threads)
+DEX2OAT_OPTIONS_KEY (std::vector<std::int32_t>,      CpuSet)
 DEX2OAT_OPTIONS_KEY (std::vector<std::string>,       ImageFilenames)
 DEX2OAT_OPTIONS_KEY (std::string,                    ImageClasses)
 DEX2OAT_OPTIONS_KEY (std::string,                    ImageClassesZip)
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 34fd146..925f25e 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -1163,6 +1163,18 @@
   return VerificationResult::kVerifies;
 }
 
+// Returns true if absolute `path` ends with relative `suffix` starting at
+// a directory name boundary, i.e. after a '/'. For example, "foo/bar"
+// is a valid suffix of "/data/foo/bar" but not "/data-foo/bar".
+static inline bool AbsolutePathHasRelativeSuffix(const std::string& path,
+                                                 const std::string& suffix) {
+  DCHECK(IsAbsoluteLocation(path));
+  DCHECK(!IsAbsoluteLocation(suffix));
+  return (path.size() > suffix.size()) &&
+         (path[path.size() - suffix.size() - 1u] == '/') &&
+         (std::string_view(path).substr(/*pos*/ path.size() - suffix.size()) == suffix);
+}
+
 bool ClassLoaderContext::ClassLoaderInfoMatch(
     const ClassLoaderInfo& info,
     const ClassLoaderInfo& expected_info,
@@ -1197,40 +1209,34 @@
       // and the other as an absolute one.
       bool is_dex_name_absolute = IsAbsoluteLocation(info.classpath[k]);
       bool is_expected_dex_name_absolute = IsAbsoluteLocation(expected_info.classpath[k]);
-      std::string dex_name;
-      std::string expected_dex_name;
+      bool dex_names_match = false;
+
 
       if (is_dex_name_absolute == is_expected_dex_name_absolute) {
         // If both locations are absolute or relative then compare them as they are.
         // This is usually the case for: shared libraries and secondary dex files.
-        dex_name = info.classpath[k];
-        expected_dex_name = expected_info.classpath[k];
+        dex_names_match = (info.classpath[k] == expected_info.classpath[k]);
       } else if (is_dex_name_absolute) {
         // The runtime name is absolute but the compiled name (the expected one) is relative.
         // This is the case for split apks which depend on base or on other splits.
-        dex_name = info.classpath[k];
-        OatFile::ResolveRelativeEncodedDexLocation(info.classpath[k].c_str(),
-                                                   expected_info.classpath[k],
-                                                   &expected_dex_name);
+        dex_names_match =
+            AbsolutePathHasRelativeSuffix(info.classpath[k], expected_info.classpath[k]);
       } else if (is_expected_dex_name_absolute) {
         // The runtime name is relative but the compiled name is absolute.
         // There is no expected use case that would end up here as dex files are always loaded
         // with their absolute location. However, be tolerant and do the best effort (in case
         // there are unexpected new use case...).
-        OatFile::ResolveRelativeEncodedDexLocation(expected_info.classpath[k].c_str(),
-                                                   info.classpath[k],
-                                                   &dex_name);
-        expected_dex_name = expected_info.classpath[k];
+        dex_names_match =
+            AbsolutePathHasRelativeSuffix(expected_info.classpath[k], info.classpath[k]);
       } else {
         // Both locations are relative. In this case there's not much we can be sure about
         // except that the names are the same. The checksum will ensure that the files are
         // are same. This should not happen outside testing and manual invocations.
-        dex_name = info.classpath[k];
-        expected_dex_name = expected_info.classpath[k];
+        dex_names_match = (info.classpath[k] == expected_info.classpath[k]);
       }
 
       // Compare the locations.
-      if (dex_name != expected_dex_name) {
+      if (!dex_names_match) {
         LOG(WARNING) << "ClassLoaderContext classpath element mismatch"
             << ". expected=" << expected_info.classpath[k]
             << ", found=" << info.classpath[k]
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 0c36fd4..0083278 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -1402,7 +1402,18 @@
 
   std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader);
 
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")),
+  std::string context_with_no_base_dir = context->EncodeContextForOatFile("");
+  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_no_base_dir),
+            ClassLoaderContext::VerificationResult::kVerifies);
+
+  std::string dex_location = GetTestDexFileName("MultiDex");
+  size_t pos = dex_location.rfind('/');
+  ASSERT_NE(std::string::npos, pos);
+  std::string parent = dex_location.substr(0, pos);
+
+  std::string context_with_base_dir = context->EncodeContextForOatFile(parent);
+  ASSERT_NE(context_with_base_dir, context_with_no_base_dir);
+  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_base_dir),
             ClassLoaderContext::VerificationResult::kVerifies);
 }
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 3e3d199..4a4fac5 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1996,14 +1996,9 @@
 
   // Step 0: Extra zygote work.
 
-  // Step 0.a: If we're the zygote, mark boot.
-  if (loader.IsZygote() && CanWriteToDalvikCache(image_isa)) {
-    MarkZygoteStart(image_isa, Runtime::Current()->GetZygoteMaxFailedBoots());
-  }
-
   loader.FindImageFiles();
 
-  // Step 0.b: If we're the zygote, check for free space, and prune the cache preemptively,
+  // Step 0.a: If we're the zygote, check for free space, and prune the cache preemptively,
   //           if necessary. While the runtime may be fine (it is pretty tolerant to
   //           out-of-disk-space situations), other parts of the platform are not.
   //
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index 0eab35f..c491893 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -104,71 +104,6 @@
   }
 }
 
-// We write out an empty file to the zygote's ISA specific cache dir at the start of
-// every zygote boot and delete it when the boot completes. If we find a file already
-// present, it usually means the boot didn't complete. We wipe the entire dalvik
-// cache if that's the case.
-static void MarkZygoteStart(const InstructionSet isa, const uint32_t max_failed_boots) {
-  const std::string isa_subdir = GetDalvikCache(GetInstructionSetString(isa));
-  CHECK(!isa_subdir.empty()) << "Dalvik cache not found";
-  const std::string boot_marker = isa_subdir + "/.booting";
-  const char* file_name = boot_marker.c_str();
-
-  uint32_t num_failed_boots = 0;
-  std::unique_ptr<File> file(OS::OpenFileReadWrite(file_name));
-  if (file.get() == nullptr) {
-    file.reset(OS::CreateEmptyFile(file_name));
-
-    if (file.get() == nullptr) {
-      int saved_errno = errno;
-      PLOG(WARNING) << "Failed to create boot marker.";
-      if (saved_errno != ENOSPC) {
-        return;
-      }
-
-      LOG(WARNING) << "Pruning dalvik cache because of low-memory situation.";
-      impl::DeleteDirectoryContents(isa_subdir, false);
-
-      // Try once more.
-      file.reset(OS::OpenFileReadWrite(file_name));
-      if (file == nullptr) {
-        PLOG(WARNING) << "Failed to create boot marker.";
-        return;
-      }
-    }
-  } else {
-    if (!file->ReadFully(&num_failed_boots, sizeof(num_failed_boots))) {
-      PLOG(WARNING) << "Failed to read boot marker.";
-      file->Erase();
-      return;
-    }
-  }
-
-  if (max_failed_boots != 0 && num_failed_boots > max_failed_boots) {
-    LOG(WARNING) << "Incomplete boot detected. Pruning dalvik cache";
-    impl::DeleteDirectoryContents(isa_subdir, false);
-  }
-
-  ++num_failed_boots;
-  VLOG(startup) << "Number of failed boots on : " << boot_marker << " = " << num_failed_boots;
-
-  if (lseek(file->Fd(), 0, SEEK_SET) == -1) {
-    PLOG(WARNING) << "Failed to write boot marker.";
-    file->Erase();
-    return;
-  }
-
-  if (!file->WriteFully(&num_failed_boots, sizeof(num_failed_boots))) {
-    PLOG(WARNING) << "Failed to write boot marker.";
-    file->Erase();
-    return;
-  }
-
-  if (file->FlushCloseOrErase() != 0) {
-    PLOG(WARNING) << "Failed to flush boot marker.";
-  }
-}
-
 }  // namespace space
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc
index e3b95b9..1055057 100644
--- a/runtime/jni/jni_internal.cc
+++ b/runtime/jni/jni_internal.cc
@@ -342,10 +342,13 @@
 // things not rendering correctly. E.g. b/16858794
 static constexpr bool kWarnJniAbort = false;
 
+// Disable native JNI checking pending stack walk re-evaluation (b/136276414).
+static constexpr bool kNativeJniCheckEnabled = false;
+
 template<typename T>
 ALWAYS_INLINE static bool ShouldDenyAccessToMember(T* member, Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (IsWhitelistedNativeCaller()) {
+  if (kNativeJniCheckEnabled && IsWhitelistedNativeCaller()) {
     return false;
   }
   return hiddenapi::ShouldDenyAccessToMember(
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 05015e3..54dae10 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1425,13 +1425,17 @@
     // SetVdex will take ownership of the VdexFile.
     SetVdex(vdex_file.release());
 
-    // Create a dummy OatHeader.
+    // Create a dummy OatHeader with a key store containing only the compiler
+    // filter (it helps debugging and is required by
+    // OatHeader::GetCompilerFilter).
     std::unique_ptr<const InstructionSetFeatures> isa_features =
         InstructionSetFeatures::FromCppDefines();
+    SafeMap<std::string, std::string> store;
+    store.Put(OatHeader::kCompilerFilter, CompilerFilter::NameOfFilter(CompilerFilter::kVerify));
     oat_header_.reset(OatHeader::Create(kRuntimeISA,
                                         isa_features.get(),
                                         dex_files.size(),
-                                        nullptr));
+                                        &store));
     const uint8_t* begin = reinterpret_cast<const uint8_t*>(oat_header_.get());
     SetBegin(begin);
     SetEnd(begin + oat_header_->GetHeaderSize());
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 70ed7c8..be0e30a 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1833,8 +1833,11 @@
           group_name_field->GetObject(thread_group)->AsString();
       group_name = (group_name_string != nullptr) ? group_name_string->ToModifiedUtf8() : "<null>";
     }
+  } else if (thread != nullptr) {
+    priority = thread->GetNativePriority();
   } else {
-    priority = GetNativePriority();
+    PaletteStatus status = PaletteSchedGetPriority(tid, &priority);
+    CHECK(status == PaletteStatus::kOkay || status == PaletteStatus::kCheckErrno);
   }
 
   std::string scheduler_group_name(GetSchedulerGroupName(tid));
@@ -4266,15 +4269,13 @@
 }
 
 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);
+  PaletteStatus status = PaletteSchedSetPriority(GetTid(), new_priority);
   CHECK(status == PaletteStatus::kOkay || status == PaletteStatus::kCheckErrno);
 }
 
-int Thread::GetNativePriority() {
+int Thread::GetNativePriority() const {
   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);
+  PaletteStatus status = PaletteSchedGetPriority(GetTid(), &priority);
   CHECK(status == PaletteStatus::kOkay || status == PaletteStatus::kCheckErrno);
   return priority;
 }
diff --git a/runtime/thread.h b/runtime/thread.h
index dd483c1..ae04600 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -375,12 +375,12 @@
   void SetNativePriority(int newPriority);
 
   /*
-   * Returns the thread priority for the current thread by querying the system.
+   * Returns the priority of this thread by querying the system.
    * This is useful when attaching a thread through JNI.
    *
    * Returns a value from 1 to 10 (compatible with java.lang.Thread values).
    */
-  static int GetNativePriority();
+  int GetNativePriority() const;
 
   // Guaranteed to be non-zero.
   uint32_t GetThreadId() const {
diff --git a/test/1004-checker-volatile-ref-load/expected.txt b/test/1004-checker-volatile-ref-load/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/1004-checker-volatile-ref-load/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/1004-checker-volatile-ref-load/info.txt b/test/1004-checker-volatile-ref-load/info.txt
new file mode 100644
index 0000000..1ba4a52
--- /dev/null
+++ b/test/1004-checker-volatile-ref-load/info.txt
@@ -0,0 +1,6 @@
+Regression test for b/140507091: Check that an explicit null check is
+emitted for a volatile field load on ARM64 at the beginning of the
+Baker read barrier thunk, so that a null holder object is properly
+caught (and throws a NullPointerException as expected), instead of
+trigerring a SIGSEGV, when the Concurrent Copying GC is in the marking
+phase.
diff --git a/test/1004-checker-volatile-ref-load/run b/test/1004-checker-volatile-ref-load/run
new file mode 100644
index 0000000..bdaa71b
--- /dev/null
+++ b/test/1004-checker-volatile-ref-load/run
@@ -0,0 +1,18 @@
+#! /bin/bash
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Limit the managed heap to 16 MiB to force more garbage collections.
+exec ${RUN} $@ --runtime-option -Xmx16m
diff --git a/test/1004-checker-volatile-ref-load/src/Main.java b/test/1004-checker-volatile-ref-load/src/Main.java
new file mode 100644
index 0000000..9542f36
--- /dev/null
+++ b/test/1004-checker-volatile-ref-load/src/Main.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+class Foo {
+  volatile Object bar;
+}
+
+public class Main {
+
+  public static void main(String[] args) {
+    Main main = new Main();
+    main.test();
+    System.out.println("passed");
+  }
+
+  // Check that no explicit null check is emitted for the field load of volatile
+  // field `Foo.bar` before entering the Baker read barrier thunk.
+  //
+  // Note: We cannot check the ARM64 assembly code of the Baker read barrier
+  // thunk code, as it is not emitted in the CFG output.
+  //
+  /// CHECK-START-ARM64: void Main.test() disassembly (after)
+  /// CHECK:       <<Foo:l\d+>> InstanceFieldGet [{{l\d+}}] field_name:Main.foo field_type:Reference loop:<<Loop:B\d+>>
+  /// CHECK:       NullCheck [<<Foo>>] dex_pc:<<PC:\d+>> loop:<<Loop>>
+  /// CHECK-NEXT:  InstanceFieldGet [<<Foo>>] dex_pc:<<PC>> field_name:Foo.bar field_type:Reference loop:<<Loop>>
+  /// CHECK-NEXT:      add w<<BaseRegNum:\d+>>, {{w\d+}}, #0x8 (8)
+  /// CHECK-NEXT:      adr lr, #+0x{{c|10}}
+  // The following instruction (generated by
+  // `art::arm64::CodeGeneratorARM64::EmitBakerReadBarrierCbnz`) checks the
+  // Marking Register (X20) and goes into the Baker read barrier thunk if MR is
+  // not null. The null offset (#+0x0) in the CBNZ instruction is a placeholder
+  // for the offset to the Baker read barrier thunk (which is not yet set when
+  // the CFG output is emitted).
+  /// CHECK-NEXT:      cbnz x20, #+0x0
+  /// CHECK-NEXT:      ldar {{w\d+}}, [x<<BaseRegNum>>]
+
+  public void test() {
+    // Continually check that reading field `foo.bar` throws a
+    // NullPointerException while allocating over 64 MiB of memory (with heap
+    // size limited to 16 MiB), in order to increase memory pressure and
+    // eventually trigger a concurrent garbage collection, which will start by
+    // putting the GC in marking mode and enable read barriers (when the
+    // Concurrent Copying collector is used).
+    for (int i = 0; i != 64 * 1024; ++i) {
+      allocateAtLeast1KiB();
+      try {
+        // Read volatile field `bar` of `foo`, which is null, and is expected
+        // to produce a NullPointerException. On ARM64, this is implemented as a
+        // load-acquire (LDAR instruction).
+        //
+        // When the Concurrent Copying GC is marking, read barriers are enabled
+        // and the field load executes code from a Baker read barrier thunk.
+        // On ARM64, there used to be a bug in this thunk for the load-acquire
+        // case, where an explicit null check was missing, triggering an
+        // unhandled SIGSEGV when trying to load the lock word from the volatile
+        // field (b/140507091).
+        Object foo_bar = foo.bar;
+      } catch (NullPointerException e) {
+        continue;
+      }
+      // We should not be here.
+      throw new Error("Expected NullPointerException");
+    }
+  }
+
+  // Allocate at least 1 KiB of memory on the managed heap.
+  // Retain some allocated memory and release old allocations so that the
+  // garbage collector has something to do.
+  public static void allocateAtLeast1KiB() {
+    memory[allocationIndex] = new Object[1024 / 4];
+    ++allocationIndex;
+    if (allocationIndex == memory.length) {
+      allocationIndex = 0;
+    }
+  }
+
+  public static Object[] memory = new Object[1024];
+  public static int allocationIndex = 0;
+
+  private Foo foo;
+
+}
diff --git a/test/692-vdex-inmem-loader/src/Main.java b/test/692-vdex-inmem-loader/src/Main.java
index 53f4c36..3ebe2c1 100644
--- a/test/692-vdex-inmem-loader/src/Main.java
+++ b/test/692-vdex-inmem-loader/src/Main.java
@@ -57,6 +57,13 @@
 
     if (invokeMethod) {
       loader.loadClass("art.ClassB").getDeclaredMethod("printHello").invoke(null);
+
+      if (expectedBackedByOat) {
+        String filter = getCompilerFilter(loader.loadClass("art.ClassB"));
+        if (!("verify".equals(filter))) {
+          throw new Error("Expected verify, got " + filter);
+        }
+      }
     }
   }
 
@@ -118,6 +125,7 @@
   private static native boolean hasVdexFile(ClassLoader loader);
   private static native boolean isBackedByOatFile(ClassLoader loader);
   private static native boolean areClassesPreverified(ClassLoader loader);
+  private static native String getCompilerFilter(Class cls);
 
   // Defined in 674-hiddenapi.
   private static native void appendToBootClassLoader(String dexPath, boolean isCorePlatform);
diff --git a/test/720-thread-priority/expected.txt b/test/720-thread-priority/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/720-thread-priority/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/720-thread-priority/info.txt b/test/720-thread-priority/info.txt
new file mode 100644
index 0000000..0122261
--- /dev/null
+++ b/test/720-thread-priority/info.txt
@@ -0,0 +1,2 @@
+Regression test for Thread.setPriority, which used to always set the priority
+to the main thread, instead of the passed one.
diff --git a/test/720-thread-priority/src/Main.java b/test/720-thread-priority/src/Main.java
new file mode 100644
index 0000000..9ea5cfc
--- /dev/null
+++ b/test/720-thread-priority/src/Main.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.concurrent.CountDownLatch;
+
+public class Main {
+   static final CountDownLatch processStarted = new CountDownLatch(1);
+   static final CountDownLatch prioritySet = new CountDownLatch(1);
+
+   static int initialPlatformPriority = 0;
+   static int maxPlatformPriority = 0;
+
+   static class MyThread extends Thread {
+        public void run() {
+            try {
+                int priority = getThreadPlatformPriority();
+                if (priority != initialPlatformPriority) {
+                    throw new Error("Expected " + initialPlatformPriority + ", got " + priority);
+                }
+                processStarted.countDown();
+                prioritySet.await();
+                priority = getThreadPlatformPriority();
+                if (priority != maxPlatformPriority) {
+                    throw new Error("Expected " + maxPlatformPriority + ", got " + priority);
+                }
+            } catch (Exception e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.loadLibrary(args[0]);
+
+        // Fetch priorities from the main thread to know what to compare against.
+        int javaPriority = Thread.currentThread().getPriority();
+        initialPlatformPriority = getThreadPlatformPriority();
+        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
+        maxPlatformPriority = getThreadPlatformPriority();
+        Thread.currentThread().setPriority(javaPriority);
+
+        MyThread t1 = new MyThread();
+        t1.start();
+        processStarted.await();
+
+        t1.setPriority(Thread.MAX_PRIORITY);
+        prioritySet.countDown();
+        t1.join();
+    }
+
+    private static native int getThreadPlatformPriority();
+}
diff --git a/test/720-thread-priority/thread_priority.cc b/test/720-thread-priority/thread_priority.cc
new file mode 100644
index 0000000..db4a2b2
--- /dev/null
+++ b/test/720-thread-priority/thread_priority.cc
@@ -0,0 +1,28 @@
+/*
+ * 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 <sys/time.h>
+#include <sys/resource.h>
+
+#include "base/macros.h"
+#include "base/utils.h"
+#include "jni.h"
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getThreadPlatformPriority(
+    JNIEnv* env ATTRIBUTE_UNUSED,
+    jclass clazz ATTRIBUTE_UNUSED) {
+  return getpriority(PRIO_PROCESS, art::GetTid());
+}
diff --git a/test/911-get-stack-trace/src/art/PrintThread.java b/test/911-get-stack-trace/src/art/PrintThread.java
index 798db06..94f3a33 100644
--- a/test/911-get-stack-trace/src/art/PrintThread.java
+++ b/test/911-get-stack-trace/src/art/PrintThread.java
@@ -42,7 +42,7 @@
   // may not exist depending on the environment.
   public final static String IGNORE_THREAD_NAME_REGEX =
       "Binder:|RenderThread|hwuiTask|Jit thread pool worker|Instr:|JDWP|Profile Saver|main|" +
-      "queued-work-looper|InstrumentationConnectionThread|intel_svc_streamer_thread";
+      "queued-work-looper|InstrumentationConnectionThread|intel_svc_streamer_thread|ForkJoinPool";
   public final static Matcher IGNORE_THREADS =
       Pattern.compile(IGNORE_THREAD_NAME_REGEX).matcher("");
 
diff --git a/test/Android.bp b/test/Android.bp
index 9cf5606..cb9f612 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -496,6 +496,7 @@
         "674-hiddenapi/hiddenapi.cc",
         "692-vdex-inmem-loader/vdex_inmem_loader.cc",
         "708-jit-cache-churn/jit.cc",
+        "720-thread-priority/thread_priority.cc",
         "800-smali/jni.cc",
         "909-attach-agent/disallow_debugging.cc",
         "1001-app-image-regions/app_image_regions.cc",
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index a0b2f1e..ba2d46e 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -66,6 +66,24 @@
   return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE;
 }
 
+extern "C" JNIEXPORT jobject JNICALL Java_Main_getCompilerFilter(JNIEnv* env,
+                                                                 jclass caller ATTRIBUTE_UNUSED,
+                                                                 jclass cls) {
+  ScopedObjectAccess soa(env);
+
+  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
+  const DexFile& dex_file = klass->GetDexFile();
+  const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
+  if (oat_dex_file == nullptr) {
+    return nullptr;
+  }
+
+  std::string filter =
+      CompilerFilter::NameOfFilter(oat_dex_file->GetOatFile()->GetCompilerFilter());
+  return soa.AddLocalReference<jobject>(
+      mirror::String::AllocFromModifiedUtf8(soa.Self(), filter.c_str()));
+}
+
 // public static native boolean runtimeIsSoftFail();
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_runtimeIsSoftFail(JNIEnv* env ATTRIBUTE_UNUSED,
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 0bff4c2..9e57764 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1239,6 +1239,19 @@
         "description": [ "Working as intended tests that don't pass with baseline." ]
     },
     {
+        "tests": ["1004-checker-volatile-ref-load"],
+        "env_vars": {"ART_USE_READ_BARRIER": "false"},
+        "bug": "b/140507091",
+        "description": ["Test containing Checker assertions expecting Baker read barriers."]
+    },
+    {
+        "tests": ["1004-checker-volatile-ref-load"],
+        "env_vars": {"ART_READ_BARRIER_TYPE": "TABLELOOKUP"},
+        "bug": "b/140507091",
+        "description": ["Test containing Checker assertions expecting Baker read barriers."]
+    },
+    {
+
         "tests": ["570-checker-osr-locals"],
         "variant": "jvm",
         "bug": "b/154802847",