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