• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "artd.h"
18 
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <algorithm>
25 #include <chrono>
26 #include <condition_variable>
27 #include <csignal>
28 #include <filesystem>
29 #include <functional>
30 #include <memory>
31 #include <mutex>
32 #include <optional>
33 #include <string>
34 #include <thread>
35 #include <type_traits>
36 #include <unordered_set>
37 #include <utility>
38 #include <vector>
39 
40 #include "aidl/com/android/server/art/ArtConstants.h"
41 #include "aidl/com/android/server/art/BnArtd.h"
42 #include "android-base/collections.h"
43 #include "android-base/errors.h"
44 #include "android-base/file.h"
45 #include "android-base/logging.h"
46 #include "android-base/parseint.h"
47 #include "android-base/result.h"
48 #include "android-base/scopeguard.h"
49 #include "android-base/strings.h"
50 #include "android/binder_auto_utils.h"
51 #include "android/binder_status.h"
52 #include "base/array_ref.h"
53 #include "base/common_art_test.h"
54 #include "exec_utils.h"
55 #include "fmt/format.h"
56 #include "gmock/gmock.h"
57 #include "gtest/gtest.h"
58 #include "oat_file.h"
59 #include "path_utils.h"
60 #include "profman/profman_result.h"
61 #include "testing.h"
62 #include "tools/system_properties.h"
63 
64 namespace art {
65 namespace artd {
66 namespace {
67 
68 using ::aidl::com::android::server::art::ArtConstants;
69 using ::aidl::com::android::server::art::ArtdDexoptResult;
70 using ::aidl::com::android::server::art::ArtifactsPath;
71 using ::aidl::com::android::server::art::DexMetadataPath;
72 using ::aidl::com::android::server::art::DexoptOptions;
73 using ::aidl::com::android::server::art::FileVisibility;
74 using ::aidl::com::android::server::art::FsPermission;
75 using ::aidl::com::android::server::art::GetDexoptStatusResult;
76 using ::aidl::com::android::server::art::IArtdCancellationSignal;
77 using ::aidl::com::android::server::art::OutputArtifacts;
78 using ::aidl::com::android::server::art::OutputProfile;
79 using ::aidl::com::android::server::art::PriorityClass;
80 using ::aidl::com::android::server::art::ProfilePath;
81 using ::aidl::com::android::server::art::VdexPath;
82 using ::android::base::Append;
83 using ::android::base::Error;
84 using ::android::base::make_scope_guard;
85 using ::android::base::ParseInt;
86 using ::android::base::ReadFdToString;
87 using ::android::base::ReadFileToString;
88 using ::android::base::Result;
89 using ::android::base::ScopeGuard;
90 using ::android::base::Split;
91 using ::android::base::WriteStringToFd;
92 using ::android::base::WriteStringToFile;
93 using ::testing::_;
94 using ::testing::AllOf;
95 using ::testing::AnyNumber;
96 using ::testing::AnyOf;
97 using ::testing::Contains;
98 using ::testing::ContainsRegex;
99 using ::testing::DoAll;
100 using ::testing::ElementsAre;
101 using ::testing::Field;
102 using ::testing::HasSubstr;
103 using ::testing::IsEmpty;
104 using ::testing::Matcher;
105 using ::testing::MockFunction;
106 using ::testing::Not;
107 using ::testing::Property;
108 using ::testing::ResultOf;
109 using ::testing::Return;
110 using ::testing::SetArgPointee;
111 using ::testing::UnorderedElementsAreArray;
112 using ::testing::WithArg;
113 
114 using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
115 using PrimaryRefProfilePath = ProfilePath::PrimaryRefProfilePath;
116 using TmpProfilePath = ProfilePath::TmpProfilePath;
117 
118 using ::fmt::literals::operator""_format;  // NOLINT
119 
120 constexpr uid_t kRootUid = 0;
121 
ScopedSetLogger(android::base::LogFunction && logger)122 ScopeGuard<std::function<void()>> ScopedSetLogger(android::base::LogFunction&& logger) {
123   android::base::LogFunction old_logger = android::base::SetLogger(std::move(logger));
124   return make_scope_guard([old_logger = std::move(old_logger)]() mutable {
125     android::base::SetLogger(std::move(old_logger));
126   });
127 }
128 
CheckContent(const std::string & path,const std::string & expected_content)129 void CheckContent(const std::string& path, const std::string& expected_content) {
130   std::string actual_content;
131   ASSERT_TRUE(ReadFileToString(path, &actual_content));
132   EXPECT_EQ(actual_content, expected_content);
133 }
134 
CheckOtherReadable(const std::string & path,bool expected_value)135 void CheckOtherReadable(const std::string& path, bool expected_value) {
136   EXPECT_EQ((std::filesystem::status(path).permissions() & std::filesystem::perms::others_read) !=
137                 std::filesystem::perms::none,
138             expected_value);
139 }
140 
GetFlagValues(ArrayRef<const std::string> args,std::string_view flag)141 Result<std::vector<std::string>> GetFlagValues(ArrayRef<const std::string> args,
142                                                std::string_view flag) {
143   std::vector<std::string> values;
144   for (const std::string& arg : args) {
145     std::string_view value(arg);
146     if (android::base::ConsumePrefix(&value, flag)) {
147       values.emplace_back(value);
148     }
149   }
150   if (values.empty()) {
151     return Errorf("Flag '{}' not found", flag);
152   }
153   return values;
154 }
155 
GetFlagValue(ArrayRef<const std::string> args,std::string_view flag)156 Result<std::string> GetFlagValue(ArrayRef<const std::string> args, std::string_view flag) {
157   std::vector<std::string> flag_values = OR_RETURN(GetFlagValues(args, flag));
158   if (flag_values.size() > 1) {
159     return Errorf("Duplicate flag '{}'", flag);
160   }
161   return flag_values[0];
162 }
163 
WriteToFdFlagImpl(const std::vector<std::string> & args,std::string_view flag,std::string_view content,bool assume_empty)164 void WriteToFdFlagImpl(const std::vector<std::string>& args,
165                        std::string_view flag,
166                        std::string_view content,
167                        bool assume_empty) {
168   std::string value = OR_FAIL(GetFlagValue(ArrayRef<const std::string>(args), flag));
169   ASSERT_NE(value, "");
170   int fd;
171   ASSERT_TRUE(ParseInt(value, &fd));
172   if (assume_empty) {
173     ASSERT_EQ(lseek(fd, /*offset=*/0, SEEK_CUR), 0);
174   } else {
175     ASSERT_EQ(ftruncate(fd, /*length=*/0), 0);
176     ASSERT_EQ(lseek(fd, /*offset=*/0, SEEK_SET), 0);
177   }
178   ASSERT_TRUE(WriteStringToFd(content, fd));
179 }
180 
181 // Writes `content` to the FD specified by the `flag`.
ACTION_P(WriteToFdFlag,flag,content)182 ACTION_P(WriteToFdFlag, flag, content) {
183   WriteToFdFlagImpl(arg0, flag, content, /*assume_empty=*/true);
184 }
185 
186 // Clears any existing content and writes `content` to the FD specified by the `flag`.
ACTION_P(ClearAndWriteToFdFlag,flag,content)187 ACTION_P(ClearAndWriteToFdFlag, flag, content) {
188   WriteToFdFlagImpl(arg0, flag, content, /*assume_empty=*/false);
189 }
190 
191 // Matches a flag that starts with `flag` and whose value matches `matcher`.
192 MATCHER_P2(Flag, flag, matcher, "") {
193   std::string_view value(arg);
194   if (!android::base::ConsumePrefix(&value, flag)) {
195     return false;
196   }
197   return ExplainMatchResult(matcher, std::string(value), result_listener);
198 }
199 
200 // Matches a flag that starts with `flag` and whose value is a colon-separated list that matches
201 // `matcher`. The matcher acts on an `std::vector<std::string>` of the split list argument.
202 MATCHER_P2(ListFlag, flag, matcher, "") {
203   return ExplainMatchResult(
204       Flag(flag, ResultOf(std::bind(Split, std::placeholders::_1, ":"), matcher)),
205       arg,
206       result_listener);
207 }
208 
209 // Matches an FD of a file whose path matches `matcher`.
210 MATCHER_P(FdOf, matcher, "") {
211   std::string proc_path = "/proc/self/fd/{}"_format(arg);
212   char path[PATH_MAX];
213   ssize_t len = readlink(proc_path.c_str(), path, sizeof(path));
214   if (len < 0) {
215     return false;
216   }
217   return ExplainMatchResult(matcher, std::string(path, static_cast<size_t>(len)), result_listener);
218 }
219 
220 // Matches an FD of a file whose content matches `matcher`.
221 MATCHER_P(FdHasContent, matcher, "") {
222   int fd;
223   if (!ParseInt(arg, &fd)) {
224     return false;
225   }
226   std::string actual_content;
227   if (!ReadFdToString(fd, &actual_content)) {
228     return false;
229   }
230   return ExplainMatchResult(matcher, actual_content, result_listener);
231 }
232 
233 template <typename T, typename U>
SplitBy(const std::vector<T> & list,const U & separator)234 Result<std::pair<ArrayRef<const T>, ArrayRef<const T>>> SplitBy(const std::vector<T>& list,
235                                                                 const U& separator) {
236   auto it = std::find(list.begin(), list.end(), separator);
237   if (it == list.end()) {
238     return Errorf("'{}' not found", separator);
239   }
240   size_t pos = it - list.begin();
241   return std::make_pair(ArrayRef<const T>(list).SubArray(0, pos),
242                         ArrayRef<const T>(list).SubArray(pos + 1));
243 }
244 
245 // Matches a container that, when split by `separator`, the first part matches `head_matcher`, and
246 // the second part matches `tail_matcher`.
247 MATCHER_P3(WhenSplitBy, separator, head_matcher, tail_matcher, "") {
248   auto [head, tail] = OR_MISMATCH(SplitBy(arg, separator));
249   return ExplainMatchResult(head_matcher, head, result_listener) &&
250          ExplainMatchResult(tail_matcher, tail, result_listener);
251 }
252 
253 MATCHER_P(HasKeepFdsForImpl, fd_flags, "") {
254   auto [head, tail] = OR_MISMATCH(SplitBy(arg, "--"));
255   std::string keep_fds_value = OR_MISMATCH(GetFlagValue(head, "--keep-fds="));
256   std::vector<std::string> keep_fds = Split(keep_fds_value, ":");
257   std::vector<std::string> fd_flag_values;
258   for (std::string_view fd_flag : fd_flags) {
259     for (const std::string& fd_flag_value : OR_MISMATCH(GetFlagValues(tail, fd_flag))) {
260       for (std::string& fd : Split(fd_flag_value, ":")) {
261         fd_flag_values.push_back(std::move(fd));
262       }
263     }
264   }
265   return ExplainMatchResult(UnorderedElementsAreArray(fd_flag_values), keep_fds, result_listener);
266 }
267 
268 // Matches an argument list that has the "--keep-fds=" flag before "--", whose value is a
269 // semicolon-separated list that contains exactly the values of the given flags after "--".
270 //
271 // E.g., if the flags after "--" are "--foo=1", "--bar=2:3", "--baz=4", "--baz=5", and the matcher
272 // is `HasKeepFdsFor("--foo=", "--bar=", "--baz=")`, then it requires the "--keep-fds=" flag before
273 // "--" to contain exactly 1, 2, 3, 4, and 5.
274 template <typename... Args>
HasKeepFdsFor(Args &&...args)275 auto HasKeepFdsFor(Args&&... args) {
276   std::vector<std::string_view> fd_flags;
277   Append(fd_flags, std::forward<Args>(args)...);
278   return HasKeepFdsForImpl(fd_flags);
279 }
280 
281 class MockSystemProperties : public tools::SystemProperties {
282  public:
283   MOCK_METHOD(std::string, GetProperty, (const std::string& key), (const, override));
284 };
285 
286 class MockExecUtils : public ExecUtils {
287  public:
288   // A workaround to avoid MOCK_METHOD on a method with an `std::string*` parameter, which will lead
289   // to a conflict between gmock and android-base/logging.h (b/132668253).
ExecAndReturnResult(const std::vector<std::string> & arg_vector,int,const ExecCallbacks & callbacks,ProcessStat * stat,std::string *) const290   ExecResult ExecAndReturnResult(const std::vector<std::string>& arg_vector,
291                                  int,
292                                  const ExecCallbacks& callbacks,
293                                  ProcessStat* stat,
294                                  std::string*) const override {
295     Result<int> code = DoExecAndReturnCode(arg_vector, callbacks, stat);
296     if (code.ok()) {
297       return {.status = ExecResult::kExited, .exit_code = code.value()};
298     }
299     return {.status = ExecResult::kUnknown};
300   }
301 
302   MOCK_METHOD(Result<int>,
303               DoExecAndReturnCode,
304               (const std::vector<std::string>& arg_vector,
305                const ExecCallbacks& callbacks,
306                ProcessStat* stat),
307               (const));
308 };
309 
310 class ArtdTest : public CommonArtTest {
311  protected:
SetUp()312   void SetUp() override {
313     CommonArtTest::SetUp();
314     auto mock_props = std::make_unique<MockSystemProperties>();
315     mock_props_ = mock_props.get();
316     EXPECT_CALL(*mock_props_, GetProperty).Times(AnyNumber()).WillRepeatedly(Return(""));
317     auto mock_exec_utils = std::make_unique<MockExecUtils>();
318     mock_exec_utils_ = mock_exec_utils.get();
319     artd_ = ndk::SharedRefBase::make<Artd>(std::move(mock_props),
320                                            std::move(mock_exec_utils),
321                                            mock_kill_.AsStdFunction(),
322                                            mock_fstat_.AsStdFunction());
323     scratch_dir_ = std::make_unique<ScratchDir>();
324     scratch_path_ = scratch_dir_->GetPath();
325     // Remove the trailing '/';
326     scratch_path_.resize(scratch_path_.length() - 1);
327 
328     ON_CALL(mock_fstat_, Call).WillByDefault(fstat);
329 
330     // Use an arbitrary existing directory as ART root.
331     art_root_ = scratch_path_ + "/com.android.art";
332     std::filesystem::create_directories(art_root_);
333     setenv("ANDROID_ART_ROOT", art_root_.c_str(), /*overwrite=*/1);
334 
335     // Use an arbitrary existing directory as Android data.
336     android_data_ = scratch_path_ + "/data";
337     std::filesystem::create_directories(android_data_);
338     setenv("ANDROID_DATA", android_data_.c_str(), /*overwrite=*/1);
339 
340     // Use an arbitrary existing directory as Android expand.
341     android_expand_ = scratch_path_ + "/mnt/expand";
342     std::filesystem::create_directories(android_expand_);
343     setenv("ANDROID_EXPAND", android_expand_.c_str(), /*overwrite=*/1);
344 
345     dex_file_ = scratch_path_ + "/a/b.apk";
346     isa_ = "arm64";
347     artifacts_path_ = ArtifactsPath{
348         .dexPath = dex_file_,
349         .isa = isa_,
350         .isInDalvikCache = false,
351     };
352     struct stat st;
353     ASSERT_EQ(stat(scratch_path_.c_str(), &st), 0);
354     output_artifacts_ = OutputArtifacts{
355         .artifactsPath = artifacts_path_,
356         .permissionSettings =
357             OutputArtifacts::PermissionSettings{
358                 .dirFsPermission =
359                     FsPermission{
360                         .uid = static_cast<int32_t>(st.st_uid),
361                         .gid = static_cast<int32_t>(st.st_gid),
362                         .isOtherReadable = true,
363                         .isOtherExecutable = true,
364                     },
365                 .fileFsPermission =
366                     FsPermission{
367                         .uid = static_cast<int32_t>(st.st_uid),
368                         .gid = static_cast<int32_t>(st.st_gid),
369                         .isOtherReadable = true,
370                     },
371             },
372     };
373     clc_1_ = GetTestDexFileName("Main");
374     clc_2_ = GetTestDexFileName("Nested");
375     class_loader_context_ = "PCL[{}:{}]"_format(clc_1_, clc_2_);
376     compiler_filter_ = "speed";
377     TmpProfilePath tmp_profile_path{
378         .finalPath =
379             PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "primary"},
380         .id = "12345"};
381     profile_path_ = tmp_profile_path;
382     vdex_path_ = artifacts_path_;
383     dm_path_ = DexMetadataPath{.dexPath = dex_file_};
384     std::filesystem::create_directories(
385         std::filesystem::path(OR_FATAL(BuildFinalProfilePath(tmp_profile_path))).parent_path());
386   }
387 
TearDown()388   void TearDown() override {
389     scratch_dir_.reset();
390     CommonArtTest::TearDown();
391   }
392 
RunDexopt(binder_exception_t expected_status=EX_NONE,Matcher<ArtdDexoptResult> aidl_return_matcher=Field (& ArtdDexoptResult::cancelled,false),std::shared_ptr<IArtdCancellationSignal> cancellation_signal=nullptr)393   void RunDexopt(binder_exception_t expected_status = EX_NONE,
394                  Matcher<ArtdDexoptResult> aidl_return_matcher = Field(&ArtdDexoptResult::cancelled,
395                                                                        false),
396                  std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) {
397     RunDexopt(Property(&ndk::ScopedAStatus::getExceptionCode, expected_status),
398               std::move(aidl_return_matcher),
399               cancellation_signal);
400   }
401 
RunDexopt(Matcher<ndk::ScopedAStatus> status_matcher,Matcher<ArtdDexoptResult> aidl_return_matcher=Field (& ArtdDexoptResult::cancelled,false),std::shared_ptr<IArtdCancellationSignal> cancellation_signal=nullptr)402   void RunDexopt(Matcher<ndk::ScopedAStatus> status_matcher,
403                  Matcher<ArtdDexoptResult> aidl_return_matcher = Field(&ArtdDexoptResult::cancelled,
404                                                                        false),
405                  std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) {
406     InitFilesBeforeDexopt();
407     if (cancellation_signal == nullptr) {
408       ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
409     }
410     ArtdDexoptResult aidl_return;
411     ndk::ScopedAStatus status = artd_->dexopt(output_artifacts_,
412                                               dex_file_,
413                                               isa_,
414                                               class_loader_context_,
415                                               compiler_filter_,
416                                               profile_path_,
417                                               vdex_path_,
418                                               dm_path_,
419                                               priority_class_,
420                                               dexopt_options_,
421                                               cancellation_signal,
422                                               &aidl_return);
423     ASSERT_THAT(status, std::move(status_matcher)) << status.getMessage();
424     if (status.isOk()) {
425       ASSERT_THAT(aidl_return, std::move(aidl_return_matcher));
426     }
427   }
428 
CreateFile(const std::string & filename,const std::string & content="")429   void CreateFile(const std::string& filename, const std::string& content = "") {
430     std::filesystem::path path(filename);
431     std::filesystem::create_directories(path.parent_path());
432     ASSERT_TRUE(WriteStringToFile(content, filename));
433   }
434 
435   std::shared_ptr<Artd> artd_;
436   std::unique_ptr<ScratchDir> scratch_dir_;
437   std::string scratch_path_;
438   std::string art_root_;
439   std::string android_data_;
440   std::string android_expand_;
441   MockFunction<android::base::LogFunction> mock_logger_;
442   ScopedUnsetEnvironmentVariable art_root_env_ = ScopedUnsetEnvironmentVariable("ANDROID_ART_ROOT");
443   ScopedUnsetEnvironmentVariable android_data_env_ = ScopedUnsetEnvironmentVariable("ANDROID_DATA");
444   ScopedUnsetEnvironmentVariable android_expand_env_ =
445       ScopedUnsetEnvironmentVariable("ANDROID_EXPAND");
446   MockSystemProperties* mock_props_;
447   MockExecUtils* mock_exec_utils_;
448   MockFunction<int(pid_t, int)> mock_kill_;
449   MockFunction<int(int, struct stat*)> mock_fstat_;
450 
451   std::string dex_file_;
452   std::string isa_;
453   ArtifactsPath artifacts_path_;
454   OutputArtifacts output_artifacts_;
455   std::string clc_1_;
456   std::string clc_2_;
457   std::optional<std::string> class_loader_context_;
458   std::string compiler_filter_;
459   std::optional<VdexPath> vdex_path_;
460   std::optional<DexMetadataPath> dm_path_;
461   PriorityClass priority_class_ = PriorityClass::BACKGROUND;
462   DexoptOptions dexopt_options_;
463   std::optional<ProfilePath> profile_path_;
464   bool dex_file_other_readable_ = true;
465   bool profile_other_readable_ = true;
466 
467  private:
InitFilesBeforeDexopt()468   void InitFilesBeforeDexopt() {
469     // Required files.
470     CreateFile(dex_file_);
471     std::filesystem::permissions(dex_file_,
472                                  std::filesystem::perms::others_read,
473                                  dex_file_other_readable_ ? std::filesystem::perm_options::add :
474                                                             std::filesystem::perm_options::remove);
475 
476     // Optional files.
477     if (vdex_path_.has_value()) {
478       CreateFile(OR_FATAL(BuildVdexPath(vdex_path_.value())), "old_vdex");
479     }
480     if (dm_path_.has_value()) {
481       CreateFile(OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
482     }
483     if (profile_path_.has_value()) {
484       std::string path = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
485       CreateFile(path);
486       std::filesystem::permissions(path,
487                                    std::filesystem::perms::others_read,
488                                    profile_other_readable_ ? std::filesystem::perm_options::add :
489                                                              std::filesystem::perm_options::remove);
490     }
491 
492     // Files to be replaced.
493     std::string oat_path = OR_FATAL(BuildOatPath(artifacts_path_));
494     CreateFile(oat_path, "old_oat");
495     CreateFile(OatPathToVdexPath(oat_path), "old_vdex");
496     CreateFile(OatPathToArtPath(oat_path), "old_art");
497   }
498 };
499 
TEST_F(ArtdTest,ConstantsAreInSync)500 TEST_F(ArtdTest, ConstantsAreInSync) { EXPECT_EQ(ArtConstants::REASON_VDEX, kReasonVdex); }
501 
TEST_F(ArtdTest,isAlive)502 TEST_F(ArtdTest, isAlive) {
503   bool result = false;
504   artd_->isAlive(&result);
505   EXPECT_TRUE(result);
506 }
507 
TEST_F(ArtdTest,deleteArtifacts)508 TEST_F(ArtdTest, deleteArtifacts) {
509   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
510   std::filesystem::create_directories(oat_dir);
511   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex"));  // 4 bytes.
512   ASSERT_TRUE(WriteStringToFile("ab", oat_dir + "/b.vdex"));    // 2 bytes.
513   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art"));      // 1 byte.
514 
515   int64_t result = -1;
516   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
517   EXPECT_EQ(result, 4 + 2 + 1);
518 
519   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.odex"));
520   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.vdex"));
521   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.art"));
522 }
523 
TEST_F(ArtdTest,deleteArtifactsMissingFile)524 TEST_F(ArtdTest, deleteArtifactsMissingFile) {
525   // Missing VDEX file.
526   std::string oat_dir = android_data_ + "/dalvik-cache/arm64";
527   std::filesystem::create_directories(oat_dir);
528   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/a@b.apk@classes.dex"));  // 4 bytes.
529   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/a@b.apk@classes.art"));     // 1 byte.
530 
531   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
532   EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(0);
533 
534   int64_t result = -1;
535   EXPECT_TRUE(artd_
536                   ->deleteArtifacts(
537                       ArtifactsPath{
538                           .dexPath = "/a/b.apk",
539                           .isa = "arm64",
540                           .isInDalvikCache = true,
541                       },
542                       &result)
543                   .isOk());
544   EXPECT_EQ(result, 4 + 1);
545 
546   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/a@b.apk@classes.dex"));
547   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/a@b.apk@classes.art"));
548 }
549 
TEST_F(ArtdTest,deleteArtifactsNoFile)550 TEST_F(ArtdTest, deleteArtifactsNoFile) {
551   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
552   EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(0);
553 
554   int64_t result = -1;
555   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
556   EXPECT_EQ(result, 0);
557 }
558 
TEST_F(ArtdTest,deleteArtifactsPermissionDenied)559 TEST_F(ArtdTest, deleteArtifactsPermissionDenied) {
560   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
561   std::filesystem::create_directories(oat_dir);
562   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex"));  // 4 bytes.
563   ASSERT_TRUE(WriteStringToFile("ab", oat_dir + "/b.vdex"));    // 2 bytes.
564   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art"));      // 1 byte.
565 
566   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
567   EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(3);
568 
569   auto scoped_inaccessible = ScopedInaccessible(oat_dir);
570   auto scoped_unroot = ScopedUnroot();
571 
572   int64_t result = -1;
573   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
574   EXPECT_EQ(result, 0);
575 }
576 
TEST_F(ArtdTest,deleteArtifactsFileIsDir)577 TEST_F(ArtdTest, deleteArtifactsFileIsDir) {
578   // VDEX file is a directory.
579   std::string oat_dir = scratch_path_ + "/a/oat/arm64";
580   std::filesystem::create_directories(oat_dir);
581   std::filesystem::create_directories(oat_dir + "/b.vdex");
582   ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex"));  // 4 bytes.
583   ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art"));      // 1 byte.
584 
585   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
586   EXPECT_CALL(mock_logger_,
587               Call(_, _, _, _, _, ContainsRegex(R"re(Failed to get the file size.*b\.vdex)re")))
588       .Times(1);
589 
590   int64_t result = -1;
591   EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
592   EXPECT_EQ(result, 4 + 1);
593 
594   // The directory is kept because getting the file size failed.
595   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.odex"));
596   EXPECT_TRUE(std::filesystem::exists(oat_dir + "/b.vdex"));
597   EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.art"));
598 }
599 
TEST_F(ArtdTest,dexopt)600 TEST_F(ArtdTest, dexopt) {
601   dexopt_options_.generateAppImage = true;
602 
603   EXPECT_CALL(
604       *mock_exec_utils_,
605       DoExecAndReturnCode(
606           AllOf(WhenSplitBy(
607                     "--",
608                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
609                     AllOf(Contains(art_root_ + "/bin/dex2oat32"),
610                           Contains(Flag("--zip-fd=", FdOf(dex_file_))),
611                           Contains(Flag("--zip-location=", dex_file_)),
612                           Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")),
613                           Contains(Flag("--instruction-set=", "arm64")),
614                           Contains(Flag("--compiler-filter=", "speed")),
615                           Contains(Flag(
616                               "--profile-file-fd=",
617                               FdOf(android_data_ +
618                                    "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"))),
619                           Contains(Flag("--input-vdex-fd=",
620                                         FdOf(scratch_path_ + "/a/oat/arm64/b.vdex"))),
621                           Contains(Flag("--dm-fd=", FdOf(scratch_path_ + "/a/b.dm"))))),
622                 HasKeepFdsFor("--zip-fd=",
623                               "--profile-file-fd=",
624                               "--input-vdex-fd=",
625                               "--dm-fd=",
626                               "--oat-fd=",
627                               "--output-vdex-fd=",
628                               "--app-image-fd=",
629                               "--class-loader-context-fds=",
630                               "--swap-fd=")),
631           _,
632           _))
633       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
634                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
635                       WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
636                       SetArgPointee<2>(ProcessStat{.wall_time_ms = 100, .cpu_time_ms = 400}),
637                       Return(0)));
638   RunDexopt(
639       EX_NONE,
640       AllOf(Field(&ArtdDexoptResult::cancelled, false),
641             Field(&ArtdDexoptResult::wallTimeMs, 100),
642             Field(&ArtdDexoptResult::cpuTimeMs, 400),
643             Field(&ArtdDexoptResult::sizeBytes, strlen("art") + strlen("oat") + strlen("vdex")),
644             Field(&ArtdDexoptResult::sizeBeforeBytes,
645                   strlen("old_art") + strlen("old_oat") + strlen("old_vdex"))));
646 
647   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "oat");
648   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "vdex");
649   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "art");
650   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.odex", true);
651   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.vdex", true);
652   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.art", true);
653 }
654 
TEST_F(ArtdTest,dexoptClassLoaderContext)655 TEST_F(ArtdTest, dexoptClassLoaderContext) {
656   EXPECT_CALL(
657       *mock_exec_utils_,
658       DoExecAndReturnCode(
659           WhenSplitBy("--",
660                       _,
661                       AllOf(Contains(ListFlag("--class-loader-context-fds=",
662                                               ElementsAre(FdOf(clc_1_), FdOf(clc_2_)))),
663                             Contains(Flag("--class-loader-context=", class_loader_context_)),
664                             Contains(Flag("--classpath-dir=", scratch_path_ + "/a")))),
665           _,
666           _))
667       .WillOnce(Return(0));
668   RunDexopt();
669 }
670 
TEST_F(ArtdTest,dexoptClassLoaderContextNull)671 TEST_F(ArtdTest, dexoptClassLoaderContextNull) {
672   class_loader_context_ = std::nullopt;
673 
674   EXPECT_CALL(
675       *mock_exec_utils_,
676       DoExecAndReturnCode(WhenSplitBy("--",
677                                       _,
678                                       AllOf(Not(Contains(Flag("--class-loader-context-fds=", _))),
679                                             Not(Contains(Flag("--class-loader-context=", _))),
680                                             Not(Contains(Flag("--classpath-dir=", _))))),
681                           _,
682                           _))
683       .WillOnce(Return(0));
684   RunDexopt();
685 }
686 
TEST_F(ArtdTest,dexoptNoOptionalInputFiles)687 TEST_F(ArtdTest, dexoptNoOptionalInputFiles) {
688   profile_path_ = std::nullopt;
689   vdex_path_ = std::nullopt;
690   dm_path_ = std::nullopt;
691 
692   EXPECT_CALL(*mock_exec_utils_,
693               DoExecAndReturnCode(WhenSplitBy("--",
694                                               _,
695                                               AllOf(Not(Contains(Flag("--profile-file-fd=", _))),
696                                                     Not(Contains(Flag("--input-vdex-fd=", _))),
697                                                     Not(Contains(Flag("--dm-fd=", _))))),
698                                   _,
699                                   _))
700       .WillOnce(Return(0));
701   RunDexopt();
702 }
703 
TEST_F(ArtdTest,dexoptPriorityClassBoot)704 TEST_F(ArtdTest, dexoptPriorityClassBoot) {
705   priority_class_ = PriorityClass::BOOT;
706   EXPECT_CALL(*mock_exec_utils_,
707               DoExecAndReturnCode(WhenSplitBy("--",
708                                               AllOf(Not(Contains(Flag("--set-task-profile=", _))),
709                                                     Not(Contains(Flag("--set-priority=", _)))),
710                                               Contains(Flag("--compact-dex-level=", "none"))),
711                                   _,
712                                   _))
713       .WillOnce(Return(0));
714   RunDexopt();
715 }
716 
TEST_F(ArtdTest,dexoptPriorityClassInteractive)717 TEST_F(ArtdTest, dexoptPriorityClassInteractive) {
718   priority_class_ = PriorityClass::INTERACTIVE;
719   EXPECT_CALL(*mock_exec_utils_,
720               DoExecAndReturnCode(
721                   WhenSplitBy("--",
722                               AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
723                                     Contains(Flag("--set-priority=", "background"))),
724                               Contains(Flag("--compact-dex-level=", "none"))),
725                   _,
726                   _))
727       .WillOnce(Return(0));
728   RunDexopt();
729 }
730 
TEST_F(ArtdTest,dexoptPriorityClassInteractiveFast)731 TEST_F(ArtdTest, dexoptPriorityClassInteractiveFast) {
732   priority_class_ = PriorityClass::INTERACTIVE_FAST;
733   EXPECT_CALL(*mock_exec_utils_,
734               DoExecAndReturnCode(
735                   WhenSplitBy("--",
736                               AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
737                                     Contains(Flag("--set-priority=", "background"))),
738                               Contains(Flag("--compact-dex-level=", "none"))),
739                   _,
740                   _))
741       .WillOnce(Return(0));
742   RunDexopt();
743 }
744 
TEST_F(ArtdTest,dexoptPriorityClassBackground)745 TEST_F(ArtdTest, dexoptPriorityClassBackground) {
746   priority_class_ = PriorityClass::BACKGROUND;
747   EXPECT_CALL(*mock_exec_utils_,
748               DoExecAndReturnCode(
749                   WhenSplitBy("--",
750                               AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBackground")),
751                                     Contains(Flag("--set-priority=", "background"))),
752                               Not(Contains(Flag("--compact-dex-level=", _)))),
753                   _,
754                   _))
755       .WillOnce(Return(0));
756   RunDexopt();
757 }
758 
TEST_F(ArtdTest,dexoptDexoptOptions)759 TEST_F(ArtdTest, dexoptDexoptOptions) {
760   dexopt_options_ = DexoptOptions{
761       .compilationReason = "install",
762       .targetSdkVersion = 123,
763       .debuggable = false,
764       .generateAppImage = false,
765       .hiddenApiPolicyEnabled = false,
766       .comments = "my-comments",
767   };
768 
769   EXPECT_CALL(
770       *mock_exec_utils_,
771       DoExecAndReturnCode(WhenSplitBy("--",
772                                       _,
773                                       AllOf(Contains(Flag("--compilation-reason=", "install")),
774                                             Contains(Flag("-Xtarget-sdk-version:", "123")),
775                                             Not(Contains("--debuggable")),
776                                             Not(Contains(Flag("--app-image-fd=", _))),
777                                             Not(Contains(Flag("-Xhidden-api-policy:", _))),
778                                             Contains(Flag("--comments=", "my-comments")))),
779                           _,
780                           _))
781       .WillOnce(Return(0));
782 
783   // `sizeBeforeBytes` should include the size of the old ART file even if no new ART file is
784   // generated.
785   RunDexopt(EX_NONE,
786             Field(&ArtdDexoptResult::sizeBeforeBytes,
787                   strlen("old_art") + strlen("old_oat") + strlen("old_vdex")));
788 }
789 
TEST_F(ArtdTest,dexoptDexoptOptions2)790 TEST_F(ArtdTest, dexoptDexoptOptions2) {
791   dexopt_options_ = DexoptOptions{
792       .compilationReason = "bg-dexopt",
793       .targetSdkVersion = 456,
794       .debuggable = true,
795       .generateAppImage = true,
796       .hiddenApiPolicyEnabled = true,
797   };
798 
799   EXPECT_CALL(
800       *mock_exec_utils_,
801       DoExecAndReturnCode(WhenSplitBy("--",
802                                       _,
803                                       AllOf(Contains(Flag("--compilation-reason=", "bg-dexopt")),
804                                             Contains(Flag("-Xtarget-sdk-version:", "456")),
805                                             Contains("--debuggable"),
806                                             Contains(Flag("--app-image-fd=", _)),
807                                             Contains(Flag("-Xhidden-api-policy:", "enabled")))),
808                           _,
809                           _))
810       .WillOnce(Return(0));
811 
812   RunDexopt();
813 }
814 
TEST_F(ArtdTest,dexoptDefaultFlagsWhenNoSystemProps)815 TEST_F(ArtdTest, dexoptDefaultFlagsWhenNoSystemProps) {
816   dexopt_options_.generateAppImage = true;
817 
818   EXPECT_CALL(*mock_exec_utils_,
819               DoExecAndReturnCode(
820                   WhenSplitBy("--",
821                               _,
822                               AllOf(Contains(Flag("--swap-fd=", FdOf(_))),
823                                     Not(Contains(Flag("--instruction-set-features=", _))),
824                                     Not(Contains(Flag("--instruction-set-variant=", _))),
825                                     Not(Contains(Flag("--max-image-block-size=", _))),
826                                     Not(Contains(Flag("--very-large-app-threshold=", _))),
827                                     Not(Contains(Flag("--resolve-startup-const-strings=", _))),
828                                     Not(Contains("--generate-debug-info")),
829                                     Not(Contains("--generate-mini-debug-info")),
830                                     Contains("-Xdeny-art-apex-data-files"),
831                                     Not(Contains(Flag("--cpu-set=", _))),
832                                     Not(Contains(Flag("-j", _))),
833                                     Not(Contains(Flag("-Xms", _))),
834                                     Not(Contains(Flag("-Xmx", _))),
835                                     Not(Contains("--compile-individually")),
836                                     Not(Contains(Flag("--image-format=", _))),
837                                     Not(Contains("--force-jit-zygote")),
838                                     Not(Contains(Flag("--boot-image=", _))))),
839                   _,
840                   _))
841       .WillOnce(Return(0));
842   RunDexopt();
843 }
844 
TEST_F(ArtdTest,dexoptFlagsFromSystemProps)845 TEST_F(ArtdTest, dexoptFlagsFromSystemProps) {
846   dexopt_options_.generateAppImage = true;
847 
848   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-swap")).WillOnce(Return("0"));
849   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.isa.arm64.features"))
850       .WillOnce(Return("features"));
851   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.isa.arm64.variant")).WillOnce(Return("variant"));
852   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-max-image-block-size"))
853       .WillOnce(Return("size"));
854   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-very-large"))
855       .WillOnce(Return("threshold"));
856   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-resolve-startup-strings"))
857       .WillOnce(Return("strings"));
858   EXPECT_CALL(*mock_props_, GetProperty("debug.generate-debug-info")).WillOnce(Return("1"));
859   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-minidebuginfo")).WillOnce(Return("1"));
860   EXPECT_CALL(*mock_props_, GetProperty("odsign.verification.success")).WillOnce(Return("1"));
861   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-Xms")).WillOnce(Return("xms"));
862   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-Xmx")).WillOnce(Return("xmx"));
863   EXPECT_CALL(*mock_props_, GetProperty("ro.config.low_ram")).WillOnce(Return("1"));
864   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.appimageformat")).WillOnce(Return("imgfmt"));
865   EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.boot-image")).WillOnce(Return("boot-image"));
866 
867   EXPECT_CALL(*mock_exec_utils_,
868               DoExecAndReturnCode(
869                   WhenSplitBy("--",
870                               _,
871                               AllOf(Not(Contains(Flag("--swap-fd=", _))),
872                                     Contains(Flag("--instruction-set-features=", "features")),
873                                     Contains(Flag("--instruction-set-variant=", "variant")),
874                                     Contains(Flag("--max-image-block-size=", "size")),
875                                     Contains(Flag("--very-large-app-threshold=", "threshold")),
876                                     Contains(Flag("--resolve-startup-const-strings=", "strings")),
877                                     Contains("--generate-debug-info"),
878                                     Contains("--generate-mini-debug-info"),
879                                     Not(Contains("-Xdeny-art-apex-data-files")),
880                                     Contains(Flag("-Xms", "xms")),
881                                     Contains(Flag("-Xmx", "xmx")),
882                                     Contains("--compile-individually"),
883                                     Contains(Flag("--image-format=", "imgfmt")),
884                                     Not(Contains("--force-jit-zygote")),
885                                     Contains(Flag("--boot-image=", "boot-image")))),
886                   _,
887                   _))
888       .WillOnce(Return(0));
889   RunDexopt();
890 }
891 
TEST_F(ArtdTest,dexoptFlagsForceJitZygote)892 TEST_F(ArtdTest, dexoptFlagsForceJitZygote) {
893   EXPECT_CALL(*mock_props_,
894               GetProperty("persist.device_config.runtime_native_boot.profilebootclasspath"))
895       .WillOnce(Return("true"));
896   ON_CALL(*mock_props_, GetProperty("dalvik.vm.boot-image")).WillByDefault(Return("boot-image"));
897 
898   EXPECT_CALL(*mock_exec_utils_,
899               DoExecAndReturnCode(WhenSplitBy("--",
900                                               _,
901                                               AllOf(Contains("--force-jit-zygote"),
902                                                     Not(Contains(Flag("--boot-image=", _))))),
903                                   _,
904                                   _))
905       .WillOnce(Return(0));
906   RunDexopt();
907 }
908 
SetDefaultResourceControlProps(MockSystemProperties * mock_props)909 static void SetDefaultResourceControlProps(MockSystemProperties* mock_props) {
910   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-cpu-set")).WillRepeatedly(Return("0,2"));
911   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-threads")).WillRepeatedly(Return("4"));
912 }
913 
TEST_F(ArtdTest,dexoptDefaultResourceControlBoot)914 TEST_F(ArtdTest, dexoptDefaultResourceControlBoot) {
915   SetDefaultResourceControlProps(mock_props_);
916 
917   // The default resource control properties don't apply to BOOT.
918   EXPECT_CALL(
919       *mock_exec_utils_,
920       DoExecAndReturnCode(
921           WhenSplitBy(
922               "--", _, AllOf(Not(Contains(Flag("--cpu-set=", _))), Contains(Not(Flag("-j", _))))),
923           _,
924           _))
925       .WillOnce(Return(0));
926   priority_class_ = PriorityClass::BOOT;
927   RunDexopt();
928 }
929 
TEST_F(ArtdTest,dexoptDefaultResourceControlOther)930 TEST_F(ArtdTest, dexoptDefaultResourceControlOther) {
931   SetDefaultResourceControlProps(mock_props_);
932 
933   EXPECT_CALL(
934       *mock_exec_utils_,
935       DoExecAndReturnCode(
936           WhenSplitBy(
937               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
938           _,
939           _))
940       .Times(3)
941       .WillRepeatedly(Return(0));
942   priority_class_ = PriorityClass::INTERACTIVE_FAST;
943   RunDexopt();
944   priority_class_ = PriorityClass::INTERACTIVE;
945   RunDexopt();
946   priority_class_ = PriorityClass::BACKGROUND;
947   RunDexopt();
948 }
949 
SetAllResourceControlProps(MockSystemProperties * mock_props)950 static void SetAllResourceControlProps(MockSystemProperties* mock_props) {
951   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-cpu-set")).WillRepeatedly(Return("0,2"));
952   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-threads")).WillRepeatedly(Return("4"));
953   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.boot-dex2oat-cpu-set"))
954       .WillRepeatedly(Return("0,1,2,3"));
955   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.boot-dex2oat-threads"))
956       .WillRepeatedly(Return("8"));
957   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.restore-dex2oat-cpu-set"))
958       .WillRepeatedly(Return("0,2,3"));
959   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.restore-dex2oat-threads"))
960       .WillRepeatedly(Return("6"));
961   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.background-dex2oat-cpu-set"))
962       .WillRepeatedly(Return("0"));
963   EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.background-dex2oat-threads"))
964       .WillRepeatedly(Return("2"));
965 }
966 
TEST_F(ArtdTest,dexoptAllResourceControlBoot)967 TEST_F(ArtdTest, dexoptAllResourceControlBoot) {
968   SetAllResourceControlProps(mock_props_);
969 
970   EXPECT_CALL(
971       *mock_exec_utils_,
972       DoExecAndReturnCode(
973           WhenSplitBy(
974               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,1,2,3")), Contains(Flag("-j", "8")))),
975           _,
976           _))
977       .WillOnce(Return(0));
978   priority_class_ = PriorityClass::BOOT;
979   RunDexopt();
980 }
981 
TEST_F(ArtdTest,dexoptAllResourceControlInteractiveFast)982 TEST_F(ArtdTest, dexoptAllResourceControlInteractiveFast) {
983   SetAllResourceControlProps(mock_props_);
984 
985   EXPECT_CALL(
986       *mock_exec_utils_,
987       DoExecAndReturnCode(
988           WhenSplitBy(
989               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2,3")), Contains(Flag("-j", "6")))),
990           _,
991           _))
992       .WillOnce(Return(0));
993   priority_class_ = PriorityClass::INTERACTIVE_FAST;
994   RunDexopt();
995 }
996 
TEST_F(ArtdTest,dexoptAllResourceControlInteractive)997 TEST_F(ArtdTest, dexoptAllResourceControlInteractive) {
998   SetAllResourceControlProps(mock_props_);
999 
1000   // INTERACTIVE always uses the default resource control properties.
1001   EXPECT_CALL(
1002       *mock_exec_utils_,
1003       DoExecAndReturnCode(
1004           WhenSplitBy(
1005               "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
1006           _,
1007           _))
1008       .WillOnce(Return(0));
1009   priority_class_ = PriorityClass::INTERACTIVE;
1010   RunDexopt();
1011 }
1012 
TEST_F(ArtdTest,dexoptAllResourceControlBackground)1013 TEST_F(ArtdTest, dexoptAllResourceControlBackground) {
1014   SetAllResourceControlProps(mock_props_);
1015 
1016   EXPECT_CALL(
1017       *mock_exec_utils_,
1018       DoExecAndReturnCode(
1019           WhenSplitBy("--", _, AllOf(Contains(Flag("--cpu-set=", "0")), Contains(Flag("-j", "2")))),
1020           _,
1021           _))
1022       .WillOnce(Return(0));
1023   priority_class_ = PriorityClass::BACKGROUND;
1024   RunDexopt();
1025 }
1026 
TEST_F(ArtdTest,dexoptFailed)1027 TEST_F(ArtdTest, dexoptFailed) {
1028   dexopt_options_.generateAppImage = true;
1029   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1030       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1031                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1032                       WithArg<0>(WriteToFdFlag("--app-image-fd=", "new_art")),
1033                       Return(1)));
1034   RunDexopt(EX_SERVICE_SPECIFIC);
1035 
1036   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1037   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1038   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
1039 }
1040 
TEST_F(ArtdTest,dexoptFailedToCommit)1041 TEST_F(ArtdTest, dexoptFailedToCommit) {
1042   std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_inaccessible;
1043   std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_unroot;
1044 
1045   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1046       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1047                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1048                       [&](auto, auto, auto) {
1049                         scoped_inaccessible = std::make_unique<ScopeGuard<std::function<void()>>>(
1050                             ScopedInaccessible(scratch_path_ + "/a/oat/arm64"));
1051                         scoped_unroot =
1052                             std::make_unique<ScopeGuard<std::function<void()>>>(ScopedUnroot());
1053                         return 0;
1054                       }));
1055 
1056   RunDexopt(
1057       EX_SERVICE_SPECIFIC,
1058       AllOf(Field(&ArtdDexoptResult::sizeBytes, 0), Field(&ArtdDexoptResult::sizeBeforeBytes, 0)));
1059 }
1060 
TEST_F(ArtdTest,dexoptCancelledBeforeDex2oat)1061 TEST_F(ArtdTest, dexoptCancelledBeforeDex2oat) {
1062   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1063   ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1064 
1065   constexpr pid_t kPid = 123;
1066 
1067   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1068       .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
1069         callbacks.on_start(kPid);
1070         callbacks.on_end(kPid);
1071         return Error();
1072       });
1073   EXPECT_CALL(mock_kill_, Call(kPid, SIGKILL));
1074 
1075   cancellation_signal->cancel();
1076 
1077   RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, true), cancellation_signal);
1078 
1079   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1080   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1081   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
1082 }
1083 
TEST_F(ArtdTest,dexoptCancelledDuringDex2oat)1084 TEST_F(ArtdTest, dexoptCancelledDuringDex2oat) {
1085   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1086   ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1087 
1088   constexpr pid_t kPid = 123;
1089   constexpr std::chrono::duration<int> kTimeout = std::chrono::seconds(1);
1090 
1091   std::condition_variable process_started_cv, process_killed_cv;
1092   std::mutex mu;
1093 
1094   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1095       .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
1096         std::unique_lock<std::mutex> lock(mu);
1097         // Step 2.
1098         callbacks.on_start(kPid);
1099         process_started_cv.notify_one();
1100         EXPECT_EQ(process_killed_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
1101         // Step 5.
1102         callbacks.on_end(kPid);
1103         return Error();
1104       });
1105 
1106   EXPECT_CALL(mock_kill_, Call(kPid, SIGKILL)).WillOnce([&](auto, auto) {
1107     // Step 4.
1108     process_killed_cv.notify_one();
1109     return 0;
1110   });
1111 
1112   std::thread t;
1113   {
1114     std::unique_lock<std::mutex> lock(mu);
1115     // Step 1.
1116     t = std::thread([&] {
1117       RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, true), cancellation_signal);
1118     });
1119     EXPECT_EQ(process_started_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
1120     // Step 3.
1121     cancellation_signal->cancel();
1122   }
1123 
1124   t.join();
1125 
1126   // Step 6.
1127   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1128   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1129   CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
1130 }
1131 
TEST_F(ArtdTest,dexoptCancelledAfterDex2oat)1132 TEST_F(ArtdTest, dexoptCancelledAfterDex2oat) {
1133   std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1134   ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1135 
1136   constexpr pid_t kPid = 123;
1137 
1138   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1139       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1140                       WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1141                       [&](auto, const ExecCallbacks& callbacks, auto) {
1142                         callbacks.on_start(kPid);
1143                         callbacks.on_end(kPid);
1144                         return 0;
1145                       }));
1146   EXPECT_CALL(mock_kill_, Call).Times(0);
1147 
1148   RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, false), cancellation_signal);
1149 
1150   // This signal should be ignored.
1151   cancellation_signal->cancel();
1152 
1153   CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "new_oat");
1154   CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "new_vdex");
1155   EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.art"));
1156 }
1157 
TEST_F(ArtdTest,dexoptDexFileNotOtherReadable)1158 TEST_F(ArtdTest, dexoptDexFileNotOtherReadable) {
1159   dex_file_other_readable_ = false;
1160   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1161   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1162                   Property(&ndk::ScopedAStatus::getMessage,
1163                            HasSubstr("Outputs cannot be other-readable because the dex file"))));
1164 }
1165 
TEST_F(ArtdTest,dexoptProfileNotOtherReadable)1166 TEST_F(ArtdTest, dexoptProfileNotOtherReadable) {
1167   profile_other_readable_ = false;
1168   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1169   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1170                   Property(&ndk::ScopedAStatus::getMessage,
1171                            HasSubstr("Outputs cannot be other-readable because the profile"))));
1172 }
1173 
TEST_F(ArtdTest,dexoptOutputNotOtherReadable)1174 TEST_F(ArtdTest, dexoptOutputNotOtherReadable) {
1175   output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1176   dex_file_other_readable_ = false;
1177   profile_other_readable_ = false;
1178   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(0));
1179   RunDexopt();
1180   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.odex", false);
1181   CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.vdex", false);
1182 }
1183 
TEST_F(ArtdTest,dexoptUidMismatch)1184 TEST_F(ArtdTest, dexoptUidMismatch) {
1185   output_artifacts_.permissionSettings.fileFsPermission.uid = 12345;
1186   output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1187   dex_file_other_readable_ = false;
1188   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1189   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1190                   Property(&ndk::ScopedAStatus::getMessage,
1191                            HasSubstr("Outputs' owner doesn't match the dex file"))));
1192 }
1193 
TEST_F(ArtdTest,dexoptGidMismatch)1194 TEST_F(ArtdTest, dexoptGidMismatch) {
1195   output_artifacts_.permissionSettings.fileFsPermission.gid = 12345;
1196   output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1197   dex_file_other_readable_ = false;
1198   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1199   RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1200                   Property(&ndk::ScopedAStatus::getMessage,
1201                            HasSubstr("Outputs' owner doesn't match the dex file"))));
1202 }
1203 
TEST_F(ArtdTest,dexoptGidMatchesUid)1204 TEST_F(ArtdTest, dexoptGidMatchesUid) {
1205   output_artifacts_.permissionSettings.fileFsPermission = {
1206       .uid = 123, .gid = 123, .isOtherReadable = false};
1207   EXPECT_CALL(mock_fstat_, Call(_, _)).WillRepeatedly(fstat);  // For profile.
1208   EXPECT_CALL(mock_fstat_, Call(FdOf(dex_file_), _))
1209       .WillOnce(DoAll(SetArgPointee<1>((struct stat){
1210                           .st_mode = S_IRUSR | S_IRGRP, .st_uid = 123, .st_gid = 456}),
1211                       Return(0)));
1212   ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1213   // It's okay to fail on chown. This happens when the test is not run as root.
1214   RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1215                   AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1216                         Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1217 }
1218 
TEST_F(ArtdTest,dexoptGidMatchesGid)1219 TEST_F(ArtdTest, dexoptGidMatchesGid) {
1220   output_artifacts_.permissionSettings.fileFsPermission = {
1221       .uid = 123, .gid = 456, .isOtherReadable = false};
1222   EXPECT_CALL(mock_fstat_, Call(_, _)).WillRepeatedly(fstat);  // For profile.
1223   EXPECT_CALL(mock_fstat_, Call(FdOf(dex_file_), _))
1224       .WillOnce(DoAll(SetArgPointee<1>((struct stat){
1225                           .st_mode = S_IRUSR | S_IRGRP, .st_uid = 123, .st_gid = 456}),
1226                       Return(0)));
1227   ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1228   // It's okay to fail on chown. This happens when the test is not run as root.
1229   RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1230                   AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1231                         Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1232 }
1233 
TEST_F(ArtdTest,dexoptUidGidChangeOk)1234 TEST_F(ArtdTest, dexoptUidGidChangeOk) {
1235   // The dex file is other-readable, so we don't check uid and gid.
1236   output_artifacts_.permissionSettings.fileFsPermission = {
1237       .uid = 12345, .gid = 12345, .isOtherReadable = false};
1238   ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1239   // It's okay to fail on chown. This happens when the test is not run as root.
1240   RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1241                   AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1242                         Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1243 }
1244 
TEST_F(ArtdTest,dexoptNoUidGidChange)1245 TEST_F(ArtdTest, dexoptNoUidGidChange) {
1246   output_artifacts_.permissionSettings.fileFsPermission = {
1247       .uid = -1, .gid = -1, .isOtherReadable = false};
1248   dex_file_other_readable_ = false;
1249   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(0));
1250   RunDexopt();
1251 }
1252 
TEST_F(ArtdTest,isProfileUsable)1253 TEST_F(ArtdTest, isProfileUsable) {
1254   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1255   CreateFile(profile_file);
1256   CreateFile(dex_file_);
1257 
1258   EXPECT_CALL(
1259       *mock_exec_utils_,
1260       DoExecAndReturnCode(
1261           AllOf(WhenSplitBy(
1262                     "--",
1263                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1264                     AllOf(Contains(art_root_ + "/bin/profman"),
1265                           Contains(Flag("--reference-profile-file-fd=", FdOf(profile_file))),
1266                           Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1267                 HasKeepFdsFor("--reference-profile-file-fd=", "--apk-fd=")),
1268           _,
1269           _))
1270       .WillOnce(Return(ProfmanResult::kSkipCompilationSmallDelta));
1271 
1272   bool result;
1273   EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1274   EXPECT_TRUE(result);
1275 }
1276 
TEST_F(ArtdTest,isProfileUsableFalse)1277 TEST_F(ArtdTest, isProfileUsableFalse) {
1278   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1279   CreateFile(profile_file);
1280   CreateFile(dex_file_);
1281 
1282   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1283       .WillOnce(Return(ProfmanResult::kSkipCompilationEmptyProfiles));
1284 
1285   bool result;
1286   EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1287   EXPECT_FALSE(result);
1288 }
1289 
TEST_F(ArtdTest,isProfileUsableNotFound)1290 TEST_F(ArtdTest, isProfileUsableNotFound) {
1291   CreateFile(dex_file_);
1292 
1293   bool result;
1294   EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1295   EXPECT_FALSE(result);
1296 }
1297 
TEST_F(ArtdTest,isProfileUsableFailed)1298 TEST_F(ArtdTest, isProfileUsableFailed) {
1299   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1300   CreateFile(profile_file);
1301   CreateFile(dex_file_);
1302 
1303   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(100));
1304 
1305   bool result;
1306   ndk::ScopedAStatus status = artd_->isProfileUsable(profile_path_.value(), dex_file_, &result);
1307 
1308   EXPECT_FALSE(status.isOk());
1309   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1310   EXPECT_THAT(status.getMessage(), HasSubstr("profman returned an unexpected code: 100"));
1311 }
1312 
TEST_F(ArtdTest,copyAndRewriteProfile)1313 TEST_F(ArtdTest, copyAndRewriteProfile) {
1314   const TmpProfilePath& src = profile_path_->get<ProfilePath::tmpProfilePath>();
1315   std::string src_file = OR_FATAL(BuildTmpProfilePath(src));
1316   CreateFile(src_file, "abc");
1317   OutputProfile dst{.profilePath = src, .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1318   dst.profilePath.id = "";
1319   dst.profilePath.tmpPath = "";
1320 
1321   CreateFile(dex_file_);
1322 
1323   EXPECT_CALL(
1324       *mock_exec_utils_,
1325       DoExecAndReturnCode(
1326           AllOf(WhenSplitBy(
1327                     "--",
1328                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1329                     AllOf(Contains(art_root_ + "/bin/profman"),
1330                           Contains("--copy-and-update-profile-key"),
1331                           Contains(Flag("--profile-file-fd=", FdOf(src_file))),
1332                           Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1333                 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
1334           _,
1335           _))
1336       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
1337                       Return(ProfmanResult::kCopyAndUpdateSuccess)));
1338 
1339   bool result;
1340   EXPECT_TRUE(artd_->copyAndRewriteProfile(src, &dst, dex_file_, &result).isOk());
1341   EXPECT_TRUE(result);
1342   EXPECT_THAT(dst.profilePath.id, Not(IsEmpty()));
1343   std::string real_path = OR_FATAL(BuildTmpProfilePath(dst.profilePath));
1344   EXPECT_EQ(dst.profilePath.tmpPath, real_path);
1345   CheckContent(real_path, "def");
1346 }
1347 
TEST_F(ArtdTest,copyAndRewriteProfileFalse)1348 TEST_F(ArtdTest, copyAndRewriteProfileFalse) {
1349   const TmpProfilePath& src = profile_path_->get<ProfilePath::tmpProfilePath>();
1350   std::string src_file = OR_FATAL(BuildTmpProfilePath(src));
1351   CreateFile(src_file, "abc");
1352   OutputProfile dst{.profilePath = src, .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1353   dst.profilePath.id = "";
1354   dst.profilePath.tmpPath = "";
1355 
1356   CreateFile(dex_file_);
1357 
1358   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1359       .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1360 
1361   bool result;
1362   EXPECT_TRUE(artd_->copyAndRewriteProfile(src, &dst, dex_file_, &result).isOk());
1363   EXPECT_FALSE(result);
1364   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1365   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1366 }
1367 
TEST_F(ArtdTest,copyAndRewriteProfileNotFound)1368 TEST_F(ArtdTest, copyAndRewriteProfileNotFound) {
1369   CreateFile(dex_file_);
1370 
1371   const TmpProfilePath& src = profile_path_->get<ProfilePath::tmpProfilePath>();
1372   OutputProfile dst{.profilePath = src, .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1373   dst.profilePath.id = "";
1374   dst.profilePath.tmpPath = "";
1375 
1376   bool result;
1377   EXPECT_TRUE(artd_->copyAndRewriteProfile(src, &dst, dex_file_, &result).isOk());
1378   EXPECT_FALSE(result);
1379   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1380   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1381 }
1382 
TEST_F(ArtdTest,copyAndRewriteProfileFailed)1383 TEST_F(ArtdTest, copyAndRewriteProfileFailed) {
1384   const TmpProfilePath& src = profile_path_->get<ProfilePath::tmpProfilePath>();
1385   std::string src_file = OR_FATAL(BuildTmpProfilePath(src));
1386   CreateFile(src_file, "abc");
1387   OutputProfile dst{.profilePath = src, .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1388   dst.profilePath.id = "";
1389   dst.profilePath.tmpPath = "";
1390 
1391   CreateFile(dex_file_);
1392 
1393   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(100));
1394 
1395   bool result;
1396   ndk::ScopedAStatus status = artd_->copyAndRewriteProfile(src, &dst, dex_file_, &result);
1397 
1398   EXPECT_FALSE(status.isOk());
1399   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1400   EXPECT_THAT(status.getMessage(), HasSubstr("profman returned an unexpected code: 100"));
1401   EXPECT_THAT(dst.profilePath.id, IsEmpty());
1402   EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1403 }
1404 
TEST_F(ArtdTest,commitTmpProfile)1405 TEST_F(ArtdTest, commitTmpProfile) {
1406   const TmpProfilePath& tmp_profile_path = profile_path_->get<ProfilePath::tmpProfilePath>();
1407   std::string tmp_profile_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path));
1408   CreateFile(tmp_profile_file);
1409 
1410   EXPECT_TRUE(artd_->commitTmpProfile(tmp_profile_path).isOk());
1411 
1412   EXPECT_FALSE(std::filesystem::exists(tmp_profile_file));
1413   EXPECT_TRUE(std::filesystem::exists(OR_FATAL(BuildFinalProfilePath(tmp_profile_path))));
1414 }
1415 
TEST_F(ArtdTest,commitTmpProfileFailed)1416 TEST_F(ArtdTest, commitTmpProfileFailed) {
1417   const TmpProfilePath& tmp_profile_path = profile_path_->get<ProfilePath::tmpProfilePath>();
1418   ndk::ScopedAStatus status = artd_->commitTmpProfile(tmp_profile_path);
1419 
1420   EXPECT_FALSE(status.isOk());
1421   EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1422   EXPECT_THAT(
1423       status.getMessage(),
1424       ContainsRegex(R"re(Failed to move .*primary\.prof\.12345\.tmp.* to .*primary\.prof)re"));
1425 
1426   EXPECT_FALSE(std::filesystem::exists(OR_FATAL(BuildFinalProfilePath(tmp_profile_path))));
1427 }
1428 
TEST_F(ArtdTest,deleteProfile)1429 TEST_F(ArtdTest, deleteProfile) {
1430   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1431   CreateFile(profile_file);
1432 
1433   EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1434 
1435   EXPECT_FALSE(std::filesystem::exists(profile_file));
1436 }
1437 
TEST_F(ArtdTest,deleteProfileDoesNotExist)1438 TEST_F(ArtdTest, deleteProfileDoesNotExist) {
1439   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
1440   EXPECT_CALL(mock_logger_, Call).Times(0);
1441 
1442   EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1443 }
1444 
TEST_F(ArtdTest,deleteProfileFailed)1445 TEST_F(ArtdTest, deleteProfileFailed) {
1446   auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
1447   EXPECT_CALL(
1448       mock_logger_,
1449       Call(_, _, _, _, _, ContainsRegex(R"re(Failed to remove .*primary\.prof\.12345\.tmp)re")));
1450 
1451   std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1452   auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(profile_file).parent_path());
1453   auto scoped_unroot = ScopedUnroot();
1454 
1455   EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1456 }
1457 
1458 class ArtdGetVisibilityTest : public ArtdTest {
1459  protected:
1460   template <typename PathType>
1461   using Method = ndk::ScopedAStatus (Artd::*)(const PathType&, FileVisibility*);
1462 
1463   template <typename PathType>
TestGetVisibilityOtherReadable(Method<PathType> method,const PathType & input,const std::string & path)1464   void TestGetVisibilityOtherReadable(Method<PathType> method,
1465                                       const PathType& input,
1466                                       const std::string& path) {
1467     CreateFile(path);
1468     std::filesystem::permissions(
1469         path, std::filesystem::perms::others_read, std::filesystem::perm_options::add);
1470 
1471     FileVisibility result;
1472     ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1473     EXPECT_EQ(result, FileVisibility::OTHER_READABLE);
1474   }
1475 
1476   template <typename PathType>
TestGetVisibilityNotOtherReadable(Method<PathType> method,const PathType & input,const std::string & path)1477   void TestGetVisibilityNotOtherReadable(Method<PathType> method,
1478                                          const PathType& input,
1479                                          const std::string& path) {
1480     CreateFile(path);
1481     std::filesystem::permissions(
1482         path, std::filesystem::perms::others_read, std::filesystem::perm_options::remove);
1483 
1484     FileVisibility result;
1485     ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1486     EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE);
1487   }
1488 
1489   template <typename PathType>
TestGetVisibilityNotFound(Method<PathType> method,const PathType & input)1490   void TestGetVisibilityNotFound(Method<PathType> method, const PathType& input) {
1491     FileVisibility result;
1492     ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1493     EXPECT_EQ(result, FileVisibility::NOT_FOUND);
1494   }
1495 
1496   template <typename PathType>
TestGetVisibilityPermissionDenied(Method<PathType> method,const PathType & input,const std::string & path)1497   void TestGetVisibilityPermissionDenied(Method<PathType> method,
1498                                          const PathType& input,
1499                                          const std::string& path) {
1500     CreateFile(path);
1501 
1502     auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(path).parent_path());
1503     auto scoped_unroot = ScopedUnroot();
1504 
1505     FileVisibility result;
1506     ndk::ScopedAStatus status = ((*artd_).*method)(input, &result);
1507     EXPECT_FALSE(status.isOk());
1508     EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1509     EXPECT_THAT(status.getMessage(), HasSubstr("Failed to get status of"));
1510   }
1511 };
1512 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityOtherReadable)1513 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityOtherReadable) {
1514   TestGetVisibilityOtherReadable(&Artd::getProfileVisibility,
1515                                  profile_path_.value(),
1516                                  OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
1517 }
1518 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityNotOtherReadable)1519 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotOtherReadable) {
1520   TestGetVisibilityNotOtherReadable(&Artd::getProfileVisibility,
1521                                     profile_path_.value(),
1522                                     OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
1523 }
1524 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityNotFound)1525 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotFound) {
1526   TestGetVisibilityNotFound(&Artd::getProfileVisibility, profile_path_.value());
1527 }
1528 
TEST_F(ArtdGetVisibilityTest,getProfileVisibilityPermissionDenied)1529 TEST_F(ArtdGetVisibilityTest, getProfileVisibilityPermissionDenied) {
1530   TestGetVisibilityPermissionDenied(&Artd::getProfileVisibility,
1531                                     profile_path_.value(),
1532                                     OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
1533 }
1534 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityOtherReadable)1535 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityOtherReadable) {
1536   TestGetVisibilityOtherReadable(
1537       &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
1538 }
1539 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityNotOtherReadable)1540 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotOtherReadable) {
1541   TestGetVisibilityNotOtherReadable(
1542       &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
1543 }
1544 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityNotFound)1545 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotFound) {
1546   TestGetVisibilityNotFound(&Artd::getArtifactsVisibility, artifacts_path_);
1547 }
1548 
TEST_F(ArtdGetVisibilityTest,getArtifactsVisibilityPermissionDenied)1549 TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityPermissionDenied) {
1550   TestGetVisibilityPermissionDenied(
1551       &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
1552 }
1553 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityOtherReadable)1554 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityOtherReadable) {
1555   TestGetVisibilityOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1556 }
1557 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityNotOtherReadable)1558 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotOtherReadable) {
1559   TestGetVisibilityNotOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1560 }
1561 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityNotFound)1562 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotFound) {
1563   TestGetVisibilityNotFound(&Artd::getDexFileVisibility, dex_file_);
1564 }
1565 
TEST_F(ArtdGetVisibilityTest,getDexFileVisibilityPermissionDenied)1566 TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityPermissionDenied) {
1567   TestGetVisibilityPermissionDenied(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1568 }
1569 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityOtherReadable)1570 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityOtherReadable) {
1571   TestGetVisibilityOtherReadable(&Artd::getDmFileVisibility,
1572                                  dm_path_.value(),
1573                                  OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1574 }
1575 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityNotOtherReadable)1576 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotOtherReadable) {
1577   TestGetVisibilityNotOtherReadable(&Artd::getDmFileVisibility,
1578                                     dm_path_.value(),
1579                                     OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1580 }
1581 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityNotFound)1582 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotFound) {
1583   TestGetVisibilityNotFound(&Artd::getDmFileVisibility, dm_path_.value());
1584 }
1585 
TEST_F(ArtdGetVisibilityTest,getDmFileVisibilityPermissionDenied)1586 TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityPermissionDenied) {
1587   TestGetVisibilityPermissionDenied(&Artd::getDmFileVisibility,
1588                                     dm_path_.value(),
1589                                     OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1590 }
1591 
TEST_F(ArtdTest,mergeProfiles)1592 TEST_F(ArtdTest, mergeProfiles) {
1593   const TmpProfilePath& reference_profile_path = profile_path_->get<ProfilePath::tmpProfilePath>();
1594   std::string reference_profile_file = OR_FATAL(BuildTmpProfilePath(reference_profile_path));
1595   CreateFile(reference_profile_file, "abc");
1596 
1597   // Doesn't exist.
1598   PrimaryCurProfilePath profile_0_path{
1599       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1600   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1601 
1602   PrimaryCurProfilePath profile_1_path{
1603       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
1604   std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
1605   CreateFile(profile_1_file, "def");
1606 
1607   OutputProfile output_profile{.profilePath = reference_profile_path,
1608                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1609   output_profile.profilePath.id = "";
1610   output_profile.profilePath.tmpPath = "";
1611 
1612   std::string dex_file_1 = scratch_path_ + "/a/b.apk";
1613   std::string dex_file_2 = scratch_path_ + "/a/c.apk";
1614   CreateFile(dex_file_1);
1615   CreateFile(dex_file_2);
1616 
1617   EXPECT_CALL(
1618       *mock_exec_utils_,
1619       DoExecAndReturnCode(
1620           AllOf(WhenSplitBy(
1621                     "--",
1622                     AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1623                     AllOf(Contains(art_root_ + "/bin/profman"),
1624                           Not(Contains(Flag("--profile-file-fd=", FdOf(profile_0_file)))),
1625                           Contains(Flag("--profile-file-fd=", FdOf(profile_1_file))),
1626                           Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
1627                           Contains(Flag("--apk-fd=", FdOf(dex_file_1))),
1628                           Contains(Flag("--apk-fd=", FdOf(dex_file_2))),
1629                           Not(Contains("--force-merge")),
1630                           Not(Contains("--boot-image-merge")))),
1631                 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
1632           _,
1633           _))
1634       .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
1635                       Return(ProfmanResult::kCompile)));
1636 
1637   bool result;
1638   EXPECT_TRUE(artd_
1639                   ->mergeProfiles({profile_0_path, profile_1_path},
1640                                   reference_profile_path,
1641                                   &output_profile,
1642                                   {dex_file_1, dex_file_2},
1643                                   /*in_options=*/{},
1644                                   &result)
1645                   .isOk());
1646   EXPECT_TRUE(result);
1647   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
1648   std::string real_path = OR_FATAL(BuildTmpProfilePath(output_profile.profilePath));
1649   EXPECT_EQ(output_profile.profilePath.tmpPath, real_path);
1650   CheckContent(real_path, "merged");
1651 }
1652 
TEST_F(ArtdTest,mergeProfilesEmptyReferenceProfile)1653 TEST_F(ArtdTest, mergeProfilesEmptyReferenceProfile) {
1654   PrimaryCurProfilePath profile_0_path{
1655       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1656   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1657   CreateFile(profile_0_file, "def");
1658 
1659   OutputProfile output_profile{.profilePath = profile_path_->get<ProfilePath::tmpProfilePath>(),
1660                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1661   output_profile.profilePath.id = "";
1662   output_profile.profilePath.tmpPath = "";
1663 
1664   CreateFile(dex_file_);
1665 
1666   EXPECT_CALL(
1667       *mock_exec_utils_,
1668       DoExecAndReturnCode(
1669           WhenSplitBy("--",
1670                       AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1671                       AllOf(Contains(art_root_ + "/bin/profman"),
1672                             Contains(Flag("--profile-file-fd=", FdOf(profile_0_file))),
1673                             Contains(Flag("--reference-profile-file-fd=", FdHasContent(""))),
1674                             Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1675           _,
1676           _))
1677       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "merged")),
1678                       Return(ProfmanResult::kCompile)));
1679 
1680   bool result;
1681   EXPECT_TRUE(artd_
1682                   ->mergeProfiles({profile_0_path},
1683                                   std::nullopt,
1684                                   &output_profile,
1685                                   {dex_file_},
1686                                   /*in_options=*/{},
1687                                   &result)
1688                   .isOk());
1689   EXPECT_TRUE(result);
1690   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
1691   EXPECT_THAT(output_profile.profilePath.tmpPath, Not(IsEmpty()));
1692 }
1693 
TEST_F(ArtdTest,mergeProfilesProfilesDontExist)1694 TEST_F(ArtdTest, mergeProfilesProfilesDontExist) {
1695   const TmpProfilePath& reference_profile_path = profile_path_->get<ProfilePath::tmpProfilePath>();
1696   std::string reference_profile_file = OR_FATAL(BuildTmpProfilePath(reference_profile_path));
1697   CreateFile(reference_profile_file, "abc");
1698 
1699   // Doesn't exist.
1700   PrimaryCurProfilePath profile_0_path{
1701       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1702   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1703 
1704   // Doesn't exist.
1705   PrimaryCurProfilePath profile_1_path{
1706       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
1707   std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
1708 
1709   OutputProfile output_profile{.profilePath = reference_profile_path,
1710                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1711   output_profile.profilePath.id = "";
1712   output_profile.profilePath.tmpPath = "";
1713 
1714   CreateFile(dex_file_);
1715 
1716   EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode).Times(0);
1717 
1718   bool result;
1719   EXPECT_TRUE(artd_
1720                   ->mergeProfiles({profile_0_path},
1721                                   std::nullopt,
1722                                   &output_profile,
1723                                   {dex_file_},
1724                                   /*in_options=*/{},
1725                                   &result)
1726                   .isOk());
1727   EXPECT_FALSE(result);
1728   EXPECT_THAT(output_profile.profilePath.id, IsEmpty());
1729   EXPECT_THAT(output_profile.profilePath.tmpPath, IsEmpty());
1730 }
1731 
TEST_F(ArtdTest,mergeProfilesWithOptionsForceMerge)1732 TEST_F(ArtdTest, mergeProfilesWithOptionsForceMerge) {
1733   PrimaryCurProfilePath profile_0_path{
1734       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1735   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1736   CreateFile(profile_0_file, "def");
1737 
1738   OutputProfile output_profile{.profilePath = profile_path_->get<ProfilePath::tmpProfilePath>(),
1739                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1740   output_profile.profilePath.id = "";
1741   output_profile.profilePath.tmpPath = "";
1742 
1743   CreateFile(dex_file_);
1744 
1745   EXPECT_CALL(
1746       *mock_exec_utils_,
1747       DoExecAndReturnCode(
1748           WhenSplitBy("--", _, AllOf(Contains("--force-merge"), Contains("--boot-image-merge"))),
1749           _,
1750           _))
1751       .WillOnce(Return(ProfmanResult::kSuccess));
1752 
1753   bool result;
1754   EXPECT_TRUE(artd_
1755                   ->mergeProfiles({profile_0_path},
1756                                   std::nullopt,
1757                                   &output_profile,
1758                                   {dex_file_},
1759                                   {.forceMerge = true, .forBootImage = true},
1760                                   &result)
1761                   .isOk());
1762   EXPECT_TRUE(result);
1763   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
1764   EXPECT_THAT(output_profile.profilePath.tmpPath, Not(IsEmpty()));
1765 }
1766 
TEST_F(ArtdTest,mergeProfilesWithOptionsDumpOnly)1767 TEST_F(ArtdTest, mergeProfilesWithOptionsDumpOnly) {
1768   PrimaryCurProfilePath profile_0_path{
1769       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1770   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1771   CreateFile(profile_0_file, "def");
1772 
1773   OutputProfile output_profile{.profilePath = profile_path_->get<ProfilePath::tmpProfilePath>(),
1774                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1775   output_profile.profilePath.id = "";
1776   output_profile.profilePath.tmpPath = "";
1777 
1778   CreateFile(dex_file_);
1779 
1780   EXPECT_CALL(*mock_exec_utils_,
1781               DoExecAndReturnCode(
1782                   AllOf(WhenSplitBy("--",
1783                                     _,
1784                                     AllOf(Contains("--dump-only"),
1785                                           Not(Contains(Flag("--reference-profile-file-fd=", _))))),
1786                         HasKeepFdsFor("--profile-file-fd=", "--apk-fd=", "--dump-output-to-fd=")),
1787                   _,
1788                   _))
1789       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--dump-output-to-fd=", "dump")),
1790                       Return(ProfmanResult::kSuccess)));
1791 
1792   bool result;
1793   EXPECT_TRUE(artd_
1794                   ->mergeProfiles({profile_0_path},
1795                                   std::nullopt,
1796                                   &output_profile,
1797                                   {dex_file_},
1798                                   {.dumpOnly = true},
1799                                   &result)
1800                   .isOk());
1801   EXPECT_TRUE(result);
1802   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
1803   CheckContent(output_profile.profilePath.tmpPath, "dump");
1804 }
1805 
TEST_F(ArtdTest,mergeProfilesWithOptionsDumpClassesAndMethods)1806 TEST_F(ArtdTest, mergeProfilesWithOptionsDumpClassesAndMethods) {
1807   PrimaryCurProfilePath profile_0_path{
1808       .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1809   std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1810   CreateFile(profile_0_file, "def");
1811 
1812   OutputProfile output_profile{.profilePath = profile_path_->get<ProfilePath::tmpProfilePath>(),
1813                                .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1814   output_profile.profilePath.id = "";
1815   output_profile.profilePath.tmpPath = "";
1816 
1817   CreateFile(dex_file_);
1818 
1819   EXPECT_CALL(*mock_exec_utils_,
1820               DoExecAndReturnCode(
1821                   WhenSplitBy("--",
1822                               _,
1823                               AllOf(Contains("--dump-classes-and-methods"),
1824                                     Not(Contains(Flag("--reference-profile-file-fd=", _))))),
1825                   _,
1826                   _))
1827       .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--dump-output-to-fd=", "dump")),
1828                       Return(ProfmanResult::kSuccess)));
1829 
1830   bool result;
1831   EXPECT_TRUE(artd_
1832                   ->mergeProfiles({profile_0_path},
1833                                   std::nullopt,
1834                                   &output_profile,
1835                                   {dex_file_},
1836                                   {.dumpClassesAndMethods = true},
1837                                   &result)
1838                   .isOk());
1839   EXPECT_TRUE(result);
1840   EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
1841   CheckContent(output_profile.profilePath.tmpPath, "dump");
1842 }
1843 
TEST_F(ArtdTest,cleanup)1844 TEST_F(ArtdTest, cleanup) {
1845   // TODO(b/289037540): Fix this.
1846   if (getuid() != kRootUid) {
1847     GTEST_SKIP() << "This test requires root access";
1848   }
1849 
1850   std::vector<std::string> gc_removed_files;
1851   std::vector<std::string> gc_kept_files;
1852 
1853   auto CreateGcRemovedFile = [&](const std::string& path) {
1854     CreateFile(path);
1855     gc_removed_files.push_back(path);
1856   };
1857 
1858   auto CreateGcKeptFile = [&](const std::string& path) {
1859     CreateFile(path);
1860     gc_kept_files.push_back(path);
1861   };
1862 
1863   // Unmanaged files.
1864   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/1.odex");
1865   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/1.odex");
1866   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/1.txt");
1867   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.txt");
1868   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.tmp");
1869 
1870   // Files to keep.
1871   CreateGcKeptFile(android_data_ + "/misc/profiles/cur/1/com.android.foo/primary.prof");
1872   CreateGcKeptFile(android_data_ + "/misc/profiles/cur/3/com.android.foo/primary.prof");
1873   CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex");
1874   CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex");
1875   CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art");
1876   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.vdex");
1877   CreateGcKeptFile(
1878       android_expand_ +
1879       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex");
1880   CreateGcKeptFile(
1881       android_expand_ +
1882       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.vdex");
1883   CreateGcKeptFile(
1884       android_expand_ +
1885       "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.art");
1886   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex");
1887   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.vdex");
1888   CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.art");
1889 
1890   // Files to remove.
1891   CreateGcRemovedFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof");
1892   CreateGcRemovedFile(android_data_ + "/misc/profiles/cur/2/com.android.foo/primary.prof");
1893   CreateGcRemovedFile(android_data_ + "/misc/profiles/cur/3/com.android.bar/primary.prof");
1894   CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/extra.odex");
1895   CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.dex");
1896   CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.vdex");
1897   CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.art");
1898   CreateGcRemovedFile(
1899       android_expand_ +
1900       "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.odex");
1901   CreateGcRemovedFile(
1902       android_expand_ +
1903       "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.vdex");
1904   CreateGcRemovedFile(
1905       android_expand_ +
1906       "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.art");
1907   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/1.prof");
1908   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/1.prof.123456.tmp");
1909   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.odex");
1910   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.vdex");
1911   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.art");
1912   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.odex.123456.tmp");
1913   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/2.odex.123456.tmp");
1914   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.odex");
1915   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.art");
1916   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.vdex.123456.tmp");
1917   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.odex");
1918   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.vdex");
1919   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.art");
1920   CreateGcRemovedFile(android_data_ +
1921                       "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.art.123456.tmp");
1922   CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.bar/aaa/oat/arm64/1.vdex");
1923 
1924   int64_t aidl_return;
1925   ASSERT_TRUE(
1926       artd_
1927           ->cleanup(
1928               {
1929                   PrimaryCurProfilePath{
1930                       .userId = 1, .packageName = "com.android.foo", .profileName = "primary"},
1931                   PrimaryCurProfilePath{
1932                       .userId = 3, .packageName = "com.android.foo", .profileName = "primary"},
1933               },
1934               {
1935                   ArtifactsPath{.dexPath = "/system/app/Foo/Foo.apk",
1936                                 .isa = "arm64",
1937                                 .isInDalvikCache = true},
1938                   ArtifactsPath{
1939                       .dexPath =
1940                           android_expand_ +
1941                           "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/base.apk",
1942                       .isa = "arm64",
1943                       .isInDalvikCache = false},
1944                   ArtifactsPath{.dexPath = android_data_ + "/user_de/0/com.android.foo/aaa/2.apk",
1945                                 .isa = "arm64",
1946                                 .isInDalvikCache = false},
1947               },
1948               {
1949                   VdexPath{ArtifactsPath{
1950                       .dexPath = android_data_ + "/user_de/0/com.android.foo/aaa/1.apk",
1951                       .isa = "arm64",
1952                       .isInDalvikCache = false}},
1953               },
1954               &aidl_return)
1955           .isOk());
1956 
1957   for (const std::string& path : gc_removed_files) {
1958     EXPECT_FALSE(std::filesystem::exists(path)) << "'{}' should be removed"_format(path);
1959   }
1960 
1961   for (const std::string& path : gc_kept_files) {
1962     EXPECT_TRUE(std::filesystem::exists(path)) << "'{}' should be kept"_format(path);
1963   }
1964 }
1965 
1966 }  // namespace
1967 }  // namespace artd
1968 }  // namespace art
1969