1 /*
2  * Copyright (C) 2014 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 #ifndef ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
18 #define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
19 
20 #include <fstream>
21 #include <string>
22 #include <vector>
23 
24 #include <gtest/gtest.h>
25 
26 #include "common_runtime_test.h"
27 #include "compiler_callbacks.h"
28 #include "exec_utils.h"
29 #include "gc/heap.h"
30 #include "gc/space/image_space.h"
31 #include "oat_file_assistant.h"
32 #include "os.h"
33 #include "runtime.h"
34 #include "utils.h"
35 
36 namespace art {
37 
38 // Test class that provides some helpers to set a test up for compilation using dex2oat.
39 class Dex2oatEnvironmentTest : public CommonRuntimeTest {
40  public:
SetUp()41   virtual void SetUp() OVERRIDE {
42     CommonRuntimeTest::SetUp();
43 
44     // Create a scratch directory to work from.
45 
46     // Get the realpath of the android data. The oat dir should always point to real location
47     // when generating oat files in dalvik-cache. This avoids complicating the unit tests
48     // when matching the expected paths.
49     UniqueCPtr<const char[]> android_data_real(realpath(android_data_.c_str(), nullptr));
50     ASSERT_TRUE(android_data_real != nullptr)
51       << "Could not get the realpath of the android data" << android_data_ << strerror(errno);
52 
53     scratch_dir_.assign(android_data_real.get());
54     scratch_dir_ += "/Dex2oatEnvironmentTest";
55     ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700));
56 
57     // Create a subdirectory in scratch for odex files.
58     odex_oat_dir_ = scratch_dir_ + "/oat";
59     ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700));
60 
61     odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
62     ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
63 
64     // Verify the environment is as we expect
65     std::vector<uint32_t> checksums;
66     std::string error_msg;
67     ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str()))
68       << "Expected pre-compiled boot image to be at: " << GetSystemImageFile();
69     ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str()))
70       << "Expected dex file to be at: " << GetDexSrc1();
71     ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str()))
72       << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
73     ASSERT_FALSE(DexFile::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg))
74       << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
75     ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
76       << "Expected dex file to be at: " << GetDexSrc2();
77 
78     // GetMultiDexSrc2 should have the same primary dex checksum as
79     // GetMultiDexSrc1, but a different secondary dex checksum.
80     static constexpr bool kVerifyChecksum = true;
81     std::vector<std::unique_ptr<const DexFile>> multi1;
82     ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
83           GetMultiDexSrc1().c_str(), kVerifyChecksum, &error_msg, &multi1)) << error_msg;
84     ASSERT_GT(multi1.size(), 1u);
85 
86     std::vector<std::unique_ptr<const DexFile>> multi2;
87     ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
88           GetMultiDexSrc2().c_str(), kVerifyChecksum, &error_msg, &multi2)) << error_msg;
89     ASSERT_GT(multi2.size(), 1u);
90 
91     ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
92     ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
93   }
94 
SetUpRuntimeOptions(RuntimeOptions * options)95   virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
96     // options->push_back(std::make_pair("-verbose:oat", nullptr));
97 
98     // Set up the image location.
99     options->push_back(std::make_pair("-Ximage:" + GetImageLocation(),
100           nullptr));
101     // Make sure compilercallbacks are not set so that relocation will be
102     // enabled.
103     callbacks_.reset();
104   }
105 
TearDown()106   virtual void TearDown() OVERRIDE {
107     ClearDirectory(odex_dir_.c_str());
108     ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
109 
110     ClearDirectory(odex_oat_dir_.c_str());
111     ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
112 
113     ClearDirectory(scratch_dir_.c_str());
114     ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
115 
116     CommonRuntimeTest::TearDown();
117   }
118 
Copy(const std::string & src,const std::string & dst)119   static void Copy(const std::string& src, const std::string& dst) {
120     std::ifstream  src_stream(src, std::ios::binary);
121     std::ofstream  dst_stream(dst, std::ios::binary);
122 
123     dst_stream << src_stream.rdbuf();
124   }
125 
126   // Returns the directory where the pre-compiled core.art can be found.
127   // TODO: We should factor out this into common tests somewhere rather than
128   // re-hardcoding it here (This was copied originally from the elf writer
129   // test).
GetImageDirectory()130   std::string GetImageDirectory() const {
131     if (IsHost()) {
132       const char* host_dir = getenv("ANDROID_HOST_OUT");
133       CHECK(host_dir != nullptr);
134       return std::string(host_dir) + "/framework";
135     } else {
136       return std::string("/data/art-test");
137     }
138   }
139 
GetImageLocation()140   std::string GetImageLocation() const {
141     return GetImageDirectory() + "/core.art";
142   }
143 
GetSystemImageFile()144   std::string GetSystemImageFile() const {
145     return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA)
146       + "/core.art";
147   }
148 
GetCachedImageFile(const std::string & image_location,std::string * image,std::string * error_msg)149   bool GetCachedImageFile(const std::string& image_location,
150                           /*out*/std::string* image,
151                           /*out*/std::string* error_msg) const {
152     std::string cache;
153     bool have_android_data;
154     bool dalvik_cache_exists;
155     bool is_global_cache;
156     GetDalvikCache(GetInstructionSetString(kRuntimeISA),
157                    true,
158                    &cache,
159                    &have_android_data,
160                    &dalvik_cache_exists,
161                    &is_global_cache);
162     if (!dalvik_cache_exists) {
163       *error_msg = "Failed to create dalvik cache";
164       return false;
165     }
166     return GetDalvikCacheFilename(image_location.c_str(), cache.c_str(), image, error_msg);
167   }
168 
169   // Returns the path to an image location whose contents differ from the
170   // image at GetImageLocation(). This is used for testing mismatched
171   // image checksums in the oat_file_assistant_tests.
GetImageLocation2()172   std::string GetImageLocation2() const {
173     return GetImageDirectory() + "/core-interpreter.art";
174   }
175 
GetDexSrc1()176   std::string GetDexSrc1() const {
177     return GetTestDexFileName("Main");
178   }
179 
180   // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex
181   // file stripped.
GetStrippedDexSrc1()182   std::string GetStrippedDexSrc1() const {
183     return GetTestDexFileName("MainStripped");
184   }
185 
GetMultiDexSrc1()186   std::string GetMultiDexSrc1() const {
187     return GetTestDexFileName("MultiDex");
188   }
189 
190   // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
191   // with the contents of the secondary dex file changed.
GetMultiDexSrc2()192   std::string GetMultiDexSrc2() const {
193     return GetTestDexFileName("MultiDexModifiedSecondary");
194   }
195 
GetDexSrc2()196   std::string GetDexSrc2() const {
197     return GetTestDexFileName("Nested");
198   }
199 
200   // Scratch directory, for dex and odex files (oat files will go in the
201   // dalvik cache).
GetScratchDir()202   const std::string& GetScratchDir() const {
203     return scratch_dir_;
204   }
205 
206   // Odex directory is the subdirectory in the scratch directory where odex
207   // files should be located.
GetOdexDir()208   const std::string& GetOdexDir() const {
209     return odex_dir_;
210   }
211 
212  private:
213   std::string scratch_dir_;
214   std::string odex_oat_dir_;
215   std::string odex_dir_;
216 };
217 
218 }  // namespace art
219 
220 #endif  // ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
221