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