• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "oat_file_assistant_context.h"
18 
19 #include <memory>
20 #include <string>
21 #include <vector>
22 
23 #include "android-base/logging.h"
24 #include "android-base/stringprintf.h"
25 #include "arch/instruction_set.h"
26 #include "base/array_ref.h"
27 #include "base/logging.h"
28 #include "base/mem_map.h"
29 #include "class_linker.h"
30 #include "dex/art_dex_file_loader.h"
31 #include "gc/heap.h"
32 #include "gc/space/image_space.h"
33 
34 namespace art {
35 
36 using ::android::base::StringPrintf;
37 using ::art::gc::space::ImageSpace;
38 
OatFileAssistantContext(std::unique_ptr<OatFileAssistantContext::RuntimeOptions> runtime_options)39 OatFileAssistantContext::OatFileAssistantContext(
40     std::unique_ptr<OatFileAssistantContext::RuntimeOptions> runtime_options)
41     : runtime_options_(std::move(runtime_options)) {
42   DCHECK_EQ(runtime_options_->boot_class_path.size(),
43             runtime_options_->boot_class_path_locations.size());
44   DCHECK_IMPLIES(
45       runtime_options_->boot_class_path_fds != nullptr,
46       runtime_options_->boot_class_path.size() == runtime_options_->boot_class_path_fds->size());
47   // Opening dex files and boot images require MemMap.
48   MemMap::Init();
49 }
50 
OatFileAssistantContext(Runtime * runtime)51 OatFileAssistantContext::OatFileAssistantContext(Runtime* runtime)
52     : OatFileAssistantContext(std::make_unique<OatFileAssistantContext::RuntimeOptions>(
53           OatFileAssistantContext::RuntimeOptions{
54               .image_locations = runtime->GetImageLocations(),
55               .boot_class_path = runtime->GetBootClassPath(),
56               .boot_class_path_locations = runtime->GetBootClassPathLocations(),
57               .boot_class_path_fds = !runtime->GetBootClassPathFds().empty() ?
58                                          &runtime->GetBootClassPathFds() :
59                                          nullptr,
60               .deny_art_apex_data_files = runtime->DenyArtApexDataFiles(),
61           })) {
62   // Fetch boot image info from the runtime.
63   std::vector<BootImageInfo>& boot_image_info_list = boot_image_info_list_by_isa_[kRuntimeISA];
64   for (const ImageSpace* image_space : runtime->GetHeap()->GetBootImageSpaces()) {
65     // We only need the checksum of the first component for each boot image. They are in image
66     // spaces that have a non-zero component count.
67     if (image_space->GetComponentCount() > 0) {
68       BootImageInfo& boot_image_info = boot_image_info_list.emplace_back();
69       boot_image_info.component_count = image_space->GetComponentCount();
70       ImageSpace::AppendImageChecksum(image_space->GetComponentCount(),
71                                       image_space->GetImageHeader().GetImageChecksum(),
72                                       &boot_image_info.checksum);
73     }
74   }
75 
76   // Fetch BCP checksums from the runtime.
77   size_t bcp_index = 0;
78   std::vector<std::string>* current_bcp_checksums = nullptr;
79   for (const DexFile* dex_file : runtime->GetClassLinker()->GetBootClassPath()) {
80     if (!DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str())) {
81       DCHECK_LT(bcp_index, runtime_options_->boot_class_path.size());
82       current_bcp_checksums = &bcp_checksums_by_index_[bcp_index++];
83     }
84     DCHECK_NE(current_bcp_checksums, nullptr);
85     current_bcp_checksums->push_back(StringPrintf("/%08x", dex_file->GetLocationChecksum()));
86   }
87   DCHECK_EQ(bcp_index, runtime_options_->boot_class_path.size());
88 
89   // Fetch APEX versions from the runtime.
90   apex_versions_ = runtime->GetApexVersions();
91 }
92 
GetRuntimeOptions() const93 const OatFileAssistantContext::RuntimeOptions& OatFileAssistantContext::GetRuntimeOptions() const {
94   return *runtime_options_;
95 }
96 
FetchAll(std::string * error_msg)97 bool OatFileAssistantContext::FetchAll(std::string* error_msg) {
98   std::vector<InstructionSet> isas = GetSupportedInstructionSets(error_msg);
99   if (isas.empty()) {
100     return false;
101   }
102   for (InstructionSet isa : isas) {
103     GetBootImageInfoList(isa);
104   }
105   for (size_t i = 0; i < runtime_options_->boot_class_path.size(); i++) {
106     if (GetBcpChecksums(i, error_msg) == nullptr) {
107       return false;
108     }
109   }
110   GetApexVersions();
111   return true;
112 }
113 
114 const std::vector<OatFileAssistantContext::BootImageInfo>&
GetBootImageInfoList(InstructionSet isa)115 OatFileAssistantContext::GetBootImageInfoList(InstructionSet isa) {
116   if (auto it = boot_image_info_list_by_isa_.find(isa); it != boot_image_info_list_by_isa_.end()) {
117     return it->second;
118   }
119 
120   ImageSpace::BootImageLayout layout(
121       ArrayRef<const std::string>(runtime_options_->image_locations),
122       ArrayRef<const std::string>(runtime_options_->boot_class_path),
123       ArrayRef<const std::string>(runtime_options_->boot_class_path_locations),
124       runtime_options_->boot_class_path_fds != nullptr ?
125           ArrayRef<const int>(*runtime_options_->boot_class_path_fds) :
126           ArrayRef<const int>(),
127       /*boot_class_path_image_fds=*/ArrayRef<const int>(),
128       /*boot_class_path_vdex_fds=*/ArrayRef<const int>(),
129       /*boot_class_path_oat_fds=*/ArrayRef<const int>(),
130       &GetApexVersions());
131 
132   std::string error_msg;
133   if (!layout.LoadFromSystem(isa, /*allow_in_memory_compilation=*/false, &error_msg)) {
134     // At this point, `layout` contains nothing.
135     VLOG(oat) << "Some error occurred when loading boot images for oat file validation: "
136               << error_msg;
137     // Create an empty entry so that we don't have to retry when the function is called again.
138     return boot_image_info_list_by_isa_[isa];
139   }
140 
141   std::vector<BootImageInfo>& boot_image_info_list = boot_image_info_list_by_isa_[isa];
142   for (const ImageSpace::BootImageLayout::ImageChunk& chunk : layout.GetChunks()) {
143     BootImageInfo& boot_image_info = boot_image_info_list.emplace_back();
144     boot_image_info.component_count = chunk.component_count;
145     ImageSpace::AppendImageChecksum(
146         chunk.component_count, chunk.checksum, &boot_image_info.checksum);
147   }
148   return boot_image_info_list;
149 }
150 
GetBcpChecksums(size_t bcp_index,std::string * error_msg)151 const std::vector<std::string>* OatFileAssistantContext::GetBcpChecksums(size_t bcp_index,
152                                                                          std::string* error_msg) {
153   DCHECK_LT(bcp_index, runtime_options_->boot_class_path.size());
154 
155   if (auto it = bcp_checksums_by_index_.find(bcp_index); it != bcp_checksums_by_index_.end()) {
156     return &it->second;
157   }
158 
159   std::vector<uint32_t> checksums;
160   std::vector<std::string> dex_locations;
161   if (!ArtDexFileLoader::GetMultiDexChecksums(
162           runtime_options_->boot_class_path[bcp_index].c_str(),
163           &checksums,
164           &dex_locations,
165           error_msg,
166           runtime_options_->boot_class_path_fds != nullptr ?
167               (*runtime_options_->boot_class_path_fds)[bcp_index] :
168               -1)) {
169     return nullptr;
170   }
171 
172   DCHECK(!checksums.empty());
173   std::vector<std::string>& bcp_checksums = bcp_checksums_by_index_[bcp_index];
174   for (uint32_t checksum : checksums) {
175     bcp_checksums.push_back(StringPrintf("/%08x", checksum));
176   }
177   return &bcp_checksums;
178 }
179 
GetApexVersions()180 const std::string& OatFileAssistantContext::GetApexVersions() {
181   if (apex_versions_.has_value()) {
182     return apex_versions_.value();
183   }
184 
185   apex_versions_ = Runtime::GetApexVersions(
186       ArrayRef<const std::string>(runtime_options_->boot_class_path_locations));
187   return apex_versions_.value();
188 }
189 
190 }  // namespace art
191