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