image_space.cc revision c87d27b25994da8670d82a8f7bad6327b693bfff
1/*
2 * Copyright (C) 2011 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 "image_space.h"
18
19#include "base/stl_util.h"
20#include "base/unix_file/fd_file.h"
21#include "base/scoped_flock.h"
22#include "gc/accounting/space_bitmap-inl.h"
23#include "mirror/art_method.h"
24#include "mirror/class-inl.h"
25#include "mirror/object-inl.h"
26#include "oat_file.h"
27#include "os.h"
28#include "space-inl.h"
29#include "utils.h"
30
31namespace art {
32namespace gc {
33namespace space {
34
35Atomic<uint32_t> ImageSpace::bitmap_index_(0);
36
37ImageSpace::ImageSpace(const std::string& image_filename, const char* image_location,
38                       MemMap* mem_map, accounting::ContinuousSpaceBitmap* live_bitmap)
39    : MemMapSpace(image_filename, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
40                  kGcRetentionPolicyNeverCollect),
41      image_location_(image_location) {
42  DCHECK(live_bitmap != nullptr);
43  live_bitmap_.reset(live_bitmap);
44}
45
46static bool GenerateImage(const std::string& image_filename, std::string* error_msg) {
47  const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
48  std::vector<std::string> boot_class_path;
49  Split(boot_class_path_string, ':', boot_class_path);
50  if (boot_class_path.empty()) {
51    *error_msg = "Failed to generate image because no boot class path specified";
52    return false;
53  }
54
55  std::vector<std::string> arg_vector;
56
57  std::string dex2oat(Runtime::Current()->GetCompilerExecutable());
58  arg_vector.push_back(dex2oat);
59
60  std::string image_option_string("--image=");
61  image_option_string += image_filename;
62  arg_vector.push_back(image_option_string);
63
64  arg_vector.push_back("--runtime-arg");
65  arg_vector.push_back("-Xms64m");
66
67  arg_vector.push_back("--runtime-arg");
68  arg_vector.push_back("-Xmx64m");
69
70
71  for (size_t i = 0; i < boot_class_path.size(); i++) {
72    arg_vector.push_back(std::string("--dex-file=") + boot_class_path[i]);
73  }
74
75  std::string oat_file_option_string("--oat-file=");
76  oat_file_option_string += image_filename;
77  oat_file_option_string.erase(oat_file_option_string.size() - 3);
78  oat_file_option_string += "oat";
79  arg_vector.push_back(oat_file_option_string);
80
81  Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
82
83  arg_vector.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS));
84
85  if (kIsTargetBuild) {
86    arg_vector.push_back("--image-classes-zip=/system/framework/framework.jar");
87    arg_vector.push_back("--image-classes=preloaded-classes");
88  } else {
89    arg_vector.push_back("--host");
90  }
91
92  const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions();
93  for (size_t i = 0; i < compiler_options.size(); ++i) {
94    arg_vector.push_back(compiler_options[i].c_str());
95  }
96
97  std::string command_line(Join(arg_vector, ' '));
98  LOG(INFO) << "GenerateImage: " << command_line;
99  return Exec(arg_vector, error_msg);
100}
101
102bool ImageSpace::FindImageFilename(const char* image_location,
103                                   const InstructionSet image_isa,
104                                   std::string* image_filename,
105                                   bool *is_system) {
106  // image_location = /system/framework/boot.art
107  // system_image_location = /system/framework/<image_isa>/boot.art
108  std::string system_image_filename(GetSystemImageFilename(image_location, image_isa));
109  if (OS::FileExists(system_image_filename.c_str())) {
110    *image_filename = system_image_filename;
111    *is_system = true;
112    return true;
113  }
114
115  const std::string dalvik_cache = GetDalvikCacheOrDie(GetInstructionSetString(image_isa));
116
117  // Always set output location even if it does not exist,
118  // so that the caller knows where to create the image.
119  //
120  // image_location = /system/framework/boot.art
121  // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
122  *image_filename = GetDalvikCacheFilenameOrDie(image_location, dalvik_cache.c_str());
123  *is_system = false;
124  return OS::FileExists(image_filename->c_str());
125}
126
127ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
128                                              const InstructionSet image_isa) {
129  std::string image_filename;
130  bool is_system = false;
131  if (FindImageFilename(image_location, image_isa, &image_filename, &is_system)) {
132    std::unique_ptr<File> image_file(OS::OpenFileForReading(image_filename.c_str()));
133    std::unique_ptr<ImageHeader> image_header(new ImageHeader);
134    const bool success = image_file->ReadFully(image_header.get(), sizeof(ImageHeader));
135    if (!success || !image_header->IsValid()) {
136      LOG(FATAL) << "Invalid Image header for: " << image_filename;
137      return nullptr;
138    }
139
140    return image_header.release();
141  }
142
143  LOG(FATAL) << "Unable to find image file for: " << image_location;
144  return nullptr;
145}
146
147ImageSpace* ImageSpace::Create(const char* image_location,
148                               const InstructionSet image_isa) {
149  std::string image_filename;
150  std::string error_msg;
151  bool is_system = false;
152  const bool found_image = FindImageFilename(image_location, image_isa, &image_filename,
153                                             &is_system);
154
155  // Note that we must not use the file descriptor associated with
156  // ScopedFlock::GetFile to Init the image file. We want the file
157  // descriptor (and the associated exclusive lock) to be released when
158  // we leave Create.
159  ScopedFlock image_lock;
160  image_lock.Init(image_filename.c_str(), &error_msg);
161
162  if (found_image) {
163    ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location, !is_system,
164                                         &error_msg);
165    if (space != nullptr) {
166      return space;
167    }
168
169    // If the /system file exists, it should be up-to-date, don't try to generate it.
170    // If it's not the /system file, log a warning and fall through to GenerateImage.
171    if (is_system) {
172      LOG(FATAL) << "Failed to load image '" << image_filename << "': " << error_msg;
173      return nullptr;
174    } else {
175      LOG(WARNING) << error_msg;
176    }
177  }
178
179  CHECK(GenerateImage(image_filename, &error_msg))
180      << "Failed to generate image '" << image_filename << "': " << error_msg;
181  ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location, true, &error_msg);
182  if (space == nullptr) {
183    LOG(FATAL) << "Failed to load image '" << image_filename << "': " << error_msg;
184  }
185  return space;
186}
187
188void ImageSpace::VerifyImageAllocations() {
189  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
190  while (current < End()) {
191    DCHECK_ALIGNED(current, kObjectAlignment);
192    mirror::Object* obj = reinterpret_cast<mirror::Object*>(current);
193    CHECK(live_bitmap_->Test(obj));
194    CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
195    if (kUseBakerOrBrooksReadBarrier) {
196      obj->AssertReadBarrierPointer();
197    }
198    current += RoundUp(obj->SizeOf(), kObjectAlignment);
199  }
200}
201
202ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_location,
203                             bool validate_oat_file, std::string* error_msg) {
204  CHECK(image_filename != nullptr);
205  CHECK(image_location != nullptr);
206
207  uint64_t start_time = 0;
208  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
209    start_time = NanoTime();
210    LOG(INFO) << "ImageSpace::Init entering image_filename=" << image_filename;
211  }
212
213  std::unique_ptr<File> file(OS::OpenFileForReading(image_filename));
214  if (file.get() == NULL) {
215    *error_msg = StringPrintf("Failed to open '%s'", image_filename);
216    return nullptr;
217  }
218  ImageHeader image_header;
219  bool success = file->ReadFully(&image_header, sizeof(image_header));
220  if (!success || !image_header.IsValid()) {
221    *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
222    return nullptr;
223  }
224
225  // Note: The image header is part of the image due to mmap page alignment required of offset.
226  std::unique_ptr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
227                                                 image_header.GetImageSize(),
228                                                 PROT_READ | PROT_WRITE,
229                                                 MAP_PRIVATE,
230                                                 file->Fd(),
231                                                 0,
232                                                 false,
233                                                 image_filename,
234                                                 error_msg));
235  if (map.get() == NULL) {
236    DCHECK(!error_msg->empty());
237    return nullptr;
238  }
239  CHECK_EQ(image_header.GetImageBegin(), map->Begin());
240  DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
241
242  std::unique_ptr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
243                                                       PROT_READ, MAP_PRIVATE,
244                                                       file->Fd(), image_header.GetBitmapOffset(),
245                                                       false,
246                                                       image_filename,
247                                                       error_msg));
248  if (image_map.get() == nullptr) {
249    *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
250    return nullptr;
251  }
252  uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1);
253  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename,
254                                       bitmap_index));
255  std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap(
256      accounting::ContinuousSpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
257                                                          reinterpret_cast<byte*>(map->Begin()),
258                                                          map->Size()));
259  if (bitmap.get() == nullptr) {
260    *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str());
261    return nullptr;
262  }
263
264  std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename, image_location,
265                                             map.release(), bitmap.release()));
266
267  // VerifyImageAllocations() will be called later in Runtime::Init()
268  // as some class roots like ArtMethod::java_lang_reflect_ArtMethod_
269  // and ArtField::java_lang_reflect_ArtField_, which are used from
270  // Object::SizeOf() which VerifyImageAllocations() calls, are not
271  // set yet at this point.
272
273  space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
274  if (space->oat_file_.get() == nullptr) {
275    DCHECK(!error_msg->empty());
276    return nullptr;
277  }
278
279  if (validate_oat_file && !space->ValidateOatFile(error_msg)) {
280    DCHECK(!error_msg->empty());
281    return nullptr;
282  }
283
284  Runtime* runtime = Runtime::Current();
285  runtime->SetInstructionSet(space->oat_file_->GetOatHeader().GetInstructionSet());
286
287  mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
288  runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
289  mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod);
290  runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method));
291  mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt);
292  runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt));
293
294  mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
295  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
296  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
297  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
298  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
299  runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
300
301  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
302    LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time)
303             << ") " << *space.get();
304  }
305  return space.release();
306}
307
308OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg) const {
309  const ImageHeader& image_header = GetImageHeader();
310  std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_path);
311
312  OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin(),
313                                    !Runtime::Current()->IsCompiler(), error_msg);
314  if (oat_file == NULL) {
315    *error_msg = StringPrintf("Failed to open oat file '%s' referenced from image %s: %s",
316                              oat_filename.c_str(), GetName(), error_msg->c_str());
317    return nullptr;
318  }
319  uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
320  uint32_t image_oat_checksum = image_header.GetOatChecksum();
321  if (oat_checksum != image_oat_checksum) {
322    *error_msg = StringPrintf("Failed to match oat file checksum 0x%x to expected oat checksum 0x%x"
323                              " in image %s", oat_checksum, image_oat_checksum, GetName());
324    return nullptr;
325  }
326  return oat_file;
327}
328
329bool ImageSpace::ValidateOatFile(std::string* error_msg) const {
330  CHECK(oat_file_.get() != NULL);
331  for (const OatFile::OatDexFile* oat_dex_file : oat_file_->GetOatDexFiles()) {
332    const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
333    uint32_t dex_file_location_checksum;
334    if (!DexFile::GetChecksum(dex_file_location.c_str(), &dex_file_location_checksum, error_msg)) {
335      *error_msg = StringPrintf("Failed to get checksum of dex file '%s' referenced by image %s: "
336                                "%s", dex_file_location.c_str(), GetName(), error_msg->c_str());
337      return false;
338    }
339    if (dex_file_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
340      *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file '%s' and "
341                                "dex file '%s' (0x%x != 0x%x)",
342                                oat_file_->GetLocation().c_str(), dex_file_location.c_str(),
343                                oat_dex_file->GetDexFileLocationChecksum(),
344                                dex_file_location_checksum);
345      return false;
346    }
347  }
348  return true;
349}
350
351const OatFile* ImageSpace::GetOatFile() const {
352  return oat_file_.get();
353}
354
355OatFile* ImageSpace::ReleaseOatFile() {
356  CHECK(oat_file_.get() != NULL);
357  return oat_file_.release();
358}
359
360void ImageSpace::Dump(std::ostream& os) const {
361  os << GetType()
362      << " begin=" << reinterpret_cast<void*>(Begin())
363      << ",end=" << reinterpret_cast<void*>(End())
364      << ",size=" << PrettySize(Size())
365      << ",name=\"" << GetName() << "\"]";
366}
367
368}  // namespace space
369}  // namespace gc
370}  // namespace art
371