OSDN Git Service

Add VMRuntime.isBootClassPathOnDisk
authorBrian Carlstrom <bdc@google.com>
Mon, 29 Sep 2014 18:22:54 +0000 (11:22 -0700)
committerBrian Carlstrom <bdc@google.com>
Wed, 1 Oct 2014 04:49:43 +0000 (21:49 -0700)
Bug: 17679443

(cherry picked from commit 95a935415d44903b28326424beb4db5c013ef089)

Change-Id: Iba40291dead3f0b6715903c986370fd0cf1e41e1

runtime/class_linker.cc
runtime/gc/space/image_space.cc
runtime/gc/space/image_space.h
runtime/native/dalvik_system_VMRuntime.cc
runtime/runtime.cc
runtime/runtime.h
test/118-noimage-dex2oat/expected.txt
test/118-noimage-dex2oat/src/Main.java

index 2cf3820..6ed27bb 100644 (file)
@@ -1179,7 +1179,7 @@ bool ClassLinker::VerifyOatChecksums(const OatFile* oat_file,
   uint32_t image_oat_checksum = 0;
   uintptr_t image_oat_data_begin = 0;
   int32_t image_patch_delta = 0;
-  if (instruction_set == Runtime::Current()->GetInstructionSet()) {
+  if (instruction_set == runtime->GetInstructionSet()) {
     const ImageHeader& image_header = image_space->GetImageHeader();
     image_oat_checksum = image_header.GetOatChecksum();
     image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
index 353d00c..59630fe 100644 (file)
@@ -149,7 +149,8 @@ static bool GenerateImage(const std::string& image_filename, InstructionSet imag
   arg_vector.push_back(oat_file_option_string);
 
   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
-  CHECK_EQ(image_isa, kRuntimeISA) << "We should always be generating an image for the current isa.";
+  CHECK_EQ(image_isa, kRuntimeISA)
+      << "We should always be generating an image for the current isa.";
 
   int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
                                                     ART_BASE_ADDRESS_MAX_DELTA);
@@ -270,10 +271,10 @@ static bool RelocateImage(const char* image_location, const char* dest_filename,
   return Exec(argv, error_msg);
 }
 
-static ImageHeader* ReadSpecificImageHeaderOrDie(const char* filename) {
+static ImageHeader* ReadSpecificImageHeader(const char* filename, std::string* error_msg) {
   std::unique_ptr<ImageHeader> hdr(new ImageHeader);
   if (!ReadSpecificImageHeader(filename, hdr.get())) {
-    LOG(FATAL) << "Unable to read image header for " << filename;
+    *error_msg = StringPrintf("Unable to read image header for %s", filename);
     return nullptr;
   }
   return hdr.release();
@@ -281,6 +282,17 @@ static ImageHeader* ReadSpecificImageHeaderOrDie(const char* filename) {
 
 ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
                                               const InstructionSet image_isa) {
+  std::string error_msg;
+  ImageHeader* image_header = ReadImageHeader(image_location, image_isa, &error_msg);
+  if (image_header == nullptr) {
+    LOG(FATAL) << error_msg;
+  }
+  return image_header;
+}
+
+ImageHeader* ImageSpace::ReadImageHeader(const char* image_location,
+                                         const InstructionSet image_isa,
+                                         std::string* error_msg) {
   std::string system_filename;
   bool has_system = false;
   std::string cache_filename;
@@ -294,33 +306,37 @@ ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
         std::unique_ptr<ImageHeader> sys_hdr(new ImageHeader);
         std::unique_ptr<ImageHeader> cache_hdr(new ImageHeader);
         if (!ReadSpecificImageHeader(system_filename.c_str(), sys_hdr.get())) {
-          LOG(FATAL) << "Unable to read image header for " << image_location << " at "
-                     << system_filename;
+          *error_msg = StringPrintf("Unable to read image header for %s at %s",
+                                    image_location, system_filename.c_str());
           return nullptr;
         }
         if (!ReadSpecificImageHeader(cache_filename.c_str(), cache_hdr.get())) {
-          LOG(FATAL) << "Unable to read image header for " << image_location << " at "
-                     << cache_filename;
+          *error_msg = StringPrintf("Unable to read image header for %s at %s",
+                                    image_location, cache_filename.c_str());
           return nullptr;
         }
         if (sys_hdr->GetOatChecksum() != cache_hdr->GetOatChecksum()) {
-          LOG(FATAL) << "Unable to find a relocated version of image file " << image_location;
+          *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
+                                    image_location);
           return nullptr;
         }
         return cache_hdr.release();
       } else if (!has_cache) {
-        LOG(FATAL) << "Unable to find a relocated version of image file " << image_location;
+        *error_msg = StringPrintf("Unable to find a relocated version of image file %s",
+                                  image_location);
         return nullptr;
       } else if (!has_system && has_cache) {
         // This can probably just use the cache one.
-        return ReadSpecificImageHeaderOrDie(cache_filename.c_str());
+        return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
       }
     } else {
       // We don't want to relocate, Just pick the appropriate one if we have it and return.
       if (has_system && has_cache) {
         // We want the cache if the checksum matches, otherwise the system.
-        std::unique_ptr<ImageHeader> system(ReadSpecificImageHeaderOrDie(system_filename.c_str()));
-        std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeaderOrDie(cache_filename.c_str()));
+        std::unique_ptr<ImageHeader> system(ReadSpecificImageHeader(system_filename.c_str(),
+                                                                    error_msg));
+        std::unique_ptr<ImageHeader> cache(ReadSpecificImageHeader(cache_filename.c_str(),
+                                                                   error_msg));
         if (system.get() == nullptr ||
             (cache.get() != nullptr && cache->GetOatChecksum() == system->GetOatChecksum())) {
           return cache.release();
@@ -328,14 +344,14 @@ ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
           return system.release();
         }
       } else if (has_system) {
-        return ReadSpecificImageHeaderOrDie(system_filename.c_str());
+        return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
       } else if (has_cache) {
-        return ReadSpecificImageHeaderOrDie(cache_filename.c_str());
+        return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
       }
     }
   }
 
-  LOG(FATAL) << "Unable to find image file for: " << image_location;
+  *error_msg = StringPrintf("Unable to find image file for %s", image_location);
   return nullptr;
 }
 
