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