Snap for 9554547 from 0992003fecb94552d355b50040cb4b2936c3de3d to mainline-networking-release

Change-Id: Id7e7c5ad33ac30192625fce681eafcfd1b1c7d06
diff --git a/dex2oat/dex2oat_cts_test.cc b/dex2oat/dex2oat_cts_test.cc
index 41c7015..2541264 100644
--- a/dex2oat/dex2oat_cts_test.cc
+++ b/dex2oat/dex2oat_cts_test.cc
@@ -14,11 +14,54 @@
  * limitations under the License.
  */
 
+#include "base/file_utils.h"
 #include "dex2oat_environment_test.h"
 
 namespace art {
 
-class Dex2oatCtsTest : public Dex2oatEnvironmentTest {};
+class Dex2oatCtsTest : public CommonArtTest, public Dex2oatScratchDirs {
+ public:
+  void SetUp() override {
+    CommonArtTest::SetUp();
+    Dex2oatScratchDirs::SetUp(android_data_);
+  }
+
+  void TearDown() override {
+    Dex2oatScratchDirs::TearDown();
+    CommonArtTest::TearDown();
+  }
+
+ protected:
+  // Stripped down counterpart to Dex2oatEnvironmentTest::Dex2Oat that only adds
+  // enough arguments for our purposes.
+  int Dex2Oat(const std::vector<std::string>& dex2oat_args,
+              std::string* output,
+              std::string* error_msg) {
+    // This command line should work regardless of bitness, ISA, etc.
+    std::vector<std::string> argv = {std::string(kAndroidArtApexDefaultPath) + "/bin/dex2oat"};
+    argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
+
+    // We must set --android-root.
+    const char* android_root = getenv("ANDROID_ROOT");
+    CHECK(android_root != nullptr);
+    argv.push_back("--android-root=" + std::string(android_root));
+
+    // We need dex2oat to actually log things.
+    auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:d", 1) == 0; };
+    ForkAndExecResult res = ForkAndExec(argv, post_fork_fn, output);
+    if (res.stage != ForkAndExecResult::kFinished) {
+      *error_msg = strerror(errno);
+      ::testing::AssertionFailure() << "Failed to finish dex2oat invocation: " << *error_msg;
+    }
+
+    if (!res.StandardSuccess()) {
+      // We cannot use ASSERT_TRUE since the method returns an int and not void.
+      ::testing::AssertionFailure() << "dex2oat fork/exec failed: " << *error_msg;
+    }
+
+    return res.status_code;
+  }
+};
 
 // Run dex2oat with --enable-palette-compilation-hooks to force calls to
 // PaletteNotify{Start,End}Dex2oatCompilation.
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index 6124ed9..bd06043 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -139,6 +139,8 @@
 
   static void TearDownAndroidDataDir(const std::string& android_data, bool fail_on_error);
 
+  static void ClearDirectory(const char* dirpath, bool recursive = true);
+
   // Get the names of the libcore modules.
   virtual std::vector<std::string> GetLibCoreModuleNames() const;
 
@@ -231,8 +233,6 @@
 
   std::unique_ptr<const DexFile> LoadExpectSingleDexFile(const char* location);
 
-  void ClearDirectory(const char* dirpath, bool recursive = true);
-
   // Open a file (allows reading of framework jars).
   std::vector<std::unique_ptr<const DexFile>> OpenDexFiles(const char* filename);
 
diff --git a/libartpalette/apex/palette_test.cc b/libartpalette/apex/palette_test.cc
index 853dc29..0bcc093 100644
--- a/libartpalette/apex/palette_test.cc
+++ b/libartpalette/apex/palette_test.cc
@@ -21,7 +21,6 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
-#include "common_runtime_test.h"
 #include "gtest/gtest.h"
 
 namespace {
@@ -70,14 +69,32 @@
 #endif
 }
 
-class PaletteClientJniTest : public art::CommonRuntimeTest {};
-
-TEST_F(PaletteClientJniTest, JniInvocation) {
+TEST_F(PaletteClientTest, JniInvocation) {
+#ifndef ART_TARGET_ANDROID
+  // On host we need to set up a boot classpath and pass it in here. Let's not
+  // bother since this test is only for native API coverage on target.
+  GTEST_SKIP() << "Will only spin up a VM on Android";
+#else
   bool enabled;
   EXPECT_EQ(PALETTE_STATUS_OK, PaletteShouldReportJniInvocations(&enabled));
 
-  JNIEnv* env = art::Thread::Current()->GetJniEnv();
+  JavaVMInitArgs vm_args;
+  JavaVMOption options[] = {
+      {.optionString = "-verbose:jni", .extraInfo = nullptr},
+  };
+  vm_args.version = JNI_VERSION_1_6;
+  vm_args.nOptions = std::size(options);
+  vm_args.options = options;
+  vm_args.ignoreUnrecognized = JNI_TRUE;
+
+  JavaVM* jvm = nullptr;
+  JNIEnv* env = nullptr;
+  EXPECT_EQ(JNI_OK, JNI_CreateJavaVM(&jvm, &env, &vm_args));
   ASSERT_NE(nullptr, env);
+
   PaletteNotifyBeginJniInvocation(env);
   PaletteNotifyEndJniInvocation(env);
+
+  EXPECT_EQ(JNI_OK, jvm->DestroyJavaVM());
+#endif
 }
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 964b7f3..e867c4f 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -41,21 +41,17 @@
 
 static constexpr bool kDebugArgs = false;
 
-// Test class that provides some helpers to set a test up for compilation using dex2oat.
-class Dex2oatEnvironmentTest : public CommonRuntimeTest {
+class Dex2oatScratchDirs {
  public:
-  void SetUp() override {
-    CommonRuntimeTest::SetUp();
-    const ArtDexFileLoader dex_file_loader;
-
+  void SetUp(const std::string& android_data) {
     // Create a scratch directory to work from.
 
     // Get the realpath of the android data. The oat dir should always point to real location
     // when generating oat files in dalvik-cache. This avoids complicating the unit tests
     // when matching the expected paths.
-    UniqueCPtr<const char[]> android_data_real(realpath(android_data_.c_str(), nullptr));
+    UniqueCPtr<const char[]> android_data_real(realpath(android_data.c_str(), nullptr));
     ASSERT_TRUE(android_data_real != nullptr)
-      << "Could not get the realpath of the android data" << android_data_ << strerror(errno);
+        << "Could not get the realpath of the android data" << android_data << strerror(errno);
 
     scratch_dir_.assign(android_data_real.get());
     scratch_dir_ += "/Dex2oatEnvironmentTest";
@@ -67,6 +63,41 @@
 
     odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
     ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+  }
+
+  void TearDown() {
+    CommonArtTest::ClearDirectory(odex_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
+
+    CommonArtTest::ClearDirectory(odex_oat_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
+
+    CommonArtTest::ClearDirectory(scratch_dir_.c_str());
+    ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
+  }
+
+  // Scratch directory, for dex and odex files (oat files will go in the
+  // dalvik cache).
+  const std::string& GetScratchDir() const { return scratch_dir_; }
+
+  // Odex directory is the subdirectory in the scratch directory where odex
+  // files should be located.
+  const std::string& GetOdexDir() const { return odex_dir_; }
+
+ private:
+  std::string scratch_dir_;
+  std::string odex_oat_dir_;
+  std::string odex_dir_;
+};
+
+// Test class that provides some helpers to set a test up for compilation using dex2oat.
+class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTest {
+ public:
+  void SetUp() override {
+    CommonRuntimeTest::SetUp();
+    Dex2oatScratchDirs::SetUp(android_data_);
+
+    const ArtDexFileLoader dex_file_loader;
 
     // Verify the environment is as we expect
     std::vector<uint32_t> checksums;
@@ -122,15 +153,7 @@
   }
 
   void TearDown() override {
-    ClearDirectory(odex_dir_.c_str());
-    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
-
-    ClearDirectory(odex_oat_dir_.c_str());
-    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
-
-    ClearDirectory(scratch_dir_.c_str());
-    ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
-
+    Dex2oatScratchDirs::TearDown();
     CommonRuntimeTest::TearDown();
   }
 
@@ -165,18 +188,6 @@
     return GetTestDexFileName("Nested");
   }
 
-  // Scratch directory, for dex and odex files (oat files will go in the
-  // dalvik cache).
-  const std::string& GetScratchDir() const {
-    return scratch_dir_;
-  }
-
-  // Odex directory is the subdirectory in the scratch directory where odex
-  // files should be located.
-  const std::string& GetOdexDir() const {
-    return odex_dir_;
-  }
-
   int Dex2Oat(const std::vector<std::string>& dex2oat_args,
               std::string* output,
               std::string* error_msg) {
@@ -232,11 +243,6 @@
 
     return res.status_code;
   }
-
- private:
-  std::string scratch_dir_;
-  std::string odex_oat_dir_;
-  std::string odex_dir_;
 };
 
 }  // namespace art
diff --git a/runtime/gc/collector/mark_compact-inl.h b/runtime/gc/collector/mark_compact-inl.h
index d6919aa..57517d5 100644
--- a/runtime/gc/collector/mark_compact-inl.h
+++ b/runtime/gc/collector/mark_compact-inl.h
@@ -276,7 +276,7 @@
       stack_high_addr = reinterpret_cast<char*>(stack_low_addr) + self->GetStackSize();
     }
     if (root < stack_low_addr || root > stack_high_addr) {
-      auto ret = updated_roots_.insert(root);
+      auto ret = updated_roots_->insert(root);
       DCHECK(ret.second) << "root=" << root << " old_ref=" << old_ref
                          << " stack_low_addr=" << stack_low_addr
                          << " stack_high_addr=" << stack_high_addr;
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index 38cbcb7..f262b66 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -243,6 +243,7 @@
       gc_barrier_(0),
       mark_stack_lock_("mark compact mark stack lock", kMarkSweepMarkStackLock),
       bump_pointer_space_(heap->GetBumpPointerSpace()),
+      moving_space_bitmap_(bump_pointer_space_->GetMarkBitmap()),
       moving_to_space_fd_(kFdUnused),
       moving_from_space_fd_(kFdUnused),
       uffd_(kFdUnused),
@@ -250,9 +251,12 @@
       compaction_in_progress_count_(0),
       compacting_(false),
       uffd_initialized_(false),
-      uffd_minor_fault_supported_(GetUffdAndMinorFault().second),
+      uffd_minor_fault_supported_(false),
       minor_fault_initialized_(false),
       map_linear_alloc_shared_(false) {
+  if (kIsDebugBuild) {
+    updated_roots_.reset(new std::unordered_set<void*>());
+  }
   // TODO: Depending on how the bump-pointer space move is implemented. If we
   // switch between two virtual memories each time, then we will have to
   // initialize live_words_bitmap_ accordingly.
@@ -435,13 +439,8 @@
       // in these spaces. This card-table will eventually be used to track
       // mutations while concurrent marking is going on.
       card_table->ClearCardRange(space->Begin(), space->Limit());
-      if (space == bump_pointer_space_) {
-        // It is OK to clear the bitmap with mutators running since the only
-        // place it is read is VisitObjects which has exclusion with this GC.
-        moving_space_bitmap_ = bump_pointer_space_->GetMarkBitmap();
-        moving_space_bitmap_->Clear();
-      } else {
-        CHECK(space == heap_->GetNonMovingSpace());
+      if (space != bump_pointer_space_) {
+        CHECK_EQ(space, heap_->GetNonMovingSpace());
         non_moving_space_ = space;
         non_moving_space_bitmap_ = space->GetMarkBitmap();
       }
@@ -449,6 +448,28 @@
   }
 }
 
+void MarkCompact::MarkZygoteLargeObjects() {
+  Thread* self = thread_running_gc_;
+  DCHECK_EQ(self, Thread::Current());
+  space::LargeObjectSpace* const los = heap_->GetLargeObjectsSpace();
+  if (los != nullptr) {
+    // Pick the current live bitmap (mark bitmap if swapped).
+    accounting::LargeObjectBitmap* const live_bitmap = los->GetLiveBitmap();
+    accounting::LargeObjectBitmap* const mark_bitmap = los->GetMarkBitmap();
+    // Walk through all of the objects and explicitly mark the zygote ones so they don't get swept.
+    std::pair<uint8_t*, uint8_t*> range = los->GetBeginEndAtomic();
+    live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(range.first),
+                                  reinterpret_cast<uintptr_t>(range.second),
+                                  [mark_bitmap, los, self](mirror::Object* obj)
+                                      REQUIRES(Locks::heap_bitmap_lock_)
+                                          REQUIRES_SHARED(Locks::mutator_lock_) {
+                                            if (los->IsZygoteLargeObject(self, obj)) {
+                                              mark_bitmap->Set(obj);
+                                            }
+                                          });
+  }
+}
+
 void MarkCompact::InitializePhase() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   mark_stack_ = heap_->GetMarkStack();
@@ -3456,6 +3477,7 @@
   DCHECK_EQ(thread_running_gc_, Thread::Current());
   WriterMutexLock mu(thread_running_gc_, *Locks::heap_bitmap_lock_);
   BindAndResetBitmaps();
+  MarkZygoteLargeObjects();
   MarkRoots(
         static_cast<VisitRootFlags>(kVisitRootFlagAllRoots | kVisitRootFlagStartLoggingNewRoots));
   MarkReachableObjects();
@@ -3626,8 +3648,15 @@
         << " doesn't belong to any of the spaces and large object space doesn't exist";
     accounting::LargeObjectBitmap* los_bitmap = heap_->GetLargeObjectsSpace()->GetMarkBitmap();
     DCHECK(los_bitmap->HasAddress(obj));
-    return kParallel ? !los_bitmap->AtomicTestAndSet(obj)
-                     : !los_bitmap->Set(obj);
+    if (kParallel) {
+      los_bitmap->AtomicTestAndSet(obj);
+    } else {
+      los_bitmap->Set(obj);
+    }
+    // We only have primitive arrays in large object space. So there is no
+    // reason to push into mark-stack.
+    DCHECK(obj->IsString() || (obj->IsArrayInstance() && !obj->IsObjectArray()));
+    return false;
   }
 }
 
@@ -3752,6 +3781,11 @@
 
   info_map_.MadviseDontNeedAndZero();
   live_words_bitmap_->ClearBitmap();
+  // TODO: We can clear this bitmap right before compaction pause. But in that
+  // case we need to ensure that we don't assert on this bitmap afterwards.
+  // Also, we would still need to clear it here again as we may have to use the
+  // bitmap for black-allocations (see UpdateMovingSpaceBlackAllocations()).
+  moving_space_bitmap_->Clear();
 
   if (UNLIKELY(is_zygote && IsValidFd(uffd_))) {
     heap_->DeleteThreadPool();
@@ -3762,7 +3796,9 @@
   }
   CHECK(mark_stack_->IsEmpty());  // Ensure that the mark stack is empty.
   mark_stack_->Reset();
-  updated_roots_.clear();
+  if (kIsDebugBuild && updated_roots_.get() != nullptr) {
+    updated_roots_->clear();
+  }
   class_after_obj_ordered_map_.clear();
   delete[] moving_pages_status_;
   linear_alloc_arenas_.clear();
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index 498a56d..78ee5c5 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -510,6 +510,9 @@
   // the lowest-address obj is compacted.
   void UpdateClassAfterObjMap();
 
+  void MarkZygoteLargeObjects() REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(Locks::heap_bitmap_lock_);
+
   // Buffers, one per worker thread + gc-thread, to be used when
   // kObjPtrPoisoning == true as in that case we can't have the buffer on the
   // stack. The first page of the buffer is assigned to
@@ -536,7 +539,7 @@
   // GC-root is updated twice.
   // TODO: Must be replaced with an efficient mechanism eventually. Or ensure
   // that double updation doesn't happen in the first place.
-  std::unordered_set<void*> updated_roots_;
+  std::unique_ptr<std::unordered_set<void*>> updated_roots_;
   MemMap from_space_map_;
   MemMap shadow_to_space_map_;
   // Any array of live-bytes in logical chunks of kOffsetChunkSize size
@@ -628,11 +631,11 @@
   size_t last_checked_reclaim_page_idx_;
   uint8_t* last_reclaimed_page_;
 
-  // The main space bitmap
-  accounting::ContinuousSpaceBitmap* moving_space_bitmap_;
-  accounting::ContinuousSpaceBitmap* non_moving_space_bitmap_;
   space::ContinuousSpace* non_moving_space_;
   space::BumpPointerSpace* const bump_pointer_space_;
+  // The main space bitmap
+  accounting::ContinuousSpaceBitmap* const moving_space_bitmap_;
+  accounting::ContinuousSpaceBitmap* non_moving_space_bitmap_;
   Thread* thread_running_gc_;
   // Array of pages' compaction status.
   Atomic<PageState>* moving_pages_status_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 2cb1bf1..c450676 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -417,7 +417,18 @@
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "Heap() entering";
   }