@@ -563,12 +579,13 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat
   CHECK_EQ(image_header.GetImageBegin(), map->Begin());
   DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
 
-  std::unique_ptr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
-                                                       PROT_READ, MAP_PRIVATE,
-                                                       file->Fd(), image_header.GetBitmapOffset(),
-                                                       false,
-                                                       image_filename,
-                                                       error_msg));
+  std::unique_ptr<MemMap> image_map(
+      MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
+                               PROT_READ, MAP_PRIVATE,
+                               file->Fd(), image_header.GetBitmapOffset(),
+                               false,
+                               image_filename,
+                               error_msg));
   if (image_map.get() == nullptr) {
     *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
     return nullptr;
@@ -616,11 +633,14 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat
   runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
 
   mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method),
+                               Runtime::kSaveAll);
   callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method),
+                               Runtime::kRefsOnly);
   callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method),
+                               Runtime::kRefsAndArgs);
 
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time)
index 2586ece..d7f8057 100644 (file)
@@ -47,10 +47,17 @@ class ImageSpace : public MemMapSpace {
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Reads the image header from the specified image location for the
-  // instruction set image_isa.
+  // instruction set image_isa or dies trying.
   static ImageHeader* ReadImageHeaderOrDie(const char* image_location,
                                            InstructionSet image_isa);
 
+  // Reads the image header from the specified image location for the
+  // instruction set image_isa. Returns nullptr on failure, with
+  // reason in error_msg.
+  static ImageHeader* ReadImageHeader(const char* image_location,
+                                      InstructionSet image_isa,
+                                      std::string* error_msg);
+
   // Give access to the OatFile.
   const OatFile* GetOatFile() const;
 
index 64d4fe2..23f46f4 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <limits.h>
 
+#include "ScopedUtfChars.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "debugger.h"
@@ -24,6 +25,8 @@
 #include "gc/allocator/dlmalloc.h"
 #include "gc/heap.h"
 #include "gc/space/dlmalloc_space.h"
+#include "gc/space/image_space.h"
+#include "instruction_set.h"
 #include "intern_table.h"
 #include "jni_internal.h"
 #include "mirror/art_method-inl.h"
@@ -91,7 +94,8 @@ static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaEleme
     return nullptr;
   }
   Runtime* runtime = Runtime::Current();
-  mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class);
+  mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
+                                                                         &element_class);
   if (UNLIKELY(array_class == nullptr)) {
     return nullptr;
   }
@@ -518,6 +522,28 @@ static void VMRuntime_registerAppInfo(JNIEnv* env, jclass, jstring pkgName,
   env->ReleaseStringUTFChars(pkgName, pkgNameChars);
 }
 
