Handle new zygote flags in ART

Add support for DISABLE_VERIFIER and ONLY_USE_SYSTEM_OAT_FILES.

bug: 30972906
bug: 63920015

Test: device boots
Change-Id: I7c4eddc070908aed980d54d374c0b261d1f32d57
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index d767e98..e40a071 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -31,6 +31,8 @@
 #include "nativehelper/JNIHelp.h"
 #include "nativehelper/ScopedUtfChars.h"
 #include "non_debuggable_classes.h"
+#include "oat_file.h"
+#include "oat_file_manager.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "thread-current-inl.h"
@@ -154,20 +156,22 @@
   }
 }
 
-static void EnableDebugFeatures(uint32_t runtime_flags) {
-  // Must match values in com.android.internal.os.Zygote.
-  enum {
-    DEBUG_ENABLE_JDWP               = 1,
-    DEBUG_ENABLE_CHECKJNI           = 1 << 1,
-    DEBUG_ENABLE_ASSERT             = 1 << 2,
-    DEBUG_ENABLE_SAFEMODE           = 1 << 3,
-    DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
-    DEBUG_GENERATE_DEBUG_INFO       = 1 << 5,
-    DEBUG_ALWAYS_JIT                = 1 << 6,
-    DEBUG_NATIVE_DEBUGGABLE         = 1 << 7,
-    DEBUG_JAVA_DEBUGGABLE           = 1 << 8,
-  };
+// Must match values in com.android.internal.os.Zygote.
+enum {
+  DEBUG_ENABLE_JDWP               = 1,
+  DEBUG_ENABLE_CHECKJNI           = 1 << 1,
+  DEBUG_ENABLE_ASSERT             = 1 << 2,
+  DEBUG_ENABLE_SAFEMODE           = 1 << 3,
+  DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
+  DEBUG_GENERATE_DEBUG_INFO       = 1 << 5,
+  DEBUG_ALWAYS_JIT                = 1 << 6,
+  DEBUG_NATIVE_DEBUGGABLE         = 1 << 7,
+  DEBUG_JAVA_DEBUGGABLE           = 1 << 8,
+  DISABLE_VERIFIER                = 1 << 9,
+  ONLY_USE_SYSTEM_OAT_FILES       = 1 << 10,
+};
 
+static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
   Runtime* const runtime = Runtime::Current();
   if ((runtime_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
     JavaVMExt* vm = runtime->GetJavaVM();
@@ -237,9 +241,7 @@
     runtime_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
   }
 
-  if (runtime_flags != 0) {
-    LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
-  }
+  return runtime_flags;
 }
 
 static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
@@ -266,7 +268,21 @@
   Thread* thread = reinterpret_cast<Thread*>(token);
   // Our system thread ID, etc, has changed so reset Thread state.
   thread->InitAfterFork();
-  EnableDebugFeatures(runtime_flags);
+  runtime_flags = EnableDebugFeatures(runtime_flags);
+
+  if ((runtime_flags & DISABLE_VERIFIER) != 0) {
+    Runtime::Current()->DisableVerifier();
+    runtime_flags &= ~DISABLE_VERIFIER;
+  }
+
+  if ((runtime_flags & ONLY_USE_SYSTEM_OAT_FILES) != 0) {
+    Runtime::Current()->GetOatFileManager().SetOnlyUseSystemOatFiles();
+    runtime_flags &= ~ONLY_USE_SYSTEM_OAT_FILES;
+  }
+
+  if (runtime_flags != 0) {
+    LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
+  }
 
   // Update tracing.
   if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 516c833..05b63d2 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "android-base/stringprintf.h"
+#include "android-base/strings.h"
 
 #include "art_field-inl.h"
 #include "base/bit_vector-inl.h"
@@ -51,8 +52,15 @@
 // If true, we attempt to load the application image if it exists.
 static constexpr bool kEnableAppImage = true;
 
+static bool OatFileIsOnSystem(const std::unique_ptr<const OatFile>& oat_file) {
+  UniqueCPtr<const char[]> path(realpath(oat_file->GetLocation().c_str(), nullptr));
+  return path != nullptr && android::base::StartsWith(oat_file->GetLocation(), GetAndroidRoot());
+}
+
 const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
   WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+  CHECK(!only_use_system_oat_files_ || OatFileIsOnSystem(oat_file))
+      << "Registering a non /system oat file: " << oat_file->GetLocation();
   DCHECK(oat_file != nullptr);
   if (kIsDebugBuild) {
     CHECK(oat_files_.find(oat_file) == oat_files_.end());
@@ -421,7 +429,8 @@
 
   const OatFile* source_oat_file = nullptr;
 
-  if (!oat_file_assistant.IsUpToDate()) {
+  // No point in trying to make up-to-date if we can only use system oat files.
+  if (!only_use_system_oat_files_ && !oat_file_assistant.IsUpToDate()) {
     // Update the oat file on disk if we can, based on the --compiler-filter
     // option derived from the current runtime options.
     // This may fail, but that's okay. Best effort is all that matters here.
@@ -447,10 +456,12 @@
   // Get the oat file on disk.
   std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
 
-  // Prevent oat files from being loaded if no class_loader or dex_elements are provided.
-  // This can happen when the deprecated DexFile.<init>(String) is called directly, and it
-  // could load oat files without checking the classpath, which would be incorrect.
-  if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
+  if (oat_file != nullptr && only_use_system_oat_files_ && !OatFileIsOnSystem(oat_file)) {
+    // If the oat file is not on /system, don't use it.
+  } else  if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
+    // Prevent oat files from being loaded if no class_loader or dex_elements are provided.
+    // This can happen when the deprecated DexFile.<init>(String) is called directly, and it
+    // could load oat files without checking the classpath, which would be incorrect.
     // Take the file only if it has no collisions, or we must take it because of preopting.
     bool accept_oat_file =
         !HasCollisions(oat_file.get(), context.get(), /*out*/ &error_msg);
@@ -597,6 +608,12 @@
   return dex_files;
 }
 
+void OatFileManager::SetOnlyUseSystemOatFiles() {
+  ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
+  CHECK_EQ(oat_files_.size(), GetBootOatFiles().size());
+  only_use_system_oat_files_ = true;
+}
+
 void OatFileManager::DumpForSigQuit(std::ostream& os) {
   ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
   std::vector<const OatFile*> boot_oat_files = GetBootOatFiles();
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 4523494..1205773 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -45,7 +45,7 @@
 // pointers returned from functions are always valid.
 class OatFileManager {
  public:
-  OatFileManager() : have_non_pic_oat_file_(false) {}
+  OatFileManager() : have_non_pic_oat_file_(false), only_use_system_oat_files_(false) {}
   ~OatFileManager();
 
   // Add an oat file to the internal accounting, std::aborts if there already exists an oat file
@@ -105,6 +105,8 @@
 
   void DumpForSigQuit(std::ostream& os);
 
+  void SetOnlyUseSystemOatFiles();
+
  private:
   // Check that the class loader context of the given oat file matches the given context.
   // This will perform a check that all class loaders in the chain have the same type and
@@ -125,6 +127,7 @@
 
   std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
   bool have_non_pic_oat_file_;
+  bool only_use_system_oat_files_;
 
   DISALLOW_COPY_AND_ASSIGN(OatFileManager);
 };
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5888762..c68c341 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2330,6 +2330,10 @@
   }
 }
 
+void Runtime::DisableVerifier() {
+  verify_ = verifier::VerifyMode::kNone;
+}
+
 bool Runtime::IsVerificationEnabled() const {
   return verify_ == verifier::VerifyMode::kEnable ||
       verify_ == verifier::VerifyMode::kSoftFail;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 2eb4411..399e1c1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -514,6 +514,7 @@
     return !implicit_so_checks_;
   }
 
+  void DisableVerifier();
   bool IsVerificationEnabled() const;
   bool IsVerificationSoftFail() const;