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