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
40namespace art {
41
42// Test class that provides some helpers to set a test up for compilation using dex2oat.
43class Dex2oatEnvironmentTest : public CommonRuntimeTest {
44 public:
45  virtual 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
109  virtual 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
120  virtual 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
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).
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
154  std::string GetImageLocation() const {
155    return GetImageDirectory() + "/core.art";
156  }
157
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.
166  std::string GetImageLocation2() const {
167    return GetImageDirectory() + "/core-interpreter.art";
168  }
169
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.
176  std::string GetStrippedDexSrc1() const {
177    return GetTestDexFileName("MainStripped");
178  }
179
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.
186  std::string GetMultiDexSrc2() const {
187    return GetTestDexFileName("MultiDexModifiedSecondary");
188  }
189
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).
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.
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