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