• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "artd.h"
18 
19 #include <fcntl.h>
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <sys/statfs.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 
26 #include <climits>
27 #include <csignal>
28 #include <cstdint>
29 #include <cstring>
30 #include <filesystem>
31 #include <functional>
32 #include <map>
33 #include <memory>
34 #include <mutex>
35 #include <optional>
36 #include <ostream>
37 #include <string>
38 #include <string_view>
39 #include <system_error>
40 #include <type_traits>
41 #include <unordered_set>
42 #include <utility>
43 #include <vector>
44 
45 #include "aidl/com/android/server/art/BnArtd.h"
46 #include "aidl/com/android/server/art/DexoptTrigger.h"
47 #include "aidl/com/android/server/art/IArtdCancellationSignal.h"
48 #include "android-base/errors.h"
49 #include "android-base/file.h"
50 #include "android-base/logging.h"
51 #include "android-base/result.h"
52 #include "android-base/scopeguard.h"
53 #include "android-base/strings.h"
54 #include "android/binder_auto_utils.h"
55 #include "android/binder_interface_utils.h"
56 #include "android/binder_manager.h"
57 #include "android/binder_process.h"
58 #include "base/compiler_filter.h"
59 #include "base/file_utils.h"
60 #include "base/globals.h"
61 #include "base/logging.h"
62 #include "base/os.h"
63 #include "cmdline_types.h"
64 #include "exec_utils.h"
65 #include "file_utils.h"
66 #include "fmt/format.h"
67 #include "oat_file_assistant.h"
68 #include "oat_file_assistant_context.h"
69 #include "path_utils.h"
70 #include "profman/profman_result.h"
71 #include "selinux/android.h"
72 #include "tools/cmdline_builder.h"
73 #include "tools/tools.h"
74 
75 #ifdef __BIONIC__
76 #include <linux/incrementalfs.h>
77 #endif
78 
79 namespace art {
80 namespace artd {
81 
82 namespace {
83 
84 using ::aidl::com::android::server::art::ArtdDexoptResult;
85 using ::aidl::com::android::server::art::ArtifactsPath;
86 using ::aidl::com::android::server::art::DexMetadataPath;
87 using ::aidl::com::android::server::art::DexoptOptions;
88 using ::aidl::com::android::server::art::DexoptTrigger;
89 using ::aidl::com::android::server::art::FileVisibility;
90 using ::aidl::com::android::server::art::FsPermission;
91 using ::aidl::com::android::server::art::GetDexoptNeededResult;
92 using ::aidl::com::android::server::art::GetDexoptStatusResult;
93 using ::aidl::com::android::server::art::IArtdCancellationSignal;
94 using ::aidl::com::android::server::art::MergeProfileOptions;
95 using ::aidl::com::android::server::art::OutputArtifacts;
96 using ::aidl::com::android::server::art::OutputProfile;
97 using ::aidl::com::android::server::art::PriorityClass;
98 using ::aidl::com::android::server::art::ProfilePath;
99 using ::aidl::com::android::server::art::VdexPath;
100 using ::android::base::Dirname;
101 using ::android::base::Error;
102 using ::android::base::Join;
103 using ::android::base::make_scope_guard;
104 using ::android::base::ReadFileToString;
105 using ::android::base::Result;
106 using ::android::base::Split;
107 using ::android::base::StringReplace;
108 using ::android::base::WriteStringToFd;
109 using ::art::tools::CmdlineBuilder;
110 using ::ndk::ScopedAStatus;
111 
112 using ::fmt::literals::operator""_format;  // NOLINT
113 
114 using ArtifactsLocation = GetDexoptNeededResult::ArtifactsLocation;
115 using TmpProfilePath = ProfilePath::TmpProfilePath;
116 
117 constexpr const char* kServiceName = "artd";
118 constexpr const char* kArtdCancellationSignalType = "ArtdCancellationSignal";
119 
120 // Timeout for short operations, such as merging profiles.
121 constexpr int kShortTimeoutSec = 60;  // 1 minute.
122 
123 // Timeout for long operations, such as compilation. We set it to be smaller than the Package
124 // Manager watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that if the operation
125 // is called from the Package Manager's thread handler, it will be aborted before that watchdog
126 // would take down the system server.
127 constexpr int kLongTimeoutSec = 570;  // 9.5 minutes.
128 
GetSize(std::string_view path)129 std::optional<int64_t> GetSize(std::string_view path) {
130   std::error_code ec;
131   int64_t size = std::filesystem::file_size(path, ec);
132   if (ec) {
133     // It is okay if the file does not exist. We don't have to log it.
134     if (ec.value() != ENOENT) {
135       LOG(ERROR) << "Failed to get the file size of '{}': {}"_format(path, ec.message());
136     }
137     return std::nullopt;
138   }
139   return size;
140 }
141 
142 // Deletes a file. Returns the size of the deleted file, or 0 if the deleted file is empty or an
143 // error occurs.
GetSizeAndDeleteFile(const std::string & path)144 int64_t GetSizeAndDeleteFile(const std::string& path) {
145   std::optional<int64_t> size = GetSize(path);
146   if (!size.has_value()) {
147     return 0;
148   }
149 
150   std::error_code ec;
151   if (!std::filesystem::remove(path, ec)) {
152     LOG(ERROR) << "Failed to remove '{}': {}"_format(path, ec.message());
153     return 0;
154   }
155 
156   return size.value();
157 }
158 
EscapeErrorMessage(const std::string & message)159 std::string EscapeErrorMessage(const std::string& message) {
160   return StringReplace(message, std::string("\0", /*n=*/1), "\\0", /*all=*/true);
161 }
162 
163 // Indicates an error that should never happen (e.g., illegal arguments passed by service-art
164 // internally). System server should crash if this kind of error happens.
Fatal(const std::string & message)165 ScopedAStatus Fatal(const std::string& message) {
166   return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
167                                                      EscapeErrorMessage(message).c_str());
168 }
169 
170 // Indicates an error that service-art should handle (e.g., I/O errors, sub-process crashes).
171 // The scope of the error depends on the function that throws it, so service-art should catch the
172 // error at every call site and take different actions.
173 // Ideally, this should be a checked exception or an additional return value that forces service-art
174 // to handle it, but `ServiceSpecificException` (a separate runtime exception type) is the best
175 // approximate we have given the limitation of Java and Binder.
NonFatal(const std::string & message)176 ScopedAStatus NonFatal(const std::string& message) {
177   constexpr int32_t kArtdNonFatalErrorCode = 1;
178   return ScopedAStatus::fromServiceSpecificErrorWithMessage(kArtdNonFatalErrorCode,
179                                                             EscapeErrorMessage(message).c_str());
180 }
181 
ParseCompilerFilter(const std::string & compiler_filter_str)182 Result<CompilerFilter::Filter> ParseCompilerFilter(const std::string& compiler_filter_str) {
183   CompilerFilter::Filter compiler_filter;
184   if (!CompilerFilter::ParseCompilerFilter(compiler_filter_str.c_str(), &compiler_filter)) {
185     return Errorf("Failed to parse compiler filter '{}'", compiler_filter_str);
186   }
187   return compiler_filter;
188 }
189 
DexOptTriggerFromAidl(int32_t aidl_value)190 OatFileAssistant::DexOptTrigger DexOptTriggerFromAidl(int32_t aidl_value) {
191   OatFileAssistant::DexOptTrigger trigger{};
192   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::COMPILER_FILTER_IS_BETTER)) != 0) {
193     trigger.targetFilterIsBetter = true;
194   }
195   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::COMPILER_FILTER_IS_SAME)) != 0) {
196     trigger.targetFilterIsSame = true;
197   }
198   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::COMPILER_FILTER_IS_WORSE)) != 0) {
199     trigger.targetFilterIsWorse = true;
200   }
201   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::PRIMARY_BOOT_IMAGE_BECOMES_USABLE)) != 0) {
202     trigger.primaryBootImageBecomesUsable = true;
203   }
204   if ((aidl_value & static_cast<int32_t>(DexoptTrigger::NEED_EXTRACTION)) != 0) {
205     trigger.needExtraction = true;
206   }
207   return trigger;
208 }
209 
ArtifactsLocationToAidl(OatFileAssistant::Location location)210 ArtifactsLocation ArtifactsLocationToAidl(OatFileAssistant::Location location) {
211   switch (location) {
212     case OatFileAssistant::Location::kLocationNoneOrError:
213       return ArtifactsLocation::NONE_OR_ERROR;
214     case OatFileAssistant::Location::kLocationOat:
215       return ArtifactsLocation::DALVIK_CACHE;
216     case OatFileAssistant::Location::kLocationOdex:
217       return ArtifactsLocation::NEXT_TO_DEX;
218     case OatFileAssistant::Location::kLocationDm:
219       return ArtifactsLocation::DM;
220       // No default. All cases should be explicitly handled, or the compilation will fail.
221   }
222   // This should never happen. Just in case we get a non-enumerator value.
223   LOG(FATAL) << "Unexpected Location " << location;
224 }
225 
PrepareArtifactsDir(const std::string & path,const FsPermission & fs_permission)226 Result<void> PrepareArtifactsDir(const std::string& path, const FsPermission& fs_permission) {
227   std::error_code ec;
228   bool created = std::filesystem::create_directory(path, ec);
229   if (ec) {
230     return Errorf("Failed to create directory '{}': {}", path, ec.message());
231   }
232 
233   auto cleanup = make_scope_guard([&] {
234     if (created) {
235       std::filesystem::remove(path, ec);
236     }
237   });
238 
239   if (chmod(path.c_str(), DirFsPermissionToMode(fs_permission)) != 0) {
240     return ErrnoErrorf("Failed to chmod directory '{}'", path);
241   }
242   OR_RETURN(Chown(path, fs_permission));
243 
244   cleanup.Disable();
245   return {};
246 }
247 
PrepareArtifactsDirs(const OutputArtifacts & output_artifacts,std::string * oat_dir_path)248 Result<void> PrepareArtifactsDirs(const OutputArtifacts& output_artifacts,
249                                   /*out*/ std::string* oat_dir_path) {
250   if (output_artifacts.artifactsPath.isInDalvikCache) {
251     return {};
252   }
253 
254   std::filesystem::path oat_path(OR_RETURN(BuildOatPath(output_artifacts.artifactsPath)));
255   std::filesystem::path isa_dir = oat_path.parent_path();
256   std::filesystem::path oat_dir = isa_dir.parent_path();
257   DCHECK_EQ(oat_dir.filename(), "oat");
258 
259   OR_RETURN(PrepareArtifactsDir(oat_dir, output_artifacts.permissionSettings.dirFsPermission));
260   OR_RETURN(PrepareArtifactsDir(isa_dir, output_artifacts.permissionSettings.dirFsPermission));
261   *oat_dir_path = oat_dir;
262   return {};
263 }
264 
Restorecon(const std::string & path,const std::optional<OutputArtifacts::PermissionSettings::SeContext> & se_context)265 Result<void> Restorecon(
266     const std::string& path,
267     const std::optional<OutputArtifacts::PermissionSettings::SeContext>& se_context) {
268   if (!kIsTargetAndroid) {
269     return {};
270   }
271 
272   int res = 0;
273   if (se_context.has_value()) {
274     res = selinux_android_restorecon_pkgdir(path.c_str(),
275                                             se_context->seInfo.c_str(),
276                                             se_context->uid,
277                                             SELINUX_ANDROID_RESTORECON_RECURSE);
278   } else {
279     res = selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE);
280   }
281   if (res != 0) {
282     return ErrnoErrorf("Failed to restorecon directory '{}'", path);
283   }
284   return {};
285 }
286 
GetFileVisibility(const std::string & file)287 Result<FileVisibility> GetFileVisibility(const std::string& file) {
288   std::error_code ec;
289   std::filesystem::file_status status = std::filesystem::status(file, ec);
290   if (!std::filesystem::status_known(status)) {
291     return Errorf("Failed to get status of '{}': {}", file, ec.message());
292   }
293   if (!std::filesystem::exists(status)) {
294     return FileVisibility::NOT_FOUND;
295   }
296 
297   return (status.permissions() & std::filesystem::perms::others_read) !=
298                  std::filesystem::perms::none ?
299              FileVisibility::OTHER_READABLE :
300              FileVisibility::NOT_OTHER_READABLE;
301 }
302 
ToArtdCancellationSignal(IArtdCancellationSignal * input)303 Result<ArtdCancellationSignal*> ToArtdCancellationSignal(IArtdCancellationSignal* input) {
304   if (input == nullptr) {
305     return Error() << "Cancellation signal must not be nullptr";
306   }
307   // We cannot use `dynamic_cast` because ART code is compiled with `-fno-rtti`, so we have to check
308   // the magic number.
309   int64_t type;
310   if (!input->getType(&type).isOk() ||
311       type != reinterpret_cast<intptr_t>(kArtdCancellationSignalType)) {
312     // The cancellation signal must be created by `Artd::createCancellationSignal`.
313     return Error() << "Invalid cancellation signal type";
314   }
315   return static_cast<ArtdCancellationSignal*>(input);
316 }
317 
CopyFile(const std::string & src_path,const NewFile & dst_file)318 Result<void> CopyFile(const std::string& src_path, const NewFile& dst_file) {
319   std::string content;
320   if (!ReadFileToString(src_path, &content)) {
321     return Errorf("Failed to read file '{}': {}", src_path, strerror(errno));
322   }
323   if (!WriteStringToFd(content, dst_file.Fd())) {
324     return Errorf("Failed to write file '{}': {}", dst_file.TempPath(), strerror(errno));
325   }
326   if (fsync(dst_file.Fd()) != 0) {
327     return Errorf("Failed to flush file '{}': {}", dst_file.TempPath(), strerror(errno));
328   }
329   if (lseek(dst_file.Fd(), /*offset=*/0, SEEK_SET) != 0) {
330     return Errorf(
331         "Failed to reset the offset for file '{}': {}", dst_file.TempPath(), strerror(errno));
332   }
333   return {};
334 }
335 
SetLogVerbosity()336 Result<void> SetLogVerbosity() {
337   std::string options = android::base::GetProperty("dalvik.vm.artd-verbose", /*default_value=*/"");
338   if (options.empty()) {
339     return {};
340   }
341 
342   CmdlineType<LogVerbosity> parser;
343   CmdlineParseResult<LogVerbosity> result = parser.Parse(options);
344   if (!result.IsSuccess()) {
345     return Error() << result.GetMessage();
346   }
347 
348   gLogVerbosity = result.ReleaseValue();
349   return {};
350 }
351 
352 class FdLogger {
353  public:
Add(const NewFile & file)354   void Add(const NewFile& file) { fd_mapping_.emplace_back(file.Fd(), file.TempPath()); }
Add(const File & file)355   void Add(const File& file) { fd_mapping_.emplace_back(file.Fd(), file.GetPath()); }
356 
GetFds()357   std::string GetFds() {
358     std::vector<int> fds;
359     fds.reserve(fd_mapping_.size());
360     for (const auto& [fd, path] : fd_mapping_) {
361       fds.push_back(fd);
362     }
363     return Join(fds, ':');
364   }
365 
366  private:
367   std::vector<std::pair<int, std::string>> fd_mapping_;
368 
369   friend std::ostream& operator<<(std::ostream& os, const FdLogger& fd_logger);
370 };
371 
operator <<(std::ostream & os,const FdLogger & fd_logger)372 std::ostream& operator<<(std::ostream& os, const FdLogger& fd_logger) {
373   for (const auto& [fd, path] : fd_logger.fd_mapping_) {
374     os << fd << ":" << path << ' ';
375   }
376   return os;
377 }
378 
379 }  // namespace
380 
381 #define OR_RETURN_ERROR(func, expr)         \
382   ({                                        \
383     decltype(expr)&& tmp = (expr);          \
384     if (!tmp.ok()) {                        \
385       return (func)(tmp.error().message()); \
386     }                                       \
387     std::move(tmp).value();                 \
388   })
389 
390 #define OR_RETURN_FATAL(expr)     OR_RETURN_ERROR(Fatal, expr)
391 #define OR_RETURN_NON_FATAL(expr) OR_RETURN_ERROR(NonFatal, expr)
392 
isAlive(bool * _aidl_return)393 ScopedAStatus Artd::isAlive(bool* _aidl_return) {
394   *_aidl_return = true;
395   return ScopedAStatus::ok();
396 }
397 
deleteArtifacts(const ArtifactsPath & in_artifactsPath,int64_t * _aidl_return)398 ScopedAStatus Artd::deleteArtifacts(const ArtifactsPath& in_artifactsPath, int64_t* _aidl_return) {
399   std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_artifactsPath));
400 
401   *_aidl_return = 0;
402   *_aidl_return += GetSizeAndDeleteFile(oat_path);
403   *_aidl_return += GetSizeAndDeleteFile(OatPathToVdexPath(oat_path));
404   *_aidl_return += GetSizeAndDeleteFile(OatPathToArtPath(oat_path));
405 
406   return ScopedAStatus::ok();
407 }
408 
getDexoptStatus(const std::string & in_dexFile,const std::string & in_instructionSet,const std::optional<std::string> & in_classLoaderContext,GetDexoptStatusResult * _aidl_return)409 ScopedAStatus Artd::getDexoptStatus(const std::string& in_dexFile,
410                                     const std::string& in_instructionSet,
411                                     const std::optional<std::string>& in_classLoaderContext,
412                                     GetDexoptStatusResult* _aidl_return) {
413   Result<OatFileAssistantContext*> ofa_context = GetOatFileAssistantContext();
414   if (!ofa_context.ok()) {
415     return NonFatal("Failed to get runtime options: " + ofa_context.error().message());
416   }
417 
418   std::unique_ptr<ClassLoaderContext> context;
419   std::string error_msg;
420   auto oat_file_assistant = OatFileAssistant::Create(in_dexFile,
421                                                      in_instructionSet,
422                                                      in_classLoaderContext,
423                                                      /*load_executable=*/false,
424                                                      /*only_load_trusted_executable=*/true,
425                                                      ofa_context.value(),
426                                                      &context,
427                                                      &error_msg);
428   if (oat_file_assistant == nullptr) {
429     return NonFatal("Failed to create OatFileAssistant: " + error_msg);
430   }
431 
432   std::string ignored_odex_status;
433   oat_file_assistant->GetOptimizationStatus(&_aidl_return->locationDebugString,
434                                             &_aidl_return->compilerFilter,
435                                             &_aidl_return->compilationReason,
436                                             &ignored_odex_status);
437 
438   // We ignore odex_status because it is not meaningful. It can only be either "up-to-date",
439   // "apk-more-recent", or "io-error-no-oat", which means it doesn't give us information in addition
440   // to what we can learn from compiler_filter because compiler_filter will be the actual compiler
441   // filter, "run-from-apk-fallback", and "run-from-apk" in those three cases respectively.
442   DCHECK(ignored_odex_status == "up-to-date" || ignored_odex_status == "apk-more-recent" ||
443          ignored_odex_status == "io-error-no-oat");
444 
445   return ScopedAStatus::ok();
446 }
447 
isProfileUsable(const ProfilePath & in_profile,const std::string & in_dexFile,bool * _aidl_return)448 ndk::ScopedAStatus Artd::isProfileUsable(const ProfilePath& in_profile,
449                                          const std::string& in_dexFile,
450                                          bool* _aidl_return) {
451   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
452   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
453 
454   FdLogger fd_logger;
455 
456   CmdlineBuilder art_exec_args;
457   art_exec_args.Add(OR_RETURN_FATAL(GetArtExec())).Add("--drop-capabilities");
458 
459   CmdlineBuilder args;
460   args.Add(OR_RETURN_FATAL(GetProfman()));
461 
462   Result<std::unique_ptr<File>> profile = OpenFileForReading(profile_path);
463   if (!profile.ok()) {
464     if (profile.error().code() == ENOENT) {
465       *_aidl_return = false;
466       return ScopedAStatus::ok();
467     }
468     return NonFatal(
469         "Failed to open profile '{}': {}"_format(profile_path, profile.error().message()));
470   }
471   args.Add("--reference-profile-file-fd=%d", profile.value()->Fd());
472   fd_logger.Add(*profile.value());
473 
474   std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(in_dexFile));
475   args.Add("--apk-fd=%d", dex_file->Fd());
476   fd_logger.Add(*dex_file);
477 
478   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
479 
480   LOG(INFO) << "Running profman: " << Join(art_exec_args.Get(), /*separator=*/" ")
481             << "\nOpened FDs: " << fd_logger;
482 
483   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kShortTimeoutSec);
484   if (!result.ok()) {
485     return NonFatal("Failed to run profman: " + result.error().message());
486   }
487 
488   LOG(INFO) << "profman returned code {}"_format(result.value());
489 
490   if (result.value() != ProfmanResult::kSkipCompilationSmallDelta &&
491       result.value() != ProfmanResult::kSkipCompilationEmptyProfiles) {
492     return NonFatal("profman returned an unexpected code: {}"_format(result.value()));
493   }
494 
495   *_aidl_return = result.value() == ProfmanResult::kSkipCompilationSmallDelta;
496   return ScopedAStatus::ok();
497 }
498 
copyAndRewriteProfile(const ProfilePath & in_src,OutputProfile * in_dst,const std::string & in_dexFile,bool * _aidl_return)499 ndk::ScopedAStatus Artd::copyAndRewriteProfile(const ProfilePath& in_src,
500                                                OutputProfile* in_dst,
501                                                const std::string& in_dexFile,
502                                                bool* _aidl_return) {
503   std::string src_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_src));
504   std::string dst_path = OR_RETURN_FATAL(BuildFinalProfilePath(in_dst->profilePath));
505   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
506 
507   FdLogger fd_logger;
508 
509   CmdlineBuilder art_exec_args;
510   art_exec_args.Add(OR_RETURN_FATAL(GetArtExec())).Add("--drop-capabilities");
511 
512   CmdlineBuilder args;
513   args.Add(OR_RETURN_FATAL(GetProfman())).Add("--copy-and-update-profile-key");
514 
515   Result<std::unique_ptr<File>> src = OpenFileForReading(src_path);
516   if (!src.ok()) {
517     if (src.error().code() == ENOENT) {
518       *_aidl_return = false;
519       return ScopedAStatus::ok();
520     }
521     return NonFatal("Failed to open src profile '{}': {}"_format(src_path, src.error().message()));
522   }
523   args.Add("--profile-file-fd=%d", src.value()->Fd());
524   fd_logger.Add(*src.value());
525 
526   std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(in_dexFile));
527   args.Add("--apk-fd=%d", dex_file->Fd());
528   fd_logger.Add(*dex_file);
529 
530   std::unique_ptr<NewFile> dst =
531       OR_RETURN_NON_FATAL(NewFile::Create(dst_path, in_dst->fsPermission));
532   args.Add("--reference-profile-file-fd=%d", dst->Fd());
533   fd_logger.Add(*dst);
534 
535   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
536 
537   LOG(INFO) << "Running profman: " << Join(art_exec_args.Get(), /*separator=*/" ")
538             << "\nOpened FDs: " << fd_logger;
539 
540   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kShortTimeoutSec);
541   if (!result.ok()) {
542     return NonFatal("Failed to run profman: " + result.error().message());
543   }
544 
545   LOG(INFO) << "profman returned code {}"_format(result.value());
546 
547   if (result.value() == ProfmanResult::kCopyAndUpdateNoMatch) {
548     *_aidl_return = false;
549     return ScopedAStatus::ok();
550   }
551 
552   if (result.value() != ProfmanResult::kCopyAndUpdateSuccess) {
553     return NonFatal("profman returned an unexpected code: {}"_format(result.value()));
554   }
555 
556   OR_RETURN_NON_FATAL(dst->Keep());
557   *_aidl_return = true;
558   in_dst->profilePath.id = dst->TempId();
559   in_dst->profilePath.tmpPath = dst->TempPath();
560   return ScopedAStatus::ok();
561 }
562 
commitTmpProfile(const TmpProfilePath & in_profile)563 ndk::ScopedAStatus Artd::commitTmpProfile(const TmpProfilePath& in_profile) {
564   std::string tmp_profile_path = OR_RETURN_FATAL(BuildTmpProfilePath(in_profile));
565   std::string ref_profile_path = OR_RETURN_FATAL(BuildFinalProfilePath(in_profile));
566 
567   std::error_code ec;
568   std::filesystem::rename(tmp_profile_path, ref_profile_path, ec);
569   if (ec) {
570     return NonFatal(
571         "Failed to move '{}' to '{}': {}"_format(tmp_profile_path, ref_profile_path, ec.message()));
572   }
573 
574   return ScopedAStatus::ok();
575 }
576 
deleteProfile(const ProfilePath & in_profile)577 ndk::ScopedAStatus Artd::deleteProfile(const ProfilePath& in_profile) {
578   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
579 
580   std::error_code ec;
581   std::filesystem::remove(profile_path, ec);
582   if (ec) {
583     LOG(ERROR) << "Failed to remove '{}': {}"_format(profile_path, ec.message());
584   }
585 
586   return ScopedAStatus::ok();
587 }
588 
getProfileVisibility(const ProfilePath & in_profile,FileVisibility * _aidl_return)589 ndk::ScopedAStatus Artd::getProfileVisibility(const ProfilePath& in_profile,
590                                               FileVisibility* _aidl_return) {
591   std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
592   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(profile_path));
593   return ScopedAStatus::ok();
594 }
595 
getArtifactsVisibility(const ArtifactsPath & in_artifactsPath,FileVisibility * _aidl_return)596 ndk::ScopedAStatus Artd::getArtifactsVisibility(const ArtifactsPath& in_artifactsPath,
597                                                 FileVisibility* _aidl_return) {
598   std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_artifactsPath));
599   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(oat_path));
600   return ScopedAStatus::ok();
601 }
602 
getDexFileVisibility(const std::string & in_dexFile,FileVisibility * _aidl_return)603 ndk::ScopedAStatus Artd::getDexFileVisibility(const std::string& in_dexFile,
604                                               FileVisibility* _aidl_return) {
605   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
606   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(in_dexFile));
607   return ScopedAStatus::ok();
608 }
609 
getDmFileVisibility(const DexMetadataPath & in_dmFile,FileVisibility * _aidl_return)610 ndk::ScopedAStatus Artd::getDmFileVisibility(const DexMetadataPath& in_dmFile,
611                                              FileVisibility* _aidl_return) {
612   std::string dm_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_dmFile));
613   *_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(dm_path));
614   return ScopedAStatus::ok();
615 }
616 
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)617 ndk::ScopedAStatus Artd::mergeProfiles(const std::vector<ProfilePath>& in_profiles,
618                                        const std::optional<ProfilePath>& in_referenceProfile,
619                                        OutputProfile* in_outputProfile,
620                                        const std::vector<std::string>& in_dexFiles,
621                                        const MergeProfileOptions& in_options,
622                                        bool* _aidl_return) {
623   std::vector<std::string> profile_paths;
624   for (const ProfilePath& profile : in_profiles) {
625     std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(profile));
626     if (profile.getTag() == ProfilePath::dexMetadataPath) {
627       return Fatal("Does not support DM file, got '{}'"_format(profile_path));
628     }
629     profile_paths.push_back(std::move(profile_path));
630   }
631   std::string output_profile_path =
632       OR_RETURN_FATAL(BuildFinalProfilePath(in_outputProfile->profilePath));
633   for (const std::string& dex_file : in_dexFiles) {
634     OR_RETURN_FATAL(ValidateDexPath(dex_file));
635   }
636   if (in_options.forceMerge + in_options.dumpOnly + in_options.dumpClassesAndMethods > 1) {
637     return Fatal("Only one of 'forceMerge', 'dumpOnly', and 'dumpClassesAndMethods' can be set");
638   }
639 
640   FdLogger fd_logger;
641 
642   CmdlineBuilder art_exec_args;
643   art_exec_args.Add(OR_RETURN_FATAL(GetArtExec())).Add("--drop-capabilities");
644 
645   CmdlineBuilder args;
646   args.Add(OR_RETURN_FATAL(GetProfman()));
647 
648   std::vector<std::unique_ptr<File>> profile_files;
649   for (const std::string& profile_path : profile_paths) {
650     Result<std::unique_ptr<File>> profile_file = OpenFileForReading(profile_path);
651     if (!profile_file.ok()) {
652       if (profile_file.error().code() == ENOENT) {
653         // Skip non-existing file.
654         continue;
655       }
656       return NonFatal(
657           "Failed to open profile '{}': {}"_format(profile_path, profile_file.error().message()));
658     }
659     args.Add("--profile-file-fd=%d", profile_file.value()->Fd());
660     fd_logger.Add(*profile_file.value());
661     profile_files.push_back(std::move(profile_file.value()));
662   }
663 
664   if (profile_files.empty()) {
665     LOG(INFO) << "Merge skipped because there are no existing profiles";
666     *_aidl_return = false;
667     return ScopedAStatus::ok();
668   }
669 
670   std::unique_ptr<NewFile> output_profile_file =
671       OR_RETURN_NON_FATAL(NewFile::Create(output_profile_path, in_outputProfile->fsPermission));
672 
673   if (in_referenceProfile.has_value()) {
674     if (in_options.forceMerge || in_options.dumpOnly || in_options.dumpClassesAndMethods) {
675       return Fatal(
676           "Reference profile must not be set when 'forceMerge', 'dumpOnly', or "
677           "'dumpClassesAndMethods' is set");
678     }
679     std::string reference_profile_path =
680         OR_RETURN_FATAL(BuildProfileOrDmPath(*in_referenceProfile));
681     if (in_referenceProfile->getTag() == ProfilePath::dexMetadataPath) {
682       return Fatal("Does not support DM file, got '{}'"_format(reference_profile_path));
683     }
684     OR_RETURN_NON_FATAL(CopyFile(reference_profile_path, *output_profile_file));
685   }
686 
687   if (in_options.dumpOnly || in_options.dumpClassesAndMethods) {
688     args.Add("--dump-output-to-fd=%d", output_profile_file->Fd());
689   } else {
690     // profman is ok with this being an empty file when in_referenceProfile isn't set.
691     args.Add("--reference-profile-file-fd=%d", output_profile_file->Fd());
692   }
693   fd_logger.Add(*output_profile_file);
694 
695   std::vector<std::unique_ptr<File>> dex_files;
696   for (const std::string& dex_path : in_dexFiles) {
697     std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(dex_path));
698     args.Add("--apk-fd=%d", dex_file->Fd());
699     fd_logger.Add(*dex_file);
700     dex_files.push_back(std::move(dex_file));
701   }
702 
703   if (in_options.dumpOnly || in_options.dumpClassesAndMethods) {
704     args.Add(in_options.dumpOnly ? "--dump-only" : "--dump-classes-and-methods");
705   } else {
706     args.AddIfNonEmpty("--min-new-classes-percent-change=%s",
707                        props_->GetOrEmpty("dalvik.vm.bgdexopt.new-classes-percent"))
708         .AddIfNonEmpty("--min-new-methods-percent-change=%s",
709                        props_->GetOrEmpty("dalvik.vm.bgdexopt.new-methods-percent"))
710         .AddIf(in_options.forceMerge, "--force-merge")
711         .AddIf(in_options.forBootImage, "--boot-image-merge");
712   }
713 
714   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
715 
716   LOG(INFO) << "Running profman: " << Join(art_exec_args.Get(), /*separator=*/" ")
717             << "\nOpened FDs: " << fd_logger;
718 
719   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kShortTimeoutSec);
720   if (!result.ok()) {
721     return NonFatal("Failed to run profman: " + result.error().message());
722   }
723 
724   LOG(INFO) << "profman returned code {}"_format(result.value());
725 
726   if (result.value() == ProfmanResult::kSkipCompilationSmallDelta ||
727       result.value() == ProfmanResult::kSkipCompilationEmptyProfiles) {
728     *_aidl_return = false;
729     return ScopedAStatus::ok();
730   }
731 
732   ProfmanResult::ProcessingResult expected_result =
733       (in_options.forceMerge || in_options.dumpOnly || in_options.dumpClassesAndMethods) ?
734           ProfmanResult::kSuccess :
735           ProfmanResult::kCompile;
736   if (result.value() != expected_result) {
737     return NonFatal("profman returned an unexpected code: {}"_format(result.value()));
738   }
739 
740   OR_RETURN_NON_FATAL(output_profile_file->Keep());
741   *_aidl_return = true;
742   in_outputProfile->profilePath.id = output_profile_file->TempId();
743   in_outputProfile->profilePath.tmpPath = output_profile_file->TempPath();
744   return ScopedAStatus::ok();
745 }
746 
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)747 ndk::ScopedAStatus Artd::getDexoptNeeded(const std::string& in_dexFile,
748                                          const std::string& in_instructionSet,
749                                          const std::optional<std::string>& in_classLoaderContext,
750                                          const std::string& in_compilerFilter,
751                                          int32_t in_dexoptTrigger,
752                                          GetDexoptNeededResult* _aidl_return) {
753   Result<OatFileAssistantContext*> ofa_context = GetOatFileAssistantContext();
754   if (!ofa_context.ok()) {
755     return NonFatal("Failed to get runtime options: " + ofa_context.error().message());
756   }
757 
758   std::unique_ptr<ClassLoaderContext> context;
759   std::string error_msg;
760   auto oat_file_assistant = OatFileAssistant::Create(in_dexFile,
761                                                      in_instructionSet,
762                                                      in_classLoaderContext,
763                                                      /*load_executable=*/false,
764                                                      /*only_load_trusted_executable=*/true,
765                                                      ofa_context.value(),
766                                                      &context,
767                                                      &error_msg);
768   if (oat_file_assistant == nullptr) {
769     return NonFatal("Failed to create OatFileAssistant: " + error_msg);
770   }
771 
772   OatFileAssistant::DexOptStatus status;
773   _aidl_return->isDexoptNeeded =
774       oat_file_assistant->GetDexOptNeeded(OR_RETURN_FATAL(ParseCompilerFilter(in_compilerFilter)),
775                                           DexOptTriggerFromAidl(in_dexoptTrigger),
776                                           &status);
777   _aidl_return->isVdexUsable = status.IsVdexUsable();
778   _aidl_return->artifactsLocation = ArtifactsLocationToAidl(status.GetLocation());
779 
780   return ScopedAStatus::ok();
781 }
782 
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)783 ndk::ScopedAStatus Artd::dexopt(
784     const OutputArtifacts& in_outputArtifacts,
785     const std::string& in_dexFile,
786     const std::string& in_instructionSet,
787     const std::optional<std::string>& in_classLoaderContext,
788     const std::string& in_compilerFilter,
789     const std::optional<ProfilePath>& in_profile,
790     const std::optional<VdexPath>& in_inputVdex,
791     const std::optional<DexMetadataPath>& in_dmFile,
792     PriorityClass in_priorityClass,
793     const DexoptOptions& in_dexoptOptions,
794     const std::shared_ptr<IArtdCancellationSignal>& in_cancellationSignal,
795     ArtdDexoptResult* _aidl_return) {
796   _aidl_return->cancelled = false;
797 
798   std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_outputArtifacts.artifactsPath));
799   std::string vdex_path = OatPathToVdexPath(oat_path);
800   std::string art_path = OatPathToArtPath(oat_path);
801   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
802   std::optional<std::string> profile_path =
803       in_profile.has_value() ?
804           std::make_optional(OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile.value()))) :
805           std::nullopt;
806   ArtdCancellationSignal* cancellation_signal =
807       OR_RETURN_FATAL(ToArtdCancellationSignal(in_cancellationSignal.get()));
808 
809   std::unique_ptr<ClassLoaderContext> context = nullptr;
810   if (in_classLoaderContext.has_value()) {
811     context = ClassLoaderContext::Create(in_classLoaderContext->c_str());
812     if (context == nullptr) {
813       return Fatal("Class loader context '{}' is invalid"_format(in_classLoaderContext.value()));
814     }
815   }
816 
817   std::string oat_dir_path;  // For restorecon, can be empty if the artifacts are in dalvik-cache.
818   OR_RETURN_NON_FATAL(PrepareArtifactsDirs(in_outputArtifacts, &oat_dir_path));
819 
820   // First-round restorecon. artd doesn't have the permission to create files with the
821   // `apk_data_file` label, so we need to restorecon the "oat" directory first so that files will
822   // inherit `dalvikcache_data_file` rather than `apk_data_file`.
823   if (!in_outputArtifacts.artifactsPath.isInDalvikCache) {
824     OR_RETURN_NON_FATAL(Restorecon(oat_dir_path, in_outputArtifacts.permissionSettings.seContext));
825   }
826 
827   FdLogger fd_logger;
828 
829   CmdlineBuilder art_exec_args;
830   art_exec_args.Add(OR_RETURN_FATAL(GetArtExec())).Add("--drop-capabilities");
831 
832   CmdlineBuilder args;
833   args.Add(OR_RETURN_FATAL(GetDex2Oat()));
834 
835   const FsPermission& fs_permission = in_outputArtifacts.permissionSettings.fileFsPermission;
836 
837   std::unique_ptr<File> dex_file = OR_RETURN_NON_FATAL(OpenFileForReading(in_dexFile));
838   args.Add("--zip-fd=%d", dex_file->Fd()).Add("--zip-location=%s", in_dexFile);
839   fd_logger.Add(*dex_file);
840   struct stat dex_st = OR_RETURN_NON_FATAL(Fstat(*dex_file));
841   if ((dex_st.st_mode & S_IROTH) == 0) {
842     if (fs_permission.isOtherReadable) {
843       return NonFatal(
844           "Outputs cannot be other-readable because the dex file '{}' is not other-readable"_format(
845               dex_file->GetPath()));
846     }
847     // Negative numbers mean no `chown`. 0 means root.
848     // Note: this check is more strict than it needs to be. For example, it doesn't allow the
849     // outputs to belong to a group that is a subset of the dex file's group. This is for
850     // simplicity, and it's okay as we don't have to handle such complicated cases in practice.
851     if ((fs_permission.uid > 0 && static_cast<uid_t>(fs_permission.uid) != dex_st.st_uid) ||
852         (fs_permission.gid > 0 && static_cast<gid_t>(fs_permission.gid) != dex_st.st_uid &&
853          static_cast<gid_t>(fs_permission.gid) != dex_st.st_gid)) {
854       return NonFatal(
855           "Outputs' owner doesn't match the dex file '{}' (outputs: {}:{}, dex file: {}:{})"_format(
856               dex_file->GetPath(),
857               fs_permission.uid,
858               fs_permission.gid,
859               dex_st.st_uid,
860               dex_st.st_gid));
861     }
862   }
863 
864   std::unique_ptr<NewFile> oat_file = OR_RETURN_NON_FATAL(NewFile::Create(oat_path, fs_permission));
865   args.Add("--oat-fd=%d", oat_file->Fd()).Add("--oat-location=%s", oat_path);
866   fd_logger.Add(*oat_file);
867 
868   std::unique_ptr<NewFile> vdex_file =
869       OR_RETURN_NON_FATAL(NewFile::Create(vdex_path, fs_permission));
870   args.Add("--output-vdex-fd=%d", vdex_file->Fd());
871   fd_logger.Add(*vdex_file);
872 
873   std::vector<NewFile*> files_to_commit{oat_file.get(), vdex_file.get()};
874   std::vector<std::string_view> files_to_delete;
875 
876   std::unique_ptr<NewFile> art_file = nullptr;
877   if (in_dexoptOptions.generateAppImage) {
878     art_file = OR_RETURN_NON_FATAL(NewFile::Create(art_path, fs_permission));
879     args.Add("--app-image-fd=%d", art_file->Fd());
880     args.AddIfNonEmpty("--image-format=%s", props_->GetOrEmpty("dalvik.vm.appimageformat"));
881     fd_logger.Add(*art_file);
882     files_to_commit.push_back(art_file.get());
883   } else {
884     files_to_delete.push_back(art_path);
885   }
886 
887   std::unique_ptr<NewFile> swap_file = nullptr;
888   if (ShouldCreateSwapFileForDexopt()) {
889     swap_file = OR_RETURN_NON_FATAL(
890         NewFile::Create("{}.swap"_format(oat_path), FsPermission{.uid = -1, .gid = -1}));
891     args.Add("--swap-fd=%d", swap_file->Fd());
892     fd_logger.Add(*swap_file);
893   }
894 
895   std::vector<std::unique_ptr<File>> context_files;
896   if (context != nullptr) {
897     std::vector<std::string> flattened_context = context->FlattenDexPaths();
898     std::string dex_dir = Dirname(in_dexFile.c_str());
899     std::vector<int> context_fds;
900     for (const std::string& context_element : flattened_context) {
901       std::string context_path = std::filesystem::path(dex_dir).append(context_element);
902       OR_RETURN_FATAL(ValidateDexPath(context_path));
903       std::unique_ptr<File> context_file = OR_RETURN_NON_FATAL(OpenFileForReading(context_path));
904       context_fds.push_back(context_file->Fd());
905       fd_logger.Add(*context_file);
906       context_files.push_back(std::move(context_file));
907     }
908     args.AddIfNonEmpty("--class-loader-context-fds=%s", Join(context_fds, /*separator=*/':'))
909         .Add("--class-loader-context=%s", in_classLoaderContext.value())
910         .Add("--classpath-dir=%s", dex_dir);
911   }
912 
913   std::unique_ptr<File> input_vdex_file = nullptr;
914   if (in_inputVdex.has_value()) {
915     std::string input_vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_inputVdex.value()));
916     input_vdex_file = OR_RETURN_NON_FATAL(OpenFileForReading(input_vdex_path));
917     args.Add("--input-vdex-fd=%d", input_vdex_file->Fd());
918     fd_logger.Add(*input_vdex_file);
919   }
920 
921   std::unique_ptr<File> dm_file = nullptr;
922   if (in_dmFile.has_value()) {
923     std::string dm_path = OR_RETURN_FATAL(BuildDexMetadataPath(in_dmFile.value()));
924     dm_file = OR_RETURN_NON_FATAL(OpenFileForReading(dm_path));
925     args.Add("--dm-fd=%d", dm_file->Fd());
926     fd_logger.Add(*dm_file);
927   }
928 
929   std::unique_ptr<File> profile_file = nullptr;
930   if (profile_path.has_value()) {
931     profile_file = OR_RETURN_NON_FATAL(OpenFileForReading(profile_path.value()));
932     args.Add("--profile-file-fd=%d", profile_file->Fd());
933     fd_logger.Add(*profile_file);
934     struct stat profile_st = OR_RETURN_NON_FATAL(Fstat(*profile_file));
935     if (fs_permission.isOtherReadable && (profile_st.st_mode & S_IROTH) == 0) {
936       return NonFatal(
937           "Outputs cannot be other-readable because the profile '{}' is not other-readable"_format(
938               profile_file->GetPath()));
939     }
940     // TODO(b/260228411): Check uid and gid.
941   }
942 
943   // Second-round restorecon. Restorecon recursively after the output files are created, so that the
944   // SELinux context is applied to all of them. The SELinux context of a file is mostly inherited
945   // from the parent directory upon creation, but the MLS label is not inherited, so we need to
946   // restorecon every file so that they have the right MLS label. If the files are in dalvik-cache,
947   // there's no need to restorecon because they inherits the SELinux context of the dalvik-cache
948   // directory and they don't need to have MLS labels.
949   if (!in_outputArtifacts.artifactsPath.isInDalvikCache) {
950     OR_RETURN_NON_FATAL(Restorecon(oat_dir_path, in_outputArtifacts.permissionSettings.seContext));
951   }
952 
953   AddBootImageFlags(args);
954   AddCompilerConfigFlags(
955       in_instructionSet, in_compilerFilter, in_priorityClass, in_dexoptOptions, args);
956   AddPerfConfigFlags(in_priorityClass, art_exec_args, args);
957 
958   // For being surfaced in crash reports on crashes.
959   args.Add("--comments=%s", in_dexoptOptions.comments);
960 
961   art_exec_args.Add("--keep-fds=%s", fd_logger.GetFds()).Add("--").Concat(std::move(args));
962 
963   LOG(INFO) << "Running dex2oat: " << Join(art_exec_args.Get(), /*separator=*/" ")
964             << "\nOpened FDs: " << fd_logger;
965 
966   ExecCallbacks callbacks{
967       .on_start =
968           [&](pid_t pid) {
969             std::lock_guard<std::mutex> lock(cancellation_signal->mu_);
970             cancellation_signal->pids_.insert(pid);
971             // Handle cancellation signals sent before the process starts.
972             if (cancellation_signal->is_cancelled_) {
973               int res = kill_(pid, SIGKILL);
974               DCHECK_EQ(res, 0);
975             }
976           },
977       .on_end =
978           [&](pid_t pid) {
979             std::lock_guard<std::mutex> lock(cancellation_signal->mu_);
980             // The pid should no longer receive kill signals sent by `cancellation_signal`.
981             cancellation_signal->pids_.erase(pid);
982           },
983   };
984 
985   ProcessStat stat;
986   Result<int> result = ExecAndReturnCode(art_exec_args.Get(), kLongTimeoutSec, callbacks, &stat);
987   _aidl_return->wallTimeMs = stat.wall_time_ms;
988   _aidl_return->cpuTimeMs = stat.cpu_time_ms;
989   if (!result.ok()) {
990     {
991       std::lock_guard<std::mutex> lock(cancellation_signal->mu_);
992       if (cancellation_signal->is_cancelled_) {
993         _aidl_return->cancelled = true;
994         return ScopedAStatus::ok();
995       }
996     }
997     return NonFatal("Failed to run dex2oat: " + result.error().message());
998   }
999 
1000   LOG(INFO) << "dex2oat returned code {}"_format(result.value());
1001 
1002   if (result.value() != 0) {
1003     return NonFatal("dex2oat returned an unexpected code: {}"_format(result.value()));
1004   }
1005 
1006   int64_t size_bytes = 0;
1007   int64_t size_before_bytes = 0;
1008   for (const NewFile* file : files_to_commit) {
1009     size_bytes += GetSize(file->TempPath()).value_or(0);
1010     size_before_bytes += GetSize(file->FinalPath()).value_or(0);
1011   }
1012   for (std::string_view path : files_to_delete) {
1013     size_before_bytes += GetSize(path).value_or(0);
1014   }
1015   OR_RETURN_NON_FATAL(NewFile::CommitAllOrAbandon(files_to_commit, files_to_delete));
1016 
1017   _aidl_return->sizeBytes = size_bytes;
1018   _aidl_return->sizeBeforeBytes = size_before_bytes;
1019   return ScopedAStatus::ok();
1020 }
1021 
cancel()1022 ScopedAStatus ArtdCancellationSignal::cancel() {
1023   std::lock_guard<std::mutex> lock(mu_);
1024   is_cancelled_ = true;
1025   for (pid_t pid : pids_) {
1026     int res = kill_(pid, SIGKILL);
1027     DCHECK_EQ(res, 0);
1028   }
1029   return ScopedAStatus::ok();
1030 }
1031 
getType(int64_t * _aidl_return)1032 ScopedAStatus ArtdCancellationSignal::getType(int64_t* _aidl_return) {
1033   *_aidl_return = reinterpret_cast<intptr_t>(kArtdCancellationSignalType);
1034   return ScopedAStatus::ok();
1035 }
1036 
createCancellationSignal(std::shared_ptr<IArtdCancellationSignal> * _aidl_return)1037 ScopedAStatus Artd::createCancellationSignal(
1038     std::shared_ptr<IArtdCancellationSignal>* _aidl_return) {
1039   *_aidl_return = ndk::SharedRefBase::make<ArtdCancellationSignal>(kill_);
1040   return ScopedAStatus::ok();
1041 }
1042 
cleanup(const std::vector<ProfilePath> & in_profilesToKeep,const std::vector<ArtifactsPath> & in_artifactsToKeep,const std::vector<VdexPath> & in_vdexFilesToKeep,int64_t * _aidl_return)1043 ScopedAStatus Artd::cleanup(const std::vector<ProfilePath>& in_profilesToKeep,
1044                             const std::vector<ArtifactsPath>& in_artifactsToKeep,
1045                             const std::vector<VdexPath>& in_vdexFilesToKeep,
1046                             int64_t* _aidl_return) {
1047   std::unordered_set<std::string> files_to_keep;
1048   for (const ProfilePath& profile : in_profilesToKeep) {
1049     files_to_keep.insert(OR_RETURN_FATAL(BuildProfileOrDmPath(profile)));
1050   }
1051   for (const ArtifactsPath& artifacts : in_artifactsToKeep) {
1052     std::string oat_path = OR_RETURN_FATAL(BuildOatPath(artifacts));
1053     files_to_keep.insert(OatPathToVdexPath(oat_path));
1054     files_to_keep.insert(OatPathToArtPath(oat_path));
1055     files_to_keep.insert(std::move(oat_path));
1056   }
1057   for (const VdexPath& vdex : in_vdexFilesToKeep) {
1058     files_to_keep.insert(OR_RETURN_FATAL(BuildVdexPath(vdex)));
1059   }
1060   *_aidl_return = 0;
1061   for (const std::string& file : OR_RETURN_NON_FATAL(ListManagedFiles())) {
1062     if (files_to_keep.find(file) == files_to_keep.end()) {
1063       LOG(INFO) << "Cleaning up obsolete file '{}'"_format(file);
1064       *_aidl_return += GetSizeAndDeleteFile(file);
1065     }
1066   }
1067   return ScopedAStatus::ok();
1068 }
1069 
isIncrementalFsPath(const std::string & in_dexFile,bool * _aidl_return)1070 ScopedAStatus Artd::isIncrementalFsPath(const std::string& in_dexFile [[maybe_unused]],
1071                                         bool* _aidl_return) {
1072 #ifdef __BIONIC__
1073   OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
1074   struct statfs st;
1075   if (statfs(in_dexFile.c_str(), &st) != 0) {
1076     PLOG(ERROR) << "Failed to statfs '{}'"_format(in_dexFile);
1077     *_aidl_return = false;
1078     return ScopedAStatus::ok();
1079   }
1080   *_aidl_return = st.f_type == INCFS_MAGIC_NUMBER;
1081   return ScopedAStatus::ok();
1082 #else
1083   *_aidl_return = false;
1084   return ScopedAStatus::ok();
1085 #endif
1086 }
1087 
Start()1088 Result<void> Artd::Start() {
1089   OR_RETURN(SetLogVerbosity());
1090 
1091   ScopedAStatus status = ScopedAStatus::fromStatus(
1092       AServiceManager_registerLazyService(this->asBinder().get(), kServiceName));
1093   if (!status.isOk()) {
1094     return Error() << status.getDescription();
1095   }
1096 
1097   ABinderProcess_startThreadPool();
1098 
1099   return {};
1100 }
1101 
GetOatFileAssistantContext()1102 Result<OatFileAssistantContext*> Artd::GetOatFileAssistantContext() {
1103   std::lock_guard<std::mutex> lock(ofa_context_mu_);
1104 
1105   if (ofa_context_ == nullptr) {
1106     ofa_context_ = std::make_unique<OatFileAssistantContext>(
1107         std::make_unique<OatFileAssistantContext::RuntimeOptions>(
1108             OatFileAssistantContext::RuntimeOptions{
1109                 .image_locations = *OR_RETURN(GetBootImageLocations()),
1110                 .boot_class_path = *OR_RETURN(GetBootClassPath()),
1111                 .boot_class_path_locations = *OR_RETURN(GetBootClassPath()),
1112                 .deny_art_apex_data_files = DenyArtApexDataFiles(),
1113             }));
1114     std::string error_msg;
1115     if (!ofa_context_->FetchAll(&error_msg)) {
1116       return Error() << error_msg;
1117     }
1118   }
1119 
1120   return ofa_context_.get();
1121 }
1122 
GetBootImageLocations()1123 Result<const std::vector<std::string>*> Artd::GetBootImageLocations() {
1124   std::lock_guard<std::mutex> lock(cache_mu_);
1125 
1126   if (!cached_boot_image_locations_.has_value()) {
1127     std::string location_str;
1128 
1129     if (UseJitZygoteLocked()) {
1130       location_str = GetJitZygoteBootImageLocation();
1131     } else if (std::string value = GetUserDefinedBootImageLocationsLocked(); !value.empty()) {
1132       location_str = std::move(value);
1133     } else {
1134       std::string error_msg;
1135       std::string android_root = GetAndroidRootSafe(&error_msg);
1136       if (!error_msg.empty()) {
1137         return Errorf("Failed to get ANDROID_ROOT: {}", error_msg);
1138       }
1139       location_str = GetDefaultBootImageLocation(android_root, DenyArtApexDataFilesLocked());
1140     }
1141 
1142     cached_boot_image_locations_ = Split(location_str, ":");
1143   }
1144 
1145   return &cached_boot_image_locations_.value();
1146 }
1147 
GetBootClassPath()1148 Result<const std::vector<std::string>*> Artd::GetBootClassPath() {
1149   std::lock_guard<std::mutex> lock(cache_mu_);
1150 
1151   if (!cached_boot_class_path_.has_value()) {
1152     const char* env_value = getenv("BOOTCLASSPATH");
1153     if (env_value == nullptr || strlen(env_value) == 0) {
1154       return Errorf("Failed to get environment variable 'BOOTCLASSPATH'");
1155     }
1156     cached_boot_class_path_ = Split(env_value, ":");
1157   }
1158 
1159   return &cached_boot_class_path_.value();
1160 }
1161 
UseJitZygote()1162 bool Artd::UseJitZygote() {
1163   std::lock_guard<std::mutex> lock(cache_mu_);
1164   return UseJitZygoteLocked();
1165 }
1166 
UseJitZygoteLocked()1167 bool Artd::UseJitZygoteLocked() {
1168   if (!cached_use_jit_zygote_.has_value()) {
1169     cached_use_jit_zygote_ =
1170         props_->GetBool("persist.device_config.runtime_native_boot.profilebootclasspath",
1171                         "dalvik.vm.profilebootclasspath",
1172                         /*default_value=*/false);
1173   }
1174 
1175   return cached_use_jit_zygote_.value();
1176 }
1177 
GetUserDefinedBootImageLocations()1178 const std::string& Artd::GetUserDefinedBootImageLocations() {
1179   std::lock_guard<std::mutex> lock(cache_mu_);
1180   return GetUserDefinedBootImageLocationsLocked();
1181 }
1182 
GetUserDefinedBootImageLocationsLocked()1183 const std::string& Artd::GetUserDefinedBootImageLocationsLocked() {
1184   if (!cached_user_defined_boot_image_locations_.has_value()) {
1185     cached_user_defined_boot_image_locations_ = props_->GetOrEmpty("dalvik.vm.boot-image");
1186   }
1187 
1188   return cached_user_defined_boot_image_locations_.value();
1189 }
1190 
DenyArtApexDataFiles()1191 bool Artd::DenyArtApexDataFiles() {
1192   std::lock_guard<std::mutex> lock(cache_mu_);
1193   return DenyArtApexDataFilesLocked();
1194 }
1195 
DenyArtApexDataFilesLocked()1196 bool Artd::DenyArtApexDataFilesLocked() {
1197   if (!cached_deny_art_apex_data_files_.has_value()) {
1198     cached_deny_art_apex_data_files_ =
1199         !props_->GetBool("odsign.verification.success", /*default_value=*/false);
1200   }
1201 
1202   return cached_deny_art_apex_data_files_.value();
1203 }
1204 
GetProfman()1205 Result<std::string> Artd::GetProfman() { return BuildArtBinPath("profman"); }
1206 
GetArtExec()1207 Result<std::string> Artd::GetArtExec() { return BuildArtBinPath("art_exec"); }
1208 
ShouldUseDex2Oat64()1209 bool Artd::ShouldUseDex2Oat64() {
1210   return !props_->GetOrEmpty("ro.product.cpu.abilist64").empty() &&
1211          props_->GetBool("dalvik.vm.dex2oat64.enabled", /*default_value=*/false);
1212 }
1213 
GetDex2Oat()1214 Result<std::string> Artd::GetDex2Oat() {
1215   std::string binary_name = ShouldUseDex2Oat64() ? "dex2oat64" : "dex2oat32";
1216   // TODO(b/234351700): Should we use the "d" variant?
1217   return BuildArtBinPath(binary_name);
1218 }
1219 
ShouldCreateSwapFileForDexopt()1220 bool Artd::ShouldCreateSwapFileForDexopt() {
1221   // Create a swap file by default. Dex2oat will decide whether to use it or not.
1222   return props_->GetBool("dalvik.vm.dex2oat-swap", /*default_value=*/true);
1223 }
1224 
AddBootImageFlags(CmdlineBuilder & args)1225 void Artd::AddBootImageFlags(/*out*/ CmdlineBuilder& args) {
1226   if (UseJitZygote()) {
1227     args.Add("--force-jit-zygote");
1228   } else {
1229     args.AddIfNonEmpty("--boot-image=%s", GetUserDefinedBootImageLocations());
1230   }
1231 }
1232 
AddCompilerConfigFlags(const std::string & instruction_set,const std::string & compiler_filter,PriorityClass priority_class,const DexoptOptions & dexopt_options,CmdlineBuilder & args)1233 void Artd::AddCompilerConfigFlags(const std::string& instruction_set,
1234                                   const std::string& compiler_filter,
1235                                   PriorityClass priority_class,
1236                                   const DexoptOptions& dexopt_options,
1237                                   /*out*/ CmdlineBuilder& args) {
1238   args.Add("--instruction-set=%s", instruction_set);
1239   std::string features_prop = "dalvik.vm.isa.{}.features"_format(instruction_set);
1240   args.AddIfNonEmpty("--instruction-set-features=%s", props_->GetOrEmpty(features_prop));
1241   std::string variant_prop = "dalvik.vm.isa.{}.variant"_format(instruction_set);
1242   args.AddIfNonEmpty("--instruction-set-variant=%s", props_->GetOrEmpty(variant_prop));
1243 
1244   args.Add("--compiler-filter=%s", compiler_filter)
1245       .Add("--compilation-reason=%s", dexopt_options.compilationReason);
1246 
1247   args.AddIf(priority_class >= PriorityClass::INTERACTIVE, "--compact-dex-level=none");
1248 
1249   args.AddIfNonEmpty("--max-image-block-size=%s",
1250                      props_->GetOrEmpty("dalvik.vm.dex2oat-max-image-block-size"))
1251       .AddIfNonEmpty("--very-large-app-threshold=%s",
1252                      props_->GetOrEmpty("dalvik.vm.dex2oat-very-large"))
1253       .AddIfNonEmpty(
1254           "--resolve-startup-const-strings=%s",
1255           props_->GetOrEmpty("persist.device_config.runtime.dex2oat_resolve_startup_strings",
1256                              "dalvik.vm.dex2oat-resolve-startup-strings"));
1257 
1258   args.AddIf(dexopt_options.debuggable, "--debuggable")
1259       .AddIf(props_->GetBool("debug.generate-debug-info", /*default_value=*/false),
1260              "--generate-debug-info")
1261       .AddIf(props_->GetBool("dalvik.vm.dex2oat-minidebuginfo", /*default_value=*/false),
1262              "--generate-mini-debug-info");
1263 
1264   args.AddRuntimeIf(DenyArtApexDataFiles(), "-Xdeny-art-apex-data-files")
1265       .AddRuntime("-Xtarget-sdk-version:%d", dexopt_options.targetSdkVersion)
1266       .AddRuntimeIf(dexopt_options.hiddenApiPolicyEnabled, "-Xhidden-api-policy:enabled");
1267 }
1268 
AddPerfConfigFlags(PriorityClass priority_class,CmdlineBuilder & art_exec_args,CmdlineBuilder & dex2oat_args)1269 void Artd::AddPerfConfigFlags(PriorityClass priority_class,
1270                               /*out*/ CmdlineBuilder& art_exec_args,
1271                               /*out*/ CmdlineBuilder& dex2oat_args) {
1272   // CPU set and number of threads.
1273   std::string default_cpu_set_prop = "dalvik.vm.dex2oat-cpu-set";
1274   std::string default_threads_prop = "dalvik.vm.dex2oat-threads";
1275   std::string cpu_set;
1276   std::string threads;
1277   if (priority_class >= PriorityClass::BOOT) {
1278     cpu_set = props_->GetOrEmpty("dalvik.vm.boot-dex2oat-cpu-set");
1279     threads = props_->GetOrEmpty("dalvik.vm.boot-dex2oat-threads");
1280   } else if (priority_class >= PriorityClass::INTERACTIVE_FAST) {
1281     cpu_set = props_->GetOrEmpty("dalvik.vm.restore-dex2oat-cpu-set", default_cpu_set_prop);
1282     threads = props_->GetOrEmpty("dalvik.vm.restore-dex2oat-threads", default_threads_prop);
1283   } else if (priority_class <= PriorityClass::BACKGROUND) {
1284     cpu_set = props_->GetOrEmpty("dalvik.vm.background-dex2oat-cpu-set", default_cpu_set_prop);
1285     threads = props_->GetOrEmpty("dalvik.vm.background-dex2oat-threads", default_threads_prop);
1286   } else {
1287     cpu_set = props_->GetOrEmpty(default_cpu_set_prop);
1288     threads = props_->GetOrEmpty(default_threads_prop);
1289   }
1290   dex2oat_args.AddIfNonEmpty("--cpu-set=%s", cpu_set).AddIfNonEmpty("-j%s", threads);
1291 
1292   if (priority_class < PriorityClass::BOOT) {
1293     art_exec_args
1294         .Add(priority_class <= PriorityClass::BACKGROUND ? "--set-task-profile=Dex2OatBackground" :
1295                                                            "--set-task-profile=Dex2OatBootComplete")
1296         .Add("--set-priority=background");
1297   }
1298 
1299   dex2oat_args.AddRuntimeIfNonEmpty("-Xms%s", props_->GetOrEmpty("dalvik.vm.dex2oat-Xms"))
1300       .AddRuntimeIfNonEmpty("-Xmx%s", props_->GetOrEmpty("dalvik.vm.dex2oat-Xmx"));
1301 
1302   // Enable compiling dex files in isolation on low ram devices.
1303   // It takes longer but reduces the memory footprint.
1304   dex2oat_args.AddIf(props_->GetBool("ro.config.low_ram", /*default_value=*/false),
1305                      "--compile-individually");
1306 }
1307 
ExecAndReturnCode(const std::vector<std::string> & args,int timeout_sec,const ExecCallbacks & callbacks,ProcessStat * stat) const1308 Result<int> Artd::ExecAndReturnCode(const std::vector<std::string>& args,
1309                                     int timeout_sec,
1310                                     const ExecCallbacks& callbacks,
1311                                     ProcessStat* stat) const {
1312   std::string error_msg;
1313   ExecResult result =
1314       exec_utils_->ExecAndReturnResult(args, timeout_sec, callbacks, stat, &error_msg);
1315   if (result.status != ExecResult::kExited) {
1316     return Error() << error_msg;
1317   }
1318   return result.exit_code;
1319 }
1320 
Fstat(const File & file) const1321 Result<struct stat> Artd::Fstat(const File& file) const {
1322   struct stat st;
1323   if (fstat_(file.Fd(), &st) != 0) {
1324     return Errorf("Unable to fstat file '{}'", file.GetPath());
1325   }
1326   return st;
1327 }
1328 
1329 }  // namespace artd
1330 }  // namespace art
1331