1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "path_utils.h"
18
19 #include "aidl/com/android/server/art/BnArtd.h"
20 #include "android-base/result-gmock.h"
21 #include "base/common_art_test.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24
25 namespace art {
26 namespace artd {
27 namespace {
28
29 using ::aidl::com::android::server::art::ArtifactsPath;
30 using ::aidl::com::android::server::art::DexMetadataPath;
31 using ::aidl::com::android::server::art::ProfilePath;
32 using ::android::base::testing::HasError;
33 using ::android::base::testing::HasValue;
34 using ::android::base::testing::WithMessage;
35 using ::testing::AllOf;
36 using ::testing::Field;
37
38 using PrebuiltProfilePath = ProfilePath::PrebuiltProfilePath;
39 using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
40 using PrimaryRefProfilePath = ProfilePath::PrimaryRefProfilePath;
41 using SecondaryCurProfilePath = ProfilePath::SecondaryCurProfilePath;
42 using SecondaryRefProfilePath = ProfilePath::SecondaryRefProfilePath;
43 using TmpProfilePath = ProfilePath::TmpProfilePath;
44
45 using std::literals::operator""s; // NOLINT
46
47 class PathUtilsTest : public CommonArtTest {};
48
TEST_F(PathUtilsTest,BuildArtBinPath)49 TEST_F(PathUtilsTest, BuildArtBinPath) {
50 auto scratch_dir = std::make_unique<ScratchDir>();
51 auto art_root_env = ScopedUnsetEnvironmentVariable("ANDROID_ART_ROOT");
52 setenv("ANDROID_ART_ROOT", scratch_dir->GetPath().c_str(), /*overwrite=*/1);
53 EXPECT_THAT(BuildArtBinPath("foo"), HasValue(scratch_dir->GetPath() + "/bin/foo"));
54 }
55
TEST_F(PathUtilsTest,BuildArtifactsPath)56 TEST_F(PathUtilsTest, BuildArtifactsPath) {
57 EXPECT_THAT(
58 BuildArtifactsPath(ArtifactsPath{
59 .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = false, .isPreReboot = false}),
60 HasValue(AllOf(Field(&RawArtifactsPath::oat_path, "/a/oat/arm64/b.odex"),
61 Field(&RawArtifactsPath::vdex_path, "/a/oat/arm64/b.vdex"),
62 Field(&RawArtifactsPath::art_path, "/a/oat/arm64/b.art"))));
63 }
64
TEST_F(PathUtilsTest,BuildArtifactsPathPreReboot)65 TEST_F(PathUtilsTest, BuildArtifactsPathPreReboot) {
66 EXPECT_THAT(
67 BuildArtifactsPath(ArtifactsPath{
68 .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = false, .isPreReboot = true}),
69 HasValue(AllOf(Field(&RawArtifactsPath::oat_path, "/a/oat/arm64/b.odex.staged"),
70 Field(&RawArtifactsPath::vdex_path, "/a/oat/arm64/b.vdex.staged"),
71 Field(&RawArtifactsPath::art_path, "/a/oat/arm64/b.art.staged"))));
72 }
73
TEST_F(PathUtilsTest,BuildArtifactsPathDalvikCache)74 TEST_F(PathUtilsTest, BuildArtifactsPathDalvikCache) {
75 EXPECT_THAT(
76 BuildArtifactsPath(ArtifactsPath{
77 .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = true, .isPreReboot = false}),
78 HasValue(AllOf(Field(&RawArtifactsPath::oat_path,
79 android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.dex"),
80 Field(&RawArtifactsPath::vdex_path,
81 android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.vdex"),
82 Field(&RawArtifactsPath::art_path,
83 android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.art"))));
84 }
85
TEST_F(PathUtilsTest,BuildArtifactsPathDalvikCachePreReboot)86 TEST_F(PathUtilsTest, BuildArtifactsPathDalvikCachePreReboot) {
87 EXPECT_THAT(
88 BuildArtifactsPath(ArtifactsPath{
89 .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = true, .isPreReboot = true}),
90 HasValue(AllOf(Field(&RawArtifactsPath::oat_path,
91 android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.dex.staged"),
92 Field(&RawArtifactsPath::vdex_path,
93 android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.vdex.staged"),
94 Field(&RawArtifactsPath::art_path,
95 android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.art.staged"))));
96 }
97
TEST_F(PathUtilsTest,BuildOatPathInvalidDexPath)98 TEST_F(PathUtilsTest, BuildOatPathInvalidDexPath) {
99 EXPECT_THAT(
100 BuildArtifactsPath(ArtifactsPath{
101 .dexPath = "a/b.apk", .isa = "arm64", .isInDalvikCache = false, .isPreReboot = false}),
102 HasError(WithMessage("Path 'a/b.apk' is not an absolute path")));
103 }
104
TEST_F(PathUtilsTest,BuildOatPathInvalidIsa)105 TEST_F(PathUtilsTest, BuildOatPathInvalidIsa) {
106 EXPECT_THAT(
107 BuildArtifactsPath(ArtifactsPath{
108 .dexPath = "/a/b.apk", .isa = "invalid", .isInDalvikCache = false, .isPreReboot = false}),
109 HasError(WithMessage("Instruction set 'invalid' is invalid")));
110 }
111
TEST_F(PathUtilsTest,BuildPrimaryRefProfilePath)112 TEST_F(PathUtilsTest, BuildPrimaryRefProfilePath) {
113 EXPECT_THAT(
114 BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
115 .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false}),
116 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
117 }
118
TEST_F(PathUtilsTest,BuildPrimaryRefProfilePathPreReboot)119 TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPreReboot) {
120 EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
121 .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = true}),
122 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.staged"));
123 }
124
TEST_F(PathUtilsTest,BuildPrimaryRefProfilePathPackageNameOk)125 TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPackageNameOk) {
126 EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
127 .packageName = "...", .profileName = "primary", .isPreReboot = false}),
128 HasValue(android_data_ + "/misc/profiles/ref/.../primary.prof"));
129 }
130
TEST_F(PathUtilsTest,BuildPrimaryRefProfilePathPackageNameWrong)131 TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPackageNameWrong) {
132 EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
133 .packageName = "..", .profileName = "primary", .isPreReboot = false}),
134 HasError(WithMessage("Invalid packageName '..'")));
135 EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
136 .packageName = "a/b", .profileName = "primary", .isPreReboot = false}),
137 HasError(WithMessage("packageName 'a/b' has invalid character '/'")));
138 }
139
TEST_F(PathUtilsTest,BuildPrimaryRefProfilePathProfileNameOk)140 TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathProfileNameOk) {
141 EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
142 .packageName = "com.android.foo", .profileName = "..", .isPreReboot = false}),
143 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/...prof"));
144 }
145
TEST_F(PathUtilsTest,BuildPrimaryRefProfilePathProfileNameWrong)146 TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathProfileNameWrong) {
147 EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
148 .packageName = "com.android.foo", .profileName = "a/b", .isPreReboot = false}),
149 HasError(WithMessage("profileName 'a/b' has invalid character '/'")));
150 }
151
TEST_F(PathUtilsTest,BuildFinalProfilePathForPrimary)152 TEST_F(PathUtilsTest, BuildFinalProfilePathForPrimary) {
153 EXPECT_THAT(BuildFinalProfilePath(TmpProfilePath{
154 .finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
155 .profileName = "primary",
156 .isPreReboot = false},
157 .id = "12345"}),
158 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
159 }
160
TEST_F(PathUtilsTest,BuildFinalProfilePathForSecondary)161 TEST_F(PathUtilsTest, BuildFinalProfilePathForSecondary) {
162 EXPECT_THAT(BuildFinalProfilePath(TmpProfilePath{
163 .finalPath = SecondaryRefProfilePath{.dexPath = android_data_ +
164 "/user/0/com.android.foo/a.apk",
165 .isPreReboot = false},
166 .id = "12345"}),
167 HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof"));
168 }
169
TEST_F(PathUtilsTest,BuildTmpProfilePathForPrimary)170 TEST_F(PathUtilsTest, BuildTmpProfilePathForPrimary) {
171 EXPECT_THAT(
172 BuildTmpProfilePath(TmpProfilePath{
173 .finalPath =
174 PrimaryRefProfilePath{
175 .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false},
176 .id = "12345"}),
177 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"));
178 }
179
TEST_F(PathUtilsTest,BuildTmpProfilePathForSecondary)180 TEST_F(PathUtilsTest, BuildTmpProfilePathForSecondary) {
181 EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
182 .finalPath = SecondaryRefProfilePath{.dexPath = android_data_ +
183 "/user/0/com.android.foo/a.apk",
184 .isPreReboot = false},
185 .id = "12345"}),
186 HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof.12345.tmp"));
187 }
188
TEST_F(PathUtilsTest,BuildTmpProfilePathIdWrong)189 TEST_F(PathUtilsTest, BuildTmpProfilePathIdWrong) {
190 EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
191 .finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
192 .profileName = "primary",
193 .isPreReboot = false},
194 .id = "123/45"}),
195 HasError(WithMessage("id '123/45' has invalid character '/'")));
196 }
197
TEST_F(PathUtilsTest,BuildPrebuiltProfilePath)198 TEST_F(PathUtilsTest, BuildPrebuiltProfilePath) {
199 EXPECT_THAT(BuildPrebuiltProfilePath(PrebuiltProfilePath{.dexPath = "/a/b.apk"}),
200 HasValue("/a/b.apk.prof"));
201 }
202
TEST_F(PathUtilsTest,BuildPrimaryCurProfilePath)203 TEST_F(PathUtilsTest, BuildPrimaryCurProfilePath) {
204 EXPECT_THAT(BuildPrimaryCurProfilePath(PrimaryCurProfilePath{
205 .userId = 1, .packageName = "com.android.foo", .profileName = "primary"}),
206 HasValue(android_data_ + "/misc/profiles/cur/1/com.android.foo/primary.prof"));
207 }
208
TEST_F(PathUtilsTest,BuildSecondaryRefProfilePath)209 TEST_F(PathUtilsTest, BuildSecondaryRefProfilePath) {
210 EXPECT_THAT(
211 BuildSecondaryRefProfilePath(SecondaryRefProfilePath{
212 .dexPath = android_data_ + "/user/0/com.android.foo/a.apk", .isPreReboot = false}),
213 HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof"));
214 }
215
TEST_F(PathUtilsTest,BuildSecondaryRefProfilePathPreReboot)216 TEST_F(PathUtilsTest, BuildSecondaryRefProfilePathPreReboot) {
217 EXPECT_THAT(BuildSecondaryRefProfilePath(SecondaryRefProfilePath{
218 .dexPath = android_data_ + "/user/0/com.android.foo/a.apk", .isPreReboot = true}),
219 HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof.staged"));
220 }
221
TEST_F(PathUtilsTest,BuildSecondaryCurProfilePath)222 TEST_F(PathUtilsTest, BuildSecondaryCurProfilePath) {
223 EXPECT_THAT(BuildSecondaryCurProfilePath(SecondaryCurProfilePath{
224 .dexPath = android_data_ + "/user/0/com.android.foo/a.apk"}),
225 HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.cur.prof"));
226 }
227
TEST_F(PathUtilsTest,BuildDexMetadataPath)228 TEST_F(PathUtilsTest, BuildDexMetadataPath) {
229 EXPECT_THAT(BuildDexMetadataPath(DexMetadataPath{.dexPath = "/a/b.apk"}), HasValue("/a/b.dm"));
230 }
231
TEST_F(PathUtilsTest,BuildProfilePath)232 TEST_F(PathUtilsTest, BuildProfilePath) {
233 EXPECT_THAT(
234 BuildProfileOrDmPath(PrimaryRefProfilePath{
235 .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false}),
236 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
237 EXPECT_THAT(
238 BuildProfileOrDmPath(TmpProfilePath{
239 .finalPath =
240 PrimaryRefProfilePath{
241 .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false},
242 .id = "12345"}),
243 HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"));
244 EXPECT_THAT(BuildProfileOrDmPath(PrebuiltProfilePath{.dexPath = "/a/b.apk"}),
245 HasValue("/a/b.apk.prof"));
246 EXPECT_THAT(BuildProfileOrDmPath(PrimaryCurProfilePath{
247 .userId = 1, .packageName = "com.android.foo", .profileName = "primary"}),
248 HasValue(android_data_ + "/misc/profiles/cur/1/com.android.foo/primary.prof"));
249 EXPECT_THAT(BuildProfileOrDmPath(DexMetadataPath{.dexPath = "/a/b.apk"}), HasValue("/a/b.dm"));
250 }
251
TEST_F(PathUtilsTest,BuildVdexPath)252 TEST_F(PathUtilsTest, BuildVdexPath) {
253 EXPECT_THAT(
254 BuildVdexPath(ArtifactsPath{.dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = false}),
255 HasValue("/a/oat/arm64/b.vdex"));
256 }
257
258 } // namespace
259 } // namespace artd
260 } // namespace art
261