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