xref: /aosp_15_r20/art/odrefresh/odrefresh.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "odrefresh.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <errno.h>
20*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
21*795d594fSAndroid Build Coastguard Worker #include <inttypes.h>
22*795d594fSAndroid Build Coastguard Worker #include <limits.h>
23*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
24*795d594fSAndroid Build Coastguard Worker #include <string.h>
25*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
26*795d594fSAndroid Build Coastguard Worker #include <sysexits.h>
27*795d594fSAndroid Build Coastguard Worker #include <time.h>
28*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker #include <algorithm>
31*795d594fSAndroid Build Coastguard Worker #include <cerrno>
32*795d594fSAndroid Build Coastguard Worker #include <cstdarg>
33*795d594fSAndroid Build Coastguard Worker #include <cstdint>
34*795d594fSAndroid Build Coastguard Worker #include <cstdio>
35*795d594fSAndroid Build Coastguard Worker #include <cstdlib>
36*795d594fSAndroid Build Coastguard Worker #include <cstring>
37*795d594fSAndroid Build Coastguard Worker #include <filesystem>
38*795d594fSAndroid Build Coastguard Worker #include <fstream>
39*795d594fSAndroid Build Coastguard Worker #include <functional>
40*795d594fSAndroid Build Coastguard Worker #include <initializer_list>
41*795d594fSAndroid Build Coastguard Worker #include <iosfwd>
42*795d594fSAndroid Build Coastguard Worker #include <iostream>
43*795d594fSAndroid Build Coastguard Worker #include <iterator>
44*795d594fSAndroid Build Coastguard Worker #include <memory>
45*795d594fSAndroid Build Coastguard Worker #include <optional>
46*795d594fSAndroid Build Coastguard Worker #include <ostream>
47*795d594fSAndroid Build Coastguard Worker #include <set>
48*795d594fSAndroid Build Coastguard Worker #include <sstream>
49*795d594fSAndroid Build Coastguard Worker #include <string>
50*795d594fSAndroid Build Coastguard Worker #include <string_view>
51*795d594fSAndroid Build Coastguard Worker #include <system_error>
52*795d594fSAndroid Build Coastguard Worker #include <type_traits>
53*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
54*795d594fSAndroid Build Coastguard Worker #include <unordered_set>
55*795d594fSAndroid Build Coastguard Worker #include <utility>
56*795d594fSAndroid Build Coastguard Worker #include <vector>
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker #include "android-base/chrono_utils.h"
59*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
60*795d594fSAndroid Build Coastguard Worker #include "android-base/function_ref.h"
61*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
62*795d594fSAndroid Build Coastguard Worker #include "android-base/macros.h"
63*795d594fSAndroid Build Coastguard Worker #include "android-base/parseint.h"
64*795d594fSAndroid Build Coastguard Worker #include "android-base/properties.h"
65*795d594fSAndroid Build Coastguard Worker #include "android-base/result.h"
66*795d594fSAndroid Build Coastguard Worker #include "android-base/scopeguard.h"
67*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
68*795d594fSAndroid Build Coastguard Worker #include "android-base/strings.h"
69*795d594fSAndroid Build Coastguard Worker #include "android-modules-utils/sdk_level.h"
70*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
71*795d594fSAndroid Build Coastguard Worker #include "base/file_utils.h"
72*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
73*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
74*795d594fSAndroid Build Coastguard Worker #include "base/os.h"
75*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
76*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
77*795d594fSAndroid Build Coastguard Worker #include "com_android_apex.h"
78*795d594fSAndroid Build Coastguard Worker #include "com_android_art.h"
79*795d594fSAndroid Build Coastguard Worker #include "dex/art_dex_file_loader.h"
80*795d594fSAndroid Build Coastguard Worker #include "exec_utils.h"
81*795d594fSAndroid Build Coastguard Worker #include "gc/collector/mark_compact.h"
82*795d594fSAndroid Build Coastguard Worker #include "odr_artifacts.h"
83*795d594fSAndroid Build Coastguard Worker #include "odr_common.h"
84*795d594fSAndroid Build Coastguard Worker #include "odr_config.h"
85*795d594fSAndroid Build Coastguard Worker #include "odr_fs_utils.h"
86*795d594fSAndroid Build Coastguard Worker #include "odr_metrics.h"
87*795d594fSAndroid Build Coastguard Worker #include "odrefresh/odrefresh.h"
88*795d594fSAndroid Build Coastguard Worker #include "tools/cmdline_builder.h"
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker namespace art {
91*795d594fSAndroid Build Coastguard Worker namespace odrefresh {
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker namespace {
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker namespace apex = com::android::apex;
96*795d594fSAndroid Build Coastguard Worker namespace art_apex = com::android::art;
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker using ::android::base::Basename;
99*795d594fSAndroid Build Coastguard Worker using ::android::base::Dirname;
100*795d594fSAndroid Build Coastguard Worker using ::android::base::Join;
101*795d594fSAndroid Build Coastguard Worker using ::android::base::ParseInt;
102*795d594fSAndroid Build Coastguard Worker using ::android::base::Result;
103*795d594fSAndroid Build Coastguard Worker using ::android::base::ScopeGuard;
104*795d594fSAndroid Build Coastguard Worker using ::android::base::SetProperty;
105*795d594fSAndroid Build Coastguard Worker using ::android::base::Split;
106*795d594fSAndroid Build Coastguard Worker using ::android::base::StringPrintf;
107*795d594fSAndroid Build Coastguard Worker using ::android::base::Timer;
108*795d594fSAndroid Build Coastguard Worker using ::android::modules::sdklevel::IsAtLeastU;
109*795d594fSAndroid Build Coastguard Worker using ::android::modules::sdklevel::IsAtLeastV;
110*795d594fSAndroid Build Coastguard Worker using ::art::tools::CmdlineBuilder;
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker // Name of cache info file in the ART Apex artifact cache.
113*795d594fSAndroid Build Coastguard Worker constexpr const char* kCacheInfoFile = "cache-info.xml";
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker // Maximum execution time for odrefresh from start to end.
116*795d594fSAndroid Build Coastguard Worker constexpr time_t kMaximumExecutionSeconds = 480;
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker // Maximum execution time for any child process spawned.
119*795d594fSAndroid Build Coastguard Worker constexpr time_t kMaxChildProcessSeconds = 120;
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker constexpr mode_t kFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
122*795d594fSAndroid Build Coastguard Worker 
123*795d594fSAndroid Build Coastguard Worker constexpr const char* kFirstBootImageBasename = "boot.art";
124*795d594fSAndroid Build Coastguard Worker constexpr const char* kMinimalBootImageBasename = "boot_minimal.art";
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker // The default compiler filter for primary boot image.
127*795d594fSAndroid Build Coastguard Worker constexpr const char* kPrimaryCompilerFilter = "speed-profile";
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker // The compiler filter for boot image mainline extension. We don't have profiles for mainline BCP
130*795d594fSAndroid Build Coastguard Worker // jars, so we always use "verify".
131*795d594fSAndroid Build Coastguard Worker constexpr const char* kMainlineCompilerFilter = "verify";
132*795d594fSAndroid Build Coastguard Worker 
EraseFiles(const std::vector<std::unique_ptr<File>> & files)133*795d594fSAndroid Build Coastguard Worker void EraseFiles(const std::vector<std::unique_ptr<File>>& files) {
134*795d594fSAndroid Build Coastguard Worker   for (auto& file : files) {
135*795d594fSAndroid Build Coastguard Worker     file->Erase(/*unlink=*/true);
136*795d594fSAndroid Build Coastguard Worker   }
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker // Moves `files` to the directory `output_directory_path`.
140*795d594fSAndroid Build Coastguard Worker //
141*795d594fSAndroid Build Coastguard Worker // If any of the files cannot be moved, then all copies of the files are removed from both
142*795d594fSAndroid Build Coastguard Worker // the original location and the output location.
143*795d594fSAndroid Build Coastguard Worker //
144*795d594fSAndroid Build Coastguard Worker // Returns true if all files are moved, false otherwise.
MoveOrEraseFiles(const std::vector<std::unique_ptr<File>> & files,std::string_view output_directory_path,android::base::function_ref<int (const char *,unsigned int)> restorecon)145*795d594fSAndroid Build Coastguard Worker bool MoveOrEraseFiles(const std::vector<std::unique_ptr<File>>& files,
146*795d594fSAndroid Build Coastguard Worker                       std::string_view output_directory_path,
147*795d594fSAndroid Build Coastguard Worker                       android::base::function_ref<int(const char*, unsigned int)> restorecon) {
148*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<File>> output_files;
149*795d594fSAndroid Build Coastguard Worker   for (auto& file : files) {
150*795d594fSAndroid Build Coastguard Worker     std::string file_basename(Basename(file->GetPath()));
151*795d594fSAndroid Build Coastguard Worker     std::string output_file_path = ART_FORMAT("{}/{}", output_directory_path, file_basename);
152*795d594fSAndroid Build Coastguard Worker     std::string input_file_path = file->GetPath();
153*795d594fSAndroid Build Coastguard Worker 
154*795d594fSAndroid Build Coastguard Worker     if (IsAtLeastV()) {
155*795d594fSAndroid Build Coastguard Worker       // Simply rename the existing file. Requires at least V as odrefresh does not have
156*795d594fSAndroid Build Coastguard Worker       // `selinux_android_restorecon` permissions on U and lower.
157*795d594fSAndroid Build Coastguard Worker       if (!file->Rename(output_file_path)) {
158*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to rename " << QuotePath(input_file_path) << " to "
159*795d594fSAndroid Build Coastguard Worker                     << QuotePath(output_file_path);
160*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
161*795d594fSAndroid Build Coastguard Worker         return false;
162*795d594fSAndroid Build Coastguard Worker       }
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker       if (file->FlushCloseOrErase() != 0) {
165*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to flush and close file " << QuotePath(output_file_path);
166*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
167*795d594fSAndroid Build Coastguard Worker         return false;
168*795d594fSAndroid Build Coastguard Worker       }
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker       if (restorecon(output_file_path.c_str(), 0) < 0) {
171*795d594fSAndroid Build Coastguard Worker         LOG(ERROR) << "Failed to set security context for file " << QuotePath(output_file_path);
172*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
173*795d594fSAndroid Build Coastguard Worker         return false;
174*795d594fSAndroid Build Coastguard Worker       }
175*795d594fSAndroid Build Coastguard Worker     } else {
176*795d594fSAndroid Build Coastguard Worker       // Create a new file in the output directory, copy the input file's data across, then delete
177*795d594fSAndroid Build Coastguard Worker       // the input file.
178*795d594fSAndroid Build Coastguard Worker       output_files.emplace_back(OS::CreateEmptyFileWriteOnly(output_file_path.c_str()));
179*795d594fSAndroid Build Coastguard Worker       if (output_files.back() == nullptr) {
180*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to open " << QuotePath(output_file_path);
181*795d594fSAndroid Build Coastguard Worker         output_files.pop_back();
182*795d594fSAndroid Build Coastguard Worker         EraseFiles(output_files);
183*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
184*795d594fSAndroid Build Coastguard Worker         return false;
185*795d594fSAndroid Build Coastguard Worker       }
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker       if (fchmod(output_files.back()->Fd(), kFileMode) != 0) {
188*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Could not set file mode on " << QuotePath(output_file_path);
189*795d594fSAndroid Build Coastguard Worker         EraseFiles(output_files);
190*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
191*795d594fSAndroid Build Coastguard Worker         return false;
192*795d594fSAndroid Build Coastguard Worker       }
193*795d594fSAndroid Build Coastguard Worker 
194*795d594fSAndroid Build Coastguard Worker       size_t file_bytes = file->GetLength();
195*795d594fSAndroid Build Coastguard Worker       if (!output_files.back()->Copy(file.get(), /*offset=*/0, file_bytes)) {
196*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to copy " << QuotePath(file->GetPath()) << " to "
197*795d594fSAndroid Build Coastguard Worker                     << QuotePath(output_file_path);
198*795d594fSAndroid Build Coastguard Worker         EraseFiles(output_files);
199*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
200*795d594fSAndroid Build Coastguard Worker         return false;
201*795d594fSAndroid Build Coastguard Worker       }
202*795d594fSAndroid Build Coastguard Worker 
203*795d594fSAndroid Build Coastguard Worker       if (!file->Erase(/*unlink=*/true)) {
204*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to erase " << QuotePath(file->GetPath());
205*795d594fSAndroid Build Coastguard Worker         EraseFiles(output_files);
206*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
207*795d594fSAndroid Build Coastguard Worker         return false;
208*795d594fSAndroid Build Coastguard Worker       }
209*795d594fSAndroid Build Coastguard Worker 
210*795d594fSAndroid Build Coastguard Worker       if (output_files.back()->FlushCloseOrErase() != 0) {
211*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to flush and close file " << QuotePath(output_file_path);
212*795d594fSAndroid Build Coastguard Worker         EraseFiles(output_files);
213*795d594fSAndroid Build Coastguard Worker         EraseFiles(files);
214*795d594fSAndroid Build Coastguard Worker         return false;
215*795d594fSAndroid Build Coastguard Worker       }
216*795d594fSAndroid Build Coastguard Worker     }
217*795d594fSAndroid Build Coastguard Worker   }
218*795d594fSAndroid Build Coastguard Worker   return true;
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker 
221*795d594fSAndroid Build Coastguard Worker // Gets the `ApexInfo` associated with the currently active ART APEX.
GetArtApexInfo(const std::vector<apex::ApexInfo> & info_list)222*795d594fSAndroid Build Coastguard Worker std::optional<apex::ApexInfo> GetArtApexInfo(const std::vector<apex::ApexInfo>& info_list) {
223*795d594fSAndroid Build Coastguard Worker   auto it = std::find_if(info_list.begin(), info_list.end(), [](const apex::ApexInfo& info) {
224*795d594fSAndroid Build Coastguard Worker     return info.getModuleName() == "com.android.art";
225*795d594fSAndroid Build Coastguard Worker   });
226*795d594fSAndroid Build Coastguard Worker   return it != info_list.end() ? std::make_optional(*it) : std::nullopt;
227*795d594fSAndroid Build Coastguard Worker }
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker // Returns cache provenance information based on the current APEX version and filesystem
230*795d594fSAndroid Build Coastguard Worker // information.
GenerateModuleInfo(const apex::ApexInfo & apex_info)231*795d594fSAndroid Build Coastguard Worker art_apex::ModuleInfo GenerateModuleInfo(const apex::ApexInfo& apex_info) {
232*795d594fSAndroid Build Coastguard Worker   // The lastUpdateMillis is an addition to ApexInfoList.xsd to support samegrade installs.
233*795d594fSAndroid Build Coastguard Worker   int64_t last_update_millis =
234*795d594fSAndroid Build Coastguard Worker       apex_info.hasLastUpdateMillis() ? apex_info.getLastUpdateMillis() : 0;
235*795d594fSAndroid Build Coastguard Worker   return art_apex::ModuleInfo{apex_info.getModuleName(),
236*795d594fSAndroid Build Coastguard Worker                               apex_info.getVersionCode(),
237*795d594fSAndroid Build Coastguard Worker                               apex_info.getVersionName(),
238*795d594fSAndroid Build Coastguard Worker                               last_update_millis};
239*795d594fSAndroid Build Coastguard Worker }
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker // Returns cache provenance information for all APEXes.
GenerateModuleInfoList(const std::vector<apex::ApexInfo> & apex_info_list)242*795d594fSAndroid Build Coastguard Worker std::vector<art_apex::ModuleInfo> GenerateModuleInfoList(
243*795d594fSAndroid Build Coastguard Worker     const std::vector<apex::ApexInfo>& apex_info_list) {
244*795d594fSAndroid Build Coastguard Worker   std::vector<art_apex::ModuleInfo> module_info_list;
245*795d594fSAndroid Build Coastguard Worker   std::transform(apex_info_list.begin(),
246*795d594fSAndroid Build Coastguard Worker                  apex_info_list.end(),
247*795d594fSAndroid Build Coastguard Worker                  std::back_inserter(module_info_list),
248*795d594fSAndroid Build Coastguard Worker                  GenerateModuleInfo);
249*795d594fSAndroid Build Coastguard Worker   return module_info_list;
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker 
252*795d594fSAndroid Build Coastguard Worker // Returns a rewritten path based on environment variables for interesting paths.
RewriteParentDirectoryIfNeeded(const std::string & path)253*795d594fSAndroid Build Coastguard Worker std::string RewriteParentDirectoryIfNeeded(const std::string& path) {
254*795d594fSAndroid Build Coastguard Worker   if (path.starts_with("/system/")) {
255*795d594fSAndroid Build Coastguard Worker     return GetAndroidRoot() + path.substr(7);
256*795d594fSAndroid Build Coastguard Worker   } else if (path.starts_with("/system_ext/")) {
257*795d594fSAndroid Build Coastguard Worker     return GetSystemExtRoot() + path.substr(11);
258*795d594fSAndroid Build Coastguard Worker   } else {
259*795d594fSAndroid Build Coastguard Worker     return path;
260*795d594fSAndroid Build Coastguard Worker   }
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker 
263*795d594fSAndroid Build Coastguard Worker template <typename T>
CheckComponents(const std::vector<T> & expected_components,const std::vector<T> & actual_components,const std::function<Result<void> (const T & expected,const T & actual)> & custom_checker=[](const T &,const T &)->Result<void>{})264*795d594fSAndroid Build Coastguard Worker Result<void> CheckComponents(
265*795d594fSAndroid Build Coastguard Worker     const std::vector<T>& expected_components,
266*795d594fSAndroid Build Coastguard Worker     const std::vector<T>& actual_components,
267*795d594fSAndroid Build Coastguard Worker     const std::function<Result<void>(const T& expected, const T& actual)>& custom_checker =
268*795d594fSAndroid Build Coastguard Worker         [](const T&, const T&) -> Result<void> { return {}; }) {
269*795d594fSAndroid Build Coastguard Worker   if (expected_components.size() != actual_components.size()) {
270*795d594fSAndroid Build Coastguard Worker     return Errorf(
271*795d594fSAndroid Build Coastguard Worker         "Component count differs ({} != {})", expected_components.size(), actual_components.size());
272*795d594fSAndroid Build Coastguard Worker   }
273*795d594fSAndroid Build Coastguard Worker 
274*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < expected_components.size(); ++i) {
275*795d594fSAndroid Build Coastguard Worker     const T& expected = expected_components[i];
276*795d594fSAndroid Build Coastguard Worker     const T& actual = actual_components[i];
277*795d594fSAndroid Build Coastguard Worker 
278*795d594fSAndroid Build Coastguard Worker     if (expected.getFile() != actual.getFile()) {
279*795d594fSAndroid Build Coastguard Worker       return Errorf(
280*795d594fSAndroid Build Coastguard Worker           "Component {} file differs ('{}' != '{}')", i, expected.getFile(), actual.getFile());
281*795d594fSAndroid Build Coastguard Worker     }
282*795d594fSAndroid Build Coastguard Worker 
283*795d594fSAndroid Build Coastguard Worker     if (expected.getSize() != actual.getSize()) {
284*795d594fSAndroid Build Coastguard Worker       return Errorf(
285*795d594fSAndroid Build Coastguard Worker           "Component {} size differs ({} != {})", i, expected.getSize(), actual.getSize());
286*795d594fSAndroid Build Coastguard Worker     }
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker     if (expected.getChecksums() != actual.getChecksums()) {
289*795d594fSAndroid Build Coastguard Worker       return Errorf("Component {} checksums differ ('{}' != '{}')",
290*795d594fSAndroid Build Coastguard Worker                     i,
291*795d594fSAndroid Build Coastguard Worker                     expected.getChecksums(),
292*795d594fSAndroid Build Coastguard Worker                     actual.getChecksums());
293*795d594fSAndroid Build Coastguard Worker     }
294*795d594fSAndroid Build Coastguard Worker 
295*795d594fSAndroid Build Coastguard Worker     Result<void> result = custom_checker(expected, actual);
296*795d594fSAndroid Build Coastguard Worker     if (!result.ok()) {
297*795d594fSAndroid Build Coastguard Worker       return Errorf("Component {} {}", i, result.error().message());
298*795d594fSAndroid Build Coastguard Worker     }
299*795d594fSAndroid Build Coastguard Worker   }
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker   return {};
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker 
CheckSystemServerComponents(const std::vector<art_apex::SystemServerComponent> & expected_components,const std::vector<art_apex::SystemServerComponent> & actual_components)304*795d594fSAndroid Build Coastguard Worker Result<void> CheckSystemServerComponents(
305*795d594fSAndroid Build Coastguard Worker     const std::vector<art_apex::SystemServerComponent>& expected_components,
306*795d594fSAndroid Build Coastguard Worker     const std::vector<art_apex::SystemServerComponent>& actual_components) {
307*795d594fSAndroid Build Coastguard Worker   return CheckComponents<art_apex::SystemServerComponent>(
308*795d594fSAndroid Build Coastguard Worker       expected_components,
309*795d594fSAndroid Build Coastguard Worker       actual_components,
310*795d594fSAndroid Build Coastguard Worker       [](const art_apex::SystemServerComponent& expected,
311*795d594fSAndroid Build Coastguard Worker          const art_apex::SystemServerComponent& actual) -> Result<void> {
312*795d594fSAndroid Build Coastguard Worker         if (expected.getIsInClasspath() != actual.getIsInClasspath()) {
313*795d594fSAndroid Build Coastguard Worker           return Errorf("isInClasspath differs ({} != {})",
314*795d594fSAndroid Build Coastguard Worker                         expected.getIsInClasspath(),
315*795d594fSAndroid Build Coastguard Worker                         actual.getIsInClasspath());
316*795d594fSAndroid Build Coastguard Worker         }
317*795d594fSAndroid Build Coastguard Worker 
318*795d594fSAndroid Build Coastguard Worker         return {};
319*795d594fSAndroid Build Coastguard Worker       });
320*795d594fSAndroid Build Coastguard Worker }
321*795d594fSAndroid Build Coastguard Worker 
322*795d594fSAndroid Build Coastguard Worker template <typename T>
GenerateComponents(const std::vector<std::string> & jars,const std::function<T (const std::string & path,uint64_t size,const std::string & checksum)> & custom_generator)323*795d594fSAndroid Build Coastguard Worker std::vector<T> GenerateComponents(
324*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& jars,
325*795d594fSAndroid Build Coastguard Worker     const std::function<T(const std::string& path, uint64_t size, const std::string& checksum)>&
326*795d594fSAndroid Build Coastguard Worker         custom_generator) {
327*795d594fSAndroid Build Coastguard Worker   std::vector<T> components;
328*795d594fSAndroid Build Coastguard Worker 
329*795d594fSAndroid Build Coastguard Worker   for (const std::string& path : jars) {
330*795d594fSAndroid Build Coastguard Worker     std::string actual_path = RewriteParentDirectoryIfNeeded(path);
331*795d594fSAndroid Build Coastguard Worker     struct stat sb;
332*795d594fSAndroid Build Coastguard Worker     if (stat(actual_path.c_str(), &sb) == -1) {
333*795d594fSAndroid Build Coastguard Worker       PLOG(ERROR) << "Failed to stat component: " << QuotePath(actual_path);
334*795d594fSAndroid Build Coastguard Worker       return {};
335*795d594fSAndroid Build Coastguard Worker     }
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker     std::optional<uint32_t> checksum;
338*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
339*795d594fSAndroid Build Coastguard Worker     ArtDexFileLoader dex_loader(actual_path);
340*795d594fSAndroid Build Coastguard Worker     if (!dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) {
341*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to get multi-dex checksum: " << error_msg;
342*795d594fSAndroid Build Coastguard Worker       return {};
343*795d594fSAndroid Build Coastguard Worker     }
344*795d594fSAndroid Build Coastguard Worker 
345*795d594fSAndroid Build Coastguard Worker     const std::string checksum_str =
346*795d594fSAndroid Build Coastguard Worker         checksum.has_value() ? StringPrintf("%08x", checksum.value()) : std::string();
347*795d594fSAndroid Build Coastguard Worker 
348*795d594fSAndroid Build Coastguard Worker     Result<T> component = custom_generator(path, static_cast<uint64_t>(sb.st_size), checksum_str);
349*795d594fSAndroid Build Coastguard Worker     if (!component.ok()) {
350*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to generate component: " << component.error();
351*795d594fSAndroid Build Coastguard Worker       return {};
352*795d594fSAndroid Build Coastguard Worker     }
353*795d594fSAndroid Build Coastguard Worker 
354*795d594fSAndroid Build Coastguard Worker     components.push_back(*std::move(component));
355*795d594fSAndroid Build Coastguard Worker   }
356*795d594fSAndroid Build Coastguard Worker 
357*795d594fSAndroid Build Coastguard Worker   return components;
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker 
GenerateComponents(const std::vector<std::string> & jars)360*795d594fSAndroid Build Coastguard Worker std::vector<art_apex::Component> GenerateComponents(const std::vector<std::string>& jars) {
361*795d594fSAndroid Build Coastguard Worker   return GenerateComponents<art_apex::Component>(
362*795d594fSAndroid Build Coastguard Worker       jars, [](const std::string& path, uint64_t size, const std::string& checksum) {
363*795d594fSAndroid Build Coastguard Worker         return art_apex::Component{path, size, checksum};
364*795d594fSAndroid Build Coastguard Worker       });
365*795d594fSAndroid Build Coastguard Worker }
366*795d594fSAndroid Build Coastguard Worker 
367*795d594fSAndroid Build Coastguard Worker // Checks whether a group of artifacts exists. Returns true if all are present, false otherwise.
368*795d594fSAndroid Build Coastguard Worker // If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`.
ArtifactsExist(const OdrArtifacts & artifacts,bool check_art_file,std::string * error_msg,std::vector<std::string> * checked_artifacts=nullptr)369*795d594fSAndroid Build Coastguard Worker bool ArtifactsExist(const OdrArtifacts& artifacts,
370*795d594fSAndroid Build Coastguard Worker                     bool check_art_file,
371*795d594fSAndroid Build Coastguard Worker                     /*out*/ std::string* error_msg,
372*795d594fSAndroid Build Coastguard Worker                     /*out*/ std::vector<std::string>* checked_artifacts = nullptr) {
373*795d594fSAndroid Build Coastguard Worker   std::vector<const char*> paths{artifacts.OatPath().c_str(), artifacts.VdexPath().c_str()};
374*795d594fSAndroid Build Coastguard Worker   if (check_art_file) {
375*795d594fSAndroid Build Coastguard Worker     paths.push_back(artifacts.ImagePath().c_str());
376*795d594fSAndroid Build Coastguard Worker   }
377*795d594fSAndroid Build Coastguard Worker   for (const char* path : paths) {
378*795d594fSAndroid Build Coastguard Worker     if (!OS::FileExists(path)) {
379*795d594fSAndroid Build Coastguard Worker       if (errno == EACCES) {
380*795d594fSAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to stat() " << path;
381*795d594fSAndroid Build Coastguard Worker       }
382*795d594fSAndroid Build Coastguard Worker       *error_msg = "Missing file: " + QuotePath(path);
383*795d594fSAndroid Build Coastguard Worker       return false;
384*795d594fSAndroid Build Coastguard Worker     }
385*795d594fSAndroid Build Coastguard Worker   }
386*795d594fSAndroid Build Coastguard Worker   // This should be done after checking all artifacts because either all of them are valid or none
387*795d594fSAndroid Build Coastguard Worker   // of them is valid.
388*795d594fSAndroid Build Coastguard Worker   if (checked_artifacts != nullptr) {
389*795d594fSAndroid Build Coastguard Worker     for (const char* path : paths) {
390*795d594fSAndroid Build Coastguard Worker       checked_artifacts->emplace_back(path);
391*795d594fSAndroid Build Coastguard Worker     }
392*795d594fSAndroid Build Coastguard Worker   }
393*795d594fSAndroid Build Coastguard Worker   return true;
394*795d594fSAndroid Build Coastguard Worker }
395*795d594fSAndroid Build Coastguard Worker 
AddDex2OatCommonOptions(CmdlineBuilder & args)396*795d594fSAndroid Build Coastguard Worker void AddDex2OatCommonOptions(/*inout*/ CmdlineBuilder& args) {
397*795d594fSAndroid Build Coastguard Worker   args.Add("--android-root=out/empty");
398*795d594fSAndroid Build Coastguard Worker   args.Add("--no-abort-on-hard-verifier-error");
399*795d594fSAndroid Build Coastguard Worker   args.Add("--no-abort-on-soft-verifier-error");
400*795d594fSAndroid Build Coastguard Worker   args.Add("--compilation-reason=boot");
401*795d594fSAndroid Build Coastguard Worker   args.Add("--image-format=lz4");
402*795d594fSAndroid Build Coastguard Worker   args.Add("--force-determinism");
403*795d594fSAndroid Build Coastguard Worker   args.Add("--resolve-startup-const-strings=true");
404*795d594fSAndroid Build Coastguard Worker 
405*795d594fSAndroid Build Coastguard Worker   // Avoid storing dex2oat cmdline in oat header. We want to be sure that the compiled artifacts
406*795d594fSAndroid Build Coastguard Worker   // are identical regardless of where the compilation happened. But some of the cmdline flags tends
407*795d594fSAndroid Build Coastguard Worker   // to be unstable, e.g. those contains FD numbers. To avoid the problem, the whole cmdline is not
408*795d594fSAndroid Build Coastguard Worker   // added to the oat header.
409*795d594fSAndroid Build Coastguard Worker   args.Add("--avoid-storing-invocation");
410*795d594fSAndroid Build Coastguard Worker }
411*795d594fSAndroid Build Coastguard Worker 
IsCpuSetSpecValid(const std::string & cpu_set)412*795d594fSAndroid Build Coastguard Worker bool IsCpuSetSpecValid(const std::string& cpu_set) {
413*795d594fSAndroid Build Coastguard Worker   for (const std::string& str : Split(cpu_set, ",")) {
414*795d594fSAndroid Build Coastguard Worker     int id;
415*795d594fSAndroid Build Coastguard Worker     if (!ParseInt(str, &id, 0)) {
416*795d594fSAndroid Build Coastguard Worker       return false;
417*795d594fSAndroid Build Coastguard Worker     }
418*795d594fSAndroid Build Coastguard Worker   }
419*795d594fSAndroid Build Coastguard Worker   return true;
420*795d594fSAndroid Build Coastguard Worker }
421*795d594fSAndroid Build Coastguard Worker 
AddDex2OatConcurrencyArguments(CmdlineBuilder & args,bool is_compilation_os,const OdrSystemProperties & system_properties)422*795d594fSAndroid Build Coastguard Worker Result<void> AddDex2OatConcurrencyArguments(/*inout*/ CmdlineBuilder& args,
423*795d594fSAndroid Build Coastguard Worker                                             bool is_compilation_os,
424*795d594fSAndroid Build Coastguard Worker                                             const OdrSystemProperties& system_properties) {
425*795d594fSAndroid Build Coastguard Worker   std::string threads;
426*795d594fSAndroid Build Coastguard Worker   if (is_compilation_os) {
427*795d594fSAndroid Build Coastguard Worker     threads = system_properties.GetOrEmpty("dalvik.vm.background-dex2oat-threads",
428*795d594fSAndroid Build Coastguard Worker                                            "dalvik.vm.dex2oat-threads");
429*795d594fSAndroid Build Coastguard Worker   } else {
430*795d594fSAndroid Build Coastguard Worker     threads = system_properties.GetOrEmpty("dalvik.vm.boot-dex2oat-threads");
431*795d594fSAndroid Build Coastguard Worker   }
432*795d594fSAndroid Build Coastguard Worker   args.AddIfNonEmpty("-j%s", threads);
433*795d594fSAndroid Build Coastguard Worker 
434*795d594fSAndroid Build Coastguard Worker   std::string cpu_set;
435*795d594fSAndroid Build Coastguard Worker   if (is_compilation_os) {
436*795d594fSAndroid Build Coastguard Worker     cpu_set = system_properties.GetOrEmpty("dalvik.vm.background-dex2oat-cpu-set",
437*795d594fSAndroid Build Coastguard Worker                                            "dalvik.vm.dex2oat-cpu-set");
438*795d594fSAndroid Build Coastguard Worker   } else {
439*795d594fSAndroid Build Coastguard Worker     cpu_set = system_properties.GetOrEmpty("dalvik.vm.boot-dex2oat-cpu-set");
440*795d594fSAndroid Build Coastguard Worker   }
441*795d594fSAndroid Build Coastguard Worker   if (!cpu_set.empty()) {
442*795d594fSAndroid Build Coastguard Worker     if (!IsCpuSetSpecValid(cpu_set)) {
443*795d594fSAndroid Build Coastguard Worker       return Errorf("Invalid CPU set spec '{}'", cpu_set);
444*795d594fSAndroid Build Coastguard Worker     }
445*795d594fSAndroid Build Coastguard Worker     args.Add("--cpu-set=%s", cpu_set);
446*795d594fSAndroid Build Coastguard Worker   }
447*795d594fSAndroid Build Coastguard Worker 
448*795d594fSAndroid Build Coastguard Worker   return {};
449*795d594fSAndroid Build Coastguard Worker }
450*795d594fSAndroid Build Coastguard Worker 
AddDex2OatDebugInfo(CmdlineBuilder & args)451*795d594fSAndroid Build Coastguard Worker void AddDex2OatDebugInfo(/*inout*/ CmdlineBuilder& args) {
452*795d594fSAndroid Build Coastguard Worker   args.Add("--generate-mini-debug-info");
453*795d594fSAndroid Build Coastguard Worker   args.Add("--strip");
454*795d594fSAndroid Build Coastguard Worker }
455*795d594fSAndroid Build Coastguard Worker 
AddDex2OatInstructionSet(CmdlineBuilder & args,InstructionSet isa,const OdrSystemProperties & system_properties)456*795d594fSAndroid Build Coastguard Worker void AddDex2OatInstructionSet(/*inout*/ CmdlineBuilder& args,
457*795d594fSAndroid Build Coastguard Worker                               InstructionSet isa,
458*795d594fSAndroid Build Coastguard Worker                               const OdrSystemProperties& system_properties) {
459*795d594fSAndroid Build Coastguard Worker   const char* isa_str = GetInstructionSetString(isa);
460*795d594fSAndroid Build Coastguard Worker   args.Add("--instruction-set=%s", isa_str);
461*795d594fSAndroid Build Coastguard Worker   std::string features_prop = ART_FORMAT("dalvik.vm.isa.{}.features", isa_str);
462*795d594fSAndroid Build Coastguard Worker   args.AddIfNonEmpty("--instruction-set-features=%s", system_properties.GetOrEmpty(features_prop));
463*795d594fSAndroid Build Coastguard Worker   std::string variant_prop = ART_FORMAT("dalvik.vm.isa.{}.variant", isa_str);
464*795d594fSAndroid Build Coastguard Worker   args.AddIfNonEmpty("--instruction-set-variant=%s", system_properties.GetOrEmpty(variant_prop));
465*795d594fSAndroid Build Coastguard Worker }
466*795d594fSAndroid Build Coastguard Worker 
467*795d594fSAndroid Build Coastguard Worker // Returns true if any profile has been added, or false if no profile exists, or error if any error
468*795d594fSAndroid Build Coastguard Worker // occurred.
AddDex2OatProfile(CmdlineBuilder & args,std::vector<std::unique_ptr<File>> & output_files,const std::vector<std::string> & profile_paths)469*795d594fSAndroid Build Coastguard Worker Result<bool> AddDex2OatProfile(
470*795d594fSAndroid Build Coastguard Worker     /*inout*/ CmdlineBuilder& args,
471*795d594fSAndroid Build Coastguard Worker     /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
472*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& profile_paths) {
473*795d594fSAndroid Build Coastguard Worker   bool has_any_profile = false;
474*795d594fSAndroid Build Coastguard Worker   for (const std::string& path : profile_paths) {
475*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> profile_file(OS::OpenFileForReading(path.c_str()));
476*795d594fSAndroid Build Coastguard Worker     if (profile_file != nullptr) {
477*795d594fSAndroid Build Coastguard Worker       args.Add("--profile-file-fd=%d", profile_file->Fd());
478*795d594fSAndroid Build Coastguard Worker       output_files.emplace_back(std::move(profile_file));
479*795d594fSAndroid Build Coastguard Worker       has_any_profile = true;
480*795d594fSAndroid Build Coastguard Worker     } else if (errno != ENOENT) {
481*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Failed to open profile file '{}'", path);
482*795d594fSAndroid Build Coastguard Worker     }
483*795d594fSAndroid Build Coastguard Worker   }
484*795d594fSAndroid Build Coastguard Worker   return has_any_profile;
485*795d594fSAndroid Build Coastguard Worker }
486*795d594fSAndroid Build Coastguard Worker 
AddBootClasspathFds(CmdlineBuilder & args,std::vector<std::unique_ptr<File>> & output_files,const std::vector<std::string> & bcp_jars)487*795d594fSAndroid Build Coastguard Worker Result<void> AddBootClasspathFds(/*inout*/ CmdlineBuilder& args,
488*795d594fSAndroid Build Coastguard Worker                                  /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
489*795d594fSAndroid Build Coastguard Worker                                  const std::vector<std::string>& bcp_jars) {
490*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> bcp_fds;
491*795d594fSAndroid Build Coastguard Worker   for (const std::string& jar : bcp_jars) {
492*795d594fSAndroid Build Coastguard Worker     // Special treatment for Compilation OS. JARs in staged APEX may not be visible to Android, and
493*795d594fSAndroid Build Coastguard Worker     // may only be visible in the VM where the staged APEX is mounted. On the contrary, JARs in
494*795d594fSAndroid Build Coastguard Worker     // /system is not available by path in the VM, and can only made available via (remote) FDs.
495*795d594fSAndroid Build Coastguard Worker     if (jar.starts_with("/apex/")) {
496*795d594fSAndroid Build Coastguard Worker       bcp_fds.emplace_back("-1");
497*795d594fSAndroid Build Coastguard Worker     } else {
498*795d594fSAndroid Build Coastguard Worker       std::string actual_path = RewriteParentDirectoryIfNeeded(jar);
499*795d594fSAndroid Build Coastguard Worker       std::unique_ptr<File> jar_file(OS::OpenFileForReading(actual_path.c_str()));
500*795d594fSAndroid Build Coastguard Worker       if (jar_file == nullptr) {
501*795d594fSAndroid Build Coastguard Worker         return ErrnoErrorf("Failed to open a BCP jar '{}'", actual_path);
502*795d594fSAndroid Build Coastguard Worker       }
503*795d594fSAndroid Build Coastguard Worker       bcp_fds.push_back(std::to_string(jar_file->Fd()));
504*795d594fSAndroid Build Coastguard Worker       output_files.push_back(std::move(jar_file));
505*795d594fSAndroid Build Coastguard Worker     }
506*795d594fSAndroid Build Coastguard Worker   }
507*795d594fSAndroid Build Coastguard Worker   args.AddRuntime("-Xbootclasspathfds:%s", Join(bcp_fds, ':'));
508*795d594fSAndroid Build Coastguard Worker   return {};
509*795d594fSAndroid Build Coastguard Worker }
510*795d594fSAndroid Build Coastguard Worker 
AddCacheInfoFd(CmdlineBuilder & args,std::vector<std::unique_ptr<File>> & readonly_files_raii,const std::string & cache_info_filename)511*795d594fSAndroid Build Coastguard Worker Result<void> AddCacheInfoFd(/*inout*/ CmdlineBuilder& args,
512*795d594fSAndroid Build Coastguard Worker                             /*inout*/ std::vector<std::unique_ptr<File>>& readonly_files_raii,
513*795d594fSAndroid Build Coastguard Worker                             const std::string& cache_info_filename) {
514*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<File> cache_info_file(OS::OpenFileForReading(cache_info_filename.c_str()));
515*795d594fSAndroid Build Coastguard Worker   if (cache_info_file == nullptr) {
516*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Failed to open a cache info file '{}'", cache_info_filename);
517*795d594fSAndroid Build Coastguard Worker   }
518*795d594fSAndroid Build Coastguard Worker 
519*795d594fSAndroid Build Coastguard Worker   args.Add("--cache-info-fd=%d", cache_info_file->Fd());
520*795d594fSAndroid Build Coastguard Worker   readonly_files_raii.push_back(std::move(cache_info_file));
521*795d594fSAndroid Build Coastguard Worker   return {};
522*795d594fSAndroid Build Coastguard Worker }
523*795d594fSAndroid Build Coastguard Worker 
GetBootImageComponentBasename(const std::string & jar_path,bool is_first_jar)524*795d594fSAndroid Build Coastguard Worker std::string GetBootImageComponentBasename(const std::string& jar_path, bool is_first_jar) {
525*795d594fSAndroid Build Coastguard Worker   if (is_first_jar) {
526*795d594fSAndroid Build Coastguard Worker     return kFirstBootImageBasename;
527*795d594fSAndroid Build Coastguard Worker   }
528*795d594fSAndroid Build Coastguard Worker   std::string jar_name = Basename(jar_path);
529*795d594fSAndroid Build Coastguard Worker   return "boot-" + ReplaceFileExtension(jar_name, kArtExtension);
530*795d594fSAndroid Build Coastguard Worker }
531*795d594fSAndroid Build Coastguard Worker 
AddCompiledBootClasspathFdsIfAny(CmdlineBuilder & args,std::vector<std::unique_ptr<File>> & output_files,const std::vector<std::string> & bcp_jars,InstructionSet isa,const std::vector<std::string> & boot_image_locations)532*795d594fSAndroid Build Coastguard Worker Result<void> AddCompiledBootClasspathFdsIfAny(
533*795d594fSAndroid Build Coastguard Worker     /*inout*/ CmdlineBuilder& args,
534*795d594fSAndroid Build Coastguard Worker     /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
535*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& bcp_jars,
536*795d594fSAndroid Build Coastguard Worker     InstructionSet isa,
537*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& boot_image_locations) {
538*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> bcp_image_fds;
539*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> bcp_oat_fds;
540*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> bcp_vdex_fds;
541*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<File>> opened_files;
542*795d594fSAndroid Build Coastguard Worker   bool added_any = false;
543*795d594fSAndroid Build Coastguard Worker   std::string artifact_dir;
544*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < bcp_jars.size(); i++) {
545*795d594fSAndroid Build Coastguard Worker     const std::string& jar = bcp_jars[i];
546*795d594fSAndroid Build Coastguard Worker     std::string basename = GetBootImageComponentBasename(jar, /*is_first_jar=*/i == 0);
547*795d594fSAndroid Build Coastguard Worker     // If there is an entry in `boot_image_locations` for the current jar, update `artifact_dir` for
548*795d594fSAndroid Build Coastguard Worker     // the current jar and the subsequent jars.
549*795d594fSAndroid Build Coastguard Worker     for (const std::string& location : boot_image_locations) {
550*795d594fSAndroid Build Coastguard Worker       if (Basename(location) == basename) {
551*795d594fSAndroid Build Coastguard Worker         artifact_dir = Dirname(location);
552*795d594fSAndroid Build Coastguard Worker         break;
553*795d594fSAndroid Build Coastguard Worker       }
554*795d594fSAndroid Build Coastguard Worker     }
555*795d594fSAndroid Build Coastguard Worker     CHECK(!artifact_dir.empty());
556*795d594fSAndroid Build Coastguard Worker     std::string image_path = ART_FORMAT("{}/{}", artifact_dir, basename);
557*795d594fSAndroid Build Coastguard Worker     image_path = GetSystemImageFilename(image_path.c_str(), isa);
558*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> image_file(OS::OpenFileForReading(image_path.c_str()));
559*795d594fSAndroid Build Coastguard Worker     if (image_file != nullptr) {
560*795d594fSAndroid Build Coastguard Worker       bcp_image_fds.push_back(std::to_string(image_file->Fd()));
561*795d594fSAndroid Build Coastguard Worker       opened_files.push_back(std::move(image_file));
562*795d594fSAndroid Build Coastguard Worker       added_any = true;
563*795d594fSAndroid Build Coastguard Worker     } else if (errno == ENOENT) {
564*795d594fSAndroid Build Coastguard Worker       bcp_image_fds.push_back("-1");
565*795d594fSAndroid Build Coastguard Worker     } else {
566*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Failed to open boot image file '{}'", image_path);
567*795d594fSAndroid Build Coastguard Worker     }
568*795d594fSAndroid Build Coastguard Worker 
569*795d594fSAndroid Build Coastguard Worker     std::string oat_path = ReplaceFileExtension(image_path, kOatExtension);
570*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> oat_file(OS::OpenFileForReading(oat_path.c_str()));
571*795d594fSAndroid Build Coastguard Worker     if (oat_file != nullptr) {
572*795d594fSAndroid Build Coastguard Worker       bcp_oat_fds.push_back(std::to_string(oat_file->Fd()));
573*795d594fSAndroid Build Coastguard Worker       opened_files.push_back(std::move(oat_file));
574*795d594fSAndroid Build Coastguard Worker       added_any = true;
575*795d594fSAndroid Build Coastguard Worker     } else if (errno == ENOENT) {
576*795d594fSAndroid Build Coastguard Worker       bcp_oat_fds.push_back("-1");
577*795d594fSAndroid Build Coastguard Worker     } else {
578*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Failed to open boot image file '{}'", oat_path);
579*795d594fSAndroid Build Coastguard Worker     }
580*795d594fSAndroid Build Coastguard Worker 
581*795d594fSAndroid Build Coastguard Worker     std::string vdex_path = ReplaceFileExtension(image_path, kVdexExtension);
582*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_path.c_str()));
583*795d594fSAndroid Build Coastguard Worker     if (vdex_file != nullptr) {
584*795d594fSAndroid Build Coastguard Worker       bcp_vdex_fds.push_back(std::to_string(vdex_file->Fd()));
585*795d594fSAndroid Build Coastguard Worker       opened_files.push_back(std::move(vdex_file));
586*795d594fSAndroid Build Coastguard Worker       added_any = true;
587*795d594fSAndroid Build Coastguard Worker     } else if (errno == ENOENT) {
588*795d594fSAndroid Build Coastguard Worker       bcp_vdex_fds.push_back("-1");
589*795d594fSAndroid Build Coastguard Worker     } else {
590*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Failed to open boot image file '{}'", vdex_path);
591*795d594fSAndroid Build Coastguard Worker     }
592*795d594fSAndroid Build Coastguard Worker   }
593*795d594fSAndroid Build Coastguard Worker   // Add same amount of FDs as BCP JARs, or none.
594*795d594fSAndroid Build Coastguard Worker   if (added_any) {
595*795d594fSAndroid Build Coastguard Worker     std::move(opened_files.begin(), opened_files.end(), std::back_inserter(output_files));
596*795d594fSAndroid Build Coastguard Worker 
597*795d594fSAndroid Build Coastguard Worker     args.AddRuntime("-Xbootclasspathimagefds:%s", Join(bcp_image_fds, ':'));
598*795d594fSAndroid Build Coastguard Worker     args.AddRuntime("-Xbootclasspathoatfds:%s", Join(bcp_oat_fds, ':'));
599*795d594fSAndroid Build Coastguard Worker     args.AddRuntime("-Xbootclasspathvdexfds:%s", Join(bcp_vdex_fds, ':'));
600*795d594fSAndroid Build Coastguard Worker   }
601*795d594fSAndroid Build Coastguard Worker 
602*795d594fSAndroid Build Coastguard Worker   return {};
603*795d594fSAndroid Build Coastguard Worker }
604*795d594fSAndroid Build Coastguard Worker 
GetStagingLocation(const std::string & staging_dir,const std::string & path)605*795d594fSAndroid Build Coastguard Worker std::string GetStagingLocation(const std::string& staging_dir, const std::string& path) {
606*795d594fSAndroid Build Coastguard Worker   return staging_dir + "/" + Basename(path);
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker 
CheckCompilationSpace()609*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool CheckCompilationSpace() {
610*795d594fSAndroid Build Coastguard Worker   // Check the available storage space against an arbitrary threshold because dex2oat does not
611*795d594fSAndroid Build Coastguard Worker   // report when it runs out of storage space and we do not want to completely fill
612*795d594fSAndroid Build Coastguard Worker   // the users data partition.
613*795d594fSAndroid Build Coastguard Worker   //
614*795d594fSAndroid Build Coastguard Worker   // We do not have a good way of pre-computing the required space for a compilation step, but
615*795d594fSAndroid Build Coastguard Worker   // typically observe no more than 48MiB as the largest total size of AOT artifacts for a single
616*795d594fSAndroid Build Coastguard Worker   // dex2oat invocation, which includes an image file, an executable file, and a verification data
617*795d594fSAndroid Build Coastguard Worker   // file.
618*795d594fSAndroid Build Coastguard Worker   static constexpr uint64_t kMinimumSpaceForCompilation = 48 * 1024 * 1024;
619*795d594fSAndroid Build Coastguard Worker 
620*795d594fSAndroid Build Coastguard Worker   uint64_t bytes_available;
621*795d594fSAndroid Build Coastguard Worker   const std::string& art_apex_data_path = GetArtApexData();
622*795d594fSAndroid Build Coastguard Worker   if (!GetFreeSpace(art_apex_data_path, &bytes_available)) {
623*795d594fSAndroid Build Coastguard Worker     return false;
624*795d594fSAndroid Build Coastguard Worker   }
625*795d594fSAndroid Build Coastguard Worker 
626*795d594fSAndroid Build Coastguard Worker   if (bytes_available < kMinimumSpaceForCompilation) {
627*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << "Low space for " << QuotePath(art_apex_data_path) << " (" << bytes_available
628*795d594fSAndroid Build Coastguard Worker                  << " bytes)";
629*795d594fSAndroid Build Coastguard Worker     return false;
630*795d594fSAndroid Build Coastguard Worker   }
631*795d594fSAndroid Build Coastguard Worker 
632*795d594fSAndroid Build Coastguard Worker   return true;
633*795d594fSAndroid Build Coastguard Worker }
634*795d594fSAndroid Build Coastguard Worker 
HasVettedDeviceSystemServerProfiles()635*795d594fSAndroid Build Coastguard Worker bool HasVettedDeviceSystemServerProfiles() {
636*795d594fSAndroid Build Coastguard Worker   // While system_server profiles were bundled on the device prior to U+, they were not used by
637*795d594fSAndroid Build Coastguard Worker   // default or rigorously tested, so we cannot vouch for their efficacy.
638*795d594fSAndroid Build Coastguard Worker   static const bool kDeviceIsAtLeastU = IsAtLeastU();
639*795d594fSAndroid Build Coastguard Worker   return kDeviceIsAtLeastU;
640*795d594fSAndroid Build Coastguard Worker }
641*795d594fSAndroid Build Coastguard Worker 
642*795d594fSAndroid Build Coastguard Worker }  // namespace
643*795d594fSAndroid Build Coastguard Worker 
CompileAll(const OnDeviceRefresh & odr)644*795d594fSAndroid Build Coastguard Worker CompilationOptions CompilationOptions::CompileAll(const OnDeviceRefresh& odr) {
645*795d594fSAndroid Build Coastguard Worker   CompilationOptions options;
646*795d594fSAndroid Build Coastguard Worker   for (InstructionSet isa : odr.Config().GetBootClasspathIsas()) {
647*795d594fSAndroid Build Coastguard Worker     options.boot_images_to_generate_for_isas.emplace_back(
648*795d594fSAndroid Build Coastguard Worker         isa, BootImages{.primary_boot_image = true, .boot_image_mainline_extension = true});
649*795d594fSAndroid Build Coastguard Worker   }
650*795d594fSAndroid Build Coastguard Worker   options.system_server_jars_to_compile = odr.AllSystemServerJars();
651*795d594fSAndroid Build Coastguard Worker   return options;
652*795d594fSAndroid Build Coastguard Worker }
653*795d594fSAndroid Build Coastguard Worker 
Count() const654*795d594fSAndroid Build Coastguard Worker int BootImages::Count() const {
655*795d594fSAndroid Build Coastguard Worker   int count = 0;
656*795d594fSAndroid Build Coastguard Worker   if (primary_boot_image) {
657*795d594fSAndroid Build Coastguard Worker     count++;
658*795d594fSAndroid Build Coastguard Worker   }
659*795d594fSAndroid Build Coastguard Worker   if (boot_image_mainline_extension) {
660*795d594fSAndroid Build Coastguard Worker     count++;
661*795d594fSAndroid Build Coastguard Worker   }
662*795d594fSAndroid Build Coastguard Worker   return count;
663*795d594fSAndroid Build Coastguard Worker }
664*795d594fSAndroid Build Coastguard Worker 
GetTypeForMetrics() const665*795d594fSAndroid Build Coastguard Worker OdrMetrics::BcpCompilationType BootImages::GetTypeForMetrics() const {
666*795d594fSAndroid Build Coastguard Worker   if (primary_boot_image && boot_image_mainline_extension) {
667*795d594fSAndroid Build Coastguard Worker     return OdrMetrics::BcpCompilationType::kPrimaryAndMainline;
668*795d594fSAndroid Build Coastguard Worker   }
669*795d594fSAndroid Build Coastguard Worker   if (boot_image_mainline_extension) {
670*795d594fSAndroid Build Coastguard Worker     return OdrMetrics::BcpCompilationType::kMainline;
671*795d594fSAndroid Build Coastguard Worker   }
672*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unexpected BCP compilation type";
673*795d594fSAndroid Build Coastguard Worker   UNREACHABLE();
674*795d594fSAndroid Build Coastguard Worker }
675*795d594fSAndroid Build Coastguard Worker 
CompilationUnitCount() const676*795d594fSAndroid Build Coastguard Worker int CompilationOptions::CompilationUnitCount() const {
677*795d594fSAndroid Build Coastguard Worker   int count = 0;
678*795d594fSAndroid Build Coastguard Worker   for (const auto& [isa, boot_images] : boot_images_to_generate_for_isas) {
679*795d594fSAndroid Build Coastguard Worker     count += boot_images.Count();
680*795d594fSAndroid Build Coastguard Worker   }
681*795d594fSAndroid Build Coastguard Worker   count += system_server_jars_to_compile.size();
682*795d594fSAndroid Build Coastguard Worker   return count;
683*795d594fSAndroid Build Coastguard Worker }
684*795d594fSAndroid Build Coastguard Worker 
OnDeviceRefresh(const OdrConfig & config,android::base::function_ref<int (const char *,const char *)> setfilecon,android::base::function_ref<int (const char *,unsigned int)> restorecon)685*795d594fSAndroid Build Coastguard Worker OnDeviceRefresh::OnDeviceRefresh(
686*795d594fSAndroid Build Coastguard Worker     const OdrConfig& config,
687*795d594fSAndroid Build Coastguard Worker     android::base::function_ref<int(const char*, const char*)> setfilecon,
688*795d594fSAndroid Build Coastguard Worker     android::base::function_ref<int(const char*, unsigned int)> restorecon)
689*795d594fSAndroid Build Coastguard Worker     : OnDeviceRefresh(config,
690*795d594fSAndroid Build Coastguard Worker                       setfilecon,
691*795d594fSAndroid Build Coastguard Worker                       restorecon,
692*795d594fSAndroid Build Coastguard Worker                       config.GetArtifactDirectory() + "/" + kCacheInfoFile,
693*795d594fSAndroid Build Coastguard Worker                       std::make_unique<ExecUtils>(),
694*795d594fSAndroid Build Coastguard Worker                       CheckCompilationSpace) {}
695*795d594fSAndroid Build Coastguard Worker 
OnDeviceRefresh(const OdrConfig & config,android::base::function_ref<int (const char *,const char *)> setfilecon,android::base::function_ref<int (const char *,unsigned int)> restorecon,const std::string & cache_info_filename,std::unique_ptr<ExecUtils> exec_utils,android::base::function_ref<bool ()> check_compilation_space)696*795d594fSAndroid Build Coastguard Worker OnDeviceRefresh::OnDeviceRefresh(
697*795d594fSAndroid Build Coastguard Worker     const OdrConfig& config,
698*795d594fSAndroid Build Coastguard Worker     android::base::function_ref<int(const char*, const char*)> setfilecon,
699*795d594fSAndroid Build Coastguard Worker     android::base::function_ref<int(const char*, unsigned int)> restorecon,
700*795d594fSAndroid Build Coastguard Worker     const std::string& cache_info_filename,
701*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<ExecUtils> exec_utils,
702*795d594fSAndroid Build Coastguard Worker     android::base::function_ref<bool()> check_compilation_space)
703*795d594fSAndroid Build Coastguard Worker     : config_(config),
704*795d594fSAndroid Build Coastguard Worker       cache_info_filename_(cache_info_filename),
705*795d594fSAndroid Build Coastguard Worker       start_time_(time(nullptr)),
706*795d594fSAndroid Build Coastguard Worker       exec_utils_(std::move(exec_utils)),
707*795d594fSAndroid Build Coastguard Worker       check_compilation_space_(check_compilation_space),
708*795d594fSAndroid Build Coastguard Worker       setfilecon_(setfilecon),
709*795d594fSAndroid Build Coastguard Worker       restorecon_(restorecon) {
710*795d594fSAndroid Build Coastguard Worker   // Updatable APEXes should not have DEX files in the DEX2OATBOOTCLASSPATH. At the time of
711*795d594fSAndroid Build Coastguard Worker   // writing i18n is a non-updatable APEX and so does appear in the DEX2OATBOOTCLASSPATH.
712*795d594fSAndroid Build Coastguard Worker   dex2oat_boot_classpath_jars_ = Split(config_.GetDex2oatBootClasspath(), ":");
713*795d594fSAndroid Build Coastguard Worker 
714*795d594fSAndroid Build Coastguard Worker   all_systemserver_jars_ = Split(config_.GetSystemServerClasspath(), ":");
715*795d594fSAndroid Build Coastguard Worker   systemserver_classpath_jars_ = {all_systemserver_jars_.begin(), all_systemserver_jars_.end()};
716*795d594fSAndroid Build Coastguard Worker   boot_classpath_jars_ = Split(config_.GetBootClasspath(), ":");
717*795d594fSAndroid Build Coastguard Worker   std::string standalone_system_server_jars_str = config_.GetStandaloneSystemServerJars();
718*795d594fSAndroid Build Coastguard Worker   if (!standalone_system_server_jars_str.empty()) {
719*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> standalone_systemserver_jars =
720*795d594fSAndroid Build Coastguard Worker         Split(standalone_system_server_jars_str, ":");
721*795d594fSAndroid Build Coastguard Worker     std::move(standalone_systemserver_jars.begin(),
722*795d594fSAndroid Build Coastguard Worker               standalone_systemserver_jars.end(),
723*795d594fSAndroid Build Coastguard Worker               std::back_inserter(all_systemserver_jars_));
724*795d594fSAndroid Build Coastguard Worker   }
725*795d594fSAndroid Build Coastguard Worker }
726*795d594fSAndroid Build Coastguard Worker 
GetExecutionTimeUsed() const727*795d594fSAndroid Build Coastguard Worker time_t OnDeviceRefresh::GetExecutionTimeUsed() const { return time(nullptr) - start_time_; }
728*795d594fSAndroid Build Coastguard Worker 
GetExecutionTimeRemaining() const729*795d594fSAndroid Build Coastguard Worker time_t OnDeviceRefresh::GetExecutionTimeRemaining() const {
730*795d594fSAndroid Build Coastguard Worker   return std::max(static_cast<time_t>(0),
731*795d594fSAndroid Build Coastguard Worker                   kMaximumExecutionSeconds - GetExecutionTimeUsed());
732*795d594fSAndroid Build Coastguard Worker }
733*795d594fSAndroid Build Coastguard Worker 
GetSubprocessTimeout() const734*795d594fSAndroid Build Coastguard Worker time_t OnDeviceRefresh::GetSubprocessTimeout() const {
735*795d594fSAndroid Build Coastguard Worker   return std::min(GetExecutionTimeRemaining(), kMaxChildProcessSeconds);
736*795d594fSAndroid Build Coastguard Worker }
737*795d594fSAndroid Build Coastguard Worker 
CreateStagingDirectory() const738*795d594fSAndroid Build Coastguard Worker Result<std::string> OnDeviceRefresh::CreateStagingDirectory() const {
739*795d594fSAndroid Build Coastguard Worker   std::string staging_dir = GetArtApexData() + "/staging";
740*795d594fSAndroid Build Coastguard Worker 
741*795d594fSAndroid Build Coastguard Worker   std::error_code ec;
742*795d594fSAndroid Build Coastguard Worker   if (std::filesystem::exists(staging_dir, ec)) {
743*795d594fSAndroid Build Coastguard Worker     if (std::filesystem::remove_all(staging_dir, ec) < 0) {
744*795d594fSAndroid Build Coastguard Worker       return Errorf(
745*795d594fSAndroid Build Coastguard Worker           "Could not remove existing staging directory '{}': {}", staging_dir, ec.message());
746*795d594fSAndroid Build Coastguard Worker     }
747*795d594fSAndroid Build Coastguard Worker   }
748*795d594fSAndroid Build Coastguard Worker 
749*795d594fSAndroid Build Coastguard Worker   if (mkdir(staging_dir.c_str(), S_IRWXU) != 0) {
750*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Could not create staging directory '{}'", staging_dir);
751*795d594fSAndroid Build Coastguard Worker   }
752*795d594fSAndroid Build Coastguard Worker 
753*795d594fSAndroid Build Coastguard Worker   if (setfilecon_(staging_dir.c_str(), "u:object_r:apex_art_staging_data_file:s0") != 0) {
754*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Could not set label on staging directory '{}'", staging_dir);
755*795d594fSAndroid Build Coastguard Worker   }
756*795d594fSAndroid Build Coastguard Worker 
757*795d594fSAndroid Build Coastguard Worker   return staging_dir;
758*795d594fSAndroid Build Coastguard Worker }
759*795d594fSAndroid Build Coastguard Worker 
GetApexInfoList() const760*795d594fSAndroid Build Coastguard Worker std::optional<std::vector<apex::ApexInfo>> OnDeviceRefresh::GetApexInfoList() const {
761*795d594fSAndroid Build Coastguard Worker   std::optional<apex::ApexInfoList> info_list =
762*795d594fSAndroid Build Coastguard Worker       apex::readApexInfoList(config_.GetApexInfoListFile().c_str());
763*795d594fSAndroid Build Coastguard Worker   if (!info_list.has_value()) {
764*795d594fSAndroid Build Coastguard Worker     return std::nullopt;
765*795d594fSAndroid Build Coastguard Worker   }
766*795d594fSAndroid Build Coastguard Worker 
767*795d594fSAndroid Build Coastguard Worker   // We are only interested in active APEXes that contain compilable JARs.
768*795d594fSAndroid Build Coastguard Worker   std::unordered_set<std::string_view> relevant_apexes;
769*795d594fSAndroid Build Coastguard Worker   relevant_apexes.reserve(info_list->getApexInfo().size());
770*795d594fSAndroid Build Coastguard Worker   for (const std::vector<std::string>* jar_list :
771*795d594fSAndroid Build Coastguard Worker        {&all_systemserver_jars_, &boot_classpath_jars_}) {
772*795d594fSAndroid Build Coastguard Worker     for (const std::string& jar : *jar_list) {
773*795d594fSAndroid Build Coastguard Worker       std::string_view apex = ApexNameFromLocation(jar);
774*795d594fSAndroid Build Coastguard Worker       if (!apex.empty()) {
775*795d594fSAndroid Build Coastguard Worker         relevant_apexes.insert(apex);
776*795d594fSAndroid Build Coastguard Worker       }
777*795d594fSAndroid Build Coastguard Worker     }
778*795d594fSAndroid Build Coastguard Worker   }
779*795d594fSAndroid Build Coastguard Worker   // The ART APEX is always relevant no matter it contains any compilable JAR or not, because it
780*795d594fSAndroid Build Coastguard Worker   // contains the runtime.
781*795d594fSAndroid Build Coastguard Worker   relevant_apexes.insert("com.android.art");
782*795d594fSAndroid Build Coastguard Worker 
783*795d594fSAndroid Build Coastguard Worker   std::vector<apex::ApexInfo> filtered_info_list;
784*795d594fSAndroid Build Coastguard Worker   std::copy_if(info_list->getApexInfo().begin(),
785*795d594fSAndroid Build Coastguard Worker                info_list->getApexInfo().end(),
786*795d594fSAndroid Build Coastguard Worker                std::back_inserter(filtered_info_list),
787*795d594fSAndroid Build Coastguard Worker                [&](const apex::ApexInfo& info) {
788*795d594fSAndroid Build Coastguard Worker                  return info.getIsActive() && relevant_apexes.count(info.getModuleName()) != 0;
789*795d594fSAndroid Build Coastguard Worker                });
790*795d594fSAndroid Build Coastguard Worker   return filtered_info_list;
791*795d594fSAndroid Build Coastguard Worker }
792*795d594fSAndroid Build Coastguard Worker 
ReadCacheInfo() const793*795d594fSAndroid Build Coastguard Worker Result<art_apex::CacheInfo> OnDeviceRefresh::ReadCacheInfo() const {
794*795d594fSAndroid Build Coastguard Worker   std::optional<art_apex::CacheInfo> cache_info = art_apex::read(cache_info_filename_.c_str());
795*795d594fSAndroid Build Coastguard Worker   if (!cache_info.has_value()) {
796*795d594fSAndroid Build Coastguard Worker     if (errno != 0) {
797*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Failed to load {}", QuotePath(cache_info_filename_));
798*795d594fSAndroid Build Coastguard Worker     } else {
799*795d594fSAndroid Build Coastguard Worker       return Errorf("Failed to parse {}", QuotePath(cache_info_filename_));
800*795d594fSAndroid Build Coastguard Worker     }
801*795d594fSAndroid Build Coastguard Worker   }
802*795d594fSAndroid Build Coastguard Worker   return cache_info.value();
803*795d594fSAndroid Build Coastguard Worker }
804*795d594fSAndroid Build Coastguard Worker 
805*795d594fSAndroid Build Coastguard Worker // This function has a large stack frame, so avoid inlining it because doing so
806*795d594fSAndroid Build Coastguard Worker // could push its caller's stack frame over the limit. See b/330851312.
WriteCacheInfo() const807*795d594fSAndroid Build Coastguard Worker NO_INLINE Result<void> OnDeviceRefresh::WriteCacheInfo() const {
808*795d594fSAndroid Build Coastguard Worker   if (OS::FileExists(cache_info_filename_.c_str())) {
809*795d594fSAndroid Build Coastguard Worker     if (unlink(cache_info_filename_.c_str()) != 0) {
810*795d594fSAndroid Build Coastguard Worker       return ErrnoErrorf("Failed to unlink file {}", QuotePath(cache_info_filename_));
811*795d594fSAndroid Build Coastguard Worker     }
812*795d594fSAndroid Build Coastguard Worker   }
813*795d594fSAndroid Build Coastguard Worker 
814*795d594fSAndroid Build Coastguard Worker   std::string dir_name = Dirname(cache_info_filename_);
815*795d594fSAndroid Build Coastguard Worker   if (!EnsureDirectoryExists(dir_name)) {
816*795d594fSAndroid Build Coastguard Worker     return Errorf("Could not create directory {}", QuotePath(dir_name));
817*795d594fSAndroid Build Coastguard Worker   }
818*795d594fSAndroid Build Coastguard Worker 
819*795d594fSAndroid Build Coastguard Worker   std::vector<art_apex::KeyValuePair> system_properties;
820*795d594fSAndroid Build Coastguard Worker   for (const auto& [key, value] : config_.GetSystemProperties()) {
821*795d594fSAndroid Build Coastguard Worker     if (!art::ContainsElement(kIgnoredSystemProperties, key)) {
822*795d594fSAndroid Build Coastguard Worker       system_properties.emplace_back(key, value);
823*795d594fSAndroid Build Coastguard Worker     }
824*795d594fSAndroid Build Coastguard Worker   }
825*795d594fSAndroid Build Coastguard Worker 
826*795d594fSAndroid Build Coastguard Worker   std::optional<std::vector<apex::ApexInfo>> apex_info_list = GetApexInfoList();
827*795d594fSAndroid Build Coastguard Worker   if (!apex_info_list.has_value()) {
828*795d594fSAndroid Build Coastguard Worker     return Errorf("Could not update {}: no APEX info", QuotePath(cache_info_filename_));
829*795d594fSAndroid Build Coastguard Worker   }
830*795d594fSAndroid Build Coastguard Worker 
831*795d594fSAndroid Build Coastguard Worker   std::optional<apex::ApexInfo> art_apex_info = GetArtApexInfo(apex_info_list.value());
832*795d594fSAndroid Build Coastguard Worker   if (!art_apex_info.has_value()) {
833*795d594fSAndroid Build Coastguard Worker     return Errorf("Could not update {}: no ART APEX info", QuotePath(cache_info_filename_));
834*795d594fSAndroid Build Coastguard Worker   }
835*795d594fSAndroid Build Coastguard Worker 
836*795d594fSAndroid Build Coastguard Worker   art_apex::ModuleInfo art_module_info = GenerateModuleInfo(art_apex_info.value());
837*795d594fSAndroid Build Coastguard Worker   std::vector<art_apex::ModuleInfo> module_info_list =
838*795d594fSAndroid Build Coastguard Worker       GenerateModuleInfoList(apex_info_list.value());
839*795d594fSAndroid Build Coastguard Worker 
840*795d594fSAndroid Build Coastguard Worker   std::vector<art_apex::Component> bcp_components = GenerateBootClasspathComponents();
841*795d594fSAndroid Build Coastguard Worker   std::vector<art_apex::Component> dex2oat_bcp_components =
842*795d594fSAndroid Build Coastguard Worker       GenerateDex2oatBootClasspathComponents();
843*795d594fSAndroid Build Coastguard Worker   std::vector<art_apex::SystemServerComponent> system_server_components =
844*795d594fSAndroid Build Coastguard Worker       GenerateSystemServerComponents();
845*795d594fSAndroid Build Coastguard Worker 
846*795d594fSAndroid Build Coastguard Worker   std::ofstream out(cache_info_filename_.c_str());
847*795d594fSAndroid Build Coastguard Worker   if (out.fail()) {
848*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Could not create cache info file {}", QuotePath(cache_info_filename_));
849*795d594fSAndroid Build Coastguard Worker   }
850*795d594fSAndroid Build Coastguard Worker 
851*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<art_apex::CacheInfo> info(new art_apex::CacheInfo(
852*795d594fSAndroid Build Coastguard Worker       {art_apex::KeyValuePairList(system_properties)},
853*795d594fSAndroid Build Coastguard Worker       {art_module_info},
854*795d594fSAndroid Build Coastguard Worker       {art_apex::ModuleInfoList(module_info_list)},
855*795d594fSAndroid Build Coastguard Worker       {art_apex::Classpath(bcp_components)},
856*795d594fSAndroid Build Coastguard Worker       {art_apex::Classpath(dex2oat_bcp_components)},
857*795d594fSAndroid Build Coastguard Worker       {art_apex::SystemServerComponents(system_server_components)},
858*795d594fSAndroid Build Coastguard Worker       config_.GetCompilationOsMode() ? std::make_optional(true) : std::nullopt));
859*795d594fSAndroid Build Coastguard Worker 
860*795d594fSAndroid Build Coastguard Worker   art_apex::write(out, *info);
861*795d594fSAndroid Build Coastguard Worker   out.close();
862*795d594fSAndroid Build Coastguard Worker   if (out.fail()) {
863*795d594fSAndroid Build Coastguard Worker     return ErrnoErrorf("Could not write cache info file {}", QuotePath(cache_info_filename_));
864*795d594fSAndroid Build Coastguard Worker   }
865*795d594fSAndroid Build Coastguard Worker 
866*795d594fSAndroid Build Coastguard Worker   return {};
867*795d594fSAndroid Build Coastguard Worker }
868*795d594fSAndroid Build Coastguard Worker 
ReportNextBootAnimationProgress(uint32_t current_compilation,uint32_t number_of_compilations)869*795d594fSAndroid Build Coastguard Worker static void ReportNextBootAnimationProgress(uint32_t current_compilation,
870*795d594fSAndroid Build Coastguard Worker                                             uint32_t number_of_compilations) {
871*795d594fSAndroid Build Coastguard Worker   // We arbitrarily show progress until 90%, expecting that our compilations take a large chunk of
872*795d594fSAndroid Build Coastguard Worker   // boot time.
873*795d594fSAndroid Build Coastguard Worker   uint32_t value = (90 * current_compilation) / number_of_compilations;
874*795d594fSAndroid Build Coastguard Worker   SetProperty("service.bootanim.progress", std::to_string(value));
875*795d594fSAndroid Build Coastguard Worker }
876*795d594fSAndroid Build Coastguard Worker 
GenerateBootClasspathComponents() const877*795d594fSAndroid Build Coastguard Worker std::vector<art_apex::Component> OnDeviceRefresh::GenerateBootClasspathComponents() const {
878*795d594fSAndroid Build Coastguard Worker   return GenerateComponents(boot_classpath_jars_);
879*795d594fSAndroid Build Coastguard Worker }
880*795d594fSAndroid Build Coastguard Worker 
GenerateDex2oatBootClasspathComponents() const881*795d594fSAndroid Build Coastguard Worker std::vector<art_apex::Component> OnDeviceRefresh::GenerateDex2oatBootClasspathComponents() const {
882*795d594fSAndroid Build Coastguard Worker   return GenerateComponents(dex2oat_boot_classpath_jars_);
883*795d594fSAndroid Build Coastguard Worker }
884*795d594fSAndroid Build Coastguard Worker 
GenerateSystemServerComponents() const885*795d594fSAndroid Build Coastguard Worker std::vector<art_apex::SystemServerComponent> OnDeviceRefresh::GenerateSystemServerComponents()
886*795d594fSAndroid Build Coastguard Worker     const {
887*795d594fSAndroid Build Coastguard Worker   return GenerateComponents<art_apex::SystemServerComponent>(
888*795d594fSAndroid Build Coastguard Worker       all_systemserver_jars_,
889*795d594fSAndroid Build Coastguard Worker       [&](const std::string& path, uint64_t size, const std::string& checksum) {
890*795d594fSAndroid Build Coastguard Worker         bool isInClasspath = ContainsElement(systemserver_classpath_jars_, path);
891*795d594fSAndroid Build Coastguard Worker         return art_apex::SystemServerComponent{path, size, checksum, isInClasspath};
892*795d594fSAndroid Build Coastguard Worker       });
893*795d594fSAndroid Build Coastguard Worker }
894*795d594fSAndroid Build Coastguard Worker 
GetArtBcpJars() const895*795d594fSAndroid Build Coastguard Worker std::vector<std::string> OnDeviceRefresh::GetArtBcpJars() const {
896*795d594fSAndroid Build Coastguard Worker   std::string art_root = GetArtRoot() + "/";
897*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> art_bcp_jars;
898*795d594fSAndroid Build Coastguard Worker   for (const std::string& jar : dex2oat_boot_classpath_jars_) {
899*795d594fSAndroid Build Coastguard Worker     if (jar.starts_with(art_root)) {
900*795d594fSAndroid Build Coastguard Worker       art_bcp_jars.push_back(jar);
901*795d594fSAndroid Build Coastguard Worker     }
902*795d594fSAndroid Build Coastguard Worker   }
903*795d594fSAndroid Build Coastguard Worker   CHECK(!art_bcp_jars.empty());
904*795d594fSAndroid Build Coastguard Worker   return art_bcp_jars;
905*795d594fSAndroid Build Coastguard Worker }
906*795d594fSAndroid Build Coastguard Worker 
GetFrameworkBcpJars() const907*795d594fSAndroid Build Coastguard Worker std::vector<std::string> OnDeviceRefresh::GetFrameworkBcpJars() const {
908*795d594fSAndroid Build Coastguard Worker   std::string art_root = GetArtRoot() + "/";
909*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> framework_bcp_jars;
910*795d594fSAndroid Build Coastguard Worker   for (const std::string& jar : dex2oat_boot_classpath_jars_) {
911*795d594fSAndroid Build Coastguard Worker     if (!jar.starts_with(art_root)) {
912*795d594fSAndroid Build Coastguard Worker       framework_bcp_jars.push_back(jar);
913*795d594fSAndroid Build Coastguard Worker     }
914*795d594fSAndroid Build Coastguard Worker   }
915*795d594fSAndroid Build Coastguard Worker   CHECK(!framework_bcp_jars.empty());
916*795d594fSAndroid Build Coastguard Worker   return framework_bcp_jars;
917*795d594fSAndroid Build Coastguard Worker }
918*795d594fSAndroid Build Coastguard Worker 
GetMainlineBcpJars() const919*795d594fSAndroid Build Coastguard Worker std::vector<std::string> OnDeviceRefresh::GetMainlineBcpJars() const {
920*795d594fSAndroid Build Coastguard Worker   // Elements in `dex2oat_boot_classpath_jars_` should be at the beginning of
921*795d594fSAndroid Build Coastguard Worker   // `boot_classpath_jars_`, followed by mainline BCP jars.
922*795d594fSAndroid Build Coastguard Worker   CHECK_LT(dex2oat_boot_classpath_jars_.size(), boot_classpath_jars_.size());
923*795d594fSAndroid Build Coastguard Worker   CHECK(std::equal(dex2oat_boot_classpath_jars_.begin(),
924*795d594fSAndroid Build Coastguard Worker                    dex2oat_boot_classpath_jars_.end(),
925*795d594fSAndroid Build Coastguard Worker                    boot_classpath_jars_.begin(),
926*795d594fSAndroid Build Coastguard Worker                    boot_classpath_jars_.begin() + dex2oat_boot_classpath_jars_.size()));
927*795d594fSAndroid Build Coastguard Worker   return {boot_classpath_jars_.begin() + dex2oat_boot_classpath_jars_.size(),
928*795d594fSAndroid Build Coastguard Worker           boot_classpath_jars_.end()};
929*795d594fSAndroid Build Coastguard Worker }
930*795d594fSAndroid Build Coastguard Worker 
GetPrimaryBootImage(bool on_system,bool minimal) const931*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetPrimaryBootImage(bool on_system, bool minimal) const {
932*795d594fSAndroid Build Coastguard Worker   DCHECK(!on_system || !minimal);
933*795d594fSAndroid Build Coastguard Worker   const char* basename = minimal ? kMinimalBootImageBasename : kFirstBootImageBasename;
934*795d594fSAndroid Build Coastguard Worker   if (on_system) {
935*795d594fSAndroid Build Coastguard Worker     // Typically "/system/framework/boot.art".
936*795d594fSAndroid Build Coastguard Worker     return GetPrebuiltPrimaryBootImageDir() + "/" + basename;
937*795d594fSAndroid Build Coastguard Worker   } else {
938*795d594fSAndroid Build Coastguard Worker     // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot.art".
939*795d594fSAndroid Build Coastguard Worker     return config_.GetArtifactDirectory() + "/" + basename;
940*795d594fSAndroid Build Coastguard Worker   }
941*795d594fSAndroid Build Coastguard Worker }
942*795d594fSAndroid Build Coastguard Worker 
GetPrimaryBootImagePath(bool on_system,bool minimal,InstructionSet isa) const943*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetPrimaryBootImagePath(bool on_system,
944*795d594fSAndroid Build Coastguard Worker                                                      bool minimal,
945*795d594fSAndroid Build Coastguard Worker                                                      InstructionSet isa) const {
946*795d594fSAndroid Build Coastguard Worker   // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/<isa>/boot.art".
947*795d594fSAndroid Build Coastguard Worker   return GetSystemImageFilename(GetPrimaryBootImage(on_system, minimal).c_str(), isa);
948*795d594fSAndroid Build Coastguard Worker }
949*795d594fSAndroid Build Coastguard Worker 
GetSystemBootImageFrameworkExtension() const950*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetSystemBootImageFrameworkExtension() const {
951*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> framework_bcp_jars = GetFrameworkBcpJars();
952*795d594fSAndroid Build Coastguard Worker   std::string basename =
953*795d594fSAndroid Build Coastguard Worker       GetBootImageComponentBasename(framework_bcp_jars[0], /*is_first_jar=*/false);
954*795d594fSAndroid Build Coastguard Worker   // Typically "/system/framework/boot-framework.art".
955*795d594fSAndroid Build Coastguard Worker   return ART_FORMAT("{}/framework/{}", GetAndroidRoot(), basename);
956*795d594fSAndroid Build Coastguard Worker }
957*795d594fSAndroid Build Coastguard Worker 
GetSystemBootImageFrameworkExtensionPath(InstructionSet isa) const958*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetSystemBootImageFrameworkExtensionPath(InstructionSet isa) const {
959*795d594fSAndroid Build Coastguard Worker   // Typically "/system/framework/<isa>/boot-framework.art".
960*795d594fSAndroid Build Coastguard Worker   return GetSystemImageFilename(GetSystemBootImageFrameworkExtension().c_str(), isa);
961*795d594fSAndroid Build Coastguard Worker }
962*795d594fSAndroid Build Coastguard Worker 
GetBootImageMainlineExtension(bool on_system) const963*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetBootImageMainlineExtension(bool on_system) const {
964*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> mainline_bcp_jars = GetMainlineBcpJars();
965*795d594fSAndroid Build Coastguard Worker   std::string basename =
966*795d594fSAndroid Build Coastguard Worker       GetBootImageComponentBasename(mainline_bcp_jars[0], /*is_first_jar=*/false);
967*795d594fSAndroid Build Coastguard Worker   if (on_system) {
968*795d594fSAndroid Build Coastguard Worker     // Typically "/system/framework/boot-framework-adservices.art".
969*795d594fSAndroid Build Coastguard Worker     return ART_FORMAT("{}/framework/{}", GetAndroidRoot(), basename);
970*795d594fSAndroid Build Coastguard Worker   } else {
971*795d594fSAndroid Build Coastguard Worker     // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot-framework-adservices.art".
972*795d594fSAndroid Build Coastguard Worker     return ART_FORMAT("{}/{}", config_.GetArtifactDirectory(), basename);
973*795d594fSAndroid Build Coastguard Worker   }
974*795d594fSAndroid Build Coastguard Worker }
975*795d594fSAndroid Build Coastguard Worker 
GetBootImageMainlineExtensionPath(bool on_system,InstructionSet isa) const976*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetBootImageMainlineExtensionPath(bool on_system,
977*795d594fSAndroid Build Coastguard Worker                                                                InstructionSet isa) const {
978*795d594fSAndroid Build Coastguard Worker   // Typically
979*795d594fSAndroid Build Coastguard Worker   // "/data/misc/apexdata/com.android.art/dalvik-cache/<isa>/boot-framework-adservices.art".
980*795d594fSAndroid Build Coastguard Worker   return GetSystemImageFilename(GetBootImageMainlineExtension(on_system).c_str(), isa);
981*795d594fSAndroid Build Coastguard Worker }
982*795d594fSAndroid Build Coastguard Worker 
GetBestBootImages(InstructionSet isa,bool include_mainline_extension) const983*795d594fSAndroid Build Coastguard Worker std::vector<std::string> OnDeviceRefresh::GetBestBootImages(InstructionSet isa,
984*795d594fSAndroid Build Coastguard Worker                                                             bool include_mainline_extension) const {
985*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> locations;
986*795d594fSAndroid Build Coastguard Worker   std::string unused_error_msg;
987*795d594fSAndroid Build Coastguard Worker   bool primary_on_data = false;
988*795d594fSAndroid Build Coastguard Worker   if (PrimaryBootImageExist(
989*795d594fSAndroid Build Coastguard Worker           /*on_system=*/false, /*minimal=*/false, isa, &unused_error_msg)) {
990*795d594fSAndroid Build Coastguard Worker     primary_on_data = true;
991*795d594fSAndroid Build Coastguard Worker     locations.push_back(GetPrimaryBootImage(/*on_system=*/false, /*minimal=*/false));
992*795d594fSAndroid Build Coastguard Worker   } else {
993*795d594fSAndroid Build Coastguard Worker     locations.push_back(GetPrimaryBootImage(/*on_system=*/true, /*minimal=*/false));
994*795d594fSAndroid Build Coastguard Worker     if (!IsAtLeastU()) {
995*795d594fSAndroid Build Coastguard Worker       // Prior to U, there was a framework extension.
996*795d594fSAndroid Build Coastguard Worker       locations.push_back(GetSystemBootImageFrameworkExtension());
997*795d594fSAndroid Build Coastguard Worker     }
998*795d594fSAndroid Build Coastguard Worker   }
999*795d594fSAndroid Build Coastguard Worker   if (include_mainline_extension) {
1000*795d594fSAndroid Build Coastguard Worker     if (BootImageMainlineExtensionExist(/*on_system=*/false, isa, &unused_error_msg)) {
1001*795d594fSAndroid Build Coastguard Worker       locations.push_back(GetBootImageMainlineExtension(/*on_system=*/false));
1002*795d594fSAndroid Build Coastguard Worker     } else {
1003*795d594fSAndroid Build Coastguard Worker       // If the primary boot image is on /data, it means we have regenerated all boot images, so the
1004*795d594fSAndroid Build Coastguard Worker       // mainline extension must be on /data too.
1005*795d594fSAndroid Build Coastguard Worker       CHECK(!primary_on_data)
1006*795d594fSAndroid Build Coastguard Worker           << "Mainline extension not found while primary boot image is on /data";
1007*795d594fSAndroid Build Coastguard Worker       locations.push_back(GetBootImageMainlineExtension(/*on_system=*/true));
1008*795d594fSAndroid Build Coastguard Worker     }
1009*795d594fSAndroid Build Coastguard Worker   }
1010*795d594fSAndroid Build Coastguard Worker   return locations;
1011*795d594fSAndroid Build Coastguard Worker }
1012*795d594fSAndroid Build Coastguard Worker 
GetSystemServerImagePath(bool on_system,const std::string & jar_path) const1013*795d594fSAndroid Build Coastguard Worker std::string OnDeviceRefresh::GetSystemServerImagePath(bool on_system,
1014*795d594fSAndroid Build Coastguard Worker                                                       const std::string& jar_path) const {
1015*795d594fSAndroid Build Coastguard Worker   if (on_system) {
1016*795d594fSAndroid Build Coastguard Worker     if (LocationIsOnApex(jar_path)) {
1017*795d594fSAndroid Build Coastguard Worker       return GetSystemOdexFilenameForApex(jar_path, config_.GetSystemServerIsa());
1018*795d594fSAndroid Build Coastguard Worker     }
1019*795d594fSAndroid Build Coastguard Worker     std::string jar_name = Basename(jar_path);
1020*795d594fSAndroid Build Coastguard Worker     std::string image_name = ReplaceFileExtension(jar_name, kArtExtension);
1021*795d594fSAndroid Build Coastguard Worker     const char* isa_str = GetInstructionSetString(config_.GetSystemServerIsa());
1022*795d594fSAndroid Build Coastguard Worker     // Typically "/system/framework/oat/<isa>/services.art".
1023*795d594fSAndroid Build Coastguard Worker     return ART_FORMAT("{}/oat/{}/{}", Dirname(jar_path), isa_str, image_name);
1024*795d594fSAndroid Build Coastguard Worker   } else {
1025*795d594fSAndroid Build Coastguard Worker     // Typically
1026*795d594fSAndroid Build Coastguard Worker     // "/data/misc/apexdata/.../dalvik-cache/<isa>/system@[email protected]@classes.art".
1027*795d594fSAndroid Build Coastguard Worker     const std::string image = GetApexDataImage(jar_path);
1028*795d594fSAndroid Build Coastguard Worker     return GetSystemImageFilename(image.c_str(), config_.GetSystemServerIsa());
1029*795d594fSAndroid Build Coastguard Worker   }
1030*795d594fSAndroid Build Coastguard Worker }
1031*795d594fSAndroid Build Coastguard Worker 
RemoveArtifactsDirectory() const1032*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool OnDeviceRefresh::RemoveArtifactsDirectory() const {
1033*795d594fSAndroid Build Coastguard Worker   if (config_.GetDryRun()) {
1034*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Directory " << QuotePath(config_.GetArtifactDirectory())
1035*795d594fSAndroid Build Coastguard Worker               << " and contents would be removed (dry-run).";
1036*795d594fSAndroid Build Coastguard Worker     return true;
1037*795d594fSAndroid Build Coastguard Worker   }
1038*795d594fSAndroid Build Coastguard Worker   return RemoveDirectory(config_.GetArtifactDirectory());
1039*795d594fSAndroid Build Coastguard Worker }
1040*795d594fSAndroid Build Coastguard Worker 
PrimaryBootImageExist(bool on_system,bool minimal,InstructionSet isa,std::string * error_msg,std::vector<std::string> * checked_artifacts) const1041*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool OnDeviceRefresh::PrimaryBootImageExist(
1042*795d594fSAndroid Build Coastguard Worker     bool on_system,
1043*795d594fSAndroid Build Coastguard Worker     bool minimal,
1044*795d594fSAndroid Build Coastguard Worker     InstructionSet isa,
1045*795d594fSAndroid Build Coastguard Worker     /*out*/ std::string* error_msg,
1046*795d594fSAndroid Build Coastguard Worker     /*out*/ std::vector<std::string>* checked_artifacts) const {
1047*795d594fSAndroid Build Coastguard Worker   std::string path = GetPrimaryBootImagePath(on_system, minimal, isa);
1048*795d594fSAndroid Build Coastguard Worker   OdrArtifacts artifacts = OdrArtifacts::ForBootImage(path);
1049*795d594fSAndroid Build Coastguard Worker   if (!ArtifactsExist(artifacts, /*check_art_file=*/true, error_msg, checked_artifacts)) {
1050*795d594fSAndroid Build Coastguard Worker     return false;
1051*795d594fSAndroid Build Coastguard Worker   }
1052*795d594fSAndroid Build Coastguard Worker   // Prior to U, there was a split between the primary boot image and the extension on /system, so
1053*795d594fSAndroid Build Coastguard Worker   // they need to be checked separately. This does not apply to the boot image on /data.
1054*795d594fSAndroid Build Coastguard Worker   if (on_system && !IsAtLeastU()) {
1055*795d594fSAndroid Build Coastguard Worker     std::string extension_path = GetSystemBootImageFrameworkExtensionPath(isa);
1056*795d594fSAndroid Build Coastguard Worker     OdrArtifacts extension_artifacts = OdrArtifacts::ForBootImage(extension_path);
1057*795d594fSAndroid Build Coastguard Worker     if (!ArtifactsExist(
1058*795d594fSAndroid Build Coastguard Worker             extension_artifacts, /*check_art_file=*/true, error_msg, checked_artifacts)) {
1059*795d594fSAndroid Build Coastguard Worker       return false;
1060*795d594fSAndroid Build Coastguard Worker     }
1061*795d594fSAndroid Build Coastguard Worker   }
1062*795d594fSAndroid Build Coastguard Worker   return true;
1063*795d594fSAndroid Build Coastguard Worker }
1064*795d594fSAndroid Build Coastguard Worker 
BootImageMainlineExtensionExist(bool on_system,InstructionSet isa,std::string * error_msg,std::vector<std::string> * checked_artifacts) const1065*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool OnDeviceRefresh::BootImageMainlineExtensionExist(
1066*795d594fSAndroid Build Coastguard Worker     bool on_system,
1067*795d594fSAndroid Build Coastguard Worker     InstructionSet isa,
1068*795d594fSAndroid Build Coastguard Worker     /*out*/ std::string* error_msg,
1069*795d594fSAndroid Build Coastguard Worker     /*out*/ std::vector<std::string>* checked_artifacts) const {
1070*795d594fSAndroid Build Coastguard Worker   std::string path = GetBootImageMainlineExtensionPath(on_system, isa);
1071*795d594fSAndroid Build Coastguard Worker   OdrArtifacts artifacts = OdrArtifacts::ForBootImage(path);
1072*795d594fSAndroid Build Coastguard Worker   return ArtifactsExist(artifacts, /*check_art_file=*/true, error_msg, checked_artifacts);
1073*795d594fSAndroid Build Coastguard Worker }
1074*795d594fSAndroid Build Coastguard Worker 
SystemServerArtifactsExist(bool on_system,std::string * error_msg,std::set<std::string> * jars_missing_artifacts,std::vector<std::string> * checked_artifacts) const1075*795d594fSAndroid Build Coastguard Worker bool OnDeviceRefresh::SystemServerArtifactsExist(
1076*795d594fSAndroid Build Coastguard Worker     bool on_system,
1077*795d594fSAndroid Build Coastguard Worker     /*out*/ std::string* error_msg,
1078*795d594fSAndroid Build Coastguard Worker     /*out*/ std::set<std::string>* jars_missing_artifacts,
1079*795d594fSAndroid Build Coastguard Worker     /*out*/ std::vector<std::string>* checked_artifacts) const {
1080*795d594fSAndroid Build Coastguard Worker   for (const std::string& jar_path : all_systemserver_jars_) {
1081*795d594fSAndroid Build Coastguard Worker     const std::string image_location = GetSystemServerImagePath(on_system, jar_path);
1082*795d594fSAndroid Build Coastguard Worker     const OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
1083*795d594fSAndroid Build Coastguard Worker     // .art files are optional and are not generated for all jars by the build system.
1084*795d594fSAndroid Build Coastguard Worker     const bool check_art_file = !on_system;
1085*795d594fSAndroid Build Coastguard Worker     std::string error_msg_tmp;
1086*795d594fSAndroid Build Coastguard Worker     if (!ArtifactsExist(artifacts, check_art_file, &error_msg_tmp, checked_artifacts)) {
1087*795d594fSAndroid Build Coastguard Worker       jars_missing_artifacts->insert(jar_path);
1088*795d594fSAndroid Build Coastguard Worker       *error_msg = error_msg->empty() ? error_msg_tmp : *error_msg + "\n" + error_msg_tmp;
1089*795d594fSAndroid Build Coastguard Worker     }
1090*795d594fSAndroid Build Coastguard Worker   }
1091*795d594fSAndroid Build Coastguard Worker   return jars_missing_artifacts->empty();
1092*795d594fSAndroid Build Coastguard Worker }
1093*795d594fSAndroid Build Coastguard Worker 
CheckSystemPropertiesAreDefault() const1094*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool OnDeviceRefresh::CheckSystemPropertiesAreDefault() const {
1095*795d594fSAndroid Build Coastguard Worker   // We don't have to check properties that match `kCheckedSystemPropertyPrefixes` here because none
1096*795d594fSAndroid Build Coastguard Worker   // of them is persistent. This only applies when `cache-info.xml` does not exist. When
1097*795d594fSAndroid Build Coastguard Worker   // `cache-info.xml` exists, we call `CheckSystemPropertiesHaveNotChanged` instead.
1098*795d594fSAndroid Build Coastguard Worker   DCHECK(std::none_of(std::begin(kCheckedSystemPropertyPrefixes),
1099*795d594fSAndroid Build Coastguard Worker                       std::end(kCheckedSystemPropertyPrefixes),
1100*795d594fSAndroid Build Coastguard Worker                       [](std::string_view prefix) { return prefix.starts_with("persist."); }));
1101*795d594fSAndroid Build Coastguard Worker 
1102*795d594fSAndroid Build Coastguard Worker   const OdrSystemProperties& system_properties = config_.GetSystemProperties();
1103*795d594fSAndroid Build Coastguard Worker 
1104*795d594fSAndroid Build Coastguard Worker   for (const SystemPropertyConfig& system_property_config : *kSystemProperties.get()) {
1105*795d594fSAndroid Build Coastguard Worker     // Note that the `kSystemPropertySystemServerCompilerFilterOverride` property has an empty
1106*795d594fSAndroid Build Coastguard Worker     // default value, so we use the `GetOrNull` method and check against nullopt
1107*795d594fSAndroid Build Coastguard Worker     std::optional<std::string> property = system_properties.GetOrNull(system_property_config.name);
1108*795d594fSAndroid Build Coastguard Worker     DCHECK(property.has_value()) << "Property " << system_property_config.name
1109*795d594fSAndroid Build Coastguard Worker                                  << " does not exist in system properties map!";
1110*795d594fSAndroid Build Coastguard Worker 
1111*795d594fSAndroid Build Coastguard Worker     if (*property != system_property_config.default_value) {
1112*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "System property " << system_property_config.name << " has a non-default value ("
1113*795d594fSAndroid Build Coastguard Worker                 << *property << ").";
1114*795d594fSAndroid Build Coastguard Worker       return false;
1115*795d594fSAndroid Build Coastguard Worker     }
1116*795d594fSAndroid Build Coastguard Worker   }
1117*795d594fSAndroid Build Coastguard Worker 
1118*795d594fSAndroid Build Coastguard Worker   return true;
1119*795d594fSAndroid Build Coastguard Worker }
1120*795d594fSAndroid Build Coastguard Worker 
CheckSystemPropertiesHaveNotChanged(const art_apex::CacheInfo & cache_info) const1121*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool OnDeviceRefresh::CheckSystemPropertiesHaveNotChanged(
1122*795d594fSAndroid Build Coastguard Worker     const art_apex::CacheInfo& cache_info) const {
1123*795d594fSAndroid Build Coastguard Worker   std::unordered_map<std::string, std::string> cached_system_properties;
1124*795d594fSAndroid Build Coastguard Worker   std::unordered_set<std::string> checked_properties;
1125*795d594fSAndroid Build Coastguard Worker 
1126*795d594fSAndroid Build Coastguard Worker   const art_apex::KeyValuePairList* list = cache_info.getFirstSystemProperties();
1127*795d594fSAndroid Build Coastguard Worker   if (list == nullptr) {
1128*795d594fSAndroid Build Coastguard Worker     // This should never happen. We have already checked the ART module version, and the cache
1129*795d594fSAndroid Build Coastguard Worker     // info is generated by the latest version of the ART module if it exists.
1130*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Missing system properties from cache-info.";
1131*795d594fSAndroid Build Coastguard Worker     return false;
1132*795d594fSAndroid Build Coastguard Worker   }
1133*795d594fSAndroid Build Coastguard Worker 
1134*795d594fSAndroid Build Coastguard Worker   for (const art_apex::KeyValuePair& pair : list->getItem()) {
1135*795d594fSAndroid Build Coastguard Worker     cached_system_properties[pair.getK()] = pair.getV();
1136*795d594fSAndroid Build Coastguard Worker     checked_properties.insert(pair.getK());
1137*795d594fSAndroid Build Coastguard Worker   }
1138*795d594fSAndroid Build Coastguard Worker 
1139*795d594fSAndroid Build Coastguard Worker   const OdrSystemProperties& system_properties = config_.GetSystemProperties();
1140*795d594fSAndroid Build Coastguard Worker 
1141*795d594fSAndroid Build Coastguard Worker   for (const auto& [key, value] : system_properties) {
1142*795d594fSAndroid Build Coastguard Worker     if (!art::ContainsElement(kIgnoredSystemProperties, key)) {
1143*795d594fSAndroid Build Coastguard Worker       checked_properties.insert(key);
1144*795d594fSAndroid Build Coastguard Worker     }
1145*795d594fSAndroid Build Coastguard Worker   }
1146*795d594fSAndroid Build Coastguard Worker 
1147*795d594fSAndroid Build Coastguard Worker   for (const std::string& name : checked_properties) {
1148*795d594fSAndroid Build Coastguard Worker     std::string property = system_properties.GetOrEmpty(name);
1149*795d594fSAndroid Build Coastguard Worker     std::string cached_property = cached_system_properties[name];
1150*795d594fSAndroid Build Coastguard Worker 
1151*795d594fSAndroid Build Coastguard Worker     if (property != cached_property) {
1152*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "System property " << name << " value changed (before: \"" << cached_property
1153*795d594fSAndroid Build Coastguard Worker                 << "\", now: \"" << property << "\").";
1154*795d594fSAndroid Build Coastguard Worker       return false;
1155*795d594fSAndroid Build Coastguard Worker     }
1156*795d594fSAndroid Build Coastguard Worker   }
1157*795d594fSAndroid Build Coastguard Worker 
1158*795d594fSAndroid Build Coastguard Worker   return true;
1159*795d594fSAndroid Build Coastguard Worker }
1160*795d594fSAndroid Build Coastguard Worker 
CheckBuildUserfaultFdGc() const1161*795d594fSAndroid Build Coastguard Worker WARN_UNUSED bool OnDeviceRefresh::CheckBuildUserfaultFdGc() const {
1162*795d594fSAndroid Build Coastguard Worker   bool build_enable_uffd_gc =
1163*795d594fSAndroid Build Coastguard Worker       config_.GetSystemProperties().GetBool("ro.dalvik.vm.enable_uffd_gc", /*default_value=*/false);
1164*795d594fSAndroid Build Coastguard Worker   bool is_at_most_u = !IsAtLeastV();
1165*795d594fSAndroid Build Coastguard Worker   bool kernel_supports_uffd = KernelSupportsUffd();
1166*795d594fSAndroid Build Coastguard Worker   if (!art::odrefresh::CheckBuildUserfaultFdGc(
1167*795d594fSAndroid Build Coastguard Worker           build_enable_uffd_gc, is_at_most_u, kernel_supports_uffd)) {
1168*795d594fSAndroid Build Coastguard Worker     // Normally, this should not happen. If this happens, the system image was probably built with a
1169*795d594fSAndroid Build Coastguard Worker     // wrong PRODUCT_ENABLE_UFFD_GC flag.
1170*795d594fSAndroid Build Coastguard Worker     LOG(WARNING) << ART_FORMAT(
1171*795d594fSAndroid Build Coastguard Worker         "Userfaultfd GC check failed (build_enable_uffd_gc: {}, is_at_most_u: {}, "
1172*795d594fSAndroid Build Coastguard Worker         "kernel_supports_uffd: {}).",
1173*795d594fSAndroid Build Coastguard Worker         build_enable_uffd_gc,
1174*795d594fSAndroid Build Coastguard Worker         is_at_most_u,
1175*795d594fSAndroid Build Coastguard Worker         kernel_supports_uffd);
1176*795d594fSAndroid Build Coastguard Worker     return false;
1177*795d594fSAndroid Build Coastguard Worker   }
1178*795d594fSAndroid Build Coastguard Worker   return true;
1179*795d594fSAndroid Build Coastguard Worker }
1180*795d594fSAndroid Build Coastguard Worker 
CheckPreconditionForSystem(const std::vector<apex::ApexInfo> & apex_info_list) const1181*795d594fSAndroid Build Coastguard Worker WARN_UNUSED PreconditionCheckResult OnDeviceRefresh::CheckPreconditionForSystem(
1182*795d594fSAndroid Build Coastguard Worker     const std::vector<apex::ApexInfo>& apex_info_list) const {
1183*795d594fSAndroid Build Coastguard Worker   if (!CheckSystemPropertiesAreDefault()) {
1184*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1185*795d594fSAndroid Build Coastguard Worker   }
1186*795d594fSAndroid Build Coastguard Worker 
1187*795d594fSAndroid Build Coastguard Worker   if (!CheckBuildUserfaultFdGc()) {
1188*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1189*795d594fSAndroid Build Coastguard Worker   }
1190*795d594fSAndroid Build Coastguard Worker 
1191*795d594fSAndroid Build Coastguard Worker   std::optional<apex::ApexInfo> art_apex_info = GetArtApexInfo(apex_info_list);
1192*795d594fSAndroid Build Coastguard Worker   if (!art_apex_info.has_value()) {
1193*795d594fSAndroid Build Coastguard Worker     // This should never happen, further up-to-date checks are not possible if it does.
1194*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Could not get ART APEX info.";
1195*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kUnknown);
1196*795d594fSAndroid Build Coastguard Worker   }
1197*795d594fSAndroid Build Coastguard Worker 
1198*795d594fSAndroid Build Coastguard Worker   if (!art_apex_info->getIsFactory()) {
1199*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Updated ART APEX mounted";
1200*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1201*795d594fSAndroid Build Coastguard Worker   }
1202*795d594fSAndroid Build Coastguard Worker 
1203*795d594fSAndroid Build Coastguard Worker   if (std::any_of(apex_info_list.begin(),
1204*795d594fSAndroid Build Coastguard Worker                   apex_info_list.end(),
1205*795d594fSAndroid Build Coastguard Worker                   [](const apex::ApexInfo& apex_info) { return !apex_info.getIsFactory(); })) {
1206*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Updated APEXes mounted";
1207*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::BootImageMainlineExtensionNotOk(
1208*795d594fSAndroid Build Coastguard Worker         OdrMetrics::Trigger::kApexVersionMismatch);
1209*795d594fSAndroid Build Coastguard Worker   }
1210*795d594fSAndroid Build Coastguard Worker 
1211*795d594fSAndroid Build Coastguard Worker   return PreconditionCheckResult::AllOk();
1212*795d594fSAndroid Build Coastguard Worker }
1213*795d594fSAndroid Build Coastguard Worker 
CheckModuleInfo(const art_apex::ModuleInfo & cached_info,const apex::ApexInfo & current_info)1214*795d594fSAndroid Build Coastguard Worker WARN_UNUSED static bool CheckModuleInfo(const art_apex::ModuleInfo& cached_info,
1215*795d594fSAndroid Build Coastguard Worker                                         const apex::ApexInfo& current_info) {
1216*795d594fSAndroid Build Coastguard Worker   if (cached_info.getVersionCode() != current_info.getVersionCode()) {
1217*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << ART_FORMAT("APEX ({}) version code mismatch (before: {}, now: {})",
1218*795d594fSAndroid Build Coastguard Worker                             current_info.getModuleName(),
1219*795d594fSAndroid Build Coastguard Worker                             cached_info.getVersionCode(),
1220*795d594fSAndroid Build Coastguard Worker                             current_info.getVersionCode());
1221*795d594fSAndroid Build Coastguard Worker     return false;
1222*795d594fSAndroid Build Coastguard Worker   }
1223*795d594fSAndroid Build Coastguard Worker 
1224*795d594fSAndroid Build Coastguard Worker   if (cached_info.getVersionName() != current_info.getVersionName()) {
1225*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << ART_FORMAT("APEX ({}) version name mismatch (before: {}, now: {})",
1226*795d594fSAndroid Build Coastguard Worker                             current_info.getModuleName(),
1227*795d594fSAndroid Build Coastguard Worker                             cached_info.getVersionName(),
1228*795d594fSAndroid Build Coastguard Worker                             current_info.getVersionName());
1229*795d594fSAndroid Build Coastguard Worker     return false;
1230*795d594fSAndroid Build Coastguard Worker   }
1231*795d594fSAndroid Build Coastguard Worker 
1232*795d594fSAndroid Build Coastguard Worker   // Check lastUpdateMillis for samegrade installs. If `cached_info` is missing the lastUpdateMillis
1233*795d594fSAndroid Build Coastguard Worker   // field then it is not current with the schema used by this binary so treat it as a samegrade
1234*795d594fSAndroid Build Coastguard Worker   // update. Otherwise check whether the lastUpdateMillis changed.
1235*795d594fSAndroid Build Coastguard Worker   const int64_t cached_last_update_millis =
1236*795d594fSAndroid Build Coastguard Worker       cached_info.hasLastUpdateMillis() ? cached_info.getLastUpdateMillis() : -1;
1237*795d594fSAndroid Build Coastguard Worker   if (cached_last_update_millis != current_info.getLastUpdateMillis()) {
1238*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << ART_FORMAT("APEX ({}) last update time mismatch (before: {}, now: {})",
1239*795d594fSAndroid Build Coastguard Worker                             current_info.getModuleName(),
1240*795d594fSAndroid Build Coastguard Worker                             cached_info.getLastUpdateMillis(),
1241*795d594fSAndroid Build Coastguard Worker                             current_info.getLastUpdateMillis());
1242*795d594fSAndroid Build Coastguard Worker     return false;
1243*795d594fSAndroid Build Coastguard Worker   }
1244*795d594fSAndroid Build Coastguard Worker 
1245*795d594fSAndroid Build Coastguard Worker   return true;
1246*795d594fSAndroid Build Coastguard Worker }
1247*795d594fSAndroid Build Coastguard Worker 
CheckPreconditionForData(const std::vector<com::android::apex::ApexInfo> & apex_info_list) const1248*795d594fSAndroid Build Coastguard Worker WARN_UNUSED PreconditionCheckResult OnDeviceRefresh::CheckPreconditionForData(
1249*795d594fSAndroid Build Coastguard Worker     const std::vector<com::android::apex::ApexInfo>& apex_info_list) const {
1250*795d594fSAndroid Build Coastguard Worker   Result<art_apex::CacheInfo> cache_info = ReadCacheInfo();
1251*795d594fSAndroid Build Coastguard Worker   if (!cache_info.ok()) {
1252*795d594fSAndroid Build Coastguard Worker     if (cache_info.error().code() == ENOENT) {
1253*795d594fSAndroid Build Coastguard Worker       // If the cache info file does not exist, it usually means it's the first boot, or the
1254*795d594fSAndroid Build Coastguard Worker       // dalvik-cache directory is cleared by odsign due to corrupted files. Set the trigger to be
1255*795d594fSAndroid Build Coastguard Worker       // `kApexVersionMismatch` to force generate the cache info file and compile if necessary.
1256*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "No prior cache-info file: " << QuotePath(cache_info_filename_);
1257*795d594fSAndroid Build Coastguard Worker     } else {
1258*795d594fSAndroid Build Coastguard Worker       // This should not happen unless odrefresh is updated to a new version that is not compatible
1259*795d594fSAndroid Build Coastguard Worker       // with an old cache-info file. Further up-to-date checks are not possible if it does.
1260*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << cache_info.error().message();
1261*795d594fSAndroid Build Coastguard Worker     }
1262*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1263*795d594fSAndroid Build Coastguard Worker   }
1264*795d594fSAndroid Build Coastguard Worker 
1265*795d594fSAndroid Build Coastguard Worker   if (!CheckSystemPropertiesHaveNotChanged(cache_info.value())) {
1266*795d594fSAndroid Build Coastguard Worker     // We don't have a trigger kind for system property changes. For now, we reuse
1267*795d594fSAndroid Build Coastguard Worker     // `kApexVersionMismatch` as it implies the expected behavior: re-compile regardless of the last
1268*795d594fSAndroid Build Coastguard Worker     // compilation attempt.
1269*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1270*795d594fSAndroid Build Coastguard Worker   }
1271*795d594fSAndroid Build Coastguard Worker 
1272*795d594fSAndroid Build Coastguard Worker   // Check whether the current cache ART module info differs from the current ART module info.
1273*795d594fSAndroid Build Coastguard Worker   const art_apex::ModuleInfo* cached_art_info = cache_info->getFirstArtModuleInfo();
1274*795d594fSAndroid Build Coastguard Worker   if (cached_art_info == nullptr) {
1275*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Missing ART APEX info from cache-info.";
1276*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1277*795d594fSAndroid Build Coastguard Worker   }
1278*795d594fSAndroid Build Coastguard Worker 
1279*795d594fSAndroid Build Coastguard Worker   std::optional<apex::ApexInfo> current_art_info = GetArtApexInfo(apex_info_list);
1280*795d594fSAndroid Build Coastguard Worker   if (!current_art_info.has_value()) {
1281*795d594fSAndroid Build Coastguard Worker     // This should never happen, further up-to-date checks are not possible if it does.
1282*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Could not get ART APEX info.";
1283*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kUnknown);
1284*795d594fSAndroid Build Coastguard Worker   }
1285*795d594fSAndroid Build Coastguard Worker 
1286*795d594fSAndroid Build Coastguard Worker   if (!CheckModuleInfo(*cached_art_info, *current_art_info)) {
1287*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1288*795d594fSAndroid Build Coastguard Worker   }
1289*795d594fSAndroid Build Coastguard Worker 
1290*795d594fSAndroid Build Coastguard Worker   // Check boot class components.
1291*795d594fSAndroid Build Coastguard Worker   //
1292*795d594fSAndroid Build Coastguard Worker   // This checks the size and checksums of odrefresh compilable files on the DEX2OATBOOTCLASSPATH
1293*795d594fSAndroid Build Coastguard Worker   // (the Odrefresh constructor determines which files are compilable). If the number of files
1294*795d594fSAndroid Build Coastguard Worker   // there changes, or their size or checksums change then compilation will be triggered.
1295*795d594fSAndroid Build Coastguard Worker   //
1296*795d594fSAndroid Build Coastguard Worker   // The boot class components may change unexpectedly, for example an OTA could update
1297*795d594fSAndroid Build Coastguard Worker   // framework.jar.
1298*795d594fSAndroid Build Coastguard Worker   const std::vector<art_apex::Component> current_dex2oat_bcp_components =
1299*795d594fSAndroid Build Coastguard Worker       GenerateDex2oatBootClasspathComponents();
1300*795d594fSAndroid Build Coastguard Worker 
1301*795d594fSAndroid Build Coastguard Worker   const art_apex::Classpath* cached_dex2oat_bcp_components =
1302*795d594fSAndroid Build Coastguard Worker       cache_info->getFirstDex2oatBootClasspath();
1303*795d594fSAndroid Build Coastguard Worker   if (cached_dex2oat_bcp_components == nullptr) {
1304*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Missing Dex2oatBootClasspath components.";
1305*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kApexVersionMismatch);
1306*795d594fSAndroid Build Coastguard Worker   }
1307*795d594fSAndroid Build Coastguard Worker 
1308*795d594fSAndroid Build Coastguard Worker   Result<void> result = CheckComponents(current_dex2oat_bcp_components,
1309*795d594fSAndroid Build Coastguard Worker                                         cached_dex2oat_bcp_components->getComponent());
1310*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1311*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Dex2OatClasspath components mismatch: " << result.error();
1312*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::NoneOk(OdrMetrics::Trigger::kDexFilesChanged);
1313*795d594fSAndroid Build Coastguard Worker   }
1314*795d594fSAndroid Build Coastguard Worker 
1315*795d594fSAndroid Build Coastguard Worker   // Check whether the current cached module info differs from the current module info.
1316*795d594fSAndroid Build Coastguard Worker   const art_apex::ModuleInfoList* cached_module_info_list = cache_info->getFirstModuleInfoList();
1317*795d594fSAndroid Build Coastguard Worker   if (cached_module_info_list == nullptr) {
1318*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Missing APEX info list from cache-info.";
1319*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::BootImageMainlineExtensionNotOk(
1320*795d594fSAndroid Build Coastguard Worker         OdrMetrics::Trigger::kApexVersionMismatch);
1321*795d594fSAndroid Build Coastguard Worker   }
1322*795d594fSAndroid Build Coastguard Worker 
1323*795d594fSAndroid Build Coastguard Worker   std::unordered_map<std::string, const art_apex::ModuleInfo*> cached_module_info_map;
1324*795d594fSAndroid Build Coastguard Worker   for (const art_apex::ModuleInfo& module_info : cached_module_info_list->getModuleInfo()) {
1325*795d594fSAndroid Build Coastguard Worker     cached_module_info_map[module_info.getName()] = &module_info;
1326*795d594fSAndroid Build Coastguard Worker   }
1327*795d594fSAndroid Build Coastguard Worker 
1328*795d594fSAndroid Build Coastguard Worker   // Note that apex_info_list may omit APEXes that are included in cached_module_info - e.g. if an
1329*795d594fSAndroid Build Coastguard Worker   // apex used to be compilable, but now isn't. That won't be detected by this loop, but will be
1330*795d594fSAndroid Build Coastguard Worker   // detected below in CheckComponents.
1331*795d594fSAndroid Build Coastguard Worker   for (const apex::ApexInfo& current_apex_info : apex_info_list) {
1332*795d594fSAndroid Build Coastguard Worker     auto& apex_name = current_apex_info.getModuleName();
1333*795d594fSAndroid Build Coastguard Worker 
1334*795d594fSAndroid Build Coastguard Worker     auto it = cached_module_info_map.find(apex_name);
1335*795d594fSAndroid Build Coastguard Worker     if (it == cached_module_info_map.end()) {
1336*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Missing APEX info from cache-info (" << apex_name << ").";
1337*795d594fSAndroid Build Coastguard Worker       return PreconditionCheckResult::BootImageMainlineExtensionNotOk(
1338*795d594fSAndroid Build Coastguard Worker           OdrMetrics::Trigger::kApexVersionMismatch);
1339*795d594fSAndroid Build Coastguard Worker     }
1340*795d594fSAndroid Build Coastguard Worker 
1341*795d594fSAndroid Build Coastguard Worker     const art_apex::ModuleInfo* cached_module_info = it->second;
1342*795d594fSAndroid Build Coastguard Worker     if (!CheckModuleInfo(*cached_module_info, current_apex_info)) {
1343*795d594fSAndroid Build Coastguard Worker       return PreconditionCheckResult::BootImageMainlineExtensionNotOk(
1344*795d594fSAndroid Build Coastguard Worker           OdrMetrics::Trigger::kApexVersionMismatch);
1345*795d594fSAndroid Build Coastguard Worker     }
1346*795d594fSAndroid Build Coastguard Worker   }
1347*795d594fSAndroid Build Coastguard Worker 
1348*795d594fSAndroid Build Coastguard Worker   const std::vector<art_apex::Component> current_bcp_components = GenerateBootClasspathComponents();
1349*795d594fSAndroid Build Coastguard Worker 
1350*795d594fSAndroid Build Coastguard Worker   const art_apex::Classpath* cached_bcp_components = cache_info->getFirstBootClasspath();
1351*795d594fSAndroid Build Coastguard Worker   if (cached_bcp_components == nullptr) {
1352*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Missing BootClasspath components.";
1353*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::BootImageMainlineExtensionNotOk(
1354*795d594fSAndroid Build Coastguard Worker         OdrMetrics::Trigger::kApexVersionMismatch);
1355*795d594fSAndroid Build Coastguard Worker   }
1356*795d594fSAndroid Build Coastguard Worker 
1357*795d594fSAndroid Build Coastguard Worker   result = CheckComponents(current_bcp_components, cached_bcp_components->getComponent());
1358*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1359*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "BootClasspath components mismatch: " << result.error();
1360*795d594fSAndroid Build Coastguard Worker     // Boot classpath components can be dependencies of system_server components, so system_server
1361*795d594fSAndroid Build Coastguard Worker     // components need to be recompiled if boot classpath components are changed.
1362*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::BootImageMainlineExtensionNotOk(
1363*795d594fSAndroid Build Coastguard Worker         OdrMetrics::Trigger::kDexFilesChanged);
1364*795d594fSAndroid Build Coastguard Worker   }
1365*795d594fSAndroid Build Coastguard Worker 
1366*795d594fSAndroid Build Coastguard Worker   // Check system server components.
1367*795d594fSAndroid Build Coastguard Worker   //
1368*795d594fSAndroid Build Coastguard Worker   // This checks the size and checksums of odrefresh compilable files on the
1369*795d594fSAndroid Build Coastguard Worker   // SYSTEMSERVERCLASSPATH (the Odrefresh constructor determines which files are compilable). If
1370*795d594fSAndroid Build Coastguard Worker   // the number of files there changes, or their size or checksums change then compilation will be
1371*795d594fSAndroid Build Coastguard Worker   // triggered.
1372*795d594fSAndroid Build Coastguard Worker   //
1373*795d594fSAndroid Build Coastguard Worker   // The system_server components may change unexpectedly, for example an OTA could update
1374*795d594fSAndroid Build Coastguard Worker   // services.jar.
1375*795d594fSAndroid Build Coastguard Worker   const std::vector<art_apex::SystemServerComponent> current_system_server_components =
1376*795d594fSAndroid Build Coastguard Worker       GenerateSystemServerComponents();
1377*795d594fSAndroid Build Coastguard Worker 
1378*795d594fSAndroid Build Coastguard Worker   const art_apex::SystemServerComponents* cached_system_server_components =
1379*795d594fSAndroid Build Coastguard Worker       cache_info->getFirstSystemServerComponents();
1380*795d594fSAndroid Build Coastguard Worker   if (cached_system_server_components == nullptr) {
1381*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Missing SystemServerComponents.";
1382*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::SystemServerNotOk(OdrMetrics::Trigger::kApexVersionMismatch);
1383*795d594fSAndroid Build Coastguard Worker   }
1384*795d594fSAndroid Build Coastguard Worker 
1385*795d594fSAndroid Build Coastguard Worker   result = CheckSystemServerComponents(current_system_server_components,
1386*795d594fSAndroid Build Coastguard Worker                                        cached_system_server_components->getComponent());
1387*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1388*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "SystemServerComponents mismatch: " << result.error();
1389*795d594fSAndroid Build Coastguard Worker     return PreconditionCheckResult::SystemServerNotOk(OdrMetrics::Trigger::kDexFilesChanged);
1390*795d594fSAndroid Build Coastguard Worker   }
1391*795d594fSAndroid Build Coastguard Worker 
1392*795d594fSAndroid Build Coastguard Worker   return PreconditionCheckResult::AllOk();
1393*795d594fSAndroid Build Coastguard Worker }
1394*795d594fSAndroid Build Coastguard Worker 
CheckBootClasspathArtifactsAreUpToDate(OdrMetrics & metrics,InstructionSet isa,const PreconditionCheckResult & system_result,const PreconditionCheckResult & data_result,std::vector<std::string> * checked_artifacts) const1395*795d594fSAndroid Build Coastguard Worker WARN_UNUSED BootImages OnDeviceRefresh::CheckBootClasspathArtifactsAreUpToDate(
1396*795d594fSAndroid Build Coastguard Worker     OdrMetrics& metrics,
1397*795d594fSAndroid Build Coastguard Worker     InstructionSet isa,
1398*795d594fSAndroid Build Coastguard Worker     const PreconditionCheckResult& system_result,
1399*795d594fSAndroid Build Coastguard Worker     const PreconditionCheckResult& data_result,
1400*795d594fSAndroid Build Coastguard Worker     /*out*/ std::vector<std::string>* checked_artifacts) const {
1401*795d594fSAndroid Build Coastguard Worker   const char* isa_str = GetInstructionSetString(isa);
1402*795d594fSAndroid Build Coastguard Worker 
1403*795d594fSAndroid Build Coastguard Worker   BootImages boot_images_on_system{.primary_boot_image = false,
1404*795d594fSAndroid Build Coastguard Worker                                    .boot_image_mainline_extension = false};
1405*795d594fSAndroid Build Coastguard Worker   if (system_result.IsPrimaryBootImageOk()) {
1406*795d594fSAndroid Build Coastguard Worker     // We can use the artifacts on /system. Check if they exist.
1407*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
1408*795d594fSAndroid Build Coastguard Worker     if (PrimaryBootImageExist(/*on_system=*/true, /*minimal=*/false, isa, &error_msg)) {
1409*795d594fSAndroid Build Coastguard Worker       boot_images_on_system.primary_boot_image = true;
1410*795d594fSAndroid Build Coastguard Worker     } else {
1411*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Incomplete primary boot image or framework extension on /system: " << error_msg;
1412*795d594fSAndroid Build Coastguard Worker     }
1413*795d594fSAndroid Build Coastguard Worker   }
1414*795d594fSAndroid Build Coastguard Worker 
1415*795d594fSAndroid Build Coastguard Worker   if (boot_images_on_system.primary_boot_image && system_result.IsBootImageMainlineExtensionOk()) {
1416*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
1417*795d594fSAndroid Build Coastguard Worker     if (BootImageMainlineExtensionExist(/*on_system=*/true, isa, &error_msg)) {
1418*795d594fSAndroid Build Coastguard Worker       boot_images_on_system.boot_image_mainline_extension = true;
1419*795d594fSAndroid Build Coastguard Worker     } else {
1420*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Incomplete boot image mainline extension on /system: " << error_msg;
1421*795d594fSAndroid Build Coastguard Worker     }
1422*795d594fSAndroid Build Coastguard Worker   }
1423*795d594fSAndroid Build Coastguard Worker 
1424*795d594fSAndroid Build Coastguard Worker   if (boot_images_on_system.Count() == BootImages::kMaxCount) {
1425*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << ART_FORMAT("Boot images on /system OK ({})", isa_str);
1426*795d594fSAndroid Build Coastguard Worker     // Nothing to compile.
1427*795d594fSAndroid Build Coastguard Worker     return BootImages{.primary_boot_image = false, .boot_image_mainline_extension = false};
1428*795d594fSAndroid Build Coastguard Worker   }
1429*795d594fSAndroid Build Coastguard Worker 
1430*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << ART_FORMAT("Checking boot images /data ({})", isa_str);
1431*795d594fSAndroid Build Coastguard Worker   BootImages boot_images_on_data{.primary_boot_image = false,
1432*795d594fSAndroid Build Coastguard Worker                                  .boot_image_mainline_extension = false};
1433*795d594fSAndroid Build Coastguard Worker 
1434*795d594fSAndroid Build Coastguard Worker   if (data_result.IsPrimaryBootImageOk()) {
1435*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
1436*795d594fSAndroid Build Coastguard Worker     if (PrimaryBootImageExist(
1437*795d594fSAndroid Build Coastguard Worker             /*on_system=*/false, /*minimal=*/false, isa, &error_msg, checked_artifacts)) {
1438*795d594fSAndroid Build Coastguard Worker       boot_images_on_data.primary_boot_image = true;
1439*795d594fSAndroid Build Coastguard Worker     } else {
1440*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Incomplete primary boot image on /data: " << error_msg;
1441*795d594fSAndroid Build Coastguard Worker       metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
1442*795d594fSAndroid Build Coastguard Worker       // Add the minimal boot image to `checked_artifacts` if exists. This is to prevent the minimal
1443*795d594fSAndroid Build Coastguard Worker       // boot image from being deleted. It does not affect the return value because we should still
1444*795d594fSAndroid Build Coastguard Worker       // attempt to generate a full boot image even if the minimal one exists.
1445*795d594fSAndroid Build Coastguard Worker       if (PrimaryBootImageExist(
1446*795d594fSAndroid Build Coastguard Worker               /*on_system=*/false, /*minimal=*/true, isa, &error_msg, checked_artifacts)) {
1447*795d594fSAndroid Build Coastguard Worker         LOG(INFO) << ART_FORMAT("Found minimal primary boot image ({})", isa_str);
1448*795d594fSAndroid Build Coastguard Worker       }
1449*795d594fSAndroid Build Coastguard Worker     }
1450*795d594fSAndroid Build Coastguard Worker   } else {
1451*795d594fSAndroid Build Coastguard Worker     metrics.SetTrigger(data_result.GetTrigger());
1452*795d594fSAndroid Build Coastguard Worker   }
1453*795d594fSAndroid Build Coastguard Worker 
1454*795d594fSAndroid Build Coastguard Worker   if (boot_images_on_system.primary_boot_image || boot_images_on_data.primary_boot_image) {
1455*795d594fSAndroid Build Coastguard Worker     if (data_result.IsBootImageMainlineExtensionOk()) {
1456*795d594fSAndroid Build Coastguard Worker       std::string error_msg;
1457*795d594fSAndroid Build Coastguard Worker       if (BootImageMainlineExtensionExist(
1458*795d594fSAndroid Build Coastguard Worker               /*on_system=*/false, isa, &error_msg, checked_artifacts)) {
1459*795d594fSAndroid Build Coastguard Worker         boot_images_on_data.boot_image_mainline_extension = true;
1460*795d594fSAndroid Build Coastguard Worker       } else {
1461*795d594fSAndroid Build Coastguard Worker         LOG(INFO) << "Incomplete boot image mainline extension on /data: " << error_msg;
1462*795d594fSAndroid Build Coastguard Worker         metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
1463*795d594fSAndroid Build Coastguard Worker       }
1464*795d594fSAndroid Build Coastguard Worker     } else {
1465*795d594fSAndroid Build Coastguard Worker       metrics.SetTrigger(data_result.GetTrigger());
1466*795d594fSAndroid Build Coastguard Worker     }
1467*795d594fSAndroid Build Coastguard Worker   }
1468*795d594fSAndroid Build Coastguard Worker 
1469*795d594fSAndroid Build Coastguard Worker   BootImages boot_images_to_generate{
1470*795d594fSAndroid Build Coastguard Worker       .primary_boot_image =
1471*795d594fSAndroid Build Coastguard Worker           !boot_images_on_system.primary_boot_image && !boot_images_on_data.primary_boot_image,
1472*795d594fSAndroid Build Coastguard Worker       .boot_image_mainline_extension = !boot_images_on_system.boot_image_mainline_extension &&
1473*795d594fSAndroid Build Coastguard Worker                                        !boot_images_on_data.boot_image_mainline_extension,
1474*795d594fSAndroid Build Coastguard Worker   };
1475*795d594fSAndroid Build Coastguard Worker 
1476*795d594fSAndroid Build Coastguard Worker   if (boot_images_to_generate.Count() == 0) {
1477*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << ART_FORMAT("Boot images on /data OK ({})", isa_str);
1478*795d594fSAndroid Build Coastguard Worker   }
1479*795d594fSAndroid Build Coastguard Worker 
1480*795d594fSAndroid Build Coastguard Worker   return boot_images_to_generate;
1481*795d594fSAndroid Build Coastguard Worker }
1482*795d594fSAndroid Build Coastguard Worker 
CheckSystemServerArtifactsAreUpToDate(OdrMetrics & metrics,const PreconditionCheckResult & system_result,const PreconditionCheckResult & data_result,std::vector<std::string> * checked_artifacts) const1483*795d594fSAndroid Build Coastguard Worker std::set<std::string> OnDeviceRefresh::CheckSystemServerArtifactsAreUpToDate(
1484*795d594fSAndroid Build Coastguard Worker     OdrMetrics& metrics,
1485*795d594fSAndroid Build Coastguard Worker     const PreconditionCheckResult& system_result,
1486*795d594fSAndroid Build Coastguard Worker     const PreconditionCheckResult& data_result,
1487*795d594fSAndroid Build Coastguard Worker     /*out*/ std::vector<std::string>* checked_artifacts) const {
1488*795d594fSAndroid Build Coastguard Worker   std::set<std::string> jars_to_compile;
1489*795d594fSAndroid Build Coastguard Worker   std::set<std::string> jars_missing_artifacts_on_system;
1490*795d594fSAndroid Build Coastguard Worker   if (system_result.IsSystemServerOk()) {
1491*795d594fSAndroid Build Coastguard Worker     // We can use the artifacts on /system. Check if they exist.
1492*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
1493*795d594fSAndroid Build Coastguard Worker     if (SystemServerArtifactsExist(
1494*795d594fSAndroid Build Coastguard Worker             /*on_system=*/true, &error_msg, &jars_missing_artifacts_on_system)) {
1495*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "system_server artifacts on /system OK";
1496*795d594fSAndroid Build Coastguard Worker       return {};
1497*795d594fSAndroid Build Coastguard Worker     }
1498*795d594fSAndroid Build Coastguard Worker 
1499*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Incomplete system server artifacts on /system: " << error_msg;
1500*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Checking system server artifacts /data";
1501*795d594fSAndroid Build Coastguard Worker   } else {
1502*795d594fSAndroid Build Coastguard Worker     jars_missing_artifacts_on_system = AllSystemServerJars();
1503*795d594fSAndroid Build Coastguard Worker   }
1504*795d594fSAndroid Build Coastguard Worker 
1505*795d594fSAndroid Build Coastguard Worker   std::set<std::string> jars_missing_artifacts_on_data;
1506*795d594fSAndroid Build Coastguard Worker   std::string error_msg;
1507*795d594fSAndroid Build Coastguard Worker   if (data_result.IsSystemServerOk()) {
1508*795d594fSAndroid Build Coastguard Worker     SystemServerArtifactsExist(
1509*795d594fSAndroid Build Coastguard Worker         /*on_system=*/false, &error_msg, &jars_missing_artifacts_on_data, checked_artifacts);
1510*795d594fSAndroid Build Coastguard Worker   } else {
1511*795d594fSAndroid Build Coastguard Worker     jars_missing_artifacts_on_data = AllSystemServerJars();
1512*795d594fSAndroid Build Coastguard Worker   }
1513*795d594fSAndroid Build Coastguard Worker 
1514*795d594fSAndroid Build Coastguard Worker   std::set_intersection(jars_missing_artifacts_on_system.begin(),
1515*795d594fSAndroid Build Coastguard Worker                         jars_missing_artifacts_on_system.end(),
1516*795d594fSAndroid Build Coastguard Worker                         jars_missing_artifacts_on_data.begin(),
1517*795d594fSAndroid Build Coastguard Worker                         jars_missing_artifacts_on_data.end(),
1518*795d594fSAndroid Build Coastguard Worker                         std::inserter(jars_to_compile, jars_to_compile.end()));
1519*795d594fSAndroid Build Coastguard Worker   if (!jars_to_compile.empty()) {
1520*795d594fSAndroid Build Coastguard Worker     if (data_result.IsSystemServerOk()) {
1521*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Incomplete system_server artifacts on /data: " << error_msg;
1522*795d594fSAndroid Build Coastguard Worker       metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
1523*795d594fSAndroid Build Coastguard Worker     } else {
1524*795d594fSAndroid Build Coastguard Worker       metrics.SetTrigger(data_result.GetTrigger());
1525*795d594fSAndroid Build Coastguard Worker     }
1526*795d594fSAndroid Build Coastguard Worker     return jars_to_compile;
1527*795d594fSAndroid Build Coastguard Worker   }
1528*795d594fSAndroid Build Coastguard Worker 
1529*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "system_server artifacts on /data OK";
1530*795d594fSAndroid Build Coastguard Worker   return {};
1531*795d594fSAndroid Build Coastguard Worker }
1532*795d594fSAndroid Build Coastguard Worker 
CleanupArtifactDirectory(OdrMetrics & metrics,const std::vector<std::string> & artifacts_to_keep) const1533*795d594fSAndroid Build Coastguard Worker Result<void> OnDeviceRefresh::CleanupArtifactDirectory(
1534*795d594fSAndroid Build Coastguard Worker     OdrMetrics& metrics, const std::vector<std::string>& artifacts_to_keep) const {
1535*795d594fSAndroid Build Coastguard Worker   const std::string& artifact_dir = config_.GetArtifactDirectory();
1536*795d594fSAndroid Build Coastguard Worker   std::unordered_set<std::string> artifact_set{artifacts_to_keep.begin(), artifacts_to_keep.end()};
1537*795d594fSAndroid Build Coastguard Worker 
1538*795d594fSAndroid Build Coastguard Worker   // When anything unexpected happens, remove all artifacts.
1539*795d594fSAndroid Build Coastguard Worker   auto remove_artifact_dir = android::base::make_scope_guard([&]() {
1540*795d594fSAndroid Build Coastguard Worker     if (!RemoveDirectory(artifact_dir)) {
1541*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to remove the artifact directory";
1542*795d594fSAndroid Build Coastguard Worker     }
1543*795d594fSAndroid Build Coastguard Worker   });
1544*795d594fSAndroid Build Coastguard Worker 
1545*795d594fSAndroid Build Coastguard Worker   std::vector<std::filesystem::directory_entry> entries;
1546*795d594fSAndroid Build Coastguard Worker   std::error_code ec;
1547*795d594fSAndroid Build Coastguard Worker   for (const auto& entry : std::filesystem::recursive_directory_iterator(artifact_dir, ec)) {
1548*795d594fSAndroid Build Coastguard Worker     // Save the entries and use them later because modifications during the iteration will result in
1549*795d594fSAndroid Build Coastguard Worker     // undefined behavior;
1550*795d594fSAndroid Build Coastguard Worker     entries.push_back(entry);
1551*795d594fSAndroid Build Coastguard Worker   }
1552*795d594fSAndroid Build Coastguard Worker   if (ec && ec.value() != ENOENT) {
1553*795d594fSAndroid Build Coastguard Worker     metrics.SetStatus(ec.value() == EPERM ? OdrMetrics::Status::kDalvikCachePermissionDenied :
1554*795d594fSAndroid Build Coastguard Worker                                             OdrMetrics::Status::kIoError);
1555*795d594fSAndroid Build Coastguard Worker     return Errorf("Failed to iterate over entries in the artifact directory: {}", ec.message());
1556*795d594fSAndroid Build Coastguard Worker   }
1557*795d594fSAndroid Build Coastguard Worker 
1558*795d594fSAndroid Build Coastguard Worker   for (const std::filesystem::directory_entry& entry : entries) {
1559*795d594fSAndroid Build Coastguard Worker     std::string path = entry.path().string();
1560*795d594fSAndroid Build Coastguard Worker     if (entry.is_regular_file()) {
1561*795d594fSAndroid Build Coastguard Worker       if (!ContainsElement(artifact_set, path)) {
1562*795d594fSAndroid Build Coastguard Worker         LOG(INFO) << "Removing " << path;
1563*795d594fSAndroid Build Coastguard Worker         if (unlink(path.c_str()) != 0) {
1564*795d594fSAndroid Build Coastguard Worker           metrics.SetStatus(OdrMetrics::Status::kIoError);
1565*795d594fSAndroid Build Coastguard Worker           return ErrnoErrorf("Failed to remove file {}", QuotePath(path));
1566*795d594fSAndroid Build Coastguard Worker         }
1567*795d594fSAndroid Build Coastguard Worker       }
1568*795d594fSAndroid Build Coastguard Worker     } else if (!entry.is_directory()) {
1569*795d594fSAndroid Build Coastguard Worker       // Neither a regular file nor a directory. Unexpected file type.
1570*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Removing " << path;
1571*795d594fSAndroid Build Coastguard Worker       if (unlink(path.c_str()) != 0) {
1572*795d594fSAndroid Build Coastguard Worker         metrics.SetStatus(OdrMetrics::Status::kIoError);
1573*795d594fSAndroid Build Coastguard Worker         return ErrnoErrorf("Failed to remove file {}", QuotePath(path));
1574*795d594fSAndroid Build Coastguard Worker       }
1575*795d594fSAndroid Build Coastguard Worker     }
1576*795d594fSAndroid Build Coastguard Worker   }
1577*795d594fSAndroid Build Coastguard Worker 
1578*795d594fSAndroid Build Coastguard Worker   remove_artifact_dir.Disable();
1579*795d594fSAndroid Build Coastguard Worker   return {};
1580*795d594fSAndroid Build Coastguard Worker }
1581*795d594fSAndroid Build Coastguard Worker 
RefreshExistingArtifacts() const1582*795d594fSAndroid Build Coastguard Worker Result<void> OnDeviceRefresh::RefreshExistingArtifacts() const {
1583*795d594fSAndroid Build Coastguard Worker   const std::string& artifact_dir = config_.GetArtifactDirectory();
1584*795d594fSAndroid Build Coastguard Worker   if (!OS::DirectoryExists(artifact_dir.c_str())) {
1585*795d594fSAndroid Build Coastguard Worker     return {};
1586*795d594fSAndroid Build Coastguard Worker   }
1587*795d594fSAndroid Build Coastguard Worker 
1588*795d594fSAndroid Build Coastguard Worker   std::vector<std::filesystem::directory_entry> entries;
1589*795d594fSAndroid Build Coastguard Worker   std::error_code ec;
1590*795d594fSAndroid Build Coastguard Worker   for (const auto& entry : std::filesystem::recursive_directory_iterator(artifact_dir, ec)) {
1591*795d594fSAndroid Build Coastguard Worker     // Save the entries and use them later because modifications during the iteration will result in
1592*795d594fSAndroid Build Coastguard Worker     // undefined behavior;
1593*795d594fSAndroid Build Coastguard Worker     entries.push_back(entry);
1594*795d594fSAndroid Build Coastguard Worker   }
1595*795d594fSAndroid Build Coastguard Worker   if (ec) {
1596*795d594fSAndroid Build Coastguard Worker     return Errorf("Failed to iterate over entries in the artifact directory: {}", ec.message());
1597*795d594fSAndroid Build Coastguard Worker   }
1598*795d594fSAndroid Build Coastguard Worker 
1599*795d594fSAndroid Build Coastguard Worker   for (const std::filesystem::directory_entry& entry : entries) {
1600*795d594fSAndroid Build Coastguard Worker     std::string path = entry.path().string();
1601*795d594fSAndroid Build Coastguard Worker     if (entry.is_regular_file()) {
1602*795d594fSAndroid Build Coastguard Worker       // Unexpected files are already removed by `CleanupArtifactDirectory`. We can safely assume
1603*795d594fSAndroid Build Coastguard Worker       // that all the remaining files are good.
1604*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Refreshing " << path;
1605*795d594fSAndroid Build Coastguard Worker       std::string content;
1606*795d594fSAndroid Build Coastguard Worker       if (!android::base::ReadFileToString(path, &content)) {
1607*795d594fSAndroid Build Coastguard Worker         return Errorf("Failed to read file {}", QuotePath(path));
1608*795d594fSAndroid Build Coastguard Worker       }
1609*795d594fSAndroid Build Coastguard Worker       if (unlink(path.c_str()) != 0) {
1610*795d594fSAndroid Build Coastguard Worker         return ErrnoErrorf("Failed to remove file {}", QuotePath(path));
1611*795d594fSAndroid Build Coastguard Worker       }
1612*795d594fSAndroid Build Coastguard Worker       if (!android::base::WriteStringToFile(content, path)) {
1613*795d594fSAndroid Build Coastguard Worker         return Errorf("Failed to write file {}", QuotePath(path));
1614*795d594fSAndroid Build Coastguard Worker       }
1615*795d594fSAndroid Build Coastguard Worker       if (chmod(path.c_str(), kFileMode) != 0) {
1616*795d594fSAndroid Build Coastguard Worker         return ErrnoErrorf("Failed to chmod file {}", QuotePath(path));
1617*795d594fSAndroid Build Coastguard Worker       }
1618*795d594fSAndroid Build Coastguard Worker     }
1619*795d594fSAndroid Build Coastguard Worker   }
1620*795d594fSAndroid Build Coastguard Worker 
1621*795d594fSAndroid Build Coastguard Worker   return {};
1622*795d594fSAndroid Build Coastguard Worker }
1623*795d594fSAndroid Build Coastguard Worker 
1624*795d594fSAndroid Build Coastguard Worker WARN_UNUSED ExitCode
CheckArtifactsAreUpToDate(OdrMetrics & metrics,CompilationOptions * compilation_options) const1625*795d594fSAndroid Build Coastguard Worker OnDeviceRefresh::CheckArtifactsAreUpToDate(OdrMetrics& metrics,
1626*795d594fSAndroid Build Coastguard Worker                                            /*out*/ CompilationOptions* compilation_options) const {
1627*795d594fSAndroid Build Coastguard Worker   metrics.SetStage(OdrMetrics::Stage::kCheck);
1628*795d594fSAndroid Build Coastguard Worker 
1629*795d594fSAndroid Build Coastguard Worker   // Clean-up helper used to simplify clean-ups and handling failures there.
1630*795d594fSAndroid Build Coastguard Worker   auto cleanup_and_compile_all = [&, this]() {
1631*795d594fSAndroid Build Coastguard Worker     *compilation_options = CompilationOptions::CompileAll(*this);
1632*795d594fSAndroid Build Coastguard Worker     if (!RemoveArtifactsDirectory()) {
1633*795d594fSAndroid Build Coastguard Worker       metrics.SetStatus(OdrMetrics::Status::kIoError);
1634*795d594fSAndroid Build Coastguard Worker       return ExitCode::kCleanupFailed;
1635*795d594fSAndroid Build Coastguard Worker     }
1636*795d594fSAndroid Build Coastguard Worker     return ExitCode::kCompilationRequired;
1637*795d594fSAndroid Build Coastguard Worker   };
1638*795d594fSAndroid Build Coastguard Worker 
1639*795d594fSAndroid Build Coastguard Worker   std::optional<std::vector<apex::ApexInfo>> apex_info_list = GetApexInfoList();
1640*795d594fSAndroid Build Coastguard Worker   if (!apex_info_list.has_value()) {
1641*795d594fSAndroid Build Coastguard Worker     // This should never happen, further up-to-date checks are not possible if it does.
1642*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Could not get APEX info.";
1643*795d594fSAndroid Build Coastguard Worker     metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
1644*795d594fSAndroid Build Coastguard Worker     return cleanup_and_compile_all();
1645*795d594fSAndroid Build Coastguard Worker   }
1646*795d594fSAndroid Build Coastguard Worker 
1647*795d594fSAndroid Build Coastguard Worker   std::optional<apex::ApexInfo> art_apex_info = GetArtApexInfo(apex_info_list.value());
1648*795d594fSAndroid Build Coastguard Worker   if (!art_apex_info.has_value()) {
1649*795d594fSAndroid Build Coastguard Worker     // This should never happen, further up-to-date checks are not possible if it does.
1650*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Could not get ART APEX info.";
1651*795d594fSAndroid Build Coastguard Worker     metrics.SetTrigger(OdrMetrics::Trigger::kUnknown);
1652*795d594fSAndroid Build Coastguard Worker     return cleanup_and_compile_all();
1653*795d594fSAndroid Build Coastguard Worker   }
1654*795d594fSAndroid Build Coastguard Worker 
1655*795d594fSAndroid Build Coastguard Worker   // Record ART APEX version for metrics reporting.
1656*795d594fSAndroid Build Coastguard Worker   metrics.SetArtApexVersion(art_apex_info->getVersionCode());
1657*795d594fSAndroid Build Coastguard Worker 
1658*795d594fSAndroid Build Coastguard Worker   // Log the version so there's a starting point for any issues reported (b/197489543).
1659*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "ART APEX version " << art_apex_info->getVersionCode();
1660*795d594fSAndroid Build Coastguard Worker 
1661*795d594fSAndroid Build Coastguard Worker   // Record ART APEX last update milliseconds (used in compilation log).
1662*795d594fSAndroid Build Coastguard Worker   metrics.SetArtApexLastUpdateMillis(art_apex_info->getLastUpdateMillis());
1663*795d594fSAndroid Build Coastguard Worker 
1664*795d594fSAndroid Build Coastguard Worker   InstructionSet system_server_isa = config_.GetSystemServerIsa();
1665*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> checked_artifacts;
1666*795d594fSAndroid Build Coastguard Worker 
1667*795d594fSAndroid Build Coastguard Worker   PreconditionCheckResult system_result = CheckPreconditionForSystem(apex_info_list.value());
1668*795d594fSAndroid Build Coastguard Worker   PreconditionCheckResult data_result = CheckPreconditionForData(apex_info_list.value());
1669*795d594fSAndroid Build Coastguard Worker 
1670*795d594fSAndroid Build Coastguard Worker   for (InstructionSet isa : config_.GetBootClasspathIsas()) {
1671*795d594fSAndroid Build Coastguard Worker     BootImages boot_images_to_generate = CheckBootClasspathArtifactsAreUpToDate(
1672*795d594fSAndroid Build Coastguard Worker         metrics, isa, system_result, data_result, &checked_artifacts);
1673*795d594fSAndroid Build Coastguard Worker     if (boot_images_to_generate.Count() > 0) {
1674*795d594fSAndroid Build Coastguard Worker       compilation_options->boot_images_to_generate_for_isas.emplace_back(isa,
1675*795d594fSAndroid Build Coastguard Worker                                                                          boot_images_to_generate);
1676*795d594fSAndroid Build Coastguard Worker       // system_server artifacts are invalid without valid boot classpath artifacts.
1677*795d594fSAndroid Build Coastguard Worker       if (isa == system_server_isa) {
1678*795d594fSAndroid Build Coastguard Worker         compilation_options->system_server_jars_to_compile = AllSystemServerJars();
1679*795d594fSAndroid Build Coastguard Worker       }
1680*795d594fSAndroid Build Coastguard Worker     }
1681*795d594fSAndroid Build Coastguard Worker   }
1682*795d594fSAndroid Build Coastguard Worker 
1683*795d594fSAndroid Build Coastguard Worker   if (compilation_options->system_server_jars_to_compile.empty()) {
1684*795d594fSAndroid Build Coastguard Worker     compilation_options->system_server_jars_to_compile = CheckSystemServerArtifactsAreUpToDate(
1685*795d594fSAndroid Build Coastguard Worker         metrics, system_result, data_result, &checked_artifacts);
1686*795d594fSAndroid Build Coastguard Worker   }
1687*795d594fSAndroid Build Coastguard Worker 
1688*795d594fSAndroid Build Coastguard Worker   bool compilation_required = compilation_options->CompilationUnitCount() > 0;
1689*795d594fSAndroid Build Coastguard Worker 
1690*795d594fSAndroid Build Coastguard Worker   if (!compilation_required && !data_result.IsAllOk()) {
1691*795d594fSAndroid Build Coastguard Worker     // Return kCompilationRequired to generate the cache info even if there's nothing to compile.
1692*795d594fSAndroid Build Coastguard Worker     compilation_required = true;
1693*795d594fSAndroid Build Coastguard Worker     metrics.SetTrigger(data_result.GetTrigger());
1694*795d594fSAndroid Build Coastguard Worker   }
1695*795d594fSAndroid Build Coastguard Worker 
1696*795d594fSAndroid Build Coastguard Worker   // Always keep the cache info.
1697*795d594fSAndroid Build Coastguard Worker   checked_artifacts.push_back(cache_info_filename_);
1698*795d594fSAndroid Build Coastguard Worker 
1699*795d594fSAndroid Build Coastguard Worker   Result<void> result = CleanupArtifactDirectory(metrics, checked_artifacts);
1700*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1701*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << result.error();
1702*795d594fSAndroid Build Coastguard Worker     return ExitCode::kCleanupFailed;
1703*795d594fSAndroid Build Coastguard Worker   }
1704*795d594fSAndroid Build Coastguard Worker 
1705*795d594fSAndroid Build Coastguard Worker   return compilation_required ? ExitCode::kCompilationRequired : ExitCode::kOkay;
1706*795d594fSAndroid Build Coastguard Worker }
1707*795d594fSAndroid Build Coastguard Worker 
RunDex2oat(const std::string & staging_dir,const std::string & debug_message,InstructionSet isa,const std::vector<std::string> & dex_files,const std::vector<std::string> & boot_classpath,const std::vector<std::string> & input_boot_images,const OdrArtifacts & artifacts,CmdlineBuilder && extra_args,std::vector<std::unique_ptr<File>> & readonly_files_raii) const1708*795d594fSAndroid Build Coastguard Worker WARN_UNUSED CompilationResult OnDeviceRefresh::RunDex2oat(
1709*795d594fSAndroid Build Coastguard Worker     const std::string& staging_dir,
1710*795d594fSAndroid Build Coastguard Worker     const std::string& debug_message,
1711*795d594fSAndroid Build Coastguard Worker     InstructionSet isa,
1712*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& dex_files,
1713*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& boot_classpath,
1714*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& input_boot_images,
1715*795d594fSAndroid Build Coastguard Worker     const OdrArtifacts& artifacts,
1716*795d594fSAndroid Build Coastguard Worker     CmdlineBuilder&& extra_args,
1717*795d594fSAndroid Build Coastguard Worker     /*inout*/ std::vector<std::unique_ptr<File>>& readonly_files_raii) const {
1718*795d594fSAndroid Build Coastguard Worker   CmdlineBuilder args;
1719*795d594fSAndroid Build Coastguard Worker   args.Add(config_.GetDex2Oat());
1720*795d594fSAndroid Build Coastguard Worker 
1721*795d594fSAndroid Build Coastguard Worker   AddDex2OatCommonOptions(args);
1722*795d594fSAndroid Build Coastguard Worker   AddDex2OatDebugInfo(args);
1723*795d594fSAndroid Build Coastguard Worker   AddDex2OatInstructionSet(args, isa, config_.GetSystemProperties());
1724*795d594fSAndroid Build Coastguard Worker   Result<void> result = AddDex2OatConcurrencyArguments(
1725*795d594fSAndroid Build Coastguard Worker       args, config_.GetCompilationOsMode(), config_.GetSystemProperties());
1726*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1727*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Error(OdrMetrics::Status::kUnknown, result.error().message());
1728*795d594fSAndroid Build Coastguard Worker   }
1729*795d594fSAndroid Build Coastguard Worker 
1730*795d594fSAndroid Build Coastguard Worker   // dex2oat reads some system properties from cache-info.xml generated by odrefresh.
1731*795d594fSAndroid Build Coastguard Worker   result = AddCacheInfoFd(args, readonly_files_raii, cache_info_filename_);
1732*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1733*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Error(OdrMetrics::Status::kUnknown, result.error().message());
1734*795d594fSAndroid Build Coastguard Worker   }
1735*795d594fSAndroid Build Coastguard Worker 
1736*795d594fSAndroid Build Coastguard Worker   for (const std::string& dex_file : dex_files) {
1737*795d594fSAndroid Build Coastguard Worker     std::string actual_path = RewriteParentDirectoryIfNeeded(dex_file);
1738*795d594fSAndroid Build Coastguard Worker     args.Add("--dex-file=%s", dex_file);
1739*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> file(OS::OpenFileForReading(actual_path.c_str()));
1740*795d594fSAndroid Build Coastguard Worker     if (file == nullptr) {
1741*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(
1742*795d594fSAndroid Build Coastguard Worker           OdrMetrics::Status::kIoError,
1743*795d594fSAndroid Build Coastguard Worker           ART_FORMAT("Failed to open dex file '{}': {}", actual_path, strerror(errno)));
1744*795d594fSAndroid Build Coastguard Worker     }
1745*795d594fSAndroid Build Coastguard Worker     args.Add("--dex-fd=%d", file->Fd());
1746*795d594fSAndroid Build Coastguard Worker     readonly_files_raii.push_back(std::move(file));
1747*795d594fSAndroid Build Coastguard Worker   }
1748*795d594fSAndroid Build Coastguard Worker 
1749*795d594fSAndroid Build Coastguard Worker   args.AddRuntime("-Xbootclasspath:%s", Join(boot_classpath, ":"));
1750*795d594fSAndroid Build Coastguard Worker   result = AddBootClasspathFds(args, readonly_files_raii, boot_classpath);
1751*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
1752*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Error(OdrMetrics::Status::kIoError, result.error().message());
1753*795d594fSAndroid Build Coastguard Worker   }
1754*795d594fSAndroid Build Coastguard Worker 
1755*795d594fSAndroid Build Coastguard Worker   if (!input_boot_images.empty()) {
1756*795d594fSAndroid Build Coastguard Worker     args.Add("--boot-image=%s", Join(input_boot_images, ':'));
1757*795d594fSAndroid Build Coastguard Worker     result = AddCompiledBootClasspathFdsIfAny(
1758*795d594fSAndroid Build Coastguard Worker         args, readonly_files_raii, boot_classpath, isa, input_boot_images);
1759*795d594fSAndroid Build Coastguard Worker     if (!result.ok()) {
1760*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(OdrMetrics::Status::kIoError, result.error().message());
1761*795d594fSAndroid Build Coastguard Worker     }
1762*795d594fSAndroid Build Coastguard Worker   }
1763*795d594fSAndroid Build Coastguard Worker 
1764*795d594fSAndroid Build Coastguard Worker   args.Add("--oat-location=%s", artifacts.OatPath());
1765*795d594fSAndroid Build Coastguard Worker   std::pair<std::string, const char*> location_kind_pairs[] = {
1766*795d594fSAndroid Build Coastguard Worker       std::make_pair(artifacts.ImagePath(), artifacts.ImageKind()),
1767*795d594fSAndroid Build Coastguard Worker       std::make_pair(artifacts.OatPath(), "oat"),
1768*795d594fSAndroid Build Coastguard Worker       std::make_pair(artifacts.VdexPath(), "output-vdex")};
1769*795d594fSAndroid Build Coastguard Worker 
1770*795d594fSAndroid Build Coastguard Worker   std::string install_location = Dirname(artifacts.OatPath());
1771*795d594fSAndroid Build Coastguard Worker   if (!EnsureDirectoryExists(install_location)) {
1772*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Error(
1773*795d594fSAndroid Build Coastguard Worker         OdrMetrics::Status::kIoError,
1774*795d594fSAndroid Build Coastguard Worker         ART_FORMAT("Error encountered when preparing directory '{}'", install_location));
1775*795d594fSAndroid Build Coastguard Worker   }
1776*795d594fSAndroid Build Coastguard Worker 
1777*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<File>> output_files;
1778*795d594fSAndroid Build Coastguard Worker   for (const auto& [location, kind] : location_kind_pairs) {
1779*795d594fSAndroid Build Coastguard Worker     std::string output_location =
1780*795d594fSAndroid Build Coastguard Worker         staging_dir.empty() ? location : GetStagingLocation(staging_dir, location);
1781*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> output_file(OS::CreateEmptyFile(output_location.c_str()));
1782*795d594fSAndroid Build Coastguard Worker     if (output_file == nullptr) {
1783*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(
1784*795d594fSAndroid Build Coastguard Worker           OdrMetrics::Status::kIoError,
1785*795d594fSAndroid Build Coastguard Worker           ART_FORMAT("Failed to create {} file '{}': {}", kind, output_location, strerror(errno)));
1786*795d594fSAndroid Build Coastguard Worker     }
1787*795d594fSAndroid Build Coastguard Worker     args.Add(StringPrintf("--%s-fd=%d", kind, output_file->Fd()));
1788*795d594fSAndroid Build Coastguard Worker     output_files.emplace_back(std::move(output_file));
1789*795d594fSAndroid Build Coastguard Worker   }
1790*795d594fSAndroid Build Coastguard Worker 
1791*795d594fSAndroid Build Coastguard Worker   // We don't care about file state on failure.
1792*795d594fSAndroid Build Coastguard Worker   auto cleanup = ScopeGuard([&] {
1793*795d594fSAndroid Build Coastguard Worker     for (const std::unique_ptr<File>& file : output_files) {
1794*795d594fSAndroid Build Coastguard Worker       file->MarkUnchecked();
1795*795d594fSAndroid Build Coastguard Worker     }
1796*795d594fSAndroid Build Coastguard Worker   });
1797*795d594fSAndroid Build Coastguard Worker 
1798*795d594fSAndroid Build Coastguard Worker   args.Concat(std::move(extra_args));
1799*795d594fSAndroid Build Coastguard Worker 
1800*795d594fSAndroid Build Coastguard Worker   Timer timer;
1801*795d594fSAndroid Build Coastguard Worker   time_t timeout = GetSubprocessTimeout();
1802*795d594fSAndroid Build Coastguard Worker   std::string cmd_line = Join(args.Get(), ' ');
1803*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << ART_FORMAT("{}: {} [timeout {}s]", debug_message, cmd_line, timeout);
1804*795d594fSAndroid Build Coastguard Worker   if (config_.GetDryRun()) {
1805*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Compilation skipped (dry-run).";
1806*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Ok();
1807*795d594fSAndroid Build Coastguard Worker   }
1808*795d594fSAndroid Build Coastguard Worker 
1809*795d594fSAndroid Build Coastguard Worker   std::string error_msg;
1810*795d594fSAndroid Build Coastguard Worker   ExecResult dex2oat_result = exec_utils_->ExecAndReturnResult(args.Get(), timeout, &error_msg);
1811*795d594fSAndroid Build Coastguard Worker 
1812*795d594fSAndroid Build Coastguard Worker   if (dex2oat_result.exit_code != 0) {
1813*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Dex2oatError(
1814*795d594fSAndroid Build Coastguard Worker         dex2oat_result.exit_code < 0 ?
1815*795d594fSAndroid Build Coastguard Worker             error_msg :
1816*795d594fSAndroid Build Coastguard Worker             ART_FORMAT("dex2oat returned an unexpected code: {}", dex2oat_result.exit_code),
1817*795d594fSAndroid Build Coastguard Worker         timer.duration().count(),
1818*795d594fSAndroid Build Coastguard Worker         dex2oat_result);
1819*795d594fSAndroid Build Coastguard Worker   }
1820*795d594fSAndroid Build Coastguard Worker 
1821*795d594fSAndroid Build Coastguard Worker   if (staging_dir.empty()) {
1822*795d594fSAndroid Build Coastguard Worker     for (const std::unique_ptr<File>& file : output_files) {
1823*795d594fSAndroid Build Coastguard Worker       if (file->FlushCloseOrErase() != 0) {
1824*795d594fSAndroid Build Coastguard Worker         return CompilationResult::Error(
1825*795d594fSAndroid Build Coastguard Worker             OdrMetrics::Status::kIoError,
1826*795d594fSAndroid Build Coastguard Worker             ART_FORMAT("Failed to flush close file '{}'", file->GetPath()));
1827*795d594fSAndroid Build Coastguard Worker       }
1828*795d594fSAndroid Build Coastguard Worker     }
1829*795d594fSAndroid Build Coastguard Worker   } else {
1830*795d594fSAndroid Build Coastguard Worker     for (const std::unique_ptr<File>& file : output_files) {
1831*795d594fSAndroid Build Coastguard Worker       if (file->Flush() != 0) {
1832*795d594fSAndroid Build Coastguard Worker         return CompilationResult::Error(OdrMetrics::Status::kIoError,
1833*795d594fSAndroid Build Coastguard Worker                                         ART_FORMAT("Failed to flush file '{}'", file->GetPath()));
1834*795d594fSAndroid Build Coastguard Worker       }
1835*795d594fSAndroid Build Coastguard Worker     }
1836*795d594fSAndroid Build Coastguard Worker     if (!MoveOrEraseFiles(output_files, install_location, restorecon_)) {
1837*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(
1838*795d594fSAndroid Build Coastguard Worker           OdrMetrics::Status::kIoError,
1839*795d594fSAndroid Build Coastguard Worker           ART_FORMAT("Failed to commit artifacts to '{}'", install_location));
1840*795d594fSAndroid Build Coastguard Worker     }
1841*795d594fSAndroid Build Coastguard Worker   }
1842*795d594fSAndroid Build Coastguard Worker 
1843*795d594fSAndroid Build Coastguard Worker   cleanup.Disable();
1844*795d594fSAndroid Build Coastguard Worker   return CompilationResult::Dex2oatOk(timer.duration().count(), dex2oat_result);
1845*795d594fSAndroid Build Coastguard Worker }
1846*795d594fSAndroid Build Coastguard Worker 
1847*795d594fSAndroid Build Coastguard Worker WARN_UNUSED CompilationResult
RunDex2oatForBootClasspath(const std::string & staging_dir,const std::string & debug_name,InstructionSet isa,const std::vector<std::string> & dex_files,const std::vector<std::string> & boot_classpath,const std::vector<std::string> & input_boot_images,const std::string & output_path) const1848*795d594fSAndroid Build Coastguard Worker OnDeviceRefresh::RunDex2oatForBootClasspath(const std::string& staging_dir,
1849*795d594fSAndroid Build Coastguard Worker                                             const std::string& debug_name,
1850*795d594fSAndroid Build Coastguard Worker                                             InstructionSet isa,
1851*795d594fSAndroid Build Coastguard Worker                                             const std::vector<std::string>& dex_files,
1852*795d594fSAndroid Build Coastguard Worker                                             const std::vector<std::string>& boot_classpath,
1853*795d594fSAndroid Build Coastguard Worker                                             const std::vector<std::string>& input_boot_images,
1854*795d594fSAndroid Build Coastguard Worker                                             const std::string& output_path) const {
1855*795d594fSAndroid Build Coastguard Worker   CmdlineBuilder args;
1856*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<File>> readonly_files_raii;
1857*795d594fSAndroid Build Coastguard Worker 
1858*795d594fSAndroid Build Coastguard Worker   // Compile as a single image for fewer files and slightly less memory overhead.
1859*795d594fSAndroid Build Coastguard Worker   args.Add("--single-image");
1860*795d594fSAndroid Build Coastguard Worker 
1861*795d594fSAndroid Build Coastguard Worker   if (input_boot_images.empty()) {
1862*795d594fSAndroid Build Coastguard Worker     // Primary boot image.
1863*795d594fSAndroid Build Coastguard Worker     std::string art_boot_profile_file = GetArtRoot() + "/etc/boot-image.prof";
1864*795d594fSAndroid Build Coastguard Worker     std::string framework_boot_profile_file = GetAndroidRoot() + "/etc/boot-image.prof";
1865*795d594fSAndroid Build Coastguard Worker     Result<bool> has_any_profile = AddDex2OatProfile(
1866*795d594fSAndroid Build Coastguard Worker         args, readonly_files_raii, {art_boot_profile_file, framework_boot_profile_file});
1867*795d594fSAndroid Build Coastguard Worker     if (!has_any_profile.ok()) {
1868*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(OdrMetrics::Status::kIoError,
1869*795d594fSAndroid Build Coastguard Worker                                       has_any_profile.error().message());
1870*795d594fSAndroid Build Coastguard Worker     }
1871*795d594fSAndroid Build Coastguard Worker     if (!*has_any_profile) {
1872*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(OdrMetrics::Status::kIoError, "Missing boot image profile");
1873*795d594fSAndroid Build Coastguard Worker     }
1874*795d594fSAndroid Build Coastguard Worker     const std::string& compiler_filter = config_.GetBootImageCompilerFilter();
1875*795d594fSAndroid Build Coastguard Worker     if (!compiler_filter.empty()) {
1876*795d594fSAndroid Build Coastguard Worker       args.Add("--compiler-filter=%s", compiler_filter);
1877*795d594fSAndroid Build Coastguard Worker     } else {
1878*795d594fSAndroid Build Coastguard Worker       args.Add("--compiler-filter=%s", kPrimaryCompilerFilter);
1879*795d594fSAndroid Build Coastguard Worker     }
1880*795d594fSAndroid Build Coastguard Worker 
1881*795d594fSAndroid Build Coastguard Worker     args.Add(StringPrintf("--base=0x%08x", ART_BASE_ADDRESS));
1882*795d594fSAndroid Build Coastguard Worker 
1883*795d594fSAndroid Build Coastguard Worker     for (const std::string& prefix : {GetAndroidRoot(), GetArtRoot()}) {
1884*795d594fSAndroid Build Coastguard Worker       std::string dirty_image_objects_file = prefix + "/etc/dirty-image-objects";
1885*795d594fSAndroid Build Coastguard Worker       std::unique_ptr<File> file(OS::OpenFileForReading(dirty_image_objects_file.c_str()));
1886*795d594fSAndroid Build Coastguard Worker       if (file != nullptr) {
1887*795d594fSAndroid Build Coastguard Worker         args.Add("--dirty-image-objects-fd=%d", file->Fd());
1888*795d594fSAndroid Build Coastguard Worker         readonly_files_raii.push_back(std::move(file));
1889*795d594fSAndroid Build Coastguard Worker       } else if (errno == ENOENT) {
1890*795d594fSAndroid Build Coastguard Worker         LOG(WARNING) << ART_FORMAT("Missing dirty objects file '{}'", dirty_image_objects_file);
1891*795d594fSAndroid Build Coastguard Worker       } else {
1892*795d594fSAndroid Build Coastguard Worker         return CompilationResult::Error(OdrMetrics::Status::kIoError,
1893*795d594fSAndroid Build Coastguard Worker                                         ART_FORMAT("Failed to open dirty objects file '{}': {}",
1894*795d594fSAndroid Build Coastguard Worker                                                    dirty_image_objects_file,
1895*795d594fSAndroid Build Coastguard Worker                                                    strerror(errno)));
1896*795d594fSAndroid Build Coastguard Worker       }
1897*795d594fSAndroid Build Coastguard Worker     }
1898*795d594fSAndroid Build Coastguard Worker 
1899*795d594fSAndroid Build Coastguard Worker     std::string preloaded_classes_file(GetAndroidRoot() + "/etc/preloaded-classes");
1900*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<File> file(OS::OpenFileForReading(preloaded_classes_file.c_str()));
1901*795d594fSAndroid Build Coastguard Worker     if (file != nullptr) {
1902*795d594fSAndroid Build Coastguard Worker       args.Add("--preloaded-classes-fds=%d", file->Fd());
1903*795d594fSAndroid Build Coastguard Worker       readonly_files_raii.push_back(std::move(file));
1904*795d594fSAndroid Build Coastguard Worker     } else if (errno == ENOENT) {
1905*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << ART_FORMAT("Missing preloaded classes file '{}'", preloaded_classes_file);
1906*795d594fSAndroid Build Coastguard Worker     } else {
1907*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(OdrMetrics::Status::kIoError,
1908*795d594fSAndroid Build Coastguard Worker                                       ART_FORMAT("Failed to open preloaded classes file '{}': {}",
1909*795d594fSAndroid Build Coastguard Worker                                                  preloaded_classes_file,
1910*795d594fSAndroid Build Coastguard Worker                                                  strerror(errno)));
1911*795d594fSAndroid Build Coastguard Worker     }
1912*795d594fSAndroid Build Coastguard Worker   } else {
1913*795d594fSAndroid Build Coastguard Worker     // Mainline extension.
1914*795d594fSAndroid Build Coastguard Worker     args.Add("--compiler-filter=%s", kMainlineCompilerFilter);
1915*795d594fSAndroid Build Coastguard Worker   }
1916*795d594fSAndroid Build Coastguard Worker 
1917*795d594fSAndroid Build Coastguard Worker   const OdrSystemProperties& system_properties = config_.GetSystemProperties();
1918*795d594fSAndroid Build Coastguard Worker   args.AddRuntimeIfNonEmpty("-Xms%s", system_properties.GetOrEmpty("dalvik.vm.image-dex2oat-Xms"))
1919*795d594fSAndroid Build Coastguard Worker       .AddRuntimeIfNonEmpty("-Xmx%s", system_properties.GetOrEmpty("dalvik.vm.image-dex2oat-Xmx"));
1920*795d594fSAndroid Build Coastguard Worker 
1921*795d594fSAndroid Build Coastguard Worker   return RunDex2oat(
1922*795d594fSAndroid Build Coastguard Worker       staging_dir,
1923*795d594fSAndroid Build Coastguard Worker       ART_FORMAT("Compiling boot classpath ({}, {})", GetInstructionSetString(isa), debug_name),
1924*795d594fSAndroid Build Coastguard Worker       isa,
1925*795d594fSAndroid Build Coastguard Worker       dex_files,
1926*795d594fSAndroid Build Coastguard Worker       boot_classpath,
1927*795d594fSAndroid Build Coastguard Worker       input_boot_images,
1928*795d594fSAndroid Build Coastguard Worker       OdrArtifacts::ForBootImage(output_path),
1929*795d594fSAndroid Build Coastguard Worker       std::move(args),
1930*795d594fSAndroid Build Coastguard Worker       readonly_files_raii);
1931*795d594fSAndroid Build Coastguard Worker }
1932*795d594fSAndroid Build Coastguard Worker 
1933*795d594fSAndroid Build Coastguard Worker WARN_UNUSED CompilationResult
CompileBootClasspath(const std::string & staging_dir,InstructionSet isa,BootImages boot_images,const std::function<void ()> & on_dex2oat_success) const1934*795d594fSAndroid Build Coastguard Worker OnDeviceRefresh::CompileBootClasspath(const std::string& staging_dir,
1935*795d594fSAndroid Build Coastguard Worker                                       InstructionSet isa,
1936*795d594fSAndroid Build Coastguard Worker                                       BootImages boot_images,
1937*795d594fSAndroid Build Coastguard Worker                                       const std::function<void()>& on_dex2oat_success) const {
1938*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(boot_images.Count(), 0);
1939*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(boot_images.primary_boot_image, boot_images.boot_image_mainline_extension);
1940*795d594fSAndroid Build Coastguard Worker 
1941*795d594fSAndroid Build Coastguard Worker   CompilationResult result = CompilationResult::Ok();
1942*795d594fSAndroid Build Coastguard Worker 
1943*795d594fSAndroid Build Coastguard Worker   if (config_.GetMinimal()) {
1944*795d594fSAndroid Build Coastguard Worker     result.Merge(
1945*795d594fSAndroid Build Coastguard Worker         CompilationResult::Error(OdrMetrics::Status::kUnknown, "Minimal boot image requested"));
1946*795d594fSAndroid Build Coastguard Worker   }
1947*795d594fSAndroid Build Coastguard Worker 
1948*795d594fSAndroid Build Coastguard Worker   if (!check_compilation_space_()) {
1949*795d594fSAndroid Build Coastguard Worker     result.Merge(CompilationResult::Error(OdrMetrics::Status::kNoSpace, "Insufficient space"));
1950*795d594fSAndroid Build Coastguard Worker   }
1951*795d594fSAndroid Build Coastguard Worker 
1952*795d594fSAndroid Build Coastguard Worker   if (result.IsOk() && boot_images.primary_boot_image) {
1953*795d594fSAndroid Build Coastguard Worker     CompilationResult primary_result = RunDex2oatForBootClasspath(
1954*795d594fSAndroid Build Coastguard Worker         staging_dir,
1955*795d594fSAndroid Build Coastguard Worker         "primary",
1956*795d594fSAndroid Build Coastguard Worker         isa,
1957*795d594fSAndroid Build Coastguard Worker         dex2oat_boot_classpath_jars_,
1958*795d594fSAndroid Build Coastguard Worker         dex2oat_boot_classpath_jars_,
1959*795d594fSAndroid Build Coastguard Worker         /*input_boot_images=*/{},
1960*795d594fSAndroid Build Coastguard Worker         GetPrimaryBootImagePath(/*on_system=*/false, /*minimal=*/false, isa));
1961*795d594fSAndroid Build Coastguard Worker     result.Merge(primary_result);
1962*795d594fSAndroid Build Coastguard Worker 
1963*795d594fSAndroid Build Coastguard Worker     if (primary_result.IsOk()) {
1964*795d594fSAndroid Build Coastguard Worker       on_dex2oat_success();
1965*795d594fSAndroid Build Coastguard Worker 
1966*795d594fSAndroid Build Coastguard Worker       // Remove the minimal boot image only if the full boot image is successfully generated.
1967*795d594fSAndroid Build Coastguard Worker       std::string path = GetPrimaryBootImagePath(/*on_system=*/false, /*minimal=*/true, isa);
1968*795d594fSAndroid Build Coastguard Worker       OdrArtifacts artifacts = OdrArtifacts::ForBootImage(path);
1969*795d594fSAndroid Build Coastguard Worker       unlink(artifacts.ImagePath().c_str());
1970*795d594fSAndroid Build Coastguard Worker       unlink(artifacts.OatPath().c_str());
1971*795d594fSAndroid Build Coastguard Worker       unlink(artifacts.VdexPath().c_str());
1972*795d594fSAndroid Build Coastguard Worker     }
1973*795d594fSAndroid Build Coastguard Worker   }
1974*795d594fSAndroid Build Coastguard Worker 
1975*795d594fSAndroid Build Coastguard Worker   if (!result.IsOk() && boot_images.primary_boot_image) {
1976*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Compilation of primary BCP failed: " << result.error_msg;
1977*795d594fSAndroid Build Coastguard Worker 
1978*795d594fSAndroid Build Coastguard Worker     // Fall back to generating a minimal boot image.
1979*795d594fSAndroid Build Coastguard Worker     // The compilation of the full boot image will be retried on later reboots with a backoff
1980*795d594fSAndroid Build Coastguard Worker     // time, and the minimal boot image will be removed once the compilation of the full boot
1981*795d594fSAndroid Build Coastguard Worker     // image succeeds.
1982*795d594fSAndroid Build Coastguard Worker     std::string ignored_error_msg;
1983*795d594fSAndroid Build Coastguard Worker     if (PrimaryBootImageExist(
1984*795d594fSAndroid Build Coastguard Worker             /*on_system=*/false, /*minimal=*/true, isa, &ignored_error_msg)) {
1985*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "Minimal boot image already up-to-date";
1986*795d594fSAndroid Build Coastguard Worker       return result;
1987*795d594fSAndroid Build Coastguard Worker     }
1988*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> art_bcp_jars = GetArtBcpJars();
1989*795d594fSAndroid Build Coastguard Worker     CompilationResult minimal_result = RunDex2oatForBootClasspath(
1990*795d594fSAndroid Build Coastguard Worker         staging_dir,
1991*795d594fSAndroid Build Coastguard Worker         "minimal",
1992*795d594fSAndroid Build Coastguard Worker         isa,
1993*795d594fSAndroid Build Coastguard Worker         art_bcp_jars,
1994*795d594fSAndroid Build Coastguard Worker         art_bcp_jars,
1995*795d594fSAndroid Build Coastguard Worker         /*input_boot_images=*/{},
1996*795d594fSAndroid Build Coastguard Worker         GetPrimaryBootImagePath(/*on_system=*/false, /*minimal=*/true, isa));
1997*795d594fSAndroid Build Coastguard Worker     result.Merge(minimal_result);
1998*795d594fSAndroid Build Coastguard Worker 
1999*795d594fSAndroid Build Coastguard Worker     if (!minimal_result.IsOk()) {
2000*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Compilation of minimal BCP failed: " << result.error_msg;
2001*795d594fSAndroid Build Coastguard Worker     }
2002*795d594fSAndroid Build Coastguard Worker 
2003*795d594fSAndroid Build Coastguard Worker     return result;
2004*795d594fSAndroid Build Coastguard Worker   }
2005*795d594fSAndroid Build Coastguard Worker 
2006*795d594fSAndroid Build Coastguard Worker   if (result.IsOk() && boot_images.boot_image_mainline_extension) {
2007*795d594fSAndroid Build Coastguard Worker     CompilationResult mainline_result =
2008*795d594fSAndroid Build Coastguard Worker         RunDex2oatForBootClasspath(staging_dir,
2009*795d594fSAndroid Build Coastguard Worker                                    "mainline",
2010*795d594fSAndroid Build Coastguard Worker                                    isa,
2011*795d594fSAndroid Build Coastguard Worker                                    GetMainlineBcpJars(),
2012*795d594fSAndroid Build Coastguard Worker                                    boot_classpath_jars_,
2013*795d594fSAndroid Build Coastguard Worker                                    GetBestBootImages(isa, /*include_mainline_extension=*/false),
2014*795d594fSAndroid Build Coastguard Worker                                    GetBootImageMainlineExtensionPath(/*on_system=*/false, isa));
2015*795d594fSAndroid Build Coastguard Worker     result.Merge(mainline_result);
2016*795d594fSAndroid Build Coastguard Worker 
2017*795d594fSAndroid Build Coastguard Worker     if (mainline_result.IsOk()) {
2018*795d594fSAndroid Build Coastguard Worker       on_dex2oat_success();
2019*795d594fSAndroid Build Coastguard Worker     }
2020*795d594fSAndroid Build Coastguard Worker   }
2021*795d594fSAndroid Build Coastguard Worker 
2022*795d594fSAndroid Build Coastguard Worker   if (!result.IsOk() && boot_images.boot_image_mainline_extension) {
2023*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Compilation of mainline BCP failed: " << result.error_msg;
2024*795d594fSAndroid Build Coastguard Worker   }
2025*795d594fSAndroid Build Coastguard Worker 
2026*795d594fSAndroid Build Coastguard Worker   return result;
2027*795d594fSAndroid Build Coastguard Worker }
2028*795d594fSAndroid Build Coastguard Worker 
RunDex2oatForSystemServer(const std::string & staging_dir,const std::string & dex_file,const std::vector<std::string> & classloader_context) const2029*795d594fSAndroid Build Coastguard Worker WARN_UNUSED CompilationResult OnDeviceRefresh::RunDex2oatForSystemServer(
2030*795d594fSAndroid Build Coastguard Worker     const std::string& staging_dir,
2031*795d594fSAndroid Build Coastguard Worker     const std::string& dex_file,
2032*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& classloader_context) const {
2033*795d594fSAndroid Build Coastguard Worker   CmdlineBuilder args;
2034*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<File>> readonly_files_raii;
2035*795d594fSAndroid Build Coastguard Worker   InstructionSet isa = config_.GetSystemServerIsa();
2036*795d594fSAndroid Build Coastguard Worker   std::string output_path = GetSystemServerImagePath(/*on_system=*/false, dex_file);
2037*795d594fSAndroid Build Coastguard Worker 
2038*795d594fSAndroid Build Coastguard Worker   std::string actual_jar_path = RewriteParentDirectoryIfNeeded(dex_file);
2039*795d594fSAndroid Build Coastguard Worker   std::string profile = actual_jar_path + ".prof";
2040*795d594fSAndroid Build Coastguard Worker   const std::string& compiler_filter = config_.GetSystemServerCompilerFilter();
2041*795d594fSAndroid Build Coastguard Worker   bool maybe_add_profile = !compiler_filter.empty() || HasVettedDeviceSystemServerProfiles();
2042*795d594fSAndroid Build Coastguard Worker   bool has_added_profile = false;
2043*795d594fSAndroid Build Coastguard Worker   if (maybe_add_profile) {
2044*795d594fSAndroid Build Coastguard Worker     Result<bool> has_any_profile = AddDex2OatProfile(args, readonly_files_raii, {profile});
2045*795d594fSAndroid Build Coastguard Worker     if (!has_any_profile.ok()) {
2046*795d594fSAndroid Build Coastguard Worker       return CompilationResult::Error(OdrMetrics::Status::kIoError,
2047*795d594fSAndroid Build Coastguard Worker                                       has_any_profile.error().message());
2048*795d594fSAndroid Build Coastguard Worker     }
2049*795d594fSAndroid Build Coastguard Worker     has_added_profile = *has_any_profile;
2050*795d594fSAndroid Build Coastguard Worker   }
2051*795d594fSAndroid Build Coastguard Worker   if (!compiler_filter.empty()) {
2052*795d594fSAndroid Build Coastguard Worker     args.Add("--compiler-filter=%s", compiler_filter);
2053*795d594fSAndroid Build Coastguard Worker   } else if (has_added_profile) {
2054*795d594fSAndroid Build Coastguard Worker     args.Add("--compiler-filter=speed-profile");
2055*795d594fSAndroid Build Coastguard Worker   } else {
2056*795d594fSAndroid Build Coastguard Worker     args.Add("--compiler-filter=speed");
2057*795d594fSAndroid Build Coastguard Worker   }
2058*795d594fSAndroid Build Coastguard Worker 
2059*795d594fSAndroid Build Coastguard Worker   std::string context_path = Join(classloader_context, ':');
2060*795d594fSAndroid Build Coastguard Worker   if (art::ContainsElement(systemserver_classpath_jars_, dex_file)) {
2061*795d594fSAndroid Build Coastguard Worker     args.Add("--class-loader-context=PCL[%s]", context_path);
2062*795d594fSAndroid Build Coastguard Worker   } else {
2063*795d594fSAndroid Build Coastguard Worker     args.Add("--class-loader-context=PCL[];PCL[%s]", context_path);
2064*795d594fSAndroid Build Coastguard Worker   }
2065*795d594fSAndroid Build Coastguard Worker   if (!classloader_context.empty()) {
2066*795d594fSAndroid Build Coastguard Worker     std::vector<int> fds;
2067*795d594fSAndroid Build Coastguard Worker     for (const std::string& path : classloader_context) {
2068*795d594fSAndroid Build Coastguard Worker       std::string actual_path = RewriteParentDirectoryIfNeeded(path);
2069*795d594fSAndroid Build Coastguard Worker       std::unique_ptr<File> file(OS::OpenFileForReading(actual_path.c_str()));
2070*795d594fSAndroid Build Coastguard Worker       if (file == nullptr) {
2071*795d594fSAndroid Build Coastguard Worker         return CompilationResult::Error(
2072*795d594fSAndroid Build Coastguard Worker             OdrMetrics::Status::kIoError,
2073*795d594fSAndroid Build Coastguard Worker             ART_FORMAT(
2074*795d594fSAndroid Build Coastguard Worker                 "Failed to open classloader context '{}': {}", actual_path, strerror(errno)));
2075*795d594fSAndroid Build Coastguard Worker       }
2076*795d594fSAndroid Build Coastguard Worker       fds.emplace_back(file->Fd());
2077*795d594fSAndroid Build Coastguard Worker       readonly_files_raii.emplace_back(std::move(file));
2078*795d594fSAndroid Build Coastguard Worker     }
2079*795d594fSAndroid Build Coastguard Worker     args.Add("--class-loader-context-fds=%s", Join(fds, ':'));
2080*795d594fSAndroid Build Coastguard Worker   }
2081*795d594fSAndroid Build Coastguard Worker 
2082*795d594fSAndroid Build Coastguard Worker   const OdrSystemProperties& system_properties = config_.GetSystemProperties();
2083*795d594fSAndroid Build Coastguard Worker   args.AddRuntimeIfNonEmpty("-Xms%s", system_properties.GetOrEmpty("dalvik.vm.dex2oat-Xms"))
2084*795d594fSAndroid Build Coastguard Worker       .AddRuntimeIfNonEmpty("-Xmx%s", system_properties.GetOrEmpty("dalvik.vm.dex2oat-Xmx"));
2085*795d594fSAndroid Build Coastguard Worker 
2086*795d594fSAndroid Build Coastguard Worker   return RunDex2oat(staging_dir,
2087*795d594fSAndroid Build Coastguard Worker                     ART_FORMAT("Compiling {}", Basename(dex_file)),
2088*795d594fSAndroid Build Coastguard Worker                     isa,
2089*795d594fSAndroid Build Coastguard Worker                     {dex_file},
2090*795d594fSAndroid Build Coastguard Worker                     boot_classpath_jars_,
2091*795d594fSAndroid Build Coastguard Worker                     GetBestBootImages(isa, /*include_mainline_extension=*/true),
2092*795d594fSAndroid Build Coastguard Worker                     OdrArtifacts::ForSystemServer(output_path),
2093*795d594fSAndroid Build Coastguard Worker                     std::move(args),
2094*795d594fSAndroid Build Coastguard Worker                     readonly_files_raii);
2095*795d594fSAndroid Build Coastguard Worker }
2096*795d594fSAndroid Build Coastguard Worker 
2097*795d594fSAndroid Build Coastguard Worker WARN_UNUSED CompilationResult
CompileSystemServer(const std::string & staging_dir,const std::set<std::string> & system_server_jars_to_compile,const std::function<void ()> & on_dex2oat_success) const2098*795d594fSAndroid Build Coastguard Worker OnDeviceRefresh::CompileSystemServer(const std::string& staging_dir,
2099*795d594fSAndroid Build Coastguard Worker                                      const std::set<std::string>& system_server_jars_to_compile,
2100*795d594fSAndroid Build Coastguard Worker                                      const std::function<void()>& on_dex2oat_success) const {
2101*795d594fSAndroid Build Coastguard Worker   DCHECK(!system_server_jars_to_compile.empty());
2102*795d594fSAndroid Build Coastguard Worker 
2103*795d594fSAndroid Build Coastguard Worker   CompilationResult result = CompilationResult::Ok();
2104*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> classloader_context;
2105*795d594fSAndroid Build Coastguard Worker 
2106*795d594fSAndroid Build Coastguard Worker   if (!check_compilation_space_()) {
2107*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Compilation of system_server failed: Insufficient space";
2108*795d594fSAndroid Build Coastguard Worker     return CompilationResult::Error(OdrMetrics::Status::kNoSpace, "Insufficient space");
2109*795d594fSAndroid Build Coastguard Worker   }
2110*795d594fSAndroid Build Coastguard Worker 
2111*795d594fSAndroid Build Coastguard Worker   for (const std::string& jar : all_systemserver_jars_) {
2112*795d594fSAndroid Build Coastguard Worker     if (ContainsElement(system_server_jars_to_compile, jar)) {
2113*795d594fSAndroid Build Coastguard Worker       CompilationResult current_result =
2114*795d594fSAndroid Build Coastguard Worker           RunDex2oatForSystemServer(staging_dir, jar, classloader_context);
2115*795d594fSAndroid Build Coastguard Worker       result.Merge(current_result);
2116*795d594fSAndroid Build Coastguard Worker 
2117*795d594fSAndroid Build Coastguard Worker       if (current_result.IsOk()) {
2118*795d594fSAndroid Build Coastguard Worker         on_dex2oat_success();
2119*795d594fSAndroid Build Coastguard Worker       } else {
2120*795d594fSAndroid Build Coastguard Worker         LOG(ERROR) << ART_FORMAT("Compilation of {} failed: {}", Basename(jar), result.error_msg);
2121*795d594fSAndroid Build Coastguard Worker       }
2122*795d594fSAndroid Build Coastguard Worker     }
2123*795d594fSAndroid Build Coastguard Worker 
2124*795d594fSAndroid Build Coastguard Worker     if (ContainsElement(systemserver_classpath_jars_, jar)) {
2125*795d594fSAndroid Build Coastguard Worker       classloader_context.emplace_back(jar);
2126*795d594fSAndroid Build Coastguard Worker     }
2127*795d594fSAndroid Build Coastguard Worker   }
2128*795d594fSAndroid Build Coastguard Worker 
2129*795d594fSAndroid Build Coastguard Worker   return result;
2130*795d594fSAndroid Build Coastguard Worker }
2131*795d594fSAndroid Build Coastguard Worker 
Compile(OdrMetrics & metrics,CompilationOptions compilation_options) const2132*795d594fSAndroid Build Coastguard Worker WARN_UNUSED ExitCode OnDeviceRefresh::Compile(OdrMetrics& metrics,
2133*795d594fSAndroid Build Coastguard Worker                                               CompilationOptions compilation_options) const {
2134*795d594fSAndroid Build Coastguard Worker   std::string staging_dir;
2135*795d594fSAndroid Build Coastguard Worker   metrics.SetStage(OdrMetrics::Stage::kPreparation);
2136*795d594fSAndroid Build Coastguard Worker 
2137*795d594fSAndroid Build Coastguard Worker   // If partial compilation is disabled, we should compile everything regardless of what's in
2138*795d594fSAndroid Build Coastguard Worker   // `compilation_options`.
2139*795d594fSAndroid Build Coastguard Worker   if (!config_.GetPartialCompilation()) {
2140*795d594fSAndroid Build Coastguard Worker     compilation_options = CompilationOptions::CompileAll(*this);
2141*795d594fSAndroid Build Coastguard Worker     if (!RemoveArtifactsDirectory()) {
2142*795d594fSAndroid Build Coastguard Worker       metrics.SetStatus(OdrMetrics::Status::kIoError);
2143*795d594fSAndroid Build Coastguard Worker       return ExitCode::kCleanupFailed;
2144*795d594fSAndroid Build Coastguard Worker     }
2145*795d594fSAndroid Build Coastguard Worker   }
2146*795d594fSAndroid Build Coastguard Worker 
2147*795d594fSAndroid Build Coastguard Worker   if (!EnsureDirectoryExists(config_.GetArtifactDirectory())) {
2148*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to prepare artifact directory";
2149*795d594fSAndroid Build Coastguard Worker     metrics.SetStatus(errno == EPERM ? OdrMetrics::Status::kDalvikCachePermissionDenied :
2150*795d594fSAndroid Build Coastguard Worker                                        OdrMetrics::Status::kIoError);
2151*795d594fSAndroid Build Coastguard Worker     return ExitCode::kCleanupFailed;
2152*795d594fSAndroid Build Coastguard Worker   }
2153*795d594fSAndroid Build Coastguard Worker 
2154*795d594fSAndroid Build Coastguard Worker   if (config_.GetRefresh()) {
2155*795d594fSAndroid Build Coastguard Worker     Result<void> result = RefreshExistingArtifacts();
2156*795d594fSAndroid Build Coastguard Worker     if (!result.ok()) {
2157*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to refresh existing artifacts: " << result.error();
2158*795d594fSAndroid Build Coastguard Worker       metrics.SetStatus(OdrMetrics::Status::kIoError);
2159*795d594fSAndroid Build Coastguard Worker       return ExitCode::kCleanupFailed;
2160*795d594fSAndroid Build Coastguard Worker     }
2161*795d594fSAndroid Build Coastguard Worker   }
2162*795d594fSAndroid Build Coastguard Worker 
2163*795d594fSAndroid Build Coastguard Worker   // Emit cache info before compiling. This can be used to throttle compilation attempts later.
2164*795d594fSAndroid Build Coastguard Worker   Result<void> result = WriteCacheInfo();
2165*795d594fSAndroid Build Coastguard Worker   if (!result.ok()) {
2166*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << result.error();
2167*795d594fSAndroid Build Coastguard Worker     metrics.SetStatus(OdrMetrics::Status::kIoError);
2168*795d594fSAndroid Build Coastguard Worker     return ExitCode::kCleanupFailed;
2169*795d594fSAndroid Build Coastguard Worker   }
2170*795d594fSAndroid Build Coastguard Worker 
2171*795d594fSAndroid Build Coastguard Worker   if (config_.GetCompilationOsMode()) {
2172*795d594fSAndroid Build Coastguard Worker     // We don't need to stage files in CompOS. If the compilation fails (partially or entirely),
2173*795d594fSAndroid Build Coastguard Worker     // CompOS will not sign any artifacts, and odsign will discard CompOS outputs entirely.
2174*795d594fSAndroid Build Coastguard Worker     staging_dir = "";
2175*795d594fSAndroid Build Coastguard Worker   } else {
2176*795d594fSAndroid Build Coastguard Worker     // Create staging area and assign label for generating compilation artifacts.
2177*795d594fSAndroid Build Coastguard Worker     Result<std::string> res = CreateStagingDirectory();
2178*795d594fSAndroid Build Coastguard Worker     if (!res.ok()) {
2179*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << res.error().message();
2180*795d594fSAndroid Build Coastguard Worker       metrics.SetStatus(OdrMetrics::Status::kStagingFailed);
2181*795d594fSAndroid Build Coastguard Worker       return ExitCode::kCleanupFailed;
2182*795d594fSAndroid Build Coastguard Worker     }
2183*795d594fSAndroid Build Coastguard Worker     staging_dir = res.value();
2184*795d594fSAndroid Build Coastguard Worker   }
2185*795d594fSAndroid Build Coastguard Worker 
2186*795d594fSAndroid Build Coastguard Worker   uint32_t dex2oat_invocation_count = 0;
2187*795d594fSAndroid Build Coastguard Worker   uint32_t total_dex2oat_invocation_count = compilation_options.CompilationUnitCount();
2188*795d594fSAndroid Build Coastguard Worker   ReportNextBootAnimationProgress(dex2oat_invocation_count, total_dex2oat_invocation_count);
2189*795d594fSAndroid Build Coastguard Worker   auto advance_animation_progress = [&]() {
2190*795d594fSAndroid Build Coastguard Worker     ReportNextBootAnimationProgress(++dex2oat_invocation_count, total_dex2oat_invocation_count);
2191*795d594fSAndroid Build Coastguard Worker   };
2192*795d594fSAndroid Build Coastguard Worker 
2193*795d594fSAndroid Build Coastguard Worker   const std::vector<InstructionSet>& bcp_instruction_sets = config_.GetBootClasspathIsas();
2194*795d594fSAndroid Build Coastguard Worker   DCHECK(!bcp_instruction_sets.empty() && bcp_instruction_sets.size() <= 2);
2195*795d594fSAndroid Build Coastguard Worker   InstructionSet system_server_isa = config_.GetSystemServerIsa();
2196*795d594fSAndroid Build Coastguard Worker 
2197*795d594fSAndroid Build Coastguard Worker   bool system_server_isa_failed = false;
2198*795d594fSAndroid Build Coastguard Worker   std::optional<std::pair<OdrMetrics::Stage, OdrMetrics::Status>> first_failure;
2199*795d594fSAndroid Build Coastguard Worker 
2200*795d594fSAndroid Build Coastguard Worker   for (const auto& [isa, boot_images_to_generate] :
2201*795d594fSAndroid Build Coastguard Worker        compilation_options.boot_images_to_generate_for_isas) {
2202*795d594fSAndroid Build Coastguard Worker     OdrMetrics::Stage stage = (isa == bcp_instruction_sets.front()) ?
2203*795d594fSAndroid Build Coastguard Worker                                   OdrMetrics::Stage::kPrimaryBootClasspath :
2204*795d594fSAndroid Build Coastguard Worker                                   OdrMetrics::Stage::kSecondaryBootClasspath;
2205*795d594fSAndroid Build Coastguard Worker     CompilationResult bcp_result =
2206*795d594fSAndroid Build Coastguard Worker         CompileBootClasspath(staging_dir, isa, boot_images_to_generate, advance_animation_progress);
2207*795d594fSAndroid Build Coastguard Worker     metrics.SetDex2OatResult(stage, bcp_result.elapsed_time_ms, bcp_result.dex2oat_result);
2208*795d594fSAndroid Build Coastguard Worker     metrics.SetBcpCompilationType(stage, boot_images_to_generate.GetTypeForMetrics());
2209*795d594fSAndroid Build Coastguard Worker     if (!bcp_result.IsOk()) {
2210*795d594fSAndroid Build Coastguard Worker       if (isa == system_server_isa) {
2211*795d594fSAndroid Build Coastguard Worker         system_server_isa_failed = true;
2212*795d594fSAndroid Build Coastguard Worker       }
2213*795d594fSAndroid Build Coastguard Worker       first_failure = first_failure.value_or(std::make_pair(stage, bcp_result.status));
2214*795d594fSAndroid Build Coastguard Worker     }
2215*795d594fSAndroid Build Coastguard Worker   }
2216*795d594fSAndroid Build Coastguard Worker 
2217*795d594fSAndroid Build Coastguard Worker   // Don't compile system server if the compilation of BCP failed.
2218*795d594fSAndroid Build Coastguard Worker   if (!system_server_isa_failed && !compilation_options.system_server_jars_to_compile.empty() &&
2219*795d594fSAndroid Build Coastguard Worker       !config_.GetOnlyBootImages()) {
2220*795d594fSAndroid Build Coastguard Worker     OdrMetrics::Stage stage = OdrMetrics::Stage::kSystemServerClasspath;
2221*795d594fSAndroid Build Coastguard Worker     CompilationResult ss_result = CompileSystemServer(
2222*795d594fSAndroid Build Coastguard Worker         staging_dir, compilation_options.system_server_jars_to_compile, advance_animation_progress);
2223*795d594fSAndroid Build Coastguard Worker     metrics.SetDex2OatResult(stage, ss_result.elapsed_time_ms, ss_result.dex2oat_result);
2224*795d594fSAndroid Build Coastguard Worker     if (!ss_result.IsOk()) {
2225*795d594fSAndroid Build Coastguard Worker       first_failure = first_failure.value_or(std::make_pair(stage, ss_result.status));
2226*795d594fSAndroid Build Coastguard Worker     }
2227*795d594fSAndroid Build Coastguard Worker   }
2228*795d594fSAndroid Build Coastguard Worker 
2229*795d594fSAndroid Build Coastguard Worker   if (first_failure.has_value()) {
2230*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Compilation failed, stage: " << first_failure->first
2231*795d594fSAndroid Build Coastguard Worker                << " status: " << first_failure->second;
2232*795d594fSAndroid Build Coastguard Worker     metrics.SetStage(first_failure->first);
2233*795d594fSAndroid Build Coastguard Worker     metrics.SetStatus(first_failure->second);
2234*795d594fSAndroid Build Coastguard Worker 
2235*795d594fSAndroid Build Coastguard Worker     if (!config_.GetDryRun() && !RemoveDirectory(staging_dir)) {
2236*795d594fSAndroid Build Coastguard Worker       return ExitCode::kCleanupFailed;
2237*795d594fSAndroid Build Coastguard Worker     }
2238*795d594fSAndroid Build Coastguard Worker     return ExitCode::kCompilationFailed;
2239*795d594fSAndroid Build Coastguard Worker   }
2240*795d594fSAndroid Build Coastguard Worker 
2241*795d594fSAndroid Build Coastguard Worker   metrics.SetStage(OdrMetrics::Stage::kComplete);
2242*795d594fSAndroid Build Coastguard Worker   metrics.SetStatus(OdrMetrics::Status::kOK);
2243*795d594fSAndroid Build Coastguard Worker   return ExitCode::kCompilationSuccess;
2244*795d594fSAndroid Build Coastguard Worker }
2245*795d594fSAndroid Build Coastguard Worker 
2246*795d594fSAndroid Build Coastguard Worker }  // namespace odrefresh
2247*795d594fSAndroid Build Coastguard Worker }  // namespace art
2248