Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <string>
     18 #include <vector>
     19 
     20 #include <backtrace/BacktraceMap.h>
     21 #include <gtest/gtest.h>
     22 
     23 #include "base/file_utils.h"
     24 #include "common_runtime_test.h"
     25 #include "compiler_callbacks.h"
     26 #include "dex2oat_environment_test.h"
     27 #include "dexopt_test.h"
     28 #include "gc/space/image_space.h"
     29 #include "mem_map.h"
     30 
     31 namespace art {
     32 void DexoptTest::SetUp() {
     33   ReserveImageSpace();
     34   Dex2oatEnvironmentTest::SetUp();
     35 }
     36 
     37 void DexoptTest::PreRuntimeCreate() {
     38   std::string error_msg;
     39   ASSERT_TRUE(PreRelocateImage(GetImageLocation(), &error_msg)) << error_msg;
     40   ASSERT_TRUE(PreRelocateImage(GetImageLocation2(), &error_msg)) << error_msg;
     41   UnreserveImageSpace();
     42 }
     43 
     44 void DexoptTest::PostRuntimeCreate() {
     45   ReserveImageSpace();
     46 }
     47 
     48 void DexoptTest::GenerateOatForTest(const std::string& dex_location,
     49                                     const std::string& oat_location_in,
     50                                     CompilerFilter::Filter filter,
     51                                     bool relocate,
     52                                     bool pic,
     53                                     bool with_alternate_image,
     54                                     const char* compilation_reason) {
     55   std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA));
     56   std::string dalvik_cache_tmp = dalvik_cache + ".redirected";
     57   std::string oat_location = oat_location_in;
     58   if (!relocate) {
     59     // Temporarily redirect the dalvik cache so dex2oat doesn't find the
     60     // relocated image file.
     61     ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno);
     62     // If the oat location is in dalvik cache, replace the cache path with the temporary one.
     63     size_t pos = oat_location.find(dalvik_cache);
     64     if (pos != std::string::npos) {
     65         oat_location = oat_location.replace(pos, dalvik_cache.length(), dalvik_cache_tmp);
     66     }
     67   }
     68 
     69   std::vector<std::string> args;
     70   args.push_back("--dex-file=" + dex_location);
     71   args.push_back("--oat-file=" + oat_location);
     72   args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
     73   args.push_back("--runtime-arg");
     74 
     75   // Use -Xnorelocate regardless of the relocate argument.
     76   // We control relocation by redirecting the dalvik cache when needed
     77   // rather than use this flag.
     78   args.push_back("-Xnorelocate");
     79 
     80   ScratchFile profile_file;
     81   if (CompilerFilter::DependsOnProfile(filter)) {
     82     args.push_back("--profile-file=" + profile_file.GetFilename());
     83   }
     84 
     85   if (pic) {
     86     args.push_back("--compile-pic");
     87   }
     88 
     89   std::string image_location = GetImageLocation();
     90   if (with_alternate_image) {
     91     args.push_back("--boot-image=" + GetImageLocation2());
     92   }
     93 
     94   if (compilation_reason != nullptr) {
     95     args.push_back("--compilation-reason=" + std::string(compilation_reason));
     96   }
     97 
     98   std::string error_msg;
     99   ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
    100 
    101   if (!relocate) {
    102     // Restore the dalvik cache if needed.
    103     ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno);
    104     oat_location = oat_location_in;
    105   }
    106 
    107   // Verify the odex file was generated as expected.
    108   std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1,
    109                                                    oat_location.c_str(),
    110                                                    oat_location.c_str(),
    111                                                    nullptr,
    112                                                    nullptr,
    113                                                    false,
    114                                                    /*low_4gb*/false,
    115                                                    dex_location.c_str(),
    116                                                    &error_msg));
    117   ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    118   EXPECT_EQ(pic, odex_file->IsPic());
    119   EXPECT_EQ(filter, odex_file->GetCompilerFilter());
    120 
    121   std::unique_ptr<ImageHeader> image_header(
    122           gc::space::ImageSpace::ReadImageHeader(image_location.c_str(),
    123                                                  kRuntimeISA,
    124                                                  &error_msg));
    125   ASSERT_TRUE(image_header != nullptr) << error_msg;
    126   const OatHeader& oat_header = odex_file->GetOatHeader();
    127   uint32_t combined_checksum = image_header->GetOatChecksum();
    128 
    129   if (CompilerFilter::DependsOnImageChecksum(filter)) {
    130     if (with_alternate_image) {
    131       EXPECT_NE(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
    132     } else {
    133       EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
    134     }
    135   }
    136 
    137   if (!with_alternate_image) {
    138     if (CompilerFilter::IsAotCompilationEnabled(filter)) {
    139       if (relocate) {
    140         EXPECT_EQ(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
    141             oat_header.GetImageFileLocationOatDataBegin());
    142         EXPECT_EQ(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta());
    143       } else {
    144         EXPECT_NE(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
    145             oat_header.GetImageFileLocationOatDataBegin());
    146         EXPECT_NE(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta());
    147       }
    148     }
    149   }
    150 }
    151 
    152 void DexoptTest::GenerateOdexForTest(const std::string& dex_location,
    153                          const std::string& odex_location,
    154                          CompilerFilter::Filter filter) {
    155   GenerateOatForTest(dex_location,
    156                      odex_location,
    157                      filter,
    158                      /*relocate*/false,
    159                      /*pic*/false,
    160                      /*with_alternate_image*/false);
    161 }
    162 
    163 void DexoptTest::GeneratePicOdexForTest(const std::string& dex_location,
    164                             const std::string& odex_location,
    165                             CompilerFilter::Filter filter,
    166                             const char* compilation_reason) {
    167   GenerateOatForTest(dex_location,
    168                      odex_location,
    169                      filter,
    170                      /*relocate*/false,
    171                      /*pic*/true,
    172                      /*with_alternate_image*/false,
    173                      compilation_reason);
    174 }
    175 
    176 void DexoptTest::GenerateOatForTest(const char* dex_location,
    177                         CompilerFilter::Filter filter,
    178                         bool relocate,
    179                         bool pic,
    180                         bool with_alternate_image) {
    181   std::string oat_location;
    182   std::string error_msg;
    183   ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
    184         dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
    185   GenerateOatForTest(dex_location,
    186                      oat_location,
    187                      filter,
    188                      relocate,
    189                      pic,
    190                      with_alternate_image);
    191 }
    192 
    193 void DexoptTest::GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
    194   GenerateOatForTest(dex_location,
    195                      filter,
    196                      /*relocate*/true,
    197                      /*pic*/false,
    198                      /*with_alternate_image*/false);
    199 }
    200 
    201 bool DexoptTest::PreRelocateImage(const std::string& image_location, std::string* error_msg) {
    202   std::string dalvik_cache;
    203   bool have_android_data;
    204   bool dalvik_cache_exists;
    205   bool is_global_cache;
    206   GetDalvikCache(GetInstructionSetString(kRuntimeISA),
    207                  true,
    208                  &dalvik_cache,
    209                  &have_android_data,
    210                  &dalvik_cache_exists,
    211                  &is_global_cache);
    212   if (!dalvik_cache_exists) {
    213     *error_msg = "Failed to create dalvik cache";
    214     return false;
    215   }
    216 
    217   std::string patchoat = GetAndroidRoot();
    218   patchoat += kIsDebugBuild ? "/bin/patchoatd" : "/bin/patchoat";
    219 
    220   std::vector<std::string> argv;
    221   argv.push_back(patchoat);
    222   argv.push_back("--input-image-location=" + image_location);
    223   argv.push_back("--output-image-directory=" + dalvik_cache);
    224   argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)));
    225   argv.push_back("--base-offset-delta=0x00008000");
    226   return Exec(argv, error_msg);
    227 }
    228 
    229 void DexoptTest::ReserveImageSpace() {
    230   MemMap::Init();
    231 
    232   // Ensure a chunk of memory is reserved for the image space.
    233   // The reservation_end includes room for the main space that has to come
    234   // right after the image in case of the GSS collector.
    235   uint64_t reservation_start = ART_BASE_ADDRESS;
    236   uint64_t reservation_end = ART_BASE_ADDRESS + 384 * MB;
    237 
    238   std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true));
    239   ASSERT_TRUE(map.get() != nullptr) << "Failed to build process map";
    240   for (BacktraceMap::iterator it = map->begin();
    241       reservation_start < reservation_end && it != map->end(); ++it) {
    242     const backtrace_map_t* entry = *it;
    243     ReserveImageSpaceChunk(reservation_start, std::min(entry->start, reservation_end));
    244     reservation_start = std::max(reservation_start, entry->end);
    245   }
    246   ReserveImageSpaceChunk(reservation_start, reservation_end);
    247 }
    248 
    249 void DexoptTest::ReserveImageSpaceChunk(uintptr_t start, uintptr_t end) {
    250   if (start < end) {
    251     std::string error_msg;
    252     image_reservation_.push_back(std::unique_ptr<MemMap>(
    253         MemMap::MapAnonymous("image reservation",
    254             reinterpret_cast<uint8_t*>(start), end - start,
    255             PROT_NONE, false, false, &error_msg)));
    256     ASSERT_TRUE(image_reservation_.back().get() != nullptr) << error_msg;
    257     LOG(INFO) << "Reserved space for image " <<
    258       reinterpret_cast<void*>(image_reservation_.back()->Begin()) << "-" <<
    259       reinterpret_cast<void*>(image_reservation_.back()->End());
    260   }
    261 }
    262 
    263 void DexoptTest::UnreserveImageSpace() {
    264   image_reservation_.clear();
    265 }
    266 
    267 }  // namespace art
    268