+
   LOG(INFO) << "Using " << foreground_collector_type_ << " GC.";
+  if (!gUseUserfaultfd) {
+    // This ensures that userfaultfd syscall is done before any seccomp filter is installed.
+    // TODO(b/266731037): Remove this when we no longer need to collect metric on userfaultfd
+    // support.
+    auto [uffd_supported, minor_fault_supported] = collector::MarkCompact::GetUffdAndMinorFault();
+    // The check is just to ensure that compiler doesn't eliminate the function call above.
+    // Userfaultfd support is certain to be there if its minor-fault feature is supported.
+    CHECK_IMPLIES(minor_fault_supported, uffd_supported);
+  }
+
   if (gUseReadBarrier) {
     CHECK_EQ(foreground_collector_type_, kCollectorTypeCC);
     CHECK_EQ(background_collector_type_, kCollectorTypeCCBackground);
@@ -2521,7 +2532,7 @@
       new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space_);
   CHECK(mod_union_table != nullptr) << "Failed to create zygote space mod-union table";
 
-  if (collector_type_ != kCollectorTypeCC) {
+  if (collector_type_ != kCollectorTypeCC && collector_type_ != kCollectorTypeCMC) {
     // Set all the cards in the mod-union table since we don't know which objects contain references
     // to large objects.
     mod_union_table->SetCards();
@@ -2533,10 +2544,10 @@
     mod_union_table->ProcessCards();
     mod_union_table->ClearTable();
 
-    // For CC we never collect zygote large objects. This means we do not need to set the cards for
-    // the zygote mod-union table and we can also clear all of the existing image mod-union tables.
-    // The existing mod-union tables are only for image spaces and may only reference zygote and
-    // image objects.
+    // For CC and CMC we never collect zygote large objects. This means we do not need to set the
+    // cards for the zygote mod-union table and we can also clear all of the existing image
+    // mod-union tables. The existing mod-union tables are only for image spaces and may only
+    // reference zygote and image objects.
     for (auto& pair : mod_union_tables_) {
       CHECK(pair.first->IsImageSpace());
       CHECK(!pair.first->AsImageSpace()->GetImageHeader().IsAppImage());
diff --git a/test/924-threads/src/art/Test924.java b/test/924-threads/src/art/Test924.java
index e97c9c6..3555720 100644
--- a/test/924-threads/src/art/Test924.java
+++ b/test/924-threads/src/art/Test924.java
@@ -337,6 +337,19 @@
     }
   }
 
+  private static List<String> filterForThread(Object[] thread_messages, String thread_name) {
+    List<String> messageListForThread = new ArrayList<String>();
+
+    for (int i = 0; i < thread_messages.length; i++) {
+      String message = (String)thread_messages[i];
+      if (message.startsWith("Thread(" + thread_name + ")")) {
+        messageListForThread.add(message);
+      }
+    }
+
+    return messageListForThread;
+  }
+
   private static void doTestEvents() throws Exception {
     enableThreadEvents(true);
 
@@ -354,21 +367,24 @@
         }
       }
     };
-    Thread t = new Thread(r, "EventTestThread");
+    String thread_name = "EventTestThread";
+    Thread t = new Thread(r, thread_name);
 
     System.out.println("Constructed thread");
     Thread.yield();
     Thread.sleep(100);
-    System.out.println(Arrays.toString(getThreadEventMessages()));
+
+    // Check that there are no events related to EventTestThread that we just created.
+    System.out.println(filterForThread(getThreadEventMessages(), thread_name).toString());
 
     t.start();
     cdl1.await();
 
-    System.out.println(Arrays.toString(getThreadEventMessages()));
+    System.out.println(filterForThread(getThreadEventMessages(), thread_name).toString());
 
     cdl2.countDown();
     t.join();
-    System.out.println(Arrays.toString(getThreadEventMessages()));
+    System.out.println(filterForThread(getThreadEventMessages(), thread_name).toString());
 
     System.out.println("Thread joined");