+static jboolean VMRuntime_isBootClassPathOnDisk(JNIEnv* env, jclass, jstring java_instruction_set) {
+  ScopedUtfChars instruction_set(env, java_instruction_set);
+  if (instruction_set.c_str() == nullptr) {
+    return JNI_FALSE;
+  }
+  InstructionSet isa = GetInstructionSetFromString(instruction_set.c_str());
+  if (isa == kNone) {
+    ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException"));
+    std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str()));
+    env->ThrowNew(iae.get(), message.c_str());
+    return JNI_FALSE;
+  }
+  std::string error_msg;
+  std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeader(
+      Runtime::Current()->GetImageLocation().c_str(), isa, &error_msg));
+  return image_header.get() != nullptr;
+}
+
+static jstring VMRuntime_getCurrentInstructionSet(JNIEnv* env, jclass) {
+  return env->NewStringUTF(GetInstructionSetString(kRuntimeISA));
+}
+
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"),
   NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -543,7 +569,10 @@ static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMRuntime, is64Bit, "!()Z"),
   NATIVE_METHOD(VMRuntime, isCheckJniEnabled, "!()Z"),
   NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"),
-  NATIVE_METHOD(VMRuntime, registerAppInfo, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
+  NATIVE_METHOD(VMRuntime, registerAppInfo,
+                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"),
+  NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
+  NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
 };
 
 void register_dalvik_system_VMRuntime(JNIEnv* env) {
index 49f8c63..48439b6 100644 (file)
@@ -678,6 +678,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
   compiler_executable_ = options->compiler_executable_;
   compiler_options_ = options->compiler_options_;
   image_compiler_options_ = options->image_compiler_options_;
+  image_location_ = options->image_;
 
   max_spins_before_thin_lock_inflation_ = options->max_spins_before_thin_lock_inflation_;
 
index 35e3a88..1a6c6e0 100644 (file)
@@ -137,6 +137,10 @@ class Runtime {
     return image_compiler_options_;
   }
 
+  const std::string& GetImageLocation() const {
+    return image_location_;
+  }
+
   const ProfilerOptions& GetProfilerOptions() const {
     return profiler_options_;
   }
@@ -537,6 +541,7 @@ class Runtime {
   std::string patchoat_executable_;
   std::vector<std::string> compiler_options_;
   std::vector<std::string> image_compiler_options_;
+  std::string image_location_;
 
   std::string boot_class_path_string_;
   std::string class_path_string_;
index 472a5f2..6825fae 100644 (file)
@@ -1,6 +1,6 @@
 Run -Xnoimage-dex2oat
-Has image is false, is image dex2oat enabled is false.
+Has image is false, is image dex2oat enabled is false, is BOOTCLASSPATH on disk is false.
 Run -Ximage-dex2oat
-Has image is true, is image dex2oat enabled is true.
+Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
 Run default
-Has image is true, is image dex2oat enabled is true.
+Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true.
index 11c736a..c83b84d 100644 (file)
  * limitations under the License.
  */
 
+import java.lang.reflect.Method;
+
 public class Main {
-  public static void main(String[] args) {
+  public static void main(String[] args) throws Exception {
     boolean hasImage = hasImage();
+    String instructionSet = VMRuntime.getCurrentInstructionSet();
+    boolean isBootClassPathOnDisk = VMRuntime.isBootClassPathOnDisk(instructionSet);
     System.out.println(
         "Has image is " + hasImage + ", is image dex2oat enabled is "
-        + isImageDex2OatEnabled() + ".");
+        + isImageDex2OatEnabled() + ", is BOOTCLASSPATH on disk is "
+        + isBootClassPathOnDisk + ".");
 
     if (hasImage && !isImageDex2OatEnabled()) {
       throw new Error("Image with dex2oat disabled runs with an oat file");
     } else if (!hasImage && isImageDex2OatEnabled()) {
       throw new Error("Image with dex2oat enabled runs without an oat file");
     }
+    if (hasImage && !isBootClassPathOnDisk) {
+      throw new Error("Image with dex2oat disabled runs with an image file");
+    } else if (!hasImage && isBootClassPathOnDisk) {
+      throw new Error("Image with dex2oat enabled runs without an image file");
+    }
   }
 
   static {
@@ -35,4 +45,26 @@ public class Main {
   private native static boolean hasImage();
 
   private native static boolean isImageDex2OatEnabled();
+
+  private static class VMRuntime {
+    private static final Method getCurrentInstructionSetMethod;
+    private static final Method isBootClassPathOnDiskMethod;
+    static {
+        try {
+            Class c = Class.forName("dalvik.system.VMRuntime");
+            getCurrentInstructionSetMethod = c.getDeclaredMethod("getCurrentInstructionSet");
+            isBootClassPathOnDiskMethod = c.getDeclaredMethod("isBootClassPathOnDisk",
+                                                              String.class);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String getCurrentInstructionSet() throws Exception {
+      return (String) getCurrentInstructionSetMethod.invoke(null);
+    }
+    public static boolean isBootClassPathOnDisk(String instructionSet) throws Exception {
+      return (boolean) isBootClassPathOnDiskMethod.invoke(null, instructionSet);
+    }
+  }
 }