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