Implement VerifierDeps encoding/decoding

This patch implements serialization and deserialization of the data
recorded by VerifierDeps.

Test: m test-art-host-gtest-verifier_deps_test
Bug: 30937355
Change-Id: I19320b8e70d5c5128653d09a5cdb5b6f677a2f2d
diff --git a/runtime/verifier/verifier_deps_test.cc b/runtime/verifier/verifier_deps_test.cc
index 41a9ad3..bbaf59f 100644
--- a/runtime/verifier/verifier_deps_test.cc
+++ b/runtime/verifier/verifier_deps_test.cc
@@ -59,11 +59,21 @@
     StackHandleScope<1> hs(Thread::Current());
     Handle<mirror::ClassLoader> class_loader_handle(
         hs.NewHandle(soa->Decode<mirror::ClassLoader*>(class_loader_)));
-    mirror::Class* result = class_linker_->FindClass(Thread::Current(),
-                                                     name.c_str(),
-                                                     class_loader_handle);
-    DCHECK(result != nullptr) << name;
-    return result;
+    mirror::Class* klass = class_linker_->FindClass(Thread::Current(),
+                                                    name.c_str(),
+                                                    class_loader_handle);
+    if (klass == nullptr) {
+      DCHECK(Thread::Current()->IsExceptionPending());
+      Thread::Current()->ClearException();
+    }
+    return klass;
+  }
+
+  void SetVerifierDeps(const std::vector<const DexFile*>& dex_files) {
+    verifier_deps_.reset(new verifier::VerifierDeps(dex_files));
+    VerifierDepsCompilerCallbacks* callbacks =
+        reinterpret_cast<VerifierDepsCompilerCallbacks*>(callbacks_.get());
+    callbacks->SetVerifierDeps(verifier_deps_.get());
   }
 
   void LoadDexFile(ScopedObjectAccess* soa) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -72,16 +82,13 @@
     CHECK_EQ(dex_files.size(), 1u);
     dex_file_ = dex_files.front();
 
+    SetVerifierDeps(dex_files);
+
     mirror::ClassLoader* loader = soa->Decode<mirror::ClassLoader*>(class_loader_);
     class_linker_->RegisterDexFile(*dex_file_, loader);
 
     klass_Main_ = FindClassByName("LMain;", soa);
     CHECK(klass_Main_ != nullptr);
-
-    verifier_deps_.reset(new verifier::VerifierDeps(dex_files));
-    VerifierDepsCompilerCallbacks* callbacks =
-        reinterpret_cast<VerifierDepsCompilerCallbacks*>(callbacks_.get());
-    callbacks->SetVerifierDeps(verifier_deps_.get());
   }
 
   bool VerifyMethod(const std::string& method_name) {
@@ -138,15 +145,40 @@
     return !verifier.HasFailures();
   }
 
+  void VerifyDexFile() {
+    std::string error_msg;
+    ScopedObjectAccess soa(Thread::Current());
+
+    LoadDexFile(&soa);
+    SetVerifierDeps({ dex_file_ });
+
+    for (size_t i = 0; i < dex_file_->NumClassDefs(); i++) {
+      const char* descriptor = dex_file_->GetClassDescriptor(dex_file_->GetClassDef(i));
+      mirror::Class* klass = FindClassByName(descriptor, &soa);
+      if (klass != nullptr) {
+        MethodVerifier::VerifyClass(Thread::Current(),
+                                    klass,
+                                    nullptr,
+                                    true,
+                                    HardFailLogMode::kLogWarning,
+                                    &error_msg);
+      }
+    }
+  }
+
   bool TestAssignabilityRecording(const std::string& dst,
                                   const std::string& src,
                                   bool is_strict,
                                   bool is_assignable) {
     ScopedObjectAccess soa(Thread::Current());
     LoadDexFile(&soa);
+    mirror::Class* klass_dst = FindClassByName(dst, &soa);
+    DCHECK(klass_dst != nullptr);
+    mirror::Class* klass_src = FindClassByName(src, &soa);
+    DCHECK(klass_src != nullptr);
     verifier_deps_->AddAssignability(*dex_file_,
-                                     FindClassByName(dst, &soa),
-                                     FindClassByName(src, &soa),
+                                     klass_dst,
+                                     klass_src,
                                      is_strict,
                                      is_assignable);
     return true;
@@ -316,6 +348,34 @@
     return false;
   }
 
+  size_t NumberOfCompiledDexFiles() {
+    MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+    return verifier_deps_->dex_deps_.size();
+  }
+
+  size_t HasEachKindOfRecord() {
+    MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+
+    bool has_strings = false;
+    bool has_assignability = false;
+    bool has_classes = false;
+    bool has_fields = false;
+    bool has_methods = false;
+
+    for (auto& entry : verifier_deps_->dex_deps_) {
+      has_strings |= !entry.second->strings_.empty();
+      has_assignability |= !entry.second->assignable_types_.empty();
+      has_assignability |= !entry.second->unassignable_types_.empty();
+      has_classes |= !entry.second->classes_.empty();
+      has_fields |= !entry.second->fields_.empty();
+      has_methods |= !entry.second->direct_methods_.empty();
+      has_methods |= !entry.second->virtual_methods_.empty();
+      has_methods |= !entry.second->interface_methods_.empty();
+    }
+
+    return has_strings && has_assignability && has_classes && has_fields && has_methods;
+  }
+
   std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
   const DexFile* dex_file_;
   jobject class_loader_;
@@ -982,5 +1042,19 @@
       "virtual", "Ljava/lang/Integer;", "intValue", "()I", true, "public", "Ljava/lang/Integer;"));
 }
 
+TEST_F(VerifierDepsTest, EncodeDecode) {
+  VerifyDexFile();
+
+  ASSERT_EQ(1u, NumberOfCompiledDexFiles());
+  ASSERT_TRUE(HasEachKindOfRecord());
+
+  std::vector<uint8_t> buffer;
+  verifier_deps_->Encode(&buffer);
+  ASSERT_FALSE(buffer.empty());
+
+  VerifierDeps decoded_deps({ dex_file_ }, ArrayRef<uint8_t>(buffer));
+  ASSERT_TRUE(verifier_deps_->Equals(decoded_deps));
+}
+
 }  // namespace verifier
 }  // namespace art