1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "artd.h"
18 
19 #include <fcntl.h>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include <climits>
26 #include <csignal>
27 #include <cstddef>
28 #include <cstdint>
29 #include <cstdlib>
30 #include <cstring>
31 #include <filesystem>
32 #include <functional>
33 #include <iterator>
34 #include <map>
35 #include <memory>
36 #include <mutex>
37 #include <optional>
38 #include <ostream>
39 #include <regex>
40 #include <string>
41 #include <string_view>
42 #include <system_error>
43 #include <type_traits>
44 #include <unordered_set>
45 #include <utility>
46 #include <vector>
47 
48 #include "aidl/com/android/server/art/BnArtd.h"
49 #include "aidl/com/android/server/art/DexoptTrigger.h"
50 #include "aidl/com/android/server/art/IArtdCancellationSignal.h"
51 #include "android-base/errors.h"
52 #include "android-base/file.h"
53 #include "android-base/logging.h"
54 #include "android-base/parseint.h"
55 #include "android-base/result.h"
56 #include "android-base/scopeguard.h"
57 #include "android-base/strings.h"
58 #include "android/binder_auto_utils.h"
59 #include "android/binder_interface_utils.h"
60 #include "android/binder_manager.h"
61 #include "android/binder_process.h"
62 #include "base/compiler_filter.h"
63 #include "base/file_magic.h"
64 #include "base/file_utils.h"
65 #include "base/globals.h"
66 #include "base/logging.h"
67 #include "base/macros.h"
68 #include "base/mem_map.h"
69 #include "base/memfd.h"
70 #include "base/os.h"
71 #include "base/zip_archive.h"
72 #include "cmdline_types.h"
73 #include "dex/dex_file_loader.h"
74 #include "exec_utils.h"
75 #include "file_utils.h"
76 #include "fstab/fstab.h"
77 #include "oat/oat_file_assistant.h"
78 #include "oat/oat_file_assistant_context.h"
79 #include "odrefresh/odrefresh.h"
80 #include "path_utils.h"
81 #include "profman/profman_result.h"
82 #include "selinux/android.h"
83 #include "service.h"
84 #include "tools/binder_utils.h"
85 #include "tools/cmdline_builder.h"
86 #include "tools/tools.h"
87 
88 namespace art {
89 namespace artd {
90 
91 namespace {
92 
93 using ::aidl::com::android::server::art::ArtdDexoptResult;
94 using ::aidl::com::android::server::art::ArtifactsLocation;
95 using ::aidl::com::android::server::art::ArtifactsPath;
96 using ::aidl::com::android::server::art::CopyAndRewriteProfileResult;
97 using ::aidl::com::android::server::art::DexMetadataPath;
98 using ::aidl::com::android::server::art::DexoptOptions;
99 using ::aidl::com::android::server::art::DexoptTrigger;
100 using ::aidl::com::android::server::art::FileVisibility;
101 using ::aidl::com::android::server::art::FsPermission;
102 using ::aidl::com::android::server::art::GetDexoptNeededResult;
103 using ::aidl::com::android::server::art::GetDexoptStatusResult;
104 using ::aidl::com::android::server::art::IArtdCancellationSignal;
105 using ::aidl::com::android::server::art::MergeProfileOptions;
106 using ::aidl::com::android::server::art::OutputArtifacts;
107 using ::aidl::com::android::server::art::OutputProfile;
108 using ::aidl::com::android::server::art::PriorityClass;
109 using ::aidl::com::android::server::art::ProfilePath;
110 using ::aidl::com::android::server::art::RuntimeArtifactsPath;
111 using ::aidl::com::android::server::art::VdexPath;
112 using ::android::base::Dirname;
113 using ::android::base::ErrnoError;
114 using ::android::base::Error;
115 using ::android::base::Join;
116 using ::android::base::make_scope_guard;
117 using ::android::base::ParseInt;
118 using ::android::base::ReadFileToString;
119 using ::android::base::Result;
120 using ::android::base::Split;
121 using ::android::base::Tokenize;
122 using ::android::base::Trim;
123 using ::android::base::WriteStringToFd;
124 using ::android::base::WriteStringToFile;
125 using ::android::fs_mgr::FstabEntry;
126 using ::art::service::ValidateClassLoaderContext;
127 using ::art::service::ValidateDexPath;
128 using ::art::tools::CmdlineBuilder;
129 using ::art::tools::Fatal;
130 using ::art::tools::GetProcMountsAncestorsOfPath;
131 using ::art::tools::NonFatal;
132 using ::ndk::ScopedAStatus;
133 
134 using TmpProfilePath = ProfilePath::TmpProfilePath;
135 using WritableProfilePath = ProfilePath::WritableProfilePath;
136 
137 constexpr const char* kServiceName = "artd";
138 constexpr const char* kPreRebootServiceName = "artd_pre_reboot";
139 constexpr const char* kArtdCancellationSignalType = "ArtdCancellationSignal";
140 constexpr const char* kDefaultPreRebootTmpDir = "/mnt/artd_tmp";
141 
142 // Timeout for short operations, such as merging profiles.
143 constexpr int kShortTimeoutSec = 60;  // 1 minute.
144 
145 // Timeout for long operations, such as compilation. We set it to be smaller than the Package
146 // Manager watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that if the operation
147 // is called from the Package Manager's thread handler, it will be aborted before that watchdog
148 // would take down the system server.
149 constexpr int kLongTimeoutSec = 570;  // 9.5 minutes.
150 
GetSize(std::string_view path)151 std::optional<int64_t> GetSize(std::string_view path) {
152   std::error_code ec;
153   int64_t size = std::filesystem::file_size(path, ec);
154   if (ec) {
155     // It is okay if the file does not exist. We don't have to log it.
156     if (ec.value() != ENOENT) {
157       LOG(ERROR) << ART_FORMAT("Failed to get the file size of '{}': {}", path, ec.message());
158     }
159     return std::nullopt;
160   }
161   return size;
162 }
163 
DeleteFile(const std::string & path)164 bool DeleteFile(const std::string& path) {
165   std::error_code ec;
166   std::filesystem::remove(path, ec);
167   if (ec) {
168     LOG(ERROR) << ART_FORMAT("Failed to remove '{}': {}", path, ec.message());
169     return false;
170   }
171   return true;
172 }
173 
174 // Deletes a file. Returns the size of the deleted file, or 0 if the deleted file is empty or an
175 // error occurs.
GetSizeAndDeleteFile(const std::string & path)176 int64_t GetSizeAndDeleteFile(const std::string& path) {
177   std::optional<int64_t> size = GetSize(path);
178   if (!size.has_value()) {
179     return 0;
180   }
181   if (!DeleteFile(path)) {
182     return 0;
183   }
184   return size.value();
185 }
186 
ParseCompilerFilter(const std::string & compiler_filter_str)187 Result<CompilerFilter::Filter> ParseCompilerFilter(const std::string& compiler_filter_str) {
188   CompilerFilter::Filter compiler_filter;
189   if (!CompilerFilter::ParseCompilerFilter(compiler_filter_str.c_str(), &compiler_filter)) {
190     return Errorf("Failed to parse compiler filter '{}'", compiler_filter_str);
191   }
192   return compiler_filter;
193 }
194 
DexOptTriggerFromAidl(int32_t aidl_value)195 OatFileAssistant::DexOptTrigger DexOptTriggerFromAidl(int32_t aidl_value) {
196   OatFileAssistant::DexOptTrigger trigger{};
197   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::COMPILER_FILTER_IS_BETTER)) != 0) {
198     trigger.targetFilterIsBetter = true;
199   }
200   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::COMPILER_FILTER_IS_SAME)) != 0) {
201     trigger.targetFilterIsSame = true;
202   }
203   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::COMPILER_FILTER_IS_WORSE)) != 0) {
204     trigger.targetFilterIsWorse = true;
205   }
206   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::PRIMARY_BOOT_IMAGE_BECOMES_USABLE)) != 0) {
207     trigger.primaryBootImageBecomesUsable = true;
208   }
209   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::NEED_EXTRACTION)) != 0) {
210     trigger.needExtraction = true;
211   }
212   return trigger;
213 }
214 
ArtifactsLocationToAidl(OatFileAssistant::Location location)215 ArtifactsLocation ArtifactsLocationToAidl(OatFileAssistant::Location location) {
216   switch (location) {
217     case OatFileAssistant::Location::kLocationNoneOrError:
218       return ArtifactsLocation::NONE_OR_ERROR;
219     case OatFileAssistant::Location::kLocationOat:
220       return ArtifactsLocation::DALVIK_CACHE;
221     case OatFileAssistant::Location::kLocationOdex:
222       return ArtifactsLocation::NEXT_TO_DEX;
223     case OatFileAssistant::Location::kLocationDm:
224       return ArtifactsLocation::DM;
225       // No default. All cases should be explicitly handled, or the compilation will fail.
226   }
227   // This should never happen. Just in case we get a non-enumerator value.
228   LOG(FATAL) << "Unexpected Location " << location;
229 }
230 
CreateDir(const std::string & path)231 Result<bool> CreateDir(const std::string& path) {
232   std::error_code ec;
233   bool created = std::filesystem::create_directory(path, ec);
234   if (ec) {
235     return Errorf("Failed to create directory '{}': {}", path, ec.message());
236   }
237   return created;
238 }
239 
PrepareArtifactsDir(const std::string & path,const FsPermission & fs_permission)240 Result<void> PrepareArtifactsDir(const std::string& path, const FsPermission& fs_permission) {
241   bool created = OR_RETURN(CreateDir(path));
242 
243   auto cleanup = make_scope_guard([&] {
244     if (created) {
245       std::error_code ec;
246       std::filesystem::remove(path, ec);
247     }
248   });
249 
250   if (chmod(path.c_str(), DirFsPermissionToMode(fs_permission)) != 0) {
251     return ErrnoErrorf("Failed to chmod directory '{}'", path);
252   }
253   OR_RETURN(Chown(path, fs_permission));
254 
255   cleanup.Disable();
256   return {};
257 }
258 
PrepareArtifactsDirs(const OutputArtifacts & output_artifacts,std::string * oat_dir_path)259 Result<void> PrepareArtifactsDirs(const OutputArtifacts& output_artifacts,
260                                   /*out*/ std::string* oat_dir_path) {
261   if (output_artifacts.artifactsPath.isInDalvikCache) {
262     return {};
263   }
264 
265   std::filesystem::path oat_path(
266       OR_RETURN(BuildArtifactsPath(output_artifacts.artifactsPath)).oat_path);
267   std::filesystem::path isa_dir = oat_path.parent_path();
268   std::filesystem::path oat_dir = isa_dir.parent_path();
269   DCHECK_EQ(oat_dir.filename(), "oat");
270 
271   OR_RETURN(PrepareArtifactsDir(oat_dir, output_artifacts.permissionSettings.dirFsPermission));
272   OR_RETURN(PrepareArtifactsDir(isa_dir, output_artifacts.permissionSettings.dirFsPermission));
273   *oat_dir_path = oat_dir;
274   return {};
275 }
276 
GetFileVisibility(const std::string & file)277 Result<FileVisibility> GetFileVisibility(const std::string& file) {
278   std::error_code ec;
279   std::filesystem::file_status status = std::filesystem::status(file, ec);
280   if (!std::filesystem::status_known(status)) {
281     return Errorf("Failed to get status of '{}': {}", file, ec.message());
282   }
283   if (!std::filesystem::exists(status)) {
284     return FileVisibility::NOT_FOUND;
285   }
286 
287   return (status.permissions() & std::filesystem::perms::others_read) !=
288                  std::filesystem::perms::none ?
289              FileVisibility::OTHER_READABLE :
290              FileVisibility::NOT_OTHER_READABLE;
291 }
292 
ToArtdCancellationSignal(IArtdCancellationSignal * input)293 Result<ArtdCancellationSignal*> ToArtdCancellationSignal(IArtdCancellationSignal* input) {
294   if (input == nullptr) {
295     return Error() << "Cancellation signal must not be nullptr";
296   }
297   // We cannot use `dynamic_cast` because ART code is compiled with `-fno-rtti`, so we have to check
298   // the magic number.
299   int64_t type;
300   if (!input->getType(&type).isOk() ||
301       type != reinterpret_cast<intptr_t>(kArtdCancellationSignalType)) {
302     // The cancellation signal must be created by `Artd::createCancellationSignal`.
303     return Error() << "Invalid cancellation signal type";
304   }
305   return static_cast<ArtdCancellationSignal*>(input);
306 }
307 
CopyFile(const std::string & src_path,const NewFile & dst_file)308 Result<void> CopyFile(const std::string& src_path, const NewFile& dst_file) {
309   std::string content;
310   if (!ReadFileToString(src_path, &content)) {
311     return Errorf("Failed to read file '{}': {}", src_path, strerror(errno));
312   }
313   if (!WriteStringToFd(content, dst_file.Fd())) {
314     return Errorf("Failed to write file '{}': {}", dst_file.TempPath(), strerror(errno));
315   }
316   if (fsync(dst_file.Fd()) != 0) {
317     return Errorf("Failed to flush file '{}': {}", dst_file.TempPath(), strerror(errno));
318   }
319   if (lseek(dst_file.Fd(), /*offset=*/0, SEEK_SET) != 0) {
320     return Errorf(
321         "Failed to reset the offset for file '{}': {}", dst_file.TempPath(), strerror(errno));
322   }
323   return {};
324 }
325 
SetLogVerbosity()326 Result<void> SetLogVerbosity() {
327   std::string options =
328       android::base::GetProperty("dalvik.vm.artd-verbose", /*default_value=*/"oat");
329   if (options.empty()) {
330     return {};
331   }
332 
333   CmdlineType<LogVerbosity> parser;
334   CmdlineParseResult<LogVerbosity> result = parser.Parse(options);
335   if (!result.IsSuccess()) {
336     return Error() << result.GetMessage();
337   }
338 
339   gLogVerbosity = result.ReleaseValue();
340   return {};
341 }
342 
AnalyzeCopyAndRewriteProfileFailure(File * src,ProfmanResult::CopyAndUpdateResult result)343 CopyAndRewriteProfileResult AnalyzeCopyAndRewriteProfileFailure(
344     File* src, ProfmanResult::CopyAndUpdateResult result) {
345   DCHECK(result == ProfmanResult::kCopyAndUpdateNoMatch ||
346          result == ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile);
347 
348   auto bad_profile = [&](std::string_view error_msg) {
349     return CopyAndRewriteProfileResult{
350         .status = CopyAndRewriteProfileResult::Status::BAD_PROFILE,
351         .errorMsg = ART_FORMAT("Failed to load profile '{}': {}", src->GetPath(), error_msg)};
352   };
353   CopyAndRewriteProfileResult no_profile{.status = CopyAndRewriteProfileResult::Status::NO_PROFILE,
354                                          .errorMsg = ""};
355 
356   int64_t length = src->GetLength();
357   if (length < 0) {
358     return bad_profile(strerror(-length));
359   }
360   if (length == 0) {
361     return no_profile;
362   }
363 
364   std::string error_msg;
365   uint32_t magic;
366   if (!ReadMagicAndReset(src->Fd(), &magic, &error_msg)) {
367     return bad_profile(error_msg);
368   }
369   if (IsZipMagic(magic)) {
370     std::unique_ptr<ZipArchive> zip_archive(
371         ZipArchive::OpenFromOwnedFd(src->Fd(), src->GetPath().c_str(), &error_msg));
372     if (zip_archive == nullptr) {
373       return bad_profile(error_msg);
374     }
375     std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find("primary.prof", &error_msg));
376     if (zip_entry == nullptr || zip_entry->GetUncompressedLength() == 0) {
377       return no_profile;
378     }
379   }
380 
381   if (result == ProfmanResult::kCopyAndUpdateNoMatch) {
382     return bad_profile(
383         "The profile does not match the APK (The checksums in the profile do not match the "
384         "checksums of the .dex files in the APK)");
385   }
386   return bad_profile("The profile is in the wrong format or an I/O error has occurred");
387 }
388 
389 // Returns the fd on success, or an invalid fd if the dex file contains no profile, or error if any
390 // error occurs.
ExtractEmbeddedProfileToFd(const std::string & dex_path)391 Result<File> ExtractEmbeddedProfileToFd(const std::string& dex_path) {
392   std::unique_ptr<File> dex_file = OR_RETURN(OpenFileForReading(dex_path));
393 
394   std::string error_msg;
395   uint32_t magic;
396   if (!ReadMagicAndReset(dex_file->Fd(), &magic, &error_msg)) {
397     return Error() << error_msg;
398   }
399   if (!IsZipMagic(magic)) {
400     if (DexFileLoader::IsMagicValid(magic)) {
401       // The dex file can be a plain dex file. This is expected.
402       return File();
403     }
404     return Error() << "File is neither a zip file nor a plain dex file";
405   }
406 
407   std::unique_ptr<ZipArchive> zip_archive(
408       ZipArchive::OpenFromOwnedFd(dex_file->Fd(), dex_path.c_str(), &error_msg));
409   if (zip_archive == nullptr) {
410     return Error() << error_msg;
411   }
412   constexpr const char* kEmbeddedProfileEntry = "assets/art-profile/baseline.prof";
413   std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kEmbeddedProfileEntry, &error_msg));
414   size_t size;
415   if (zip_entry == nullptr || (size = zip_entry->GetUncompressedLength()) == 0) {
416     // From system/libziparchive/zip_error.cpp.
417     constexpr const char* kEntryNotFound = "Entry not found";
418     if (error_msg != kEntryNotFound) {
419       LOG(WARNING) << ART_FORMAT(
420           "Failed to find zip entry '{}' in '{}': {}", kEmbeddedProfileEntry, dex_path, error_msg);
421     }
422     // The dex file doesn't necessarily contain a profile. This is expected.
423     return File();
424   }
425 
426   // The name is for debugging only.
427   std::string memfd_name =
428       ART_FORMAT("{} extracted in memory from {}", kEmbeddedProfileEntry, dex_path);
429   File memfd(memfd_create(memfd_name.c_str(), /*flags=*/0),
430              memfd_name,
431              /*check_usage=*/false);
432   if (!memfd.IsValid()) {
433     return ErrnoError() << "Failed to create memfd";
434   }
435   if (ftruncate(memfd.Fd(), size) != 0) {
436     return ErrnoError() << "Failed to ftruncate memfd";
437   }
438   // Map with MAP_SHARED because we're feeding the fd to profman.
439   MemMap mem_map = MemMap::MapFile(size,
440                                    PROT_READ | PROT_WRITE,
441                                    MAP_SHARED,
442                                    memfd.Fd(),
443                                    /*start=*/0,
444                                    /*low_4gb=*/false,
445                                    memfd_name.c_str(),
446                                    &error_msg);
447   if (!mem_map.IsValid()) {
448     return Errorf("Failed to mmap memfd: {}", error_msg);
449   }
450   if (!zip_entry->ExtractToMemory(mem_map.Begin(), &error_msg)) {
451     return Errorf("Failed to extract '{}': {}", kEmbeddedProfileEntry, error_msg);
452   }
453 
454   // Reopen the memfd with readonly to make SELinux happy when the fd is passed to a child process
455   // who doesn't have write permission. (b/303909581)
456   std::string path = ART_FORMAT("/proc/self/fd/{}", memfd.Fd());
457   // NOLINTNEXTLINE - O_CLOEXEC is omitted on purpose
458   File memfd_readonly(open(path.c_str(), O_RDONLY),
459                       memfd_name,
460                       /*check_usage=*/false,
461                       /*read_only_mode=*/true);
462   if (!memfd_readonly.IsOpened()) {
463     return ErrnoErrorf("Failed to open file '{}' ('{}')", path, memfd_name);
464   }
465 
466   return memfd_readonly;
467 }
468 
469 class FdLogger {
470  public:
Add(const NewFile & file)471   void Add(const NewFile& file) { fd_mapping_.emplace_back(file.Fd(), file.TempPath()); }
Add(const File & file)472   void Add(const File& file) { fd_mapping_.emplace_back(file.Fd(), file.GetPath()); }
473 
GetFds()474   std::string GetFds() {
475     std::vector<int> fds;
476     fds.reserve(fd_mapping_.size());
477     for (const auto& [fd, path] : fd_mapping_) {
478       fds.push_back(fd);
479     }
480     return Join(fds, ':');
481   }
482 
483  private:
484   std::vector<std::pair<int, std::string>> fd_mapping_;
485 
486   friend std::ostream& operator<<(std::ostream& os, const FdLogger& fd_logger);
487 };
488 
operator <<(std::ostream & os,const FdLogger & fd_logger)489 std::ostream& operator<<(std::ostream& os, const FdLogger& fd_logger) {
490   for (const auto& [fd, path] : fd_logger.fd_mapping_) {
491     os << fd << ":" << path << ' ';
492   }
493   return os;
494 }
495 
496 }  // namespace
497 
498 #define RETURN_FATAL_IF_PRE_REBOOT(options)                                 \
499   if ((options).is_pre_reboot) {                                            \
500     return Fatal("This method is not supported in Pre-reboot Dexopt mode"); \
501   }
502 
503 #define RETURN_FATAL_IF_NOT_PRE_REBOOT(options)                              \
504   if (!(options).is_pre_reboot) {                                            \
505     return Fatal("This method is only supported in Pre-reboot Dexopt mode"); \
506   }
507 
508 #define RETURN_FATAL_IF_ARG_IS_PRE_REBOOT_IMPL(expected, arg, log_name)                        \
509   {                                                                                            \
510     auto&& __return_fatal_tmp = PreRebootFlag(arg);                                            \
511     if ((expected) != __return_fatal_tmp) {                                                    \
512       return Fatal(ART_FORMAT("Expected flag 'isPreReboot' in argument '{}' to be {}, got {}", \
513                               log_name,                                                        \
514                               expected,                                                        \
515                               __return_fatal_tmp));                                            \
516     }                                                                                          \
517   }
518 
519 #define RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options, arg, log_name) \
520   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT_IMPL((options).is_pre_reboot, arg, log_name)
521 
522 #define RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(arg, log_name) \
523   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT_IMPL(false, arg, log_name)
524 
Restorecon(const std::string & path,const std::optional<OutputArtifacts::PermissionSettings::SeContext> & se_context,bool recurse)525 Result<void> Restorecon(
526     const std::string& path,
527     const std::optional<OutputArtifacts::PermissionSettings::SeContext>& se_context,
528     bool recurse) {
529   if (!kIsTargetAndroid) {
530     return {};
531   }
532 
533   unsigned int flags = recurse ? SELINUX_ANDROID_RESTORECON_RECURSE : 0;
534   int res = 0;
535   if (se_context.has_value()) {
536     res = selinux_android_restorecon_pkgdir(
537         path.c_str(), se_context->seInfo.c_str(), se_context->uid, flags);
538   } else {
539     res = selinux_android_restorecon(path.c_str(), flags);
540   }
541   if (res != 0) {
542     return ErrnoErrorf("Failed to restorecon directory '{}'", path);
543   }
544   return {};
545 }
546 
isAlive(bool * _aidl_return)547 ScopedAStatus Artd::isAlive(bool* _aidl_return) {
548   *_aidl_return = true;
549   return ScopedAStatus::ok();
550 }
551 
deleteArtifacts(const ArtifactsPath & in_artifactsPath,int64_t * _aidl_return)552 ScopedAStatus Artd::deleteArtifacts(const ArtifactsPath& in_artifactsPath, int64_t* _aidl_return) {
553   RETURN_FATAL_IF_PRE_REBOOT(options_);
554   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_artifactsPath, "artifactsPath");
555 
556   RawArtifactsPath path = OR_RETURN_FATAL(BuildArtifactsPath(in_artifactsPath));
557 
558   *_aidl_return = 0;
559   *_aidl_return += GetSizeAndDeleteFile(path.oat_path);
560   *_aidl_return += GetSizeAndDeleteFile(path.vdex_path);
561   *_aidl_return += GetSizeAndDeleteFile(path.art_path);
562 
563   return ScopedAStatus::ok();
564 }
565 
getDexoptStatus(const std::string & in_dexFile,const std::string & in_instructionSet,const std::optional<std::string> & in_classLoaderContext,GetDexoptStatusResult * _aidl_return)566 ScopedAStatus Artd::getDexoptStatus(const std::string& in_dexFile,
567                                     const std::string& in_instructionSet,
568                                     const std::optional<std::string>& in_classLoaderContext,
569                                     GetDexoptStatusResult* _aidl_return) {
570   RETURN_FATAL_IF_PRE_REBOOT(options_);
571 
572   Result<OatFileAssistantContext*> ofa_context = GetOatFileAssistantContext();
573   if (!ofa_context.ok()) {
574     return NonFatal("Failed to get runtime options: " + ofa_context.error().message());
575   }
576 
577   std::unique_ptr<ClassLoaderContext> context;
578   std::string error_msg;
579   auto oat_file_assistant = OatFileAssistant::Create(in_dexFile,
580                                                      in_instructionSet,
581                                                      in_classLoaderContext,
582                                                      /*load_executable=*/false,
583                                                      /*only_load_trusted_executable=*/true,
584                                                      ofa_context.value(),
585                                                      &context,
586                                                      &error_msg);
587   if (oat_file_assistant == nullptr) {
588     return NonFatal("Failed to create OatFileAssistant: " + error_msg);
589   }
590 
591   std::string ignored_odex_status;
592   OatFileAssistant::Location location;
593   oat_file_assistant->GetOptimizationStatus(&_aidl_return->locationDebugString,
594                                             &_aidl_return->compilerFilter,
595                                             &_aidl_return->compilationReason,
596                                             &ignored_odex_status,
597                                             &location);
598   _aidl_return->artifactsLocation = ArtifactsLocationToAidl(location);
599 
600   // We ignore odex_status because it is not meaningful. It can only be either "up-to-date",
601   // "apk-more-recent", or "io-error-no-oat", which means it doesn't give us information in addition
602   // to what we can learn from compiler_filter because compiler_filter will be the actual compiler
603   // filter, "run-from-apk-fallback", and "run-from-apk" in those three cases respectively.
604   DCHECK(ignored_odex_status == "up-to-date" || ignored_odex_status == "apk-more-recent" ||
605          ignored_odex_status == "io-error-no-oat");
606 
607   return ScopedAStatus::ok();
608 }
609 
isProfileUsable(const ProfilePath & in_profile,const std::string & in_dexFile,bool * _aidl_return)610 ndk::ScopedAStatus Artd::isProfileUsable(const ProfilePath& in_profile,
611                                          const std::string& in_dexFile,
612                                          bool* _aidl_return) {
613   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
614 
615   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
616   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
617 
618   FdLogger fd_logger;
619 
620   CmdlineBuilder art_exec_args = OR_RETURN_FATAL(GetArtExecCmdlineBuilder());
621 
622   CmdlineBuilder args;
623   args.Add(OR_RETURN_FATAL(GetProfman()));
624 
625   Result<std::unique_ptr<File>> profile = OpenFileForReading(profile_path);
626   if (!profile.ok()) {
627     if (profile.error().code() == ENOENT) {
628       *_aidl_return = false;
629       return ScopedAStatus::ok();
630     }
631     return NonFatal(
632         ART_FORMAT("Failed to open profile '{}': {}", profile_path, profile.error().message()));
633   }
634   args.Add("--reference-profile-file-fd=%d", profile.value()->Fd());
635   fd_logger.Add(*profile.value());
636 
637   std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(in_dexFile));
638   args.Add("--apk-fd=%d", dex_file->Fd());
639   fd_logger.Add(*dex_file);
640 
641   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
642 
643   LOG(INFO) << "Running profman: " << Join(art_exec_args.Get(), /*separator=*/" ")
644             << "\nOpened FDs: " << fd_logger;
645 
646   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kShortTimeoutSec);
647   if (!result.ok()) {
648     return NonFatal("Failed to run profman: " + result.error().message());
649   }
650 
651   LOG(INFO) << ART_FORMAT("profman returned code {}", result.value());
652 
653   if (result.value() != ProfmanResult::kSkipCompilationSmallDelta &&
654       result.value() != ProfmanResult::kSkipCompilationEmptyProfiles) {
655     return NonFatal(ART_FORMAT("profman returned an unexpected code: {}", result.value()));
656   }
657 
658   *_aidl_return = result.value() == ProfmanResult::kSkipCompilationSmallDelta;
659   return ScopedAStatus::ok();
660 }
661 
CopyAndRewriteProfileImpl(File src,OutputProfile * dst_aidl,const std::string & dex_path,CopyAndRewriteProfileResult * aidl_return)662 ndk::ScopedAStatus Artd::CopyAndRewriteProfileImpl(File src,
663                                                    OutputProfile* dst_aidl,
664                                                    const std::string& dex_path,
665                                                    CopyAndRewriteProfileResult* aidl_return) {
666   RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, *dst_aidl, "dst");
667   std::string dst_path = OR_RETURN_FATAL(BuildFinalProfilePath(dst_aidl->profilePath));
668   OR_RETURN_FATAL(ValidateDexPath(dex_path));
669 
670   FdLogger fd_logger;
671 
672   CmdlineBuilder art_exec_args = OR_RETURN_FATAL(GetArtExecCmdlineBuilder());
673 
674   CmdlineBuilder args;
675   args.Add(OR_RETURN_FATAL(GetProfman())).Add("--copy-and-update-profile-key");
676 
677   args.Add("--profile-file-fd=%d", src.Fd());
678   fd_logger.Add(src);
679 
680   std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(dex_path));
681   args.Add("--apk-fd=%d", dex_file->Fd());
682   fd_logger.Add(*dex_file);
683 
684   std::unique_ptr<NewFile> dst =
685       OR_RETURN_NON_FATAL(NewFile::Create(dst_path, dst_aidl->fsPermission));
686   args.Add("--reference-profile-file-fd=%d", dst->Fd());
687   fd_logger.Add(*dst);
688 
689   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
690 
691   LOG(INFO) << "Running profman: " << Join(art_exec_args.Get(), /*separator=*/" ")
692             << "\nOpened FDs: " << fd_logger;
693 
694   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kShortTimeoutSec);
695   if (!result.ok()) {
696     return NonFatal("Failed to run profman: " + result.error().message());
697   }
698 
699   LOG(INFO) << ART_FORMAT("profman returned code {}", result.value());
700 
701   if (result.value() == ProfmanResult::kCopyAndUpdateNoMatch ||
702       result.value() == ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile) {
703     *aidl_return = AnalyzeCopyAndRewriteProfileFailure(
704         &src, static_cast<ProfmanResult::CopyAndUpdateResult>(result.value()));
705     return ScopedAStatus::ok();
706   }
707 
708   if (result.value() != ProfmanResult::kCopyAndUpdateSuccess) {
709     return NonFatal(ART_FORMAT("profman returned an unexpected code: {}", result.value()));
710   }
711 
712   OR_RETURN_NON_FATAL(dst->Keep());
713   aidl_return->status = CopyAndRewriteProfileResult::Status::SUCCESS;
714   dst_aidl->profilePath.id = dst->TempId();
715   dst_aidl->profilePath.tmpPath = dst->TempPath();
716   return ScopedAStatus::ok();
717 }
718 
copyAndRewriteProfile(const ProfilePath & in_src,OutputProfile * in_dst,const std::string & in_dexFile,CopyAndRewriteProfileResult * _aidl_return)719 ndk::ScopedAStatus Artd::copyAndRewriteProfile(const ProfilePath& in_src,
720                                                OutputProfile* in_dst,
721                                                const std::string& in_dexFile,
722                                                CopyAndRewriteProfileResult* _aidl_return) {
723   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_src, "src");
724 
725   std::string src_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_src));
726 
727   Result<std::unique_ptr<File>> src = OpenFileForReading(src_path);
728   if (!src.ok()) {
729     if (src.error().code() == ENOENT) {
730       _aidl_return->status = CopyAndRewriteProfileResult::Status::NO_PROFILE;
731       return ScopedAStatus::ok();
732     }
733     return NonFatal(
734         ART_FORMAT("Failed to open src profile '{}': {}", src_path, src.error().message()));
735   }
736 
737   return CopyAndRewriteProfileImpl(std::move(*src.value()), in_dst, in_dexFile, _aidl_return);
738 }
739 
copyAndRewriteEmbeddedProfile(OutputProfile * in_dst,const std::string & in_dexFile,CopyAndRewriteProfileResult * _aidl_return)740 ndk::ScopedAStatus Artd::copyAndRewriteEmbeddedProfile(OutputProfile* in_dst,
741                                                        const std::string& in_dexFile,
742                                                        CopyAndRewriteProfileResult* _aidl_return) {
743   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
744 
745   Result<File> src = ExtractEmbeddedProfileToFd(in_dexFile);
746   if (!src.ok()) {
747     return NonFatal(ART_FORMAT(
748         "Failed to extract profile from dex file '{}': {}", in_dexFile, src.error().message()));
749   }
750   if (!src->IsValid()) {
751     _aidl_return->status = CopyAndRewriteProfileResult::Status::NO_PROFILE;
752     return ScopedAStatus::ok();
753   }
754 
755   return CopyAndRewriteProfileImpl(std::move(src.value()), in_dst, in_dexFile, _aidl_return);
756 }
757 
commitTmpProfile(const TmpProfilePath & in_profile)758 ndk::ScopedAStatus Artd::commitTmpProfile(const TmpProfilePath& in_profile) {
759   RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, in_profile, "profile");
760   std::string tmp_profile_path = OR_RETURN_FATAL(BuildTmpProfilePath(in_profile));
761   std::string ref_profile_path = OR_RETURN_FATAL(BuildFinalProfilePath(in_profile));
762 
763   std::error_code ec;
764   std::filesystem::rename(tmp_profile_path, ref_profile_path, ec);
765   if (ec) {
766     return NonFatal(ART_FORMAT(
767         "Failed to move '{}' to '{}': {}", tmp_profile_path, ref_profile_path, ec.message()));
768   }
769 
770   return ScopedAStatus::ok();
771 }
772 
deleteProfile(const ProfilePath & in_profile)773 ndk::ScopedAStatus Artd::deleteProfile(const ProfilePath& in_profile) {
774   // `in_profile` can be either a Pre-reboot path or an ordinary one.
775   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
776   DeleteFile(profile_path);
777 
778   return ScopedAStatus::ok();
779 }
780 
getProfileVisibility(const ProfilePath & in_profile,FileVisibility * _aidl_return)781 ndk::ScopedAStatus Artd::getProfileVisibility(const ProfilePath& in_profile,
782                                               FileVisibility* _aidl_return) {
783   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
784   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
785   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(profile_path));
786   return ScopedAStatus::ok();
787 }
788 
getArtifactsVisibility(const ArtifactsPath & in_artifactsPath,FileVisibility * _aidl_return)789 ndk::ScopedAStatus Artd::getArtifactsVisibility(const ArtifactsPath& in_artifactsPath,
790                                                 FileVisibility* _aidl_return) {
791   // `in_artifactsPath` can be either a Pre-reboot path or an ordinary one.
792   std::string oat_path = OR_RETURN_FATAL(BuildArtifactsPath(in_artifactsPath)).oat_path;
793   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(oat_path));
794   return ScopedAStatus::ok();
795 }
796 
getDexFileVisibility(const std::string & in_dexFile,FileVisibility * _aidl_return)797 ndk::ScopedAStatus Artd::getDexFileVisibility(const std::string& in_dexFile,
798                                               FileVisibility* _aidl_return) {
799   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
800   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(in_dexFile));
801   return ScopedAStatus::ok();
802 }
803 
getDmFileVisibility(const DexMetadataPath & in_dmFile,FileVisibility * _aidl_return)804 ndk::ScopedAStatus Artd::getDmFileVisibility(const DexMetadataPath& in_dmFile,
805                                              FileVisibility* _aidl_return) {
806   std::string dm_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_dmFile));
807   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(dm_path));
808   return ScopedAStatus::ok();
809 }
810 
mergeProfiles(const std::vector<ProfilePath> & in_profiles,const std::optional<ProfilePath> & in_referenceProfile,OutputProfile * in_outputProfile,const std::vector<std::string> & in_dexFiles,const MergeProfileOptions & in_options,bool * _aidl_return)811 ndk::ScopedAStatus Artd::mergeProfiles(const std::vector<ProfilePath>& in_profiles,
812                                        const std::optional<ProfilePath>& in_referenceProfile,
813                                        OutputProfile* in_outputProfile,
814                                        const std::vector<std::string>& in_dexFiles,
815                                        const MergeProfileOptions& in_options,
816                                        bool* _aidl_return) {
817   std::vector<std::string> profile_paths;
818   for (const ProfilePath& profile : in_profiles) {
819     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(profile, "profiles");
820     std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(profile));
821     if (profile.getTag() == ProfilePath::dexMetadataPath) {
822       return Fatal(ART_FORMAT("Does not support DM file, got '{}'", profile_path));
823     }
824     profile_paths.push_back(std::move(profile_path));
825   }
826 
827   RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, *in_outputProfile, "outputProfile");
828   std::string output_profile_path =
829       OR_RETURN_FATAL(BuildFinalProfilePath(in_outputProfile->profilePath));
830   for (const std::string& dex_file : in_dexFiles) {
831     OR_RETURN_FATAL(ValidateDexPath(dex_file));
832   }
833   if (in_options.forceMerge + in_options.dumpOnly + in_options.dumpClassesAndMethods > 1) {
834     return Fatal("Only one of 'forceMerge', 'dumpOnly', and 'dumpClassesAndMethods' can be set");
835   }
836 
837   FdLogger fd_logger;
838 
839   CmdlineBuilder art_exec_args = OR_RETURN_FATAL(GetArtExecCmdlineBuilder());
840 
841   CmdlineBuilder args;
842   args.Add(OR_RETURN_FATAL(GetProfman()));
843 
844   std::vector<std::unique_ptr<File>> profile_files;
845   for (const std::string& profile_path : profile_paths) {
846     Result<std::unique_ptr<File>> profile_file = OpenFileForReading(profile_path);
847     if (!profile_file.ok()) {
848       if (profile_file.error().code() == ENOENT) {
849         // Skip non-existing file.
850         continue;
851       }
852       return NonFatal(ART_FORMAT(
853           "Failed to open profile '{}': {}", profile_path, profile_file.error().message()));
854     }
855     args.Add("--profile-file-fd=%d", profile_file.value()->Fd());
856     fd_logger.Add(*profile_file.value());
857     profile_files.push_back(std::move(profile_file.value()));
858   }
859 
860   if (profile_files.empty()) {
861     LOG(INFO) << "Merge skipped because there are no existing profiles";
862     *_aidl_return = false;
863     return ScopedAStatus::ok();
864   }
865 
866   std::unique_ptr<NewFile> output_profile_file =
867       OR_RETURN_NON_FATAL(NewFile::Create(output_profile_path, in_outputProfile->fsPermission));
868 
869   if (in_referenceProfile.has_value()) {
870     if (in_options.dumpOnly || in_options.dumpClassesAndMethods) {
871       return Fatal(
872           "Reference profile must not be set when 'dumpOnly' or 'dumpClassesAndMethods' is set");
873     }
874     // `in_referenceProfile` can be either a Pre-reboot profile or an ordinary one.
875     std::string reference_profile_path =
876         OR_RETURN_FATAL(BuildProfileOrDmPath(*in_referenceProfile));
877     if (in_referenceProfile->getTag() == ProfilePath::dexMetadataPath) {
878       return Fatal(ART_FORMAT("Does not support DM file, got '{}'", reference_profile_path));
879     }
880     OR_RETURN_NON_FATAL(CopyFile(reference_profile_path, *output_profile_file));
881   }
882 
883   if (in_options.dumpOnly || in_options.dumpClassesAndMethods) {
884     args.Add("--dump-output-to-fd=%d", output_profile_file->Fd());
885   } else {
886     // profman is ok with this being an empty file when in_referenceProfile isn't set.
887     args.Add("--reference-profile-file-fd=%d", output_profile_file->Fd());
888   }
889   fd_logger.Add(*output_profile_file);
890 
891   std::vector<std::unique_ptr<File>> dex_files;
892   for (const std::string& dex_path : in_dexFiles) {
893     std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(dex_path));
894     args.Add("--apk-fd=%d", dex_file->Fd());
895     fd_logger.Add(*dex_file);
896     dex_files.push_back(std::move(dex_file));
897   }
898 
899   if (in_options.dumpOnly || in_options.dumpClassesAndMethods) {
900     args.Add(in_options.dumpOnly ? "--dump-only" : "--dump-classes-and-methods");
901   } else {
902     args.AddIfNonEmpty("--min-new-classes-percent-change=%s",
903                        props_->GetOrEmpty("dalvik.vm.bgdexopt.new-classes-percent"))
904         .AddIfNonEmpty("--min-new-methods-percent-change=%s",
905                        props_->GetOrEmpty("dalvik.vm.bgdexopt.new-methods-percent"))
906         .AddIf(in_options.forceMerge, "--force-merge-and-analyze")
907         .AddIf(in_options.forBootImage, "--boot-image-merge");
908   }
909 
910   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
911 
912   LOG(INFO) << "Running profman: " << Join(art_exec_args.Get(), /*separator=*/" ")
913             << "\nOpened FDs: " << fd_logger;
914 
915   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kShortTimeoutSec);
916   if (!result.ok()) {
917     return NonFatal("Failed to run profman: " + result.error().message());
918   }
919 
920   LOG(INFO) << ART_FORMAT("profman returned code {}", result.value());
921 
922   if (result.value() == ProfmanResult::kSkipCompilationSmallDelta ||
923       result.value() == ProfmanResult::kSkipCompilationEmptyProfiles) {
924     *_aidl_return = false;
925     return ScopedAStatus::ok();
926   }
927 
928   ProfmanResult::ProcessingResult expected_result =
929       (in_options.dumpOnly || in_options.dumpClassesAndMethods) ? ProfmanResult::kSuccess :
930                                                                   ProfmanResult::kCompile;
931   if (result.value() != expected_result) {
932     return NonFatal(ART_FORMAT("profman returned an unexpected code: {}", result.value()));
933   }
934 
935   OR_RETURN_NON_FATAL(output_profile_file->Keep());
936   *_aidl_return = true;
937   in_outputProfile->profilePath.id = output_profile_file->TempId();
938   in_outputProfile->profilePath.tmpPath = output_profile_file->TempPath();
939   return ScopedAStatus::ok();
940 }
941 
getDexoptNeeded(const std::string & in_dexFile,const std::string & in_instructionSet,const std::optional<std::string> & in_classLoaderContext,const std::string & in_compilerFilter,int32_t in_dexoptTrigger,GetDexoptNeededResult * _aidl_return)942 ndk::ScopedAStatus Artd::getDexoptNeeded(const std::string& in_dexFile,
943                                          const std::string& in_instructionSet,
944                                          const std::optional<std::string>& in_classLoaderContext,
945                                          const std::string& in_compilerFilter,
946                                          int32_t in_dexoptTrigger,
947                                          GetDexoptNeededResult* _aidl_return) {
948   Result<OatFileAssistantContext*> ofa_context = GetOatFileAssistantContext();
949   if (!ofa_context.ok()) {
950     return NonFatal("Failed to get runtime options: " + ofa_context.error().message());
951   }
952 
953   std::unique_ptr<ClassLoaderContext> context;
954   std::string error_msg;
955   auto oat_file_assistant = OatFileAssistant::Create(in_dexFile,
956                                                      in_instructionSet,
957                                                      in_classLoaderContext,
958                                                      /*load_executable=*/false,
959                                                      /*only_load_trusted_executable=*/true,
960                                                      ofa_context.value(),
961                                                      &context,
962                                                      &error_msg);
963   if (oat_file_assistant == nullptr) {
964     return NonFatal("Failed to create OatFileAssistant: " + error_msg);
965   }
966 
967   OatFileAssistant::DexOptStatus status;
968   _aidl_return->isDexoptNeeded =
969       oat_file_assistant->GetDexOptNeeded(OR_RETURN_FATAL(ParseCompilerFilter(in_compilerFilter)),
970                                           DexOptTriggerFromAidl(in_dexoptTrigger),
971                                           &status);
972   _aidl_return->isVdexUsable = status.IsVdexUsable();
973   _aidl_return->artifactsLocation = ArtifactsLocationToAidl(status.GetLocation());
974 
975   std::optional<bool> has_dex_files = oat_file_assistant->HasDexFiles(&error_msg);
976   if (!has_dex_files.has_value()) {
977     return NonFatal("Failed to open dex file: " + error_msg);
978   }
979   _aidl_return->hasDexCode = *has_dex_files;
980 
981   return ScopedAStatus::ok();
982 }
983 
dexopt(const OutputArtifacts & in_outputArtifacts,const std::string & in_dexFile,const std::string & in_instructionSet,const std::optional<std::string> & in_classLoaderContext,const std::string & in_compilerFilter,const std::optional<ProfilePath> & in_profile,const std::optional<VdexPath> & in_inputVdex,const std::optional<DexMetadataPath> & in_dmFile,PriorityClass in_priorityClass,const DexoptOptions & in_dexoptOptions,const std::shared_ptr<IArtdCancellationSignal> & in_cancellationSignal,ArtdDexoptResult * _aidl_return)984 ndk::ScopedAStatus Artd::dexopt(
985     const OutputArtifacts& in_outputArtifacts,
986     const std::string& in_dexFile,
987     const std::string& in_instructionSet,
988     const std::optional<std::string>& in_classLoaderContext,
989     const std::string& in_compilerFilter,
990     const std::optional<ProfilePath>& in_profile,
991     const std::optional<VdexPath>& in_inputVdex,
992     const std::optional<DexMetadataPath>& in_dmFile,
993     PriorityClass in_priorityClass,
994     const DexoptOptions& in_dexoptOptions,
995     const std::shared_ptr<IArtdCancellationSignal>& in_cancellationSignal,
996     ArtdDexoptResult* _aidl_return) {
997   _aidl_return->cancelled = false;
998 
999   RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, in_outputArtifacts, "outputArtifacts");
1000   RawArtifactsPath artifacts_path =
1001       OR_RETURN_FATAL(BuildArtifactsPath(in_outputArtifacts.artifactsPath));
1002   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
1003   // `in_profile` can be either a Pre-reboot profile or an ordinary one.
1004   std::optional<std::string> profile_path =
1005       in_profile.has_value() ?
1006           std::make_optional(OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile.value()))) :
1007           std::nullopt;
1008   ArtdCancellationSignal* cancellation_signal =
1009       OR_RETURN_FATAL(ToArtdCancellationSignal(in_cancellationSignal.get()));
1010 
1011   std::unique_ptr<ClassLoaderContext> context = nullptr;
1012   if (in_classLoaderContext.has_value()) {
1013     context = ClassLoaderContext::Create(in_classLoaderContext.value());
1014     if (context == nullptr) {
1015       return Fatal(
1016           ART_FORMAT("Class loader context '{}' is invalid", in_classLoaderContext.value()));
1017     }
1018   }
1019 
1020   std::string oat_dir_path;  // For restorecon, can be empty if the artifacts are in dalvik-cache.
1021   OR_RETURN_NON_FATAL(PrepareArtifactsDirs(in_outputArtifacts, &oat_dir_path));
1022 
1023   // First-round restorecon. artd doesn't have the permission to create files with the
1024   // `apk_data_file` label, so we need to restorecon the "oat" directory first so that files will
1025   // inherit `dalvikcache_data_file` rather than `apk_data_file`.
1026   if (!in_outputArtifacts.artifactsPath.isInDalvikCache) {
1027     OR_RETURN_NON_FATAL(restorecon_(
1028         oat_dir_path, in_outputArtifacts.permissionSettings.seContext, /*recurse=*/true));
1029   }
1030 
1031   FdLogger fd_logger;
1032 
1033   CmdlineBuilder art_exec_args = OR_RETURN_FATAL(GetArtExecCmdlineBuilder());
1034 
1035   CmdlineBuilder args;
1036   args.Add(OR_RETURN_FATAL(GetDex2Oat()));
1037 
1038   const FsPermission& fs_permission = in_outputArtifacts.permissionSettings.fileFsPermission;
1039 
1040   std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(in_dexFile));
1041   args.Add("--zip-fd=%d", dex_file->Fd()).Add("--zip-location=%s", in_dexFile);
1042   fd_logger.Add(*dex_file);
1043   struct stat dex_st = OR_RETURN_NON_FATAL(Fstat(*dex_file));
1044   if ((dex_st.st_mode & S_IROTH) == 0) {
1045     if (fs_permission.isOtherReadable) {
1046       return NonFatal(ART_FORMAT(
1047           "Outputs cannot be other-readable because the dex file '{}' is not other-readable",
1048           dex_file->GetPath()));
1049     }
1050     // Negative numbers mean no `chown`. 0 means root.
1051     // Note: this check is more strict than it needs to be. For example, it doesn't allow the
1052     // outputs to belong to a group that is a subset of the dex file's group. This is for
1053     // simplicity, and it's okay as we don't have to handle such complicated cases in practice.
1054     if ((fs_permission.uid > 0 && static_cast<uid_t>(fs_permission.uid) != dex_st.st_uid) ||
1055         (fs_permission.gid > 0 && static_cast<gid_t>(fs_permission.gid) != dex_st.st_uid &&
1056          static_cast<gid_t>(fs_permission.gid) != dex_st.st_gid)) {
1057       return NonFatal(ART_FORMAT(
1058           "Outputs' owner doesn't match the dex file '{}' (outputs: {}:{}, dex file: {}:{})",
1059           dex_file->GetPath(),
1060           fs_permission.uid,
1061           fs_permission.gid,
1062           dex_st.st_uid,
1063           dex_st.st_gid));
1064     }
1065   }
1066 
1067   std::unique_ptr<NewFile> oat_file =
1068       OR_RETURN_NON_FATAL(NewFile::Create(artifacts_path.oat_path, fs_permission));
1069   args.Add("--oat-fd=%d", oat_file->Fd()).Add("--oat-location=%s", artifacts_path.oat_path);
1070   fd_logger.Add(*oat_file);
1071 
1072   std::unique_ptr<NewFile> vdex_file =
1073       OR_RETURN_NON_FATAL(NewFile::Create(artifacts_path.vdex_path, fs_permission));
1074   args.Add("--output-vdex-fd=%d", vdex_file->Fd());
1075   fd_logger.Add(*vdex_file);
1076 
1077   std::vector<NewFile*> files_to_commit{oat_file.get(), vdex_file.get()};
1078   std::vector<std::string_view> files_to_delete;
1079 
1080   std::unique_ptr<NewFile> art_file = nullptr;
1081   if (in_dexoptOptions.generateAppImage) {
1082     art_file = OR_RETURN_NON_FATAL(NewFile::Create(artifacts_path.art_path, fs_permission));
1083     args.Add("--app-image-fd=%d", art_file->Fd());
1084     args.AddIfNonEmpty("--image-format=%s", props_->GetOrEmpty("dalvik.vm.appimageformat"));
1085     fd_logger.Add(*art_file);
1086     files_to_commit.push_back(art_file.get());
1087   } else {
1088     files_to_delete.push_back(artifacts_path.art_path);
1089   }
1090 
1091   std::unique_ptr<NewFile> swap_file = nullptr;
1092   if (ShouldCreateSwapFileForDexopt()) {
1093     std::string swap_file_path = ART_FORMAT("{}.swap", artifacts_path.oat_path);
1094     swap_file =
1095         OR_RETURN_NON_FATAL(NewFile::Create(swap_file_path, FsPermission{.uid = -1, .gid = -1}));
1096     args.Add("--swap-fd=%d", swap_file->Fd());
1097     fd_logger.Add(*swap_file);
1098   }
1099 
1100   std::vector<std::unique_ptr<File>> context_files;
1101   if (context != nullptr) {
1102     std::vector<std::string> flattened_context = context->FlattenDexPaths();
1103     std::string dex_dir = Dirname(in_dexFile);
1104     std::vector<int> context_fds;
1105     for (const std::string& context_element : flattened_context) {
1106       std::string context_path = std::filesystem::path(dex_dir).append(context_element);
1107       OR_RETURN_FATAL(ValidateDexPath(context_path));
1108       std::unique_ptr<File> context_file = OR_RETURN_NON_FATAL(OpenFileForReading(context_path));
1109       context_fds.push_back(context_file->Fd());
1110       fd_logger.Add(*context_file);
1111       context_files.push_back(std::move(context_file));
1112     }
1113     args.AddIfNonEmpty("--class-loader-context-fds=%s", Join(context_fds, /*separator=*/':'))
1114         .Add("--class-loader-context=%s", in_classLoaderContext.value())
1115         .Add("--classpath-dir=%s", dex_dir);
1116   }
1117 
1118   std::unique_ptr<File> input_vdex_file = nullptr;
1119   if (in_inputVdex.has_value()) {
1120     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_inputVdex.value(), "inputVdex");
1121     std::string input_vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_inputVdex.value()));
1122     input_vdex_file = OR_RETURN_NON_FATAL(OpenFileForReading(input_vdex_path));
1123     args.Add("--input-vdex-fd=%d", input_vdex_file->Fd());
1124     fd_logger.Add(*input_vdex_file);
1125   }
1126 
1127   std::unique_ptr<File> dm_file = nullptr;
1128   if (in_dmFile.has_value()) {
1129     std::string dm_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_dmFile.value()));
1130     dm_file = OR_RETURN_NON_FATAL(OpenFileForReading(dm_path));
1131     args.Add("--dm-fd=%d", dm_file->Fd());
1132     fd_logger.Add(*dm_file);
1133   }
1134 
1135   std::unique_ptr<File> profile_file = nullptr;
1136   if (profile_path.has_value()) {
1137     profile_file = OR_RETURN_NON_FATAL(OpenFileForReading(profile_path.value()));
1138     args.Add("--profile-file-fd=%d", profile_file->Fd());
1139     fd_logger.Add(*profile_file);
1140     struct stat profile_st = OR_RETURN_NON_FATAL(Fstat(*profile_file));
1141     if (fs_permission.isOtherReadable && (profile_st.st_mode & S_IROTH) == 0) {
1142       return NonFatal(ART_FORMAT(
1143           "Outputs cannot be other-readable because the profile '{}' is not other-readable",
1144           profile_file->GetPath()));
1145     }
1146     // TODO(b/260228411): Check uid and gid.
1147   }
1148 
1149   // Second-round restorecon. Restorecon recursively after the output files are created, so that the
1150   // SELinux context is applied to all of them. The SELinux context of a file is mostly inherited
1151   // from the parent directory upon creation, but the MLS label is not inherited, so we need to
1152   // restorecon every file so that they have the right MLS label. If the files are in dalvik-cache,
1153   // there's no need to restorecon because they inherits the SELinux context of the dalvik-cache
1154   // directory and they don't need to have MLS labels.
1155   if (!in_outputArtifacts.artifactsPath.isInDalvikCache) {
1156     OR_RETURN_NON_FATAL(restorecon_(
1157         oat_dir_path, in_outputArtifacts.permissionSettings.seContext, /*recurse=*/true));
1158   }
1159 
1160   AddBootImageFlags(args);
1161   AddCompilerConfigFlags(
1162       in_instructionSet, in_compilerFilter, in_priorityClass, in_dexoptOptions, args);
1163   AddPerfConfigFlags(in_priorityClass, art_exec_args, args);
1164 
1165   // For being surfaced in crash reports on crashes.
1166   args.Add("--comments=%s", in_dexoptOptions.comments);
1167 
1168   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
1169 
1170   LOG(INFO) << "Running dex2oat: " << Join(art_exec_args.Get(), /*separator=*/" ")
1171             << "\nOpened FDs: " << fd_logger;
1172 
1173   ProcessStat stat;
1174   Result<int> result = ExecAndReturnCode(
1175       art_exec_args.Get(), kLongTimeoutSec, cancellation_signal->CreateExecCallbacks(), &stat);
1176   _aidl_return->wallTimeMs = stat.wall_time_ms;
1177   _aidl_return->cpuTimeMs = stat.cpu_time_ms;
1178   if (!result.ok()) {
1179     if (cancellation_signal->IsCancelled()) {
1180       _aidl_return->cancelled = true;
1181       return ScopedAStatus::ok();
1182     }
1183     return NonFatal("Failed to run dex2oat: " + result.error().message());
1184   }
1185 
1186   LOG(INFO) << ART_FORMAT("dex2oat returned code {}", result.value());
1187 
1188   if (result.value() != 0) {
1189     return NonFatal(ART_FORMAT("dex2oat returned an unexpected code: {}", result.value()));
1190   }
1191 
1192   int64_t size_bytes = 0;
1193   int64_t size_before_bytes = 0;
1194   for (const NewFile* file : files_to_commit) {
1195     size_bytes += GetSize(file->TempPath()).value_or(0);
1196     size_before_bytes += GetSize(file->FinalPath()).value_or(0);
1197   }
1198   for (std::string_view path : files_to_delete) {
1199     size_before_bytes += GetSize(path).value_or(0);
1200   }
1201   OR_RETURN_NON_FATAL(NewFile::CommitAllOrAbandon(files_to_commit, files_to_delete));
1202 
1203   _aidl_return->sizeBytes = size_bytes;
1204   _aidl_return->sizeBeforeBytes = size_before_bytes;
1205   return ScopedAStatus::ok();
1206 }
1207 
cancel()1208 ScopedAStatus ArtdCancellationSignal::cancel() {
1209   std::lock_guard<std::mutex> lock(mu_);
1210   is_cancelled_ = true;
1211   for (pid_t pid : pids_) {
1212     // Kill the whole process group.
1213     int res = kill_(-pid, SIGKILL);
1214     DCHECK_EQ(res, 0);
1215   }
1216   return ScopedAStatus::ok();
1217 }
1218 
getType(int64_t * _aidl_return)1219 ScopedAStatus ArtdCancellationSignal::getType(int64_t* _aidl_return) {
1220   *_aidl_return = reinterpret_cast<intptr_t>(kArtdCancellationSignalType);
1221   return ScopedAStatus::ok();
1222 }
1223 
CreateExecCallbacks()1224 ExecCallbacks ArtdCancellationSignal::CreateExecCallbacks() {
1225   return {
1226       .on_start =
1227           [&](pid_t pid) {
1228             std::lock_guard<std::mutex> lock(mu_);
1229             pids_.insert(pid);
1230             // Handle cancellation signals sent before the process starts.
1231             if (is_cancelled_) {
1232               int res = kill_(-pid, SIGKILL);
1233               DCHECK_EQ(res, 0);
1234             }
1235           },
1236       .on_end =
1237           [&](pid_t pid) {
1238             std::lock_guard<std::mutex> lock(mu_);
1239             // The pid should no longer receive kill signals sent by `cancellation_signal`.
1240             pids_.erase(pid);
1241           },
1242   };
1243 }
1244 
IsCancelled()1245 bool ArtdCancellationSignal::IsCancelled() {
1246   std::lock_guard<std::mutex> lock(mu_);
1247   return is_cancelled_;
1248 }
1249 
createCancellationSignal(std::shared_ptr<IArtdCancellationSignal> * _aidl_return)1250 ScopedAStatus Artd::createCancellationSignal(
1251     std::shared_ptr<IArtdCancellationSignal>* _aidl_return) {
1252   *_aidl_return = ndk::SharedRefBase::make<ArtdCancellationSignal>(kill_);
1253   return ScopedAStatus::ok();
1254 }
1255 
cleanup(const std::vector<ProfilePath> & in_profilesToKeep,const std::vector<ArtifactsPath> & in_artifactsToKeep,const std::vector<VdexPath> & in_vdexFilesToKeep,const std::vector<RuntimeArtifactsPath> & in_runtimeArtifactsToKeep,bool in_keepPreRebootStagedFiles,int64_t * _aidl_return)1256 ScopedAStatus Artd::cleanup(const std::vector<ProfilePath>& in_profilesToKeep,
1257                             const std::vector<ArtifactsPath>& in_artifactsToKeep,
1258                             const std::vector<VdexPath>& in_vdexFilesToKeep,
1259                             const std::vector<RuntimeArtifactsPath>& in_runtimeArtifactsToKeep,
1260                             bool in_keepPreRebootStagedFiles,
1261                             int64_t* _aidl_return) {
1262   RETURN_FATAL_IF_PRE_REBOOT(options_);
1263   std::unordered_set<std::string> files_to_keep;
1264   for (const ProfilePath& profile : in_profilesToKeep) {
1265     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(profile, "profilesToKeep");
1266     files_to_keep.insert(OR_RETURN_FATAL(BuildProfileOrDmPath(profile)));
1267   }
1268   for (const ArtifactsPath& artifacts : in_artifactsToKeep) {
1269     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(artifacts, "artifactsToKeep");
1270     RawArtifactsPath path = OR_RETURN_FATAL(BuildArtifactsPath(artifacts));
1271     files_to_keep.insert(std::move(path.oat_path));
1272     files_to_keep.insert(std::move(path.vdex_path));
1273     files_to_keep.insert(std::move(path.art_path));
1274   }
1275   for (const VdexPath& vdex : in_vdexFilesToKeep) {
1276     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(vdex, "vdexFilesToKeep");
1277     files_to_keep.insert(OR_RETURN_FATAL(BuildVdexPath(vdex)));
1278   }
1279   std::string android_data = OR_RETURN_NON_FATAL(GetAndroidDataOrError());
1280   std::string android_expand = OR_RETURN_NON_FATAL(GetAndroidExpandOrError());
1281   for (const RuntimeArtifactsPath& runtime_image_path : in_runtimeArtifactsToKeep) {
1282     OR_RETURN_FATAL(ValidateRuntimeArtifactsPath(runtime_image_path));
1283     std::vector<std::string> files =
1284         ListRuntimeArtifactsFiles(android_data, android_expand, runtime_image_path);
1285     std::move(files.begin(), files.end(), std::inserter(files_to_keep, files_to_keep.end()));
1286   }
1287   *_aidl_return = 0;
1288   for (const std::string& file : ListManagedFiles(android_data, android_expand)) {
1289     if (files_to_keep.find(file) == files_to_keep.end() &&
1290         (!in_keepPreRebootStagedFiles || !IsPreRebootStagedFile(file))) {
1291       LOG(INFO) << ART_FORMAT("Cleaning up obsolete file '{}'", file);
1292       *_aidl_return += GetSizeAndDeleteFile(file);
1293     }
1294   }
1295   return ScopedAStatus::ok();
1296 }
1297 
cleanUpPreRebootStagedFiles()1298 ScopedAStatus Artd::cleanUpPreRebootStagedFiles() {
1299   RETURN_FATAL_IF_PRE_REBOOT(options_);
1300   std::string android_data = OR_RETURN_NON_FATAL(GetAndroidDataOrError());
1301   std::string android_expand = OR_RETURN_NON_FATAL(GetAndroidExpandOrError());
1302   for (const std::string& file : ListManagedFiles(android_data, android_expand)) {
1303     if (IsPreRebootStagedFile(file)) {
1304       LOG(INFO) << ART_FORMAT("Cleaning up obsolete Pre-reboot staged file '{}'", file);
1305       DeleteFile(file);
1306     }
1307   }
1308   return ScopedAStatus::ok();
1309 }
1310 
isInDalvikCache(const std::string & in_dexFile,bool * _aidl_return)1311 ScopedAStatus Artd::isInDalvikCache(const std::string& in_dexFile, bool* _aidl_return) {
1312   // The artifacts should be in the global dalvik-cache directory if:
1313   // (1). the dex file is on a system partition, even if the partition is remounted read-write,
1314   //      or
1315   // (2). the dex file is in any other readonly location. (At the time of writing, this only
1316   //      include Incremental FS.)
1317   //
1318   // We cannot rely on access(2) because:
1319   // - It doesn't take effective capabilities into account, from which artd gets root access
1320   //   to the filesystem.
1321   // - The `faccessat` variant with the `AT_EACCESS` flag, which takes effective capabilities
1322   //   into account, is not supported by bionic.
1323 
1324   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
1325 
1326   std::vector<FstabEntry> entries = OR_RETURN_NON_FATAL(GetProcMountsAncestorsOfPath(in_dexFile));
1327   // The last one controls because `/proc/mounts` reflects the sequence of `mount`.
1328   for (auto it = entries.rbegin(); it != entries.rend(); it++) {
1329     if (it->fs_type == "overlay") {
1330       // Ignore the overlays created by `remount`.
1331       continue;
1332     }
1333     // We need to special-case Incremental FS since it is tagged as read-write while it's actually
1334     // not.
1335     *_aidl_return = (it->flags & MS_RDONLY) != 0 || it->fs_type == "incremental-fs";
1336     return ScopedAStatus::ok();
1337   }
1338 
1339   return NonFatal(ART_FORMAT("Fstab entries not found for '{}'", in_dexFile));
1340 }
1341 
deleteRuntimeArtifacts(const RuntimeArtifactsPath & in_runtimeArtifactsPath,int64_t * _aidl_return)1342 ScopedAStatus Artd::deleteRuntimeArtifacts(const RuntimeArtifactsPath& in_runtimeArtifactsPath,
1343                                            int64_t* _aidl_return) {
1344   RETURN_FATAL_IF_PRE_REBOOT(options_);
1345   OR_RETURN_FATAL(ValidateRuntimeArtifactsPath(in_runtimeArtifactsPath));
1346   *_aidl_return = 0;
1347   std::string android_data = OR_LOG_AND_RETURN_OK(GetAndroidDataOrError());
1348   std::string android_expand = OR_LOG_AND_RETURN_OK(GetAndroidExpandOrError());
1349   for (const std::string& file :
1350        ListRuntimeArtifactsFiles(android_data, android_expand, in_runtimeArtifactsPath)) {
1351     *_aidl_return += GetSizeAndDeleteFile(file);
1352   }
1353   return ScopedAStatus::ok();
1354 }
1355 
getArtifactsSize(const ArtifactsPath & in_artifactsPath,int64_t * _aidl_return)1356 ScopedAStatus Artd::getArtifactsSize(const ArtifactsPath& in_artifactsPath, int64_t* _aidl_return) {
1357   RETURN_FATAL_IF_PRE_REBOOT(options_);
1358   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_artifactsPath, "artifactsPath");
1359   RawArtifactsPath path = OR_RETURN_FATAL(BuildArtifactsPath(in_artifactsPath));
1360   *_aidl_return = 0;
1361   *_aidl_return += GetSize(path.oat_path).value_or(0);
1362   *_aidl_return += GetSize(path.vdex_path).value_or(0);
1363   *_aidl_return += GetSize(path.art_path).value_or(0);
1364   return ScopedAStatus::ok();
1365 }
1366 
getVdexFileSize(const VdexPath & in_vdexPath,int64_t * _aidl_return)1367 ScopedAStatus Artd::getVdexFileSize(const VdexPath& in_vdexPath, int64_t* _aidl_return) {
1368   RETURN_FATAL_IF_PRE_REBOOT(options_);
1369   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_vdexPath, "vdexPath");
1370   std::string vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_vdexPath));
1371   *_aidl_return = GetSize(vdex_path).value_or(0);
1372   return ScopedAStatus::ok();
1373 }
1374 
getRuntimeArtifactsSize(const RuntimeArtifactsPath & in_runtimeArtifactsPath,int64_t * _aidl_return)1375 ScopedAStatus Artd::getRuntimeArtifactsSize(const RuntimeArtifactsPath& in_runtimeArtifactsPath,
1376                                             int64_t* _aidl_return) {
1377   RETURN_FATAL_IF_PRE_REBOOT(options_);
1378   OR_RETURN_FATAL(ValidateRuntimeArtifactsPath(in_runtimeArtifactsPath));
1379   *_aidl_return = 0;
1380   std::string android_data = OR_LOG_AND_RETURN_OK(GetAndroidDataOrError());
1381   std::string android_expand = OR_LOG_AND_RETURN_OK(GetAndroidExpandOrError());
1382   for (const std::string& file :
1383        ListRuntimeArtifactsFiles(android_data, android_expand, in_runtimeArtifactsPath)) {
1384     *_aidl_return += GetSize(file).value_or(0);
1385   }
1386   return ScopedAStatus::ok();
1387 }
1388 
getProfileSize(const ProfilePath & in_profile,int64_t * _aidl_return)1389 ScopedAStatus Artd::getProfileSize(const ProfilePath& in_profile, int64_t* _aidl_return) {
1390   RETURN_FATAL_IF_PRE_REBOOT(options_);
1391   RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
1392   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
1393   *_aidl_return = GetSize(profile_path).value_or(0);
1394   return ScopedAStatus::ok();
1395 }
1396 
commitPreRebootStagedFiles(const std::vector<ArtifactsPath> & in_artifacts,const std::vector<WritableProfilePath> & in_profiles,bool * _aidl_return)1397 ScopedAStatus Artd::commitPreRebootStagedFiles(const std::vector<ArtifactsPath>& in_artifacts,
1398                                                const std::vector<WritableProfilePath>& in_profiles,
1399                                                bool* _aidl_return) {
1400   RETURN_FATAL_IF_PRE_REBOOT(options_);
1401 
1402   std::vector<std::pair<std::string, std::string>> files_to_move;
1403   std::vector<std::string> files_to_remove;
1404 
1405   for (const ArtifactsPath& artifacts : in_artifacts) {
1406     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(artifacts, "artifacts");
1407 
1408     ArtifactsPath pre_reboot_artifacts = artifacts;
1409     pre_reboot_artifacts.isPreReboot = true;
1410 
1411     auto src_artifacts = std::make_unique<RawArtifactsPath>(
1412         OR_RETURN_FATAL(BuildArtifactsPath(pre_reboot_artifacts)));
1413     auto dst_artifacts =
1414         std::make_unique<RawArtifactsPath>(OR_RETURN_FATAL(BuildArtifactsPath(artifacts)));
1415 
1416     if (OS::FileExists(src_artifacts->oat_path.c_str())) {
1417       files_to_move.emplace_back(src_artifacts->oat_path, dst_artifacts->oat_path);
1418       files_to_move.emplace_back(src_artifacts->vdex_path, dst_artifacts->vdex_path);
1419       if (OS::FileExists(src_artifacts->art_path.c_str())) {
1420         files_to_move.emplace_back(src_artifacts->art_path, dst_artifacts->art_path);
1421       } else {
1422         files_to_remove.push_back(dst_artifacts->art_path);
1423       }
1424     }
1425   }
1426 
1427   for (const WritableProfilePath& profile : in_profiles) {
1428     RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(profile, "profiles");
1429 
1430     WritableProfilePath pre_reboot_profile = profile;
1431     PreRebootFlag(pre_reboot_profile) = true;
1432 
1433     auto src_profile = std::make_unique<std::string>(
1434         OR_RETURN_FATAL(BuildWritableProfilePath(pre_reboot_profile)));
1435     auto dst_profile =
1436         std::make_unique<std::string>(OR_RETURN_FATAL(BuildWritableProfilePath(profile)));
1437 
1438     if (OS::FileExists(src_profile->c_str())) {
1439       files_to_move.emplace_back(*src_profile, *dst_profile);
1440     }
1441   }
1442 
1443   OR_RETURN_NON_FATAL(MoveAllOrAbandon(files_to_move, files_to_remove));
1444 
1445   for (const auto& [src_path, dst_path] : files_to_move) {
1446     LOG(INFO) << ART_FORMAT("Committed Pre-reboot staged file '{}' to '{}'", src_path, dst_path);
1447   }
1448 
1449   *_aidl_return = !files_to_move.empty();
1450   return ScopedAStatus::ok();
1451 }
1452 
checkPreRebootSystemRequirements(const std::string & in_chrootDir,bool * _aidl_return)1453 ScopedAStatus Artd::checkPreRebootSystemRequirements(const std::string& in_chrootDir,
1454                                                      bool* _aidl_return) {
1455   RETURN_FATAL_IF_PRE_REBOOT(options_);
1456   BuildSystemProperties new_props =
1457       OR_RETURN_NON_FATAL(BuildSystemProperties::Create(in_chrootDir + "/system/build.prop"));
1458   std::string old_release_str = props_->GetOrEmpty("ro.build.version.release");
1459   int old_release;
1460   if (!ParseInt(old_release_str, &old_release)) {
1461     return NonFatal(
1462         ART_FORMAT("Failed to read or parse old release number, got '{}'", old_release_str));
1463   }
1464   std::string new_release_str = new_props.GetOrEmpty("ro.build.version.release");
1465   int new_release;
1466   if (!ParseInt(new_release_str, &new_release)) {
1467     return NonFatal(
1468         ART_FORMAT("Failed to read or parse new release number, got '{}'", new_release_str));
1469   }
1470   if (new_release - old_release >= 2) {
1471     // When the release version difference is large, there is no particular technical reason why we
1472     // can't run Pre-reboot Dexopt, but we cannot test and support those cases.
1473     LOG(WARNING) << ART_FORMAT(
1474         "Pre-reboot Dexopt not supported due to large difference in release versions (old_release: "
1475         "{}, new_release: {})",
1476         old_release,
1477         new_release);
1478     *_aidl_return = false;
1479     return ScopedAStatus::ok();
1480   }
1481 
1482   *_aidl_return = true;
1483   return ScopedAStatus::ok();
1484 }
1485 
Start()1486 Result<void> Artd::Start() {
1487   OR_RETURN(SetLogVerbosity());
1488   MemMap::Init();
1489 
1490   ScopedAStatus status = ScopedAStatus::fromStatus(AServiceManager_registerLazyService(
1491       this->asBinder().get(), options_.is_pre_reboot ? kPreRebootServiceName : kServiceName));
1492   if (!status.isOk()) {
1493     return Error() << status.getDescription();
1494   }
1495 
1496   ABinderProcess_startThreadPool();
1497 
1498   return {};
1499 }
1500 
GetOatFileAssistantContext()1501 Result<OatFileAssistantContext*> Artd::GetOatFileAssistantContext() {
1502   std::lock_guard<std::mutex> lock(ofa_context_mu_);
1503 
1504   if (ofa_context_ == nullptr) {
1505     ofa_context_ = std::make_unique<OatFileAssistantContext>(
1506         std::make_unique<OatFileAssistantContext::RuntimeOptions>(
1507             OatFileAssistantContext::RuntimeOptions{
1508                 .image_locations = *OR_RETURN(GetBootImageLocations()),
1509                 .boot_class_path = *OR_RETURN(GetBootClassPath()),
1510                 .boot_class_path_locations = *OR_RETURN(GetBootClassPath()),
1511                 .deny_art_apex_data_files = DenyArtApexDataFiles(),
1512             }));
1513     std::string error_msg;
1514     if (!ofa_context_->FetchAll(&error_msg)) {
1515       return Error() << error_msg;
1516     }
1517   }
1518 
1519   return ofa_context_.get();
1520 }
1521 
GetBootImageLocations()1522 Result<const std::vector<std::string>*> Artd::GetBootImageLocations() {
1523   std::lock_guard<std::mutex> lock(cache_mu_);
1524 
1525   if (!cached_boot_image_locations_.has_value()) {
1526     std::string location_str;
1527 
1528     if (UseJitZygoteLocked()) {
1529       location_str = GetJitZygoteBootImageLocation();
1530     } else if (std::string value = GetUserDefinedBootImageLocationsLocked(); !value.empty()) {
1531       location_str = std::move(value);
1532     } else {
1533       std::string error_msg;
1534       std::string android_root = GetAndroidRootSafe(&error_msg);
1535       if (!error_msg.empty()) {
1536         return Errorf("Failed to get ANDROID_ROOT: {}", error_msg);
1537       }
1538       location_str = GetDefaultBootImageLocation(android_root, DenyArtApexDataFilesLocked());
1539     }
1540 
1541     cached_boot_image_locations_ = Split(location_str, ":");
1542   }
1543 
1544   return &cached_boot_image_locations_.value();
1545 }
1546 
GetBootClassPath()1547 Result<const std::vector<std::string>*> Artd::GetBootClassPath() {
1548   std::lock_guard<std::mutex> lock(cache_mu_);
1549 
1550   if (!cached_boot_class_path_.has_value()) {
1551     const char* env_value = getenv("BOOTCLASSPATH");
1552     if (env_value == nullptr || strlen(env_value) == 0) {
1553       return Errorf("Failed to get environment variable 'BOOTCLASSPATH'");
1554     }
1555     cached_boot_class_path_ = Split(env_value, ":");
1556   }
1557 
1558   return &cached_boot_class_path_.value();
1559 }
1560 
UseJitZygote()1561 bool Artd::UseJitZygote() {
1562   std::lock_guard<std::mutex> lock(cache_mu_);
1563   return UseJitZygoteLocked();
1564 }
1565 
UseJitZygoteLocked()1566 bool Artd::UseJitZygoteLocked() {
1567   if (!cached_use_jit_zygote_.has_value()) {
1568     cached_use_jit_zygote_ =
1569         props_->GetBool("persist.device_config.runtime_native_boot.profilebootclasspath",
1570                         "dalvik.vm.profilebootclasspath",
1571                         /*default_value=*/false);
1572   }
1573 
1574   return cached_use_jit_zygote_.value();
1575 }
1576 
GetUserDefinedBootImageLocations()1577 const std::string& Artd::GetUserDefinedBootImageLocations() {
1578   std::lock_guard<std::mutex> lock(cache_mu_);
1579   return GetUserDefinedBootImageLocationsLocked();
1580 }
1581 
GetUserDefinedBootImageLocationsLocked()1582 const std::string& Artd::GetUserDefinedBootImageLocationsLocked() {
1583   if (!cached_user_defined_boot_image_locations_.has_value()) {
1584     cached_user_defined_boot_image_locations_ = props_->GetOrEmpty("dalvik.vm.boot-image");
1585   }
1586 
1587   return cached_user_defined_boot_image_locations_.value();
1588 }
1589 
DenyArtApexDataFiles()1590 bool Artd::DenyArtApexDataFiles() {
1591   std::lock_guard<std::mutex> lock(cache_mu_);
1592   return DenyArtApexDataFilesLocked();
1593 }
1594 
DenyArtApexDataFilesLocked()1595 bool Artd::DenyArtApexDataFilesLocked() {
1596   if (!cached_deny_art_apex_data_files_.has_value()) {
1597     cached_deny_art_apex_data_files_ =
1598         !props_->GetBool("odsign.verification.success", /*default_value=*/false);
1599   }
1600 
1601   return cached_deny_art_apex_data_files_.value();
1602 }
1603 
GetProfman()1604 Result<std::string> Artd::GetProfman() { return BuildArtBinPath("profman"); }
1605 
GetArtExecCmdlineBuilder()1606 Result<CmdlineBuilder> Artd::GetArtExecCmdlineBuilder() {
1607   CmdlineBuilder args;
1608   args.Add(OR_RETURN(BuildArtBinPath("art_exec")))
1609       .Add("--drop-capabilities")
1610       .AddIf(options_.is_pre_reboot, "--process-name-suffix=Pre-reboot Dexopt chroot");
1611   return args;
1612 }
1613 
ShouldUseDex2Oat64()1614 bool Artd::ShouldUseDex2Oat64() {
1615   return !props_->GetOrEmpty("ro.product.cpu.abilist64").empty() &&
1616          props_->GetBool("dalvik.vm.dex2oat64.enabled", /*default_value=*/false);
1617 }
1618 
GetDex2Oat()1619 Result<std::string> Artd::GetDex2Oat() {
1620   std::string binary_name = ShouldUseDex2Oat64() ? "dex2oat64" : "dex2oat32";
1621   // TODO(b/234351700): Should we use the "d" variant?
1622   return BuildArtBinPath(binary_name);
1623 }
1624 
ShouldCreateSwapFileForDexopt()1625 bool Artd::ShouldCreateSwapFileForDexopt() {
1626   // Create a swap file by default. Dex2oat will decide whether to use it or not.
1627   return props_->GetBool("dalvik.vm.dex2oat-swap", /*default_value=*/true);
1628 }
1629 
AddBootImageFlags(CmdlineBuilder & args)1630 void Artd::AddBootImageFlags(/*out*/ CmdlineBuilder& args) {
1631   if (UseJitZygote()) {
1632     args.Add("--force-jit-zygote");
1633   } else {
1634     args.AddIfNonEmpty("--boot-image=%s", GetUserDefinedBootImageLocations());
1635   }
1636 }
1637 
AddCompilerConfigFlags(const std::string & instruction_set,const std::string & compiler_filter,PriorityClass priority_class,const DexoptOptions & dexopt_options,CmdlineBuilder & args)1638 void Artd::AddCompilerConfigFlags(const std::string& instruction_set,
1639                                   const std::string& compiler_filter,
1640                                   PriorityClass priority_class,
1641                                   const DexoptOptions& dexopt_options,
1642                                   /*out*/ CmdlineBuilder& args) {
1643   args.Add("--instruction-set=%s", instruction_set);
1644   std::string features_prop = ART_FORMAT("dalvik.vm.isa.{}.features", instruction_set);
1645   args.AddIfNonEmpty("--instruction-set-features=%s", props_->GetOrEmpty(features_prop));
1646   std::string variant_prop = ART_FORMAT("dalvik.vm.isa.{}.variant", instruction_set);
1647   args.AddIfNonEmpty("--instruction-set-variant=%s", props_->GetOrEmpty(variant_prop));
1648 
1649   args.Add("--compiler-filter=%s", compiler_filter)
1650       .Add("--compilation-reason=%s", dexopt_options.compilationReason);
1651 
1652   args.AddIf(priority_class >= PriorityClass::INTERACTIVE, "--compact-dex-level=none");
1653 
1654   args.AddIfNonEmpty("--max-image-block-size=%s",
1655                      props_->GetOrEmpty("dalvik.vm.dex2oat-max-image-block-size"))
1656       .AddIfNonEmpty("--very-large-app-threshold=%s",
1657                      props_->GetOrEmpty("dalvik.vm.dex2oat-very-large"))
1658       .AddIfNonEmpty(
1659           "--resolve-startup-const-strings=%s",
1660           props_->GetOrEmpty("dalvik.vm.dex2oat-resolve-startup-strings"));
1661 
1662   args.AddIf(dexopt_options.debuggable, "--debuggable")
1663       .AddIf(props_->GetBool("debug.generate-debug-info", /*default_value=*/false),
1664              "--generate-debug-info")
1665       .AddIf(props_->GetBool("dalvik.vm.dex2oat-minidebuginfo", /*default_value=*/false),
1666              "--generate-mini-debug-info");
1667 
1668   args.AddRuntimeIf(DenyArtApexDataFiles(), "-Xdeny-art-apex-data-files")
1669       .AddRuntime("-Xtarget-sdk-version:%d", dexopt_options.targetSdkVersion)
1670       .AddRuntimeIf(dexopt_options.hiddenApiPolicyEnabled, "-Xhidden-api-policy:enabled");
1671 }
1672 
AddPerfConfigFlags(PriorityClass priority_class,CmdlineBuilder & art_exec_args,CmdlineBuilder & dex2oat_args)1673 void Artd::AddPerfConfigFlags(PriorityClass priority_class,
1674                               /*out*/ CmdlineBuilder& art_exec_args,
1675                               /*out*/ CmdlineBuilder& dex2oat_args) {
1676   // CPU set and number of threads.
1677   std::string default_cpu_set_prop = "dalvik.vm.dex2oat-cpu-set";
1678   std::string default_threads_prop = "dalvik.vm.dex2oat-threads";
1679   std::string cpu_set;
1680   std::string threads;
1681   if (priority_class >= PriorityClass::BOOT) {
1682     cpu_set = props_->GetOrEmpty("dalvik.vm.boot-dex2oat-cpu-set");
1683     threads = props_->GetOrEmpty("dalvik.vm.boot-dex2oat-threads");
1684   } else if (priority_class >= PriorityClass::INTERACTIVE_FAST) {
1685     cpu_set = props_->GetOrEmpty("dalvik.vm.restore-dex2oat-cpu-set", default_cpu_set_prop);
1686     threads = props_->GetOrEmpty("dalvik.vm.restore-dex2oat-threads", default_threads_prop);
1687   } else if (priority_class <= PriorityClass::BACKGROUND) {
1688     cpu_set = props_->GetOrEmpty("dalvik.vm.background-dex2oat-cpu-set", default_cpu_set_prop);
1689     threads = props_->GetOrEmpty("dalvik.vm.background-dex2oat-threads", default_threads_prop);
1690   } else {
1691     cpu_set = props_->GetOrEmpty(default_cpu_set_prop);
1692     threads = props_->GetOrEmpty(default_threads_prop);
1693   }
1694   dex2oat_args.AddIfNonEmpty("--cpu-set=%s", cpu_set).AddIfNonEmpty("-j%s", threads);
1695 
1696   if (priority_class < PriorityClass::BOOT) {
1697     art_exec_args
1698         .Add(priority_class <= PriorityClass::BACKGROUND ? "--set-task-profile=Dex2OatBackground" :
1699                                                            "--set-task-profile=Dex2OatBootComplete")
1700         .Add("--set-priority=background");
1701   }
1702 
1703   dex2oat_args.AddRuntimeIfNonEmpty("-Xms%s", props_->GetOrEmpty("dalvik.vm.dex2oat-Xms"))
1704       .AddRuntimeIfNonEmpty("-Xmx%s", props_->GetOrEmpty("dalvik.vm.dex2oat-Xmx"));
1705 
1706   // Enable compiling dex files in isolation on low ram devices.
1707   // It takes longer but reduces the memory footprint.
1708   dex2oat_args.AddIf(props_->GetBool("ro.config.low_ram", /*default_value=*/false),
1709                      "--compile-individually");
1710 
1711   for (const std::string& flag :
1712        Tokenize(props_->GetOrEmpty("dalvik.vm.dex2oat-flags"), /*delimiters=*/" ")) {
1713     dex2oat_args.AddIfNonEmpty("%s", flag);
1714   }
1715 }
1716 
ExecAndReturnCode(const std::vector<std::string> & args,int timeout_sec,const ExecCallbacks & callbacks,ProcessStat * stat) const1717 Result<int> Artd::ExecAndReturnCode(const std::vector<std::string>& args,
1718                                     int timeout_sec,
1719                                     const ExecCallbacks& callbacks,
1720                                     ProcessStat* stat) const {
1721   std::string error_msg;
1722   // Create a new process group so that we can kill the process subtree at once by killing the
1723   // process group.
1724   ExecResult result = exec_utils_->ExecAndReturnResult(
1725       args, timeout_sec, callbacks, /*new_process_group=*/true, stat, &error_msg);
1726   if (result.status != ExecResult::kExited) {
1727     return Error() << error_msg;
1728   }
1729   return result.exit_code;
1730 }
1731 
Fstat(const File & file) const1732 Result<struct stat> Artd::Fstat(const File& file) const {
1733   struct stat st;
1734   if (fstat_(file.Fd(), &st) != 0) {
1735     return Errorf("Unable to fstat file '{}'", file.GetPath());
1736   }
1737   return st;
1738 }
1739 
BindMountNewDir(const std::string & source,const std::string & target) const1740 Result<void> Artd::BindMountNewDir(const std::string& source, const std::string& target) const {
1741   OR_RETURN(CreateDir(source));
1742   OR_RETURN(BindMount(source, target));
1743   OR_RETURN(restorecon_(target, /*se_context=*/std::nullopt, /*recurse=*/false));
1744   return {};
1745 }
1746 
BindMount(const std::string & source,const std::string & target) const1747 Result<void> Artd::BindMount(const std::string& source, const std::string& target) const {
1748   if (mount_(source.c_str(),
1749              target.c_str(),
1750              /*fs_type=*/nullptr,
1751              MS_BIND | MS_PRIVATE,
1752              /*data=*/nullptr) != 0) {
1753     return ErrnoErrorf("Failed to bind-mount '{}' at '{}'", source, target);
1754   }
1755   return {};
1756 }
1757 
preRebootInit(const std::shared_ptr<IArtdCancellationSignal> & in_cancellationSignal,bool * _aidl_return)1758 ScopedAStatus Artd::preRebootInit(
1759     const std::shared_ptr<IArtdCancellationSignal>& in_cancellationSignal, bool* _aidl_return) {
1760   RETURN_FATAL_IF_NOT_PRE_REBOOT(options_);
1761 
1762   std::string tmp_dir = pre_reboot_tmp_dir_.value_or(kDefaultPreRebootTmpDir);
1763   std::string preparation_done_file = tmp_dir + "/preparation_done";
1764   std::string classpath_file = tmp_dir + "/classpath.txt";
1765   std::string art_apex_data_dir = tmp_dir + "/art_apex_data";
1766   std::string odrefresh_dir = tmp_dir + "/odrefresh";
1767 
1768   bool preparation_done = OS::FileExists(preparation_done_file.c_str());
1769 
1770   if (!preparation_done) {
1771     std::error_code ec;
1772     bool is_empty = std::filesystem::is_empty(tmp_dir, ec);
1773     if (ec) {
1774       return NonFatal(ART_FORMAT("Failed to check dir '{}': {}", tmp_dir, ec.message()));
1775     }
1776     if (!is_empty) {
1777       return Fatal(
1778           "preRebootInit must not be concurrently called or retried after cancellation or failure");
1779     }
1780   }
1781 
1782   OR_RETURN_NON_FATAL(PreRebootInitClearEnvs());
1783   OR_RETURN_NON_FATAL(
1784       PreRebootInitSetEnvFromFile(init_environ_rc_path_.value_or("/init.environ.rc")));
1785   if (!preparation_done) {
1786     OR_RETURN_NON_FATAL(PreRebootInitDeriveClasspath(classpath_file));
1787   }
1788   OR_RETURN_NON_FATAL(PreRebootInitSetEnvFromFile(classpath_file));
1789   if (!preparation_done) {
1790     OR_RETURN_NON_FATAL(BindMountNewDir(art_apex_data_dir, GetArtApexData()));
1791     OR_RETURN_NON_FATAL(BindMountNewDir(odrefresh_dir, "/data/misc/odrefresh"));
1792     ArtdCancellationSignal* cancellation_signal =
1793         OR_RETURN_FATAL(ToArtdCancellationSignal(in_cancellationSignal.get()));
1794     if (!OR_RETURN_NON_FATAL(PreRebootInitBootImages(cancellation_signal))) {
1795       *_aidl_return = false;
1796       return ScopedAStatus::ok();
1797     }
1798   }
1799 
1800   if (!preparation_done) {
1801     if (!WriteStringToFile(/*content=*/"", preparation_done_file)) {
1802       return NonFatal(
1803           ART_FORMAT("Failed to write '{}': {}", preparation_done_file, strerror(errno)));
1804     }
1805   }
1806 
1807   *_aidl_return = true;
1808   return ScopedAStatus::ok();
1809 }
1810 
PreRebootInitClearEnvs()1811 Result<void> Artd::PreRebootInitClearEnvs() {
1812   if (clearenv() != 0) {
1813     return ErrnoErrorf("Failed to clear environment variables");
1814   }
1815   return {};
1816 }
1817 
PreRebootInitSetEnvFromFile(const std::string & path)1818 Result<void> Artd::PreRebootInitSetEnvFromFile(const std::string& path) {
1819   std::regex export_line_pattern("\\s*export\\s+(.+?)\\s+(.+)");
1820 
1821   std::string content;
1822   if (!ReadFileToString(path, &content)) {
1823     return ErrnoErrorf("Failed to read '{}'", path);
1824   }
1825   bool found = false;
1826   for (const std::string& line : Split(content, "\n")) {
1827     if (line.find_first_of("\\\"") != std::string::npos) {
1828       return Errorf("Backslashes and quotes in env var file are not supported for now, got '{}'",
1829                     line);
1830     }
1831     std::smatch match;
1832     if (!std::regex_match(line, match, export_line_pattern)) {
1833       continue;
1834     }
1835     const std::string& key = match[1].str();
1836     const std::string& value = match[2].str();
1837     LOG(INFO) << ART_FORMAT("Setting environment variable '{}' to '{}'", key, value);
1838     if (setenv(key.c_str(), value.c_str(), /*replace=*/1) != 0) {
1839       return ErrnoErrorf("Failed to set environment variable '{}' to '{}'", key, value);
1840     }
1841     found = true;
1842   }
1843   if (!found) {
1844     return Errorf("Malformed env var file '{}': {}", path, content);
1845   }
1846   return {};
1847 }
1848 
PreRebootInitDeriveClasspath(const std::string & path)1849 Result<void> Artd::PreRebootInitDeriveClasspath(const std::string& path) {
1850   std::unique_ptr<File> output(OS::CreateEmptyFile(path.c_str()));
1851   if (output == nullptr) {
1852     return ErrnoErrorf("Failed to create '{}'", path);
1853   }
1854 
1855   CmdlineBuilder args = OR_RETURN(GetArtExecCmdlineBuilder());
1856   args.Add("--keep-fds=%d", output->Fd())
1857       .Add("--")
1858       .Add("/apex/com.android.sdkext/bin/derive_classpath")
1859       .Add("/proc/self/fd/%d", output->Fd());
1860 
1861   LOG(INFO) << "Running derive_classpath: " << Join(args.Get(), /*separator=*/" ");
1862 
1863   Result<int> result = ExecAndReturnCode(args.Get(), kShortTimeoutSec);
1864   if (!result.ok()) {
1865     return Errorf("Failed to run derive_classpath: {}", result.error().message());
1866   }
1867 
1868   LOG(INFO) << ART_FORMAT("derive_classpath returned code {}", result.value());
1869 
1870   if (result.value() != 0) {
1871     return Errorf("derive_classpath returned an unexpected code: {}", result.value());
1872   }
1873 
1874   if (output->FlushClose() != 0) {
1875     return ErrnoErrorf("Failed to flush and close '{}'", path);
1876   }
1877 
1878   return {};
1879 }
1880 
PreRebootInitBootImages(ArtdCancellationSignal * cancellation_signal)1881 Result<bool> Artd::PreRebootInitBootImages(ArtdCancellationSignal* cancellation_signal) {
1882   CmdlineBuilder args = OR_RETURN(GetArtExecCmdlineBuilder());
1883   args.Add("--")
1884       .Add(OR_RETURN(BuildArtBinPath("odrefresh")))
1885       .Add("--only-boot-images")
1886       .Add("--compile");
1887 
1888   LOG(INFO) << "Running odrefresh: " << Join(args.Get(), /*separator=*/" ");
1889 
1890   Result<int> result =
1891       ExecAndReturnCode(args.Get(), kLongTimeoutSec, cancellation_signal->CreateExecCallbacks());
1892   if (!result.ok()) {
1893     if (cancellation_signal->IsCancelled()) {
1894       return false;
1895     }
1896     return Errorf("Failed to run odrefresh: {}", result.error().message());
1897   }
1898 
1899   LOG(INFO) << ART_FORMAT("odrefresh returned code {}", result.value());
1900 
1901   if (result.value() != odrefresh::ExitCode::kCompilationSuccess &&
1902       result.value() != odrefresh::ExitCode::kOkay) {
1903     return Errorf("odrefresh returned an unexpected code: {}", result.value());
1904   }
1905 
1906   return true;
1907 }
1908 
validateDexPath(const std::string & in_dexFile,std::optional<std::string> * _aidl_return)1909 ScopedAStatus Artd::validateDexPath(const std::string& in_dexFile,
1910                                     std::optional<std::string>* _aidl_return) {
1911   RETURN_FATAL_IF_NOT_PRE_REBOOT(options_);
1912   if (Result<void> result = ValidateDexPath(in_dexFile); !result.ok()) {
1913     *_aidl_return = result.error().message();
1914   } else {
1915     *_aidl_return = std::nullopt;
1916   }
1917   return ScopedAStatus::ok();
1918 }
1919 
validateClassLoaderContext(const std::string & in_dexFile,const std::string & in_classLoaderContext,std::optional<std::string> * _aidl_return)1920 ScopedAStatus Artd::validateClassLoaderContext(const std::string& in_dexFile,
1921                                                const std::string& in_classLoaderContext,
1922                                                std::optional<std::string>* _aidl_return) {
1923   RETURN_FATAL_IF_NOT_PRE_REBOOT(options_);
1924   if (Result<void> result = ValidateClassLoaderContext(in_dexFile, in_classLoaderContext);
1925       !result.ok()) {
1926     *_aidl_return = result.error().message();
1927   } else {
1928     *_aidl_return = std::nullopt;
1929   }
1930   return ScopedAStatus::ok();
1931 }
1932 
Create(const std::string & filename)1933 Result<BuildSystemProperties> BuildSystemProperties::Create(const std::string& filename) {
1934   std::string content;
1935   if (!ReadFileToString(filename, &content)) {
1936     return ErrnoErrorf("Failed to read '{}'", filename);
1937   }
1938   std::unordered_map<std::string, std::string> system_properties;
1939   for (const std::string& raw_line : Split(content, "\n")) {
1940     std::string line = Trim(raw_line);
1941     if (line.empty() || line.starts_with('#')) {
1942       continue;
1943     }
1944     size_t pos = line.find('=');
1945     if (pos == std::string::npos || pos == 0 || (pos == 1 && line[1] == '?')) {
1946       return Errorf("Malformed system property line '{}' in file '{}'", line, filename);
1947     }
1948     if (line[pos - 1] == '?') {
1949       std::string key = line.substr(/*pos=*/0, /*n=*/pos - 1);
1950       if (system_properties.find(key) == system_properties.end()) {
1951         system_properties[key] = line.substr(pos + 1);
1952       }
1953     } else {
1954       system_properties[line.substr(/*pos=*/0, /*n=*/pos)] = line.substr(pos + 1);
1955     }
1956   }
1957   return BuildSystemProperties(std::move(system_properties));
1958 }
1959 
GetProperty(const std::string & key) const1960 std::string BuildSystemProperties::GetProperty(const std::string& key) const {
1961   auto it = system_properties_.find(key);
1962   return it != system_properties_.end() ? it->second : "";
1963 }
1964 
1965 }  // namespace artd
1966 }  // namespace art
1967