• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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/types.h>
23 #include <unistd.h>
24 
25 #include <algorithm>
26 #include <chrono>
27 #include <condition_variable>
28 #include <csignal>
29 #include <cstdint>
30 #include <cstdio>
31 #include <cstring>
32 #include <filesystem>
33 #include <functional>
34 #include <memory>
35 #include <mutex>
36 #include <optional>
37 #include <string>
38 #include <thread>
39 #include <tuple>
40 #include <type_traits>
41 #include <utility>
42 #include <vector>
43 
44 #include "aidl/com/android/server/art/ArtConstants.h"
45 #include "aidl/com/android/server/art/BnArtd.h"
46 #include "aidl/com/android/server/art/OutputArtifacts.h"
47 #include "android-base/collections.h"
48 #include "android-base/errors.h"
49 #include "android-base/file.h"
50 #include "android-base/logging.h"
51 #include "android-base/parseint.h"
52 #include "android-base/result-gmock.h"
53 #include "android-base/result.h"
54 #include "android-base/scopeguard.h"
55 #include "android-base/strings.h"
56 #include "android/binder_auto_utils.h"
57 #include "android/binder_status.h"
58 #include "base/array_ref.h"
59 #include "base/common_art_test.h"
60 #include "base/macros.h"
61 #include "base/pidfd.h"
62 #include "base/time_utils.h"
63 #include "exec_utils.h"
64 #include "file_utils.h"
65 #include "gmock/gmock.h"
66 #include "gtest/gtest.h"
67 #include "oat/oat_file.h"
68 #include "path_utils.h"
69 #include "profile/profile_compilation_info.cc"
70 #include "profman/profman_result.h"
71 #include "testing.h"
72 #include "tools/binder_utils.h"
73 #include "tools/system_properties.h"
74 #include "tools/testing.h"
75 #include "vdex_file.h"
76 #include "ziparchive/zip_writer.h"
77 
78 extern char** environ;
79 
80 namespace art {
81 namespace artd {
82 namespace {
83 
84 using ::aidl::com::android::server::art::ArtConstants;
85 using ::aidl::com::android::server::art::ArtdDexoptResult;
86 using ::aidl::com::android::server::art::ArtifactsPath;
87 using ::aidl::com::android::server::art::CopyAndRewriteProfileResult;
88 using ::aidl::com::android::server::art::DexMetadataPath;
89 using ::aidl::com::android::server::art::DexoptOptions;
90 using ::aidl::com::android::server::art::FileVisibility;
91 using ::aidl::com::android::server::art::FsPermission;
92 using ::aidl::com::android::server::art::IArtdCancellationSignal;
93 using ::aidl::com::android::server::art::IArtdNotification;
94 using ::aidl::com::android::server::art::OutputArtifacts;
95 using ::aidl::com::android::server::art::OutputProfile;
96 using ::aidl::com::android::server::art::PriorityClass;
97 using ::aidl::com::android::server::art::ProfilePath;
98 using ::aidl::com::android::server::art::RuntimeArtifactsPath;
99 using ::aidl::com::android::server::art::SecureDexMetadataWithCompanionPaths;
100 using ::aidl::com::android::server::art::VdexPath;
101 using ::android::base::Append;
102 using ::android::base::Dirname;
103 using ::android::base::Error;
104 using ::android::base::make_scope_guard;
105 using ::android::base::ParseInt;
106 using ::android::base::ReadFdToString;
107 using ::android::base::ReadFileToString;
108 using ::android::base::Result;
109 using ::android::base::ScopeGuard;
110 using ::android::base::Split;
111 using ::android::base::WriteStringToFd;
112 using ::android::base::WriteStringToFile;
113 using ::android::base::testing::HasValue;
114 using ::art::tools::GetBin;
115 using ::art::tools::ScopedExec;
116 using ::testing::_;
117 using ::testing::AllOf;
118 using ::testing::AnyNumber;
119 using ::testing::AnyOf;
120 using ::testing::Contains;
121 using ::testing::ContainsRegex;
122 using ::testing::DoAll;
123 using ::testing::ElementsAre;
124 using ::testing::Field;
125 using ::testing::HasSubstr;
126 using ::testing::InSequence;
127 using ::testing::IsEmpty;
128 using ::testing::Matcher;
129 using ::testing::MockFunction;
130 using ::testing::NiceMock;
131 using ::testing::Not;
132 using ::testing::Property;
133 using ::testing::ResultOf;
134 using ::testing::Return;
135 using ::testing::SetArgPointee;
136 using ::testing::StartsWith;
137 using ::testing::StrEq;
138 using ::testing::UnorderedElementsAreArray;
139 using ::testing::WithArg;
140 
141 using PermissionSettings = OutputArtifacts::PermissionSettings;
142 using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
143 using PrimaryRefProfilePath = ProfilePath::PrimaryRefProfilePath;
144 using TmpProfilePath = ProfilePath::TmpProfilePath;
145 using WritableProfilePath = ProfilePath::WritableProfilePath;
146 
147 using std::literals::operator""s;  // NOLINT
148 
149 // User build is missing the SELinux permission for the test process (run as `shell`) to reopen
150 // the memfd that it creates itself
151 // (https://cs.android.com/android/platform/superproject/main/+/main:system/sepolicy/private/shell.te;l=221;drc=3335a04676d400bda57d42d4af0ef4b1d311de21).
152 #define TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS() TEST_DISABLED_FOR_USER_BUILD()
153 
ScopedSetLogger(android::base::LogFunction && logger)154 ScopeGuard<std::function<void()>> ScopedSetLogger(android::base::LogFunction&& logger) {
155   android::base::LogFunction old_logger = android::base::SetLogger(std::move(logger));
156   return make_scope_guard([old_logger = std::move(old_logger)]() mutable {
157     android::base::SetLogger(std::move(old_logger));
158   });
159 }
160 
CheckContent(const std::string & path,const Matcher<std::string> & expected_content_matcher)161 void CheckContent(const std::string& path, const Matcher<std::string>& expected_content_matcher) {
162   std::string actual_content;
163   ASSERT_TRUE(ReadFileToString(path, &actual_content));
164   EXPECT_THAT(actual_content, expected_content_matcher);
165 }
166 
CheckOtherReadable(const std::string & path,bool expected_value)167 void CheckOtherReadable(const std::string& path, bool expected_value) {
168   EXPECT_EQ((std::filesystem::status(path).permissions() & std::filesystem::perms::others_read) !=
169                 std::filesystem::perms::none,
170             expected_value);
171 }
172 
GetFlagValues(ArrayRef<const std::string> args,std::string_view flag)173 Result<std::vector<std::string>> GetFlagValues(ArrayRef<const std::string> args,
174                                                std::string_view flag) {
175   std::vector<std::string> values;
176   for (const std::string& arg : args) {
177     std::string_view value(arg);
178     if (android::base::ConsumePrefix(&value, flag)) {
179       values.emplace_back(value);
180     }
181   }
182   if (values.empty()) {
183     return Errorf("Flag '{}' not found", flag);
184   }
185   return values;
186 }
187 
GetFlagValue(ArrayRef<const std::string> args,std::string_view flag)188 Result<std::string> GetFlagValue(ArrayRef<const std::string> args, std::string_view flag) {
189   std::vector<std::string> flag_values = OR_RETURN(GetFlagValues(args, flag));
190   if (flag_values.size() > 1) {
191     return Errorf("Duplicate flag '{}'", flag);
192   }
193   return flag_values[0];
194 }
195 
WriteToFdFlagImpl(const std::vector<std::string> & args,std::string_view flag,std::string_view content,bool assume_empty)196 void WriteToFdFlagImpl(const std::vector<std::string>& args,
197                        std::string_view flag,
198                        std::string_view content,
199                        bool assume_empty) {
200   std::string value = OR_FAIL(GetFlagValue(ArrayRef<const std::string>(args), flag));
201   ASSERT_NE(value, "");
202   int fd;
203   ASSERT_TRUE(ParseInt(value, &fd));
204   if (assume_empty) {
205     ASSERT_EQ(lseek(fd, /*offset=*/0, SEEK_CUR), 0);
206   } else {
207     ASSERT_EQ(ftruncate(fd, /*length=*/0), 0);
208     ASSERT_EQ(lseek(fd, /*offset=*/0, SEEK_SET), 0);
209   }
210   ASSERT_TRUE(WriteStringToFd(content, fd));
211 }
212 
213 // Writes `content` to the FD specified by the `flag`.
ACTION_P(WriteToFdFlag,flag,content)214 ACTION_P(WriteToFdFlag, flag, content) {
215   WriteToFdFlagImpl(arg0, flag, content, /*assume_empty=*/true);
216 }
217 
218 // Clears any existing content and writes `content` to the FD specified by the `flag`.
ACTION_P(ClearAndWriteToFdFlag,flag,content)219 ACTION_P(ClearAndWriteToFdFlag, flag, content) {
220   WriteToFdFlagImpl(arg0, flag, content, /*assume_empty=*/false);
221 }
222 
223 // Matches a flag that starts with `flag` and whose value matches `matcher`.
224 MATCHER_P2(Flag, flag, matcher, "") {
225   std::string_view value(arg);
226   if (!android::base::ConsumePrefix(&value, flag)) {
227     return false;
228   }
229   return ExplainMatchResult(matcher, std::string(value), result_listener);
230 }
231 
232 // Matches a flag that starts with `flag` and whose value is a colon-separated list that matches
233 // `matcher`. The matcher acts on an `std::vector<std::string>` of the split list argument.
234 MATCHER_P2(ListFlag, flag, matcher, "") {
235   return ExplainMatchResult(
236       Flag(flag, ResultOf(std::bind(Split, std::placeholders::_1, ":"), matcher)),
237       arg,
238       result_listener);
239 }
240 
241 // Matches an FD of a file whose path matches `matcher`.
242 MATCHER_P(FdOf, matcher, "") {
243   std::string proc_path = ART_FORMAT("/proc/self/fd/{}", arg);
244   char path[PATH_MAX];
245   ssize_t len = readlink(proc_path.c_str(), path, sizeof(path));
246   if (len < 0) {
247     return false;
248   }
249   return ExplainMatchResult(matcher, std::string(path, static_cast<size_t>(len)), result_listener);
250 }
251 
252 // Matches an FD of a file whose content matches `matcher`.
253 MATCHER_P(FdHasContent, matcher, "") {
254   int fd;
255   if (!ParseInt(arg, &fd)) {
256     return false;
257   }
258   std::string actual_content;
259   if (!ReadFdToString(fd, &actual_content)) {
260     return false;
261   }
262   return ExplainMatchResult(matcher, actual_content, result_listener);
263 }
264 
265 template <typename T, typename U>
SplitBy(const std::vector<T> & list,const U & separator)266 Result<std::pair<ArrayRef<const T>, ArrayRef<const T>>> SplitBy(const std::vector<T>& list,
267                                                                 const U& separator) {
268   auto it = std::find(list.begin(), list.end(), separator);
269   if (it == list.end()) {
270     return Errorf("'{}' not found", separator);
271   }
272   size_t pos = it - list.begin();
273   return std::make_pair(ArrayRef<const T>(list).SubArray(0, pos),
274                         ArrayRef<const T>(list).SubArray(pos + 1));
275 }
276 
277 // Matches a container that, when split by `separator`, the first part matches `head_matcher`, and
278 // the second part matches `tail_matcher`.
279 MATCHER_P3(WhenSplitBy, separator, head_matcher, tail_matcher, "") {
280   auto [head, tail] = OR_MISMATCH(SplitBy(arg, separator));
281   return ExplainMatchResult(head_matcher, head, result_listener) &&
282          ExplainMatchResult(tail_matcher, tail, result_listener);
283 }
284 
285 MATCHER_P(HasKeepFdsForImpl, fd_flags, "") {
286   auto [head, tail] = OR_MISMATCH(SplitBy(arg, "--"));
287   std::string keep_fds_value = OR_MISMATCH(GetFlagValue(head, "--keep-fds="));
288   std::vector<std::string> keep_fds = Split(keep_fds_value, ":");
289   std::vector<std::string> fd_flag_values;
290   for (std::string_view fd_flag : fd_flags) {
291     for (const std::string& fd_flag_value : OR_MISMATCH(GetFlagValues(tail, fd_flag))) {
292       for (std::string& fd : Split(fd_flag_value, ":")) {
293         fd_flag_values.push_back(std::move(fd));
294       }
295     }
296   }
297   return ExplainMatchResult(UnorderedElementsAreArray(fd_flag_values), keep_fds, result_listener);
298 }
299 
300 // Matches an argument list that has the "--keep-fds=" flag before "--", whose value is a
301 // semicolon-separated list that contains exactly the values of the given flags after "--".
302 //
303 // E.g., if the flags after "--" are "--foo=1", "--bar=2:3", "--baz=4", "--baz=5", and the matcher
304 // is `HasKeepFdsFor("--foo=", "--bar=", "--baz=")`, then it requires the "--keep-fds=" flag before
305 // "--" to contain exactly 1, 2, 3, 4, and 5.
306 template <typename... Args>
HasKeepFdsFor(Args &&...args)307 auto HasKeepFdsFor(Args&&... args) {
308   std::vector<std::string_view> fd_flags;
309   Append(fd_flags, std::forward<Args>(args)...);
310   return HasKeepFdsForImpl(fd_flags);
311 }
312 
313 class MockSystemProperties : public tools::SystemProperties {
314  public:
315   MOCK_METHOD(std::string, GetProperty, (const std::string& key), (const, override));
316 };
317 
318 class MockExecUtils : public ExecUtils {
319  public:
320   // A workaround to avoid MOCK_METHOD on a method with an `std::string*` parameter, which will lead
321   // to a conflict between gmock and android-base/logging.h (b/132668253).
ExecAndReturnResult(const std::vector<std::string> & arg_vector,int,const ExecCallbacks & callbacks,bool,ProcessStat * stat,std::string *) const322   ExecResult ExecAndReturnResult(const std::vector<std::string>& arg_vector,
323                                  int,
324                                  const ExecCallbacks& callbacks,
325                                  bool,
326                                  ProcessStat* stat,
327                                  std::string*) const override {
328     Result<int> code = DoExecAndReturnCode(arg_vector, callbacks, stat);
329     if (code.ok()) {
330       return {.status = ExecResult::kExited, .exit_code = code.value()};
331     } else {
332       return {.status = ExecResult::kSignaled, .signal = SIGKILL};
333     }
334   }
335 
336   MOCK_METHOD(Result<int>,
337               DoExecAndReturnCode,
338               (const std::vector<std::string>& arg_vector,
339                const ExecCallbacks& callbacks,
340                ProcessStat* stat),
341               (const));
342 };
343 
344 class ArtdTest : public CommonArtTest {
345  protected:
SetUp()346   void SetUp() override {
347     CommonArtTest::SetUp();
348     auto mock_props = std::make_unique<MockSystemProperties>();
349     mock_props_ = mock_props.get();
350     EXPECT_CALL(*mock_props_, GetProperty).Times(AnyNumber()).WillRepeatedly(Return(""));
351     auto mock_exec_utils = std::make_unique<MockExecUtils>();
352     mock_exec_utils_ = mock_exec_utils.get();
353     artd_ = ndk::SharedRefBase::make<Artd>(Options(),
354                                            std::move(mock_props),
355                                            std::move(mock_exec_utils),
356                                            mock_kill_.AsStdFunction(),
357                                            mock_fstat_.AsStdFunction(),
358                                            mock_poll_.AsStdFunction());
359     scratch_dir_ = std::make_unique<ScratchDir>();
360     scratch_path_ = scratch_dir_->GetPath();
361     // Remove the trailing '/';
362     scratch_path_.resize(scratch_path_.length() - 1);
363 
364     TestOnlySetListRootDir(scratch_path_);
365 
366     ON_CALL(mock_fstat_, Call).WillByDefault(fstat);
367 
368     // Use an arbitrary existing directory as ART root.
369     art_root_ = scratch_path_ + "/com.android.art";
370     std::filesystem::create_directories(art_root_);
371     setenv("ANDROID_ART_ROOT", art_root_.c_str(), /*overwrite=*/1);
372 
373     // Use an arbitrary existing directory as Android data.
374     android_data_ = scratch_path_ + "/data";
375     std::filesystem::create_directories(android_data_);
376     setenv("ANDROID_DATA", android_data_.c_str(), /*overwrite=*/1);
377 
378     // Use an arbitrary existing directory as Android expand.
379     android_expand_ = scratch_path_ + "/mnt/expand";
380     std::filesystem::create_directories(android_expand_);
381     setenv("ANDROID_EXPAND", android_expand_.c_str(), /*overwrite=*/1);
382 
383     dex_file_ = scratch_path_ + "/a/b.apk";
384     isa_ = "arm64";
385     artifacts_path_ = ArtifactsPath{
386         .dexPath = dex_file_,
387         .isa = isa_,
388         .isInDalvikCache = false,
389     };
390     struct stat st;
391     ASSERT_EQ(stat(scratch_path_.c_str(), &st), 0);
392     permission_settings_ = {
393         .dirFsPermission =
394             FsPermission{
395                 .uid = static_cast<int32_t>(st.st_uid),
396                 .gid = static_cast<int32_t>(st.st_gid),
397                 .isOtherReadable = true,
398                 .isOtherExecutable = true,
399             },
400         .fileFsPermission =
401             FsPermission{
402                 .uid = static_cast<int32_t>(st.st_uid),
403                 .gid = static_cast<int32_t>(st.st_gid),
404                 .isOtherReadable = true,
405             },
406     };
407     output_artifacts_ = OutputArtifacts{
408         .artifactsPath = artifacts_path_,
409         .permissionSettings = permission_settings_,
410     };
411     clc_1_ = GetTestDexFileName("Main");
412     clc_2_ = GetTestDexFileName("Nested");
413     class_loader_context_ = ART_FORMAT("PCL[{}:{}]", clc_1_, clc_2_);
414     compiler_filter_ = "speed";
415     tmp_profile_path_ =
416         TmpProfilePath{.finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
417                                                           .profileName = "primary",
418                                                           .isPreReboot = false},
419                        .id = "12345"};
420     profile_path_ = tmp_profile_path_;
421     vdex_path_ = artifacts_path_;
422     dm_path_ = DexMetadataPath{.dexPath = dex_file_};
423     std::filesystem::create_directories(
424         std::filesystem::path(OR_FATAL(BuildFinalProfilePath(tmp_profile_path_))).parent_path());
425 
426     sdm_sdc_paths_ = {
427         .dexPath = dex_file_,
428         .isa = isa_,
429         .isInDalvikCache = false,
430     };
431   }
432 
TearDown()433   void TearDown() override {
434     scratch_dir_.reset();
435     CommonArtTest::TearDown();
436   }
437 
RunDexopt(binder_exception_t expected_status=EX_NONE,Matcher<ArtdDexoptResult> aidl_return_matcher=Field (& ArtdDexoptResult::cancelled,false),std::shared_ptr<IArtdCancellationSignal> cancellation_signal=nullptr)438   void RunDexopt(binder_exception_t expected_status = EX_NONE,
439                  Matcher<ArtdDexoptResult> aidl_return_matcher = Field(&ArtdDexoptResult::cancelled,
440                                                                        false),
441                  std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) {
442     RunDexopt(Property(&ndk::ScopedAStatus::getExceptionCode, expected_status),
443               std::move(aidl_return_matcher),
444               std::move(cancellation_signal));
445   }
446 
RunDexopt(Matcher<ndk::ScopedAStatus> status_matcher,Matcher<ArtdDexoptResult> aidl_return_matcher=Field (& ArtdDexoptResult::cancelled,false),std::shared_ptr<IArtdCancellationSignal> cancellation_signal=nullptr)447   void RunDexopt(Matcher<ndk::ScopedAStatus> status_matcher,
448                  Matcher<ArtdDexoptResult> aidl_return_matcher = Field(&ArtdDexoptResult::cancelled,
449                                                                        false),
450                  std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) {
451     InitFilesBeforeDexopt();
452     if (cancellation_signal == nullptr) {
453       ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
454     }
455     ArtdDexoptResult aidl_return;
456     ndk::ScopedAStatus status = artd_->dexopt(output_artifacts_,
457                                               dex_file_,
458                                               isa_,
459                                               class_loader_context_,
460                                               compiler_filter_,
461                                               profile_path_,
462                                               vdex_path_,
463                                               dm_path_,
464                                               priority_class_,
465                                               dexopt_options_,
466                                               cancellation_signal,
467                                               &aidl_return);
468     ASSERT_THAT(status, std::move(status_matcher)) << status.getMessage();
469     if (status.isOk()) {
470       ASSERT_THAT(aidl_return, std::move(aidl_return_matcher));
471     }
472   }
473 
474   template <bool kExpectOk>
475   using RunCopyAndRewriteProfileResult = Result<
476       std::pair<std::conditional_t<kExpectOk, CopyAndRewriteProfileResult, ndk::ScopedAStatus>,
477                 OutputProfile>>;
478 
479   // Runs `copyAndRewriteProfile` with `profile_path_` and `dex_file_`.
480   template <bool kExpectOk = true>
RunCopyAndRewriteProfile()481   RunCopyAndRewriteProfileResult<kExpectOk> RunCopyAndRewriteProfile() {
482     OutputProfile dst{.profilePath = tmp_profile_path_,
483                       .fsPermission = FsPermission{.uid = -1, .gid = -1}};
484     dst.profilePath.id = "";
485     dst.profilePath.tmpPath = "";
486 
487     CopyAndRewriteProfileResult result;
488     ndk::ScopedAStatus status =
489         artd_->copyAndRewriteProfile(profile_path_.value(), &dst, dex_file_, &result);
490     if constexpr (kExpectOk) {
491       if (!status.isOk()) {
492         return Error() << status.getMessage();
493       }
494       return std::make_pair(std::move(result), std::move(dst));
495     } else {
496       return std::make_pair(std::move(status), std::move(dst));
497     }
498   }
499 
500   // Runs `copyAndRewriteEmbeddedProfile` with `dex_file_`.
501   template <bool kExpectOk = true>
RunCopyAndRewriteEmbeddedProfile()502   RunCopyAndRewriteProfileResult<kExpectOk> RunCopyAndRewriteEmbeddedProfile() {
503     OutputProfile dst{.profilePath = tmp_profile_path_,
504                       .fsPermission = FsPermission{.uid = -1, .gid = -1}};
505     dst.profilePath.id = "";
506     dst.profilePath.tmpPath = "";
507 
508     CopyAndRewriteProfileResult result;
509     ndk::ScopedAStatus status = artd_->copyAndRewriteEmbeddedProfile(&dst, dex_file_, &result);
510     if constexpr (kExpectOk) {
511       if (!status.isOk()) {
512         return Error() << status.getMessage();
513       }
514       return std::make_pair(std::move(result), std::move(dst));
515     } else {
516       return std::make_pair(std::move(status), std::move(dst));
517     }
518   }
519 
CreateFile(const std::string & filename,const std::string & content="")520   void CreateFile(const std::string& filename, const std::string& content = "") {
521     std::filesystem::path path(filename);
522     std::filesystem::create_directories(path.parent_path());
523     ASSERT_TRUE(WriteStringToFile(content, filename));
524   }
525 
CreateZipWithSingleEntry(const std::string & filename,const std::string & entry_name,const std::string & content="")526   void CreateZipWithSingleEntry(const std::string& filename,
527                                 const std::string& entry_name,
528                                 const std::string& content = "") {
529     std::filesystem::path path(filename);
530     std::filesystem::create_directories(path.parent_path());
531     std::unique_ptr<File> file(OS::CreateEmptyFileWriteOnly(filename.c_str()));
532     ASSERT_NE(file, nullptr) << strerror(errno);
533     file->MarkUnchecked();  // `writer.Finish()` flushes the file and the destructor closes it.
534     ZipWriter writer(fdopen(file->Fd(), "wb"));
535     ASSERT_EQ(writer.StartEntry(entry_name, /*flags=*/0), 0);
536     ASSERT_EQ(writer.WriteBytes(content.c_str(), content.size()), 0);
537     ASSERT_EQ(writer.FinishEntry(), 0);
538     ASSERT_EQ(writer.Finish(), 0);
539   }
540 
541   std::shared_ptr<Artd> artd_;
542   std::unique_ptr<ScratchDir> scratch_dir_;
543   std::string scratch_path_;
544   std::string art_root_;
545   std::string android_data_;
546   std::string android_expand_;
547   MockFunction<android::base::LogFunction> mock_logger_;
548   ScopedUnsetEnvironmentVariable art_root_env_ = ScopedUnsetEnvironmentVariable("ANDROID_ART_ROOT");
549   ScopedUnsetEnvironmentVariable android_data_env_ = ScopedUnsetEnvironmentVariable("ANDROID_DATA");
550   ScopedUnsetEnvironmentVariable android_expand_env_ =
551       ScopedUnsetEnvironmentVariable("ANDROID_EXPAND");
552   MockSystemProperties* mock_props_;
553   MockExecUtils* mock_exec_utils_;
554   MockFunction<KillFn> mock_kill_;
555   MockFunction<FstatFn> mock_fstat_;
556   MockFunction<PollFn> mock_poll_;
557 
558   std::string dex_file_;
559   std::string isa_;
560   ArtifactsPath artifacts_path_;
561   PermissionSettings permission_settings_;
562   OutputArtifacts output_artifacts_;
563   std::string clc_1_;
564   std::string clc_2_;
565   std::optional<std::string> class_loader_context_;
566   std::string compiler_filter_;
567   std::optional<VdexPath> vdex_path_;
568   std::optional<DexMetadataPath> dm_path_;
569   PriorityClass priority_class_ = PriorityClass::BACKGROUND;
570   DexoptOptions dexopt_options_;
571   std::optional<ProfilePath> profile_path_;
572   TmpProfilePath tmp_profile_path_;
573   bool dex_file_other_readable_ = true;
574   bool profile_other_readable_ = true;
575 
576   SecureDexMetadataWithCompanionPaths sdm_sdc_paths_;
577 
578  private:
InitFilesBeforeDexopt()579   void InitFilesBeforeDexopt() {
580     // Required files.
581     CreateFile(dex_file_);
582     std::filesystem::permissions(dex_file_,
583                                  std::filesystem::perms::others_read,
584                                  dex_file_other_readable_ ? std::filesystem::perm_options::add :
585                                                             std::filesystem::perm_options::remove);
586 
587     // Optional files.
588     if (vdex_path_.has_value()) {
589       CreateFile(OR_FATAL(BuildVdexPath(vdex_path_.value())), "old_vdex");
590     }
591     if (dm_path_.has_value()) {
592       CreateFile(OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
593     }
594     if (profile_path_.has_value()) {
595       std::string path = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
596       CreateFile(path);
597       std::filesystem::permissions(path,
598                                    std::filesystem::perms::others_read,
599                                    profile_other_readable_ ? std::filesystem::perm_options::add :
600                                                              std::filesystem::perm_options::remove);
601     }
602 
603     // Files to be replaced.
604     RawArtifactsPath artifacts_path = OR_FATAL(BuildArtifactsPath(artifacts_path_));
605     CreateFile(artifacts_path.oat_path, "old_oat");
606     CreateFile(artifacts_path.vdex_path, "old_vdex");
607     CreateFile(artifacts_path.art_path, "old_art");
608   }
609 };
610 
TEST_F(ArtdTest,ConstantsAreInSync)611 TEST_F(ArtdTest, ConstantsAreInSync) {
612   EXPECT_STREQ(ArtConstants::REASON_VDEX, kReasonVdex);
613   EXPECT_STREQ(ArtConstants::DEX_METADATA_FILE_EXT, kDmExtension);
614   EXPECT_STREQ(ArtConstants::SECURE_DEX_METADATA_FILE_EXT, kSdmExtension);
615   EXPECT_STREQ(ArtConstants::DEX_METADATA_PROFILE_ENTRY,
616                ProfileCompilationInfo::kDexMetadataProfileEntry);
617   EXPECT_STREQ(ArtConstants::DEX_METADATA_VDEX_ENTRY, VdexFile::kVdexNameInDmFile);
618 }
619 
TEST_F(ArtdTest,isAlive)620 TEST_F(ArtdTest, isAlive) {
621   bool result = false;
622   artd_->isAlive(&result);
623   EXPECT_TRUE(result);
624 }
625 
TEST_F(ArtdTest,deleteArtifacts)626 TEST_F(ArtdTest, deleteArtifacts) {
627   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
628   std::filesystem::create_directories(oat_dir);
629   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex"));  // 4 bytes.
630   ASSERT_TRUE(WriteStringToFile("ab", oat_dir + "/b.vdex"));    // 2 bytes.
631   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art"));      // 1 byte.
632 
633   int64_t result = -1;
634   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
635   EXPECT_EQ(result, 4 + 2 + 1);
636 
637   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.odex"));
638   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.vdex"));
639   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.art"));
640 }
641 
TEST_F(ArtdTest,deleteArtifactsMissingFile)642 TEST_F(ArtdTest, deleteArtifactsMissingFile) {
643   // Missing VDEX file.
644   std::string oat_dir = android_data_ + "/dalvik-cache/arm64";
645   std::filesystem::create_directories(oat_dir);
646   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/a@b.apk@classes.dex"));  // 4 bytes.
647   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/a@b.apk@classes.art"));     // 1 byte.
648 
649   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
650   EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(0);
651 
652   int64_t result = -1;
653   EXPECT_TRUE(artd_
654                   ->deleteArtifacts(
655                       ArtifactsPath{
656                           .dexPath = "/a/b.apk",
657                           .isa = "arm64",
658                           .isInDalvikCache = true,
659                       },
660                       &result)
661                   .isOk());
662   EXPECT_EQ(result, 4 + 1);
663 
664   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/a@b.apk@classes.dex"));
665   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/a@b.apk@classes.art"));
666 }
667 
TEST_F(ArtdTest,deleteArtifactsNoFile)668 TEST_F(ArtdTest, deleteArtifactsNoFile) {
669   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
670   EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(0);
671 
672   int64_t result = -1;
673   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
674   EXPECT_EQ(result, 0);
675 }
676 
TEST_F(ArtdTest,deleteArtifactsPermissionDenied)677 TEST_F(ArtdTest, deleteArtifactsPermissionDenied) {
678   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
679   std::filesystem::create_directories(oat_dir);
680   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex"));  // 4 bytes.
681   ASSERT_TRUE(WriteStringToFile("ab", oat_dir + "/b.vdex"));    // 2 bytes.
682   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art"));      // 1 byte.
683 
684   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
685   EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(3);
686 
687   auto scoped_inaccessible = ScopedInaccessible(oat_dir);
688   auto scoped_unroot = ScopedUnroot();
689 
690   int64_t result = -1;
691   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
692   EXPECT_EQ(result, 0);
693 }
694 
TEST_F(ArtdTest,deleteArtifactsFileIsDir)695 TEST_F(ArtdTest, deleteArtifactsFileIsDir) {
696   // VDEX file is a directory.
697   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
698   std::filesystem::create_directories(oat_dir);
699   std::filesystem::create_directories(oat_dir + "/b.vdex");
700   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex"));  // 4 bytes.
701   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art"));      // 1 byte.
702 
703   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
704   EXPECT_CALL(mock_logger_,
705               Call(_, _, _, _, _, ContainsRegex(R"re(Failed to get the file size.*b\.vdex)re")))
706       .Times(1);
707 
708   int64_t result = -1;
709   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
710   EXPECT_EQ(result, 4 + 1);
711 
712   // The directory is kept because getting the file size failed.
713   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.odex"));
714   EXPECT_TRUE(std::filesystem::exists(oat_dir + "/b.vdex"));
715   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.art"));
716 }
717 
TEST_F(ArtdTest,maybeCreateSdc)718 TEST_F(ArtdTest, maybeCreateSdc) {
719   // Unable to create OatFileAssistantContext on host to get APEX versions.
720   TEST_DISABLED_FOR_HOST();
721 
722   std::string sdm_file = OR_FAIL(BuildSdmPath(sdm_sdc_paths_));
723   std::string sdc_file = OR_FAIL(BuildSdcPath(sdm_sdc_paths_));
724   CreateFile(sdm_file);
725 
726   ASSERT_STATUS_OK(artd_->maybeCreateSdc(
727       {.sdcPath = sdm_sdc_paths_, .permissionSettings = permission_settings_}));
728 
729   CheckContent(sdc_file, StartsWith("sdm-timestamp-ns="));
730 }
731 
TEST_F(ArtdTest,maybeCreateSdcAlreadyCreated)732 TEST_F(ArtdTest, maybeCreateSdcAlreadyCreated) {
733   // Unable to create OatFileAssistantContext on host to get APEX versions.
734   TEST_DISABLED_FOR_HOST();
735 
736   std::string sdm_file = OR_FAIL(BuildSdmPath(sdm_sdc_paths_));
737   std::string sdc_file = OR_FAIL(BuildSdcPath(sdm_sdc_paths_));
738   CreateFile(sdm_file);
739 
740   ASSERT_STATUS_OK(artd_->maybeCreateSdc(
741       {.sdcPath = sdm_sdc_paths_, .permissionSettings = permission_settings_}));
742 
743   struct stat sdc_st;
744   ASSERT_EQ(stat(sdc_file.c_str(), &sdc_st), 0);
745 
746   ASSERT_STATUS_OK(artd_->maybeCreateSdc(
747       {.sdcPath = sdm_sdc_paths_, .permissionSettings = permission_settings_}));
748 
749   struct stat new_sdc_st;
750   ASSERT_EQ(stat(sdc_file.c_str(), &new_sdc_st), 0);
751 
752   EXPECT_EQ(TimeSpecToNs(sdc_st.st_mtim), TimeSpecToNs(new_sdc_st.st_mtim));
753 }
754 
TEST_F(ArtdTest,maybeCreateSdcOutdatedTimestamp)755 TEST_F(ArtdTest, maybeCreateSdcOutdatedTimestamp) {
756   // Unable to create OatFileAssistantContext on host to get APEX versions.
757   TEST_DISABLED_FOR_HOST();
758 
759   std::string sdm_file = OR_FAIL(BuildSdmPath(sdm_sdc_paths_));
760   std::string sdc_file = OR_FAIL(BuildSdcPath(sdm_sdc_paths_));
761   CreateFile(sdm_file);
762 
763   ASSERT_STATUS_OK(artd_->maybeCreateSdc(
764       {.sdcPath = sdm_sdc_paths_, .permissionSettings = permission_settings_}));
765 
766   struct stat sdc_st;
767   ASSERT_EQ(stat(sdc_file.c_str(), &sdc_st), 0);
768 
769   // Simulate that the SDM file is updated.
770   CreateFile(sdm_file);
771 
772   ASSERT_STATUS_OK(artd_->maybeCreateSdc(
773       {.sdcPath = sdm_sdc_paths_, .permissionSettings = permission_settings_}));
774 
775   struct stat new_sdc_st;
776   ASSERT_EQ(stat(sdc_file.c_str(), &new_sdc_st), 0);
777 
778   // The SDC file should be updated.
779   EXPECT_LT(TimeSpecToNs(sdc_st.st_mtim), TimeSpecToNs(new_sdc_st.st_mtim));
780 }
781 
TEST_F(ArtdTest,maybeCreateSdcNoSdm)782 TEST_F(ArtdTest, maybeCreateSdcNoSdm) {
783   std::string sdc_file = OR_FAIL(BuildSdcPath(sdm_sdc_paths_));
784 
785   ASSERT_STATUS_OK(artd_->maybeCreateSdc(
786       {.sdcPath = sdm_sdc_paths_, .permissionSettings = permission_settings_}));
787 
788   EXPECT_FALSE(std::filesystem::exists(sdc_file));
789 }
790 
TEST_F(ArtdTest,dexopt)791 TEST_F(ArtdTest, dexopt) {
792   dexopt_options_.generateAppImage = true;
793 
794   EXPECT_CALL(
795       *mock_exec_utils_,
796       DoExecAndReturnCode(
797           AllOf(WhenSplitBy(
798                     "--",
799                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
800                     AllOf(Contains(art_root_ + "/bin/dex2oat32"),
801                           Contains(Flag("--zip-fd=", FdOf(dex_file_))),
802                           Contains(Flag("--zip-location=", dex_file_)),
803                           Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")),
804                           Contains(Flag("--instruction-set=", "arm64")),
805                           Contains(Flag("--compiler-filter=", "speed")),
806                           Contains(Flag(
807                               "--profile-file-fd=",
808                               FdOf(android_data_ +
809                                    "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"))),
810                           Contains(Flag("--input-vdex-fd=",
811                                         FdOf(scratch_path_ + "/a/oat/arm64/b.vdex"))),
812                           Contains(Flag("--dm-fd=", FdOf(scratch_path_ + "/a/b.dm"))))),
813                 HasKeepFdsFor("--zip-fd=",
814                               "--profile-file-fd=",
815                               "--input-vdex-fd=",
816                               "--dm-fd=",
817                               "--oat-fd=",
818                               "--output-vdex-fd=",
819                               "--app-image-fd=",
820                               "--class-loader-context-fds=",
821                               "--swap-fd=")),
822           _,
823           _))
824       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
825                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
826                       WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
827                       SetArgPointee<2>(ProcessStat{.wall_time_ms = 100, .cpu_time_ms = 400}),
828                       Return(0)));
829   RunDexopt(
830       EX_NONE,
831       AllOf(Field(&ArtdDexoptResult::cancelled, false),
832             Field(&ArtdDexoptResult::wallTimeMs, 100),
833             Field(&ArtdDexoptResult::cpuTimeMs, 400),
834             Field(&ArtdDexoptResult::sizeBytes, strlen("art") + strlen("oat") + strlen("vdex")),
835             Field(&ArtdDexoptResult::sizeBeforeBytes,
836                   strlen("old_art") + strlen("old_oat") + strlen("old_vdex"))));
837 
838   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "oat");
839   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "vdex");
840   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "art");
841   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.odex", true);
842   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.vdex", true);
843   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.art", true);
844 }
845 
TEST_F(ArtdTest,dexoptClassLoaderContext)846 TEST_F(ArtdTest, dexoptClassLoaderContext) {
847   EXPECT_CALL(
848       *mock_exec_utils_,
849       DoExecAndReturnCode(
850           WhenSplitBy("--",
851                       _,
852                       AllOf(Contains(ListFlag("--class-loader-context-fds=",
853                                               ElementsAre(FdOf(clc_1_), FdOf(clc_2_)))),
854                             Contains(Flag("--class-loader-context=", class_loader_context_)),
855                             Contains(Flag("--classpath-dir=", scratch_path_ + "/a")))),
856           _,
857           _))
858       .WillOnce(Return(0));
859   RunDexopt();
860 }
861 
TEST_F(ArtdTest,dexoptClassLoaderContextNull)862 TEST_F(ArtdTest, dexoptClassLoaderContextNull) {
863   class_loader_context_ = std::nullopt;
864 
865   EXPECT_CALL(
866       *mock_exec_utils_,
867       DoExecAndReturnCode(WhenSplitBy("--",
868                                       _,
869                                       AllOf(Not(Contains(Flag("--class-loader-context-fds=", _))),
870                                             Not(Contains(Flag("--class-loader-context=", _))),
871                                             Not(Contains(Flag("--classpath-dir=", _))))),
872                           _,
873                           _))
874       .WillOnce(Return(0));
875   RunDexopt();
876 }
877 
TEST_F(ArtdTest,dexoptNoOptionalInputFiles)878 TEST_F(ArtdTest, dexoptNoOptionalInputFiles) {
879   profile_path_ = std::nullopt;
880   vdex_path_ = std::nullopt;
881   dm_path_ = std::nullopt;
882 
883   EXPECT_CALL(*mock_exec_utils_,
884               DoExecAndReturnCode(WhenSplitBy("--",
885                                               _,
886                                               AllOf(Not(Contains(Flag("--profile-file-fd=", _))),
887                                                     Not(Contains(Flag("--input-vdex-fd=", _))),
888                                                     Not(Contains(Flag("--dm-fd=", _))))),
889                                   _,
890                                   _))
891       .WillOnce(Return(0));
892   RunDexopt();
893 }
894 
TEST_F(ArtdTest,dexoptPriorityClassBoot)895 TEST_F(ArtdTest, dexoptPriorityClassBoot) {
896   priority_class_ = PriorityClass::BOOT;
897   EXPECT_CALL(*mock_exec_utils_,
898               DoExecAndReturnCode(WhenSplitBy("--",
899                                               AllOf(Not(Contains(Flag("--set-task-profile=", _))),
900                                                     Not(Contains(Flag("--set-priority=", _)))),
901                                               _),
902                                   _,
903                                   _))
904       .WillOnce(Return(0));
905   RunDexopt();
906 }
907 
TEST_F(ArtdTest,dexoptPriorityClassInteractive)908 TEST_F(ArtdTest, dexoptPriorityClassInteractive) {
909   priority_class_ = PriorityClass::INTERACTIVE;
910   EXPECT_CALL(*mock_exec_utils_,
911               DoExecAndReturnCode(
912                   WhenSplitBy("--",
913                               AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
914                                     Contains(Flag("--set-priority=", "background"))),
915                               _),
916                   _,
917                   _))
918       .WillOnce(Return(0));
919   RunDexopt();
920 }
921 
TEST_F(ArtdTest,dexoptPriorityClassInteractiveFast)922 TEST_F(ArtdTest, dexoptPriorityClassInteractiveFast) {
923   priority_class_ = PriorityClass::INTERACTIVE_FAST;
924   EXPECT_CALL(*mock_exec_utils_,
925               DoExecAndReturnCode(
926                   WhenSplitBy("--",
927                               AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
928                                     Contains(Flag("--set-priority=", "background"))),
929                               _),
930                   _,
931                   _))
932       .WillOnce(Return(0));
933   RunDexopt();
934 }
935 
TEST_F(ArtdTest,dexoptPriorityClassBackground)936 TEST_F(ArtdTest, dexoptPriorityClassBackground) {
937   priority_class_ = PriorityClass::BACKGROUND;
938   EXPECT_CALL(*mock_exec_utils_,
939               DoExecAndReturnCode(
940                   WhenSplitBy("--",
941                               AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBackground")),
942                                     Contains(Flag("--set-priority=", "background"))),
943                               _),
944                   _,
945                   _))
946       .WillOnce(Return(0));
947   RunDexopt();
948 }
949 
TEST_F(ArtdTest,dexoptDexoptOptions)950 TEST_F(ArtdTest, dexoptDexoptOptions) {
951   dexopt_options_ = DexoptOptions{
952       .compilationReason = "install",
953       .targetSdkVersion = 123,
954       .debuggable = false,
955       .generateAppImage = false,
956       .hiddenApiPolicyEnabled = false,
957       .comments = "my-comments",
958   };
959 
960   EXPECT_CALL(
961       *mock_exec_utils_,
962       DoExecAndReturnCode(WhenSplitBy("--",
963                                       _,
964                                       AllOf(Contains(Flag("--compilation-reason=", "install")),
965                                             Contains(Flag("-Xtarget-sdk-version:", "123")),
966                                             Not(Contains("--debuggable")),
967                                             Not(Contains(Flag("--app-image-fd=", _))),
968                                             Not(Contains(Flag("-Xhidden-api-policy:", _))),
969                                             Contains(Flag("--comments=", "my-comments")))),
970                           _,
971                           _))
972       .WillOnce(Return(0));
973 
974   // `sizeBeforeBytes` should include the size of the old ART file even if no new ART file is
975   // generated.
976   RunDexopt(EX_NONE,
977             Field(&ArtdDexoptResult::sizeBeforeBytes,
978                   strlen("old_art") + strlen("old_oat") + strlen("old_vdex")));
979 }
980 
TEST_F(ArtdTest,dexoptDexoptOptions2)981 TEST_F(ArtdTest, dexoptDexoptOptions2) {
982   dexopt_options_ = DexoptOptions{
983       .compilationReason = "bg-dexopt",
984       .targetSdkVersion = 456,
985       .debuggable = true,
986       .generateAppImage = true,
987       .hiddenApiPolicyEnabled = true,
988   };
989 
990   EXPECT_CALL(
991       *mock_exec_utils_,
992       DoExecAndReturnCode(WhenSplitBy("--",
993                                       _,
994                                       AllOf(Contains(Flag("--compilation-reason=", "bg-dexopt")),
995                                             Contains(Flag("-Xtarget-sdk-version:", "456")),
996                                             Contains("--debuggable"),
997                                             Contains(Flag("--app-image-fd=", _)),
998                                             Contains(Flag("-Xhidden-api-policy:", "enabled")))),
999                           _,
1000                           _))
1001       .WillOnce(Return(0));
1002 
1003   RunDexopt();
1004 }
1005 
TEST_F(ArtdTest,dexoptDefaultFlagsWhenNoSystemProps)1006 TEST_F(ArtdTest, dexoptDefaultFlagsWhenNoSystemProps) {
1007   dexopt_options_.generateAppImage = true;
1008 
1009   EXPECT_CALL(*mock_exec_utils_,
1010               DoExecAndReturnCode(
1011                   WhenSplitBy("--",
1012                               _,
1013                               AllOf(Contains(Flag("--swap-fd=", FdOf(_))),
1014                                     Not(Contains(Flag("--instruction-set-features=", _))),
1015                                     Not(Contains(Flag("--instruction-set-variant=", _))),
1016                                     Not(Contains(Flag("--max-image-block-size=", _))),
1017                                     Not(Contains(Flag("--very-large-app-threshold=", _))),
1018                                     Not(Contains(Flag("--resolve-startup-const-strings=", _))),
1019                                     Not(Contains("--generate-debug-info")),
1020                                     Not(Contains("--generate-mini-debug-info")),
1021                                     Contains("-Xdeny-art-apex-data-files"),
1022                                     Not(Contains(Flag("--cpu-set=", _))),
1023                                     Not(Contains(Flag("-j", _))),
1024                                     Not(Contains(Flag("-Xms", _))),
1025                                     Not(Contains(Flag("-Xmx", _))),
1026                                     Not(Contains("--compile-individually")),
1027                                     Not(Contains(Flag("--image-format=", _))),
1028                                     Not(Contains("--force-jit-zygote")),
1029                                     Not(Contains(Flag("--boot-image=", _))))),
1030                   _,
1031                   _))
1032       .WillOnce(Return(0));
1033   RunDexopt();
1034 }
1035 
TEST_F(ArtdTest,dexoptFlagsFromSystemProps)1036 TEST_F(ArtdTest, dexoptFlagsFromSystemProps) {
1037   dexopt_options_.generateAppImage = true;
1038 
1039   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-swap")).WillOnce(Return("0"));
1040   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.isa.arm64.features"))
1041       .WillOnce(Return("features"));
1042   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.isa.arm64.variant")).WillOnce(Return("variant"));
1043   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-max-image-block-size"))
1044       .WillOnce(Return("size"));
1045   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-very-large"))
1046       .WillOnce(Return("threshold"));
1047   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-resolve-startup-strings"))
1048       .WillOnce(Return("strings"));
1049   EXPECT_CALL(*mock_props_, GetProperty("debug.generate-debug-info")).WillOnce(Return("1"));
1050   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-minidebuginfo")).WillOnce(Return("1"));
1051   EXPECT_CALL(*mock_props_, GetProperty("odsign.verification.success")).WillOnce(Return("1"));
1052   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-Xms")).WillOnce(Return("xms"));
1053   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-Xmx")).WillOnce(Return("xmx"));
1054   EXPECT_CALL(*mock_props_, GetProperty("ro.config.low_ram")).WillOnce(Return("1"));
1055   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.appimageformat")).WillOnce(Return("imgfmt"));
1056   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.boot-image")).WillOnce(Return("boot-image"));
1057   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-flags"))
1058       .WillOnce(Return("--flag1 --flag2  --flag3"));
1059 
1060   EXPECT_CALL(*mock_exec_utils_,
1061               DoExecAndReturnCode(
1062                   WhenSplitBy("--",
1063                               _,
1064                               AllOf(Not(Contains(Flag("--swap-fd=", _))),
1065                                     Contains(Flag("--instruction-set-features=", "features")),
1066                                     Contains(Flag("--instruction-set-variant=", "variant")),
1067                                     Contains(Flag("--max-image-block-size=", "size")),
1068                                     Contains(Flag("--very-large-app-threshold=", "threshold")),
1069                                     Contains(Flag("--resolve-startup-const-strings=", "strings")),
1070                                     Contains("--generate-debug-info"),
1071                                     Contains("--generate-mini-debug-info"),
1072                                     Not(Contains("-Xdeny-art-apex-data-files")),
1073                                     Contains(Flag("-Xms", "xms")),
1074                                     Contains(Flag("-Xmx", "xmx")),
1075                                     Contains("--compile-individually"),
1076                                     Contains(Flag("--image-format=", "imgfmt")),
1077                                     Not(Contains("--force-jit-zygote")),
1078                                     Contains(Flag("--boot-image=", "boot-image")),
1079                                     Contains("--flag1"),
1080                                     Contains("--flag2"),
1081                                     Contains("--flag3"))),
1082                   _,
1083                   _))
1084       .WillOnce(Return(0));
1085   RunDexopt();
1086 }
1087 
TEST_F(ArtdTest,dexoptFlagsForceJitZygote)1088 TEST_F(ArtdTest, dexoptFlagsForceJitZygote) {
1089   EXPECT_CALL(*mock_props_,
1090               GetProperty("persist.device_config.runtime_native_boot.profilebootclasspath"))
1091       .WillOnce(Return("true"));
1092   ON_CALL(*mock_props_, GetProperty("dalvik.vm.boot-image")).WillByDefault(Return("boot-image"));
1093 
1094   EXPECT_CALL(*mock_exec_utils_,
1095               DoExecAndReturnCode(WhenSplitBy("--",
1096                                               _,
1097                                               AllOf(Contains("--force-jit-zygote"),
1098                                                     Not(Contains(Flag("--boot-image=", _))))),
1099                                   _,
1100                                   _))
1101       .WillOnce(Return(0));
1102   RunDexopt();
1103 }
1104 
SetDefaultResourceControlProps(MockSystemProperties * mock_props)1105 static void SetDefaultResourceControlProps(MockSystemProperties* mock_props) {
1106   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-cpu-set")).WillRepeatedly(Return("0,2"));
1107   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-threads")).WillRepeatedly(Return("4"));
1108 }
1109 
TEST_F(ArtdTest,dexoptDefaultResourceControlBoot)1110 TEST_F(ArtdTest, dexoptDefaultResourceControlBoot) {
1111   SetDefaultResourceControlProps(mock_props_);
1112 
1113   // The default resource control properties don't apply to BOOT.
1114   EXPECT_CALL(
1115       *mock_exec_utils_,
1116       DoExecAndReturnCode(
1117           WhenSplitBy(
1118               "--", _, AllOf(Not(Contains(Flag("--cpu-set=", _))), Contains(Not(Flag("-j", _))))),
1119           _,
1120           _))
1121       .WillOnce(Return(0));
1122   priority_class_ = PriorityClass::BOOT;
1123   RunDexopt();
1124 }
1125 
TEST_F(ArtdTest,dexoptDefaultResourceControlOther)1126 TEST_F(ArtdTest, dexoptDefaultResourceControlOther) {
1127   SetDefaultResourceControlProps(mock_props_);
1128 
1129   EXPECT_CALL(
1130       *mock_exec_utils_,
1131       DoExecAndReturnCode(
1132           WhenSplitBy(
1133               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
1134           _,
1135           _))
1136       .Times(3)
1137       .WillRepeatedly(Return(0));
1138   priority_class_ = PriorityClass::INTERACTIVE_FAST;
1139   RunDexopt();
1140   priority_class_ = PriorityClass::INTERACTIVE;
1141   RunDexopt();
1142   priority_class_ = PriorityClass::BACKGROUND;
1143   RunDexopt();
1144 }
1145 
SetAllResourceControlProps(MockSystemProperties * mock_props)1146 static void SetAllResourceControlProps(MockSystemProperties* mock_props) {
1147   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-cpu-set")).WillRepeatedly(Return("0,2"));
1148   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-threads")).WillRepeatedly(Return("4"));
1149   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.boot-dex2oat-cpu-set"))
1150       .WillRepeatedly(Return("0,1,2,3"));
1151   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.boot-dex2oat-threads"))
1152       .WillRepeatedly(Return("8"));
1153   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.restore-dex2oat-cpu-set"))
1154       .WillRepeatedly(Return("0,2,3"));
1155   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.restore-dex2oat-threads"))
1156       .WillRepeatedly(Return("6"));
1157   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.background-dex2oat-cpu-set"))
1158       .WillRepeatedly(Return("0"));
1159   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.background-dex2oat-threads"))
1160       .WillRepeatedly(Return("2"));
1161 }
1162 
TEST_F(ArtdTest,dexoptAllResourceControlBoot)1163 TEST_F(ArtdTest, dexoptAllResourceControlBoot) {
1164   SetAllResourceControlProps(mock_props_);
1165 
1166   EXPECT_CALL(
1167       *mock_exec_utils_,
1168       DoExecAndReturnCode(
1169           WhenSplitBy(
1170               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,1,2,3")), Contains(Flag("-j", "8")))),
1171           _,
1172           _))
1173       .WillOnce(Return(0));
1174   priority_class_ = PriorityClass::BOOT;
1175   RunDexopt();
1176 }
1177 
TEST_F(ArtdTest,dexoptAllResourceControlInteractiveFast)1178 TEST_F(ArtdTest, dexoptAllResourceControlInteractiveFast) {
1179   SetAllResourceControlProps(mock_props_);
1180 
1181   EXPECT_CALL(
1182       *mock_exec_utils_,
1183       DoExecAndReturnCode(
1184           WhenSplitBy(
1185               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2,3")), Contains(Flag("-j", "6")))),
1186           _,
1187           _))
1188       .WillOnce(Return(0));
1189   priority_class_ = PriorityClass::INTERACTIVE_FAST;
1190   RunDexopt();
1191 }
1192 
TEST_F(ArtdTest,dexoptAllResourceControlInteractive)1193 TEST_F(ArtdTest, dexoptAllResourceControlInteractive) {
1194   SetAllResourceControlProps(mock_props_);
1195 
1196   // INTERACTIVE always uses the default resource control properties.
1197   EXPECT_CALL(
1198       *mock_exec_utils_,
1199       DoExecAndReturnCode(
1200           WhenSplitBy(
1201               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
1202           _,
1203           _))
1204       .WillOnce(Return(0));
1205   priority_class_ = PriorityClass::INTERACTIVE;
1206   RunDexopt();
1207 }
1208 
TEST_F(ArtdTest,dexoptAllResourceControlBackground)1209 TEST_F(ArtdTest, dexoptAllResourceControlBackground) {
1210   SetAllResourceControlProps(mock_props_);
1211 
1212   EXPECT_CALL(
1213       *mock_exec_utils_,
1214       DoExecAndReturnCode(
1215           WhenSplitBy("--", _, AllOf(Contains(Flag("--cpu-set=", "0")), Contains(Flag("-j", "2")))),
1216           _,
1217           _))
1218       .WillOnce(Return(0));
1219   priority_class_ = PriorityClass::BACKGROUND;
1220   RunDexopt();
1221 }
1222 
TEST_F(ArtdTest,dexoptTerminatedBySignal)1223 TEST_F(ArtdTest, dexoptTerminatedBySignal) {
1224   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1225       .WillOnce(Return(Result<int>(Error())));
1226   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1227                   Property(&ndk::ScopedAStatus::getMessage,
1228                            HasSubstr(ART_FORMAT("[status={},exit_code=-1,signal={}]",
1229                                                 static_cast<int>(ExecResult::kSignaled),
1230                                                 SIGKILL)))));
1231 }
1232 
TEST_F(ArtdTest,dexoptFailed)1233 TEST_F(ArtdTest, dexoptFailed) {
1234   dexopt_options_.generateAppImage = true;
1235   constexpr int kExitCode = 135;
1236   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1237       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1238                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1239                       WithArg<0>(WriteToFdFlag("--app-image-fd=", "new_art")),
1240                       Return(kExitCode)));
1241   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1242                   Property(&ndk::ScopedAStatus::getMessage,
1243                            HasSubstr(ART_FORMAT("[status={},exit_code={},signal=0]",
1244                                                 static_cast<int>(ExecResult::kExited),
1245                                                 kExitCode)))));
1246 
1247   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1248   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1249   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
1250 }
1251 
TEST_F(ArtdTest,dexoptFailedToCommit)1252 TEST_F(ArtdTest, dexoptFailedToCommit) {
1253   std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_inaccessible;
1254   std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_unroot;
1255 
1256   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1257       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1258                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1259                       [&](auto, auto, auto) {
1260                         scoped_inaccessible = std::make_unique<ScopeGuard<std::function<void()>>>(
1261                             ScopedInaccessible(scratch_path_ + "/a/oat/arm64"));
1262                         scoped_unroot =
1263                             std::make_unique<ScopeGuard<std::function<void()>>>(ScopedUnroot());
1264                         return 0;
1265                       }));
1266 
1267   RunDexopt(
1268       EX_SERVICE_SPECIFIC,
1269       AllOf(Field(&ArtdDexoptResult::sizeBytes, 0), Field(&ArtdDexoptResult::sizeBeforeBytes, 0)));
1270 }
1271 
TEST_F(ArtdTest,dexoptCancelledBeforeDex2oat)1272 TEST_F(ArtdTest, dexoptCancelledBeforeDex2oat) {
1273   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1274   ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1275 
1276   constexpr pid_t kPid = 123;
1277 
1278   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1279       .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
1280         callbacks.on_start(kPid);
1281         callbacks.on_end(kPid);
1282         return Error();
1283       });
1284   EXPECT_CALL(mock_kill_, Call(-kPid, SIGKILL));
1285 
1286   cancellation_signal->cancel();
1287 
1288   RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, true), cancellation_signal);
1289 
1290   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1291   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1292   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
1293 }
1294 
TEST_F(ArtdTest,dexoptCancelledDuringDex2oat)1295 TEST_F(ArtdTest, dexoptCancelledDuringDex2oat) {
1296   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1297   ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1298 
1299   constexpr pid_t kPid = 123;
1300   constexpr std::chrono::duration<int> kTimeout = std::chrono::seconds(1);
1301 
1302   std::condition_variable process_started_cv, process_killed_cv;
1303   std::mutex mu;
1304 
1305   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1306       .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
1307         std::unique_lock<std::mutex> lock(mu);
1308         // Step 2.
1309         callbacks.on_start(kPid);
1310         process_started_cv.notify_one();
1311         EXPECT_EQ(process_killed_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
1312         // Step 5.
1313         callbacks.on_end(kPid);
1314         return Error();
1315       });
1316 
1317   EXPECT_CALL(mock_kill_, Call(-kPid, SIGKILL)).WillOnce([&](auto, auto) {
1318     // Step 4.
1319     process_killed_cv.notify_one();
1320     return 0;
1321   });
1322 
1323   std::thread t;
1324   {
1325     std::unique_lock<std::mutex> lock(mu);
1326     // Step 1.
1327     t = std::thread([&] {
1328       RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, true), cancellation_signal);
1329     });
1330     EXPECT_EQ(process_started_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
1331     // Step 3.
1332     cancellation_signal->cancel();
1333   }
1334 
1335   t.join();
1336 
1337   // Step 6.
1338   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1339   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1340   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
1341 }
1342 
TEST_F(ArtdTest,dexoptCancelledAfterDex2oat)1343 TEST_F(ArtdTest, dexoptCancelledAfterDex2oat) {
1344   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1345   ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1346 
1347   constexpr pid_t kPid = 123;
1348 
1349   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1350       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1351                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1352                       [&](auto, const ExecCallbacks& callbacks, auto) {
1353                         callbacks.on_start(kPid);
1354                         callbacks.on_end(kPid);
1355                         return 0;
1356                       }));
1357   EXPECT_CALL(mock_kill_, Call).Times(0);
1358 
1359   RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, false), cancellation_signal);
1360 
1361   // This signal should be ignored.
1362   cancellation_signal->cancel();
1363 
1364   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "new_oat");
1365   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "new_vdex");
1366   EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.art"));
1367 }
1368 
TEST_F(ArtdTest,dexoptDexFileNotOtherReadable)1369 TEST_F(ArtdTest, dexoptDexFileNotOtherReadable) {
1370   dex_file_other_readable_ = false;
1371   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1372   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1373                   Property(&ndk::ScopedAStatus::getMessage,
1374                            HasSubstr("Outputs cannot be other-readable because the dex file"))));
1375 }
1376 
TEST_F(ArtdTest,dexoptProfileNotOtherReadable)1377 TEST_F(ArtdTest, dexoptProfileNotOtherReadable) {
1378   profile_other_readable_ = false;
1379   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1380   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1381                   Property(&ndk::ScopedAStatus::getMessage,
1382                            HasSubstr("Outputs cannot be other-readable because the profile"))));
1383 }
1384 
TEST_F(ArtdTest,dexoptOutputNotOtherReadable)1385 TEST_F(ArtdTest, dexoptOutputNotOtherReadable) {
1386   output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1387   dex_file_other_readable_ = false;
1388   profile_other_readable_ = false;
1389   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(0));
1390   RunDexopt();
1391   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.odex", false);
1392   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.vdex", false);
1393 }
1394 
TEST_F(ArtdTest,dexoptUidMismatch)1395 TEST_F(ArtdTest, dexoptUidMismatch) {
1396   output_artifacts_.permissionSettings.fileFsPermission.uid = 12345;
1397   output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1398   dex_file_other_readable_ = false;
1399   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1400   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1401                   Property(&ndk::ScopedAStatus::getMessage,
1402                            HasSubstr("Outputs' owner doesn't match the dex file"))));
1403 }
1404 
TEST_F(ArtdTest,dexoptGidMismatch)1405 TEST_F(ArtdTest, dexoptGidMismatch) {
1406   output_artifacts_.permissionSettings.fileFsPermission.gid = 12345;
1407   output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1408   dex_file_other_readable_ = false;
1409   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1410   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1411                   Property(&ndk::ScopedAStatus::getMessage,
1412                            HasSubstr("Outputs' owner doesn't match the dex file"))));
1413 }
1414 
TEST_F(ArtdTest,dexoptGidMatchesUid)1415 TEST_F(ArtdTest, dexoptGidMatchesUid) {
1416   output_artifacts_.permissionSettings.fileFsPermission = {
1417       .uid = 123, .gid = 123, .isOtherReadable = false};
1418   EXPECT_CALL(mock_fstat_, Call(_, _)).WillRepeatedly(fstat);  // For profile.
1419   EXPECT_CALL(mock_fstat_, Call(FdOf(dex_file_), _))
1420       .WillOnce(DoAll(SetArgPointee<1>((struct stat){
1421                           .st_mode = S_IRUSR | S_IRGRP, .st_uid = 123, .st_gid = 456}),
1422                       Return(0)));
1423   ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1424   // It's okay to fail on chown. This happens when the test is not run as root.
1425   RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1426                   AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1427                         Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1428 }
1429 
TEST_F(ArtdTest,dexoptGidMatchesGid)1430 TEST_F(ArtdTest, dexoptGidMatchesGid) {
1431   output_artifacts_.permissionSettings.fileFsPermission = {
1432       .uid = 123, .gid = 456, .isOtherReadable = false};
1433   EXPECT_CALL(mock_fstat_, Call(_, _)).WillRepeatedly(fstat);  // For profile.
1434   EXPECT_CALL(mock_fstat_, Call(FdOf(dex_file_), _))
1435       .WillOnce(DoAll(SetArgPointee<1>((struct stat){
1436                           .st_mode = S_IRUSR | S_IRGRP, .st_uid = 123, .st_gid = 456}),
1437                       Return(0)));
1438   ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1439   // It's okay to fail on chown. This happens when the test is not run as root.
1440   RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1441                   AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1442                         Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1443 }
1444 
TEST_F(ArtdTest,dexoptUidGidChangeOk)1445 TEST_F(ArtdTest, dexoptUidGidChangeOk) {
1446   // The dex file is other-readable, so we don't check uid and gid.
1447   output_artifacts_.permissionSettings.fileFsPermission = {
1448       .uid = 12345, .gid = 12345, .isOtherReadable = false};
1449   ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1450   // It's okay to fail on chown. This happens when the test is not run as root.
1451   RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1452                   AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1453                         Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1454 }
1455 
TEST_F(ArtdTest,dexoptNoUidGidChange)1456 TEST_F(ArtdTest, dexoptNoUidGidChange) {
1457   output_artifacts_.permissionSettings.fileFsPermission = {
1458       .uid = -1, .gid = -1, .isOtherReadable = false};
1459   dex_file_other_readable_ = false;
1460   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(0));
1461   RunDexopt();
1462 }
1463 
TEST_F(ArtdTest,isProfileUsable)1464 TEST_F(ArtdTest, isProfileUsable) {
1465   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1466   CreateFile(profile_file);
1467   CreateFile(dex_file_);
1468 
1469   EXPECT_CALL(
1470       *mock_exec_utils_,
1471       DoExecAndReturnCode(
1472           AllOf(WhenSplitBy(
1473                     "--",
1474                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1475                     AllOf(Contains(art_root_ + "/bin/profman"),
1476                           Contains(Flag("--reference-profile-file-fd=", FdOf(profile_file))),
1477                           Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1478                 HasKeepFdsFor("--reference-profile-file-fd=", "--apk-fd=")),
1479           _,
1480           _))
1481       .WillOnce(Return(ProfmanResult::kSkipCompilationSmallDelta));
1482 
1483   bool result;
1484   EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1485   EXPECT_TRUE(result);
1486 }
1487 
TEST_F(ArtdTest,isProfileUsableFalse)1488 TEST_F(ArtdTest, isProfileUsableFalse) {
1489   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1490   CreateFile(profile_file);
1491   CreateFile(dex_file_);
1492 
1493   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1494       .WillOnce(Return(ProfmanResult::kSkipCompilationEmptyProfiles));
1495 
1496   bool result;
1497   EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1498   EXPECT_FALSE(result);
1499 }
1500 
TEST_F(ArtdTest,isProfileUsableNotFound)1501 TEST_F(ArtdTest, isProfileUsableNotFound) {
1502   CreateFile(dex_file_);
1503 
1504   bool result;
1505   EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1506   EXPECT_FALSE(result);
1507 }
1508 
TEST_F(ArtdTest,isProfileUsableFailed)1509 TEST_F(ArtdTest, isProfileUsableFailed) {
1510   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1511   CreateFile(profile_file);
1512   CreateFile(dex_file_);
1513 
1514   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(100));
1515 
1516   bool result;
1517   ndk::ScopedAStatus status = artd_->isProfileUsable(profile_path_.value(), dex_file_, &result);
1518 
1519   EXPECT_FALSE(status.isOk());
1520   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1521   EXPECT_THAT(status.getMessage(), HasSubstr("profman returned an unexpected code: 100"));
1522 }
1523 
TEST_F(ArtdTest,copyAndRewriteProfileSuccess)1524 TEST_F(ArtdTest, copyAndRewriteProfileSuccess) {
1525   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1526   CreateFile(src_file, "valid_profile");
1527 
1528   CreateFile(dex_file_);
1529 
1530   EXPECT_CALL(
1531       *mock_exec_utils_,
1532       DoExecAndReturnCode(
1533           AllOf(WhenSplitBy(
1534                     "--",
1535                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1536                     AllOf(Contains(art_root_ + "/bin/profman"),
1537                           Contains("--copy-and-update-profile-key"),
1538                           Contains(Flag("--profile-file-fd=", FdOf(src_file))),
1539                           Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1540                 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
1541           _,
1542           _))
1543       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
1544                       Return(ProfmanResult::kCopyAndUpdateSuccess)));
1545 
1546   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1547 
1548   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
1549   EXPECT_THAT(dst.profilePath.id, Not(IsEmpty()));
1550   std::string real_path = OR_FATAL(BuildTmpProfilePath(dst.profilePath));
1551   EXPECT_EQ(dst.profilePath.tmpPath, real_path);
1552   CheckContent(real_path, "def");
1553 }
1554 
1555 // The input is a plain profile file in the wrong format.
TEST_F(ArtdTest,copyAndRewriteProfileBadProfileWrongFormat)1556 TEST_F(ArtdTest, copyAndRewriteProfileBadProfileWrongFormat) {
1557   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1558   CreateFile(src_file, "wrong_format");
1559 
1560   CreateFile(dex_file_);
1561 
1562   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1563       .WillOnce(Return(ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile));
1564 
1565   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1566 
1567   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1568   EXPECT_THAT(result.errorMsg,
1569               HasSubstr("The profile is in the wrong format or an I/O error has occurred"));
1570   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1571   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1572 }
1573 
1574 // The input is a plain profile file that doesn't match the APK.
TEST_F(ArtdTest,copyAndRewriteProfileBadProfileNoMatch)1575 TEST_F(ArtdTest, copyAndRewriteProfileBadProfileNoMatch) {
1576   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1577   CreateFile(src_file, "no_match");
1578 
1579   CreateFile(dex_file_);
1580 
1581   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1582       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1583 
1584   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1585 
1586   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1587   EXPECT_THAT(result.errorMsg, HasSubstr("The profile does not match the APK"));
1588   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1589   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1590 }
1591 
1592 // The input is a plain profile file that is empty.
TEST_F(ArtdTest,copyAndRewriteProfileNoProfileEmpty)1593 TEST_F(ArtdTest, copyAndRewriteProfileNoProfileEmpty) {
1594   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1595   CreateFile(src_file, "");
1596 
1597   CreateFile(dex_file_);
1598 
1599   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1600       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1601 
1602   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1603 
1604   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1605   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1606   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1607 }
1608 
1609 // The input does not exist.
TEST_F(ArtdTest,copyAndRewriteProfileNoProfileNoFile)1610 TEST_F(ArtdTest, copyAndRewriteProfileNoProfileNoFile) {
1611   CreateFile(dex_file_);
1612 
1613   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1614 
1615   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1616   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1617   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1618 }
1619 
1620 // The input is a dm file with a profile entry in the wrong format.
TEST_F(ArtdTest,copyAndRewriteProfileNoProfileDmWrongFormat)1621 TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmWrongFormat) {
1622   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1623   CreateZipWithSingleEntry(src_file, "primary.prof", "wrong_format");
1624 
1625   CreateFile(dex_file_);
1626 
1627   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1628       .WillOnce(Return(ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile));
1629 
1630   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1631 
1632   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1633   EXPECT_THAT(result.errorMsg,
1634               HasSubstr("The profile is in the wrong format or an I/O error has occurred"));
1635   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1636   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1637 }
1638 
1639 // The input is a dm file with a profile entry that doesn't match the APK.
TEST_F(ArtdTest,copyAndRewriteProfileNoProfileDmNoMatch)1640 TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoMatch) {
1641   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1642   CreateZipWithSingleEntry(src_file, "primary.prof", "no_match");
1643 
1644   CreateFile(dex_file_);
1645 
1646   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1647       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1648 
1649   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1650 
1651   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1652   EXPECT_THAT(result.errorMsg, HasSubstr("The profile does not match the APK"));
1653   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1654   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1655 }
1656 
1657 // The input is a dm file with a profile entry that is empty.
TEST_F(ArtdTest,copyAndRewriteProfileNoProfileDmEmpty)1658 TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmEmpty) {
1659   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1660   CreateZipWithSingleEntry(src_file, "primary.prof");
1661 
1662   CreateFile(dex_file_);
1663 
1664   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1665       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1666 
1667   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1668 
1669   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1670   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1671   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1672 }
1673 
1674 // The input is a dm file without a profile entry.
TEST_F(ArtdTest,copyAndRewriteProfileNoProfileDmNoEntry)1675 TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoEntry) {
1676   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1677   CreateZipWithSingleEntry(src_file, "primary.vdex");
1678 
1679   CreateFile(dex_file_);
1680 
1681   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1682       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1683 
1684   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1685 
1686   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1687   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1688   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1689 }
1690 
TEST_F(ArtdTest,copyAndRewriteProfileException)1691 TEST_F(ArtdTest, copyAndRewriteProfileException) {
1692   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1693   CreateFile(src_file, "valid_profile");
1694 
1695   CreateFile(dex_file_);
1696 
1697   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(100));
1698 
1699   auto [status, dst] = OR_FAIL(RunCopyAndRewriteProfile</*kExpectOk=*/false>());
1700 
1701   EXPECT_FALSE(status.isOk());
1702   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1703   EXPECT_THAT(status.getMessage(), HasSubstr("profman returned an unexpected code: 100"));
1704   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1705   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1706 }
1707 
TEST_F(ArtdTest,copyAndRewriteEmbeddedProfileSuccess)1708 TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileSuccess) {
1709   TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS();
1710 
1711   CreateZipWithSingleEntry(dex_file_, "assets/art-profile/baseline.prof", "valid_profile");
1712 
1713   EXPECT_CALL(
1714       *mock_exec_utils_,
1715       DoExecAndReturnCode(
1716           AllOf(WhenSplitBy(
1717                     "--",
1718                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1719                     AllOf(Contains(art_root_ + "/bin/profman"),
1720                           Contains("--copy-and-update-profile-key"),
1721                           Contains(Flag("--profile-file-fd=", FdHasContent("valid_profile"))),
1722                           Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1723                 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
1724           _,
1725           _))
1726       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
1727                       Return(ProfmanResult::kCopyAndUpdateSuccess)));
1728 
1729   auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1730 
1731   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
1732   EXPECT_THAT(dst.profilePath.id, Not(IsEmpty()));
1733   std::string real_path = OR_FATAL(BuildTmpProfilePath(dst.profilePath));
1734   EXPECT_EQ(dst.profilePath.tmpPath, real_path);
1735   CheckContent(real_path, "def");
1736 }
1737 
1738 // The input is a plain dex file.
TEST_F(ArtdTest,copyAndRewriteEmbeddedProfileNoProfilePlainDex)1739 TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileNoProfilePlainDex) {
1740   TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS();
1741 
1742   constexpr const char* kDexMagic = "dex\n";
1743   CreateFile(dex_file_, kDexMagic + "dex_code"s);
1744 
1745   auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1746 
1747   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1748   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1749   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1750 }
1751 
1752 // The input is neither a zip nor a plain dex file.
TEST_F(ArtdTest,copyAndRewriteEmbeddedProfileNotZipNotDex)1753 TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileNotZipNotDex) {
1754   TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS();
1755 
1756   CreateFile(dex_file_, "wrong_format");
1757 
1758   auto [status, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile</*kExpectOk=*/false>());
1759 
1760   EXPECT_FALSE(status.isOk());
1761   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1762   EXPECT_THAT(status.getMessage(), HasSubstr("File is neither a zip file nor a plain dex file"));
1763   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1764   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1765 }
1766 
1767 // The input is a zip file without a profile entry.
TEST_F(ArtdTest,copyAndRewriteEmbeddedProfileNoProfileZipNoEntry)1768 TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileNoProfileZipNoEntry) {
1769   TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS();
1770 
1771   CreateZipWithSingleEntry(dex_file_, "classes.dex", "dex_code");
1772 
1773   auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1774 
1775   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1776   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1777   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1778 }
1779 
1780 // The input is a zip file with a profile entry that doesn't match itself.
TEST_F(ArtdTest,copyAndRewriteEmbeddedProfileBadProfileNoMatch)1781 TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileBadProfileNoMatch) {
1782   TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS();
1783 
1784   CreateZipWithSingleEntry(dex_file_, "assets/art-profile/baseline.prof", "no_match");
1785 
1786   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1787       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1788 
1789   auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1790 
1791   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1792   EXPECT_THAT(result.errorMsg, HasSubstr("The profile does not match the APK"));
1793   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1794   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1795 }
1796 
TEST_F(ArtdTest,commitTmpProfile)1797 TEST_F(ArtdTest, commitTmpProfile) {
1798   std::string tmp_profile_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1799   CreateFile(tmp_profile_file);
1800 
1801   EXPECT_TRUE(artd_->commitTmpProfile(tmp_profile_path_).isOk());
1802 
1803   EXPECT_FALSE(std::filesystem::exists(tmp_profile_file));
1804   EXPECT_TRUE(std::filesystem::exists(OR_FATAL(BuildFinalProfilePath(tmp_profile_path_))));
1805 }
1806 
TEST_F(ArtdTest,commitTmpProfileFailed)1807 TEST_F(ArtdTest, commitTmpProfileFailed) {
1808   ndk::ScopedAStatus status = artd_->commitTmpProfile(tmp_profile_path_);
1809 
1810   EXPECT_FALSE(status.isOk());
1811   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1812   EXPECT_THAT(
1813       status.getMessage(),
1814       ContainsRegex(R"re(Failed to move .*primary\.prof\.12345\.tmp.* to .*primary\.prof)re"));
1815 
1816   EXPECT_FALSE(std::filesystem::exists(OR_FATAL(BuildFinalProfilePath(tmp_profile_path_))));
1817 }
1818 
TEST_F(ArtdTest,deleteProfile)1819 TEST_F(ArtdTest, deleteProfile) {
1820   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1821   CreateFile(profile_file);
1822 
1823   EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1824 
1825   EXPECT_FALSE(std::filesystem::exists(profile_file));
1826 }
1827 
TEST_F(ArtdTest,deleteProfileDoesNotExist)1828 TEST_F(ArtdTest, deleteProfileDoesNotExist) {
1829   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
1830   EXPECT_CALL(mock_logger_, Call).Times(0);
1831 
1832   EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1833 }
1834 
TEST_F(ArtdTest,deleteProfileFailed)1835 TEST_F(ArtdTest, deleteProfileFailed) {
1836   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
1837   EXPECT_CALL(
1838       mock_logger_,
1839       Call(_, _, _, _, _, ContainsRegex(R"re(Failed to remove .*primary\.prof\.12345\.tmp)re")));
1840 
1841   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1842   auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(profile_file).parent_path());
1843   auto scoped_unroot = ScopedUnroot();
1844 
1845   EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1846 }
1847 
1848 class ArtdGetVisibilityTest : public ArtdTest {
1849  protected:
1850   template <typename PathType>
1851   using Method = ndk::ScopedAStatus (Artd::*)(const PathType&, FileVisibility*);
1852 
1853   template <typename PathType>
TestGetVisibilityOtherReadable(Method<PathType> method,const PathType & input,const std::string & path)1854   void TestGetVisibilityOtherReadable(Method<PathType> method,
1855                                       const PathType& input,
1856                                       const std::string& path) {
1857     CreateFile(path);
1858     std::filesystem::permissions(
1859         path, std::filesystem::perms::others_read, std::filesystem::perm_options::add);
1860 
1861     FileVisibility result;
1862     ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1863     EXPECT_EQ(result, FileVisibility::OTHER_READABLE);
1864   }
1865 
1866   template <typename PathType>
TestGetVisibilityNotOtherReadable(Method<PathType> method,const PathType & input,const std::string & path)1867   void TestGetVisibilityNotOtherReadable(Method<PathType> method,
1868                                          const PathType& input,
1869                                          const std::string& path) {
1870     CreateFile(path);
1871     std::filesystem::permissions(
1872         path, std::filesystem::perms::others_read, std::filesystem::perm_options::remove);
1873 
1874     FileVisibility result;
1875     ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1876     EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE);
1877   }
1878 
1879   template <typename PathType>
TestGetVisibilityNotFound(Method<PathType> method,const PathType & input)1880   void TestGetVisibilityNotFound(Method<PathType> method, const PathType& input) {
1881     FileVisibility result;
1882     ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1883     EXPECT_EQ(result, FileVisibility::NOT_FOUND);
1884   }
1885 
1886   template <typename PathType>
TestGetVisibilityPermissionDenied(Method<PathType> method,const PathType & input,const std::string & path)1887   void TestGetVisibilityPermissionDenied(Method<PathType> method,
1888                                          const PathType& input,
1889                                          const std::string& path) {
1890     CreateFile(path);
1891 
1892     auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(path).parent_path());
1893     auto scoped_unroot = ScopedUnroot();
1894 
1895     FileVisibility result;
1896     ndk::ScopedAStatus status = ((*artd_).*method)(input, &result);
1897     EXPECT_FALSE(status.isOk());
1898     EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1899     EXPECT_THAT(status.getMessage(), HasSubstr("Failed to get status of"));
1900   }
1901 };
1902 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityOtherReadable)1903 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityOtherReadable) {
1904   TestGetVisibilityOtherReadable(&Artd::getProfileVisibility,
1905                                  profile_path_.value(),
1906                                  OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
1907 }
1908 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityNotOtherReadable)1909 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotOtherReadable) {
1910   TestGetVisibilityNotOtherReadable(&Artd::getProfileVisibility,
1911                                     profile_path_.value(),
1912                                     OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
1913 }
1914 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityNotFound)1915 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotFound) {
1916   TestGetVisibilityNotFound(&Artd::getProfileVisibility, profile_path_.value());
1917 }
1918 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityPermissionDenied)1919 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityPermissionDenied) {
1920   TestGetVisibilityPermissionDenied(&Artd::getProfileVisibility,
1921                                     profile_path_.value(),
1922                                     OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
1923 }
1924 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityOtherReadable)1925 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityOtherReadable) {
1926   TestGetVisibilityOtherReadable(&Artd::getArtifactsVisibility,
1927                                  artifacts_path_,
1928                                  OR_FATAL(BuildArtifactsPath(artifacts_path_)).oat_path);
1929 }
1930 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityNotOtherReadable)1931 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotOtherReadable) {
1932   TestGetVisibilityNotOtherReadable(&Artd::getArtifactsVisibility,
1933                                     artifacts_path_,
1934                                     OR_FATAL(BuildArtifactsPath(artifacts_path_)).oat_path);
1935 }
1936 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityNotFound)1937 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotFound) {
1938   TestGetVisibilityNotFound(&Artd::getArtifactsVisibility, artifacts_path_);
1939 }
1940 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityPermissionDenied)1941 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityPermissionDenied) {
1942   TestGetVisibilityPermissionDenied(&Artd::getArtifactsVisibility,
1943                                     artifacts_path_,
1944                                     OR_FATAL(BuildArtifactsPath(artifacts_path_)).oat_path);
1945 }
1946 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityOtherReadable)1947 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityOtherReadable) {
1948   TestGetVisibilityOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1949 }
1950 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityNotOtherReadable)1951 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotOtherReadable) {
1952   TestGetVisibilityNotOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1953 }
1954 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityNotFound)1955 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotFound) {
1956   TestGetVisibilityNotFound(&Artd::getDexFileVisibility, dex_file_);
1957 }
1958 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityPermissionDenied)1959 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityPermissionDenied) {
1960   TestGetVisibilityPermissionDenied(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1961 }
1962 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityOtherReadable)1963 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityOtherReadable) {
1964   TestGetVisibilityOtherReadable(&Artd::getDmFileVisibility,
1965                                  dm_path_.value(),
1966                                  OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1967 }
1968 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityNotOtherReadable)1969 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotOtherReadable) {
1970   TestGetVisibilityNotOtherReadable(&Artd::getDmFileVisibility,
1971                                     dm_path_.value(),
1972                                     OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1973 }
1974 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityNotFound)1975 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotFound) {
1976   TestGetVisibilityNotFound(&Artd::getDmFileVisibility, dm_path_.value());
1977 }
1978 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityPermissionDenied)1979 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityPermissionDenied) {
1980   TestGetVisibilityPermissionDenied(&Artd::getDmFileVisibility,
1981                                     dm_path_.value(),
1982                                     OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1983 }
1984 
TEST_F(ArtdTest,mergeProfiles)1985 TEST_F(ArtdTest, mergeProfiles) {
1986   std::string reference_profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1987   CreateFile(reference_profile_file, "abc");
1988 
1989   // Doesn't exist.
1990   PrimaryCurProfilePath profile_0_path{
1991       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1992   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1993 
1994   PrimaryCurProfilePath profile_1_path{
1995       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
1996   std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
1997   CreateFile(profile_1_file, "def");
1998 
1999   OutputProfile output_profile{.profilePath = tmp_profile_path_,
2000                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2001   output_profile.profilePath.id = "";
2002   output_profile.profilePath.tmpPath = "";
2003 
2004   std::string dex_file_1 = scratch_path_ + "/a/b.apk";
2005   std::string dex_file_2 = scratch_path_ + "/a/c.apk";
2006   CreateFile(dex_file_1);
2007   CreateFile(dex_file_2);
2008 
2009   EXPECT_CALL(
2010       *mock_exec_utils_,
2011       DoExecAndReturnCode(
2012           AllOf(WhenSplitBy(
2013                     "--",
2014                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
2015                     AllOf(Contains(art_root_ + "/bin/profman"),
2016                           Not(Contains(Flag("--profile-file-fd=", FdOf(profile_0_file)))),
2017                           Contains(Flag("--profile-file-fd=", FdOf(profile_1_file))),
2018                           Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
2019                           Contains(Flag("--apk-fd=", FdOf(dex_file_1))),
2020                           Contains(Flag("--apk-fd=", FdOf(dex_file_2))),
2021                           Not(Contains("--force-merge-and-analyze")),
2022                           Not(Contains("--boot-image-merge")))),
2023                 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
2024           _,
2025           _))
2026       .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
2027                       Return(ProfmanResult::kCompile)));
2028 
2029   bool result;
2030   EXPECT_TRUE(artd_
2031                   ->mergeProfiles({profile_0_path, profile_1_path},
2032                                   profile_path_,
2033                                   &output_profile,
2034                                   {dex_file_1, dex_file_2},
2035                                   /*in_options=*/{},
2036                                   &result)
2037                   .isOk());
2038   EXPECT_TRUE(result);
2039   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2040   std::string real_path = OR_FATAL(BuildTmpProfilePath(output_profile.profilePath));
2041   EXPECT_EQ(output_profile.profilePath.tmpPath, real_path);
2042   CheckContent(real_path, "merged");
2043 }
2044 
TEST_F(ArtdTest,mergeProfilesEmptyReferenceProfile)2045 TEST_F(ArtdTest, mergeProfilesEmptyReferenceProfile) {
2046   PrimaryCurProfilePath profile_0_path{
2047       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2048   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2049   CreateFile(profile_0_file, "def");
2050 
2051   OutputProfile output_profile{.profilePath = tmp_profile_path_,
2052                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2053   output_profile.profilePath.id = "";
2054   output_profile.profilePath.tmpPath = "";
2055 
2056   CreateFile(dex_file_);
2057 
2058   EXPECT_CALL(
2059       *mock_exec_utils_,
2060       DoExecAndReturnCode(
2061           WhenSplitBy("--",
2062                       AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
2063                       AllOf(Contains(art_root_ + "/bin/profman"),
2064                             Contains(Flag("--profile-file-fd=", FdOf(profile_0_file))),
2065                             Contains(Flag("--reference-profile-file-fd=", FdHasContent(""))),
2066                             Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
2067           _,
2068           _))
2069       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "merged")),
2070                       Return(ProfmanResult::kCompile)));
2071 
2072   bool result;
2073   EXPECT_TRUE(artd_
2074                   ->mergeProfiles({profile_0_path},
2075                                   std::nullopt,
2076                                   &output_profile,
2077                                   {dex_file_},
2078                                   /*in_options=*/{},
2079                                   &result)
2080                   .isOk());
2081   EXPECT_TRUE(result);
2082   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2083   EXPECT_THAT(output_profile.profilePath.tmpPath, Not(IsEmpty()));
2084 }
2085 
TEST_F(ArtdTest,mergeProfilesProfilesDontExist)2086 TEST_F(ArtdTest, mergeProfilesProfilesDontExist) {
2087   // Doesn't exist.
2088   PrimaryCurProfilePath profile_0_path{
2089       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2090   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2091 
2092   // Doesn't exist.
2093   PrimaryCurProfilePath profile_1_path{
2094       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
2095   std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
2096 
2097   OutputProfile output_profile{.profilePath = tmp_profile_path_,
2098                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2099   output_profile.profilePath.id = "";
2100   output_profile.profilePath.tmpPath = "";
2101 
2102   CreateFile(dex_file_);
2103 
2104   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode).Times(0);
2105 
2106   bool result;
2107   EXPECT_TRUE(artd_
2108                   ->mergeProfiles({profile_0_path},
2109                                   /*in_referenceProfile=*/std::nullopt,
2110                                   &output_profile,
2111                                   {dex_file_},
2112                                   /*in_options=*/{},
2113                                   &result)
2114                   .isOk());
2115   EXPECT_FALSE(result);
2116   EXPECT_THAT(output_profile.profilePath.id, IsEmpty());
2117   EXPECT_THAT(output_profile.profilePath.tmpPath, IsEmpty());
2118 }
2119 
TEST_F(ArtdTest,mergeProfilesWithOptionsForceMerge)2120 TEST_F(ArtdTest, mergeProfilesWithOptionsForceMerge) {
2121   PrimaryCurProfilePath profile_0_path{
2122       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2123   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2124   CreateFile(profile_0_file, "def");
2125 
2126   OutputProfile output_profile{.profilePath = tmp_profile_path_,
2127                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2128   output_profile.profilePath.id = "";
2129   output_profile.profilePath.tmpPath = "";
2130 
2131   CreateFile(dex_file_);
2132 
2133   EXPECT_CALL(*mock_exec_utils_,
2134               DoExecAndReturnCode(WhenSplitBy("--",
2135                                               _,
2136                                               AllOf(Contains("--force-merge-and-analyze"),
2137                                                     Contains("--boot-image-merge"))),
2138                                   _,
2139                                   _))
2140       .WillOnce(Return(ProfmanResult::kCompile));
2141 
2142   bool result;
2143   EXPECT_TRUE(artd_
2144                   ->mergeProfiles({profile_0_path},
2145                                   std::nullopt,
2146                                   &output_profile,
2147                                   {dex_file_},
2148                                   {.forceMerge = true, .forBootImage = true},
2149                                   &result)
2150                   .isOk());
2151   EXPECT_TRUE(result);
2152   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2153   EXPECT_THAT(output_profile.profilePath.tmpPath, Not(IsEmpty()));
2154 }
2155 
TEST_F(ArtdTest,mergeProfilesWithOptionsDumpOnly)2156 TEST_F(ArtdTest, mergeProfilesWithOptionsDumpOnly) {
2157   PrimaryCurProfilePath profile_0_path{
2158       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2159   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2160   CreateFile(profile_0_file, "def");
2161 
2162   OutputProfile output_profile{.profilePath = tmp_profile_path_,
2163                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2164   output_profile.profilePath.id = "";
2165   output_profile.profilePath.tmpPath = "";
2166 
2167   CreateFile(dex_file_);
2168 
2169   EXPECT_CALL(*mock_exec_utils_,
2170               DoExecAndReturnCode(
2171                   AllOf(WhenSplitBy("--",
2172                                     _,
2173                                     AllOf(Contains("--dump-only"),
2174                                           Not(Contains(Flag("--reference-profile-file-fd=", _))))),
2175                         HasKeepFdsFor("--profile-file-fd=", "--apk-fd=", "--dump-output-to-fd=")),
2176                   _,
2177                   _))
2178       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--dump-output-to-fd=", "dump")),
2179                       Return(ProfmanResult::kSuccess)));
2180 
2181   bool result;
2182   EXPECT_TRUE(artd_
2183                   ->mergeProfiles({profile_0_path},
2184                                   std::nullopt,
2185                                   &output_profile,
2186                                   {dex_file_},
2187                                   {.dumpOnly = true},
2188                                   &result)
2189                   .isOk());
2190   EXPECT_TRUE(result);
2191   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2192   CheckContent(output_profile.profilePath.tmpPath, "dump");
2193 }
2194 
TEST_F(ArtdTest,mergeProfilesWithOptionsDumpClassesAndMethods)2195 TEST_F(ArtdTest, mergeProfilesWithOptionsDumpClassesAndMethods) {
2196   PrimaryCurProfilePath profile_0_path{
2197       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2198   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2199   CreateFile(profile_0_file, "def");
2200 
2201   OutputProfile output_profile{.profilePath = tmp_profile_path_,
2202                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2203   output_profile.profilePath.id = "";
2204   output_profile.profilePath.tmpPath = "";
2205 
2206   CreateFile(dex_file_);
2207 
2208   EXPECT_CALL(*mock_exec_utils_,
2209               DoExecAndReturnCode(
2210                   WhenSplitBy("--",
2211                               _,
2212                               AllOf(Contains("--dump-classes-and-methods"),
2213                                     Not(Contains(Flag("--reference-profile-file-fd=", _))))),
2214                   _,
2215                   _))
2216       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--dump-output-to-fd=", "dump")),
2217                       Return(ProfmanResult::kSuccess)));
2218 
2219   bool result;
2220   EXPECT_TRUE(artd_
2221                   ->mergeProfiles({profile_0_path},
2222                                   std::nullopt,
2223                                   &output_profile,
2224                                   {dex_file_},
2225                                   {.dumpClassesAndMethods = true},
2226                                   &result)
2227                   .isOk());
2228   EXPECT_TRUE(result);
2229   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2230   CheckContent(output_profile.profilePath.tmpPath, "dump");
2231 }
2232 
EncodeLocationForDalvikCache(const std::string & location)2233 static std::string EncodeLocationForDalvikCache(const std::string& location) {
2234   std::string encoded = location.substr(/*pos=*/1);  // Remove the leading '/';
2235   std::replace(encoded.begin(), encoded.end(), '/', '@');
2236   return encoded;
2237 }
2238 
2239 class ArtdCleanupTest : public ArtdTest {
2240  protected:
SetUpForCleanup()2241   void SetUpForCleanup() {
2242     // Unmanaged files.
2243     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/1.odex");
2244     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/1.arm64.sdm");
2245     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/1.odex");
2246     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/1.txt");
2247     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.txt");
2248     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.tmp");
2249     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.sdc");
2250 
2251     // Files to keep.
2252     CreateGcKeptFile(android_data_ + "/misc/profiles/cur/1/com.android.foo/primary.prof");
2253     CreateGcKeptFile(android_data_ + "/misc/profiles/cur/3/com.android.foo/primary.prof");
2254     CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex");
2255     CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex");
2256     CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art");
2257     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.vdex");
2258     CreateGcKeptFile(
2259         android_expand_ +
2260         "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex");
2261     CreateGcKeptFile(
2262         android_expand_ +
2263         "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.vdex");
2264     CreateGcKeptFile(
2265         android_expand_ +
2266         "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.art");
2267     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex");
2268     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.vdex");
2269     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.art");
2270     CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/cache/oat_primary/arm64/base.art");
2271     CreateGcKeptFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art");
2272     CreateGcKeptFile(android_data_ + "/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2273     CreateGcKeptFile(android_expand_ +
2274                      "/123456-7890/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2275     CreateGcKeptFile(android_data_ +
2276                      "/user/0/com.android.foo/cache/not_oat_dir/oat_primary/arm64/base.art");
2277     CreateGcKeptFile(android_data_ +
2278                      "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/base.arm64.sdm");
2279     CreateGcKeptFile(android_data_ +
2280                      "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/oat/arm64/base.sdc");
2281     CreateGcKeptFile(android_data_ +
2282                      "/app/~~jhrwafasr==/com.android.qux-bredcweff==/base.arm64.sdm");
2283     CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/" +
2284                      EncodeLocationForDalvikCache(android_data_) +
2285                      "@app@~~jhrwafasr==@com.android.qux-bredcweff==@base.apk@classes.sdc");
2286 
2287     // Files to remove.
2288     CreateGcRemovedFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof");
2289     CreateGcRemovedFile(android_data_ + "/misc/profiles/cur/2/com.android.foo/primary.prof");
2290     CreateGcRemovedFile(android_data_ + "/misc/profiles/cur/3/com.android.bar/primary.prof");
2291     CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/extra.odex");
2292     CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.dex");
2293     CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.vdex");
2294     CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.art");
2295     CreateGcRemovedFile(
2296         android_expand_ +
2297         "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.odex");
2298     CreateGcRemovedFile(
2299         android_expand_ +
2300         "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.vdex");
2301     CreateGcRemovedFile(
2302         android_expand_ +
2303         "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.art");
2304     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/1.prof");
2305     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/1.prof.123456.tmp");
2306     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.odex");
2307     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.vdex");
2308     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.art");
2309     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.odex.123456.tmp");
2310     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/2.odex.123456.tmp");
2311     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.odex");
2312     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.art");
2313     CreateGcRemovedFile(android_data_ +
2314                         "/user_de/0/com.android.foo/aaa/oat/arm64/1.vdex.123456.tmp");
2315     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.odex");
2316     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.vdex");
2317     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.art");
2318     CreateGcRemovedFile(android_data_ +
2319                         "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.art.123456.tmp");
2320     CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.bar/aaa/oat/arm64/1.vdex");
2321     CreateGcRemovedFile(android_data_ +
2322                         "/user/0/com.android.different_package/cache/oat_primary/arm64/base.art");
2323     CreateGcRemovedFile(android_data_ +
2324                         "/user/0/com.android.foo/cache/oat_primary/arm64/different_dex.art");
2325     CreateGcRemovedFile(android_data_ +
2326                         "/user/0/com.android.foo/cache/oat_primary/different_isa/base.art");
2327     CreateGcRemovedFile(android_data_ +
2328                         "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/different_dex.arm64.sdm");
2329     CreateGcRemovedFile(
2330         android_data_ +
2331         "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/oat/arm64/different_dex.sdc");
2332     CreateGcRemovedFile(android_data_ +
2333                         "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/base.different_isa.sdm");
2334     CreateGcRemovedFile(
2335         android_data_ +
2336         "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/oat/different_isa/base.sdc");
2337     CreateGcRemovedFile(android_data_ +
2338                         "/app/~~jhrwafasr==/com.android.qux-bredcweff==/different_dex.arm64.sdm");
2339     CreateGcRemovedFile(
2340         android_data_ + "/dalvik-cache/arm64/" + EncodeLocationForDalvikCache(android_data_) +
2341         "@app@~~jhrwafasr==@com.android.qux-bredcweff==@different_dex.apk@classes.sdc");
2342     CreateGcRemovedFile(android_data_ +
2343                         "/app/~~jhrwafasr==/com.android.qux-bredcweff==/base.different_isa.sdm");
2344     CreateGcRemovedFile(android_data_ + "/dalvik-cache/different_isa/" +
2345                         EncodeLocationForDalvikCache(android_data_) +
2346                         "@app@~~jhrwafasr==@com.android.qux-bredcweff==@base.apk@classes.sdc");
2347   }
2348 
CreateGcRemovedFile(const std::string & path)2349   void CreateGcRemovedFile(const std::string& path) {
2350     CreateFile(path);
2351     gc_removed_files_.push_back(path);
2352   }
2353 
CreateGcKeptFile(const std::string & path)2354   void CreateGcKeptFile(const std::string& path) {
2355     CreateFile(path);
2356     gc_kept_files_.push_back(path);
2357   }
2358 
RunCleanup(bool keepPreRebootStagedFiles)2359   void RunCleanup(bool keepPreRebootStagedFiles) {
2360     int64_t aidl_return;
2361     ASSERT_STATUS_OK(artd_->cleanup(
2362         {
2363             PrimaryCurProfilePath{
2364                 .userId = 1, .packageName = "com.android.foo", .profileName = "primary"},
2365             PrimaryCurProfilePath{
2366                 .userId = 3, .packageName = "com.android.foo", .profileName = "primary"},
2367         },
2368         {
2369             ArtifactsPath{
2370                 .dexPath = "/system/app/Foo/Foo.apk", .isa = "arm64", .isInDalvikCache = true},
2371             ArtifactsPath{
2372                 .dexPath = android_expand_ +
2373                            "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/base.apk",
2374                 .isa = "arm64",
2375                 .isInDalvikCache = false},
2376             ArtifactsPath{.dexPath = android_data_ + "/user_de/0/com.android.foo/aaa/2.apk",
2377                           .isa = "arm64",
2378                           .isInDalvikCache = false},
2379         },
2380         {
2381             VdexPath{
2382                 ArtifactsPath{.dexPath = android_data_ + "/user_de/0/com.android.foo/aaa/1.apk",
2383                               .isa = "arm64",
2384                               .isInDalvikCache = false}},
2385         },
2386         {
2387             SecureDexMetadataWithCompanionPaths{
2388                 .dexPath =
2389                     android_data_ + "/app/~~fadsfgadg==/com.android.baz-fadsfgadg==/base.apk",
2390                 .isa = "arm64",
2391                 .isInDalvikCache = false},
2392             SecureDexMetadataWithCompanionPaths{
2393                 .dexPath =
2394                     android_data_ + "/app/~~jhrwafasr==/com.android.qux-bredcweff==/base.apk",
2395                 .isa = "arm64",
2396                 .isInDalvikCache = true},
2397         },
2398         {
2399             RuntimeArtifactsPath{
2400                 .packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2401         },
2402         keepPreRebootStagedFiles,
2403         &aidl_return));
2404   }
2405 
Verify()2406   void Verify() {
2407     for (const std::string& path : gc_removed_files_) {
2408       EXPECT_FALSE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be removed", path);
2409     }
2410 
2411     for (const std::string& path : gc_kept_files_) {
2412       EXPECT_TRUE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be kept", path);
2413     }
2414   }
2415 
2416  private:
2417   std::vector<std::string> gc_removed_files_;
2418   std::vector<std::string> gc_kept_files_;
2419 };
2420 
TEST_F(ArtdCleanupTest,cleanupKeepingPreRebootStagedFiles)2421 TEST_F(ArtdCleanupTest, cleanupKeepingPreRebootStagedFiles) {
2422   SetUpForCleanup();
2423   CreateGcKeptFile(
2424       android_expand_ +
2425       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex.staged");
2426   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex.staged");
2427 
2428   ASSERT_NO_FATAL_FAILURE(RunCleanup(/*keepPreRebootStagedFiles=*/true));
2429   Verify();
2430 }
2431 
TEST_F(ArtdCleanupTest,cleanupRemovingPreRebootStagedFiles)2432 TEST_F(ArtdCleanupTest, cleanupRemovingPreRebootStagedFiles) {
2433   SetUpForCleanup();
2434   CreateGcRemovedFile(
2435       android_expand_ +
2436       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex.staged");
2437   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex.staged");
2438 
2439   ASSERT_NO_FATAL_FAILURE(RunCleanup(/*keepPreRebootStagedFiles=*/false));
2440   Verify();
2441 }
2442 
TEST_F(ArtdCleanupTest,cleanUpPreRebootStagedFiles)2443 TEST_F(ArtdCleanupTest, cleanUpPreRebootStagedFiles) {
2444   // Unmanaged file.
2445   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/1.odex.staged");
2446 
2447   // Not Pre-reboot staged files.
2448   CreateGcKeptFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof");
2449   CreateGcKeptFile(
2450       android_expand_ +
2451       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex");
2452   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex");
2453 
2454   // Pre-reboot staged files.
2455   CreateGcRemovedFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.staged");
2456   CreateGcRemovedFile(
2457       android_expand_ +
2458       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex.staged");
2459   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex.staged");
2460 
2461   ASSERT_STATUS_OK(artd_->cleanUpPreRebootStagedFiles());
2462   Verify();
2463 }
2464 
TEST_F(ArtdTest,isInDalvikCache)2465 TEST_F(ArtdTest, isInDalvikCache) {
2466   TEST_DISABLED_FOR_HOST();
2467 
2468   auto is_in_dalvik_cache = [this](const std::string& dex_file) -> Result<bool> {
2469     bool result;
2470     ndk::ScopedAStatus status = artd_->isInDalvikCache(dex_file, &result);
2471     if (!status.isOk()) {
2472       return Error() << status.getMessage();
2473     }
2474     return result;
2475   };
2476 
2477   EXPECT_THAT(is_in_dalvik_cache("/system/app/base.apk"), HasValue(true));
2478   EXPECT_THAT(is_in_dalvik_cache("/system_ext/app/base.apk"), HasValue(true));
2479   EXPECT_THAT(is_in_dalvik_cache("/vendor/app/base.apk"), HasValue(true));
2480   EXPECT_THAT(is_in_dalvik_cache("/product/app/base.apk"), HasValue(true));
2481   EXPECT_THAT(is_in_dalvik_cache("/data/app/base.apk"), HasValue(false));
2482 
2483   // Test a path where we don't expect to find packages. The method should still work.
2484   EXPECT_THAT(is_in_dalvik_cache("/foo"), HasValue(true));
2485 }
2486 
TEST_F(ArtdTest,deleteSdmSdcFiles)2487 TEST_F(ArtdTest, deleteSdmSdcFiles) {
2488   CreateFile(scratch_path_ + "/a/b.arm64.sdm", "**");     // 2 bytes.
2489   CreateFile(scratch_path_ + "/a/oat/arm64/b.sdc", "*");  // 1 byte.
2490 
2491   int64_t result = -1;
2492   ASSERT_STATUS_OK(artd_->deleteSdmSdcFiles(
2493       {.dexPath = scratch_path_ + "/a/b.apk", .isa = "arm64", .isInDalvikCache = false}, &result));
2494   EXPECT_EQ(result, 2 + 1);
2495 
2496   EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/b.arm64.sdm"));
2497   EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.sdc"));
2498 }
2499 
TEST_F(ArtdTest,deleteRuntimeArtifacts)2500 TEST_F(ArtdTest, deleteRuntimeArtifacts) {
2501   std::vector<std::string> removed_files;
2502   std::vector<std::string> kept_files;
2503 
2504   auto CreateRemovedFile = [&](const std::string& path) {
2505     CreateFile(path);
2506     removed_files.push_back(path);
2507   };
2508 
2509   auto CreateKeptFile = [&](const std::string& path) {
2510     CreateFile(path);
2511     kept_files.push_back(path);
2512   };
2513 
2514   CreateKeptFile(android_data_ +
2515                  "/user/0/com.android.different_package/cache/oat_primary/arm64/base.art");
2516   CreateKeptFile(android_data_ +
2517                  "/user/0/com.android.foo/cache/oat_primary/arm64/different_dex.art");
2518   CreateKeptFile(android_data_ +
2519                  "/user/0/com.android.foo/cache/oat_primary/different_isa/base.art");
2520   CreateKeptFile(android_data_ +
2521                  "/user/0/com.android.foo/cache/not_oat_dir/oat_primary/arm64/base.art");
2522 
2523   CreateRemovedFile(android_data_ + "/user_de/0/com.android.foo/cache/oat_primary/arm64/base.art");
2524   CreateRemovedFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art");
2525   CreateRemovedFile(android_data_ + "/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2526   CreateRemovedFile(android_expand_ +
2527                     "/123456-7890/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2528 
2529   int64_t aidl_return;
2530   ASSERT_TRUE(
2531       artd_
2532           ->deleteRuntimeArtifacts(
2533               {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2534               &aidl_return)
2535           .isOk());
2536 
2537   for (const std::string& path : removed_files) {
2538     EXPECT_FALSE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be removed", path);
2539   }
2540 
2541   for (const std::string& path : kept_files) {
2542     EXPECT_TRUE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be kept", path);
2543   }
2544 }
2545 
TEST_F(ArtdTest,deleteRuntimeArtifactsAndroidDataNotExist)2546 TEST_F(ArtdTest, deleteRuntimeArtifactsAndroidDataNotExist) {
2547   // Will be cleaned up by `android_data_env_`
2548   setenv("ANDROID_DATA", "/non-existing", /*replace=*/1);
2549 
2550   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
2551   EXPECT_CALL(mock_logger_,
2552               Call(_, _, _, _, _, HasSubstr("Failed to find directory /non-existing")));
2553 
2554   int64_t aidl_return;
2555   ASSERT_TRUE(
2556       artd_
2557           ->deleteRuntimeArtifacts(
2558               {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2559               &aidl_return)
2560           .isOk());
2561 
2562   EXPECT_EQ(aidl_return, 0);
2563 }
2564 
2565 // Verifies that `deleteRuntimeArtifacts` doesn't treat "*" as a wildcard. It should either treat it
2566 // as a normal character in the path or reject it. The caller is never supposed to use a wildcard.
TEST_F(ArtdTest,deleteRuntimeArtifactsSpecialChars)2567 TEST_F(ArtdTest, deleteRuntimeArtifactsSpecialChars) {
2568   std::vector<std::string> removed_files;
2569   std::vector<std::string> kept_files;
2570 
2571   auto CreateRemovedFile = [&](const std::string& path) {
2572     CreateFile(path);
2573     removed_files.push_back(path);
2574   };
2575 
2576   auto CreateKeptFile = [&](const std::string& path) {
2577     CreateFile(path);
2578     kept_files.push_back(path);
2579   };
2580 
2581   CreateKeptFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art");
2582 
2583   CreateRemovedFile(android_data_ + "/user/0/*/cache/oat_primary/arm64/base.art");
2584   CreateRemovedFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/*.art");
2585 
2586   int64_t aidl_return;
2587   ASSERT_STATUS_OK(artd_->deleteRuntimeArtifacts(
2588       {.packageName = "*", .dexPath = "/a/b/base.apk", .isa = "arm64"}, &aidl_return));
2589   ASSERT_STATUS_OK(artd_->deleteRuntimeArtifacts(
2590       {.packageName = "com.android.foo", .dexPath = "/a/b/*.apk", .isa = "arm64"}, &aidl_return));
2591   ASSERT_FALSE(artd_
2592                    ->deleteRuntimeArtifacts(
2593                        {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "*"},
2594                        &aidl_return)
2595                    .isOk());
2596 
2597   for (const std::string& path : removed_files) {
2598     EXPECT_FALSE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be removed", path);
2599   }
2600 
2601   for (const std::string& path : kept_files) {
2602     EXPECT_TRUE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be kept", path);
2603   }
2604 }
2605 
TEST_F(ArtdTest,getArtifactsSize)2606 TEST_F(ArtdTest, getArtifactsSize) {
2607   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
2608   CreateFile(oat_dir + "/b.odex", std::string(1, '*'));
2609   CreateFile(oat_dir + "/b.vdex", std::string(2, '*'));
2610   CreateFile(oat_dir + "/b.art", std::string(4, '*'));
2611 
2612   // Irrelevant.
2613   CreateFile(oat_dir + "/c.vdex", std::string(8, '*'));
2614 
2615   int64_t aidl_return = -1;
2616   ASSERT_TRUE(
2617       artd_
2618           ->getArtifactsSize(
2619               {.dexPath = scratch_path_ + "/a/b.apk", .isa = "arm64", .isInDalvikCache = false},
2620               &aidl_return)
2621           .isOk());
2622   EXPECT_EQ(aidl_return, 1 + 2 + 4);
2623 }
2624 
TEST_F(ArtdTest,getVdexFileSize)2625 TEST_F(ArtdTest, getVdexFileSize) {
2626   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
2627   CreateFile(oat_dir + "/b.vdex", std::string(1, '*'));
2628 
2629   // Irrelevant.
2630   CreateFile(oat_dir + "/b.odex", std::string(2, '*'));
2631   CreateFile(oat_dir + "/b.art", std::string(4, '*'));
2632   CreateFile(oat_dir + "/c.vdex", std::string(8, '*'));
2633 
2634   int64_t aidl_return = -1;
2635   ASSERT_TRUE(artd_
2636                   ->getVdexFileSize(ArtifactsPath{.dexPath = scratch_path_ + "/a/b.apk",
2637                                                   .isa = "arm64",
2638                                                   .isInDalvikCache = false},
2639                                     &aidl_return)
2640                   .isOk());
2641   EXPECT_EQ(aidl_return, 1);
2642 }
2643 
TEST_F(ArtdTest,getSdmFileSize)2644 TEST_F(ArtdTest, getSdmFileSize) {
2645   CreateFile(scratch_path_ + "/a/b.arm64.sdm", std::string(1, '*'));
2646 
2647   int64_t aidl_return = -1;
2648   ASSERT_TRUE(
2649       artd_
2650           ->getSdmFileSize(
2651               {.dexPath = scratch_path_ + "/a/b.apk", .isa = "arm64", .isInDalvikCache = false},
2652               &aidl_return)
2653           .isOk());
2654   EXPECT_EQ(aidl_return, 1);
2655 }
2656 
TEST_F(ArtdTest,getRuntimeArtifactsSize)2657 TEST_F(ArtdTest, getRuntimeArtifactsSize) {
2658   CreateFile(android_data_ + "/user_de/0/com.android.foo/cache/oat_primary/arm64/base.art",
2659              std::string(1, '*'));
2660   CreateFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art",
2661              std::string(2, '*'));
2662   CreateFile(android_data_ + "/user/1/com.android.foo/cache/oat_primary/arm64/base.art",
2663              std::string(4, '*'));
2664   CreateFile(
2665       android_expand_ + "/123456-7890/user/1/com.android.foo/cache/oat_primary/arm64/base.art",
2666       std::string(8, '*'));
2667 
2668   // Irrelevant.
2669   CreateFile(android_expand_ + "/user/0/com.android.foo/cache/oat_primary/arm64/different_dex.art",
2670              std::string(16, '*'));
2671 
2672   int64_t aidl_return = -1;
2673   ASSERT_TRUE(
2674       artd_
2675           ->getRuntimeArtifactsSize(
2676               {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2677               &aidl_return)
2678           .isOk());
2679 
2680   EXPECT_EQ(aidl_return, 1 + 2 + 4 + 8);
2681 }
2682 
TEST_F(ArtdTest,getProfileSize)2683 TEST_F(ArtdTest, getProfileSize) {
2684   CreateFile(android_data_ + "/misc/profiles/cur/0/com.android.foo/primary.prof",
2685              std::string(1, '*'));
2686 
2687   // Irrelevant.
2688   CreateFile(android_data_ + "/misc/profiles/cur/0/com.android.foo/split_0.split.prof",
2689              std::string(2, '*'));
2690   CreateFile(android_data_ + "/misc/profiles/cur/0/com.android.bar/primary.prof",
2691              std::string(4, '*'));
2692   CreateFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof",
2693              std::string(8, '*'));
2694 
2695   int64_t aidl_return = -1;
2696   ASSERT_TRUE(artd_
2697                   ->getProfileSize(
2698                       PrimaryCurProfilePath{
2699                           .userId = 0, .packageName = "com.android.foo", .profileName = "primary"},
2700                       &aidl_return)
2701                   .isOk());
2702   EXPECT_EQ(aidl_return, 1);
2703 }
2704 
2705 class ArtdProfileSaveNotificationTest : public ArtdTest {
2706  protected:
SetUp()2707   void SetUp() override {
2708     ArtdTest::SetUp();
2709 
2710     std::vector<std::string> args{GetBin("sleep"), "10"};
2711     std::tie(pid_, scope_guard_) = ScopedExec(args, /*wait=*/false);
2712     notification_file_ = OR_FAIL(BuildPrimaryCurProfilePath(profile_path_));
2713     std::filesystem::create_directories(Dirname(notification_file_));
2714   }
2715 
2716   const PrimaryCurProfilePath profile_path_{
2717       .userId = 0,
2718       .packageName = "com.android.foo",
2719       .profileName = "primary",
2720   };
2721   std::string notification_file_;
2722   int pid_;
2723   std::unique_ptr<ScopeGuard<std::function<void()>>> scope_guard_;
2724 };
2725 
TEST_F(ArtdProfileSaveNotificationTest,initAndWaitSuccess)2726 TEST_F(ArtdProfileSaveNotificationTest, initAndWaitSuccess) {
2727   // Use a condvar to sequence the NewFile::CommitOrAbandon calls.
2728   constexpr std::chrono::duration<int> kTimeout = std::chrono::seconds(1);
2729   std::condition_variable wait_started_cv;
2730   std::mutex mu;
2731 
2732   EXPECT_CALL(mock_poll_, Call)
2733       .Times(2)
2734       .WillRepeatedly(DoAll(
2735           [&](auto, auto, auto) {
2736             // Step 3, 5.
2737             std::unique_lock<std::mutex> lock(mu);
2738             wait_started_cv.notify_one();
2739           },
2740           poll));
2741 
2742   std::shared_ptr<IArtdNotification> notification;
2743   ASSERT_STATUS_OK(artd_->initProfileSaveNotification(profile_path_, pid_, &notification));
2744 
2745   std::unique_lock<std::mutex> lock(mu);
2746 
2747   // Step 1.
2748   std::thread t([&] {
2749     // Step 2.
2750     bool aidl_return;
2751     ASSERT_STATUS_OK(notification->wait(/*in_timeoutMs=*/1000, &aidl_return));
2752     // Step 7.
2753     EXPECT_TRUE(aidl_return);
2754   });
2755   wait_started_cv.wait_for(lock, kTimeout);
2756 
2757   // Step 4.
2758   std::unique_ptr<NewFile> unrelated_file = OR_FAIL(NewFile::Create(
2759       Dirname(notification_file_) + "/unrelated.prof", FsPermission{.uid = -1, .gid = -1}));
2760   OR_FAIL(unrelated_file->CommitOrAbandon());
2761   wait_started_cv.wait_for(lock, kTimeout);
2762 
2763   // Step 6.
2764   std::unique_ptr<NewFile> file =
2765       OR_FAIL(NewFile::Create(notification_file_, FsPermission{.uid = -1, .gid = -1}));
2766   OR_FAIL(file->CommitOrAbandon());
2767 
2768   t.join();
2769 }
2770 
TEST_F(ArtdProfileSaveNotificationTest,initAndWaitProcessGone)2771 TEST_F(ArtdProfileSaveNotificationTest, initAndWaitProcessGone) {
2772   EXPECT_CALL(mock_poll_, Call).WillOnce(poll);
2773 
2774   std::shared_ptr<IArtdNotification> notification;
2775   ASSERT_STATUS_OK(artd_->initProfileSaveNotification(profile_path_, pid_, &notification));
2776 
2777   std::thread t([&] {
2778     bool aidl_return;
2779     ASSERT_STATUS_OK(notification->wait(/*in_timeoutMs=*/1000, &aidl_return));
2780     EXPECT_TRUE(aidl_return);
2781   });
2782 
2783   kill(pid_, SIGKILL);
2784 
2785   t.join();
2786 }
2787 
TEST_F(ArtdProfileSaveNotificationTest,initAndWaitTimeout)2788 TEST_F(ArtdProfileSaveNotificationTest, initAndWaitTimeout) {
2789   EXPECT_CALL(mock_poll_, Call).WillOnce(poll).WillOnce(Return(0));
2790 
2791   std::shared_ptr<IArtdNotification> notification;
2792   ASSERT_STATUS_OK(artd_->initProfileSaveNotification(profile_path_, pid_, &notification));
2793 
2794   std::unique_ptr<NewFile> unrelated_file = OR_FAIL(NewFile::Create(
2795       Dirname(notification_file_) + "/unrelated.prof", FsPermission{.uid = -1, .gid = -1}));
2796   OR_FAIL(unrelated_file->CommitOrAbandon());
2797 
2798   bool aidl_return;
2799   ASSERT_STATUS_OK(notification->wait(/*in_timeoutMs=*/1000, &aidl_return));
2800   EXPECT_FALSE(aidl_return);
2801 }
2802 
TEST_F(ArtdProfileSaveNotificationTest,initProcessGone)2803 TEST_F(ArtdProfileSaveNotificationTest, initProcessGone) {
2804   // Kill the process before pidfd_open.
2805   scope_guard_.reset();
2806 
2807   EXPECT_CALL(mock_poll_, Call).Times(0);
2808 
2809   std::shared_ptr<IArtdNotification> notification;
2810   ASSERT_STATUS_OK(artd_->initProfileSaveNotification(profile_path_, pid_, &notification));
2811 
2812   bool aidl_return;
2813   ASSERT_STATUS_OK(notification->wait(/*in_timeoutMs=*/1000, &aidl_return));
2814   EXPECT_TRUE(aidl_return);
2815 }
2816 
TEST_F(ArtdTest,commitPreRebootStagedFiles)2817 TEST_F(ArtdTest, commitPreRebootStagedFiles) {
2818   CreateFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex.staged",
2819              "new_odex_1");
2820   CreateFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex.staged",
2821              "new_vdex_1");
2822   CreateFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art.staged",
2823              "new_art_1");
2824 
2825   CreateFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex",
2826              "old_odex_1");
2827   CreateFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex",
2828              "old_vdex_1");
2829   CreateFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art", "old_art_1");
2830 
2831   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.odex", "old_odex_2");
2832   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.vdex", "old_vdex_2");
2833   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.art", "old_art_2");
2834 
2835   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.odex.staged", "new_odex_2");
2836   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.vdex.staged", "new_vdex_2");
2837 
2838   CreateFile(android_data_ + "/app/com.android.foo/oat/arm/base.odex", "old_odex_3");
2839   CreateFile(android_data_ + "/app/com.android.foo/oat/arm/base.vdex", "old_vdex_3");
2840   CreateFile(android_data_ + "/app/com.android.foo/oat/arm/base.art", "old_art_3");
2841 
2842   CreateFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof", "old_prof_1");
2843   CreateFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.staged",
2844              "new_prof_1");
2845 
2846   CreateFile(android_data_ + "/misc/profiles/ref/com.android.bar/primary.prof", "old_prof_2");
2847 
2848   bool aidl_return;
2849   ASSERT_STATUS_OK(artd_->commitPreRebootStagedFiles(
2850       {
2851           // Has all new files. All old files should be replaced.
2852           ArtifactsPath{
2853               .dexPath = "/system/app/Foo/Foo.apk", .isa = "arm64", .isInDalvikCache = true},
2854           // Has new files but not ".art" file. Old ".odex" and ".vdex" files should be replaced,
2855           // and old ".art" file should be removed.
2856           ArtifactsPath{.dexPath = android_data_ + "/app/com.android.foo/base.apk",
2857                         .isa = "arm64",
2858                         .isInDalvikCache = false},
2859           // Has no new file. All old files should be kept.
2860           ArtifactsPath{.dexPath = android_data_ + "/app/com.android.foo/base.apk",
2861                         .isa = "arm",
2862                         .isInDalvikCache = false},
2863       },
2864       {
2865           // Has new file.
2866           PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "primary"},
2867           // Has no new file.
2868           PrimaryRefProfilePath{.packageName = "com.android.bar", .profileName = "primary"},
2869       },
2870       &aidl_return));
2871   EXPECT_TRUE(aidl_return);
2872 
2873   CheckContent(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex",
2874                "new_odex_1");
2875   CheckContent(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex",
2876                "new_vdex_1");
2877   CheckContent(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art",
2878                "new_art_1");
2879 
2880   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.odex", "new_odex_2");
2881   CreateFile(android_data_ + "/app/com.android.foo/oat/arm64/base.vdex", "new_vdex_2");
2882   EXPECT_FALSE(std::filesystem::exists(android_data_ + "/app/com.android.foo/oat/arm64/base.art"));
2883 
2884   CheckContent(android_data_ + "/app/com.android.foo/oat/arm/base.odex", "old_odex_3");
2885   CheckContent(android_data_ + "/app/com.android.foo/oat/arm/base.vdex", "old_vdex_3");
2886   CheckContent(android_data_ + "/app/com.android.foo/oat/arm/base.art", "old_art_3");
2887 
2888   CheckContent(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof", "new_prof_1");
2889 
2890   CheckContent(android_data_ + "/misc/profiles/ref/com.android.bar/primary.prof", "old_prof_2");
2891 
2892   // All staged files are gone.
2893   EXPECT_FALSE(std::filesystem::exists(
2894       android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex.staged"));
2895   EXPECT_FALSE(std::filesystem::exists(
2896       android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex.staged"));
2897   EXPECT_FALSE(std::filesystem::exists(
2898       android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art.staged"));
2899   EXPECT_FALSE(
2900       std::filesystem::exists(android_data_ + "/app/com.android.foo/oat/arm64/base.odex.staged"));
2901   EXPECT_FALSE(
2902       std::filesystem::exists(android_data_ + "/app/com.android.foo/oat/arm64/base.vdex.staged"));
2903   EXPECT_FALSE(std::filesystem::exists(android_data_ +
2904                                        "/misc/profiles/ref/com.android.foo/primary.prof.staged"));
2905 }
2906 
TEST_F(ArtdTest,commitPreRebootStagedFilesNoNewFile)2907 TEST_F(ArtdTest, commitPreRebootStagedFilesNoNewFile) {
2908   bool aidl_return;
2909   ASSERT_STATUS_OK(artd_->commitPreRebootStagedFiles(
2910       {
2911           ArtifactsPath{.dexPath = android_data_ + "/app/com.android.foo/base.apk",
2912                         .isa = "arm",
2913                         .isInDalvikCache = false},
2914       },
2915       {},
2916       &aidl_return));
2917   EXPECT_FALSE(aidl_return);
2918 }
2919 
TEST_F(ArtdTest,checkPreRebootSystemRequirements)2920 TEST_F(ArtdTest, checkPreRebootSystemRequirements) {
2921   EXPECT_CALL(*mock_props_, GetProperty("ro.build.version.release")).WillRepeatedly(Return("15"));
2922   std::string chroot_dir = scratch_path_ + "/chroot";
2923   bool aidl_return;
2924 
2925   constexpr const char* kTemplate = R"(
2926     # Comment.
2927     unrelated.system.property=abc
2928 
2929     ro.build.version.release={}
2930   )";
2931 
2932   CreateFile(chroot_dir + "/system/build.prop", ART_FORMAT(kTemplate, 15));
2933   ASSERT_STATUS_OK(artd_->checkPreRebootSystemRequirements(chroot_dir, &aidl_return));
2934   EXPECT_TRUE(aidl_return);
2935 
2936   CreateFile(chroot_dir + "/system/build.prop", ART_FORMAT(kTemplate, 16));
2937   ASSERT_STATUS_OK(artd_->checkPreRebootSystemRequirements(chroot_dir, &aidl_return));
2938   EXPECT_TRUE(aidl_return);
2939 
2940   CreateFile(chroot_dir + "/system/build.prop", ART_FORMAT(kTemplate, 17));
2941   ASSERT_STATUS_OK(artd_->checkPreRebootSystemRequirements(chroot_dir, &aidl_return));
2942   EXPECT_FALSE(aidl_return);
2943 }
2944 
TEST_F(ArtdTest,BuildSystemProperties)2945 TEST_F(ArtdTest, BuildSystemProperties) {
2946   constexpr const char* kContent = R"(
2947     # Comment.
2948     property.foo=123
2949     property.foo?=456
2950     property.bar?=000
2951     property.bar=789
2952     property.baz?=111
2953     import /vendor/my_import.prop ro.*
2954     import=222
2955   )";
2956 
2957   CreateFile(scratch_path_ + "/build.prop", kContent);
2958   BuildSystemProperties props =
2959       OR_FAIL(BuildSystemProperties::Create(scratch_path_ + "/build.prop"));
2960   EXPECT_EQ(props.GetOrEmpty("property.foo"), "123");
2961   EXPECT_EQ(props.GetOrEmpty("property.bar"), "789");
2962   EXPECT_EQ(props.GetOrEmpty("property.baz"), "111");
2963   EXPECT_EQ(props.GetOrEmpty("import"), "222");
2964 }
2965 
2966 class ArtdPreRebootTest : public ArtdTest {
2967  protected:
SetUp()2968   void SetUp() override {
2969     ArtdTest::SetUp();
2970 
2971     pre_reboot_tmp_dir_ = scratch_path_ + "/artd_tmp";
2972     std::filesystem::create_directories(pre_reboot_tmp_dir_);
2973     init_environ_rc_path_ = scratch_path_ + "/init.environ.rc";
2974 
2975     auto mock_props = std::make_unique<NiceMock<MockSystemProperties>>();
2976     mock_props_ = mock_props.get();
2977     ON_CALL(*mock_props_, GetProperty).WillByDefault(Return(""));
2978     auto mock_exec_utils = std::make_unique<MockExecUtils>();
2979     mock_exec_utils_ = mock_exec_utils.get();
2980     auto mock_pre_reboot_build_props = std::make_unique<NiceMock<MockSystemProperties>>();
2981     mock_pre_reboot_build_props_ = mock_pre_reboot_build_props.get();
2982 
2983     ON_CALL(*mock_pre_reboot_build_props_, GetProperty).WillByDefault(Return(""));
2984     ON_CALL(*mock_pre_reboot_build_props_, GetProperty("ro.build.version.sdk"))
2985         .WillByDefault(Return("35"));
2986     ON_CALL(*mock_pre_reboot_build_props_, GetProperty("ro.build.version.codename"))
2987         .WillByDefault(Return("Baklava"));
2988     ON_CALL(*mock_pre_reboot_build_props_, GetProperty("ro.build.version.known_codenames"))
2989         .WillByDefault(Return("VanillaIceCream,Baklava"));
2990 
2991     artd_ = ndk::SharedRefBase::make<Artd>(Options{.is_pre_reboot = true},
2992                                            std::move(mock_props),
2993                                            std::move(mock_exec_utils),
2994                                            mock_kill_.AsStdFunction(),
2995                                            mock_fstat_.AsStdFunction(),
2996                                            mock_poll_.AsStdFunction(),
2997                                            mock_mount_.AsStdFunction(),
2998                                            mock_restorecon_.AsStdFunction(),
2999                                            pre_reboot_tmp_dir_,
3000                                            init_environ_rc_path_,
3001                                            std::move(mock_pre_reboot_build_props));
3002 
3003     ON_CALL(mock_restorecon_, Call).WillByDefault(Return(Result<void>()));
3004 
3005     constexpr const char* kInitEnvironRcTmpl = R"(
3006       on early-init
3007           export ANDROID_ART_ROOT {}
3008           export ANDROID_DATA {}
3009     )";
3010     ASSERT_TRUE(WriteStringToFile(ART_FORMAT(kInitEnvironRcTmpl, art_root_, android_data_),
3011                                   init_environ_rc_path_));
3012 
3013     tmp_profile_path_.finalPath.get<WritableProfilePath::forPrimary>().isPreReboot = true;
3014     output_artifacts_.artifactsPath.isPreReboot = true;
3015   }
3016 
3017   std::string pre_reboot_tmp_dir_;
3018   std::string init_environ_rc_path_;
3019   MockFunction<int(const char*, const char*, const char*, uint32_t, const void*)> mock_mount_;
3020   MockFunction<Result<void>(const std::string&,
3021                             const std::optional<OutputArtifacts::PermissionSettings::SeContext>&,
3022                             bool)>
3023       mock_restorecon_;
3024   MockSystemProperties* mock_pre_reboot_build_props_;
3025 };
3026 
TEST_F(ArtdPreRebootTest,preRebootInit)3027 TEST_F(ArtdPreRebootTest, preRebootInit) {
3028   // Color the env vars to make sure that the expected values are not from the parent process but
3029   // from "/init.environ.rc".
3030   ASSERT_EQ(setenv("ANDROID_ART_ROOT", "old_value", /*replace=*/1), 0);
3031   ASSERT_EQ(setenv("ANDROID_DATA", "old_value", /*replace=*/1), 0);
3032   ASSERT_EQ(setenv("BOOTCLASSPATH", "old_value", /*replace=*/1), 0);
3033 
3034   // Add an env var that doesn't get overridden, to check that it gets removed.
3035   ASSERT_EQ(setenv("FOO", "old_value", /*replace=*/1), 0);
3036 
3037   InSequence seq;
3038 
3039   EXPECT_CALL(*mock_exec_utils_,
3040               DoExecAndReturnCode(
3041                   AllOf(WhenSplitBy("--",
3042                                     AllOf(Contains(art_root_ + "/bin/art_exec"),
3043                                           Contains("--drop-capabilities")),
3044                                     AllOf(Contains("/apex/com.android.sdkext/bin/derive_classpath"),
3045                                           Contains(Flag("--override-device-sdk-version=", "35")),
3046                                           Contains(Flag("--override-device-codename=", "Baklava")),
3047                                           Contains(Flag("--override-device-known-codenames=",
3048                                                         "VanillaIceCream,Baklava")))),
3049                         HasKeepFdsFor("/proc/self/fd/")),
3050                   _,
3051                   _))
3052       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("/proc/self/fd/", "export BOOTCLASSPATH /foo:/bar")),
3053                       Return(0)));
3054 
3055   EXPECT_CALL(mock_mount_,
3056               Call(StrEq(pre_reboot_tmp_dir_ + "/art_apex_data"),
3057                    StrEq("/data/misc/apexdata/com.android.art"),
3058                    /*fs_type=*/nullptr,
3059                    MS_BIND | MS_PRIVATE,
3060                    /*data=*/nullptr))
3061       .WillOnce(Return(0));
3062 
3063   EXPECT_CALL(mock_mount_,
3064               Call(StrEq(pre_reboot_tmp_dir_ + "/odrefresh"),
3065                    StrEq("/data/misc/odrefresh"),
3066                    /*fs_type=*/nullptr,
3067                    MS_BIND | MS_PRIVATE,
3068                    /*data=*/nullptr))
3069       .WillOnce(Return(0));
3070 
3071   EXPECT_CALL(*mock_exec_utils_,
3072               DoExecAndReturnCode(WhenSplitBy("--",
3073                                               AllOf(Contains(art_root_ + "/bin/art_exec"),
3074                                                     Contains("--drop-capabilities")),
3075                                               AllOf(Contains(art_root_ + "/bin/odrefresh"),
3076                                                     Contains("--only-boot-images"),
3077                                                     Contains("--compile"))),
3078                                   _,
3079                                   _))
3080       .WillOnce(Return(0));
3081 
3082   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
3083   ASSERT_STATUS_OK(artd_->createCancellationSignal(&cancellation_signal));
3084 
3085   bool aidl_return;
3086   ASSERT_STATUS_OK(artd_->preRebootInit(cancellation_signal, &aidl_return));
3087   EXPECT_TRUE(aidl_return);
3088 
3089   auto env_var_count = []() {
3090     int count = 0;
3091     for (char** it = environ; *it != nullptr; it++) {
3092       count++;
3093     }
3094     return count;
3095   };
3096 
3097   EXPECT_EQ(getenv("ANDROID_ART_ROOT"), art_root_);
3098   EXPECT_EQ(getenv("ANDROID_DATA"), android_data_);
3099   EXPECT_STREQ(getenv("BOOTCLASSPATH"), "/foo:/bar");
3100   EXPECT_EQ(env_var_count(), 3);
3101   EXPECT_TRUE(std::filesystem::exists(pre_reboot_tmp_dir_ + "/preparation_done"));
3102 
3103   // Color the env vars again to simulate that artd died and restarted.
3104   ASSERT_EQ(setenv("ANDROID_ART_ROOT", "old_value", /*replace=*/1), 0);
3105   ASSERT_EQ(setenv("ANDROID_DATA", "old_value", /*replace=*/1), 0);
3106   ASSERT_EQ(setenv("BOOTCLASSPATH", "old_value", /*replace=*/1), 0);
3107 
3108   // Calling again will not involve `mount`, `derive_classpath`, or `odrefresh` but only restore env
3109   // vars.
3110   ASSERT_STATUS_OK(artd_->preRebootInit(/*in_cancellationSignal=*/nullptr, &aidl_return));
3111   EXPECT_TRUE(aidl_return);
3112   EXPECT_EQ(getenv("ANDROID_ART_ROOT"), art_root_);
3113   EXPECT_EQ(getenv("ANDROID_DATA"), android_data_);
3114   EXPECT_STREQ(getenv("BOOTCLASSPATH"), "/foo:/bar");
3115   EXPECT_EQ(env_var_count(), 3);
3116 }
3117 
TEST_F(ArtdPreRebootTest,preRebootInitFailed)3118 TEST_F(ArtdPreRebootTest, preRebootInitFailed) {
3119   EXPECT_CALL(*mock_exec_utils_,
3120               DoExecAndReturnCode(Contains("/apex/com.android.sdkext/bin/derive_classpath"), _, _))
3121       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("/proc/self/fd/", "export BOOTCLASSPATH /foo:/bar")),
3122                       Return(0)));
3123 
3124   EXPECT_CALL(mock_mount_, Call).Times(2).WillRepeatedly(Return(0));
3125 
3126   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(Contains(art_root_ + "/bin/odrefresh"), _, _))
3127       .WillOnce(Return(1));
3128 
3129   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
3130   ASSERT_STATUS_OK(artd_->createCancellationSignal(&cancellation_signal));
3131 
3132   bool aidl_return;
3133   ndk::ScopedAStatus status = artd_->preRebootInit(cancellation_signal, &aidl_return);
3134   EXPECT_FALSE(status.isOk());
3135   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
3136   EXPECT_STREQ(status.getMessage(), "odrefresh returned an unexpected code: 1");
3137 }
3138 
TEST_F(ArtdPreRebootTest,preRebootInitNoRetry)3139 TEST_F(ArtdPreRebootTest, preRebootInitNoRetry) {
3140   // Simulate that a previous attempt failed halfway.
3141   ASSERT_TRUE(WriteStringToFile("", pre_reboot_tmp_dir_ + "/classpath.txt"));
3142 
3143   bool aidl_return;
3144   ndk::ScopedAStatus status = artd_->preRebootInit(/*in_cancellationSignal=*/nullptr, &aidl_return);
3145   EXPECT_FALSE(status.isOk());
3146   EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_STATE);
3147   EXPECT_STREQ(
3148       status.getMessage(),
3149       "preRebootInit must not be concurrently called or retried after cancellation or failure");
3150 }
3151 
TEST_F(ArtdPreRebootTest,preRebootInitCancelled)3152 TEST_F(ArtdPreRebootTest, preRebootInitCancelled) {
3153   EXPECT_CALL(*mock_exec_utils_,
3154               DoExecAndReturnCode(Contains("/apex/com.android.sdkext/bin/derive_classpath"), _, _))
3155       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("/proc/self/fd/", "export BOOTCLASSPATH /foo:/bar")),
3156                       Return(0)));
3157 
3158   EXPECT_CALL(mock_mount_, Call).Times(2).WillRepeatedly(Return(0));
3159 
3160   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
3161   ASSERT_STATUS_OK(artd_->createCancellationSignal(&cancellation_signal));
3162 
3163   constexpr pid_t kPid = 123;
3164   constexpr std::chrono::duration<int> kTimeout = std::chrono::seconds(1);
3165 
3166   std::condition_variable process_started_cv, process_killed_cv;
3167   std::mutex mu;
3168 
3169   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(Contains(art_root_ + "/bin/odrefresh"), _, _))
3170       .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
3171         std::unique_lock<std::mutex> lock(mu);
3172         // Step 2.
3173         callbacks.on_start(kPid);
3174         process_started_cv.notify_one();
3175         EXPECT_EQ(process_killed_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
3176         // Step 5.
3177         callbacks.on_end(kPid);
3178         return Error();
3179       });
3180 
3181   EXPECT_CALL(mock_kill_, Call(-kPid, SIGKILL)).WillOnce([&](auto, auto) {
3182     // Step 4.
3183     process_killed_cv.notify_one();
3184     return 0;
3185   });
3186 
3187   std::thread t;
3188   bool aidl_return;
3189   {
3190     std::unique_lock<std::mutex> lock(mu);
3191     // Step 1.
3192     t = std::thread(
3193         [&] { ASSERT_STATUS_OK(artd_->preRebootInit(cancellation_signal, &aidl_return)); });
3194     EXPECT_EQ(process_started_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
3195     // Step 3.
3196     cancellation_signal->cancel();
3197   }
3198 
3199   t.join();
3200 
3201   // Step 6.
3202   EXPECT_FALSE(aidl_return);
3203 }
3204 
TEST_F(ArtdPreRebootTest,dexopt)3205 TEST_F(ArtdPreRebootTest, dexopt) {
3206   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
3207 
3208   dexopt_options_.generateAppImage = true;
3209 
3210   EXPECT_CALL(
3211       *mock_exec_utils_,
3212       DoExecAndReturnCode(
3213           WhenSplitBy("--", _, Contains(Flag("--profile-file-fd=", FdOf(profile_file)))), _, _))
3214       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
3215                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
3216                       WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
3217                       Return(0)));
3218   RunDexopt();
3219 
3220   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex.staged", "oat");
3221   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex.staged", "vdex");
3222   CheckContent(scratch_path_ + "/a/oat/arm64/b.art.staged", "art");
3223 }
3224 
TEST_F(ArtdPreRebootTest,dexoptPreRebootProfile)3225 TEST_F(ArtdPreRebootTest, dexoptPreRebootProfile) {
3226   profile_path_->get<ProfilePath::tmpProfilePath>()
3227       .finalPath.get<WritableProfilePath::forPrimary>()
3228       .isPreReboot = true;
3229   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
3230 
3231   dexopt_options_.generateAppImage = true;
3232 
3233   EXPECT_CALL(
3234       *mock_exec_utils_,
3235       DoExecAndReturnCode(
3236           WhenSplitBy("--", _, Contains(Flag("--profile-file-fd=", FdOf(profile_file)))), _, _))
3237       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
3238                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
3239                       WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
3240                       Return(0)));
3241   RunDexopt();
3242 
3243   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex.staged", "oat");
3244   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex.staged", "vdex");
3245   CheckContent(scratch_path_ + "/a/oat/arm64/b.art.staged", "art");
3246 }
3247 
TEST_F(ArtdPreRebootTest,copyAndRewriteProfile)3248 TEST_F(ArtdPreRebootTest, copyAndRewriteProfile) {
3249   std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
3250   CreateFile(src_file, "valid_profile");
3251 
3252   CreateFile(dex_file_);
3253 
3254   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode)
3255       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
3256                       Return(ProfmanResult::kCopyAndUpdateSuccess)));
3257 
3258   auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
3259 
3260   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
3261   EXPECT_THAT(dst.profilePath.tmpPath, ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
3262   CheckContent(dst.profilePath.tmpPath, "def");
3263 }
3264 
TEST_F(ArtdPreRebootTest,copyAndRewriteEmbeddedProfile)3265 TEST_F(ArtdPreRebootTest, copyAndRewriteEmbeddedProfile) {
3266   TEST_DISABLED_FOR_SHELL_WITHOUT_MEMFD_ACCESS();
3267 
3268   CreateZipWithSingleEntry(dex_file_, "assets/art-profile/baseline.prof", "valid_profile");
3269 
3270   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode)
3271       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
3272                       Return(ProfmanResult::kCopyAndUpdateSuccess)));
3273 
3274   auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
3275 
3276   EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
3277   EXPECT_THAT(dst.profilePath.tmpPath, ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
3278   CheckContent(dst.profilePath.tmpPath, "def");
3279 }
3280 
TEST_F(ArtdPreRebootTest,mergeProfiles)3281 TEST_F(ArtdPreRebootTest, mergeProfiles) {
3282   std::string reference_profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
3283   CreateFile(reference_profile_file, "abc");
3284 
3285   PrimaryCurProfilePath profile_1_path{
3286       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
3287   std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
3288   CreateFile(profile_1_file, "def");
3289 
3290   OutputProfile output_profile{.profilePath = tmp_profile_path_,
3291                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
3292   output_profile.profilePath.id = "";
3293   output_profile.profilePath.tmpPath = "";
3294 
3295   std::string dex_file_1 = scratch_path_ + "/a/b.apk";
3296   CreateFile(dex_file_1);
3297 
3298   EXPECT_CALL(
3299       *mock_exec_utils_,
3300       DoExecAndReturnCode(
3301           WhenSplitBy("--",
3302                       _,
3303                       AllOf(Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
3304                             Contains(Flag("--profile-file-fd=", FdHasContent("def"))))),
3305           _,
3306           _))
3307       .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
3308                       Return(ProfmanResult::kCompile)));
3309 
3310   bool result;
3311   ASSERT_STATUS_OK(artd_->mergeProfiles({profile_1_path},
3312                                         profile_path_,
3313                                         &output_profile,
3314                                         {dex_file_1},
3315                                         /*in_options=*/{},
3316                                         &result));
3317   EXPECT_TRUE(result);
3318   EXPECT_THAT(output_profile.profilePath.tmpPath,
3319               ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
3320   CheckContent(output_profile.profilePath.tmpPath, "merged");
3321 }
3322 
TEST_F(ArtdPreRebootTest,mergeProfilesPreRebootReference)3323 TEST_F(ArtdPreRebootTest, mergeProfilesPreRebootReference) {
3324   profile_path_->get<ProfilePath::tmpProfilePath>()
3325       .finalPath.get<WritableProfilePath::forPrimary>()
3326       .isPreReboot = true;
3327   std::string reference_profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
3328   CreateFile(reference_profile_file, "abc");
3329 
3330   PrimaryCurProfilePath profile_1_path{
3331       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
3332   std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
3333   CreateFile(profile_1_file, "def");
3334 
3335   OutputProfile output_profile{.profilePath = tmp_profile_path_,
3336                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
3337   output_profile.profilePath.id = "";
3338   output_profile.profilePath.tmpPath = "";
3339 
3340   std::string dex_file_1 = scratch_path_ + "/a/b.apk";
3341   CreateFile(dex_file_1);
3342 
3343   EXPECT_CALL(
3344       *mock_exec_utils_,
3345       DoExecAndReturnCode(
3346           WhenSplitBy("--",
3347                       _,
3348                       AllOf(Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
3349                             Contains(Flag("--profile-file-fd=", FdHasContent("def"))))),
3350           _,
3351           _))
3352       .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
3353                       Return(ProfmanResult::kCompile)));
3354 
3355   bool result;
3356   ASSERT_STATUS_OK(artd_->mergeProfiles({profile_1_path},
3357                                         profile_path_,
3358                                         &output_profile,
3359                                         {dex_file_1},
3360                                         /*in_options=*/{},
3361                                         &result));
3362   EXPECT_TRUE(result);
3363   EXPECT_THAT(output_profile.profilePath.tmpPath,
3364               ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
3365   CheckContent(output_profile.profilePath.tmpPath, "merged");
3366 }
3367 
3368 }  // namespace
3369 }  // namespace artd
3370 }  // namespace art
3371