1 /*
2 * Copyright (C) 2020 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 <filesystem>
18 #include <string>
19
20 #include <errno.h>
21 #include <sys/stat.h>
22
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <android-base/stringprintf.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28
29 #include "apex_file.h"
30 #include "apex_file_repository.h"
31 #include "apexd_test_utils.h"
32 #include "apexd_verity.h"
33
34 namespace android {
35 namespace apex {
36
37 using namespace std::literals;
38
39 namespace fs = std::filesystem;
40
41 using android::apex::testing::ApexFileEq;
42 using android::apex::testing::IsOk;
43 using android::base::GetExecutableDirectory;
44 using android::base::StringPrintf;
45 using ::testing::ByRef;
46 using ::testing::UnorderedElementsAre;
47
GetTestDataDir()48 static std::string GetTestDataDir() { return GetExecutableDirectory(); }
GetTestFile(const std::string & name)49 static std::string GetTestFile(const std::string& name) {
50 return GetTestDataDir() + "/" + name;
51 }
52
53 namespace {
54 // Copies the compressed apex to |built_in_dir| and decompresses it to
55 // |decompression_dir
PrepareCompressedApex(const std::string & name,const std::string & built_in_dir,const std::string & decompression_dir)56 void PrepareCompressedApex(const std::string& name,
57 const std::string& built_in_dir,
58 const std::string& decompression_dir) {
59 fs::copy(GetTestFile(name), built_in_dir);
60 auto compressed_apex =
61 ApexFile::Open(StringPrintf("%s/%s", built_in_dir.c_str(), name.c_str()));
62
63 const auto& pkg_name = compressed_apex->GetManifest().name();
64 const int version = compressed_apex->GetManifest().version();
65
66 auto decompression_path =
67 StringPrintf("%s/%s@%d%s", decompression_dir.c_str(), pkg_name.c_str(),
68 version, kDecompressedApexPackageSuffix);
69 compressed_apex->Decompress(decompression_path);
70 }
71 } // namespace
72
TEST(ApexFileRepositoryTest,InitializeSuccess)73 TEST(ApexFileRepositoryTest, InitializeSuccess) {
74 // Prepare test data.
75 TemporaryDir built_in_dir, data_dir, decompression_dir;
76 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
77 fs::copy(GetTestFile("apex.apexd_test_different_app.apex"),
78 built_in_dir.path);
79
80 fs::copy(GetTestFile("apex.apexd_test.apex"), data_dir.path);
81 fs::copy(GetTestFile("apex.apexd_test_different_app.apex"), data_dir.path);
82
83 ApexFileRepository instance;
84 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
85 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
86
87 // Now test that apexes were scanned correctly;
88 auto test_fn = [&](const std::string& apex_name) {
89 auto apex = ApexFile::Open(GetTestFile(apex_name));
90 ASSERT_TRUE(IsOk(apex));
91
92 {
93 auto ret = instance.GetPublicKey(apex->GetManifest().name());
94 ASSERT_TRUE(IsOk(ret));
95 ASSERT_EQ(apex->GetBundledPublicKey(), *ret);
96 }
97
98 {
99 auto ret = instance.GetPreinstalledPath(apex->GetManifest().name());
100 ASSERT_TRUE(IsOk(ret));
101 ASSERT_EQ(StringPrintf("%s/%s", built_in_dir.path, apex_name.c_str()),
102 *ret);
103 }
104
105 {
106 auto ret = instance.GetDataPath(apex->GetManifest().name());
107 ASSERT_TRUE(IsOk(ret));
108 ASSERT_EQ(StringPrintf("%s/%s", data_dir.path, apex_name.c_str()), *ret);
109 }
110
111 ASSERT_TRUE(instance.HasPreInstalledVersion(apex->GetManifest().name()));
112 ASSERT_TRUE(instance.HasDataVersion(apex->GetManifest().name()));
113 };
114
115 test_fn("apex.apexd_test.apex");
116 test_fn("apex.apexd_test_different_app.apex");
117
118 // Check that second call will succeed as well.
119 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
120 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
121
122 test_fn("apex.apexd_test.apex");
123 test_fn("apex.apexd_test_different_app.apex");
124 }
125
TEST(ApexFileRepositoryTest,InitializeFailureCorruptApex)126 TEST(ApexFileRepositoryTest, InitializeFailureCorruptApex) {
127 // Prepare test data.
128 TemporaryDir td;
129 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
130 fs::copy(GetTestFile("apex.apexd_test_corrupt_superblock_apex.apex"),
131 td.path);
132
133 ApexFileRepository instance;
134 ASSERT_FALSE(IsOk(instance.AddPreInstalledApex({td.path})));
135 }
136
TEST(ApexFileRepositoryTest,InitializeCompressedApexWithoutApex)137 TEST(ApexFileRepositoryTest, InitializeCompressedApexWithoutApex) {
138 // Prepare test data.
139 TemporaryDir td;
140 fs::copy(GetTestFile("com.android.apex.compressed.v1_without_apex.capex"),
141 td.path);
142
143 ApexFileRepository instance;
144 // Compressed APEX without APEX cannot be opened
145 ASSERT_FALSE(IsOk(instance.AddPreInstalledApex({td.path})));
146 }
147
TEST(ApexFileRepositoryTest,InitializeSameNameDifferentPathAborts)148 TEST(ApexFileRepositoryTest, InitializeSameNameDifferentPathAborts) {
149 // Prepare test data.
150 TemporaryDir td;
151 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
152 fs::copy(GetTestFile("apex.apexd_test.apex"),
153 StringPrintf("%s/other.apex", td.path));
154
155 ASSERT_DEATH(
156 {
157 ApexFileRepository instance;
158 instance.AddPreInstalledApex({td.path});
159 },
160 "");
161 }
162
TEST(ApexFileRepositoryTest,InitializeSameNameDifferentPathAbortsCompressedApex)163 TEST(ApexFileRepositoryTest,
164 InitializeSameNameDifferentPathAbortsCompressedApex) {
165 // Prepare test data.
166 TemporaryDir td;
167 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), td.path);
168 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"),
169 StringPrintf("%s/other.capex", td.path));
170
171 ASSERT_DEATH(
172 {
173 ApexFileRepository instance;
174 instance.AddPreInstalledApex({td.path});
175 },
176 "");
177 }
178
TEST(ApexFileRepositoryTest,InitializePublicKeyUnexpectdlyChangedAborts)179 TEST(ApexFileRepositoryTest, InitializePublicKeyUnexpectdlyChangedAborts) {
180 // Prepare test data.
181 TemporaryDir td;
182 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
183
184 ApexFileRepository instance;
185 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({td.path})));
186
187 // Check that apex was loaded.
188 auto path = instance.GetPreinstalledPath("com.android.apex.test_package");
189 ASSERT_TRUE(IsOk(path));
190 ASSERT_EQ(StringPrintf("%s/apex.apexd_test.apex", td.path), *path);
191
192 auto public_key = instance.GetPublicKey("com.android.apex.test_package");
193 ASSERT_TRUE(IsOk(public_key));
194
195 // Substitute it with another apex with the same name, but different public
196 // key.
197 fs::copy(GetTestFile("apex.apexd_test_different_key.apex"), *path,
198 fs::copy_options::overwrite_existing);
199
200 {
201 auto apex = ApexFile::Open(*path);
202 ASSERT_TRUE(IsOk(apex));
203 // Check module name hasn't changed.
204 ASSERT_EQ("com.android.apex.test_package", apex->GetManifest().name());
205 // Check public key has changed.
206 ASSERT_NE(*public_key, apex->GetBundledPublicKey());
207 }
208
209 ASSERT_DEATH({ instance.AddPreInstalledApex({td.path}); }, "");
210 }
211
TEST(ApexFileRepositoryTest,InitializePublicKeyUnexpectdlyChangedAbortsCompressedApex)212 TEST(ApexFileRepositoryTest,
213 InitializePublicKeyUnexpectdlyChangedAbortsCompressedApex) {
214 // Prepare test data.
215 TemporaryDir td;
216 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), td.path);
217
218 ApexFileRepository instance;
219 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({td.path})));
220
221 // Check that apex was loaded.
222 auto path = instance.GetPreinstalledPath("com.android.apex.compressed");
223 ASSERT_TRUE(IsOk(path));
224 ASSERT_EQ(StringPrintf("%s/com.android.apex.compressed.v1.capex", td.path),
225 *path);
226
227 auto public_key = instance.GetPublicKey("com.android.apex.compressed");
228 ASSERT_TRUE(IsOk(public_key));
229
230 // Substitute it with another apex with the same name, but different public
231 // key.
232 fs::copy(GetTestFile("com.android.apex.compressed_different_key.capex"),
233 *path, fs::copy_options::overwrite_existing);
234
235 {
236 auto apex = ApexFile::Open(*path);
237 ASSERT_TRUE(IsOk(apex));
238 // Check module name hasn't changed.
239 ASSERT_EQ("com.android.apex.compressed", apex->GetManifest().name());
240 // Check public key has changed.
241 ASSERT_NE(*public_key, apex->GetBundledPublicKey());
242 }
243
244 ASSERT_DEATH({ instance.AddPreInstalledApex({td.path}); }, "");
245 }
246
TEST(ApexFileRepositoryTest,IsPreInstalledApex)247 TEST(ApexFileRepositoryTest, IsPreInstalledApex) {
248 // Prepare test data.
249 TemporaryDir td;
250 fs::copy(GetTestFile("apex.apexd_test.apex"), td.path);
251 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), td.path);
252
253 ApexFileRepository instance;
254 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({td.path})));
255
256 auto compressed_apex = ApexFile::Open(
257 StringPrintf("%s/com.android.apex.compressed.v1.capex", td.path));
258 ASSERT_TRUE(IsOk(compressed_apex));
259 ASSERT_TRUE(instance.IsPreInstalledApex(*compressed_apex));
260
261 auto apex1 = ApexFile::Open(StringPrintf("%s/apex.apexd_test.apex", td.path));
262 ASSERT_TRUE(IsOk(apex1));
263 ASSERT_TRUE(instance.IsPreInstalledApex(*apex1));
264
265 // It's same apex, but path is different. Shouldn't be treated as
266 // pre-installed.
267 auto apex2 = ApexFile::Open(GetTestFile("apex.apexd_test.apex"));
268 ASSERT_TRUE(IsOk(apex2));
269 ASSERT_FALSE(instance.IsPreInstalledApex(*apex2));
270
271 auto apex3 =
272 ApexFile::Open(GetTestFile("apex.apexd_test_different_app.apex"));
273 ASSERT_TRUE(IsOk(apex3));
274 ASSERT_FALSE(instance.IsPreInstalledApex(*apex3));
275 }
276
TEST(ApexFileRepositoryTest,IsDecompressedApex)277 TEST(ApexFileRepositoryTest, IsDecompressedApex) {
278 // Prepare instance
279 TemporaryDir decompression_dir;
280 ApexFileRepository instance(decompression_dir.path);
281
282 // Prepare decompressed apex
283 std::string filename = "com.android.apex.compressed.v1_original.apex";
284 fs::copy(GetTestFile(filename), decompression_dir.path);
285 auto decompressed_path =
286 StringPrintf("%s/%s", decompression_dir.path, filename.c_str());
287 auto decompressed_apex = ApexFile::Open(decompressed_path);
288
289 // Any file which is already located in |decompression_dir| should be
290 // considered decompressed
291 ASSERT_TRUE(instance.IsDecompressedApex(*decompressed_apex));
292
293 // Hard links with same file name is not considered decompressed
294 TemporaryDir active_dir;
295 auto active_path = StringPrintf("%s/%s", active_dir.path, filename.c_str());
296 std::error_code ec;
297 fs::create_hard_link(decompressed_path, active_path, ec);
298 ASSERT_FALSE(ec) << "Failed to create hardlink";
299 auto active_apex = ApexFile::Open(active_path);
300 ASSERT_FALSE(instance.IsDecompressedApex(*active_apex));
301 }
302
TEST(ApexFileRepositoryTest,AddAndGetDataApex)303 TEST(ApexFileRepositoryTest, AddAndGetDataApex) {
304 // Prepare test data.
305 TemporaryDir built_in_dir, data_dir, decompression_dir;
306 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
307 fs::copy(GetTestFile("apex.apexd_test_v2.apex"), data_dir.path);
308 PrepareCompressedApex("com.android.apex.compressed.v1.capex",
309 built_in_dir.path, decompression_dir.path);
310 // Add a data apex that has kDecompressedApexPackageSuffix
311 fs::copy(GetTestFile("com.android.apex.compressed.v1_original.apex"),
312 StringPrintf("%s/com.android.apex.compressed@1%s", data_dir.path,
313 kDecompressedApexPackageSuffix));
314
315 ApexFileRepository instance(decompression_dir.path);
316 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
317 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
318
319 // ApexFileRepository should only deal with APEX in /data/apex/active.
320 // Decompressed APEX should not be included
321 auto data_apexs = instance.GetDataApexFiles();
322 auto normal_apex =
323 ApexFile::Open(StringPrintf("%s/apex.apexd_test_v2.apex", data_dir.path));
324 ASSERT_THAT(data_apexs,
325 UnorderedElementsAre(ApexFileEq(ByRef(*normal_apex))));
326 }
327
TEST(ApexFileRepositoryTest,AddDataApexIgnoreCompressedApex)328 TEST(ApexFileRepositoryTest, AddDataApexIgnoreCompressedApex) {
329 // Prepare test data.
330 TemporaryDir data_dir, decompression_dir;
331 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"), data_dir.path);
332
333 ApexFileRepository instance;
334 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
335
336 auto data_apexs = instance.GetDataApexFiles();
337 ASSERT_EQ(data_apexs.size(), 0u);
338 }
339
TEST(ApexFileRepositoryTest,AddDataApexIgnoreIfNotPreInstalled)340 TEST(ApexFileRepositoryTest, AddDataApexIgnoreIfNotPreInstalled) {
341 // Prepare test data.
342 TemporaryDir data_dir, decompression_dir;
343 fs::copy(GetTestFile("apex.apexd_test.apex"), data_dir.path);
344
345 ApexFileRepository instance;
346 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
347
348 auto data_apexs = instance.GetDataApexFiles();
349 ASSERT_EQ(data_apexs.size(), 0u);
350 }
351
TEST(ApexFileRepositoryTest,AddDataApexPrioritizeHigherVersionApex)352 TEST(ApexFileRepositoryTest, AddDataApexPrioritizeHigherVersionApex) {
353 // Prepare test data.
354 TemporaryDir built_in_dir, data_dir, decompression_dir;
355 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
356 fs::copy(GetTestFile("apex.apexd_test.apex"), data_dir.path);
357 fs::copy(GetTestFile("apex.apexd_test_v2.apex"), data_dir.path);
358
359 ApexFileRepository instance;
360 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
361 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
362
363 auto data_apexs = instance.GetDataApexFiles();
364 auto normal_apex =
365 ApexFile::Open(StringPrintf("%s/apex.apexd_test_v2.apex", data_dir.path));
366 ASSERT_THAT(data_apexs,
367 UnorderedElementsAre(ApexFileEq(ByRef(*normal_apex))));
368 }
369
TEST(ApexFileRepositoryTest,AddDataApexDoesNotScanDecompressedApex)370 TEST(ApexFileRepositoryTest, AddDataApexDoesNotScanDecompressedApex) {
371 // Prepare test data.
372 TemporaryDir built_in_dir, data_dir, decompression_dir;
373 PrepareCompressedApex("com.android.apex.compressed.v1.capex",
374 built_in_dir.path, decompression_dir.path);
375
376 ApexFileRepository instance(decompression_dir.path);
377 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
378 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
379
380 auto data_apexs = instance.GetDataApexFiles();
381 ASSERT_EQ(data_apexs.size(), 0u);
382 }
383
TEST(ApexFileRepositoryTest,AddDataApexIgnoreWrongPublicKey)384 TEST(ApexFileRepositoryTest, AddDataApexIgnoreWrongPublicKey) {
385 // Prepare test data.
386 TemporaryDir built_in_dir, data_dir, decompression_dir;
387 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
388 fs::copy(GetTestFile("apex.apexd_test_different_key.apex"), data_dir.path);
389
390 ApexFileRepository instance;
391 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
392 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
393
394 auto data_apexs = instance.GetDataApexFiles();
395 ASSERT_EQ(data_apexs.size(), 0u);
396 }
397
TEST(ApexFileRepositoryTest,GetPreInstalledApexFiles)398 TEST(ApexFileRepositoryTest, GetPreInstalledApexFiles) {
399 // Prepare test data.
400 TemporaryDir built_in_dir;
401 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
402 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"),
403 built_in_dir.path);
404
405 ApexFileRepository instance;
406 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
407
408 auto pre_installed_apexs = instance.GetPreInstalledApexFiles();
409 auto pre_apex_1 = ApexFile::Open(
410 StringPrintf("%s/apex.apexd_test.apex", built_in_dir.path));
411 auto pre_apex_2 = ApexFile::Open(StringPrintf(
412 "%s/com.android.apex.compressed.v1.capex", built_in_dir.path));
413 ASSERT_THAT(pre_installed_apexs,
414 UnorderedElementsAre(ApexFileEq(ByRef(*pre_apex_1)),
415 ApexFileEq(ByRef(*pre_apex_2))));
416 }
417
TEST(ApexFileRepositoryTest,AllApexFilesByName)418 TEST(ApexFileRepositoryTest, AllApexFilesByName) {
419 TemporaryDir built_in_dir, decompression_dir;
420 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
421 fs::copy(GetTestFile("com.android.apex.cts.shim.apex"), built_in_dir.path);
422 fs::copy(GetTestFile("com.android.apex.compressed.v1.capex"),
423 built_in_dir.path);
424 ApexFileRepository instance;
425 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
426
427 TemporaryDir data_dir;
428 fs::copy(GetTestFile("com.android.apex.cts.shim.v2.apex"), data_dir.path);
429 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
430
431 auto result = instance.AllApexFilesByName();
432
433 // Verify the contents of result
434 auto apexd_test_file = ApexFile::Open(
435 StringPrintf("%s/apex.apexd_test.apex", built_in_dir.path));
436 auto shim_v1 = ApexFile::Open(
437 StringPrintf("%s/com.android.apex.cts.shim.apex", built_in_dir.path));
438 auto compressed_apex = ApexFile::Open(StringPrintf(
439 "%s/com.android.apex.compressed.v1.capex", built_in_dir.path));
440 auto shim_v2 = ApexFile::Open(
441 StringPrintf("%s/com.android.apex.cts.shim.v2.apex", data_dir.path));
442
443 ASSERT_EQ(result.size(), 3u);
444 ASSERT_THAT(result[apexd_test_file->GetManifest().name()],
445 UnorderedElementsAre(ApexFileEq(ByRef(*apexd_test_file))));
446 ASSERT_THAT(result[shim_v1->GetManifest().name()],
447 UnorderedElementsAre(ApexFileEq(ByRef(*shim_v1)),
448 ApexFileEq(ByRef(*shim_v2))));
449 ASSERT_THAT(result[compressed_apex->GetManifest().name()],
450 UnorderedElementsAre(ApexFileEq(ByRef(*compressed_apex))));
451 }
452
TEST(ApexFileRepositoryTest,GetDataApex)453 TEST(ApexFileRepositoryTest, GetDataApex) {
454 // Prepare test data.
455 TemporaryDir built_in_dir, data_dir;
456 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
457 fs::copy(GetTestFile("apex.apexd_test_v2.apex"), data_dir.path);
458
459 ApexFileRepository instance;
460 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
461 ASSERT_TRUE(IsOk(instance.AddDataApex(data_dir.path)));
462
463 auto apex =
464 ApexFile::Open(StringPrintf("%s/apex.apexd_test_v2.apex", data_dir.path));
465 ASSERT_RESULT_OK(apex);
466
467 auto ret = instance.GetDataApex("com.android.apex.test_package");
468 ASSERT_THAT(ret, ApexFileEq(ByRef(*apex)));
469 }
470
TEST(ApexFileRepositoryTest,GetDataApexNoSuchApexAborts)471 TEST(ApexFileRepositoryTest, GetDataApexNoSuchApexAborts) {
472 ASSERT_DEATH(
473 {
474 ApexFileRepository instance;
475 instance.GetDataApex("whatever");
476 },
477 "");
478 }
479
TEST(ApexFileRepositoryTest,GetPreInstalledApex)480 TEST(ApexFileRepositoryTest, GetPreInstalledApex) {
481 // Prepare test data.
482 TemporaryDir built_in_dir;
483 fs::copy(GetTestFile("apex.apexd_test.apex"), built_in_dir.path);
484
485 ApexFileRepository instance;
486 ASSERT_TRUE(IsOk(instance.AddPreInstalledApex({built_in_dir.path})));
487
488 auto apex = ApexFile::Open(
489 StringPrintf("%s/apex.apexd_test.apex", built_in_dir.path));
490 ASSERT_RESULT_OK(apex);
491
492 auto ret = instance.GetPreInstalledApex("com.android.apex.test_package");
493 ASSERT_THAT(ret, ApexFileEq(ByRef(*apex)));
494 }
495
TEST(ApexFileRepositoryTest,GetPreInstalledApexNoSuchApexAborts)496 TEST(ApexFileRepositoryTest, GetPreInstalledApexNoSuchApexAborts) {
497 ASSERT_DEATH(
498 {
499 ApexFileRepository instance;
500 instance.GetPreInstalledApex("whatever");
501 },
502 "");
503 }
504
505 } // namespace apex
506 } // namespace android
507