1 // Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
5 #include "smoke_tests/common/smoke_utils.h"
8 #include <gum/gum-user.h>
9 #include <gum/gum-user-service.h>
10 #include <gum/common/gum-user-types.h>
11 #include <manifest_parser/utils/version_number.h>
12 #include <sys/smack.h>
15 #include <vconf-internal-keys.h>
17 #include <gtest/gtest.h>
19 #include <common/installer/app_installer.h>
20 #include <common/utils/paths.h>
21 #include <common/pkgmgr_interface.h>
22 #include <common/utils/pkgmgr_query.h>
23 #include <common/tzip_interface.h>
25 #include "pkgmgr_parser_db.h"
33 #include <system_error>
36 namespace ci = common_installer;
37 namespace fs = std::filesystem;
41 const uid_t kDefaultUserUid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
42 const gid_t kDefaultUserGid = tzplatform_getgid(TZ_SYS_DEFAULT_USER);
43 const char kNormalUserName[] = "smokeuser";
44 const char kSystemShareGroupName[] = "system_share";
45 const char kMigrateTestDBName[] = "app2sd_migrate.db";
47 const std::vector<std::string> kDBEntries = {
48 {".pkgmgr_parser.db"},
49 {".pkgmgr_parser.db-journal"},
51 {".pkgmgr_cert.db-journal"},
53 {".app2sd.db-journal"},
56 const char kGlobalManifestDir[] = "/opt/share/packages";
57 const char kSkelDir[] = "/etc/skel/apps_rw";
58 const char kPreloadApps[] = "/usr/apps";
59 const char kPreloadManifestDir[] = "/usr/share/packages";
60 const char kPreloadIcons[] = "/usr/share/icons";
61 const char kData[] = "data";
62 const char kShared[] = ".shared";
63 const char kSharedTmp[] = ".shared_tmp";
73 const char* rwDirectories[] = {
83 namespace smoke_test {
85 const char kLegacyExtImageDir[] = "legacy_extimage_dir";
86 const std::string& kDefaultUserIdStr = std::to_string(kDefaultUserUid);
87 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
88 const uid_t kGlobalUserGid = tzplatform_getgid(TZ_SYS_GLOBALAPP_USER);
89 extern const fs::path kSdkDirectory = "/home/owner/share/tmp/sdk_tools";
91 ci::RequestMode ParseRequestMode(int argc, char** argv) {
92 const struct option long_opts[] = {
93 { "request-mode", required_argument, nullptr, 'r' },
94 { "global-request", no_argument, nullptr, 'g' },
95 { "user-request", no_argument, nullptr, 'u' },
99 std::string request_mode;
100 bool is_global_request = false;
101 bool is_user_request = false;
103 int opt = getopt_long(argc, argv, "gu", long_opts, nullptr);
110 request_mode = optarg;
113 is_global_request = true;
116 is_user_request = true;
123 if (is_global_request) {
124 std::cout << "Request mode was set to global." << std::endl;
125 return ci::RequestMode::GLOBAL;
127 if (is_user_request) {
128 std::cout << "Request mode was set to user." << std::endl;
129 return ci::RequestMode::USER;
131 if (!request_mode.empty()) {
132 if (request_mode.compare("global") == 0) {
133 std::cout << "Request mode was set to global." << std::endl;
134 return ci::RequestMode::GLOBAL;
136 if (request_mode.compare("user") == 0) {
137 std::cout << "Request mode was set to user." << std::endl;
138 return ci::RequestMode::USER;
140 std::cout << "Cannot set request mode to "
141 << request_mode << std::endl;
143 std::cout << "Request mode was set to global." << std::endl;
144 return ci::RequestMode::GLOBAL;
147 static bool AddUser(const char* user_name) {
148 GumUser* user = nullptr;
149 user = gum_user_create_sync(FALSE);
151 LOG(WARNING) << "Failed to create gum user! (user name: "
153 g_object_set(G_OBJECT(user), "username", user_name, "usertype",
154 GUM_USERTYPE_NORMAL, NULL);
155 gboolean rval = FALSE;
156 rval = gum_user_add_sync(user);
157 g_object_unref(user);
161 static bool DeleteUser(const char* user_name, bool rem_home_dir) {
163 GumUser* guser = gum_user_get_by_name_sync(user_name, FALSE);
165 rval = gum_user_delete_sync(guser, rem_home_dir);
169 bool AddTestUser(User* test_user) {
170 std::cout << "Adding test user: " << kNormalUserName << std::endl;
171 AddUser(kNormalUserName);
172 if (std::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName)) {
173 test_user->uid = *uid;
174 std::cout << "User created properly: uid=" << *uid;
175 if (std::optional<gid_t> gid = ci::GetGidByUid(*uid)) {
176 test_user->gid = *gid;
177 std::cout << " gid=" << *gid;
179 std::cout << std::endl;
182 LOG(ERROR) << "Adding test user failed";
186 bool DeleteTestUser() {
187 std::cout << "Deleting test user: " << kNormalUserName << std::endl;
189 if (std::optional<uid_t> uid = ci::GetUidByUserName(kNormalUserName))
193 DeleteUser(kNormalUserName, true);
194 if (!ci::GetUidByUserName(kNormalUserName)) {
195 std::cout << "User deleted properly: user_name=" << kNormalUserName
196 << " uid=" << test_uid << std::endl;
199 LOG(ERROR) << "Deleting test user failed";
203 bool TouchFile(const fs::path& path) {
204 FILE* f = fopen(path.c_str(), "w+");
211 void AddDataFiles(const std::string& pkgid, uid_t uid,
212 std::vector<fs::path>* result) {
213 std::vector<fs::path> files;
215 if (uid == kGlobalUserUid) {
216 ci::UserList list = ci::GetUserList();
217 for (auto l : list) {
218 auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
219 files.emplace_back(pkg_path / "data" / "file1.txt");
220 files.emplace_back(pkg_path / "data" / "file2.txt");
223 auto pkg_path = GetPackageRoot(pkgid, uid);
224 files.emplace_back(pkg_path / "data" / "file1.txt");
225 files.emplace_back(pkg_path / "data" / "file2.txt");
228 for (const auto& path : files)
229 ASSERT_TRUE(TouchFile(path));
232 *result = std::move(files);
235 void RemoveAllRecoveryFiles(const std::string& prefix, uid_t uid) {
236 fs::path root_path = ci::GetRootAppPath(false, uid);
237 if (!fs::exists(root_path))
239 for (auto& dir_entry : fs::directory_iterator(root_path)) {
240 if (fs::is_regular_file(dir_entry)) {
241 if (dir_entry.path().string().find(prefix) != std::string::npos) {
242 std::error_code error;
243 fs::remove(dir_entry, error);
245 LOG(ERROR) << "Failed to remove " << dir_entry
246 << ": " << error.message();
252 fs::path FindRecoveryFile(const std::string& prefix, uid_t uid) {
253 fs::path root_path = ci::GetRootAppPath(false, uid);
254 if (!fs::exists(root_path))
257 for (auto& dir_entry : fs::directory_iterator(root_path)) {
258 if (fs::is_regular_file(dir_entry)) {
259 if (dir_entry.path().string().find(prefix) != std::string::npos) {
267 std::unique_ptr<ci::recovery::RecoveryFile> GetRecoverFileInfo(
268 const fs::path& recovery_file_path) {
269 return ci::recovery::RecoveryFile::OpenRecoveryFile(recovery_file_path);
272 fs::path GetPackageRoot(const std::string& pkgid, uid_t uid) {
273 fs::path root_path = ci::GetRootAppPath(false, uid);
274 return root_path / pkgid;
277 bool ValidateFileContentInPackage(const std::string& pkgid,
278 const std::string& relative,
279 const std::string& expected,
280 const TestParameters& params) {
281 fs::path file_path = ci::GetRootAppPath(params.is_readonly,
282 params.test_user.uid);
283 file_path = file_path / pkgid / relative;
284 if (!fs::exists(file_path)) {
285 LOG(ERROR) << file_path << " doesn't exist";
288 FILE* handle = fopen(file_path.c_str(), "r");
290 LOG(ERROR) << file_path << " cannot be open";
294 std::array<char, 200> buffer;
295 while (fgets(buffer.data(), buffer.size(), handle)) {
296 content += buffer.data();
299 return content == expected;
302 static bool ValidatePackageRWFS(const std::string& pkgid, uid_t uid) {
303 fs::path root_path = ci::GetRootAppPath(false, uid);
304 fs::path package_path = root_path / pkgid;
305 fs::path data_path = package_path / rwDirectories[DATA];
306 fs::path cache_path = package_path / rwDirectories[CACHE];
307 fs::path shared_data_path = package_path / rwDirectories[SHARED_DATA];
309 EXTENDED_ASSERT_TRUE(fs::exists(data_path));
310 EXTENDED_ASSERT_TRUE(fs::exists(cache_path));
313 stat(data_path.c_str(), &stats);
314 // gid of RW dirs should be system_share
315 std::optional<gid_t> system_share =
316 ci::GetGidByGroupName(kSystemShareGroupName);
317 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
318 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
319 if (fs::exists(shared_data_path)) {
320 stat(shared_data_path.c_str(), &stats);
321 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
322 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
325 stat(cache_path.c_str(), &stats);
326 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
327 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
331 static bool ValidatePackageFS(const std::string& pkgid, const Apps& apps,
332 const TestParameters& params) {
333 fs::path root_path = ci::GetRootAppPath(params.is_readonly,
334 params.test_user.uid);
335 fs::path package_path = root_path / pkgid;
336 fs::path shared_path = package_path / "shared";
337 EXTENDED_ASSERT_TRUE(fs::exists(root_path));
338 EXTENDED_ASSERT_TRUE(fs::exists(package_path));
339 EXTENDED_ASSERT_TRUE(fs::exists(shared_path));
341 fs::path manifest_path =
342 fs::path(getUserManifestPath(params.test_user.uid,
343 params.is_readonly)) / (pkgid + ".xml");
344 EXTENDED_ASSERT_TRUE(fs::exists(manifest_path));
346 for (auto& app : apps) {
347 const std::string &exec = app.second;
348 fs::path binary_path = package_path / "bin" / exec;
349 EXTENDED_ASSERT_TRUE(fs::exists(binary_path));
352 if (params.pkg_type == PackageType::WGT ||
353 params.pkg_type == PackageType::HYBRID) {
354 fs::path widget_root_path = package_path / "res" / "wgt";
355 fs::path config_path = widget_root_path / "config.xml";
356 EXTENDED_ASSERT_TRUE(fs::exists(widget_root_path));
357 EXTENDED_ASSERT_TRUE(fs::exists(config_path));
359 fs::path private_tmp_path = package_path / "tmp";
360 EXTENDED_ASSERT_TRUE(fs::exists(private_tmp_path));
363 // backups should not exist
364 fs::path package_backup = ci::GetBackupPathForPackagePath(package_path);
365 fs::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
366 EXTENDED_ASSERT_FALSE(fs::exists(package_backup));
367 EXTENDED_ASSERT_FALSE(fs::exists(manifest_backup));
369 for (fs::recursive_directory_iterator iter(package_path);
370 iter != fs::recursive_directory_iterator(); ++iter) {
371 if (fs::is_symlink(symlink_status(iter->path())))
373 bool is_rw_dir = false;
374 for (const auto rw_dir : rwDirectories) {
375 fs::path rw_dir_path = rw_dir;
376 is_rw_dir |= ci::MakeRelativePath(iter->path(), package_path)
379 if (is_rw_dir || iter->path().filename() == ".mmc") {
380 iter.disable_recursion_pending();
384 stat(iter->path().c_str(), &stats);
385 EXTENDED_ASSERT_EQ(params.test_user.uid, stats.st_uid);
386 EXTENDED_ASSERT_EQ(params.test_user.gid, stats.st_gid);
391 bool ValidatePackage(const std::string& pkgid, const Apps& apps,
392 const TestParameters& params) {
393 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
394 EXTENDED_ASSERT_TRUE(pkg_query.IsPackageInstalled(
395 ci::GetRequestMode(params.test_user.uid)));
396 EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, apps, params));
397 if (params.test_user.uid == kGlobalUserUid) {
398 ci::UserList list = ci::GetUserList();
400 EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, std::get<0>(l)));
402 EXTENDED_ASSERT_TRUE(ValidatePackageRWFS(pkgid, params.test_user.uid));
407 bool ValidateDataFiles(const std::string& pkgid, uid_t uid) {
408 if (uid == kGlobalUserUid) {
409 ci::UserList list = ci::GetUserList();
410 for (auto l : list) {
411 auto pkg_path = GetPackageRoot(pkgid, std::get<0>(l));
412 EXTENDED_ASSERT_TRUE(fs::exists(pkg_path / "data" / "file1.txt"));
413 EXTENDED_ASSERT_TRUE(fs::exists(pkg_path / "data" / "file2.txt"));
416 auto pkg_path = GetPackageRoot(pkgid, uid);
417 EXTENDED_ASSERT_TRUE(fs::exists(pkg_path / "data" / "file1.txt"));
418 EXTENDED_ASSERT_TRUE(fs::exists(pkg_path / "data" / "file2.txt"));
423 static bool ValidateExternalPackageFS(const std::string& pkgid,
424 const Apps& apps, const TestParameters& params) {
425 EXTENDED_ASSERT_EQ(app2ext_usr_enable_external_pkg(pkgid.c_str(),
426 params.test_user.uid), 0);
427 fs::path root_path = ci::GetRootAppPath(false, params.test_user.uid);
428 if (params.pkg_type == PackageType::TPK) {
429 EXTENDED_ASSERT_TRUE(fs::exists(root_path / pkgid / ".mmc" / "bin"));
430 EXTENDED_ASSERT_TRUE(fs::exists(root_path / pkgid / ".mmc" / "lib"));
432 EXTENDED_ASSERT_TRUE(fs::exists(root_path / pkgid / ".mmc" / "res"));
433 EXTENDED_ASSERT_TRUE(ValidatePackageFS(pkgid, apps, params));
434 EXTENDED_ASSERT_EQ(app2ext_usr_disable_external_pkg(pkgid.c_str(),
435 params.test_user.uid), 0);
439 bool ValidateExternalPackage(const std::string& pkgid, const Apps& apps,
440 const TestParameters& params) {
441 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
442 std::string storage = pkg_query.StorageForPkgId();
443 fs::path ext_mount_path = ci::GetExternalCardPath();
444 if (fs::is_empty(ext_mount_path)) {
445 LOG(INFO) << "Sdcard not exists!";
446 EXTENDED_ASSERT_EQ(storage, "installed_internal");
448 EXTENDED_ASSERT_EQ(storage, "installed_external");
450 EXTENDED_ASSERT_TRUE(ValidateExternalPackageFS(pkgid, apps, params));
454 bool ValidateExtendedPackage(const std::string& pkgid, const Apps& apps,
455 const TestParameters& params) {
456 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
457 std::string storage = pkg_query.StorageForPkgId();
458 fs::path extended_path =
459 fs::path(ci::GetExtendedRootAppPath(params.test_user.uid)) / pkgid;
460 if (!fs::exists(extended_path)) {
461 LOG(INFO) << "Extended storage not exists!";
462 EXTENDED_ASSERT_EQ(storage, "installed_internal");
464 EXTENDED_ASSERT_EQ(storage, "installed_extended");
466 EXTENDED_ASSERT_TRUE(ValidatePackage(pkgid, apps, params));
470 static bool PackageCheckCleanup(const std::string& pkgid,
471 const TestParameters& params) {
472 fs::path root_path = ci::GetRootAppPath(params.is_readonly,
473 params.test_user.uid);
474 fs::path package_path = root_path / pkgid;
475 EXTENDED_ASSERT_FALSE(fs::exists(package_path));
477 fs::path manifest_path = fs::path(getUserManifestPath(params.test_user.uid,
478 params.is_readonly)) / (pkgid + ".xml");
479 EXTENDED_ASSERT_FALSE(fs::exists(manifest_path));
481 // backups should not exist
482 fs::path package_backup = ci::GetBackupPathForPackagePath(package_path);
483 fs::path manifest_backup = ci::GetBackupPathForManifestFile(manifest_path);
484 EXTENDED_ASSERT_FALSE(fs::exists(package_backup));
485 EXTENDED_ASSERT_FALSE(fs::exists(manifest_backup));
489 bool CheckPackageNonExistance(const std::string& pkgid,
490 const TestParameters& params) {
491 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
492 EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
493 ci::GetRequestMode(params.test_user.uid)));
494 EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
495 if (params.test_user.uid == kGlobalUserUid) {
496 fs::path skel_path(kSkelDir);
497 EXTENDED_ASSERT_FALSE(fs::exists(skel_path / pkgid));
498 EXTENDED_ASSERT_FALSE(fs::exists(skel_path / kShared / pkgid));
499 EXTENDED_ASSERT_FALSE(fs::exists(skel_path / kSharedTmp / pkgid));
500 ci::UserList list = ci::GetUserList();
501 for (auto& l : list) {
502 fs::path root_path = ci::GetRootAppPath(false, std::get<0>(l));
503 EXTENDED_ASSERT_FALSE(fs::exists(root_path / kShared / pkgid));
504 EXTENDED_ASSERT_FALSE(fs::exists(root_path / kSharedTmp / pkgid));
505 fs::path package_path = root_path / pkgid;
506 EXTENDED_ASSERT_FALSE(fs::exists(package_path));
512 bool CheckAvailableExternalPath() {
513 fs::path ext_mount_path = ci::GetExternalCardPath();
514 LOG(DEBUG) << "ext_mount_path :" << ext_mount_path;
515 if (ext_mount_path.empty()) {
516 LOG(ERROR) << "Sdcard not exists!";
522 bool CheckAvailableExtendedPath() {
523 fs::path extended_path = fs::path(tzplatform_getenv(TZ_SYS_EXTENDEDSD));
524 LOG(DEBUG) << "extended_path :" << extended_path;
525 // TODO(jeremy.jang): It should be checked by libstorage API.
526 if (!fs::exists(extended_path)) {
527 LOG(ERROR) << "Extended storage not exists!";
533 bool CheckPackageReadonlyNonExistance(const std::string& pkgid,
534 const TestParameters& params) {
535 ci::PkgQueryInterface pkg_query(pkgid, params.test_user.uid, true);
536 EXTENDED_ASSERT_FALSE(pkg_query.IsPackageInstalled(
537 ci::GetRequestMode(params.test_user.uid)));
538 EXTENDED_ASSERT_TRUE(PackageCheckCleanup(pkgid, params));
542 static bool CheckSharedDataExistanceForPath(const fs::path& apps_rw,
543 const std::string& pkgid) {
544 fs::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
545 fs::path shared = apps_rw / kShared / pkgid / kData;
546 fs::path shared_tmp = apps_rw / kSharedTmp / pkgid;
547 EXTENDED_ASSERT_TRUE(fs::exists(shared_data_path));
548 EXTENDED_ASSERT_TRUE(fs::exists(shared));
549 EXTENDED_ASSERT_TRUE(fs::exists(shared_tmp));
553 static bool CheckSharedDataPermissions(const fs::path& apps_rw,
554 const std::string& pkgid, uid_t uid) {
555 fs::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
556 fs::path shared = apps_rw / kShared / pkgid / kData;
557 fs::path shared_tmp = apps_rw / kSharedTmp / pkgid;
558 // gid of RW dirs should be system_share
559 std::optional<gid_t> system_share =
560 ci::GetGidByGroupName(kSystemShareGroupName);
562 stat(shared_data_path.c_str(), &stats);
563 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
564 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
565 stat(shared.c_str(), &stats);
566 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
567 EXTENDED_ASSERT_EQ(*system_share, stats.st_gid);
568 stat(shared_tmp.c_str(), &stats);
569 EXTENDED_ASSERT_EQ(uid, stats.st_uid);
570 EXTENDED_ASSERT_EQ(kDefaultUserGid, stats.st_gid);
574 bool CheckSharedDataExistance(const std::string& pkgid,
575 const TestParameters& params) {
576 if (params.test_user.uid == kGlobalUserUid) {
577 fs::path skel_path(kSkelDir);
578 EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(kSkelDir, pkgid));
579 ci::UserList list = ci::GetUserList();
580 for (auto& l : list) {
581 uid_t uid = std::get<0>(l);
582 fs::path apps_rw = ci::GetRootAppPath(false, uid);
583 EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(apps_rw, pkgid));
584 EXTENDED_ASSERT_TRUE(CheckSharedDataPermissions(apps_rw, pkgid, uid));
587 fs::path apps_rw = ci::GetRootAppPath(false, params.test_user.uid);
588 EXTENDED_ASSERT_TRUE(CheckSharedDataExistanceForPath(apps_rw, pkgid));
589 EXTENDED_ASSERT_TRUE(
590 CheckSharedDataPermissions(apps_rw, pkgid, params.test_user.uid));
595 static bool CheckSharedDataNonExistanceForPath(const fs::path& apps_rw,
596 const std::string pkgid) {
597 fs::path shared_data_path = apps_rw / pkgid / rwDirectories[SHARED_DATA];
598 fs::path shared = apps_rw / kShared / pkgid / kData;
599 fs::path shared_tmp = apps_rw / kSharedTmp / pkgid;
600 EXTENDED_ASSERT_FALSE(fs::exists(shared_data_path));
601 EXTENDED_ASSERT_FALSE(fs::exists(shared));
602 EXTENDED_ASSERT_FALSE(fs::exists(shared_tmp));
606 bool CheckSharedDataNonExistance(const std::string& pkgid,
607 const TestParameters& params) {
608 if (params.test_user.uid == kGlobalUserUid) {
609 fs::path skel_path(kSkelDir);
610 EXTENDED_ASSERT_TRUE(
611 CheckSharedDataNonExistanceForPath(skel_path, pkgid));
613 ci::UserList list = ci::GetUserList();
614 for (auto& l : list) {
615 uid_t uid = std::get<0>(l);
616 fs::path apps_rw = ci::GetRootAppPath(false, uid);
617 EXTENDED_ASSERT_TRUE(CheckSharedDataNonExistanceForPath(apps_rw, pkgid));
620 fs::path apps_rw = ci::GetRootAppPath(false, params.test_user.uid);
621 EXTENDED_ASSERT_TRUE(CheckSharedDataNonExistanceForPath(apps_rw, pkgid));
626 void FileInfoCollector::AddPath(const fs::path& path) {
627 root_paths_.emplace_back(path);
630 bool FileInfoCollector::CollectFileInfoRecursive() {
631 for (const auto& path : root_paths_) {
632 if (!fs::exists(path) && !fs::is_symlink(path))
635 if (!GetFileListTraversal(path))
642 bool FileInfoCollector::GetFileListTraversal(const fs::path& cur) {
643 std::error_code error;
644 fs::file_status file_status = fs::symlink_status(cur, error);
646 LOG(ERROR) << "Fail to get symlink_status, " << error.message();
651 if (lstat(cur.c_str(), &info) != 0) {
652 LOG(ERROR) << "Fail to lstat from [" << cur << "]";
656 std::string owner = ci::GetUsernameByUid(info.st_uid);
657 std::string group = ci::GetGroupNameByGid(info.st_gid);
659 char* access_label = nullptr;
660 if (smack_lgetlabel(cur.c_str(), &access_label, SMACK_LABEL_ACCESS) < 0) {
661 LOG(ERROR) << "Fail to get access label from [" << cur << "]";
665 if (access_label == nullptr) {
666 LOG(ERROR) << "Fail to get access label from [" << cur << "]";
670 FileInfos_.emplace_back(cur, file_status.type(),
671 file_status.permissions(), owner, group, access_label);
673 if (!fs::is_directory(cur) || fs::is_symlink(cur))
676 for (fs::directory_iterator file(cur);
677 file != fs::directory_iterator();
679 if (!GetFileListTraversal(file->path())) {
688 bool FileInfoCollector::FileInfoToFile(const fs::path& path) const {
689 std::ofstream out(path.string());
691 for (const auto& info : FileInfos_)
692 out << FileInfoToString(info) << std::endl;
699 bool FileInfoCollector::Init() {
700 fs::path skel_apps_rw = fs::path(kSkelDir);
702 ci::GetRootAppPath(params_.is_readonly, params_.test_user.uid);
704 AddPath(root_path / pkgid_);
705 AddPath(skel_apps_rw / pkgid_);
707 if (params_.test_user.uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) {
709 ci::UserList list = ci::GetUserList();
710 for (auto l : list) {
711 fs::path apps_rw = std::get<2>(l) / "apps_rw";
712 AddPath(apps_rw / pkgid_);
713 AddPath(apps_rw / kShared / pkgid_);
714 AddPath(apps_rw / kSharedTmp / pkgid_);
717 AddPath(root_path / kShared / pkgid_);
718 AddPath(root_path / kSharedTmp / pkgid_);
721 if (!CollectFileInfoRecursive())
724 std::sort(FileInfos_.begin(), FileInfos_.end(),
725 [](const FileInfo& l, const FileInfo& r) -> bool {
726 return std::get<0>(l) < std::get<0>(r);
732 bool FileInfoCollector::LoadFromFile(const fs::path& path) {
733 std::ifstream readFile;
734 readFile.open(path.c_str());
736 if (!readFile.is_open()) {
737 LOG(ERROR) << "Fail to read file : " << path;
743 while (std::getline(readFile, line)) {
744 std::istringstream iss(line);
750 std::string access_label;
752 iss >> p >> file_type >> std::oct >> file_permission
753 >> owner >> group >> access_label;
755 FileInfos_.emplace_back(p, fs::file_type(file_type),
756 fs::perms(file_permission), owner, group, access_label);
764 std::string FileInfoCollector::FileTypeToString(const fs::file_type type) const {
766 case fs::file_type::none:
768 case fs::file_type::not_found:
770 case fs::file_type::regular:
772 case fs::file_type::directory:
774 case fs::file_type::symlink:
776 case fs::file_type::block:
778 case fs::file_type::character:
780 case fs::file_type::fifo:
782 case fs::file_type::socket:
784 case fs::file_type::unknown:
787 return "implementation-defined";
791 int FileInfoCollector::PermsToInt(const fs::perms p) const {
794 perm_int |= fs::perms::none == (p & fs::perms::owner_read) ? 0 : 0400;
795 perm_int |= fs::perms::none == (p & fs::perms::owner_write) ? 0 : 0200;
796 perm_int |= fs::perms::none == (p & fs::perms::owner_exec) ? 0 : 0100;
797 perm_int |= fs::perms::none == (p & fs::perms::group_read) ? 0 : 040;
798 perm_int |= fs::perms::none == (p & fs::perms::group_write) ? 0 : 020;
799 perm_int |= fs::perms::none == (p & fs::perms::group_exec) ? 0 : 010;
800 perm_int |= fs::perms::none == (p & fs::perms::others_read) ? 0 : 04;
801 perm_int |= fs::perms::none == (p & fs::perms::others_write) ? 0 : 02;
802 perm_int |= fs::perms::none == (p & fs::perms::others_exec) ? 0 : 01;
807 std::string FileInfoCollector::FileInfoToString(
808 const FileInfo& file_info) const {
809 fs::path p = std::get<0>(file_info);
810 fs::file_type file_type = std::get<1>(file_info);
811 std::string file_permission;
812 std::string owner = std::get<3>(file_info);
813 std::string group = std::get<4>(file_info);
814 std::string access_label = std::get<5>(file_info);
815 std::stringstream ss;
816 ss << std::oct << PermsToInt(std::get<2>(file_info));
817 ss >> file_permission;
822 res += FileTypeToString(file_type);
824 res += file_permission;
835 bool FileInfoCollector::IsEqual(const FileInfoCollector& that,
836 const std::vector<fs::path>* exception_list) const {
837 auto it_l = FileInfos_.begin();
838 auto it_r = that.FileInfos_.begin();
841 while (it_l != FileInfos_.end() && it_r != that.FileInfos_.end()) {
842 if (*it_l == *it_r) {
848 fs::path path_l = std::get<0>(*it_l);
849 fs::path path_r = std::get<0>(*it_r);
850 if (exception_list && path_l == path_r &&
851 std::find(exception_list->begin(), exception_list->end(), path_r)
852 != exception_list->end()) {
860 if (path_l > path_r) {
861 LOG(ERROR) << "There is an unexpected file [" << path_r << "]";
863 } else if (path_l < path_r) {
864 LOG(ERROR) << "There is not exists an expected file [" << path_l << "]";
867 LOG(ERROR) << "There is a different status file. expected ["
868 << FileInfoToString(*it_l) << "], result ["
869 << FileInfoToString(*it_r) << "]";
875 while (it_l != FileInfos_.end()) {
876 LOG(ERROR) << "There is an unexpected file [" << std::get<0>(*it_l) << "]";
881 while (it_r != that.FileInfos_.end()) {
882 LOG(ERROR) << "There is not exists an expected file ["
883 << std::get<0>(*it_r) << "]";
891 void BackendInterface::TestRollbackAfterEachStep(int argc, const char* argv[],
892 std::function<bool()> validator) const {
893 ci::Subprocess backend_helper = CreateSubprocess();
894 bool result = backend_helper.RunFunc({[&]() -> int {
895 TestPkgmgrInstaller pkgmgr_installer;
896 std::shared_ptr<ci::AppQueryInterface> query_interface =
897 CreateQueryInterface();
899 ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
903 LOG(ERROR) << "Failed to initialize pkgmgr interface";
906 AppInstallerPtr backend;
907 unsigned int insert_idx = 0;
909 backend = CreateFailExpectedInstaller(pkgmgr, insert_idx);
910 LOG(DEBUG) << "StepFail is inserted at: " << insert_idx;
911 ci::AppInstaller::Result ret = backend->Run();
912 if (ret != ci::AppInstaller::Result::ERROR) {
913 LOG(ERROR) << "StepFail not executed";
917 LOG(ERROR) << "Fail to validate. index of StepFail : " << insert_idx;
921 } while (insert_idx < backend->StepCount());
922 if (insert_idx != backend->StepCount())
927 ASSERT_EQ(result, true);
928 int status = backend_helper.Wait();
929 ASSERT_NE(WIFEXITED(status), 0);
930 ASSERT_EQ(WEXITSTATUS(status), 0);
933 void BackendInterface::CrashAfterEachStep(std::vector<std::string>* args,
934 std::function<bool(int iter)> validator, PackageType type) const {
935 ci::Subprocess backend_helper = CreateSubprocess();
936 bool result = backend_helper.RunFunc({[&]() {
937 std::unique_ptr<const char*[]> argv(new const char*[args->size()]);
938 for (size_t i = 0; i < args->size(); ++i) {
939 argv[i] = args->at(i).c_str();
941 TestPkgmgrInstaller pkgmgr_installer;
942 auto query_interface = CreateQueryInterface();
943 auto pkgmgr = ci::PkgMgrInterface::Create(args->size(),
944 const_cast<char**>(argv.get()), &pkgmgr_installer, query_interface);
946 LOG(ERROR) << "Failed to initialize pkgmgr interface";
949 auto backend = CreateFailExpectedInstaller(pkgmgr, 0);
950 if (backend->Run() != ci::AppInstaller::Result::ERROR) {
951 LOG(ERROR) << "StepFail not executed";
954 int stepCount = backend->StepCount();
956 args->push_back("-idx");
957 args->push_back(std::to_string(stepCount));
959 std::string prefix = (type == PackageType::TPK) ? "tpk" : "wgt";
960 for (insert_idx = 0; insert_idx < stepCount; insert_idx++) {
961 ci::Subprocess backend_crash(
962 "/usr/bin/" + prefix + "-installer-ut/smoke-test-helper");
963 args->back() = std::to_string(insert_idx);
964 backend_crash.Run(*args);
965 if (backend_crash.Wait() == 0) {
966 LOG(ERROR) << "Subprocess exit without crash";
969 if (!validator(insert_idx)) {
970 LOG(ERROR) << "Fail to validate. index of StepCrash : " << insert_idx;
974 if (stepCount != insert_idx)
977 args->push_back("-type_clean");
978 for (insert_idx = stepCount - 1; insert_idx >= 2; insert_idx--) {
979 ci::Subprocess backend_crash(
980 "/usr/bin/" + prefix + "-installer-ut/smoke-test-helper");
981 auto it = args->end();
983 *it = std::to_string(insert_idx);
984 backend_crash.Run(*args);
985 if (backend_crash.Wait() == 0) {
986 LOG(ERROR) << "Subprocess exit without crash";
989 if (!validator(insert_idx)) {
990 LOG(ERROR) << "Fail to validate. index of StepCrash : " << insert_idx;
1000 ASSERT_EQ(result, true);
1001 int status = backend_helper.Wait();
1002 ASSERT_NE(WIFEXITED(status), 0);
1003 ASSERT_EQ(WEXITSTATUS(status), 0);
1006 BackendInterface::CommandResult BackendInterface::RunInstallersWithPkgmgr(
1007 ci::PkgMgrPtr pkgmgr) const {
1008 std::list<AppInstallerPtr> installers;
1009 for (int i = 0; i < pkgmgr->GetRequestInfoCount(); i++) {
1010 AppInstallerPtr installer;
1011 if (mode_ == RequestResult::FAIL && i == pkgmgr->GetRequestInfoCount() - 1)
1012 installer = factory_->CreateFailExpectedInstaller(i, pkgmgr);
1014 installer = factory_->CreateInstaller(i, pkgmgr);
1016 LOG(ERROR) << "Failed to create installer";
1018 installers.emplace_back(std::move(installer));
1021 // FIXME: I think we should not implement this logic here...
1022 CommandResult result = CommandResult::OK;
1023 std::list<AppInstallerPtr>::iterator it(installers.begin());
1024 for (; it != installers.end(); ++it) {
1025 result = (*it)->Process();
1026 if (result != CommandResult::OK)
1029 if (it != installers.end() && result == CommandResult::ERROR) {
1031 CommandResult ret = (*it)->Undo();
1032 if (ret != CommandResult::OK && ret != CommandResult::ERROR)
1033 result = CommandResult::UNDO_ERROR;
1034 } while (it-- != installers.begin());
1038 if ((*it)->Clean() != CommandResult::OK)
1039 result = CommandResult::CLEANUP_ERROR;
1040 } while (it-- != installers.begin());
1045 BackendInterface::CommandResult BackendInterface::CallBackendWithRunner(
1046 int argc, const char* argv[]) const {
1047 TestPkgmgrInstaller pkgmgr_installer;
1048 auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
1051 LOG(ERROR) << "Failed to initialize pkgmgr interface";
1052 return BackendInterface::CommandResult::UNKNOWN;
1054 return RunInstallersWithPkgmgr(pkgmgr);
1057 BackendInterface::CommandResult BackendInterface::Install(
1058 const std::vector<fs::path>& paths) const {
1059 std::vector<const char*> argv;
1060 argv.emplace_back("");
1061 argv.emplace_back("-i");
1062 for (const auto& p : paths)
1063 argv.emplace_back(p.c_str());
1064 return CallBackendWithRunner(argv.size(), argv.data());
1067 BackendInterface::CommandResult BackendInterface::Uninstall(
1068 const std::vector<std::string>& pkgids) const {
1069 std::vector<const char*> argv;
1070 argv.emplace_back("");
1071 argv.emplace_back("-d");
1072 for (const auto& p : pkgids)
1073 argv.emplace_back(p.c_str());
1074 return CallBackendWithRunner(argv.size(), argv.data());
1077 BackendInterface::CommandResult BackendInterface::InstallSuccess(
1078 const std::vector<fs::path>& paths) const {
1079 RequestResult tmp_mode = mode_;
1080 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1081 original_mode = RequestResult::NORMAL;
1082 if (Install(paths) != BackendInterface::CommandResult::OK) {
1083 LOG(ERROR) << "Failed to install application. Cannot update";
1084 return BackendInterface::CommandResult::UNKNOWN;
1086 original_mode = tmp_mode;
1087 return BackendInterface::CommandResult::OK;
1090 BackendInterface::CommandResult BackendInterface::RunInstallerWithPkgrmgr(
1091 ci::PkgMgrPtr pkgmgr) const {
1092 std::unique_ptr<ci::AppInstaller> installer;
1094 case RequestResult::FAIL:
1095 installer = CreateFailExpectedInstaller(pkgmgr);
1098 installer = CreateInstaller(pkgmgr);
1101 return installer->Run();
1104 BackendInterface::CommandResult BackendInterface::CallBackend(int argc,
1105 const char* argv[]) const {
1106 TestPkgmgrInstaller pkgmgr_installer;
1107 auto query_interface = CreateQueryInterface();
1108 auto pkgmgr = ci::PkgMgrInterface::Create(argc, const_cast<char**>(argv),
1109 &pkgmgr_installer, query_interface);
1111 LOG(ERROR) << "Failed to initialize pkgmgr interface";
1112 return BackendInterface::CommandResult::UNKNOWN;
1114 return RunInstallerWithPkgrmgr(pkgmgr);
1117 BackendInterface::CommandResult BackendInterface::Install(
1118 const fs::path& path) const {
1119 const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
1120 return CallBackend(SIZEOFARRAY(argv), argv);
1123 BackendInterface::CommandResult BackendInterface::InstallPreload(
1124 const fs::path& path) const {
1125 const char* argv[] = {"", "-i", path.c_str(), "--preload"};
1126 return CallBackend(SIZEOFARRAY(argv), argv);
1129 BackendInterface::CommandResult BackendInterface::InstallWithStorage(
1130 const fs::path& path, StorageType type) const {
1131 int default_storage = 0;
1134 case StorageType::EXTERNAL:
1137 case StorageType::EXTENDED:
1141 LOG(ERROR) << "Unknown storage type";
1144 if (vconf_get_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
1145 &default_storage) != 0) {
1146 LOG(ERROR) << "Failed to get value of "
1147 "VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT";
1148 return BackendInterface::CommandResult::ERROR;
1150 if (vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
1152 LOG(ERROR) << "Failed to set value of "
1153 "VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT";
1154 return BackendInterface::CommandResult::ERROR;
1157 const char* argv[] = {"", "-i", path.c_str(), "-u", uid_str_.c_str()};
1158 BackendInterface::CommandResult result = CallBackend(SIZEOFARRAY(argv), argv);
1160 if (vconf_set_int(VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT,
1161 default_storage) != 0) {
1162 LOG(ERROR) << "Failed to set value of "
1163 "VCONFKEY_SETAPPL_DEFAULT_MEM_INSTALL_APPLICATIONS_INT";
1164 return BackendInterface::CommandResult::ERROR;
1170 BackendInterface::CommandResult BackendInterface::MigrateLegacyExternalImage(
1171 const std::string& pkgid,
1172 const fs::path& path,
1173 const fs::path& legacy_path) const {
1174 if (InstallWithStorage(path, StorageType::EXTERNAL) !=
1175 BackendInterface::CommandResult::OK) {
1176 LOG(ERROR) << "Failed to install application. Cannot perform Migrate";
1177 return BackendInterface::CommandResult::ERROR;
1180 fs::path ext_mount_path = ci::GetExternalCardPath();
1181 if (fs::is_empty(ext_mount_path)) {
1182 LOG(ERROR) << "Sdcard not exists!";
1183 return BackendInterface::CommandResult::ERROR;
1185 fs::path app2sd_path = ext_mount_path / "app2sd";
1187 char* image_name = app2ext_usr_getname_image(pkgid.c_str(),
1190 LOG(ERROR) << "Failed to get external image name";
1191 return BackendInterface::CommandResult::ERROR;
1193 fs::path org_image = app2sd_path / image_name;
1196 std::error_code error;
1197 fs::remove(org_image, error);
1199 LOG(ERROR) << "Failed to remove org image";
1200 return BackendInterface::CommandResult::ERROR;
1203 fs::path db_path = tzplatform_getenv(TZ_SYS_DB);
1204 fs::path app2sd_db = db_path / ".app2sd.db";
1205 fs::path app2sd_db_journal = db_path / ".app2sd.db-journal";
1206 fs::remove(app2sd_db, error);
1208 LOG(ERROR) << "Failed to remove app2sd db";
1209 return BackendInterface::CommandResult::ERROR;
1211 fs::remove(app2sd_db_journal, error);
1213 LOG(ERROR) << "Failed to remove app2sd journal db";
1214 return BackendInterface::CommandResult::ERROR;
1217 fs::path app2sd_migrate_db = legacy_path / kMigrateTestDBName;
1218 if (!ci::CopyFile(app2sd_migrate_db, app2sd_db)) {
1219 LOG(ERROR) << "Failed to copy test db";
1220 return BackendInterface::CommandResult::ERROR;
1223 fs::path legacy_src = legacy_path / pkgid;
1224 fs::path legacy_dst = app2sd_path / pkgid;
1225 if (!ci::CopyFile(legacy_src, legacy_dst)) {
1226 LOG(ERROR) << "Failed to copy test image";
1227 return BackendInterface::CommandResult::ERROR;
1229 const char* argv[] = {"", "--migrate-extimg", pkgid.c_str(),
1230 "-u", uid_str_.c_str()};
1231 return CallBackend(SIZEOFARRAY(argv), argv);
1234 BackendInterface::CommandResult BackendInterface::RDSUpdate(
1235 const fs::path& path,
1236 const std::string& pkgid) const {
1237 RequestResult tmp_mode = mode_;
1238 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1239 original_mode = RequestResult::NORMAL;
1240 if (Install(path) != BackendInterface::CommandResult::OK) {
1241 LOG(ERROR) << "Failed to install application. Cannot perform RDS";
1242 return BackendInterface::CommandResult::UNKNOWN;
1244 const char* argv[] = {"", "-r", pkgid.c_str(), "-u",
1246 original_mode = tmp_mode;
1247 return CallBackend(SIZEOFARRAY(argv), argv);
1250 BackendInterface::CommandResult BackendInterface::EnablePackage(
1251 const std::string& pkgid) const {
1252 const char* argv[] = {"", "-A", pkgid.c_str(), "-u", uid_str_.c_str()};
1253 return CallBackend(SIZEOFARRAY(argv), argv);
1256 BackendInterface::CommandResult BackendInterface::DisablePackage(
1257 const std::string& pkgid) const {
1258 const char* argv[] = {"", "-D", pkgid.c_str(), "-u", uid_str_.c_str()};
1259 return CallBackend(SIZEOFARRAY(argv), argv);
1262 BackendInterface::CommandResult BackendInterface::Recover(
1263 const fs::path& recovery_file) const {
1264 const char* argv[] = {"", "-b", recovery_file.c_str(), "-u",
1266 return CallBackend(SIZEOFARRAY(argv), argv);
1269 BackendInterface::CommandResult BackendInterface::ManifestDirectInstall(
1270 const std::string& pkgid) const {
1271 const char* argv[] = {"", "-y", pkgid.c_str(), "-u", uid_str_.c_str()};
1272 return CallBackend(SIZEOFARRAY(argv), argv);
1275 BackendInterface::CommandResult BackendInterface::Uninstall(
1276 const std::string& pkgid) const {
1277 const char* argv[] = {"", "-d", pkgid.c_str(), "-u", uid_str_.c_str()};
1278 return CallBackend(SIZEOFARRAY(argv), argv);
1281 BackendInterface::CommandResult BackendInterface::UninstallPreload(
1282 const std::string& pkgid) const {
1283 const char* argv[] = {"", "-d", pkgid.c_str(), "--preload",
1285 return CallBackend(SIZEOFARRAY(argv), argv);
1288 BackendInterface::CommandResult BackendInterface::InstallSuccess(
1289 const fs::path& path) const {
1290 RequestResult tmp_mode = mode_;
1291 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1292 original_mode = RequestResult::NORMAL;
1293 if (Install(path) != BackendInterface::CommandResult::OK) {
1294 LOG(ERROR) << "Failed to install application. Cannot update";
1295 return BackendInterface::CommandResult::UNKNOWN;
1297 original_mode = tmp_mode;
1298 return BackendInterface::CommandResult::OK;
1301 BackendInterface::CommandResult BackendInterface::InstallPreloadSuccess(
1302 const fs::path& path) const {
1303 RequestResult tmp_mode = mode_;
1304 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1305 original_mode = RequestResult::NORMAL;
1306 if (InstallPreload(path) != BackendInterface::CommandResult::OK) {
1307 LOG(ERROR) << "Failed to install application. Cannot update";
1308 return BackendInterface::CommandResult::UNKNOWN;
1310 original_mode = tmp_mode;
1311 return BackendInterface::CommandResult::OK;
1314 BackendInterface::CommandResult BackendInterface::MountInstall(
1315 const fs::path& path) const {
1316 const char* argv[] = {"", "-w", path.c_str(), "-u", uid_str_.c_str()};
1317 return CallBackend(SIZEOFARRAY(argv), argv);
1320 BackendInterface::CommandResult BackendInterface::MountInstallSuccess(
1321 const fs::path& path) const {
1322 RequestResult tmp_mode = mode_;
1323 RequestResult &original_mode = const_cast<RequestResult&>(mode_);
1324 original_mode = RequestResult::NORMAL;
1325 if (MountInstall(path) != BackendInterface::CommandResult::OK) {
1326 LOG(ERROR) << "Failed to mount-install application. Cannot mount-update";
1327 return BackendInterface::CommandResult::UNKNOWN;
1329 original_mode = tmp_mode;
1330 return BackendInterface::CommandResult::OK;
1333 static std::filesystem::path GetTrashPath(
1334 const std::filesystem::path& path) {
1335 return path.string() + ".trash";
1338 BackendInterface::SubProcessResult BackendInterface::RunSubprocess(
1339 std::vector<std::string> args) const {
1340 args.push_back("-remove_plugin_steps");
1341 ci::Subprocess backend = CreateSubprocess();
1342 backend.RunWithArgs(args);
1343 int status = backend.Wait();
1344 if (WIFEXITED(status)) {
1345 if (WEXITSTATUS(status) == 0)
1346 return BackendInterface::SubProcessResult::SUCCESS;
1348 return BackendInterface::SubProcessResult::FAIL;
1350 return BackendInterface::SubProcessResult::UnKnown;
1353 BackendInterface::SubProcessResult BackendInterface::RunSubprocessAndKill(
1354 std::vector<std::string> args, useconds_t delay) const {
1355 args.push_back("-remove_plugin_steps");
1356 ci::Subprocess backend = CreateSubprocess();
1357 backend.RunWithArgs(args);
1360 int status = backend.Wait();
1361 if (WIFEXITED(status)) {
1362 if (WEXITSTATUS(status) == 0)
1363 return BackendInterface::SubProcessResult::SUCCESS;
1365 return BackendInterface::SubProcessResult::FAIL;
1367 if (WTERMSIG(status) == SIGKILL)
1368 return BackendInterface::SubProcessResult::KILLED;
1370 return BackendInterface::SubProcessResult::UnKnown;
1374 BackendInterface::SubProcessResult BackendInterface::InstallWithSubprocess(
1375 const fs::path& path) const {
1376 std::vector<std::string> args =
1377 { "-i", path.string(), "-u", uid_str_ };
1378 return RunSubprocess(args);
1381 BackendInterface::SubProcessResult BackendInterface::MountInstallWithSubprocess(
1382 const fs::path& path) const {
1383 std::vector<std::string> args =
1384 { "-w", path.string(), "-u", uid_str_ };
1385 return RunSubprocess(args);
1388 BackendInterface::SubProcessResult BackendInterface::RecoverWithSubprocess(
1389 const fs::path& path) const {
1390 std::vector<std::string> args =
1391 { "-b", path.string(), "-u", uid_str_ };
1392 return RunSubprocess(args);
1395 BackendInterface::SubProcessResult BackendInterface::UninstallWithSubprocess(
1396 const std::string& pkgid) const {
1397 std::vector<std::string> args = { "-d", pkgid, "-u", uid_str_ };
1398 return RunSubprocess(args);
1401 BackendInterface::SubProcessResult
1402 BackendInterface::InstallPreloadWithSubprocess(
1403 const std::filesystem::path& path) const {
1404 std::vector<std::string> args = { "", "-i", path.string(), "--preload" };
1405 return RunSubprocess(args);
1408 BackendInterface::SubProcessResult
1409 BackendInterface::InstallWithSubprocessAndKill(
1410 const fs::path& path, useconds_t delay) const {
1411 std::vector<std::string> args =
1412 { "-i", path.string(), "-u", uid_str_ };
1413 return RunSubprocessAndKill(args, delay);
1416 BackendInterface::SubProcessResult
1417 BackendInterface::MountInstallWithSubprocessAndKill(
1418 const fs::path& path, useconds_t delay) const {
1419 std::vector<std::string> args =
1420 { "-w", path.string(), "-u", uid_str_ };
1421 return RunSubprocessAndKill(args, delay);
1424 BackendInterface::SubProcessResult
1425 BackendInterface::UninstallWithSubprocessAndKill(
1426 const std::string& pkgid, useconds_t delay) const {
1427 std::vector<std::string> args =
1428 { "-d", pkgid, "-u", uid_str_ };
1429 return RunSubprocessAndKill(args, delay);
1432 BackendInterface::SubProcessResult BackendInterface::InstallPkgsWithSubprocess(
1433 const std::vector<fs::path>& paths) const {
1434 std::vector<std::string> args;
1435 args.emplace_back("-i");
1436 for (const fs::path& p : paths)
1437 args.emplace_back(p.string());
1438 args.emplace_back("-u");
1439 args.emplace_back(uid_str_);
1440 return RunSubprocess(args);
1443 BackendInterface::SubProcessResult
1444 BackendInterface::MountInstallPkgsWithSubprocess(
1445 const std::vector<fs::path>& paths) const {
1446 std::vector<std::string> args;
1447 args.emplace_back("-w");
1448 for (const fs::path& p : paths)
1449 args.emplace_back(p.string());
1450 args.emplace_back("-u");
1451 args.emplace_back(uid_str_);
1452 return RunSubprocess(args);
1455 BackendInterface::SubProcessResult BackendInterface::RecoverPkgsWithSubprocess(
1456 const std::vector<fs::path>& paths) const {
1457 std::vector<std::string> args;
1458 args.emplace_back("-b");
1459 for (const fs::path& p : paths)
1460 args.emplace_back(p.string());
1461 args.emplace_back("-u");
1462 args.emplace_back(uid_str_);
1463 return RunSubprocess(args);
1466 BackendInterface::SubProcessResult
1467 BackendInterface::UninstallPkgsWithSubprocess(
1468 const std::vector<std::string>& pkgids) const {
1469 std::vector<std::string> args;
1470 args.emplace_back("-d");
1471 args.insert(args.end(), pkgids.begin(), pkgids.end());
1472 args.emplace_back("-u");
1473 args.emplace_back(uid_str_);
1474 return RunSubprocess(args);
1477 BackendInterface::SubProcessResult
1478 BackendInterface::InstallPkgsWithSubprocessAndKill(
1479 const std::vector<fs::path>& paths, useconds_t delay) const {
1480 std::vector<std::string> args;
1481 args.emplace_back("-i");
1482 for (const fs::path& p : paths)
1483 args.emplace_back(p.string());
1484 args.emplace_back("-u");
1485 args.emplace_back(uid_str_);
1486 return RunSubprocessAndKill(args, delay);
1489 BackendInterface::SubProcessResult
1490 BackendInterface::MountInstallPkgsWithSubprocessAndKill(
1491 const std::vector<fs::path>& paths, useconds_t delay) const {
1492 std::vector<std::string> args;
1493 args.emplace_back("-w");
1494 for (const fs::path& p : paths)
1495 args.emplace_back(p.string());
1496 args.emplace_back("-u");
1497 args.emplace_back(uid_str_);
1498 return RunSubprocessAndKill(args, delay);
1501 bool CopySmackAccess(const std::filesystem::path& src,
1502 const std::filesystem::path& dst) {
1503 if (!fs::exists(src) && !fs::is_symlink(src)) {
1504 LOG(ERROR) << "Failed to copy smack access label";
1508 char* access_label = nullptr;
1509 ret = smack_lgetlabel(src.c_str(), &access_label, SMACK_LABEL_ACCESS);
1511 LOG(ERROR) << "get access label from [" << src << "] fail";
1516 ret = smack_lsetlabel(dst.c_str(), access_label, SMACK_LABEL_ACCESS);
1519 LOG(ERROR) << "set access label to [" << dst << "] fail";
1525 bool CopySmackExec(const std::filesystem::path& src,
1526 const std::filesystem::path& dst) {
1527 if (!fs::exists(src) && !fs::is_symlink(src)) {
1528 LOG(ERROR) << "Failed to copy smack exec label";
1532 char *exec_label = nullptr;
1533 ret = smack_lgetlabel(src.c_str(), &exec_label, SMACK_LABEL_EXEC);
1535 LOG(ERROR) << "get exec label from [" << src << "] fail";
1540 ret = smack_lsetlabel(dst.c_str(), exec_label, SMACK_LABEL_EXEC);
1543 LOG(ERROR) << "set exec label to [" << dst << "] fail";
1549 bool CopySmackMmap(const std::filesystem::path& src,
1550 const std::filesystem::path& dst) {
1551 if (!fs::exists(src) && !fs::is_symlink(src)) {
1552 LOG(ERROR) << "Failed to copy smack mmap label";
1556 char *mmap_label = nullptr;
1557 ret = smack_lgetlabel(src.c_str(), &mmap_label, SMACK_LABEL_MMAP);
1559 LOG(ERROR) << "get mmap label from [" << src << "] fail";
1564 ret = smack_lsetlabel(dst.c_str(), mmap_label, SMACK_LABEL_MMAP);
1567 LOG(ERROR) << "set mmap label to [" << dst << "] fail";
1573 bool CopySmackTransmute(const std::filesystem::path& src,
1574 const std::filesystem::path& dst) {
1575 if (!fs::exists(src)) {
1576 LOG(ERROR) << "Failed to copy smack tranmute label";
1580 char *transmute_label = nullptr;
1581 ret = smack_lgetlabel(src.c_str(), &transmute_label, SMACK_LABEL_TRANSMUTE);
1583 LOG(ERROR) << "get access label from [" << src << "] fail";
1586 if (!transmute_label) {
1587 ret = smack_lsetlabel(dst.c_str(), "0", SMACK_LABEL_TRANSMUTE);
1589 if (strcmp(transmute_label, "TRUE") == 0)
1590 ret = smack_lsetlabel(dst.c_str(), "1", SMACK_LABEL_TRANSMUTE);
1592 ret = smack_lsetlabel(dst.c_str(), "0", SMACK_LABEL_TRANSMUTE);
1593 free(transmute_label);
1595 LOG(ERROR) << "set access label to [" << dst << "] fail";
1603 bool CopySmackLabels(const std::filesystem::path& src,
1604 const std::filesystem::path& dst) {
1605 if (!CopySmackAccess(src, dst))
1607 if (!CopySmackExec(src, dst))
1609 if (!CopySmackMmap(src, dst))
1611 if (!fs::is_symlink(src) && fs::is_directory(src)) {
1612 if (!CopySmackTransmute(src, dst))
1618 bool CopyAndRemoveWithSmack(const fs::path& src, const fs::path& dst) {
1619 std::error_code error;
1620 if (fs::exists(dst)) {
1622 fs::remove_all(dst, error);
1624 std::cout << "Exception occurred during remove [" << dst.string()
1625 << "], and skip this file"<< std::endl;
1628 if (!fs::is_directory(dst)) {
1629 LOG(ERROR) << "remove_all fail";
1635 if (fs::is_symlink(src)) {
1636 fs::copy_symlink(src, dst, error);
1638 LOG(ERROR) << "Failed to copy symlink: " << src << ", "
1642 if (!CopySmackLabels(src, dst)) {
1643 LOG(ERROR) << "copy smack label from [" << src.string()
1644 << "] to [" << dst.string() << "] fail";
1647 } else if (fs::is_directory(src)) {
1648 if (!fs::exists(dst)) {
1649 fs::create_directories(dst, error);
1651 LOG(ERROR) << "create directories fail";
1654 ci::CopyOwnershipAndPermissions(src, dst);
1655 if (!CopySmackLabels(src, dst)) {
1656 LOG(ERROR) << "copy smack label from [" << src.string()
1657 << "] to [" << dst.string() << "] fail";
1661 bool success = true;
1662 for (fs::directory_iterator file(src);
1663 file != fs::directory_iterator();
1665 fs::path current(file->path());
1666 fs::path target = dst / current.filename();
1667 success &= CopyAndRemoveWithSmack(current, target);
1669 fs::remove_all(src);
1673 fs::copy_file(src, dst);
1674 ci::CopyOwnershipAndPermissions(src, dst);
1675 if (!CopySmackLabels(src, dst)) {
1676 LOG(ERROR) << "copy smack label from [" << src.string()
1677 << "] to [" << dst.string() << "] fail";
1680 fs::remove_all(src);
1683 std::cout << "Exception occurred during copy [" << src.string()
1684 << "], and skip this file"<< std::endl;
1691 bool BackupPathCopyAndRemove(const fs::path& path) {
1692 if (!fs::exists(path))
1695 fs::path backup_path = path.string() + ".bck";
1696 std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
1697 if (!CopyAndRemoveWithSmack(path, backup_path)) {
1698 LOG(ERROR) << "Failed to setup test environment. Does some previous"
1699 << " test crashed? Path: "
1700 << backup_path << " should not exist.";
1706 bool BackupPath(const fs::path& path) {
1707 fs::path trash_path = GetTrashPath(path);
1708 if (fs::exists(trash_path)) {
1709 LOG(ERROR) << trash_path << " exists. Please remove "
1710 << trash_path << " manually!";
1713 fs::path backup_path = path.string() + ".bck";
1714 std::cout << "Backup path: " << path << " to " << backup_path << std::endl;
1715 std::error_code error;
1716 fs::remove_all(backup_path, error);
1718 LOG(ERROR) << "Remove failed: " << backup_path
1719 << " (" << error.message() << ")";
1720 if (fs::exists(path)) {
1721 fs::rename(path, backup_path, error);
1723 LOG(ERROR) << "Failed to setup test environment. Does some previous"
1724 << " test crashed? Path: "
1725 << backup_path << " should not exist.";
1729 if (fs::is_directory(backup_path))
1730 fs::create_directory(path);
1735 void CreateDatabase() {
1736 pkgmgr_parser_create_and_initialize_db(kGlobalUserUid);
1737 pkgmgr_parser_create_and_initialize_db(getuid());
1740 bool RestorePathCopyAndRemove(const fs::path& path) {
1741 fs::path backup_path = path.string() + ".bck";
1742 if (!fs::exists(backup_path))
1745 std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
1746 if (!CopyAndRemoveWithSmack(backup_path, path)) {
1747 LOG(ERROR) << "Failed to restore backup path: " << backup_path;
1753 bool RestorePath(const fs::path& path) {
1754 fs::path backup_path = path.string() + ".bck";
1755 std::cout << "Restore path: " << path << " from " << backup_path << std::endl;
1756 std::error_code error;
1757 fs::remove_all(path, error);
1759 fs::path trash_path = GetTrashPath(path);
1760 LOG(ERROR) << "Remove failed: " << path << " (" << error.message() << ")";
1761 std::cout << "Moving " << path << " to " << trash_path << std::endl;
1762 fs::rename(path, trash_path, error);
1764 LOG(ERROR) << "Failed to move " << path << " to " << trash_path
1765 << " (" << error.message() << ")";
1767 LOG(ERROR) << trash_path << " should be removed manually!";
1769 if (fs::exists(backup_path)) {
1770 fs::rename(backup_path, path, error);
1772 LOG(ERROR) << "Failed to restore backup path: " << backup_path
1773 << " (" << error.message() << ")";
1780 std::vector<fs::path> SetupBackupDirectories(uid_t test_uid) {
1781 std::vector<fs::path> entries;
1782 fs::path db_dir = fs::path(tzplatform_getenv(TZ_SYS_DB));
1783 if (test_uid != kGlobalUserUid)
1784 db_dir = db_dir / "user" / std::to_string(test_uid);
1785 for (auto e : kDBEntries) {
1786 fs::path path = db_dir / e;
1787 entries.emplace_back(path);
1790 if (getuid() == 0) {
1791 entries.emplace_back(kPreloadApps);
1792 entries.emplace_back(kPreloadManifestDir);
1793 entries.emplace_back(kPreloadIcons);
1796 if (test_uid == kGlobalUserUid) {
1797 entries.emplace_back(kSkelDir);
1798 entries.emplace_back(kGlobalManifestDir);
1799 ci::UserList list = ci::GetUserList();
1800 for (auto l : list) {
1801 fs::path apps = std::get<2>(l) / "apps_rw";
1802 entries.emplace_back(apps);
1805 tzplatform_set_user(test_uid);
1806 fs::path approot = tzplatform_getenv(TZ_USER_APPROOT);
1807 tzplatform_reset_user();
1808 entries.emplace_back(approot);
1811 fs::path apps_rw = ci::GetRootAppPath(false, test_uid);
1812 entries.emplace_back(apps_rw);
1813 entries.emplace_back(kSdkDirectory);
1818 void UninstallAllAppsInDirectory(fs::path dir, bool is_preload,
1819 BackendInterface* backend) {
1820 if (fs::exists(dir)) {
1821 for (auto& dir_entry : fs::directory_iterator(dir)) {
1822 if (dir_entry.path().string().find("smoke") != std::string::npos &&
1823 fs::is_directory(dir_entry)) {
1824 std::string package = dir_entry.path().filename().string();
1825 std::regex pkg_regex("smoke[a-zA-Z0-9]{5,}");
1826 if (std::regex_match(package, pkg_regex)) {
1827 BackendInterface::CommandResult result =
1828 BackendInterface::CommandResult::OK;
1830 result = backend->UninstallPreload(
1831 dir_entry.path().filename().string());
1833 result = backend->Uninstall(
1834 dir_entry.path().filename().string());
1835 if (result != BackendInterface::CommandResult::OK) {
1836 LOG(ERROR) << "Cannot uninstall smoke test app: "
1837 << dir_entry.path().filename().string();
1845 void UninstallAllSmokeApps(ci::RequestMode request_mode, uid_t test_uid,
1846 BackendInterface *backend) {
1847 std::cout << "Uninstalling all smoke apps" << std::endl;
1848 fs::path apps_rw = ci::GetRootAppPath(false, test_uid);
1849 UninstallAllAppsInDirectory(apps_rw, false, backend);
1850 if (getuid() == 0 && request_mode == ci::RequestMode::GLOBAL) {
1851 fs::path root_path = kPreloadApps;
1852 UninstallAllAppsInDirectory(root_path, true, backend);
1856 int GetAppInstalledTime(const char* appid, uid_t uid) {
1858 int installed_time = 0;
1859 pkgmgrinfo_appinfo_h handle = NULL;
1860 ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &handle);
1861 if (ret != PMINFO_R_OK)
1863 ret = pkgmgrinfo_appinfo_get_installed_time(handle, &installed_time);
1864 if (ret != PMINFO_R_OK) {
1865 pkgmgrinfo_appinfo_destroy_appinfo(handle);
1868 pkgmgrinfo_appinfo_destroy_appinfo(handle);
1869 return installed_time;
1872 bool CompareFileInfo(const std::string& pkgid, const TestParameters& params,
1873 const fs::path& file) {
1874 FileInfoCollector result(pkgid, params);
1878 fs::path p = "/tmp";
1879 p /= file.filename();
1881 if (!result.FileInfoToFile(p))
1884 FileInfoCollector expected(pkgid, params);
1885 if (!expected.LoadFromFile(file))
1888 return result.IsEqual(expected);
1891 } // namespace smoke_test