blob: fc7c0765ef2e3e5a993208a48769eb5cec8924eb [file] [log] [blame]
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +01001/*
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
Jiakai Zhangab3f4192022-09-23 13:14:18 +010019#include <fcntl.h>
Jiakai Zhanga4692662022-11-23 14:10:03 +000020#include <sys/stat.h>
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010021#include <sys/types.h>
Jiakai Zhangab3f4192022-09-23 13:14:18 +010022#include <unistd.h>
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010023
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010024#include <algorithm>
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010025#include <chrono>
26#include <condition_variable>
27#include <csignal>
Jiakai Zhang851b3f82023-09-06 18:40:05 +010028#include <cstdio>
Jiakai Zhang543be882023-09-28 20:11:19 +010029#include <cstring>
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010030#include <filesystem>
31#include <functional>
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +010032#include <memory>
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010033#include <mutex>
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010034#include <optional>
35#include <string>
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010036#include <thread>
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010037#include <type_traits>
Jiakai Zhang7b6aef72022-12-12 19:30:44 +000038#include <unordered_set>
39#include <utility>
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010040#include <vector>
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +010041
Jiakai Zhang3041b6d2022-12-23 18:18:27 +000042#include "aidl/com/android/server/art/ArtConstants.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010043#include "aidl/com/android/server/art/BnArtd.h"
Jiakai Zhang7b6aef72022-12-12 19:30:44 +000044#include "android-base/collections.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010045#include "android-base/errors.h"
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010046#include "android-base/file.h"
47#include "android-base/logging.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010048#include "android-base/parseint.h"
Jiakai Zhangb30ed112023-06-28 13:44:56 +010049#include "android-base/result-gmock.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010050#include "android-base/result.h"
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010051#include "android-base/scopeguard.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010052#include "android-base/strings.h"
53#include "android/binder_auto_utils.h"
54#include "android/binder_status.h"
Jiakai Zhang7b6aef72022-12-12 19:30:44 +000055#include "base/array_ref.h"
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +010056#include "base/common_art_test.h"
Krzysztof KosiƄski997d3cf2023-04-30 01:22:28 +000057#include "base/macros.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010058#include "exec_utils.h"
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010059#include "gmock/gmock.h"
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +010060#include "gtest/gtest.h"
Dmitrii Ishcheikin06d94bd2024-01-17 15:54:51 +000061#include "oat/oat_file.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010062#include "path_utils.h"
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +010063#include "profman/profman_result.h"
Jiakai Zhang7b6aef72022-12-12 19:30:44 +000064#include "testing.h"
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010065#include "tools/system_properties.h"
Jiakai Zhang851b3f82023-09-06 18:40:05 +010066#include "ziparchive/zip_writer.h"
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +010067
68namespace art {
69namespace artd {
70namespace {
71
Jiakai Zhang3041b6d2022-12-23 18:18:27 +000072using ::aidl::com::android::server::art::ArtConstants;
Jiakai Zhang771f64e2023-01-12 17:32:36 +080073using ::aidl::com::android::server::art::ArtdDexoptResult;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010074using ::aidl::com::android::server::art::ArtifactsPath;
Jiakai Zhang851b3f82023-09-06 18:40:05 +010075using ::aidl::com::android::server::art::CopyAndRewriteProfileResult;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010076using ::aidl::com::android::server::art::DexMetadataPath;
77using ::aidl::com::android::server::art::DexoptOptions;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +010078using ::aidl::com::android::server::art::FileVisibility;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010079using ::aidl::com::android::server::art::FsPermission;
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010080using ::aidl::com::android::server::art::IArtdCancellationSignal;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010081using ::aidl::com::android::server::art::OutputArtifacts;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +010082using ::aidl::com::android::server::art::OutputProfile;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010083using ::aidl::com::android::server::art::PriorityClass;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +010084using ::aidl::com::android::server::art::ProfilePath;
Jiakai Zhang35650592023-09-07 19:05:10 +010085using ::aidl::com::android::server::art::RuntimeArtifactsPath;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010086using ::aidl::com::android::server::art::VdexPath;
Jiakai Zhang7b6aef72022-12-12 19:30:44 +000087using ::android::base::Append;
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +010088using ::android::base::Error;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010089using ::android::base::make_scope_guard;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010090using ::android::base::ParseInt;
Jiakai Zhangab3f4192022-09-23 13:14:18 +010091using ::android::base::ReadFdToString;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010092using ::android::base::ReadFileToString;
93using ::android::base::Result;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010094using ::android::base::ScopeGuard;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +010095using ::android::base::Split;
96using ::android::base::WriteStringToFd;
97using ::android::base::WriteStringToFile;
Jiakai Zhangb30ed112023-06-28 13:44:56 +010098using ::android::base::testing::HasValue;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +010099using ::testing::_;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100100using ::testing::AllOf;
101using ::testing::AnyNumber;
Jiakai Zhanga4692662022-11-23 14:10:03 +0000102using ::testing::AnyOf;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100103using ::testing::Contains;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100104using ::testing::ContainsRegex;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100105using ::testing::DoAll;
106using ::testing::ElementsAre;
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100107using ::testing::Field;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100108using ::testing::HasSubstr;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100109using ::testing::IsEmpty;
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100110using ::testing::Matcher;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100111using ::testing::MockFunction;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100112using ::testing::Not;
Jiakai Zhanga4692662022-11-23 14:10:03 +0000113using ::testing::Property;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100114using ::testing::ResultOf;
115using ::testing::Return;
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100116using ::testing::SetArgPointee;
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000117using ::testing::UnorderedElementsAreArray;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100118using ::testing::WithArg;
119
Jiakai Zhangca327972022-10-18 10:59:10 +0100120using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
121using PrimaryRefProfilePath = ProfilePath::PrimaryRefProfilePath;
122using TmpProfilePath = ProfilePath::TmpProfilePath;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100123
Jiakai Zhang543be882023-09-28 20:11:19 +0100124using std::literals::operator""s; // NOLINT
125
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100126ScopeGuard<std::function<void()>> ScopedSetLogger(android::base::LogFunction&& logger) {
127 android::base::LogFunction old_logger = android::base::SetLogger(std::move(logger));
128 return make_scope_guard([old_logger = std::move(old_logger)]() mutable {
129 android::base::SetLogger(std::move(old_logger));
130 });
131}
132
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100133void CheckContent(const std::string& path, const std::string& expected_content) {
134 std::string actual_content;
135 ASSERT_TRUE(ReadFileToString(path, &actual_content));
136 EXPECT_EQ(actual_content, expected_content);
137}
138
Jiakai Zhanga4692662022-11-23 14:10:03 +0000139void CheckOtherReadable(const std::string& path, bool expected_value) {
140 EXPECT_EQ((std::filesystem::status(path).permissions() & std::filesystem::perms::others_read) !=
141 std::filesystem::perms::none,
142 expected_value);
143}
144
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000145Result<std::vector<std::string>> GetFlagValues(ArrayRef<const std::string> args,
146 std::string_view flag) {
147 std::vector<std::string> values;
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100148 for (const std::string& arg : args) {
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100149 std::string_view value(arg);
150 if (android::base::ConsumePrefix(&value, flag)) {
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000151 values.emplace_back(value);
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100152 }
153 }
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000154 if (values.empty()) {
155 return Errorf("Flag '{}' not found", flag);
156 }
157 return values;
158}
159
160Result<std::string> GetFlagValue(ArrayRef<const std::string> args, std::string_view flag) {
161 std::vector<std::string> flag_values = OR_RETURN(GetFlagValues(args, flag));
162 if (flag_values.size() > 1) {
163 return Errorf("Duplicate flag '{}'", flag);
164 }
165 return flag_values[0];
166}
167
168void WriteToFdFlagImpl(const std::vector<std::string>& args,
169 std::string_view flag,
170 std::string_view content,
171 bool assume_empty) {
172 std::string value = OR_FAIL(GetFlagValue(ArrayRef<const std::string>(args), flag));
173 ASSERT_NE(value, "");
174 int fd;
175 ASSERT_TRUE(ParseInt(value, &fd));
176 if (assume_empty) {
177 ASSERT_EQ(lseek(fd, /*offset=*/0, SEEK_CUR), 0);
178 } else {
179 ASSERT_EQ(ftruncate(fd, /*length=*/0), 0);
180 ASSERT_EQ(lseek(fd, /*offset=*/0, SEEK_SET), 0);
181 }
182 ASSERT_TRUE(WriteStringToFd(content, fd));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100183}
184
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100185// Writes `content` to the FD specified by the `flag`.
186ACTION_P(WriteToFdFlag, flag, content) {
187 WriteToFdFlagImpl(arg0, flag, content, /*assume_empty=*/true);
188}
189
190// Clears any existing content and writes `content` to the FD specified by the `flag`.
191ACTION_P(ClearAndWriteToFdFlag, flag, content) {
192 WriteToFdFlagImpl(arg0, flag, content, /*assume_empty=*/false);
193}
194
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100195// Matches a flag that starts with `flag` and whose value matches `matcher`.
196MATCHER_P2(Flag, flag, matcher, "") {
197 std::string_view value(arg);
198 if (!android::base::ConsumePrefix(&value, flag)) {
199 return false;
200 }
201 return ExplainMatchResult(matcher, std::string(value), result_listener);
202}
203
204// Matches a flag that starts with `flag` and whose value is a colon-separated list that matches
205// `matcher`. The matcher acts on an `std::vector<std::string>` of the split list argument.
206MATCHER_P2(ListFlag, flag, matcher, "") {
207 return ExplainMatchResult(
208 Flag(flag, ResultOf(std::bind(Split, std::placeholders::_1, ":"), matcher)),
209 arg,
210 result_listener);
211}
212
213// Matches an FD of a file whose path matches `matcher`.
214MATCHER_P(FdOf, matcher, "") {
Krzysztof KosiƄski997d3cf2023-04-30 01:22:28 +0000215 std::string proc_path = ART_FORMAT("/proc/self/fd/{}", arg);
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100216 char path[PATH_MAX];
217 ssize_t len = readlink(proc_path.c_str(), path, sizeof(path));
218 if (len < 0) {
219 return false;
220 }
221 return ExplainMatchResult(matcher, std::string(path, static_cast<size_t>(len)), result_listener);
222}
223
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100224// Matches an FD of a file whose content matches `matcher`.
225MATCHER_P(FdHasContent, matcher, "") {
226 int fd;
227 if (!ParseInt(arg, &fd)) {
228 return false;
229 }
230 std::string actual_content;
231 if (!ReadFdToString(fd, &actual_content)) {
232 return false;
233 }
234 return ExplainMatchResult(matcher, actual_content, result_listener);
235}
236
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000237template <typename T, typename U>
238Result<std::pair<ArrayRef<const T>, ArrayRef<const T>>> SplitBy(const std::vector<T>& list,
239 const U& separator) {
240 auto it = std::find(list.begin(), list.end(), separator);
241 if (it == list.end()) {
242 return Errorf("'{}' not found", separator);
243 }
244 size_t pos = it - list.begin();
245 return std::make_pair(ArrayRef<const T>(list).SubArray(0, pos),
246 ArrayRef<const T>(list).SubArray(pos + 1));
247}
248
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100249// Matches a container that, when split by `separator`, the first part matches `head_matcher`, and
250// the second part matches `tail_matcher`.
251MATCHER_P3(WhenSplitBy, separator, head_matcher, tail_matcher, "") {
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000252 auto [head, tail] = OR_MISMATCH(SplitBy(arg, separator));
253 return ExplainMatchResult(head_matcher, head, result_listener) &&
254 ExplainMatchResult(tail_matcher, tail, result_listener);
255}
256
257MATCHER_P(HasKeepFdsForImpl, fd_flags, "") {
258 auto [head, tail] = OR_MISMATCH(SplitBy(arg, "--"));
259 std::string keep_fds_value = OR_MISMATCH(GetFlagValue(head, "--keep-fds="));
260 std::vector<std::string> keep_fds = Split(keep_fds_value, ":");
261 std::vector<std::string> fd_flag_values;
262 for (std::string_view fd_flag : fd_flags) {
263 for (const std::string& fd_flag_value : OR_MISMATCH(GetFlagValues(tail, fd_flag))) {
264 for (std::string& fd : Split(fd_flag_value, ":")) {
265 fd_flag_values.push_back(std::move(fd));
266 }
267 }
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100268 }
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000269 return ExplainMatchResult(UnorderedElementsAreArray(fd_flag_values), keep_fds, result_listener);
270}
271
272// Matches an argument list that has the "--keep-fds=" flag before "--", whose value is a
273// semicolon-separated list that contains exactly the values of the given flags after "--".
274//
275// E.g., if the flags after "--" are "--foo=1", "--bar=2:3", "--baz=4", "--baz=5", and the matcher
276// is `HasKeepFdsFor("--foo=", "--bar=", "--baz=")`, then it requires the "--keep-fds=" flag before
277// "--" to contain exactly 1, 2, 3, 4, and 5.
278template <typename... Args>
279auto HasKeepFdsFor(Args&&... args) {
280 std::vector<std::string_view> fd_flags;
281 Append(fd_flags, std::forward<Args>(args)...);
282 return HasKeepFdsForImpl(fd_flags);
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100283}
284
285class MockSystemProperties : public tools::SystemProperties {
286 public:
287 MOCK_METHOD(std::string, GetProperty, (const std::string& key), (const, override));
288};
289
290class MockExecUtils : public ExecUtils {
291 public:
292 // A workaround to avoid MOCK_METHOD on a method with an `std::string*` parameter, which will lead
293 // to a conflict between gmock and android-base/logging.h (b/132668253).
Jiakai Zhangfa152ba2022-09-13 14:14:16 +0100294 ExecResult ExecAndReturnResult(const std::vector<std::string>& arg_vector,
295 int,
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100296 const ExecCallbacks& callbacks,
Jiakai Zhangfa152ba2022-09-13 14:14:16 +0100297 ProcessStat* stat,
298 std::string*) const override {
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100299 Result<int> code = DoExecAndReturnCode(arg_vector, callbacks, stat);
Jiakai Zhangfa152ba2022-09-13 14:14:16 +0100300 if (code.ok()) {
301 return {.status = ExecResult::kExited, .exit_code = code.value()};
302 }
303 return {.status = ExecResult::kUnknown};
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100304 }
305
Jiakai Zhangfa152ba2022-09-13 14:14:16 +0100306 MOCK_METHOD(Result<int>,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100307 DoExecAndReturnCode,
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100308 (const std::vector<std::string>& arg_vector,
309 const ExecCallbacks& callbacks,
310 ProcessStat* stat),
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100311 (const));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100312};
313
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +0100314class ArtdTest : public CommonArtTest {
315 protected:
316 void SetUp() override {
317 CommonArtTest::SetUp();
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100318 auto mock_props = std::make_unique<MockSystemProperties>();
319 mock_props_ = mock_props.get();
320 EXPECT_CALL(*mock_props_, GetProperty).Times(AnyNumber()).WillRepeatedly(Return(""));
321 auto mock_exec_utils = std::make_unique<MockExecUtils>();
322 mock_exec_utils_ = mock_exec_utils.get();
Jiakai Zhanga4692662022-11-23 14:10:03 +0000323 artd_ = ndk::SharedRefBase::make<Artd>(std::move(mock_props),
324 std::move(mock_exec_utils),
325 mock_kill_.AsStdFunction(),
326 mock_fstat_.AsStdFunction());
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100327 scratch_dir_ = std::make_unique<ScratchDir>();
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100328 scratch_path_ = scratch_dir_->GetPath();
329 // Remove the trailing '/';
330 scratch_path_.resize(scratch_path_.length() - 1);
331
Jiakai Zhangcde2f062023-09-08 20:52:59 +0100332 TestOnlySetListRootDir(scratch_path_);
333
Jiakai Zhanga4692662022-11-23 14:10:03 +0000334 ON_CALL(mock_fstat_, Call).WillByDefault(fstat);
335
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100336 // Use an arbitrary existing directory as ART root.
337 art_root_ = scratch_path_ + "/com.android.art";
338 std::filesystem::create_directories(art_root_);
339 setenv("ANDROID_ART_ROOT", art_root_.c_str(), /*overwrite=*/1);
340
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100341 // Use an arbitrary existing directory as Android data.
342 android_data_ = scratch_path_ + "/data";
343 std::filesystem::create_directories(android_data_);
344 setenv("ANDROID_DATA", android_data_.c_str(), /*overwrite=*/1);
345
Jiakai Zhang3041b6d2022-12-23 18:18:27 +0000346 // Use an arbitrary existing directory as Android expand.
347 android_expand_ = scratch_path_ + "/mnt/expand";
348 std::filesystem::create_directories(android_expand_);
349 setenv("ANDROID_EXPAND", android_expand_.c_str(), /*overwrite=*/1);
350
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100351 dex_file_ = scratch_path_ + "/a/b.apk";
352 isa_ = "arm64";
353 artifacts_path_ = ArtifactsPath{
354 .dexPath = dex_file_,
355 .isa = isa_,
356 .isInDalvikCache = false,
357 };
358 struct stat st;
359 ASSERT_EQ(stat(scratch_path_.c_str(), &st), 0);
360 output_artifacts_ = OutputArtifacts{
361 .artifactsPath = artifacts_path_,
362 .permissionSettings =
363 OutputArtifacts::PermissionSettings{
364 .dirFsPermission =
365 FsPermission{
366 .uid = static_cast<int32_t>(st.st_uid),
367 .gid = static_cast<int32_t>(st.st_gid),
368 .isOtherReadable = true,
369 .isOtherExecutable = true,
370 },
371 .fileFsPermission =
372 FsPermission{
373 .uid = static_cast<int32_t>(st.st_uid),
374 .gid = static_cast<int32_t>(st.st_gid),
375 .isOtherReadable = true,
376 },
377 },
378 };
379 clc_1_ = GetTestDexFileName("Main");
380 clc_2_ = GetTestDexFileName("Nested");
Krzysztof KosiƄski997d3cf2023-04-30 01:22:28 +0000381 class_loader_context_ = ART_FORMAT("PCL[{}:{}]", clc_1_, clc_2_);
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100382 compiler_filter_ = "speed";
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100383 tmp_profile_path_ =
384 TmpProfilePath{.finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
385 .profileName = "primary"},
386 .id = "12345"};
387 profile_path_ = tmp_profile_path_;
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000388 vdex_path_ = artifacts_path_;
389 dm_path_ = DexMetadataPath{.dexPath = dex_file_};
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100390 std::filesystem::create_directories(
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100391 std::filesystem::path(OR_FATAL(BuildFinalProfilePath(tmp_profile_path_))).parent_path());
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +0100392 }
393
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100394 void TearDown() override {
395 scratch_dir_.reset();
396 CommonArtTest::TearDown();
397 }
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +0100398
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100399 void RunDexopt(binder_exception_t expected_status = EX_NONE,
Jiakai Zhang771f64e2023-01-12 17:32:36 +0800400 Matcher<ArtdDexoptResult> aidl_return_matcher = Field(&ArtdDexoptResult::cancelled,
401 false),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100402 std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) {
Jiakai Zhanga4692662022-11-23 14:10:03 +0000403 RunDexopt(Property(&ndk::ScopedAStatus::getExceptionCode, expected_status),
404 std::move(aidl_return_matcher),
Yabin Cui50510ba2023-05-31 19:43:37 +0000405 std::move(cancellation_signal));
Jiakai Zhanga4692662022-11-23 14:10:03 +0000406 }
407
408 void RunDexopt(Matcher<ndk::ScopedAStatus> status_matcher,
Jiakai Zhang771f64e2023-01-12 17:32:36 +0800409 Matcher<ArtdDexoptResult> aidl_return_matcher = Field(&ArtdDexoptResult::cancelled,
410 false),
Jiakai Zhanga4692662022-11-23 14:10:03 +0000411 std::shared_ptr<IArtdCancellationSignal> cancellation_signal = nullptr) {
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000412 InitFilesBeforeDexopt();
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100413 if (cancellation_signal == nullptr) {
414 ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
415 }
Jiakai Zhang771f64e2023-01-12 17:32:36 +0800416 ArtdDexoptResult aidl_return;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100417 ndk::ScopedAStatus status = artd_->dexopt(output_artifacts_,
418 dex_file_,
419 isa_,
420 class_loader_context_,
421 compiler_filter_,
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100422 profile_path_,
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100423 vdex_path_,
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000424 dm_path_,
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100425 priority_class_,
426 dexopt_options_,
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100427 cancellation_signal,
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100428 &aidl_return);
Jiakai Zhanga4692662022-11-23 14:10:03 +0000429 ASSERT_THAT(status, std::move(status_matcher)) << status.getMessage();
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100430 if (status.isOk()) {
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100431 ASSERT_THAT(aidl_return, std::move(aidl_return_matcher));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100432 }
433 }
434
Jiakai Zhang543be882023-09-28 20:11:19 +0100435 template <bool kExpectOk>
436 using RunCopyAndRewriteProfileResult = Result<
437 std::pair<std::conditional_t<kExpectOk, CopyAndRewriteProfileResult, ndk::ScopedAStatus>,
438 OutputProfile>>;
439
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100440 // Runs `copyAndRewriteProfile` with `tmp_profile_path_` and `dex_file_`.
441 template <bool kExpectOk = true>
Jiakai Zhang543be882023-09-28 20:11:19 +0100442 RunCopyAndRewriteProfileResult<kExpectOk> RunCopyAndRewriteProfile() {
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100443 OutputProfile dst{.profilePath = tmp_profile_path_,
444 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
445 dst.profilePath.id = "";
446 dst.profilePath.tmpPath = "";
447
448 CopyAndRewriteProfileResult result;
449 ndk::ScopedAStatus status =
450 artd_->copyAndRewriteProfile(tmp_profile_path_, &dst, dex_file_, &result);
451 if constexpr (kExpectOk) {
452 if (!status.isOk()) {
453 return Error() << status.getMessage();
454 }
455 return std::make_pair(std::move(result), std::move(dst));
456 } else {
457 return std::make_pair(std::move(status), std::move(dst));
458 }
459 }
460
Jiakai Zhang543be882023-09-28 20:11:19 +0100461 // Runs `copyAndRewriteEmbeddedProfile` with `dex_file_`.
462 template <bool kExpectOk = true>
463 RunCopyAndRewriteProfileResult<kExpectOk> RunCopyAndRewriteEmbeddedProfile() {
464 OutputProfile dst{.profilePath = tmp_profile_path_,
465 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
466 dst.profilePath.id = "";
467 dst.profilePath.tmpPath = "";
468
469 CopyAndRewriteProfileResult result;
470 ndk::ScopedAStatus status = artd_->copyAndRewriteEmbeddedProfile(&dst, dex_file_, &result);
471 if constexpr (kExpectOk) {
472 if (!status.isOk()) {
473 return Error() << status.getMessage();
474 }
475 return std::make_pair(std::move(result), std::move(dst));
476 } else {
477 return std::make_pair(std::move(status), std::move(dst));
478 }
479 }
480
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100481 void CreateFile(const std::string& filename, const std::string& content = "") {
482 std::filesystem::path path(filename);
483 std::filesystem::create_directories(path.parent_path());
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100484 ASSERT_TRUE(WriteStringToFile(content, filename));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100485 }
486
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100487 void CreateZipWithSingleEntry(const std::string& filename,
488 const std::string& entry_name,
489 const std::string& content = "") {
Jiakai Zhang543be882023-09-28 20:11:19 +0100490 std::filesystem::path path(filename);
491 std::filesystem::create_directories(path.parent_path());
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100492 std::unique_ptr<File> file(OS::CreateEmptyFileWriteOnly(filename.c_str()));
Jiakai Zhang543be882023-09-28 20:11:19 +0100493 ASSERT_NE(file, nullptr) << strerror(errno);
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100494 file->MarkUnchecked(); // `writer.Finish()` flushes the file and the destructor closes it.
495 ZipWriter writer(fdopen(file->Fd(), "wb"));
496 ASSERT_EQ(writer.StartEntry(entry_name, /*flags=*/0), 0);
497 ASSERT_EQ(writer.WriteBytes(content.c_str(), content.size()), 0);
498 ASSERT_EQ(writer.FinishEntry(), 0);
499 ASSERT_EQ(writer.Finish(), 0);
500 }
501
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +0100502 std::shared_ptr<Artd> artd_;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100503 std::unique_ptr<ScratchDir> scratch_dir_;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100504 std::string scratch_path_;
505 std::string art_root_;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100506 std::string android_data_;
Jiakai Zhang3041b6d2022-12-23 18:18:27 +0000507 std::string android_expand_;
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100508 MockFunction<android::base::LogFunction> mock_logger_;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100509 ScopedUnsetEnvironmentVariable art_root_env_ = ScopedUnsetEnvironmentVariable("ANDROID_ART_ROOT");
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100510 ScopedUnsetEnvironmentVariable android_data_env_ = ScopedUnsetEnvironmentVariable("ANDROID_DATA");
Jiakai Zhang3041b6d2022-12-23 18:18:27 +0000511 ScopedUnsetEnvironmentVariable android_expand_env_ =
512 ScopedUnsetEnvironmentVariable("ANDROID_EXPAND");
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100513 MockSystemProperties* mock_props_;
514 MockExecUtils* mock_exec_utils_;
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100515 MockFunction<int(pid_t, int)> mock_kill_;
Jiakai Zhanga4692662022-11-23 14:10:03 +0000516 MockFunction<int(int, struct stat*)> mock_fstat_;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100517
518 std::string dex_file_;
519 std::string isa_;
520 ArtifactsPath artifacts_path_;
521 OutputArtifacts output_artifacts_;
522 std::string clc_1_;
523 std::string clc_2_;
Jiakai Zhang12f45c42022-10-27 15:23:03 +0100524 std::optional<std::string> class_loader_context_;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100525 std::string compiler_filter_;
526 std::optional<VdexPath> vdex_path_;
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000527 std::optional<DexMetadataPath> dm_path_;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100528 PriorityClass priority_class_ = PriorityClass::BACKGROUND;
529 DexoptOptions dexopt_options_;
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100530 std::optional<ProfilePath> profile_path_;
Jiakai Zhang851b3f82023-09-06 18:40:05 +0100531 TmpProfilePath tmp_profile_path_;
Jiakai Zhanga4692662022-11-23 14:10:03 +0000532 bool dex_file_other_readable_ = true;
533 bool profile_other_readable_ = true;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100534
535 private:
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000536 void InitFilesBeforeDexopt() {
537 // Required files.
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100538 CreateFile(dex_file_);
Jiakai Zhanga4692662022-11-23 14:10:03 +0000539 std::filesystem::permissions(dex_file_,
540 std::filesystem::perms::others_read,
541 dex_file_other_readable_ ? std::filesystem::perm_options::add :
542 std::filesystem::perm_options::remove);
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000543
544 // Optional files.
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100545 if (vdex_path_.has_value()) {
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000546 CreateFile(OR_FATAL(BuildVdexPath(vdex_path_.value())), "old_vdex");
547 }
548 if (dm_path_.has_value()) {
549 CreateFile(OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100550 }
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100551 if (profile_path_.has_value()) {
Jiakai Zhanga4692662022-11-23 14:10:03 +0000552 std::string path = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
553 CreateFile(path);
554 std::filesystem::permissions(path,
555 std::filesystem::perms::others_read,
556 profile_other_readable_ ? std::filesystem::perm_options::add :
557 std::filesystem::perm_options::remove);
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100558 }
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000559
560 // Files to be replaced.
561 std::string oat_path = OR_FATAL(BuildOatPath(artifacts_path_));
562 CreateFile(oat_path, "old_oat");
563 CreateFile(OatPathToVdexPath(oat_path), "old_vdex");
564 CreateFile(OatPathToArtPath(oat_path), "old_art");
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100565 }
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +0100566};
567
Florian Mayer614afe52023-10-10 18:52:25 +0000568TEST_F(ArtdTest, ConstantsAreInSync) { EXPECT_STREQ(ArtConstants::REASON_VDEX, kReasonVdex); }
Jiakai Zhang3041b6d2022-12-23 18:18:27 +0000569
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +0100570TEST_F(ArtdTest, isAlive) {
571 bool result = false;
572 artd_->isAlive(&result);
573 EXPECT_TRUE(result);
574}
575
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100576TEST_F(ArtdTest, deleteArtifacts) {
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100577 std::string oat_dir = scratch_path_ + "/a/oat/arm64";
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100578 std::filesystem::create_directories(oat_dir);
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100579 ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex")); // 4 bytes.
580 ASSERT_TRUE(WriteStringToFile("ab", oat_dir + "/b.vdex")); // 2 bytes.
581 ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art")); // 1 byte.
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100582
583 int64_t result = -1;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100584 EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100585 EXPECT_EQ(result, 4 + 2 + 1);
586
587 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.odex"));
588 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.vdex"));
589 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.art"));
590}
591
592TEST_F(ArtdTest, deleteArtifactsMissingFile) {
593 // Missing VDEX file.
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +0100594 std::string oat_dir = android_data_ + "/dalvik-cache/arm64";
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100595 std::filesystem::create_directories(oat_dir);
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100596 ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/a@b.apk@classes.dex")); // 4 bytes.
597 ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/a@b.apk@classes.art")); // 1 byte.
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100598
599 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
600 EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(0);
601
602 int64_t result = -1;
603 EXPECT_TRUE(artd_
604 ->deleteArtifacts(
605 ArtifactsPath{
606 .dexPath = "/a/b.apk",
607 .isa = "arm64",
608 .isInDalvikCache = true,
609 },
610 &result)
611 .isOk());
612 EXPECT_EQ(result, 4 + 1);
613
614 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/a@b.apk@classes.dex"));
615 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/a@b.apk@classes.art"));
616}
617
618TEST_F(ArtdTest, deleteArtifactsNoFile) {
619 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
620 EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(0);
621
622 int64_t result = -1;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100623 EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100624 EXPECT_EQ(result, 0);
625}
626
627TEST_F(ArtdTest, deleteArtifactsPermissionDenied) {
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100628 std::string oat_dir = scratch_path_ + "/a/oat/arm64";
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100629 std::filesystem::create_directories(oat_dir);
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100630 ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex")); // 4 bytes.
631 ASSERT_TRUE(WriteStringToFile("ab", oat_dir + "/b.vdex")); // 2 bytes.
632 ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art")); // 1 byte.
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100633
634 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
635 EXPECT_CALL(mock_logger_, Call(_, _, _, _, _, HasSubstr("Failed to get the file size"))).Times(3);
636
637 auto scoped_inaccessible = ScopedInaccessible(oat_dir);
638 auto scoped_unroot = ScopedUnroot();
639
640 int64_t result = -1;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100641 EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100642 EXPECT_EQ(result, 0);
643}
644
645TEST_F(ArtdTest, deleteArtifactsFileIsDir) {
646 // VDEX file is a directory.
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100647 std::string oat_dir = scratch_path_ + "/a/oat/arm64";
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100648 std::filesystem::create_directories(oat_dir);
649 std::filesystem::create_directories(oat_dir + "/b.vdex");
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100650 ASSERT_TRUE(WriteStringToFile("abcd", oat_dir + "/b.odex")); // 4 bytes.
651 ASSERT_TRUE(WriteStringToFile("a", oat_dir + "/b.art")); // 1 byte.
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100652
653 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
654 EXPECT_CALL(mock_logger_,
655 Call(_, _, _, _, _, ContainsRegex(R"re(Failed to get the file size.*b\.vdex)re")))
656 .Times(1);
657
658 int64_t result = -1;
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100659 EXPECT_TRUE(artd_->deleteArtifacts(artifacts_path_, &result).isOk());
Jiakai Zhang6b9e3442022-06-06 19:57:38 +0100660 EXPECT_EQ(result, 4 + 1);
661
662 // The directory is kept because getting the file size failed.
663 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.odex"));
664 EXPECT_TRUE(std::filesystem::exists(oat_dir + "/b.vdex"));
665 EXPECT_FALSE(std::filesystem::exists(oat_dir + "/b.art"));
666}
667
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100668TEST_F(ArtdTest, dexopt) {
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000669 dexopt_options_.generateAppImage = true;
670
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100671 EXPECT_CALL(
672 *mock_exec_utils_,
673 DoExecAndReturnCode(
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000674 AllOf(WhenSplitBy(
675 "--",
676 AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
677 AllOf(Contains(art_root_ + "/bin/dex2oat32"),
678 Contains(Flag("--zip-fd=", FdOf(dex_file_))),
679 Contains(Flag("--zip-location=", dex_file_)),
680 Contains(Flag("--oat-location=", scratch_path_ + "/a/oat/arm64/b.odex")),
681 Contains(Flag("--instruction-set=", "arm64")),
682 Contains(Flag("--compiler-filter=", "speed")),
683 Contains(Flag(
684 "--profile-file-fd=",
685 FdOf(android_data_ +
686 "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"))),
687 Contains(Flag("--input-vdex-fd=",
688 FdOf(scratch_path_ + "/a/oat/arm64/b.vdex"))),
689 Contains(Flag("--dm-fd=", FdOf(scratch_path_ + "/a/b.dm"))))),
690 HasKeepFdsFor("--zip-fd=",
691 "--profile-file-fd=",
692 "--input-vdex-fd=",
693 "--dm-fd=",
694 "--oat-fd=",
695 "--output-vdex-fd=",
696 "--app-image-fd=",
697 "--class-loader-context-fds=",
698 "--swap-fd=")),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100699 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100700 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100701 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
702 WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000703 WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100704 SetArgPointee<2>(ProcessStat{.wall_time_ms = 100, .cpu_time_ms = 400}),
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100705 Return(0)));
Jiakai Zhang771f64e2023-01-12 17:32:36 +0800706 RunDexopt(
707 EX_NONE,
708 AllOf(Field(&ArtdDexoptResult::cancelled, false),
709 Field(&ArtdDexoptResult::wallTimeMs, 100),
710 Field(&ArtdDexoptResult::cpuTimeMs, 400),
711 Field(&ArtdDexoptResult::sizeBytes, strlen("art") + strlen("oat") + strlen("vdex")),
712 Field(&ArtdDexoptResult::sizeBeforeBytes,
713 strlen("old_art") + strlen("old_oat") + strlen("old_vdex"))));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100714
715 CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "oat");
716 CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "vdex");
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000717 CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "art");
Jiakai Zhanga4692662022-11-23 14:10:03 +0000718 CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.odex", true);
719 CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.vdex", true);
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000720 CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.art", true);
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100721}
722
723TEST_F(ArtdTest, dexoptClassLoaderContext) {
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100724 EXPECT_CALL(
725 *mock_exec_utils_,
726 DoExecAndReturnCode(
727 WhenSplitBy("--",
728 _,
729 AllOf(Contains(ListFlag("--class-loader-context-fds=",
730 ElementsAre(FdOf(clc_1_), FdOf(clc_2_)))),
731 Contains(Flag("--class-loader-context=", class_loader_context_)),
732 Contains(Flag("--classpath-dir=", scratch_path_ + "/a")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100733 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100734 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100735 .WillOnce(Return(0));
736 RunDexopt();
737}
738
Jiakai Zhang12f45c42022-10-27 15:23:03 +0100739TEST_F(ArtdTest, dexoptClassLoaderContextNull) {
740 class_loader_context_ = std::nullopt;
741
742 EXPECT_CALL(
743 *mock_exec_utils_,
744 DoExecAndReturnCode(WhenSplitBy("--",
745 _,
746 AllOf(Not(Contains(Flag("--class-loader-context-fds=", _))),
747 Not(Contains(Flag("--class-loader-context=", _))),
748 Not(Contains(Flag("--classpath-dir=", _))))),
749 _,
750 _))
751 .WillOnce(Return(0));
752 RunDexopt();
753}
754
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000755TEST_F(ArtdTest, dexoptNoOptionalInputFiles) {
756 profile_path_ = std::nullopt;
757 vdex_path_ = std::nullopt;
758 dm_path_ = std::nullopt;
759
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100760 EXPECT_CALL(*mock_exec_utils_,
761 DoExecAndReturnCode(WhenSplitBy("--",
762 _,
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000763 AllOf(Not(Contains(Flag("--profile-file-fd=", _))),
764 Not(Contains(Flag("--input-vdex-fd=", _))),
765 Not(Contains(Flag("--dm-fd=", _))))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100766 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100767 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100768 .WillOnce(Return(0));
769 RunDexopt();
770}
771
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100772TEST_F(ArtdTest, dexoptPriorityClassBoot) {
773 priority_class_ = PriorityClass::BOOT;
774 EXPECT_CALL(*mock_exec_utils_,
775 DoExecAndReturnCode(WhenSplitBy("--",
776 AllOf(Not(Contains(Flag("--set-task-profile=", _))),
777 Not(Contains(Flag("--set-priority=", _)))),
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100778 Contains(Flag("--compact-dex-level=", "none"))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100779 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100780 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100781 .WillOnce(Return(0));
782 RunDexopt();
783}
784
785TEST_F(ArtdTest, dexoptPriorityClassInteractive) {
786 priority_class_ = PriorityClass::INTERACTIVE;
787 EXPECT_CALL(*mock_exec_utils_,
788 DoExecAndReturnCode(
789 WhenSplitBy("--",
790 AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
791 Contains(Flag("--set-priority=", "background"))),
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100792 Contains(Flag("--compact-dex-level=", "none"))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100793 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100794 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100795 .WillOnce(Return(0));
796 RunDexopt();
797}
798
799TEST_F(ArtdTest, dexoptPriorityClassInteractiveFast) {
800 priority_class_ = PriorityClass::INTERACTIVE_FAST;
801 EXPECT_CALL(*mock_exec_utils_,
802 DoExecAndReturnCode(
803 WhenSplitBy("--",
804 AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBootComplete")),
805 Contains(Flag("--set-priority=", "background"))),
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100806 Contains(Flag("--compact-dex-level=", "none"))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100807 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100808 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100809 .WillOnce(Return(0));
810 RunDexopt();
811}
812
813TEST_F(ArtdTest, dexoptPriorityClassBackground) {
814 priority_class_ = PriorityClass::BACKGROUND;
815 EXPECT_CALL(*mock_exec_utils_,
816 DoExecAndReturnCode(
817 WhenSplitBy("--",
Jiakai Zhang7c572522022-12-06 15:44:04 +0000818 AllOf(Contains(Flag("--set-task-profile=", "Dex2OatBackground")),
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100819 Contains(Flag("--set-priority=", "background"))),
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100820 Not(Contains(Flag("--compact-dex-level=", _)))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100821 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100822 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100823 .WillOnce(Return(0));
824 RunDexopt();
825}
826
827TEST_F(ArtdTest, dexoptDexoptOptions) {
828 dexopt_options_ = DexoptOptions{
829 .compilationReason = "install",
830 .targetSdkVersion = 123,
831 .debuggable = false,
832 .generateAppImage = false,
833 .hiddenApiPolicyEnabled = false,
Jiakai Zhang4a76e232023-02-24 12:14:13 +0000834 .comments = "my-comments",
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100835 };
836
837 EXPECT_CALL(
838 *mock_exec_utils_,
839 DoExecAndReturnCode(WhenSplitBy("--",
840 _,
841 AllOf(Contains(Flag("--compilation-reason=", "install")),
842 Contains(Flag("-Xtarget-sdk-version:", "123")),
843 Not(Contains("--debuggable")),
844 Not(Contains(Flag("--app-image-fd=", _))),
Jiakai Zhang4a76e232023-02-24 12:14:13 +0000845 Not(Contains(Flag("-Xhidden-api-policy:", _))),
846 Contains(Flag("--comments=", "my-comments")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100847 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100848 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100849 .WillOnce(Return(0));
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000850
851 // `sizeBeforeBytes` should include the size of the old ART file even if no new ART file is
852 // generated.
853 RunDexopt(EX_NONE,
Jiakai Zhang771f64e2023-01-12 17:32:36 +0800854 Field(&ArtdDexoptResult::sizeBeforeBytes,
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000855 strlen("old_art") + strlen("old_oat") + strlen("old_vdex")));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100856}
857
858TEST_F(ArtdTest, dexoptDexoptOptions2) {
859 dexopt_options_ = DexoptOptions{
860 .compilationReason = "bg-dexopt",
861 .targetSdkVersion = 456,
862 .debuggable = true,
863 .generateAppImage = true,
864 .hiddenApiPolicyEnabled = true,
865 };
866
867 EXPECT_CALL(
868 *mock_exec_utils_,
869 DoExecAndReturnCode(WhenSplitBy("--",
870 _,
871 AllOf(Contains(Flag("--compilation-reason=", "bg-dexopt")),
872 Contains(Flag("-Xtarget-sdk-version:", "456")),
873 Contains("--debuggable"),
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000874 Contains(Flag("--app-image-fd=", _)),
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100875 Contains(Flag("-Xhidden-api-policy:", "enabled")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100876 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100877 _))
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000878 .WillOnce(Return(0));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100879
Jiakai Zhang7b6aef72022-12-12 19:30:44 +0000880 RunDexopt();
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100881}
882
883TEST_F(ArtdTest, dexoptDefaultFlagsWhenNoSystemProps) {
Jiakai Zhang7a8a8412022-11-14 13:53:24 +0000884 dexopt_options_.generateAppImage = true;
885
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100886 EXPECT_CALL(*mock_exec_utils_,
887 DoExecAndReturnCode(
888 WhenSplitBy("--",
889 _,
890 AllOf(Contains(Flag("--swap-fd=", FdOf(_))),
891 Not(Contains(Flag("--instruction-set-features=", _))),
892 Not(Contains(Flag("--instruction-set-variant=", _))),
893 Not(Contains(Flag("--max-image-block-size=", _))),
894 Not(Contains(Flag("--very-large-app-threshold=", _))),
895 Not(Contains(Flag("--resolve-startup-const-strings=", _))),
896 Not(Contains("--generate-debug-info")),
897 Not(Contains("--generate-mini-debug-info")),
898 Contains("-Xdeny-art-apex-data-files"),
899 Not(Contains(Flag("--cpu-set=", _))),
900 Not(Contains(Flag("-j", _))),
901 Not(Contains(Flag("-Xms", _))),
902 Not(Contains(Flag("-Xmx", _))),
Jiakai Zhang7a8a8412022-11-14 13:53:24 +0000903 Not(Contains("--compile-individually")),
Jiakai Zhang6012ce32022-11-14 17:21:40 +0000904 Not(Contains(Flag("--image-format=", _))),
905 Not(Contains("--force-jit-zygote")),
906 Not(Contains(Flag("--boot-image=", _))))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100907 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100908 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100909 .WillOnce(Return(0));
910 RunDexopt();
911}
912
913TEST_F(ArtdTest, dexoptFlagsFromSystemProps) {
Jiakai Zhang7a8a8412022-11-14 13:53:24 +0000914 dexopt_options_.generateAppImage = true;
915
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100916 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-swap")).WillOnce(Return("0"));
917 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.isa.arm64.features"))
918 .WillOnce(Return("features"));
919 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.isa.arm64.variant")).WillOnce(Return("variant"));
920 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-max-image-block-size"))
921 .WillOnce(Return("size"));
922 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-very-large"))
923 .WillOnce(Return("threshold"));
924 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-resolve-startup-strings"))
925 .WillOnce(Return("strings"));
926 EXPECT_CALL(*mock_props_, GetProperty("debug.generate-debug-info")).WillOnce(Return("1"));
927 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-minidebuginfo")).WillOnce(Return("1"));
928 EXPECT_CALL(*mock_props_, GetProperty("odsign.verification.success")).WillOnce(Return("1"));
929 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-Xms")).WillOnce(Return("xms"));
930 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.dex2oat-Xmx")).WillOnce(Return("xmx"));
931 EXPECT_CALL(*mock_props_, GetProperty("ro.config.low_ram")).WillOnce(Return("1"));
Jiakai Zhang7a8a8412022-11-14 13:53:24 +0000932 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.appimageformat")).WillOnce(Return("imgfmt"));
Jiakai Zhang6012ce32022-11-14 17:21:40 +0000933 EXPECT_CALL(*mock_props_, GetProperty("dalvik.vm.boot-image")).WillOnce(Return("boot-image"));
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100934
935 EXPECT_CALL(*mock_exec_utils_,
936 DoExecAndReturnCode(
937 WhenSplitBy("--",
938 _,
939 AllOf(Not(Contains(Flag("--swap-fd=", _))),
940 Contains(Flag("--instruction-set-features=", "features")),
941 Contains(Flag("--instruction-set-variant=", "variant")),
942 Contains(Flag("--max-image-block-size=", "size")),
943 Contains(Flag("--very-large-app-threshold=", "threshold")),
944 Contains(Flag("--resolve-startup-const-strings=", "strings")),
945 Contains("--generate-debug-info"),
946 Contains("--generate-mini-debug-info"),
947 Not(Contains("-Xdeny-art-apex-data-files")),
948 Contains(Flag("-Xms", "xms")),
949 Contains(Flag("-Xmx", "xmx")),
Jiakai Zhang7a8a8412022-11-14 13:53:24 +0000950 Contains("--compile-individually"),
Jiakai Zhang6012ce32022-11-14 17:21:40 +0000951 Contains(Flag("--image-format=", "imgfmt")),
952 Not(Contains("--force-jit-zygote")),
953 Contains(Flag("--boot-image=", "boot-image")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100954 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100955 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100956 .WillOnce(Return(0));
957 RunDexopt();
958}
959
Jiakai Zhang6012ce32022-11-14 17:21:40 +0000960TEST_F(ArtdTest, dexoptFlagsForceJitZygote) {
961 EXPECT_CALL(*mock_props_,
962 GetProperty("persist.device_config.runtime_native_boot.profilebootclasspath"))
963 .WillOnce(Return("true"));
964 ON_CALL(*mock_props_, GetProperty("dalvik.vm.boot-image")).WillByDefault(Return("boot-image"));
965
966 EXPECT_CALL(*mock_exec_utils_,
967 DoExecAndReturnCode(WhenSplitBy("--",
968 _,
969 AllOf(Contains("--force-jit-zygote"),
970 Not(Contains(Flag("--boot-image=", _))))),
971 _,
972 _))
973 .WillOnce(Return(0));
974 RunDexopt();
975}
976
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100977static void SetDefaultResourceControlProps(MockSystemProperties* mock_props) {
978 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-cpu-set")).WillRepeatedly(Return("0,2"));
979 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-threads")).WillRepeatedly(Return("4"));
980}
981
982TEST_F(ArtdTest, dexoptDefaultResourceControlBoot) {
983 SetDefaultResourceControlProps(mock_props_);
984
985 // The default resource control properties don't apply to BOOT.
986 EXPECT_CALL(
987 *mock_exec_utils_,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100988 DoExecAndReturnCode(
989 WhenSplitBy(
990 "--", _, AllOf(Not(Contains(Flag("--cpu-set=", _))), Contains(Not(Flag("-j", _))))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +0100991 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +0100992 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +0100993 .WillOnce(Return(0));
994 priority_class_ = PriorityClass::BOOT;
995 RunDexopt();
996}
997
998TEST_F(ArtdTest, dexoptDefaultResourceControlOther) {
999 SetDefaultResourceControlProps(mock_props_);
1000
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001001 EXPECT_CALL(
1002 *mock_exec_utils_,
1003 DoExecAndReturnCode(
1004 WhenSplitBy(
1005 "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001006 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001007 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001008 .Times(3)
1009 .WillRepeatedly(Return(0));
1010 priority_class_ = PriorityClass::INTERACTIVE_FAST;
1011 RunDexopt();
1012 priority_class_ = PriorityClass::INTERACTIVE;
1013 RunDexopt();
1014 priority_class_ = PriorityClass::BACKGROUND;
1015 RunDexopt();
1016}
1017
1018static void SetAllResourceControlProps(MockSystemProperties* mock_props) {
1019 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-cpu-set")).WillRepeatedly(Return("0,2"));
1020 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.dex2oat-threads")).WillRepeatedly(Return("4"));
1021 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.boot-dex2oat-cpu-set"))
1022 .WillRepeatedly(Return("0,1,2,3"));
1023 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.boot-dex2oat-threads"))
1024 .WillRepeatedly(Return("8"));
1025 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.restore-dex2oat-cpu-set"))
1026 .WillRepeatedly(Return("0,2,3"));
1027 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.restore-dex2oat-threads"))
1028 .WillRepeatedly(Return("6"));
1029 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.background-dex2oat-cpu-set"))
1030 .WillRepeatedly(Return("0"));
1031 EXPECT_CALL(*mock_props, GetProperty("dalvik.vm.background-dex2oat-threads"))
1032 .WillRepeatedly(Return("2"));
1033}
1034
1035TEST_F(ArtdTest, dexoptAllResourceControlBoot) {
1036 SetAllResourceControlProps(mock_props_);
1037
1038 EXPECT_CALL(
1039 *mock_exec_utils_,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001040 DoExecAndReturnCode(
1041 WhenSplitBy(
1042 "--", _, AllOf(Contains(Flag("--cpu-set=", "0,1,2,3")), Contains(Flag("-j", "8")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001043 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001044 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001045 .WillOnce(Return(0));
1046 priority_class_ = PriorityClass::BOOT;
1047 RunDexopt();
1048}
1049
1050TEST_F(ArtdTest, dexoptAllResourceControlInteractiveFast) {
1051 SetAllResourceControlProps(mock_props_);
1052
1053 EXPECT_CALL(
1054 *mock_exec_utils_,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001055 DoExecAndReturnCode(
1056 WhenSplitBy(
1057 "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2,3")), Contains(Flag("-j", "6")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001058 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001059 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001060 .WillOnce(Return(0));
1061 priority_class_ = PriorityClass::INTERACTIVE_FAST;
1062 RunDexopt();
1063}
1064
1065TEST_F(ArtdTest, dexoptAllResourceControlInteractive) {
1066 SetAllResourceControlProps(mock_props_);
1067
1068 // INTERACTIVE always uses the default resource control properties.
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001069 EXPECT_CALL(
1070 *mock_exec_utils_,
1071 DoExecAndReturnCode(
1072 WhenSplitBy(
1073 "--", _, AllOf(Contains(Flag("--cpu-set=", "0,2")), Contains(Flag("-j", "4")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001074 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001075 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001076 .WillOnce(Return(0));
1077 priority_class_ = PriorityClass::INTERACTIVE;
1078 RunDexopt();
1079}
1080
1081TEST_F(ArtdTest, dexoptAllResourceControlBackground) {
1082 SetAllResourceControlProps(mock_props_);
1083
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001084 EXPECT_CALL(
1085 *mock_exec_utils_,
1086 DoExecAndReturnCode(
1087 WhenSplitBy("--", _, AllOf(Contains(Flag("--cpu-set=", "0")), Contains(Flag("-j", "2")))),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001088 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001089 _))
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001090 .WillOnce(Return(0));
1091 priority_class_ = PriorityClass::BACKGROUND;
1092 RunDexopt();
1093}
1094
1095TEST_F(ArtdTest, dexoptFailed) {
1096 dexopt_options_.generateAppImage = true;
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001097 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001098 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1099 WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1100 WithArg<0>(WriteToFdFlag("--app-image-fd=", "new_art")),
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001101 Return(1)));
1102 RunDexopt(EX_SERVICE_SPECIFIC);
1103
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001104 CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1105 CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1106 CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
Jiakai Zhang3aaecf02022-08-10 15:35:28 +01001107}
1108
Jiakai Zhang843ce522022-11-11 14:00:39 +00001109TEST_F(ArtdTest, dexoptFailedToCommit) {
1110 std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_inaccessible;
1111 std::unique_ptr<ScopeGuard<std::function<void()>>> scoped_unroot;
1112
1113 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1114 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1115 WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1116 [&](auto, auto, auto) {
1117 scoped_inaccessible = std::make_unique<ScopeGuard<std::function<void()>>>(
1118 ScopedInaccessible(scratch_path_ + "/a/oat/arm64"));
1119 scoped_unroot =
1120 std::make_unique<ScopeGuard<std::function<void()>>>(ScopedUnroot());
1121 return 0;
1122 }));
1123
Jiakai Zhang771f64e2023-01-12 17:32:36 +08001124 RunDexopt(
1125 EX_SERVICE_SPECIFIC,
1126 AllOf(Field(&ArtdDexoptResult::sizeBytes, 0), Field(&ArtdDexoptResult::sizeBeforeBytes, 0)));
Jiakai Zhang843ce522022-11-11 14:00:39 +00001127}
1128
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001129TEST_F(ArtdTest, dexoptCancelledBeforeDex2oat) {
1130 std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1131 ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1132
1133 constexpr pid_t kPid = 123;
1134
1135 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1136 .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
1137 callbacks.on_start(kPid);
1138 callbacks.on_end(kPid);
1139 return Error();
1140 });
1141 EXPECT_CALL(mock_kill_, Call(kPid, SIGKILL));
1142
1143 cancellation_signal->cancel();
1144
Jiakai Zhang771f64e2023-01-12 17:32:36 +08001145 RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, true), cancellation_signal);
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001146
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001147 CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1148 CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1149 CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001150}
1151
1152TEST_F(ArtdTest, dexoptCancelledDuringDex2oat) {
1153 std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1154 ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1155
1156 constexpr pid_t kPid = 123;
1157 constexpr std::chrono::duration<int> kTimeout = std::chrono::seconds(1);
1158
1159 std::condition_variable process_started_cv, process_killed_cv;
1160 std::mutex mu;
1161
1162 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1163 .WillOnce([&](auto, const ExecCallbacks& callbacks, auto) {
1164 std::unique_lock<std::mutex> lock(mu);
1165 // Step 2.
1166 callbacks.on_start(kPid);
1167 process_started_cv.notify_one();
1168 EXPECT_EQ(process_killed_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
1169 // Step 5.
1170 callbacks.on_end(kPid);
1171 return Error();
1172 });
1173
1174 EXPECT_CALL(mock_kill_, Call(kPid, SIGKILL)).WillOnce([&](auto, auto) {
1175 // Step 4.
1176 process_killed_cv.notify_one();
1177 return 0;
1178 });
1179
1180 std::thread t;
1181 {
1182 std::unique_lock<std::mutex> lock(mu);
1183 // Step 1.
Jiakai Zhang771f64e2023-01-12 17:32:36 +08001184 t = std::thread([&] {
1185 RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, true), cancellation_signal);
1186 });
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001187 EXPECT_EQ(process_started_cv.wait_for(lock, kTimeout), std::cv_status::no_timeout);
1188 // Step 3.
1189 cancellation_signal->cancel();
1190 }
1191
1192 t.join();
1193
1194 // Step 6.
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001195 CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "old_oat");
1196 CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "old_vdex");
1197 CheckContent(scratch_path_ + "/a/oat/arm64/b.art", "old_art");
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001198}
1199
1200TEST_F(ArtdTest, dexoptCancelledAfterDex2oat) {
1201 std::shared_ptr<IArtdCancellationSignal> cancellation_signal;
1202 ASSERT_TRUE(artd_->createCancellationSignal(&cancellation_signal).isOk());
1203
1204 constexpr pid_t kPid = 123;
1205
1206 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001207 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "new_oat")),
1208 WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "new_vdex")),
1209 [&](auto, const ExecCallbacks& callbacks, auto) {
1210 callbacks.on_start(kPid);
1211 callbacks.on_end(kPid);
1212 return 0;
1213 }));
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001214 EXPECT_CALL(mock_kill_, Call).Times(0);
1215
Jiakai Zhang771f64e2023-01-12 17:32:36 +08001216 RunDexopt(EX_NONE, Field(&ArtdDexoptResult::cancelled, false), cancellation_signal);
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001217
1218 // This signal should be ignored.
1219 cancellation_signal->cancel();
1220
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001221 CheckContent(scratch_path_ + "/a/oat/arm64/b.odex", "new_oat");
1222 CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex", "new_vdex");
1223 EXPECT_FALSE(std::filesystem::exists(scratch_path_ + "/a/oat/arm64/b.art"));
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001224}
1225
Jiakai Zhanga4692662022-11-23 14:10:03 +00001226TEST_F(ArtdTest, dexoptDexFileNotOtherReadable) {
1227 dex_file_other_readable_ = false;
1228 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1229 RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1230 Property(&ndk::ScopedAStatus::getMessage,
1231 HasSubstr("Outputs cannot be other-readable because the dex file"))));
1232}
1233
1234TEST_F(ArtdTest, dexoptProfileNotOtherReadable) {
1235 profile_other_readable_ = false;
1236 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1237 RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1238 Property(&ndk::ScopedAStatus::getMessage,
1239 HasSubstr("Outputs cannot be other-readable because the profile"))));
1240}
1241
1242TEST_F(ArtdTest, dexoptOutputNotOtherReadable) {
1243 output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1244 dex_file_other_readable_ = false;
1245 profile_other_readable_ = false;
1246 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(0));
1247 RunDexopt();
1248 CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.odex", false);
1249 CheckOtherReadable(scratch_path_ + "/a/oat/arm64/b.vdex", false);
1250}
1251
1252TEST_F(ArtdTest, dexoptUidMismatch) {
1253 output_artifacts_.permissionSettings.fileFsPermission.uid = 12345;
1254 output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1255 dex_file_other_readable_ = false;
1256 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1257 RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1258 Property(&ndk::ScopedAStatus::getMessage,
1259 HasSubstr("Outputs' owner doesn't match the dex file"))));
1260}
1261
1262TEST_F(ArtdTest, dexoptGidMismatch) {
1263 output_artifacts_.permissionSettings.fileFsPermission.gid = 12345;
1264 output_artifacts_.permissionSettings.fileFsPermission.isOtherReadable = false;
1265 dex_file_other_readable_ = false;
1266 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).Times(0);
1267 RunDexopt(AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1268 Property(&ndk::ScopedAStatus::getMessage,
1269 HasSubstr("Outputs' owner doesn't match the dex file"))));
1270}
1271
1272TEST_F(ArtdTest, dexoptGidMatchesUid) {
1273 output_artifacts_.permissionSettings.fileFsPermission = {
1274 .uid = 123, .gid = 123, .isOtherReadable = false};
1275 EXPECT_CALL(mock_fstat_, Call(_, _)).WillRepeatedly(fstat); // For profile.
1276 EXPECT_CALL(mock_fstat_, Call(FdOf(dex_file_), _))
1277 .WillOnce(DoAll(SetArgPointee<1>((struct stat){
1278 .st_mode = S_IRUSR | S_IRGRP, .st_uid = 123, .st_gid = 456}),
1279 Return(0)));
1280 ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1281 // It's okay to fail on chown. This happens when the test is not run as root.
1282 RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1283 AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1284 Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1285}
1286
1287TEST_F(ArtdTest, dexoptGidMatchesGid) {
1288 output_artifacts_.permissionSettings.fileFsPermission = {
1289 .uid = 123, .gid = 456, .isOtherReadable = false};
1290 EXPECT_CALL(mock_fstat_, Call(_, _)).WillRepeatedly(fstat); // For profile.
1291 EXPECT_CALL(mock_fstat_, Call(FdOf(dex_file_), _))
1292 .WillOnce(DoAll(SetArgPointee<1>((struct stat){
1293 .st_mode = S_IRUSR | S_IRGRP, .st_uid = 123, .st_gid = 456}),
1294 Return(0)));
1295 ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1296 // It's okay to fail on chown. This happens when the test is not run as root.
1297 RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1298 AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1299 Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1300}
1301
1302TEST_F(ArtdTest, dexoptUidGidChangeOk) {
1303 // The dex file is other-readable, so we don't check uid and gid.
1304 output_artifacts_.permissionSettings.fileFsPermission = {
1305 .uid = 12345, .gid = 12345, .isOtherReadable = false};
1306 ON_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillByDefault(Return(0));
1307 // It's okay to fail on chown. This happens when the test is not run as root.
1308 RunDexopt(AnyOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_NONE),
1309 AllOf(Property(&ndk::ScopedAStatus::getExceptionCode, EX_SERVICE_SPECIFIC),
1310 Property(&ndk::ScopedAStatus::getMessage, HasSubstr("Failed to chown")))));
1311}
1312
1313TEST_F(ArtdTest, dexoptNoUidGidChange) {
1314 output_artifacts_.permissionSettings.fileFsPermission = {
1315 .uid = -1, .gid = -1, .isOtherReadable = false};
1316 dex_file_other_readable_ = false;
1317 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(0));
1318 RunDexopt();
1319}
1320
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001321TEST_F(ArtdTest, isProfileUsable) {
1322 std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1323 CreateFile(profile_file);
1324 CreateFile(dex_file_);
1325
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001326 EXPECT_CALL(
1327 *mock_exec_utils_,
1328 DoExecAndReturnCode(
Jiakai Zhang7b6aef72022-12-12 19:30:44 +00001329 AllOf(WhenSplitBy(
1330 "--",
1331 AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1332 AllOf(Contains(art_root_ + "/bin/profman"),
1333 Contains(Flag("--reference-profile-file-fd=", FdOf(profile_file))),
1334 Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1335 HasKeepFdsFor("--reference-profile-file-fd=", "--apk-fd=")),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001336 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001337 _))
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001338 .WillOnce(Return(ProfmanResult::kSkipCompilationSmallDelta));
1339
1340 bool result;
1341 EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1342 EXPECT_TRUE(result);
1343}
1344
1345TEST_F(ArtdTest, isProfileUsableFalse) {
1346 std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1347 CreateFile(profile_file);
1348 CreateFile(dex_file_);
1349
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001350 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001351 .WillOnce(Return(ProfmanResult::kSkipCompilationEmptyProfiles));
1352
1353 bool result;
1354 EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1355 EXPECT_FALSE(result);
1356}
1357
1358TEST_F(ArtdTest, isProfileUsableNotFound) {
1359 CreateFile(dex_file_);
1360
1361 bool result;
1362 EXPECT_TRUE(artd_->isProfileUsable(profile_path_.value(), dex_file_, &result).isOk());
1363 EXPECT_FALSE(result);
1364}
1365
1366TEST_F(ArtdTest, isProfileUsableFailed) {
1367 std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1368 CreateFile(profile_file);
1369 CreateFile(dex_file_);
1370
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001371 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(100));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001372
1373 bool result;
1374 ndk::ScopedAStatus status = artd_->isProfileUsable(profile_path_.value(), dex_file_, &result);
1375
1376 EXPECT_FALSE(status.isOk());
1377 EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1378 EXPECT_THAT(status.getMessage(), HasSubstr("profman returned an unexpected code: 100"));
1379}
1380
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001381TEST_F(ArtdTest, copyAndRewriteProfileSuccess) {
1382 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1383 CreateFile(src_file, "valid_profile");
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001384
1385 CreateFile(dex_file_);
1386
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001387 EXPECT_CALL(
1388 *mock_exec_utils_,
1389 DoExecAndReturnCode(
Jiakai Zhang7b6aef72022-12-12 19:30:44 +00001390 AllOf(WhenSplitBy(
1391 "--",
1392 AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1393 AllOf(Contains(art_root_ + "/bin/profman"),
1394 Contains("--copy-and-update-profile-key"),
1395 Contains(Flag("--profile-file-fd=", FdOf(src_file))),
1396 Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1397 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001398 _,
Jiakai Zhang7a82e5a2022-09-06 21:14:35 +01001399 _))
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001400 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
1401 Return(ProfmanResult::kCopyAndUpdateSuccess)));
1402
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001403 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1404
1405 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001406 EXPECT_THAT(dst.profilePath.id, Not(IsEmpty()));
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001407 std::string real_path = OR_FATAL(BuildTmpProfilePath(dst.profilePath));
1408 EXPECT_EQ(dst.profilePath.tmpPath, real_path);
1409 CheckContent(real_path, "def");
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001410}
1411
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001412// The input is a plain profile file in the wrong format.
1413TEST_F(ArtdTest, copyAndRewriteProfileBadProfileWrongFormat) {
1414 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1415 CreateFile(src_file, "wrong_format");
1416
1417 CreateFile(dex_file_);
1418
1419 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1420 .WillOnce(Return(ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile));
1421
1422 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1423
1424 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1425 EXPECT_THAT(result.errorMsg,
1426 HasSubstr("The profile is in the wrong format or an I/O error has occurred"));
1427 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1428 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1429}
1430
1431// The input is a plain profile file that doesn't match the APK.
1432TEST_F(ArtdTest, copyAndRewriteProfileBadProfileNoMatch) {
1433 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1434 CreateFile(src_file, "no_match");
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001435
1436 CreateFile(dex_file_);
1437
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001438 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
Jiakai Zhang7c3153e2022-09-26 11:01:43 +01001439 .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001440
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001441 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1442
1443 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1444 EXPECT_THAT(result.errorMsg, HasSubstr("The profile does not match the APK"));
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001445 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1446 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001447}
1448
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001449// The input is a plain profile file that is empty.
1450TEST_F(ArtdTest, copyAndRewriteProfileNoProfileEmpty) {
1451 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1452 CreateFile(src_file, "");
1453
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001454 CreateFile(dex_file_);
1455
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001456 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1457 .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001458
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001459 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1460
1461 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001462 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1463 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001464}
1465
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001466// The input does not exist.
1467TEST_F(ArtdTest, copyAndRewriteProfileNoProfileNoFile) {
1468 CreateFile(dex_file_);
1469
1470 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1471
1472 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1473 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1474 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1475}
1476
1477// The input is a dm file with a profile entry in the wrong format.
1478TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmWrongFormat) {
1479 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1480 CreateZipWithSingleEntry(src_file, "primary.prof", "wrong_format");
1481
1482 CreateFile(dex_file_);
1483
1484 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1485 .WillOnce(Return(ProfmanResult::kCopyAndUpdateErrorFailedToLoadProfile));
1486
1487 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1488
1489 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1490 EXPECT_THAT(result.errorMsg,
1491 HasSubstr("The profile is in the wrong format or an I/O error has occurred"));
1492 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1493 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1494}
1495
1496// The input is a dm file with a profile entry that doesn't match the APK.
1497TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoMatch) {
1498 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1499 CreateZipWithSingleEntry(src_file, "primary.prof", "no_match");
1500
1501 CreateFile(dex_file_);
1502
1503 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1504 .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1505
1506 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1507
1508 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1509 EXPECT_THAT(result.errorMsg, HasSubstr("The profile does not match the APK"));
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 is empty.
1515TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmEmpty) {
1516 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1517 CreateZipWithSingleEntry(src_file, "primary.prof");
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::NO_PROFILE);
1527 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1528 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1529}
1530
1531// The input is a dm file without a profile entry.
1532TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoEntry) {
1533 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1534 CreateZipWithSingleEntry(src_file, "primary.vdex");
1535
1536 CreateFile(dex_file_);
1537
1538 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1539 .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1540
1541 auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
1542
1543 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1544 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1545 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1546}
1547
1548TEST_F(ArtdTest, copyAndRewriteProfileException) {
1549 std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
1550 CreateFile(src_file, "valid_profile");
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001551
1552 CreateFile(dex_file_);
1553
Jiakai Zhangfaf37cd2022-09-09 11:59:28 +01001554 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _)).WillOnce(Return(100));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001555
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001556 auto [status, dst] = OR_FAIL(RunCopyAndRewriteProfile</*kExpectOk=*/false>());
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001557
1558 EXPECT_FALSE(status.isOk());
1559 EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1560 EXPECT_THAT(status.getMessage(), HasSubstr("profman returned an unexpected code: 100"));
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001561 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1562 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001563}
1564
Jiakai Zhang543be882023-09-28 20:11:19 +01001565TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileSuccess) {
1566 CreateZipWithSingleEntry(dex_file_, "assets/art-profile/baseline.prof", "valid_profile");
1567
1568 EXPECT_CALL(
1569 *mock_exec_utils_,
1570 DoExecAndReturnCode(
1571 AllOf(WhenSplitBy(
1572 "--",
1573 AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1574 AllOf(Contains(art_root_ + "/bin/profman"),
1575 Contains("--copy-and-update-profile-key"),
1576 Contains(Flag("--profile-file-fd=", FdHasContent("valid_profile"))),
1577 Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1578 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
1579 _,
1580 _))
1581 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
1582 Return(ProfmanResult::kCopyAndUpdateSuccess)));
1583
1584 auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1585
1586 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
1587 EXPECT_THAT(dst.profilePath.id, Not(IsEmpty()));
1588 std::string real_path = OR_FATAL(BuildTmpProfilePath(dst.profilePath));
1589 EXPECT_EQ(dst.profilePath.tmpPath, real_path);
1590 CheckContent(real_path, "def");
1591}
1592
1593// The input is a plain dex file.
1594TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileNoProfilePlainDex) {
1595 constexpr const char* kDexMagic = "dex\n";
1596 CreateFile(dex_file_, kDexMagic + "dex_code"s);
1597
1598 auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1599
1600 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1601 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1602 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1603}
1604
1605// The input is neither a zip nor a plain dex file.
1606TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileNotZipNotDex) {
1607 CreateFile(dex_file_, "wrong_format");
1608
1609 auto [status, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile</*kExpectOk=*/false>());
1610
1611 EXPECT_FALSE(status.isOk());
1612 EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1613 EXPECT_THAT(status.getMessage(), HasSubstr("File is neither a zip file nor a plain dex file"));
1614 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1615 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1616}
1617
1618// The input is a zip file without a profile entry.
1619TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileNoProfileZipNoEntry) {
1620 CreateZipWithSingleEntry(dex_file_, "classes.dex", "dex_code");
1621
1622 auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1623
1624 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::NO_PROFILE);
1625 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1626 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1627}
1628
1629// The input is a zip file with a profile entry that doesn't match itself.
1630TEST_F(ArtdTest, copyAndRewriteEmbeddedProfileBadProfileNoMatch) {
1631 CreateZipWithSingleEntry(dex_file_, "assets/art-profile/baseline.prof", "no_match");
1632
1633 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_, _, _))
1634 .WillOnce(Return(ProfmanResult::kCopyAndUpdateNoMatch));
1635
1636 auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
1637
1638 EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::BAD_PROFILE);
1639 EXPECT_THAT(result.errorMsg, HasSubstr("The profile does not match the APK"));
1640 EXPECT_THAT(dst.profilePath.id, IsEmpty());
1641 EXPECT_THAT(dst.profilePath.tmpPath, IsEmpty());
1642}
1643
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001644TEST_F(ArtdTest, commitTmpProfile) {
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001645 std::string tmp_profile_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001646 CreateFile(tmp_profile_file);
1647
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001648 EXPECT_TRUE(artd_->commitTmpProfile(tmp_profile_path_).isOk());
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001649
1650 EXPECT_FALSE(std::filesystem::exists(tmp_profile_file));
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001651 EXPECT_TRUE(std::filesystem::exists(OR_FATAL(BuildFinalProfilePath(tmp_profile_path_))));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001652}
1653
1654TEST_F(ArtdTest, commitTmpProfileFailed) {
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001655 ndk::ScopedAStatus status = artd_->commitTmpProfile(tmp_profile_path_);
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001656
1657 EXPECT_FALSE(status.isOk());
1658 EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1659 EXPECT_THAT(
1660 status.getMessage(),
1661 ContainsRegex(R"re(Failed to move .*primary\.prof\.12345\.tmp.* to .*primary\.prof)re"));
1662
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001663 EXPECT_FALSE(std::filesystem::exists(OR_FATAL(BuildFinalProfilePath(tmp_profile_path_))));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001664}
1665
1666TEST_F(ArtdTest, deleteProfile) {
1667 std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1668 CreateFile(profile_file);
1669
1670 EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1671
1672 EXPECT_FALSE(std::filesystem::exists(profile_file));
1673}
1674
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001675TEST_F(ArtdTest, deleteProfileDoesNotExist) {
Jiakai Zhang9b2bddc2023-02-16 17:10:54 +00001676 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
1677 EXPECT_CALL(mock_logger_, Call).Times(0);
1678
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001679 EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1680}
1681
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001682TEST_F(ArtdTest, deleteProfileFailed) {
1683 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
1684 EXPECT_CALL(
1685 mock_logger_,
1686 Call(_, _, _, _, _, ContainsRegex(R"re(Failed to remove .*primary\.prof\.12345\.tmp)re")));
1687
Jiakai Zhang9b2bddc2023-02-16 17:10:54 +00001688 std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
1689 auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(profile_file).parent_path());
1690 auto scoped_unroot = ScopedUnroot();
1691
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001692 EXPECT_TRUE(artd_->deleteProfile(profile_path_.value()).isOk());
1693}
1694
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001695class ArtdGetVisibilityTest : public ArtdTest {
1696 protected:
1697 template <typename PathType>
1698 using Method = ndk::ScopedAStatus (Artd::*)(const PathType&, FileVisibility*);
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001699
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001700 template <typename PathType>
1701 void TestGetVisibilityOtherReadable(Method<PathType> method,
1702 const PathType& input,
1703 const std::string& path) {
1704 CreateFile(path);
1705 std::filesystem::permissions(
1706 path, std::filesystem::perms::others_read, std::filesystem::perm_options::add);
1707
1708 FileVisibility result;
1709 ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1710 EXPECT_EQ(result, FileVisibility::OTHER_READABLE);
1711 }
1712
1713 template <typename PathType>
1714 void TestGetVisibilityNotOtherReadable(Method<PathType> method,
1715 const PathType& input,
1716 const std::string& path) {
1717 CreateFile(path);
1718 std::filesystem::permissions(
1719 path, std::filesystem::perms::others_read, std::filesystem::perm_options::remove);
1720
1721 FileVisibility result;
1722 ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1723 EXPECT_EQ(result, FileVisibility::NOT_OTHER_READABLE);
1724 }
1725
1726 template <typename PathType>
1727 void TestGetVisibilityNotFound(Method<PathType> method, const PathType& input) {
1728 FileVisibility result;
1729 ASSERT_TRUE(((*artd_).*method)(input, &result).isOk());
1730 EXPECT_EQ(result, FileVisibility::NOT_FOUND);
1731 }
1732
1733 template <typename PathType>
1734 void TestGetVisibilityPermissionDenied(Method<PathType> method,
1735 const PathType& input,
1736 const std::string& path) {
1737 CreateFile(path);
1738
1739 auto scoped_inaccessible = ScopedInaccessible(std::filesystem::path(path).parent_path());
1740 auto scoped_unroot = ScopedUnroot();
1741
1742 FileVisibility result;
1743 ndk::ScopedAStatus status = ((*artd_).*method)(input, &result);
1744 EXPECT_FALSE(status.isOk());
1745 EXPECT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
1746 EXPECT_THAT(status.getMessage(), HasSubstr("Failed to get status of"));
1747 }
1748};
1749
1750TEST_F(ArtdGetVisibilityTest, getProfileVisibilityOtherReadable) {
1751 TestGetVisibilityOtherReadable(&Artd::getProfileVisibility,
1752 profile_path_.value(),
1753 OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001754}
1755
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001756TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotOtherReadable) {
1757 TestGetVisibilityNotOtherReadable(&Artd::getProfileVisibility,
1758 profile_path_.value(),
1759 OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001760}
1761
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001762TEST_F(ArtdGetVisibilityTest, getProfileVisibilityNotFound) {
1763 TestGetVisibilityNotFound(&Artd::getProfileVisibility, profile_path_.value());
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001764}
1765
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001766TEST_F(ArtdGetVisibilityTest, getProfileVisibilityPermissionDenied) {
1767 TestGetVisibilityPermissionDenied(&Artd::getProfileVisibility,
1768 profile_path_.value(),
1769 OR_FATAL(BuildProfileOrDmPath(profile_path_.value())));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001770}
1771
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001772TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityOtherReadable) {
1773 TestGetVisibilityOtherReadable(
1774 &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001775}
1776
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001777TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotOtherReadable) {
1778 TestGetVisibilityNotOtherReadable(
1779 &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001780}
1781
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001782TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotFound) {
1783 TestGetVisibilityNotFound(&Artd::getArtifactsVisibility, artifacts_path_);
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001784}
1785
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001786TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityPermissionDenied) {
1787 TestGetVisibilityPermissionDenied(
1788 &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
Jiakai Zhang8ef6b6c2022-08-10 17:28:41 +01001789}
1790
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001791TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityOtherReadable) {
1792 TestGetVisibilityOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_);
Jiakai Zhang12f45c42022-10-27 15:23:03 +01001793}
1794
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001795TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotOtherReadable) {
1796 TestGetVisibilityNotOtherReadable(&Artd::getDexFileVisibility, dex_file_, dex_file_);
Jiakai Zhang12f45c42022-10-27 15:23:03 +01001797}
1798
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001799TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityNotFound) {
1800 TestGetVisibilityNotFound(&Artd::getDexFileVisibility, dex_file_);
Jiakai Zhang12f45c42022-10-27 15:23:03 +01001801}
1802
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001803TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityPermissionDenied) {
1804 TestGetVisibilityPermissionDenied(&Artd::getDexFileVisibility, dex_file_, dex_file_);
1805}
Jiakai Zhang12f45c42022-10-27 15:23:03 +01001806
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001807TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityOtherReadable) {
1808 TestGetVisibilityOtherReadable(&Artd::getDmFileVisibility,
1809 dm_path_.value(),
1810 OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1811}
Jiakai Zhang12f45c42022-10-27 15:23:03 +01001812
Jiakai Zhangbfd155d2022-11-08 13:17:50 +00001813TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotOtherReadable) {
1814 TestGetVisibilityNotOtherReadable(&Artd::getDmFileVisibility,
1815 dm_path_.value(),
1816 OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
1817}
1818
1819TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityNotFound) {
1820 TestGetVisibilityNotFound(&Artd::getDmFileVisibility, dm_path_.value());
1821}
1822
1823TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityPermissionDenied) {
1824 TestGetVisibilityPermissionDenied(&Artd::getDmFileVisibility,
1825 dm_path_.value(),
1826 OR_FATAL(BuildDexMetadataPath(dm_path_.value())));
Jiakai Zhang12f45c42022-10-27 15:23:03 +01001827}
1828
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001829TEST_F(ArtdTest, mergeProfiles) {
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001830 const TmpProfilePath& reference_profile_path = tmp_profile_path_;
Jiakai Zhangca327972022-10-18 10:59:10 +01001831 std::string reference_profile_file = OR_FATAL(BuildTmpProfilePath(reference_profile_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001832 CreateFile(reference_profile_file, "abc");
1833
1834 // Doesn't exist.
Jiakai Zhangca327972022-10-18 10:59:10 +01001835 PrimaryCurProfilePath profile_0_path{
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001836 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
Jiakai Zhangca327972022-10-18 10:59:10 +01001837 std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001838
Jiakai Zhangca327972022-10-18 10:59:10 +01001839 PrimaryCurProfilePath profile_1_path{
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001840 .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
Jiakai Zhangca327972022-10-18 10:59:10 +01001841 std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001842 CreateFile(profile_1_file, "def");
1843
1844 OutputProfile output_profile{.profilePath = reference_profile_path,
1845 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1846 output_profile.profilePath.id = "";
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001847 output_profile.profilePath.tmpPath = "";
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001848
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001849 std::string dex_file_1 = scratch_path_ + "/a/b.apk";
1850 std::string dex_file_2 = scratch_path_ + "/a/c.apk";
1851 CreateFile(dex_file_1);
1852 CreateFile(dex_file_2);
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001853
1854 EXPECT_CALL(
1855 *mock_exec_utils_,
1856 DoExecAndReturnCode(
Jiakai Zhang7b6aef72022-12-12 19:30:44 +00001857 AllOf(WhenSplitBy(
1858 "--",
1859 AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1860 AllOf(Contains(art_root_ + "/bin/profman"),
1861 Not(Contains(Flag("--profile-file-fd=", FdOf(profile_0_file)))),
1862 Contains(Flag("--profile-file-fd=", FdOf(profile_1_file))),
1863 Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
1864 Contains(Flag("--apk-fd=", FdOf(dex_file_1))),
1865 Contains(Flag("--apk-fd=", FdOf(dex_file_2))),
Jiakai Zhang610a5832023-11-28 16:55:47 +00001866 Not(Contains("--force-merge-and-analyze")),
Jiakai Zhang7b6aef72022-12-12 19:30:44 +00001867 Not(Contains("--boot-image-merge")))),
1868 HasKeepFdsFor("--profile-file-fd=", "--reference-profile-file-fd=", "--apk-fd=")),
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001869 _,
1870 _))
1871 .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
1872 Return(ProfmanResult::kCompile)));
1873
1874 bool result;
1875 EXPECT_TRUE(artd_
1876 ->mergeProfiles({profile_0_path, profile_1_path},
1877 reference_profile_path,
1878 &output_profile,
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001879 {dex_file_1, dex_file_2},
1880 /*in_options=*/{},
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001881 &result)
1882 .isOk());
1883 EXPECT_TRUE(result);
1884 EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001885 std::string real_path = OR_FATAL(BuildTmpProfilePath(output_profile.profilePath));
1886 EXPECT_EQ(output_profile.profilePath.tmpPath, real_path);
1887 CheckContent(real_path, "merged");
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001888}
1889
1890TEST_F(ArtdTest, mergeProfilesEmptyReferenceProfile) {
Jiakai Zhangca327972022-10-18 10:59:10 +01001891 PrimaryCurProfilePath profile_0_path{
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001892 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
Jiakai Zhangca327972022-10-18 10:59:10 +01001893 std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001894 CreateFile(profile_0_file, "def");
1895
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001896 OutputProfile output_profile{.profilePath = tmp_profile_path_,
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001897 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1898 output_profile.profilePath.id = "";
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001899 output_profile.profilePath.tmpPath = "";
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001900
1901 CreateFile(dex_file_);
1902
1903 EXPECT_CALL(
1904 *mock_exec_utils_,
1905 DoExecAndReturnCode(
1906 WhenSplitBy("--",
1907 AllOf(Contains(art_root_ + "/bin/art_exec"), Contains("--drop-capabilities")),
1908 AllOf(Contains(art_root_ + "/bin/profman"),
1909 Contains(Flag("--profile-file-fd=", FdOf(profile_0_file))),
1910 Contains(Flag("--reference-profile-file-fd=", FdHasContent(""))),
1911 Contains(Flag("--apk-fd=", FdOf(dex_file_))))),
1912 _,
1913 _))
1914 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "merged")),
1915 Return(ProfmanResult::kCompile)));
1916
1917 bool result;
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001918 EXPECT_TRUE(artd_
1919 ->mergeProfiles({profile_0_path},
1920 std::nullopt,
1921 &output_profile,
1922 {dex_file_},
1923 /*in_options=*/{},
1924 &result)
1925 .isOk());
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001926 EXPECT_TRUE(result);
1927 EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001928 EXPECT_THAT(output_profile.profilePath.tmpPath, Not(IsEmpty()));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001929}
1930
1931TEST_F(ArtdTest, mergeProfilesProfilesDontExist) {
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001932 const TmpProfilePath& reference_profile_path = tmp_profile_path_;
Jiakai Zhangca327972022-10-18 10:59:10 +01001933 std::string reference_profile_file = OR_FATAL(BuildTmpProfilePath(reference_profile_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001934 CreateFile(reference_profile_file, "abc");
1935
1936 // Doesn't exist.
Jiakai Zhangca327972022-10-18 10:59:10 +01001937 PrimaryCurProfilePath profile_0_path{
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001938 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
Jiakai Zhangca327972022-10-18 10:59:10 +01001939 std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001940
1941 // Doesn't exist.
Jiakai Zhangca327972022-10-18 10:59:10 +01001942 PrimaryCurProfilePath profile_1_path{
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001943 .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
Jiakai Zhangca327972022-10-18 10:59:10 +01001944 std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001945
1946 OutputProfile output_profile{.profilePath = reference_profile_path,
1947 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1948 output_profile.profilePath.id = "";
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001949 output_profile.profilePath.tmpPath = "";
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001950
1951 CreateFile(dex_file_);
1952
1953 EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode).Times(0);
1954
1955 bool result;
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001956 EXPECT_TRUE(artd_
1957 ->mergeProfiles({profile_0_path},
1958 std::nullopt,
1959 &output_profile,
1960 {dex_file_},
1961 /*in_options=*/{},
1962 &result)
1963 .isOk());
Jiakai Zhangab3f4192022-09-23 13:14:18 +01001964 EXPECT_FALSE(result);
1965 EXPECT_THAT(output_profile.profilePath.id, IsEmpty());
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001966 EXPECT_THAT(output_profile.profilePath.tmpPath, IsEmpty());
1967}
1968
Jiakai Zhangd46824b2022-12-06 10:35:29 +00001969TEST_F(ArtdTest, mergeProfilesWithOptionsForceMerge) {
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001970 PrimaryCurProfilePath profile_0_path{
1971 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
1972 std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
1973 CreateFile(profile_0_file, "def");
1974
Jiakai Zhang851b3f82023-09-06 18:40:05 +01001975 OutputProfile output_profile{.profilePath = tmp_profile_path_,
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001976 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
1977 output_profile.profilePath.id = "";
1978 output_profile.profilePath.tmpPath = "";
1979
1980 CreateFile(dex_file_);
1981
Jiakai Zhang610a5832023-11-28 16:55:47 +00001982 EXPECT_CALL(*mock_exec_utils_,
1983 DoExecAndReturnCode(WhenSplitBy("--",
1984 _,
1985 AllOf(Contains("--force-merge-and-analyze"),
1986 Contains("--boot-image-merge"))),
1987 _,
1988 _))
1989 .WillOnce(Return(ProfmanResult::kCompile));
Jiakai Zhangb1d3db62022-11-11 14:00:44 +00001990
1991 bool result;
1992 EXPECT_TRUE(artd_
1993 ->mergeProfiles({profile_0_path},
1994 std::nullopt,
1995 &output_profile,
1996 {dex_file_},
1997 {.forceMerge = true, .forBootImage = true},
1998 &result)
1999 .isOk());
2000 EXPECT_TRUE(result);
2001 EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2002 EXPECT_THAT(output_profile.profilePath.tmpPath, Not(IsEmpty()));
Jiakai Zhangab3f4192022-09-23 13:14:18 +01002003}
2004
Jiakai Zhangd46824b2022-12-06 10:35:29 +00002005TEST_F(ArtdTest, mergeProfilesWithOptionsDumpOnly) {
2006 PrimaryCurProfilePath profile_0_path{
2007 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2008 std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2009 CreateFile(profile_0_file, "def");
2010
Jiakai Zhang851b3f82023-09-06 18:40:05 +01002011 OutputProfile output_profile{.profilePath = tmp_profile_path_,
Jiakai Zhangd46824b2022-12-06 10:35:29 +00002012 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2013 output_profile.profilePath.id = "";
2014 output_profile.profilePath.tmpPath = "";
2015
2016 CreateFile(dex_file_);
2017
2018 EXPECT_CALL(*mock_exec_utils_,
2019 DoExecAndReturnCode(
Jiakai Zhang7b6aef72022-12-12 19:30:44 +00002020 AllOf(WhenSplitBy("--",
2021 _,
2022 AllOf(Contains("--dump-only"),
2023 Not(Contains(Flag("--reference-profile-file-fd=", _))))),
2024 HasKeepFdsFor("--profile-file-fd=", "--apk-fd=", "--dump-output-to-fd=")),
Jiakai Zhangd46824b2022-12-06 10:35:29 +00002025 _,
2026 _))
2027 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--dump-output-to-fd=", "dump")),
2028 Return(ProfmanResult::kSuccess)));
2029
2030 bool result;
2031 EXPECT_TRUE(artd_
2032 ->mergeProfiles({profile_0_path},
2033 std::nullopt,
2034 &output_profile,
2035 {dex_file_},
2036 {.dumpOnly = true},
2037 &result)
2038 .isOk());
2039 EXPECT_TRUE(result);
2040 EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2041 CheckContent(output_profile.profilePath.tmpPath, "dump");
2042}
2043
2044TEST_F(ArtdTest, mergeProfilesWithOptionsDumpClassesAndMethods) {
2045 PrimaryCurProfilePath profile_0_path{
2046 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
2047 std::string profile_0_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_0_path));
2048 CreateFile(profile_0_file, "def");
2049
Jiakai Zhang851b3f82023-09-06 18:40:05 +01002050 OutputProfile output_profile{.profilePath = tmp_profile_path_,
Jiakai Zhangd46824b2022-12-06 10:35:29 +00002051 .fsPermission = FsPermission{.uid = -1, .gid = -1}};
2052 output_profile.profilePath.id = "";
2053 output_profile.profilePath.tmpPath = "";
2054
2055 CreateFile(dex_file_);
2056
2057 EXPECT_CALL(*mock_exec_utils_,
2058 DoExecAndReturnCode(
2059 WhenSplitBy("--",
2060 _,
2061 AllOf(Contains("--dump-classes-and-methods"),
2062 Not(Contains(Flag("--reference-profile-file-fd=", _))))),
2063 _,
2064 _))
2065 .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--dump-output-to-fd=", "dump")),
2066 Return(ProfmanResult::kSuccess)));
2067
2068 bool result;
2069 EXPECT_TRUE(artd_
2070 ->mergeProfiles({profile_0_path},
2071 std::nullopt,
2072 &output_profile,
2073 {dex_file_},
2074 {.dumpClassesAndMethods = true},
2075 &result)
2076 .isOk());
2077 EXPECT_TRUE(result);
2078 EXPECT_THAT(output_profile.profilePath.id, Not(IsEmpty()));
2079 CheckContent(output_profile.profilePath.tmpPath, "dump");
2080}
2081
Jiakai Zhang3041b6d2022-12-23 18:18:27 +00002082TEST_F(ArtdTest, cleanup) {
2083 std::vector<std::string> gc_removed_files;
2084 std::vector<std::string> gc_kept_files;
2085
2086 auto CreateGcRemovedFile = [&](const std::string& path) {
2087 CreateFile(path);
2088 gc_removed_files.push_back(path);
2089 };
2090
2091 auto CreateGcKeptFile = [&](const std::string& path) {
2092 CreateFile(path);
2093 gc_kept_files.push_back(path);
2094 };
2095
2096 // Unmanaged files.
2097 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/1.odex");
2098 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/1.odex");
2099 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/1.txt");
2100 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.txt");
2101 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.tmp");
2102
2103 // Files to keep.
2104 CreateGcKeptFile(android_data_ + "/misc/profiles/cur/1/com.android.foo/primary.prof");
2105 CreateGcKeptFile(android_data_ + "/misc/profiles/cur/3/com.android.foo/primary.prof");
2106 CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.dex");
2107 CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.vdex");
2108 CreateGcKeptFile(android_data_ + "/dalvik-cache/arm64/system@app@Foo@Foo.apk@classes.art");
2109 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.vdex");
2110 CreateGcKeptFile(
2111 android_expand_ +
2112 "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.odex");
2113 CreateGcKeptFile(
2114 android_expand_ +
2115 "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.vdex");
2116 CreateGcKeptFile(
2117 android_expand_ +
2118 "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/oat/arm64/base.art");
2119 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.odex");
2120 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.vdex");
2121 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/2.art");
Jiakai Zhangf1b8f882023-09-08 14:03:53 +01002122 CreateGcKeptFile(android_data_ + "/user_de/0/com.android.foo/cache/oat_primary/arm64/base.art");
2123 CreateGcKeptFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art");
2124 CreateGcKeptFile(android_data_ + "/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2125 CreateGcKeptFile(android_expand_ +
2126 "/123456-7890/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2127 CreateGcKeptFile(android_data_ +
2128 "/user/0/com.android.foo/cache/not_oat_dir/oat_primary/arm64/base.art");
Jiakai Zhang3041b6d2022-12-23 18:18:27 +00002129
2130 // Files to remove.
2131 CreateGcRemovedFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof");
2132 CreateGcRemovedFile(android_data_ + "/misc/profiles/cur/2/com.android.foo/primary.prof");
2133 CreateGcRemovedFile(android_data_ + "/misc/profiles/cur/3/com.android.bar/primary.prof");
2134 CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/extra.odex");
2135 CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.dex");
2136 CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.vdex");
2137 CreateGcRemovedFile(android_data_ + "/dalvik-cache/arm64/system@app@Bar@Bar.apk@classes.art");
2138 CreateGcRemovedFile(
2139 android_expand_ +
2140 "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.odex");
2141 CreateGcRemovedFile(
2142 android_expand_ +
2143 "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.vdex");
2144 CreateGcRemovedFile(
2145 android_expand_ +
2146 "/123456-7890/app/~~daewfweaf==/com.android.foo-fjuwidhia==/oat/arm64/base.art");
2147 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/1.prof");
2148 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/1.prof.123456.tmp");
2149 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.odex");
2150 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.vdex");
2151 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.art");
2152 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/1.odex.123456.tmp");
2153 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/oat/arm64/2.odex.123456.tmp");
2154 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.odex");
2155 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.art");
2156 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/oat/arm64/1.vdex.123456.tmp");
2157 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.odex");
2158 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.vdex");
2159 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.art");
2160 CreateGcRemovedFile(android_data_ +
2161 "/user_de/0/com.android.foo/aaa/bbb/oat/arm64/1.art.123456.tmp");
2162 CreateGcRemovedFile(android_data_ + "/user_de/0/com.android.bar/aaa/oat/arm64/1.vdex");
Jiakai Zhangf1b8f882023-09-08 14:03:53 +01002163 CreateGcRemovedFile(android_data_ +
2164 "/user/0/com.android.different_package/cache/oat_primary/arm64/base.art");
2165 CreateGcRemovedFile(android_data_ +
2166 "/user/0/com.android.foo/cache/oat_primary/arm64/different_dex.art");
2167 CreateGcRemovedFile(android_data_ +
2168 "/user/0/com.android.foo/cache/oat_primary/different_isa/base.art");
Jiakai Zhang3041b6d2022-12-23 18:18:27 +00002169
2170 int64_t aidl_return;
2171 ASSERT_TRUE(
2172 artd_
2173 ->cleanup(
2174 {
2175 PrimaryCurProfilePath{
2176 .userId = 1, .packageName = "com.android.foo", .profileName = "primary"},
2177 PrimaryCurProfilePath{
2178 .userId = 3, .packageName = "com.android.foo", .profileName = "primary"},
2179 },
2180 {
2181 ArtifactsPath{.dexPath = "/system/app/Foo/Foo.apk",
2182 .isa = "arm64",
2183 .isInDalvikCache = true},
2184 ArtifactsPath{
2185 .dexPath =
2186 android_expand_ +
2187 "/123456-7890/app/~~nkfeankfna==/com.android.bar-jfoeaofiew==/base.apk",
2188 .isa = "arm64",
2189 .isInDalvikCache = false},
2190 ArtifactsPath{.dexPath = android_data_ + "/user_de/0/com.android.foo/aaa/2.apk",
2191 .isa = "arm64",
2192 .isInDalvikCache = false},
2193 },
2194 {
2195 VdexPath{ArtifactsPath{
2196 .dexPath = android_data_ + "/user_de/0/com.android.foo/aaa/1.apk",
2197 .isa = "arm64",
2198 .isInDalvikCache = false}},
2199 },
Jiakai Zhangf1b8f882023-09-08 14:03:53 +01002200 {
2201 RuntimeArtifactsPath{
2202 .packageName = "com.android.foo", .isa = "arm64", .dexPath = "/a/b/base.apk"},
2203 },
Jiakai Zhang3041b6d2022-12-23 18:18:27 +00002204 &aidl_return)
2205 .isOk());
2206
2207 for (const std::string& path : gc_removed_files) {
Krzysztof KosiƄski997d3cf2023-04-30 01:22:28 +00002208 EXPECT_FALSE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be removed", path);
Jiakai Zhang3041b6d2022-12-23 18:18:27 +00002209 }
2210
2211 for (const std::string& path : gc_kept_files) {
Krzysztof KosiƄski997d3cf2023-04-30 01:22:28 +00002212 EXPECT_TRUE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be kept", path);
Jiakai Zhang3041b6d2022-12-23 18:18:27 +00002213 }
2214}
2215
Jiakai Zhangb30ed112023-06-28 13:44:56 +01002216TEST_F(ArtdTest, isInDalvikCache) {
2217 TEST_DISABLED_FOR_HOST();
2218
2219 if (GetProcMountsEntriesForPath("/")->empty()) {
2220 GTEST_SKIP() << "Skipped for chroot";
2221 }
2222
2223 auto is_in_dalvik_cache = [this](const std::string& dex_file) -> Result<bool> {
2224 bool result;
2225 ndk::ScopedAStatus status = artd_->isInDalvikCache(dex_file, &result);
2226 if (!status.isOk()) {
2227 return Error() << status.getMessage();
2228 }
2229 return result;
2230 };
2231
2232 EXPECT_THAT(is_in_dalvik_cache("/system/app/base.apk"), HasValue(true));
2233 EXPECT_THAT(is_in_dalvik_cache("/system_ext/app/base.apk"), HasValue(true));
2234 EXPECT_THAT(is_in_dalvik_cache("/vendor/app/base.apk"), HasValue(true));
2235 EXPECT_THAT(is_in_dalvik_cache("/product/app/base.apk"), HasValue(true));
2236 EXPECT_THAT(is_in_dalvik_cache("/data/app/base.apk"), HasValue(false));
2237
2238 // Test a path where we don't expect to find packages. The method should still work.
2239 EXPECT_THAT(is_in_dalvik_cache("/foo"), HasValue(true));
2240}
2241
Jiakai Zhang35650592023-09-07 19:05:10 +01002242TEST_F(ArtdTest, deleteRuntimeArtifacts) {
Jiakai Zhang35650592023-09-07 19:05:10 +01002243 std::vector<std::string> removed_files;
2244 std::vector<std::string> kept_files;
2245
2246 auto CreateRemovedFile = [&](const std::string& path) {
2247 CreateFile(path);
2248 removed_files.push_back(path);
2249 };
2250
2251 auto CreateKeptFile = [&](const std::string& path) {
2252 CreateFile(path);
2253 kept_files.push_back(path);
2254 };
2255
2256 CreateKeptFile(android_data_ +
2257 "/user/0/com.android.different_package/cache/oat_primary/arm64/base.art");
2258 CreateKeptFile(android_data_ +
2259 "/user/0/com.android.foo/cache/oat_primary/arm64/different_dex.art");
2260 CreateKeptFile(android_data_ +
2261 "/user/0/com.android.foo/cache/oat_primary/different_isa/base.art");
2262 CreateKeptFile(android_data_ +
2263 "/user/0/com.android.foo/cache/not_oat_dir/oat_primary/arm64/base.art");
2264
2265 CreateRemovedFile(android_data_ + "/user_de/0/com.android.foo/cache/oat_primary/arm64/base.art");
2266 CreateRemovedFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art");
2267 CreateRemovedFile(android_data_ + "/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2268 CreateRemovedFile(android_expand_ +
2269 "/123456-7890/user/1/com.android.foo/cache/oat_primary/arm64/base.art");
2270
2271 int64_t aidl_return;
2272 ASSERT_TRUE(
2273 artd_
2274 ->deleteRuntimeArtifacts(
2275 {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2276 &aidl_return)
2277 .isOk());
2278
2279 for (const std::string& path : removed_files) {
2280 EXPECT_FALSE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be removed", path);
2281 }
2282
2283 for (const std::string& path : kept_files) {
2284 EXPECT_TRUE(std::filesystem::exists(path)) << ART_FORMAT("'{}' should be kept", path);
2285 }
2286}
2287
Jiakai Zhang239f3b02024-01-05 17:25:17 +00002288TEST_F(ArtdTest, deleteRuntimeArtifactsAndroidDataNotExist) {
2289 // Will be cleaned up by `android_data_env_`
2290 setenv("ANDROID_DATA", "/non-existing", /*replace=*/1);
2291
2292 auto scoped_set_logger = ScopedSetLogger(mock_logger_.AsStdFunction());
2293 EXPECT_CALL(mock_logger_,
2294 Call(_, _, _, _, _, HasSubstr("Failed to find directory /non-existing")));
2295
2296 int64_t aidl_return;
2297 ASSERT_TRUE(
2298 artd_
2299 ->deleteRuntimeArtifacts(
2300 {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2301 &aidl_return)
2302 .isOk());
2303
2304 EXPECT_EQ(aidl_return, 0);
2305}
2306
Jiakai Zhang35650592023-09-07 19:05:10 +01002307TEST_F(ArtdTest, deleteRuntimeArtifactsSpecialChars) {
Jiakai Zhang35650592023-09-07 19:05:10 +01002308 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_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art");
2322
2323 CreateRemovedFile(android_data_ + "/user/0/*/cache/oat_primary/arm64/base.art");
2324 CreateRemovedFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/*/base.art");
2325 CreateRemovedFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/*.art");
2326
2327 int64_t aidl_return;
2328 ASSERT_TRUE(
2329 artd_
2330 ->deleteRuntimeArtifacts({.packageName = "*", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2331 &aidl_return)
2332 .isOk());
2333 ASSERT_TRUE(artd_
2334 ->deleteRuntimeArtifacts(
2335 {.packageName = "com.android.foo", .dexPath = "/a/b/*.apk", .isa = "arm64"},
2336 &aidl_return)
2337 .isOk());
2338 ASSERT_TRUE(artd_
2339 ->deleteRuntimeArtifacts(
2340 {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "*"},
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
Jiakai Zhang3208e7e2024-01-05 14:45:38 +00002353TEST_F(ArtdTest, getArtifactsSize) {
2354 std::string oat_dir = scratch_path_ + "/a/oat/arm64";
2355 CreateFile(oat_dir + "/b.odex", std::string(1, '*'));
2356 CreateFile(oat_dir + "/b.vdex", std::string(2, '*'));
2357 CreateFile(oat_dir + "/b.art", std::string(4, '*'));
2358
2359 // Irrelevant.
2360 CreateFile(oat_dir + "/c.vdex", std::string(8, '*'));
2361
2362 int64_t aidl_return = -1;
2363 ASSERT_TRUE(
2364 artd_
2365 ->getArtifactsSize(
2366 {.dexPath = scratch_path_ + "/a/b.apk", .isa = "arm64", .isInDalvikCache = false},
2367 &aidl_return)
2368 .isOk());
2369 EXPECT_EQ(aidl_return, 1 + 2 + 4);
2370}
2371
2372TEST_F(ArtdTest, getVdexFileSize) {
2373 std::string oat_dir = scratch_path_ + "/a/oat/arm64";
2374 CreateFile(oat_dir + "/b.vdex", std::string(1, '*'));
2375
2376 // Irrelevant.
2377 CreateFile(oat_dir + "/b.odex", std::string(2, '*'));
2378 CreateFile(oat_dir + "/b.art", std::string(4, '*'));
2379 CreateFile(oat_dir + "/c.vdex", std::string(8, '*'));
2380
2381 int64_t aidl_return = -1;
2382 ASSERT_TRUE(artd_
2383 ->getVdexFileSize(ArtifactsPath{.dexPath = scratch_path_ + "/a/b.apk",
2384 .isa = "arm64",
2385 .isInDalvikCache = false},
2386 &aidl_return)
2387 .isOk());
2388 EXPECT_EQ(aidl_return, 1);
2389}
2390
2391TEST_F(ArtdTest, getRuntimeArtifactsSize) {
2392 CreateFile(android_data_ + "/user_de/0/com.android.foo/cache/oat_primary/arm64/base.art",
2393 std::string(1, '*'));
2394 CreateFile(android_data_ + "/user/0/com.android.foo/cache/oat_primary/arm64/base.art",
2395 std::string(2, '*'));
2396 CreateFile(android_data_ + "/user/1/com.android.foo/cache/oat_primary/arm64/base.art",
2397 std::string(4, '*'));
2398 CreateFile(
2399 android_expand_ + "/123456-7890/user/1/com.android.foo/cache/oat_primary/arm64/base.art",
2400 std::string(8, '*'));
2401
2402 // Irrelevant.
2403 CreateFile(android_expand_ + "/user/0/com.android.foo/cache/oat_primary/arm64/different_dex.art",
2404 std::string(16, '*'));
2405
2406 int64_t aidl_return = -1;
2407 ASSERT_TRUE(
2408 artd_
2409 ->getRuntimeArtifactsSize(
2410 {.packageName = "com.android.foo", .dexPath = "/a/b/base.apk", .isa = "arm64"},
2411 &aidl_return)
2412 .isOk());
2413
2414 EXPECT_EQ(aidl_return, 1 + 2 + 4 + 8);
2415}
2416
2417TEST_F(ArtdTest, getProfileSize) {
2418 CreateFile(android_data_ + "/misc/profiles/cur/0/com.android.foo/primary.prof",
2419 std::string(1, '*'));
2420
2421 // Irrelevant.
2422 CreateFile(android_data_ + "/misc/profiles/cur/0/com.android.foo/split_0.split.prof",
2423 std::string(2, '*'));
2424 CreateFile(android_data_ + "/misc/profiles/cur/0/com.android.bar/primary.prof",
2425 std::string(4, '*'));
2426 CreateFile(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof",
2427 std::string(8, '*'));
2428
2429 int64_t aidl_return = -1;
2430 ASSERT_TRUE(artd_
2431 ->getProfileSize(
2432 PrimaryCurProfilePath{
2433 .userId = 0, .packageName = "com.android.foo", .profileName = "primary"},
2434 &aidl_return)
2435 .isOk());
2436 EXPECT_EQ(aidl_return, 1);
2437}
2438
Jiakai Zhanged4f3ba2022-06-08 16:22:07 +01002439} // namespace
2440} // namespace artd
2441} // namespace art