1 /*
2 * Copyright (C) 2017 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 <sstream>
18 #include <string>
19
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/statvfs.h>
24 #include <sys/stat.h>
25 #include <sys/xattr.h>
26
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/scopeguard.h>
31 #include <android-base/stringprintf.h>
32 #include <cutils/properties.h>
33 #include <gtest/gtest.h>
34
35 #include "binder_test_utils.h"
36 #include "InstalldNativeService.h"
37 #include "dexopt.h"
38 #include "globals.h"
39 #include "utils.h"
40
41 using android::base::StringPrintf;
42
43 namespace android {
44 namespace installd {
45
46 constexpr const char* kTestUuid = "TEST";
47
48 #define FLAG_FORCE InstalldNativeService::FLAG_FORCE
49
get_property(const char * key,char * value,const char * default_value)50 int get_property(const char *key, char *value, const char *default_value) {
51 return property_get(key, value, default_value);
52 }
53
calculate_oat_file_path(char path[PKG_PATH_MAX],const char * oat_dir,const char * apk_path,const char * instruction_set)54 bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
55 const char *instruction_set) {
56 return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
57 }
58
calculate_odex_file_path(char path[PKG_PATH_MAX],const char * apk_path,const char * instruction_set)59 bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
60 const char *instruction_set) {
61 return calculate_odex_file_path_default(path, apk_path, instruction_set);
62 }
63
create_cache_path(char path[PKG_PATH_MAX],const char * src,const char * instruction_set)64 bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
65 return create_cache_path_default(path, src, instruction_set);
66 }
67
get_full_path(const char * path)68 static std::string get_full_path(const char* path) {
69 return StringPrintf("/data/local/tmp/user/0/%s", path);
70 }
71
mkdir(const char * path,uid_t owner,gid_t group,mode_t mode)72 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
73 const std::string fullPath = get_full_path(path);
74 EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
75 EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
76 EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
77 }
78
touch(const char * path,uid_t owner,gid_t group,mode_t mode)79 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
80 int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
81 EXPECT_NE(fd, -1);
82 EXPECT_EQ(::fchown(fd, owner, group), 0);
83 EXPECT_EQ(::fchmod(fd, mode), 0);
84 EXPECT_EQ(::close(fd), 0);
85 }
86
stat_gid(const char * path)87 static int stat_gid(const char* path) {
88 struct stat buf;
89 EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
90 return buf.st_gid;
91 }
92
stat_mode(const char * path)93 static int stat_mode(const char* path) {
94 struct stat buf;
95 EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
96 return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
97 }
98
99 class ServiceTest : public testing::Test {
100 protected:
101 InstalldNativeService* service;
102 std::optional<std::string> testUuid;
103
SetUp()104 virtual void SetUp() {
105 setenv("ANDROID_LOG_TAGS", "*:v", 1);
106 android::base::InitLogging(nullptr);
107
108 service = new InstalldNativeService();
109 testUuid = kTestUuid;
110 system("mkdir -p /data/local/tmp/user/0");
111
112 init_globals_from_data_and_root();
113 }
114
TearDown()115 virtual void TearDown() {
116 delete service;
117 system("rm -rf /data/local/tmp/user");
118 }
119 };
120
TEST_F(ServiceTest,FixupAppData_Upgrade)121 TEST_F(ServiceTest, FixupAppData_Upgrade) {
122 LOG(INFO) << "FixupAppData_Upgrade";
123
124 mkdir("com.example", 10000, 10000, 0700);
125 mkdir("com.example/normal", 10000, 10000, 0700);
126 mkdir("com.example/cache", 10000, 10000, 0700);
127 touch("com.example/cache/file", 10000, 10000, 0700);
128
129 service->fixupAppData(testUuid, 0);
130
131 EXPECT_EQ(10000, stat_gid("com.example/normal"));
132 EXPECT_EQ(20000, stat_gid("com.example/cache"));
133 EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
134
135 EXPECT_EQ(0700, stat_mode("com.example/normal"));
136 EXPECT_EQ(02771, stat_mode("com.example/cache"));
137 EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
138 }
139
TEST_F(ServiceTest,FixupAppData_Moved)140 TEST_F(ServiceTest, FixupAppData_Moved) {
141 LOG(INFO) << "FixupAppData_Moved";
142
143 mkdir("com.example", 10000, 10000, 0700);
144 mkdir("com.example/foo", 10000, 10000, 0700);
145 touch("com.example/foo/file", 10000, 20000, 0700);
146 mkdir("com.example/bar", 10000, 20000, 0700);
147 touch("com.example/bar/file", 10000, 20000, 0700);
148
149 service->fixupAppData(testUuid, 0);
150
151 EXPECT_EQ(10000, stat_gid("com.example/foo"));
152 EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
153 EXPECT_EQ(10000, stat_gid("com.example/bar"));
154 EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
155
156 service->fixupAppData(testUuid, FLAG_FORCE);
157
158 EXPECT_EQ(10000, stat_gid("com.example/foo"));
159 EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
160 EXPECT_EQ(10000, stat_gid("com.example/bar"));
161 EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
162 }
163
TEST_F(ServiceTest,HashSecondaryDex)164 TEST_F(ServiceTest, HashSecondaryDex) {
165 LOG(INFO) << "HashSecondaryDex";
166
167 mkdir("com.example", 10000, 10000, 0700);
168 mkdir("com.example/foo", 10000, 10000, 0700);
169 touch("com.example/foo/file", 10000, 20000, 0700);
170
171 std::vector<uint8_t> result;
172 std::string dexPath = get_full_path("com.example/foo/file");
173 EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
174 dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
175
176 EXPECT_EQ(result.size(), 32U);
177
178 std::ostringstream output;
179 output << std::hex << std::setfill('0');
180 for (auto b : result) {
181 output << std::setw(2) << +b;
182 }
183
184 // This is the SHA256 of an empty string (sha256sum /dev/null)
185 EXPECT_EQ(output.str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
186 }
187
TEST_F(ServiceTest,HashSecondaryDex_NoSuch)188 TEST_F(ServiceTest, HashSecondaryDex_NoSuch) {
189 LOG(INFO) << "HashSecondaryDex_NoSuch";
190
191 std::vector<uint8_t> result;
192 std::string dexPath = get_full_path("com.example/foo/file");
193 EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
194 dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
195
196 EXPECT_EQ(result.size(), 0U);
197 }
198
TEST_F(ServiceTest,HashSecondaryDex_Unreadable)199 TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
200 LOG(INFO) << "HashSecondaryDex_Unreadable";
201
202 mkdir("com.example", 10000, 10000, 0700);
203 mkdir("com.example/foo", 10000, 10000, 0700);
204 touch("com.example/foo/file", 10000, 20000, 0300);
205
206 std::vector<uint8_t> result;
207 std::string dexPath = get_full_path("com.example/foo/file");
208 EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
209 dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
210
211 EXPECT_EQ(result.size(), 0U);
212 }
213
TEST_F(ServiceTest,HashSecondaryDex_WrongApp)214 TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
215 LOG(INFO) << "HashSecondaryDex_WrongApp";
216
217 mkdir("com.example", 10000, 10000, 0700);
218 mkdir("com.example/foo", 10000, 10000, 0700);
219 touch("com.example/foo/file", 10000, 20000, 0700);
220
221 std::vector<uint8_t> result;
222 std::string dexPath = get_full_path("com.example/foo/file");
223 EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
224 dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
225 }
226
TEST_F(ServiceTest,CalculateOat)227 TEST_F(ServiceTest, CalculateOat) {
228 char buf[PKG_PATH_MAX];
229
230 EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa"));
231 EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
232
233 EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa"));
234 EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa"));
235 }
236
TEST_F(ServiceTest,CalculateOdex)237 TEST_F(ServiceTest, CalculateOdex) {
238 char buf[PKG_PATH_MAX];
239
240 EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa"));
241 EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
242 }
243
TEST_F(ServiceTest,CalculateCache)244 TEST_F(ServiceTest, CalculateCache) {
245 char buf[PKG_PATH_MAX];
246
247 EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
248 EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
249 }
250
mkdirs(const std::string & path,mode_t mode)251 static bool mkdirs(const std::string& path, mode_t mode) {
252 struct stat sb;
253 if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
254 return true;
255 }
256
257 if (!mkdirs(android::base::Dirname(path), mode)) {
258 return false;
259 }
260
261 if (::mkdir(path.c_str(), mode) != 0) {
262 PLOG(DEBUG) << "Failed to create folder " << path;
263 return false;
264 }
265 return true;
266 }
267
268 class AppDataSnapshotTest : public testing::Test {
269 private:
270 std::string rollback_ce_base_dir;
271 std::string rollback_de_base_dir;
272
273 protected:
274 InstalldNativeService* service;
275
276 std::string fake_package_ce_path;
277 std::string fake_package_de_path;
278
SetUp()279 virtual void SetUp() {
280 setenv("ANDROID_LOG_TAGS", "*:v", 1);
281 android::base::InitLogging(nullptr);
282
283 service = new InstalldNativeService();
284 ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
285
286 init_globals_from_data_and_root();
287
288 rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0);
289 rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0);
290
291 fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
292 fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
293
294 ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700));
295 ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700));
296 ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700));
297 ASSERT_TRUE(mkdirs(fake_package_de_path, 0700));
298 }
299
TearDown()300 virtual void TearDown() {
301 ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true));
302 ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true));
303 ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true));
304 ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true));
305
306 delete service;
307 ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true));
308 }
309 };
310
TEST_F(AppDataSnapshotTest,CreateAppDataSnapshot)311 TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) {
312 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37);
313 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37);
314
315 ASSERT_TRUE(android::base::WriteStringToFile(
316 "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
317 0700, 10000, 20000, false /* follow_symlinks */));
318 ASSERT_TRUE(android::base::WriteStringToFile(
319 "TEST_CONTENT_DE", fake_package_de_path + "/file1",
320 0700, 10000, 20000, false /* follow_symlinks */));
321
322 // Request a snapshot of the CE content but not the DE content.
323 int64_t ce_snapshot_inode;
324 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
325 "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
326 struct stat buf;
327 memset(&buf, 0, sizeof(buf));
328 ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
329 ASSERT_EQ(ce_snapshot_inode, (int64_t) buf.st_ino);
330
331 std::string ce_content, de_content;
332 // At this point, we should have the CE content but not the DE content.
333 ASSERT_TRUE(android::base::ReadFileToString(
334 rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
335 ASSERT_FALSE(android::base::ReadFileToString(
336 rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
337 ASSERT_EQ("TEST_CONTENT_CE", ce_content);
338
339 // Modify the CE content, so we can assert later that it's reflected
340 // in the snapshot.
341 ASSERT_TRUE(android::base::WriteStringToFile(
342 "TEST_CONTENT_CE_MODIFIED", fake_package_ce_path + "/file1",
343 0700, 10000, 20000, false /* follow_symlinks */));
344
345 // Request a snapshot of the DE content but not the CE content.
346 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
347 "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
348 // Only DE content snapshot was requested.
349 ASSERT_EQ(ce_snapshot_inode, 0);
350
351 // At this point, both the CE as well as the DE content should be fully
352 // populated.
353 ASSERT_TRUE(android::base::ReadFileToString(
354 rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
355 ASSERT_TRUE(android::base::ReadFileToString(
356 rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
357 ASSERT_EQ("TEST_CONTENT_CE", ce_content);
358 ASSERT_EQ("TEST_CONTENT_DE", de_content);
359
360 // Modify the DE content, so we can assert later that it's reflected
361 // in our final snapshot.
362 ASSERT_TRUE(android::base::WriteStringToFile(
363 "TEST_CONTENT_DE_MODIFIED", fake_package_de_path + "/file1",
364 0700, 10000, 20000, false /* follow_symlinks */));
365
366 // Request a snapshot of both the CE as well as the DE content.
367 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
368 "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
369
370 ASSERT_TRUE(android::base::ReadFileToString(
371 rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
372 ASSERT_TRUE(android::base::ReadFileToString(
373 rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
374 ASSERT_EQ("TEST_CONTENT_CE_MODIFIED", ce_content);
375 ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
376 }
377
TEST_F(AppDataSnapshotTest,CreateAppDataSnapshot_TwoSnapshotsWithTheSameId)378 TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) {
379 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67);
380 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67);
381
382 auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar");
383 auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar");
384
385 // Since this test sets up data for another package, some bookkeeping is required.
386 auto deleter = [&]() {
387 ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true));
388 ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true));
389 };
390 auto scope_guard = android::base::make_scope_guard(deleter);
391
392 ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700));
393 ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700));
394
395 ASSERT_TRUE(android::base::WriteStringToFile(
396 "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
397 0700, 10000, 20000, false /* follow_symlinks */));
398 ASSERT_TRUE(android::base::WriteStringToFile(
399 "TEST_CONTENT_DE", fake_package_de_path + "/file1",
400 0700, 10000, 20000, false /* follow_symlinks */));
401 ASSERT_TRUE(android::base::WriteStringToFile(
402 "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1",
403 0700, 10000, 20000, false /* follow_symlinks */));
404 ASSERT_TRUE(android::base::WriteStringToFile(
405 "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1",
406 0700, 10000, 20000, false /* follow_symlinks */));
407
408 // Request snapshot for the package com.foo.
409 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
410 "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
411 // Now request snapshot with the same id for the package com.bar
412 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
413 "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
414
415 // Check that both snapshots have correct data in them.
416 std::string com_foo_ce_content, com_foo_de_content;
417 std::string com_bar_ce_content, com_bar_de_content;
418 ASSERT_TRUE(android::base::ReadFileToString(
419 rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */));
420 ASSERT_TRUE(android::base::ReadFileToString(
421 rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */));
422 ASSERT_TRUE(android::base::ReadFileToString(
423 rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */));
424 ASSERT_TRUE(android::base::ReadFileToString(
425 rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */));
426 ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content);
427 ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content);
428 ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content);
429 ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content);
430 }
431
TEST_F(AppDataSnapshotTest,CreateAppDataSnapshot_AppDataAbsent)432 TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) {
433 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73);
434 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73);
435
436 // Similuating app data absence.
437 ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true));
438 ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
439
440 int64_t ce_snapshot_inode;
441 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
442 "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
443 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
444 "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
445 // No CE content snapshot was performed.
446 ASSERT_EQ(ce_snapshot_inode, 0);
447
448 // The snapshot calls must succeed but there should be no snapshot
449 // created.
450 struct stat sb;
451 ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
452 ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
453 }
454
TEST_F(AppDataSnapshotTest,CreateAppDataSnapshot_ClearsExistingSnapshot)455 TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
456 auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo");
457 auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo");
458
459 ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
460 ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
461
462 // Simulate presence of an existing snapshot
463 ASSERT_TRUE(android::base::WriteStringToFile(
464 "TEST_CONTENT_CE", rollback_ce_dir + "/file1",
465 0700, 10000, 20000, false /* follow_symlinks */));
466 ASSERT_TRUE(android::base::WriteStringToFile(
467 "TEST_CONTENT_DE", rollback_de_dir + "/file1",
468 0700, 10000, 20000, false /* follow_symlinks */));
469
470 // Create app data.
471 ASSERT_TRUE(android::base::WriteStringToFile(
472 "TEST_CONTENT_2_CE", fake_package_ce_path + "/file2",
473 0700, 10000, 20000, false /* follow_symlinks */));
474 ASSERT_TRUE(android::base::WriteStringToFile(
475 "TEST_CONTENT_2_DE", fake_package_de_path + "/file2",
476 0700, 10000, 20000, false /* follow_symlinks */));
477
478 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
479 "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
480
481 // Previous snapshot (with data for file1) must be cleared.
482 struct stat sb;
483 ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb));
484 ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb));
485 // New snapshot (with data for file2) must be present.
486 ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb));
487 ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb));
488 }
489
TEST_F(AppDataSnapshotTest,SnapshotAppData_WrongVolumeUuid)490 TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) {
491 // Setup rollback folders to make sure that fails due to wrong volumeUuid being
492 // passed, not because of some other reason.
493 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17);
494 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17);
495
496 ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
497 ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
498
499 EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_optional<std::string>("FOO"),
500 "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
501 }
502
TEST_F(AppDataSnapshotTest,CreateAppDataSnapshot_ClearsCache)503 TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) {
504 auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
505 auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
506 auto fake_package_de_cache_path = fake_package_de_path + "/cache";
507 auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
508
509 ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700));
510 ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700));
511 ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700));
512 ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700));
513
514 ASSERT_TRUE(android::base::WriteStringToFile(
515 "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
516 0700, 10000, 20000, false /* follow_symlinks */));
517 ASSERT_TRUE(android::base::WriteStringToFile(
518 "TEST_CONTENT_CE", fake_package_ce_code_cache_path + "/file1",
519 0700, 10000, 20000, false /* follow_symlinks */));
520 ASSERT_TRUE(android::base::WriteStringToFile(
521 "TEST_CONTENT_DE", fake_package_de_cache_path + "/file1",
522 0700, 10000, 20000, false /* follow_symlinks */));
523 ASSERT_TRUE(android::base::WriteStringToFile(
524 "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
525 0700, 10000, 20000, false /* follow_symlinks */));
526 ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
527 "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
528 // The snapshot call must clear cache.
529 struct stat sb;
530 ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
531 ASSERT_EQ(-1, stat((fake_package_ce_code_cache_path + "/file1").c_str(), &sb));
532 ASSERT_EQ(-1, stat((fake_package_de_cache_path + "/file1").c_str(), &sb));
533 ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
534 }
535
TEST_F(AppDataSnapshotTest,RestoreAppDataSnapshot)536 TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) {
537 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239);
538 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239);
539
540 ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
541 ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
542
543 // Write contents to the rollback location. We'll write the same files to the
544 // app data location and make sure the restore has overwritten them.
545 ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
546 ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
547 ASSERT_TRUE(android::base::WriteStringToFile(
548 "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
549 0700, 10000, 20000, false /* follow_symlinks */));
550 ASSERT_TRUE(android::base::WriteStringToFile(
551 "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
552 0700, 10000, 20000, false /* follow_symlinks */));
553 ASSERT_TRUE(android::base::WriteStringToFile(
554 "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
555 0700, 10000, 20000, false /* follow_symlinks */));
556 ASSERT_TRUE(android::base::WriteStringToFile(
557 "TEST_CONTENT_DE", fake_package_de_path + "/file1",
558 0700, 10000, 20000, false /* follow_symlinks */));
559
560 ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_optional<std::string>("TEST"),
561 "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
562
563 std::string ce_content, de_content;
564 ASSERT_TRUE(android::base::ReadFileToString(
565 fake_package_ce_path + "/file1", &ce_content, false /* follow_symlinks */));
566 ASSERT_TRUE(android::base::ReadFileToString(
567 fake_package_de_path + "/file1", &de_content, false /* follow_symlinks */));
568 ASSERT_EQ("CE_RESTORE_CONTENT", ce_content);
569 ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
570 }
571
TEST_F(AppDataSnapshotTest,CreateSnapshotThenDestroyIt)572 TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) {
573 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57);
574 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57);
575
576 // Prepare data for snapshot.
577 ASSERT_TRUE(android::base::WriteStringToFile(
578 "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
579 0700, 10000, 20000, false /* follow_symlinks */));
580 ASSERT_TRUE(android::base::WriteStringToFile(
581 "TEST_CONTENT_DE", fake_package_de_path + "/file1",
582 0700, 10000, 20000, false /* follow_symlinks */));
583
584 int64_t ce_snapshot_inode;
585 // Request a snapshot of both the CE as well as the DE content.
586 ASSERT_TRUE(service->snapshotAppData(std::make_optional<std::string>("TEST"),
587 "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
588 // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
589 ASSERT_NE(0, ce_snapshot_inode);
590 // Check snapshot is there.
591 struct stat sb;
592 ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
593 ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
594
595
596 ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional<std::string>("TEST"),
597 "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
598 // Check snapshot is deleted.
599 ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
600 ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
601 }
602
TEST_F(AppDataSnapshotTest,DestroyAppDataSnapshot_CeSnapshotInodeIsZero)603 TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
604 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543);
605 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543);
606
607 // Create a snapshot
608 ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
609 ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
610 ASSERT_TRUE(android::base::WriteStringToFile(
611 "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
612 0700, 10000, 20000, false /* follow_symlinks */));
613 ASSERT_TRUE(android::base::WriteStringToFile(
614 "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
615 0700, 10000, 20000, false /* follow_symlinks */));
616
617 ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional<std::string>("TEST"),
618 "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
619
620 // Check snapshot is deleted.
621 struct stat sb;
622 ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
623 ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
624
625 // Check that deleting already deleted snapshot is no-op.
626 ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional<std::string>("TEST"),
627 "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
628 }
629
TEST_F(AppDataSnapshotTest,DestroyAppDataSnapshot_WrongVolumeUuid)630 TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
631 // Setup rollback data to make sure that test fails due to wrong volumeUuid
632 // being passed, not because of some other reason.
633 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43);
634 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43);
635
636 ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
637 ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
638
639 ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_optional<std::string>("BAR"),
640 "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
641 }
642
TEST_F(AppDataSnapshotTest,DestroyCeSnapshotsNotSpecified)643 TEST_F(AppDataSnapshotTest, DestroyCeSnapshotsNotSpecified) {
644 auto rollback_ce_dir_in_1 = create_data_misc_ce_rollback_path("TEST", 0, 1543);
645 auto rollback_ce_dir_in_2 = create_data_misc_ce_rollback_path("TEST", 0, 77);
646 auto rollback_ce_dir_out_1 = create_data_misc_ce_rollback_path("TEST", 0, 1500);
647 auto rollback_ce_dir_out_2 = create_data_misc_ce_rollback_path("TEST", 0, 2);
648
649 // Create snapshots
650 ASSERT_TRUE(mkdirs(rollback_ce_dir_in_1 + "/com.foo/", 0700));
651 ASSERT_TRUE(android::base::WriteStringToFile(
652 "CE_RESTORE_CONTENT", rollback_ce_dir_in_1 + "/com.foo/file1",
653 0700, 10000, 20000, false /* follow_symlinks */));
654
655 ASSERT_TRUE(mkdirs(rollback_ce_dir_in_2 + "/com.foo/", 0700));
656 ASSERT_TRUE(android::base::WriteStringToFile(
657 "CE_RESTORE_CONTENT", rollback_ce_dir_in_2 + "/com.foo/file1",
658 0700, 10000, 20000, false /* follow_symlinks */));
659
660 ASSERT_TRUE(mkdirs(rollback_ce_dir_out_1 + "/com.foo/", 0700));
661 ASSERT_TRUE(android::base::WriteStringToFile(
662 "CE_RESTORE_CONTENT", rollback_ce_dir_out_1 + "/com.foo/file1",
663 0700, 10000, 20000, false /* follow_symlinks */));
664
665 ASSERT_TRUE(mkdirs(rollback_ce_dir_out_2 + "/com.foo/", 0700));
666 ASSERT_TRUE(android::base::WriteStringToFile(
667 "CE_RESTORE_CONTENT", rollback_ce_dir_out_2 + "/com.foo/file1",
668 0700, 10000, 20000, false /* follow_symlinks */));
669
670 ASSERT_TRUE(service->destroyCeSnapshotsNotSpecified(
671 std::make_optional<std::string>("TEST"), 0, { 1543, 77 }).isOk());
672
673 // Check only snapshots not specified are deleted.
674 struct stat sb;
675 ASSERT_EQ(0, stat((rollback_ce_dir_in_1 + "/com.foo").c_str(), &sb));
676 ASSERT_EQ(0, stat((rollback_ce_dir_in_2 + "/com.foo").c_str(), &sb));
677 ASSERT_EQ(-1, stat((rollback_ce_dir_out_1 + "/com.foo").c_str(), &sb));
678 ASSERT_EQ(ENOENT, errno);
679 ASSERT_EQ(-1, stat((rollback_ce_dir_out_2 + "/com.foo").c_str(), &sb));
680 ASSERT_EQ(ENOENT, errno);
681 }
682
TEST_F(AppDataSnapshotTest,RestoreAppDataSnapshot_WrongVolumeUuid)683 TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
684 // Setup rollback data to make sure that fails due to wrong volumeUuid being
685 // passed, not because of some other reason.
686 auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41);
687 auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41);
688
689 ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
690 ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
691
692 EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_optional<std::string>("BAR"),
693 "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
694 }
695
696 } // namespace installd
697 } // namespace android
698