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