Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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 <algorithm> |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 18 | #include <filesystem> |
Andreas Gampe | a158e3d | 2018-12-10 13:46:30 -0800 | [diff] [blame] | 19 | #include <fstream> |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 20 | #include <functional> |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 21 | #include <memory> |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 22 | #include <optional> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 23 | #include <string> |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 24 | #include <unordered_set> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 25 | #include <vector> |
| 26 | |
| 27 | #include <grp.h> |
Nikita Ioffe | 88752d9 | 2020-01-02 21:55:35 +0000 | [diff] [blame] | 28 | #include <linux/loop.h> |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 29 | #include <stdio.h> |
Nikita Ioffe | 88752d9 | 2020-01-02 21:55:35 +0000 | [diff] [blame] | 30 | #include <sys/ioctl.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 31 | #include <sys/stat.h> |
| 32 | #include <sys/types.h> |
| 33 | |
| 34 | #include <android-base/file.h> |
| 35 | #include <android-base/logging.h> |
Andreas Gampe | 5ec47c5 | 2018-11-14 14:33:53 -0800 | [diff] [blame] | 36 | #include <android-base/macros.h> |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 37 | #include <android-base/properties.h> |
Andreas Gampe | c766c0a | 2018-12-06 15:51:21 -0800 | [diff] [blame] | 38 | #include <android-base/scopeguard.h> |
Andreas Gampe | 5ec47c5 | 2018-11-14 14:33:53 -0800 | [diff] [blame] | 39 | #include <android-base/stringprintf.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 40 | #include <android-base/strings.h> |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 41 | #include <android/os/IVold.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 42 | #include <binder/IServiceManager.h> |
Nikita Ioffe | 78d2bce | 2020-05-02 01:28:30 +0100 | [diff] [blame] | 43 | #include <fs_mgr_overlayfs.h> |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 44 | #include <fstab/fstab.h> |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 45 | #include <gmock/gmock.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 46 | #include <gtest/gtest.h> |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 47 | #include <libdm/dm.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 48 | #include <selinux/selinux.h> |
| 49 | |
Dario Freni | dded6c1 | 2018-11-19 16:02:26 +0000 | [diff] [blame] | 50 | #include <android/apex/ApexInfo.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 51 | #include <android/apex/IApexService.h> |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 52 | |
Andreas Gampe | f35e179 | 2019-04-01 15:58:03 -0700 | [diff] [blame] | 53 | #include "apex_constants.h" |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 54 | #include "apex_database.h" |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 55 | #include "apex_file.h" |
| 56 | #include "apex_manifest.h" |
Gavin Corkery | 92cd7b8 | 2020-01-13 12:35:38 +0000 | [diff] [blame] | 57 | #include "apexd.h" |
Andreas Gampe | 4510d49 | 2018-12-12 15:56:05 -0800 | [diff] [blame] | 58 | #include "apexd_private.h" |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 59 | #include "apexd_session.h" |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 60 | #include "apexd_test_utils.h" |
Andreas Gampe | e1a4039 | 2018-11-30 09:47:17 -0800 | [diff] [blame] | 61 | #include "apexd_utils.h" |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 62 | |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 63 | #include "session_state.pb.h" |
| 64 | |
| 65 | using apex::proto::SessionState; |
| 66 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 67 | namespace android { |
| 68 | namespace apex { |
| 69 | |
| 70 | using android::sp; |
| 71 | using android::String16; |
Nikita Ioffe | de2c40a | 2019-04-10 12:15:53 +0100 | [diff] [blame] | 72 | using android::apex::testing::ApexInfoEq; |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 73 | using android::apex::testing::CreateSessionInfo; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 74 | using android::apex::testing::IsOk; |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 75 | using android::apex::testing::SessionInfoEq; |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 76 | using android::base::Join; |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 77 | using android::base::ReadFully; |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 78 | using android::base::StartsWith; |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 79 | using android::base::StringPrintf; |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 80 | using android::base::unique_fd; |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 81 | using android::dm::DeviceMapper; |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 82 | using android::fs_mgr::Fstab; |
| 83 | using android::fs_mgr::GetEntryForMountPoint; |
| 84 | using android::fs_mgr::ReadFstabFromFile; |
Nikita Ioffe | de2c40a | 2019-04-10 12:15:53 +0100 | [diff] [blame] | 85 | using ::testing::Contains; |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 86 | using ::testing::EndsWith; |
| 87 | using ::testing::HasSubstr; |
| 88 | using ::testing::Not; |
Jooyung Han | 499de89 | 2020-05-12 12:01:05 +0900 | [diff] [blame] | 89 | using ::testing::SizeIs; |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 90 | using ::testing::UnorderedElementsAre; |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 91 | using ::testing::UnorderedElementsAreArray; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 92 | |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 93 | using MountedApexData = MountedApexDatabase::MountedApexData; |
| 94 | |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 95 | namespace fs = std::filesystem; |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 96 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 97 | class ApexServiceTest : public ::testing::Test { |
| 98 | public: |
| 99 | ApexServiceTest() { |
| 100 | using android::IBinder; |
| 101 | using android::IServiceManager; |
| 102 | |
| 103 | sp<IServiceManager> sm = android::defaultServiceManager(); |
Jon Spivack | 1b84030 | 2020-02-06 18:34:30 -0800 | [diff] [blame] | 104 | sp<IBinder> binder = sm->waitForService(String16("apexservice")); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 105 | if (binder != nullptr) { |
| 106 | service_ = android::interface_cast<IApexService>(binder); |
| 107 | } |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 108 | binder = sm->getService(String16("vold")); |
| 109 | if (binder != nullptr) { |
| 110 | vold_service_ = android::interface_cast<android::os::IVold>(binder); |
| 111 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 112 | } |
| 113 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 114 | protected: |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 115 | void SetUp() override { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 116 | // TODO(b/136647373): Move this check to environment setup |
| 117 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 118 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 119 | } |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 120 | ASSERT_NE(nullptr, service_.get()); |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 121 | ASSERT_NE(nullptr, vold_service_.get()); |
| 122 | android::binder::Status status = |
| 123 | vold_service_->supportsCheckpoint(&supports_fs_checkpointing_); |
| 124 | ASSERT_TRUE(IsOk(status)); |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 125 | CleanUp(); |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 126 | } |
| 127 | |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 128 | void TearDown() override { CleanUp(); } |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 129 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 130 | static std::string GetTestDataDir() { |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 131 | return android::base::GetExecutableDirectory(); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 132 | } |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 133 | static std::string GetTestFile(const std::string& name) { |
| 134 | return GetTestDataDir() + "/" + name; |
| 135 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 136 | |
| 137 | static bool HaveSelinux() { return 1 == is_selinux_enabled(); } |
| 138 | |
| 139 | static bool IsSelinuxEnforced() { return 0 != security_getenforce(); } |
| 140 | |
Nikita Ioffe | 78d2bce | 2020-05-02 01:28:30 +0100 | [diff] [blame] | 141 | Result<bool> IsActive(const std::string& name) { |
| 142 | std::vector<ApexInfo> list; |
| 143 | android::binder::Status status = service_->getActivePackages(&list); |
| 144 | if (!status.isOk()) { |
| 145 | return Error() << "Failed to check if " << name |
| 146 | << " is active : " << status.exceptionMessage().c_str(); |
| 147 | } |
| 148 | for (const ApexInfo& apex : list) { |
| 149 | if (apex.moduleName == name) { |
| 150 | return true; |
| 151 | } |
| 152 | } |
| 153 | return false; |
| 154 | } |
| 155 | |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 156 | Result<bool> IsActive(const std::string& name, int64_t version, |
| 157 | const std::string& path) { |
Dario Freni | dded6c1 | 2018-11-19 16:02:26 +0000 | [diff] [blame] | 158 | std::vector<ApexInfo> list; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 159 | android::binder::Status status = service_->getActivePackages(&list); |
| 160 | if (status.isOk()) { |
Dario Freni | dded6c1 | 2018-11-19 16:02:26 +0000 | [diff] [blame] | 161 | for (const ApexInfo& p : list) { |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 162 | if (p.moduleName == name && p.versionCode == version && |
| 163 | p.modulePath == path) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 164 | return true; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 165 | } |
| 166 | } |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 167 | return false; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 168 | } |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 169 | return Error() << status.exceptionMessage().c_str(); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 170 | } |
| 171 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 172 | Result<std::vector<ApexInfo>> GetAllPackages() { |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 173 | std::vector<ApexInfo> list; |
| 174 | android::binder::Status status = service_->getAllPackages(&list); |
| 175 | if (status.isOk()) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 176 | return list; |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 177 | } |
| 178 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 179 | return Error() << status.toString8().c_str(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 180 | } |
| 181 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 182 | Result<std::vector<ApexInfo>> GetActivePackages() { |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 183 | std::vector<ApexInfo> list; |
| 184 | android::binder::Status status = service_->getActivePackages(&list); |
| 185 | if (status.isOk()) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 186 | return list; |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 187 | } |
| 188 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 189 | return Error() << status.exceptionMessage().c_str(); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 190 | } |
| 191 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 192 | Result<std::vector<ApexInfo>> GetInactivePackages() { |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 193 | std::vector<ApexInfo> list; |
| 194 | android::binder::Status status = service_->getAllPackages(&list); |
| 195 | list.erase(std::remove_if( |
| 196 | list.begin(), list.end(), |
| 197 | [](const ApexInfo& apexInfo) { return apexInfo.isActive; }), |
| 198 | list.end()); |
| 199 | if (status.isOk()) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 200 | return list; |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 201 | } |
| 202 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 203 | return Error() << status.toString8().c_str(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 204 | } |
| 205 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 206 | Result<ApexInfo> GetActivePackage(const std::string& name) { |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 207 | ApexInfo package; |
| 208 | android::binder::Status status = service_->getActivePackage(name, &package); |
| 209 | if (status.isOk()) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 210 | return package; |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 211 | } |
| 212 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 213 | return Error() << status.exceptionMessage().c_str(); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 214 | } |
| 215 | |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 216 | std::string GetPackageString(const ApexInfo& p) { |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 217 | return p.moduleName + "@" + std::to_string(p.versionCode) + |
| 218 | " [path=" + p.moduleName + "]"; |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | std::vector<std::string> GetPackagesStrings( |
| 222 | const std::vector<ApexInfo>& list) { |
| 223 | std::vector<std::string> ret; |
Nikita Ioffe | bca0bc1 | 2019-06-17 18:54:13 +0100 | [diff] [blame] | 224 | ret.reserve(list.size()); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 225 | for (const ApexInfo& p : list) { |
| 226 | ret.push_back(GetPackageString(p)); |
| 227 | } |
| 228 | return ret; |
| 229 | } |
| 230 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 231 | std::vector<std::string> GetActivePackagesStrings() { |
Dario Freni | dded6c1 | 2018-11-19 16:02:26 +0000 | [diff] [blame] | 232 | std::vector<ApexInfo> list; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 233 | android::binder::Status status = service_->getActivePackages(&list); |
| 234 | if (status.isOk()) { |
Dario Freni | 6425511 | 2019-02-18 22:13:38 +0000 | [diff] [blame] | 235 | std::vector<std::string> ret(list.size()); |
Dario Freni | dded6c1 | 2018-11-19 16:02:26 +0000 | [diff] [blame] | 236 | for (const ApexInfo& p : list) { |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 237 | ret.push_back(GetPackageString(p)); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 238 | } |
| 239 | return ret; |
| 240 | } |
| 241 | |
| 242 | std::vector<std::string> error; |
| 243 | error.push_back("ERROR"); |
| 244 | return error; |
| 245 | } |
| 246 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 247 | Result<std::vector<ApexInfo>> GetFactoryPackages() { |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 248 | std::vector<ApexInfo> list; |
| 249 | android::binder::Status status = service_->getAllPackages(&list); |
| 250 | list.erase( |
| 251 | std::remove_if(list.begin(), list.end(), |
| 252 | [](ApexInfo& apexInfo) { return !apexInfo.isFactory; }), |
| 253 | list.end()); |
| 254 | if (status.isOk()) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 255 | return list; |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 256 | } |
| 257 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 258 | return Error() << status.toString8().c_str(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 259 | } |
| 260 | |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 261 | static std::vector<std::string> ListDir(const std::string& path) { |
| 262 | std::vector<std::string> ret; |
Mohammad Samiul Islam | 2d56f37 | 2019-03-27 17:07:57 +0000 | [diff] [blame] | 263 | std::error_code ec; |
| 264 | if (!fs::is_directory(path, ec)) { |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 265 | return ret; |
| 266 | } |
Nikita Ioffe | fe8b14d | 2019-06-21 01:21:13 +0100 | [diff] [blame] | 267 | auto status = WalkDir(path, [&](const fs::directory_entry& entry) { |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 268 | std::string tmp; |
Mohammad Samiul Islam | 2d56f37 | 2019-03-27 17:07:57 +0000 | [diff] [blame] | 269 | switch (entry.symlink_status(ec).type()) { |
| 270 | case fs::file_type::directory: |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 271 | tmp = "[dir]"; |
| 272 | break; |
Mohammad Samiul Islam | 2d56f37 | 2019-03-27 17:07:57 +0000 | [diff] [blame] | 273 | case fs::file_type::symlink: |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 274 | tmp = "[lnk]"; |
| 275 | break; |
Mohammad Samiul Islam | 2d56f37 | 2019-03-27 17:07:57 +0000 | [diff] [blame] | 276 | case fs::file_type::regular: |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 277 | tmp = "[reg]"; |
| 278 | break; |
| 279 | default: |
| 280 | tmp = "[other]"; |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 281 | } |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 282 | ret.push_back(tmp.append(entry.path().filename())); |
| 283 | }); |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 284 | CHECK(status.has_value()) |
| 285 | << "Failed to list " << path << " : " << status.error(); |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 286 | std::sort(ret.begin(), ret.end()); |
| 287 | return ret; |
| 288 | } |
| 289 | |
Andreas Gampe | e1a4039 | 2018-11-30 09:47:17 -0800 | [diff] [blame] | 290 | static std::string GetLogcat() { |
| 291 | // For simplicity, log to file and read it. |
| 292 | std::string file = GetTestFile("logcat.tmp.txt"); |
| 293 | std::vector<std::string> args{ |
| 294 | "/system/bin/logcat", |
| 295 | "-d", |
| 296 | "-f", |
| 297 | file, |
| 298 | }; |
| 299 | std::string error_msg; |
| 300 | int res = ForkAndRun(args, &error_msg); |
| 301 | CHECK_EQ(0, res) << error_msg; |
| 302 | |
| 303 | std::string data; |
| 304 | CHECK(android::base::ReadFileToString(file, &data)); |
| 305 | |
| 306 | unlink(file.c_str()); |
| 307 | |
| 308 | return data; |
| 309 | } |
| 310 | |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 311 | static void DeleteIfExists(const std::string& path) { |
| 312 | if (fs::exists(path)) { |
| 313 | std::error_code ec; |
| 314 | fs::remove_all(path, ec); |
| 315 | ASSERT_FALSE(ec) << "Failed to delete dir " << path << " : " |
| 316 | << ec.message(); |
| 317 | } |
| 318 | } |
| 319 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 320 | struct PrepareTestApexForInstall { |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 321 | static constexpr const char* kTestDir = "/data/app-staging/apexservice_tmp"; |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 322 | |
| 323 | // This is given to the constructor. |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 324 | std::string test_input; // Original test file. |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 325 | std::string selinux_label_input; // SELinux label to apply. |
| 326 | std::string test_dir_input; |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 327 | |
| 328 | // This is derived from the input. |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 329 | std::string test_file; // Prepared path. Under test_dir_input. |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 330 | std::string test_installed_file; // Where apexd will store it. |
| 331 | |
| 332 | std::string package; // APEX package name. |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 333 | uint64_t version; // APEX version |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 334 | |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 335 | explicit PrepareTestApexForInstall( |
| 336 | const std::string& test, |
| 337 | const std::string& test_dir = std::string(kTestDir), |
Nikita Ioffe | 936a997 | 2019-02-13 02:11:21 +0000 | [diff] [blame] | 338 | const std::string& selinux_label = "staging_data_file") { |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 339 | test_input = test; |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 340 | selinux_label_input = selinux_label; |
| 341 | test_dir_input = test_dir; |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 342 | |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 343 | test_file = test_dir_input + "/" + android::base::Basename(test); |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 344 | |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 345 | package = ""; // Explicitly mark as not initialized. |
| 346 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 347 | Result<ApexFile> apex_file = ApexFile::Open(test); |
Bernie Innocenti | 575b30d | 2020-02-09 19:23:06 +0900 | [diff] [blame] | 348 | if (!apex_file.ok()) { |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 349 | return; |
| 350 | } |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 351 | |
| 352 | const ApexManifest& manifest = apex_file->GetManifest(); |
Abhijeet Kaur | 216e36c | 2019-01-04 10:15:01 +0000 | [diff] [blame] | 353 | package = manifest.name(); |
| 354 | version = manifest.version(); |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 355 | |
Nikita Ioffe | a8453da | 2019-01-30 21:29:13 +0000 | [diff] [blame] | 356 | test_installed_file = std::string(kActiveApexPackagesDataDir) + "/" + |
| 357 | package + "@" + std::to_string(version) + ".apex"; |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 358 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 359 | |
| 360 | bool Prepare() { |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 361 | if (package.empty()) { |
| 362 | // Failure in constructor. Redo work to get error message. |
| 363 | auto fail_fn = [&]() { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 364 | Result<ApexFile> apex_file = ApexFile::Open(test_input); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 365 | ASSERT_FALSE(IsOk(apex_file)); |
Bernie Innocenti | 575b30d | 2020-02-09 19:23:06 +0900 | [diff] [blame] | 366 | ASSERT_TRUE(apex_file.ok()) |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 367 | << test_input << " failed to load: " << apex_file.error(); |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 368 | }; |
| 369 | fail_fn(); |
| 370 | return false; |
| 371 | } |
| 372 | |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 373 | auto prepare = [](const std::string& src, const std::string& trg, |
| 374 | const std::string& selinux_label) { |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 375 | ASSERT_EQ(0, access(src.c_str(), F_OK)) |
| 376 | << src << ": " << strerror(errno); |
| 377 | const std::string trg_dir = android::base::Dirname(trg); |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 378 | if (0 != mkdir(trg_dir.c_str(), 0777)) { |
| 379 | int saved_errno = errno; |
| 380 | ASSERT_EQ(saved_errno, EEXIST) << trg << ":" << strerror(saved_errno); |
| 381 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 382 | |
Andreas Gampe | a158e3d | 2018-12-10 13:46:30 -0800 | [diff] [blame] | 383 | // Do not use a hardlink, even though it's the simplest solution. |
| 384 | // b/119569101. |
| 385 | { |
| 386 | std::ifstream src_stream(src, std::ios::binary); |
| 387 | ASSERT_TRUE(src_stream.good()); |
| 388 | std::ofstream trg_stream(trg, std::ios::binary); |
| 389 | ASSERT_TRUE(trg_stream.good()); |
Andreas Gampe | 2f097cf | 2018-11-14 16:59:33 -0800 | [diff] [blame] | 390 | |
Andreas Gampe | a158e3d | 2018-12-10 13:46:30 -0800 | [diff] [blame] | 391 | trg_stream << src_stream.rdbuf(); |
Andreas Gampe | 2f097cf | 2018-11-14 16:59:33 -0800 | [diff] [blame] | 392 | } |
| 393 | |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 394 | ASSERT_EQ(0, chmod(trg.c_str(), 0666)) << strerror(errno); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 395 | struct group* g = getgrnam("system"); |
| 396 | ASSERT_NE(nullptr, g); |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 397 | ASSERT_EQ(0, chown(trg.c_str(), /* root uid */ 0, g->gr_gid)) |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 398 | << strerror(errno); |
Andreas Gampe | 2f097cf | 2018-11-14 16:59:33 -0800 | [diff] [blame] | 399 | |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 400 | int rc = setfilecon( |
| 401 | trg_dir.c_str(), |
| 402 | std::string("u:object_r:" + selinux_label + ":s0").c_str()); |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 403 | ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno); |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 404 | rc = setfilecon( |
| 405 | trg.c_str(), |
| 406 | std::string("u:object_r:" + selinux_label + ":s0").c_str()); |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 407 | ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 408 | }; |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 409 | prepare(test_input, test_file, selinux_label_input); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 410 | return !HasFatalFailure(); |
| 411 | } |
| 412 | |
| 413 | ~PrepareTestApexForInstall() { |
Nikita Ioffe | 5bddac0 | 2019-12-30 11:10:20 +0000 | [diff] [blame] | 414 | LOG(INFO) << "Deleting file " << test_file; |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 415 | if (unlink(test_file.c_str()) != 0) { |
| 416 | PLOG(ERROR) << "Unable to unlink " << test_file; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 417 | } |
Nikita Ioffe | 5bddac0 | 2019-12-30 11:10:20 +0000 | [diff] [blame] | 418 | LOG(INFO) << "Deleting directory " << test_dir_input; |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 419 | if (rmdir(test_dir_input.c_str()) != 0) { |
| 420 | PLOG(ERROR) << "Unable to rmdir " << test_dir_input; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 421 | } |
| 422 | } |
| 423 | }; |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 424 | |
| 425 | std::string GetDebugStr(PrepareTestApexForInstall* installer) { |
| 426 | StringLog log; |
| 427 | |
| 428 | if (installer != nullptr) { |
| 429 | log << "test_input=" << installer->test_input << " "; |
| 430 | log << "test_file=" << installer->test_file << " "; |
| 431 | log << "test_installed_file=" << installer->test_installed_file << " "; |
| 432 | log << "package=" << installer->package << " "; |
| 433 | log << "version=" << installer->version << " "; |
| 434 | } |
| 435 | |
| 436 | log << "active=[" << Join(GetActivePackagesStrings(), ',') << "] "; |
Nikita Ioffe | a8453da | 2019-01-30 21:29:13 +0000 | [diff] [blame] | 437 | log << kActiveApexPackagesDataDir << "=[" |
| 438 | << Join(ListDir(kActiveApexPackagesDataDir), ',') << "] "; |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 439 | log << kApexRoot << "=[" << Join(ListDir(kApexRoot), ',') << "]"; |
| 440 | |
| 441 | return log; |
| 442 | } |
| 443 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 444 | sp<IApexService> service_; |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 445 | sp<android::os::IVold> vold_service_; |
| 446 | bool supports_fs_checkpointing_; |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 447 | |
| 448 | private: |
| 449 | void CleanUp() { |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 450 | auto status = WalkDir(kApexDataDir, [](const fs::directory_entry& p) { |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 451 | std::error_code ec; |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 452 | fs::file_status status = p.status(ec); |
| 453 | ASSERT_FALSE(ec) << "Failed to stat " << p.path() << " : " |
| 454 | << ec.message(); |
| 455 | if (fs::is_directory(status)) { |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 456 | fs::remove_all(p.path(), ec); |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 457 | } else { |
| 458 | fs::remove(p.path(), ec); |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 459 | } |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 460 | ASSERT_FALSE(ec) << "Failed to delete " << p.path() << " : " |
| 461 | << ec.message(); |
| 462 | }); |
Gavin Corkery | 879fe9b | 2020-01-29 19:13:50 +0000 | [diff] [blame] | 463 | fs::remove_all(kApexSessionsDir); |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 464 | ASSERT_TRUE(IsOk(status)); |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 465 | |
| 466 | DeleteIfExists("/data/misc_ce/0/apexdata/apex.apexd_test"); |
| 467 | DeleteIfExists("/data/misc_ce/0/apexrollback/123456"); |
Oli Lan | 2993ccc | 2020-03-06 18:06:40 +0000 | [diff] [blame] | 468 | DeleteIfExists("/data/misc_ce/0/apexrollback/77777"); |
| 469 | DeleteIfExists("/data/misc_ce/0/apexrollback/98765"); |
Oli Lan | 042fbcf | 2020-01-17 11:14:16 +0000 | [diff] [blame] | 470 | DeleteIfExists("/data/misc_de/0/apexrollback/123456"); |
| 471 | DeleteIfExists("/data/misc/apexrollback/123456"); |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 472 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 473 | }; |
| 474 | |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 475 | namespace { |
| 476 | |
| 477 | bool RegularFileExists(const std::string& path) { |
| 478 | struct stat buf; |
| 479 | if (0 != stat(path.c_str(), &buf)) { |
| 480 | return false; |
| 481 | } |
| 482 | return S_ISREG(buf.st_mode); |
| 483 | } |
| 484 | |
Oli Lan | 042fbcf | 2020-01-17 11:14:16 +0000 | [diff] [blame] | 485 | bool DirExists(const std::string& path) { |
| 486 | struct stat buf; |
| 487 | if (0 != stat(path.c_str(), &buf)) { |
| 488 | return false; |
| 489 | } |
| 490 | return S_ISDIR(buf.st_mode); |
| 491 | } |
| 492 | |
| 493 | void CreateDir(const std::string& path) { |
| 494 | std::error_code ec; |
| 495 | fs::create_directory(path, ec); |
| 496 | ASSERT_FALSE(ec) << "Failed to create rollback dir " |
| 497 | << " : " << ec.message(); |
| 498 | } |
| 499 | |
| 500 | void CreateFile(const std::string& path) { |
| 501 | std::ofstream ofs(path); |
| 502 | ASSERT_TRUE(ofs.good()); |
| 503 | ofs.close(); |
| 504 | } |
| 505 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 506 | Result<std::vector<std::string>> ReadEntireDir(const std::string& path) { |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 507 | static const auto kAcceptAll = [](auto /*entry*/) { return true; }; |
| 508 | return ReadDir(path, kAcceptAll); |
| 509 | } |
| 510 | |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 511 | Result<std::string> GetBlockDeviceForApex(const std::string& package_id) { |
| 512 | std::string mount_point = std::string(kApexRoot) + "/" + package_id; |
| 513 | Fstab fstab; |
| 514 | if (!ReadFstabFromFile("/proc/mounts", &fstab)) { |
| 515 | return Error() << "Failed to read /proc/mounts"; |
| 516 | } |
| 517 | auto entry = GetEntryForMountPoint(&fstab, mount_point); |
| 518 | if (entry == nullptr) { |
| 519 | return Error() << "Can't find " << mount_point << " in /proc/mounts"; |
| 520 | } |
| 521 | return entry->blk_device; |
| 522 | } |
| 523 | |
| 524 | Result<void> ReadDevice(const std::string& block_device) { |
| 525 | static constexpr int kBlockSize = 4096; |
| 526 | static constexpr size_t kBufSize = 1024 * kBlockSize; |
| 527 | std::vector<uint8_t> buffer(kBufSize); |
| 528 | |
| 529 | unique_fd fd(TEMP_FAILURE_RETRY(open(block_device.c_str(), O_RDONLY))); |
| 530 | if (fd.get() == -1) { |
| 531 | return ErrnoError() << "Can't open " << block_device; |
| 532 | } |
| 533 | |
| 534 | while (true) { |
| 535 | int n = read(fd.get(), buffer.data(), kBufSize); |
| 536 | if (n < 0) { |
| 537 | return ErrnoError() << "Failed to read " << block_device; |
| 538 | } |
| 539 | if (n == 0) { |
| 540 | break; |
| 541 | } |
| 542 | } |
| 543 | return {}; |
| 544 | } |
| 545 | |
Nikita Ioffe | 88752d9 | 2020-01-02 21:55:35 +0000 | [diff] [blame] | 546 | std::vector<std::string> ListSlavesOfDmDevice(const std::string& name) { |
| 547 | DeviceMapper& dm = DeviceMapper::Instance(); |
| 548 | std::string dm_path; |
| 549 | EXPECT_TRUE(dm.GetDmDevicePathByName(name, &dm_path)) |
| 550 | << "Failed to get path of dm device " << name; |
| 551 | // It's a little bit sad we can't use ConsumePrefix here :( |
| 552 | constexpr std::string_view kDevPrefix = "/dev/"; |
| 553 | EXPECT_TRUE(StartsWith(dm_path, kDevPrefix)) << "Illegal path " << dm_path; |
| 554 | dm_path = dm_path.substr(kDevPrefix.length()); |
| 555 | std::vector<std::string> slaves; |
| 556 | { |
| 557 | std::string slaves_dir = "/sys/" + dm_path + "/slaves"; |
| 558 | auto st = WalkDir(slaves_dir, [&](const auto& entry) { |
| 559 | std::error_code ec; |
| 560 | if (entry.is_symlink(ec)) { |
| 561 | slaves.push_back("/dev/block/" + entry.path().filename().string()); |
| 562 | } |
| 563 | if (ec) { |
| 564 | ADD_FAILURE() << "Failed to scan " << slaves_dir << " : " << ec; |
| 565 | } |
| 566 | }); |
| 567 | EXPECT_TRUE(IsOk(st)); |
| 568 | } |
| 569 | return slaves; |
| 570 | } |
| 571 | |
Nikita Ioffe | 78d2bce | 2020-05-02 01:28:30 +0100 | [diff] [blame] | 572 | Result<void> CopyFile(const std::string& from, const std::string& to, |
| 573 | const fs::copy_options& options) { |
| 574 | std::error_code ec; |
| 575 | if (!fs::copy_file(from, to, options)) { |
| 576 | return Error() << "Failed to copy file " << from << " to " << to << " : " |
| 577 | << ec.message(); |
| 578 | } |
| 579 | return {}; |
| 580 | } |
| 581 | |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 582 | } // namespace |
| 583 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 584 | TEST_F(ApexServiceTest, HaveSelinux) { |
| 585 | // We want to test under selinux. |
| 586 | EXPECT_TRUE(HaveSelinux()); |
| 587 | } |
| 588 | |
Andreas Gampe | 1b6fa37 | 2018-11-05 09:47:28 -0800 | [diff] [blame] | 589 | // Skip for b/119032200. |
| 590 | TEST_F(ApexServiceTest, DISABLED_EnforceSelinux) { |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 591 | // Crude cutout for virtual devices. |
| 592 | #if !defined(__i386__) && !defined(__x86_64__) |
| 593 | constexpr bool kIsX86 = false; |
| 594 | #else |
| 595 | constexpr bool kIsX86 = true; |
| 596 | #endif |
| 597 | EXPECT_TRUE(IsSelinuxEnforced() || kIsX86); |
| 598 | } |
| 599 | |
| 600 | TEST_F(ApexServiceTest, StageFailAccess) { |
| 601 | if (!IsSelinuxEnforced()) { |
| 602 | LOG(WARNING) << "Skipping InstallFailAccess because of selinux"; |
| 603 | return; |
| 604 | } |
| 605 | |
| 606 | // Use an extra copy, so that even if this test fails (incorrectly installs), |
| 607 | // we have the testdata file still around. |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 608 | std::string orig_test_file = GetTestFile("apex.apexd_test.apex"); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 609 | std::string test_file = orig_test_file + ".2"; |
| 610 | ASSERT_EQ(0, link(orig_test_file.c_str(), test_file.c_str())) |
| 611 | << strerror(errno); |
| 612 | struct Deleter { |
| 613 | std::string to_delete; |
Nikita Ioffe | f94bda6 | 2019-06-18 01:13:38 +0100 | [diff] [blame] | 614 | explicit Deleter(std::string t) : to_delete(std::move(t)) {} |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 615 | ~Deleter() { |
| 616 | if (unlink(to_delete.c_str()) != 0) { |
| 617 | PLOG(ERROR) << "Could not unlink " << to_delete; |
| 618 | } |
| 619 | } |
| 620 | }; |
| 621 | Deleter del(test_file); |
| 622 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 623 | android::binder::Status st = service_->stagePackages({test_file}); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 624 | ASSERT_FALSE(IsOk(st)); |
Nikita Ioffe | c553626 | 2019-03-29 17:01:58 +0000 | [diff] [blame] | 625 | std::string error = st.exceptionMessage().c_str(); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 626 | EXPECT_NE(std::string::npos, error.find("Failed to open package")) << error; |
| 627 | EXPECT_NE(std::string::npos, error.find("I/O error")) << error; |
| 628 | } |
| 629 | |
Nikita Ioffe | d36c703 | 2020-04-24 18:50:39 +0100 | [diff] [blame] | 630 | TEST_F(ApexServiceTest, StageFailKey) { |
Andreas Gampe | cfb1ffe | 2018-12-26 15:23:53 -0800 | [diff] [blame] | 631 | PrepareTestApexForInstall installer( |
| 632 | GetTestFile("apex.apexd_test_no_inst_key.apex")); |
| 633 | if (!installer.Prepare()) { |
| 634 | return; |
| 635 | } |
| 636 | ASSERT_EQ(std::string("com.android.apex.test_package.no_inst_key"), |
| 637 | installer.package); |
| 638 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 639 | android::binder::Status st = service_->stagePackages({installer.test_file}); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 640 | ASSERT_FALSE(IsOk(st)); |
Jiyong Park | 997fcbf | 2018-12-27 16:07:49 +0900 | [diff] [blame] | 641 | |
| 642 | // May contain one of two errors. |
Nikita Ioffe | c553626 | 2019-03-29 17:01:58 +0000 | [diff] [blame] | 643 | std::string error = st.exceptionMessage().c_str(); |
Jiyong Park | 997fcbf | 2018-12-27 16:07:49 +0900 | [diff] [blame] | 644 | |
Nikita Ioffe | d36c703 | 2020-04-24 18:50:39 +0100 | [diff] [blame] | 645 | ASSERT_THAT(error, HasSubstr("No preinstalled data found for package " |
| 646 | "com.android.apex.test_package.no_inst_key")); |
Andreas Gampe | cfb1ffe | 2018-12-26 15:23:53 -0800 | [diff] [blame] | 647 | } |
| 648 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 649 | TEST_F(ApexServiceTest, StageSuccess) { |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 650 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 651 | if (!installer.Prepare()) { |
| 652 | return; |
| 653 | } |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 654 | ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 655 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 656 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 657 | EXPECT_TRUE(RegularFileExists(installer.test_installed_file)); |
| 658 | } |
| 659 | |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 660 | TEST_F(ApexServiceTest, |
| 661 | SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices) { |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 662 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
| 663 | "/data/app-staging/session_1543", |
| 664 | "staging_data_file"); |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 665 | if (!installer.Prepare()) { |
| 666 | return; |
| 667 | } |
| 668 | |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 669 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 670 | ApexSessionParams params; |
| 671 | params.sessionId = 1543; |
| 672 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 673 | |
| 674 | std::vector<DeviceMapper::DmBlockDevice> devices; |
| 675 | DeviceMapper& dm = DeviceMapper::Instance(); |
| 676 | ASSERT_TRUE(dm.GetAvailableDevices(&devices)); |
| 677 | |
| 678 | for (const auto& device : devices) { |
| 679 | ASSERT_THAT(device.name(), Not(EndsWith(".tmp"))); |
| 680 | } |
| 681 | } |
| 682 | |
Gavin Corkery | 778cace | 2019-09-26 12:53:45 +0100 | [diff] [blame] | 683 | TEST_F(ApexServiceTest, SubmitStagedSessionStoresBuildFingerprint) { |
| 684 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
| 685 | "/data/app-staging/session_1547", |
| 686 | "staging_data_file"); |
| 687 | if (!installer.Prepare()) { |
| 688 | return; |
| 689 | } |
| 690 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 691 | ApexSessionParams params; |
| 692 | params.sessionId = 1547; |
| 693 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Gavin Corkery | 778cace | 2019-09-26 12:53:45 +0100 | [diff] [blame] | 694 | |
| 695 | auto session = ApexSession::GetSession(1547); |
| 696 | ASSERT_FALSE(session->GetBuildFingerprint().empty()); |
| 697 | } |
| 698 | |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 699 | TEST_F(ApexServiceTest, SubmitStagedSessionFailDoesNotLeakTempVerityDevices) { |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 700 | PrepareTestApexForInstall installer( |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 701 | GetTestFile("apex.apexd_test_manifest_mismatch.apex"), |
| 702 | "/data/app-staging/session_239", "staging_data_file"); |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 703 | if (!installer.Prepare()) { |
| 704 | return; |
| 705 | } |
| 706 | |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 707 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 708 | ApexSessionParams params; |
| 709 | params.sessionId = 239; |
| 710 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 711 | |
| 712 | std::vector<DeviceMapper::DmBlockDevice> devices; |
| 713 | DeviceMapper& dm = DeviceMapper::Instance(); |
| 714 | ASSERT_TRUE(dm.GetAvailableDevices(&devices)); |
| 715 | |
| 716 | for (const auto& device : devices) { |
| 717 | ASSERT_THAT(device.name(), Not(EndsWith(".tmp"))); |
| 718 | } |
| 719 | } |
| 720 | |
Nikita Ioffe | 6a280af | 2019-02-04 15:28:57 +0000 | [diff] [blame] | 721 | TEST_F(ApexServiceTest, StageSuccess_ClearsPreviouslyActivePackage) { |
| 722 | PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test_v2.apex")); |
| 723 | PrepareTestApexForInstall installer2( |
| 724 | GetTestFile("apex.apexd_test_different_app.apex")); |
| 725 | PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test.apex")); |
| 726 | auto install_fn = [&](PrepareTestApexForInstall& installer) { |
| 727 | if (!installer.Prepare()) { |
| 728 | return; |
| 729 | } |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 730 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 6a280af | 2019-02-04 15:28:57 +0000 | [diff] [blame] | 731 | EXPECT_TRUE(RegularFileExists(installer.test_installed_file)); |
| 732 | }; |
| 733 | install_fn(installer1); |
| 734 | install_fn(installer2); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 735 | // Simulating a revert. After this call test_v2_apex_path should be removed. |
Nikita Ioffe | 6a280af | 2019-02-04 15:28:57 +0000 | [diff] [blame] | 736 | install_fn(installer3); |
| 737 | |
| 738 | EXPECT_FALSE(RegularFileExists(installer1.test_installed_file)); |
| 739 | EXPECT_TRUE(RegularFileExists(installer2.test_installed_file)); |
| 740 | EXPECT_TRUE(RegularFileExists(installer3.test_installed_file)); |
| 741 | } |
| 742 | |
Nikita Ioffe | a836576 | 2019-03-18 23:59:03 +0000 | [diff] [blame] | 743 | TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccess) { |
Nikita Ioffe | 8be420a | 2019-02-13 20:51:05 +0000 | [diff] [blame] | 744 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); |
| 745 | if (!installer.Prepare()) { |
| 746 | return; |
| 747 | } |
| 748 | ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); |
| 749 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 750 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 8be420a | 2019-02-13 20:51:05 +0000 | [diff] [blame] | 751 | ASSERT_TRUE(RegularFileExists(installer.test_installed_file)); |
| 752 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 753 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 8be420a | 2019-02-13 20:51:05 +0000 | [diff] [blame] | 754 | ASSERT_TRUE(RegularFileExists(installer.test_installed_file)); |
| 755 | } |
| 756 | |
Nikita Ioffe | 7943f21 | 2019-11-07 13:35:26 +0000 | [diff] [blame] | 757 | TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccessNewWins) { |
| 758 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); |
| 759 | PrepareTestApexForInstall installer2( |
| 760 | GetTestFile("apex.apexd_test_nocode.apex")); |
| 761 | if (!installer.Prepare() || !installer2.Prepare()) { |
| 762 | return; |
| 763 | } |
| 764 | ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); |
| 765 | ASSERT_EQ(installer.test_installed_file, installer2.test_installed_file); |
| 766 | |
| 767 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
| 768 | const auto& apex = ApexFile::Open(installer.test_installed_file); |
| 769 | ASSERT_TRUE(IsOk(apex)); |
| 770 | ASSERT_FALSE(apex->GetManifest().nocode()); |
| 771 | |
| 772 | ASSERT_TRUE(IsOk(service_->stagePackages({installer2.test_file}))); |
| 773 | const auto& new_apex = ApexFile::Open(installer.test_installed_file); |
| 774 | ASSERT_TRUE(IsOk(new_apex)); |
| 775 | ASSERT_TRUE(new_apex->GetManifest().nocode()); |
| 776 | } |
| 777 | |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 778 | TEST_F(ApexServiceTest, MultiStageSuccess) { |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 779 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 780 | if (!installer.Prepare()) { |
| 781 | return; |
| 782 | } |
| 783 | ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); |
| 784 | |
| 785 | // TODO: Add second test. Right now, just use a separate version. |
Andreas Gampe | 0562bc5 | 2018-12-12 15:03:58 -0800 | [diff] [blame] | 786 | PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex")); |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 787 | if (!installer2.Prepare()) { |
| 788 | return; |
| 789 | } |
| 790 | ASSERT_EQ(std::string("com.android.apex.test_package"), installer2.package); |
| 791 | |
| 792 | std::vector<std::string> packages; |
| 793 | packages.push_back(installer.test_file); |
| 794 | packages.push_back(installer2.test_file); |
| 795 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 796 | ASSERT_TRUE(IsOk(service_->stagePackages(packages))); |
Andreas Gampe | a00c545 | 2018-12-10 13:38:33 -0800 | [diff] [blame] | 797 | EXPECT_TRUE(RegularFileExists(installer.test_installed_file)); |
| 798 | EXPECT_TRUE(RegularFileExists(installer2.test_installed_file)); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 799 | } |
| 800 | |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 801 | TEST_F(ApexServiceTest, CannotBeRollbackAndHaveRollbackEnabled) { |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 802 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
| 803 | "/data/app-staging/session_1543", |
| 804 | "staging_data_file"); |
| 805 | if (!installer.Prepare()) { |
| 806 | return; |
| 807 | } |
| 808 | |
| 809 | ApexInfoList list; |
| 810 | ApexSessionParams params; |
| 811 | params.sessionId = 1543; |
| 812 | params.isRollback = true; |
| 813 | params.hasRollbackEnabled = true; |
| 814 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
| 815 | } |
| 816 | |
| 817 | TEST_F(ApexServiceTest, SessionParamDefaults) { |
| 818 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
| 819 | "/data/app-staging/session_1547", |
| 820 | "staging_data_file"); |
| 821 | if (!installer.Prepare()) { |
| 822 | return; |
| 823 | } |
| 824 | ApexInfoList list; |
| 825 | ApexSessionParams params; |
| 826 | params.sessionId = 1547; |
| 827 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
| 828 | |
| 829 | auto session = ApexSession::GetSession(1547); |
| 830 | ASSERT_TRUE(session->GetChildSessionIds().empty()); |
| 831 | ASSERT_FALSE(session->IsRollback()); |
| 832 | ASSERT_FALSE(session->HasRollbackEnabled()); |
| 833 | ASSERT_EQ(0, session->GetRollbackId()); |
| 834 | } |
| 835 | |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 836 | TEST_F(ApexServiceTest, SnapshotCeData) { |
Oli Lan | 042fbcf | 2020-01-17 11:14:16 +0000 | [diff] [blame] | 837 | CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test"); |
| 838 | CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt"); |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 839 | |
| 840 | ASSERT_TRUE( |
| 841 | RegularFileExists("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt")); |
| 842 | |
| 843 | int64_t result; |
| 844 | service_->snapshotCeData(0, 123456, "apex.apexd_test", &result); |
| 845 | |
| 846 | ASSERT_TRUE(RegularFileExists( |
| 847 | "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/hello.txt")); |
| 848 | |
| 849 | // Check that the return value is the inode of the snapshot directory. |
| 850 | struct stat buf; |
| 851 | memset(&buf, 0, sizeof(buf)); |
| 852 | ASSERT_EQ(0, |
| 853 | stat("/data/misc_ce/0/apexrollback/123456/apex.apexd_test", &buf)); |
| 854 | ASSERT_EQ(int64_t(buf.st_ino), result); |
| 855 | } |
| 856 | |
| 857 | TEST_F(ApexServiceTest, RestoreCeData) { |
Oli Lan | 042fbcf | 2020-01-17 11:14:16 +0000 | [diff] [blame] | 858 | CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test"); |
| 859 | CreateDir("/data/misc_ce/0/apexrollback/123456"); |
| 860 | CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"); |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 861 | |
Oli Lan | 042fbcf | 2020-01-17 11:14:16 +0000 | [diff] [blame] | 862 | CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"); |
| 863 | CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt"); |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 864 | |
| 865 | ASSERT_TRUE(RegularFileExists( |
| 866 | "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt")); |
| 867 | ASSERT_TRUE(RegularFileExists( |
| 868 | "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt")); |
| 869 | |
| 870 | service_->restoreCeData(0, 123456, "apex.apexd_test"); |
| 871 | |
| 872 | ASSERT_TRUE(RegularFileExists( |
| 873 | "/data/misc_ce/0/apexdata/apex.apexd_test/oldfile.txt")); |
| 874 | ASSERT_FALSE(RegularFileExists( |
| 875 | "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt")); |
JW Wang | 3c6c290 | 2020-05-13 10:51:32 +0800 | [diff] [blame] | 876 | // The snapshot should be deleted after restoration. |
| 877 | ASSERT_FALSE( |
| 878 | DirExists("/data/misc_ce/0/apexrollback/123456/apex.apexd_test")); |
Oli Lan | 2d59dfa | 2020-01-14 20:25:09 +0000 | [diff] [blame] | 879 | } |
| 880 | |
Oli Lan | 042fbcf | 2020-01-17 11:14:16 +0000 | [diff] [blame] | 881 | TEST_F(ApexServiceTest, DestroyDeSnapshots_DeSys) { |
| 882 | CreateDir("/data/misc/apexrollback/123456"); |
| 883 | CreateDir("/data/misc/apexrollback/123456/my.apex"); |
| 884 | CreateFile("/data/misc/apexrollback/123456/my.apex/hello.txt"); |
| 885 | |
| 886 | ASSERT_TRUE( |
| 887 | RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt")); |
| 888 | |
| 889 | service_->destroyDeSnapshots(8975); |
| 890 | ASSERT_TRUE( |
| 891 | RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt")); |
| 892 | |
| 893 | service_->destroyDeSnapshots(123456); |
| 894 | ASSERT_FALSE( |
| 895 | RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt")); |
| 896 | ASSERT_FALSE(DirExists("/data/misc/apexrollback/123456")); |
| 897 | } |
| 898 | |
| 899 | TEST_F(ApexServiceTest, DestroyDeSnapshots_DeUser) { |
| 900 | CreateDir("/data/misc_de/0/apexrollback/123456"); |
| 901 | CreateDir("/data/misc_de/0/apexrollback/123456/my.apex"); |
| 902 | CreateFile("/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"); |
| 903 | |
| 904 | ASSERT_TRUE(RegularFileExists( |
| 905 | "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt")); |
| 906 | |
| 907 | service_->destroyDeSnapshots(8975); |
| 908 | ASSERT_TRUE(RegularFileExists( |
| 909 | "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt")); |
| 910 | |
| 911 | service_->destroyDeSnapshots(123456); |
| 912 | ASSERT_FALSE(RegularFileExists( |
| 913 | "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt")); |
| 914 | ASSERT_FALSE(DirExists("/data/misc_de/0/apexrollback/123456")); |
| 915 | } |
| 916 | |
Oli Lan | 2993ccc | 2020-03-06 18:06:40 +0000 | [diff] [blame] | 917 | TEST_F(ApexServiceTest, DestroyCeSnapshotsNotSpecified) { |
| 918 | CreateDir("/data/misc_ce/0/apexrollback/123456"); |
| 919 | CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"); |
| 920 | CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"); |
| 921 | |
| 922 | CreateDir("/data/misc_ce/0/apexrollback/77777"); |
| 923 | CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test"); |
| 924 | CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"); |
| 925 | |
| 926 | CreateDir("/data/misc_ce/0/apexrollback/98765"); |
| 927 | CreateDir("/data/misc_ce/0/apexrollback/98765/apex.apexd_test"); |
| 928 | CreateFile("/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt"); |
| 929 | |
| 930 | ASSERT_TRUE(RegularFileExists( |
| 931 | "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt")); |
| 932 | ASSERT_TRUE(RegularFileExists( |
| 933 | "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt")); |
| 934 | ASSERT_TRUE(RegularFileExists( |
| 935 | "/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt")); |
| 936 | |
| 937 | std::vector<int> retain{123, 77777, 987654}; |
| 938 | android::binder::Status st = |
| 939 | service_->destroyCeSnapshotsNotSpecified(0, retain); |
| 940 | ASSERT_TRUE(IsOk(st)); |
| 941 | |
| 942 | ASSERT_TRUE(RegularFileExists( |
| 943 | "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt")); |
| 944 | ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456")); |
| 945 | ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/98765")); |
| 946 | } |
| 947 | |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 948 | template <typename NameProvider> |
| 949 | class ApexServiceActivationTest : public ApexServiceTest { |
| 950 | public: |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 951 | ApexServiceActivationTest() : stage_package(true) {} |
| 952 | |
Nikita Ioffe | bca0bc1 | 2019-06-17 18:54:13 +0100 | [diff] [blame] | 953 | explicit ApexServiceActivationTest(bool stage_package) |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 954 | : stage_package(stage_package) {} |
| 955 | |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 956 | void SetUp() override { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 957 | // TODO(b/136647373): Move this check to environment setup |
| 958 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 959 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 960 | } |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 961 | ApexServiceTest::SetUp(); |
| 962 | ASSERT_NE(nullptr, service_.get()); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 963 | |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 964 | installer_ = std::make_unique<PrepareTestApexForInstall>( |
| 965 | GetTestFile(NameProvider::GetTestName())); |
| 966 | if (!installer_->Prepare()) { |
| 967 | return; |
| 968 | } |
| 969 | ASSERT_EQ(NameProvider::GetPackageName(), installer_->package); |
| 970 | |
| 971 | { |
| 972 | // Check package is not active. |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 973 | std::string path = stage_package ? installer_->test_installed_file |
| 974 | : installer_->test_file; |
| 975 | Result<bool> active = |
| 976 | IsActive(installer_->package, installer_->version, path); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 977 | ASSERT_TRUE(IsOk(active)); |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 978 | ASSERT_FALSE(*active); |
| 979 | } |
| 980 | |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 981 | if (stage_package) { |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 982 | ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file}))); |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 983 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 984 | } |
| 985 | |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 986 | void TearDown() override { |
| 987 | // Attempt to deactivate. |
| 988 | if (installer_ != nullptr) { |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 989 | if (stage_package) { |
| 990 | service_->deactivatePackage(installer_->test_installed_file); |
| 991 | } else { |
| 992 | service_->deactivatePackage(installer_->test_file); |
| 993 | } |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 994 | } |
| 995 | |
| 996 | installer_.reset(); |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 997 | // ApexServiceTest::TearDown will wipe out everything under /data/apex. |
Roland Levillain | eaed544 | 2019-06-26 16:55:08 +0100 | [diff] [blame] | 998 | // Since some of that information is required for deactivatePackage binder |
Nikita Ioffe | 816a02b | 2019-02-16 16:49:45 +0000 | [diff] [blame] | 999 | // call, it's required to be called after deactivating package. |
| 1000 | ApexServiceTest::TearDown(); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1001 | } |
| 1002 | |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 1003 | std::unique_ptr<PrepareTestApexForInstall> installer_; |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 1004 | |
| 1005 | private: |
| 1006 | bool stage_package; |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 1007 | }; |
| 1008 | |
| 1009 | struct SuccessNameProvider { |
| 1010 | static std::string GetTestName() { return "apex.apexd_test.apex"; } |
| 1011 | static std::string GetPackageName() { |
| 1012 | return "com.android.apex.test_package"; |
| 1013 | } |
| 1014 | }; |
| 1015 | |
Martijn Coenen | 329f112 | 2019-02-28 16:10:08 +0100 | [diff] [blame] | 1016 | struct ManifestMismatchNameProvider { |
| 1017 | static std::string GetTestName() { |
| 1018 | return "apex.apexd_test_manifest_mismatch.apex"; |
| 1019 | } |
| 1020 | static std::string GetPackageName() { |
| 1021 | return "com.android.apex.test_package"; |
| 1022 | } |
| 1023 | }; |
| 1024 | |
| 1025 | class ApexServiceActivationManifestMismatchFailure |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 1026 | : public ApexServiceActivationTest<ManifestMismatchNameProvider> { |
| 1027 | public: |
| 1028 | ApexServiceActivationManifestMismatchFailure() |
| 1029 | : ApexServiceActivationTest(false) {} |
| 1030 | }; |
Martijn Coenen | 329f112 | 2019-02-28 16:10:08 +0100 | [diff] [blame] | 1031 | |
| 1032 | TEST_F(ApexServiceActivationManifestMismatchFailure, |
| 1033 | ActivateFailsWithManifestMismatch) { |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 1034 | android::binder::Status st = service_->activatePackage(installer_->test_file); |
Martijn Coenen | 329f112 | 2019-02-28 16:10:08 +0100 | [diff] [blame] | 1035 | ASSERT_FALSE(IsOk(st)); |
| 1036 | |
Nikita Ioffe | c553626 | 2019-03-29 17:01:58 +0000 | [diff] [blame] | 1037 | std::string error = st.exceptionMessage().c_str(); |
Nikita Ioffe | 891723c | 2019-03-25 14:35:39 +0000 | [diff] [blame] | 1038 | ASSERT_THAT( |
| 1039 | error, |
| 1040 | HasSubstr( |
| 1041 | "Manifest inside filesystem does not match manifest outside it")); |
Martijn Coenen | 329f112 | 2019-02-28 16:10:08 +0100 | [diff] [blame] | 1042 | } |
| 1043 | |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 1044 | class ApexServiceActivationSuccessTest |
| 1045 | : public ApexServiceActivationTest<SuccessNameProvider> {}; |
| 1046 | |
| 1047 | TEST_F(ApexServiceActivationSuccessTest, Activate) { |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1048 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1049 | << GetDebugStr(installer_.get()); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1050 | |
| 1051 | { |
| 1052 | // Check package is active. |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 1053 | Result<bool> active = IsActive(installer_->package, installer_->version, |
| 1054 | installer_->test_installed_file); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1055 | ASSERT_TRUE(IsOk(active)); |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 1056 | ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ','); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1057 | } |
| 1058 | |
| 1059 | { |
| 1060 | // Check that the "latest" view exists. |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 1061 | std::string latest_path = |
| 1062 | std::string(kApexRoot) + "/" + installer_->package; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1063 | struct stat buf; |
| 1064 | ASSERT_EQ(0, stat(latest_path.c_str(), &buf)) << strerror(errno); |
| 1065 | // Check that it is a folder. |
| 1066 | EXPECT_TRUE(S_ISDIR(buf.st_mode)); |
| 1067 | |
| 1068 | // Collect direct entries of a folder. |
Nikita Ioffe | fe8b14d | 2019-06-21 01:21:13 +0100 | [diff] [blame] | 1069 | auto collect_entries_fn = [&](const std::string& path) { |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1070 | std::vector<std::string> ret; |
Nikita Ioffe | fe8b14d | 2019-06-21 01:21:13 +0100 | [diff] [blame] | 1071 | auto status = WalkDir(path, [&](const fs::directory_entry& entry) { |
Mohammad Samiul Islam | 2d56f37 | 2019-03-27 17:07:57 +0000 | [diff] [blame] | 1072 | if (!entry.is_directory()) { |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 1073 | return; |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1074 | } |
Jooyung Han | 3d43d32 | 2019-05-08 12:16:24 +0900 | [diff] [blame] | 1075 | ret.emplace_back(entry.path().filename()); |
| 1076 | }); |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1077 | CHECK(status.has_value()) |
| 1078 | << "Failed to list " << path << " : " << status.error(); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1079 | std::sort(ret.begin(), ret.end()); |
| 1080 | return ret; |
| 1081 | }; |
| 1082 | |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 1083 | std::string versioned_path = std::string(kApexRoot) + "/" + |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 1084 | installer_->package + "@" + |
| 1085 | std::to_string(installer_->version); |
Andreas Gampe | c45bf32 | 2018-12-06 13:57:45 -0800 | [diff] [blame] | 1086 | std::vector<std::string> versioned_folder_entries = |
| 1087 | collect_entries_fn(versioned_path); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1088 | std::vector<std::string> latest_folder_entries = |
| 1089 | collect_entries_fn(latest_path); |
| 1090 | |
| 1091 | EXPECT_TRUE(versioned_folder_entries == latest_folder_entries) |
Andreas Gampe | 7f4ff35 | 2018-12-11 08:58:03 -0800 | [diff] [blame] | 1092 | << "Versioned: " << Join(versioned_folder_entries, ',') |
| 1093 | << " Latest: " << Join(latest_folder_entries, ','); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1094 | } |
Andreas Gampe | a2bbbbe | 2018-12-21 15:05:48 -0800 | [diff] [blame] | 1095 | } |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 1096 | |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1097 | TEST_F(ApexServiceActivationSuccessTest, GetActivePackages) { |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1098 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1099 | << GetDebugStr(installer_.get()); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1100 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1101 | Result<std::vector<ApexInfo>> active = GetActivePackages(); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1102 | ASSERT_TRUE(IsOk(active)); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1103 | ApexInfo match; |
| 1104 | |
Dario Freni | 6425511 | 2019-02-18 22:13:38 +0000 | [diff] [blame] | 1105 | for (const ApexInfo& info : *active) { |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1106 | if (info.moduleName == installer_->package) { |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1107 | match = info; |
| 1108 | break; |
| 1109 | } |
| 1110 | } |
| 1111 | |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1112 | ASSERT_EQ(installer_->package, match.moduleName); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1113 | ASSERT_EQ(installer_->version, static_cast<uint64_t>(match.versionCode)); |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1114 | ASSERT_EQ(installer_->test_installed_file, match.modulePath); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1115 | } |
| 1116 | |
| 1117 | TEST_F(ApexServiceActivationSuccessTest, GetActivePackage) { |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1118 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1119 | << GetDebugStr(installer_.get()); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1120 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1121 | Result<ApexInfo> active = GetActivePackage(installer_->package); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1122 | ASSERT_TRUE(IsOk(active)); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1123 | |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1124 | ASSERT_EQ(installer_->package, active->moduleName); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1125 | ASSERT_EQ(installer_->version, static_cast<uint64_t>(active->versionCode)); |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1126 | ASSERT_EQ(installer_->test_installed_file, active->modulePath); |
Narayan Kamath | 5ea5778 | 2019-01-03 18:17:05 +0000 | [diff] [blame] | 1127 | } |
| 1128 | |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 1129 | TEST_F(ApexServiceActivationSuccessTest, ShowsUpInMountedApexDatabase) { |
| 1130 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1131 | << GetDebugStr(installer_.get()); |
| 1132 | |
| 1133 | MountedApexDatabase db; |
| 1134 | db.PopulateFromMounts(); |
| 1135 | |
| 1136 | std::optional<MountedApexData> mounted_apex; |
| 1137 | db.ForallMountedApexes(installer_->package, |
| 1138 | [&](const MountedApexData& d, bool active) { |
| 1139 | if (active) { |
| 1140 | mounted_apex.emplace(d); |
| 1141 | } |
| 1142 | }); |
| 1143 | ASSERT_TRUE(mounted_apex) |
| 1144 | << "Haven't found " << installer_->test_installed_file |
| 1145 | << " in the database of mounted apexes"; |
| 1146 | |
| 1147 | // Get all necessary data for assertions on mounted_apex. |
| 1148 | std::string package_id = |
| 1149 | installer_->package + "@" + std::to_string(installer_->version); |
| 1150 | DeviceMapper& dm = DeviceMapper::Instance(); |
| 1151 | std::string dm_path; |
| 1152 | ASSERT_TRUE(dm.GetDmDevicePathByName(package_id, &dm_path)) |
| 1153 | << "Failed to get path of dm device " << package_id; |
| 1154 | auto loop_device = dm.GetParentBlockDeviceByPath(dm_path); |
| 1155 | ASSERT_TRUE(loop_device) << "Failed to find parent block device of " |
| 1156 | << dm_path; |
| 1157 | |
| 1158 | // Now we are ready to assert on mounted_apex. |
| 1159 | ASSERT_EQ(*loop_device, mounted_apex->loop_name); |
| 1160 | ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path); |
| 1161 | std::string expected_mount = std::string(kApexRoot) + "/" + package_id; |
| 1162 | ASSERT_EQ(expected_mount, mounted_apex->mount_point); |
| 1163 | ASSERT_EQ(package_id, mounted_apex->device_name); |
| 1164 | ASSERT_EQ("", mounted_apex->hashtree_loop_name); |
| 1165 | } |
| 1166 | |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1167 | struct NoHashtreeApexNameProvider { |
| 1168 | static std::string GetTestName() { |
| 1169 | return "apex.apexd_test_no_hashtree.apex"; |
| 1170 | } |
| 1171 | static std::string GetPackageName() { |
| 1172 | return "com.android.apex.test_package"; |
| 1173 | } |
| 1174 | }; |
| 1175 | |
| 1176 | class ApexServiceNoHashtreeApexActivationTest |
| 1177 | : public ApexServiceActivationTest<NoHashtreeApexNameProvider> {}; |
| 1178 | |
| 1179 | TEST_F(ApexServiceNoHashtreeApexActivationTest, Activate) { |
| 1180 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1181 | << GetDebugStr(installer_.get()); |
| 1182 | { |
| 1183 | // Check package is active. |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 1184 | Result<bool> active = IsActive(installer_->package, installer_->version, |
| 1185 | installer_->test_installed_file); |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1186 | ASSERT_TRUE(IsOk(active)); |
| 1187 | ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ','); |
| 1188 | } |
| 1189 | |
| 1190 | std::string package_id = |
| 1191 | installer_->package + "@" + std::to_string(installer_->version); |
| 1192 | // Check that hashtree file was created. |
| 1193 | { |
| 1194 | std::string hashtree_path = |
| 1195 | std::string(kApexHashTreeDir) + "/" + package_id; |
| 1196 | auto exists = PathExists(hashtree_path); |
| 1197 | ASSERT_TRUE(IsOk(exists)); |
| 1198 | ASSERT_TRUE(*exists); |
| 1199 | } |
| 1200 | |
| 1201 | // Check that block device can be read. |
| 1202 | auto block_device = GetBlockDeviceForApex(package_id); |
| 1203 | ASSERT_TRUE(IsOk(block_device)); |
| 1204 | ASSERT_TRUE(IsOk(ReadDevice(*block_device))); |
| 1205 | } |
| 1206 | |
| 1207 | TEST_F(ApexServiceNoHashtreeApexActivationTest, |
| 1208 | NewSessionDoesNotImpactActivePackage) { |
| 1209 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1210 | << GetDebugStr(installer_.get()); |
| 1211 | { |
| 1212 | // Check package is active. |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 1213 | Result<bool> active = IsActive(installer_->package, installer_->version, |
| 1214 | installer_->test_installed_file); |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1215 | ASSERT_TRUE(IsOk(active)); |
| 1216 | ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ','); |
| 1217 | } |
| 1218 | |
| 1219 | PrepareTestApexForInstall installer2( |
| 1220 | GetTestFile("apex.apexd_test_no_hashtree_2.apex"), |
| 1221 | "/data/app-staging/session_123", "staging_data_file"); |
| 1222 | if (!installer2.Prepare()) { |
| 1223 | FAIL(); |
| 1224 | } |
| 1225 | |
| 1226 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1227 | ApexSessionParams params; |
| 1228 | params.sessionId = 123; |
| 1229 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1230 | |
| 1231 | std::string package_id = |
| 1232 | installer_->package + "@" + std::to_string(installer_->version); |
| 1233 | // Check that new hashtree file was created. |
| 1234 | { |
| 1235 | std::string hashtree_path = |
| 1236 | std::string(kApexHashTreeDir) + "/" + package_id + ".new"; |
| 1237 | auto exists = PathExists(hashtree_path); |
| 1238 | ASSERT_TRUE(IsOk(exists)); |
Nikita Ioffe | 2b1c19a | 2020-01-01 22:53:44 +0000 | [diff] [blame] | 1239 | ASSERT_TRUE(*exists) << hashtree_path << " does not exist"; |
| 1240 | } |
| 1241 | // Check that active hashtree is still there. |
| 1242 | { |
| 1243 | std::string hashtree_path = |
| 1244 | std::string(kApexHashTreeDir) + "/" + package_id; |
| 1245 | auto exists = PathExists(hashtree_path); |
| 1246 | ASSERT_TRUE(IsOk(exists)); |
| 1247 | ASSERT_TRUE(*exists) << hashtree_path << " does not exist"; |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1248 | } |
| 1249 | |
| 1250 | // Check that block device of active APEX can still be read. |
| 1251 | auto block_device = GetBlockDeviceForApex(package_id); |
| 1252 | ASSERT_TRUE(IsOk(block_device)); |
| 1253 | } |
| 1254 | |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 1255 | TEST_F(ApexServiceNoHashtreeApexActivationTest, ShowsUpInMountedApexDatabase) { |
| 1256 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1257 | << GetDebugStr(installer_.get()); |
| 1258 | |
| 1259 | MountedApexDatabase db; |
| 1260 | db.PopulateFromMounts(); |
| 1261 | |
| 1262 | std::optional<MountedApexData> mounted_apex; |
| 1263 | db.ForallMountedApexes(installer_->package, |
| 1264 | [&](const MountedApexData& d, bool active) { |
| 1265 | if (active) { |
| 1266 | mounted_apex.emplace(d); |
| 1267 | } |
| 1268 | }); |
| 1269 | ASSERT_TRUE(mounted_apex) |
| 1270 | << "Haven't found " << installer_->test_installed_file |
| 1271 | << " in the database of mounted apexes"; |
| 1272 | |
| 1273 | // Get all necessary data for assertions on mounted_apex. |
| 1274 | std::string package_id = |
| 1275 | installer_->package + "@" + std::to_string(installer_->version); |
Nikita Ioffe | 88752d9 | 2020-01-02 21:55:35 +0000 | [diff] [blame] | 1276 | std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id); |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 1277 | ASSERT_EQ(2u, slaves.size()) |
| 1278 | << "Unexpected number of slaves: " << Join(slaves, ","); |
| 1279 | |
| 1280 | // Now we are ready to assert on mounted_apex. |
| 1281 | ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path); |
| 1282 | std::string expected_mount = std::string(kApexRoot) + "/" + package_id; |
| 1283 | ASSERT_EQ(expected_mount, mounted_apex->mount_point); |
| 1284 | ASSERT_EQ(package_id, mounted_apex->device_name); |
| 1285 | // For loops we only check that both loop_name and hashtree_loop_name are |
| 1286 | // slaves of the top device mapper device. |
| 1287 | ASSERT_THAT(slaves, Contains(mounted_apex->loop_name)); |
| 1288 | ASSERT_THAT(slaves, Contains(mounted_apex->hashtree_loop_name)); |
| 1289 | ASSERT_NE(mounted_apex->loop_name, mounted_apex->hashtree_loop_name); |
| 1290 | } |
| 1291 | |
Nikita Ioffe | 88752d9 | 2020-01-02 21:55:35 +0000 | [diff] [blame] | 1292 | TEST_F(ApexServiceNoHashtreeApexActivationTest, DeactivateFreesLoopDevices) { |
| 1293 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1294 | << GetDebugStr(installer_.get()); |
| 1295 | |
| 1296 | std::string package_id = |
| 1297 | installer_->package + "@" + std::to_string(installer_->version); |
| 1298 | std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id); |
| 1299 | ASSERT_EQ(2u, slaves.size()) |
| 1300 | << "Unexpected number of slaves: " << Join(slaves, ","); |
| 1301 | |
| 1302 | ASSERT_TRUE( |
| 1303 | IsOk(service_->deactivatePackage(installer_->test_installed_file))); |
| 1304 | |
| 1305 | for (const auto& loop : slaves) { |
| 1306 | struct loop_info li; |
| 1307 | unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC))); |
| 1308 | ASSERT_NE(-1, fd.get()) |
| 1309 | << "Failed to open " << loop << " : " << strerror(errno); |
| 1310 | ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li)) |
| 1311 | << loop << " is still alive"; |
| 1312 | ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno); |
| 1313 | } |
| 1314 | |
| 1315 | // Skip deactivatePackage on TearDown. |
| 1316 | installer_.reset(); |
| 1317 | } |
| 1318 | |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1319 | TEST_F(ApexServiceTest, NoHashtreeApexStagePackagesMovesHashtree) { |
| 1320 | PrepareTestApexForInstall installer( |
| 1321 | GetTestFile("apex.apexd_test_no_hashtree.apex"), |
| 1322 | "/data/app-staging/session_239", "staging_data_file"); |
| 1323 | if (!installer.Prepare()) { |
| 1324 | FAIL(); |
| 1325 | } |
| 1326 | |
| 1327 | auto read_fn = [](const std::string& path) -> std::vector<uint8_t> { |
| 1328 | static constexpr size_t kBufSize = 4096; |
| 1329 | std::vector<uint8_t> buffer(kBufSize); |
| 1330 | unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY))); |
| 1331 | if (fd.get() == -1) { |
| 1332 | PLOG(ERROR) << "Failed to open " << path; |
| 1333 | ADD_FAILURE(); |
| 1334 | return buffer; |
| 1335 | } |
| 1336 | if (!ReadFully(fd.get(), buffer.data(), kBufSize)) { |
| 1337 | PLOG(ERROR) << "Failed to read " << path; |
| 1338 | ADD_FAILURE(); |
| 1339 | } |
| 1340 | return buffer; |
| 1341 | }; |
| 1342 | |
| 1343 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1344 | ApexSessionParams params; |
| 1345 | params.sessionId = 239; |
| 1346 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 695b0a3 | 2019-12-05 17:17:41 +0000 | [diff] [blame] | 1347 | |
| 1348 | std::string package_id = |
| 1349 | installer.package + "@" + std::to_string(installer.version); |
| 1350 | // Check that new hashtree file was created. |
| 1351 | std::vector<uint8_t> original_hashtree_data; |
| 1352 | { |
| 1353 | std::string hashtree_path = |
| 1354 | std::string(kApexHashTreeDir) + "/" + package_id + ".new"; |
| 1355 | auto exists = PathExists(hashtree_path); |
| 1356 | ASSERT_TRUE(IsOk(exists)); |
| 1357 | ASSERT_TRUE(*exists); |
| 1358 | original_hashtree_data = read_fn(hashtree_path); |
| 1359 | } |
| 1360 | |
| 1361 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
| 1362 | // Check that hashtree file was moved. |
| 1363 | { |
| 1364 | std::string hashtree_path = |
| 1365 | std::string(kApexHashTreeDir) + "/" + package_id + ".new"; |
| 1366 | auto exists = PathExists(hashtree_path); |
| 1367 | ASSERT_TRUE(IsOk(exists)); |
| 1368 | ASSERT_FALSE(*exists); |
| 1369 | } |
| 1370 | { |
| 1371 | std::string hashtree_path = |
| 1372 | std::string(kApexHashTreeDir) + "/" + package_id; |
| 1373 | auto exists = PathExists(hashtree_path); |
| 1374 | ASSERT_TRUE(IsOk(exists)); |
| 1375 | ASSERT_TRUE(*exists); |
| 1376 | std::vector<uint8_t> moved_hashtree_data = read_fn(hashtree_path); |
| 1377 | ASSERT_EQ(moved_hashtree_data, original_hashtree_data); |
| 1378 | } |
| 1379 | } |
| 1380 | |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1381 | TEST_F(ApexServiceTest, GetFactoryPackages) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1382 | Result<std::vector<ApexInfo>> factoryPackages = GetFactoryPackages(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1383 | ASSERT_TRUE(IsOk(factoryPackages)); |
| 1384 | ASSERT_TRUE(factoryPackages->size() > 0); |
| 1385 | |
| 1386 | for (const ApexInfo& package : *factoryPackages) { |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1387 | ASSERT_TRUE(isPathForBuiltinApexes(package.modulePath)); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1388 | } |
| 1389 | } |
| 1390 | |
| 1391 | TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1392 | Result<std::vector<ApexInfo>> activePackages = GetActivePackages(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1393 | ASSERT_TRUE(IsOk(activePackages)); |
| 1394 | ASSERT_TRUE(activePackages->size() > 0); |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1395 | Result<std::vector<ApexInfo>> inactivePackages = GetInactivePackages(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1396 | ASSERT_TRUE(IsOk(inactivePackages)); |
| 1397 | std::vector<std::string> activePackagesStrings = |
| 1398 | GetPackagesStrings(*activePackages); |
| 1399 | std::vector<std::string> inactivePackagesStrings = |
| 1400 | GetPackagesStrings(*inactivePackages); |
| 1401 | std::sort(activePackagesStrings.begin(), activePackagesStrings.end()); |
| 1402 | std::sort(inactivePackagesStrings.begin(), inactivePackagesStrings.end()); |
| 1403 | std::vector<std::string> intersection; |
| 1404 | std::set_intersection( |
| 1405 | activePackagesStrings.begin(), activePackagesStrings.end(), |
| 1406 | inactivePackagesStrings.begin(), inactivePackagesStrings.end(), |
| 1407 | std::back_inserter(intersection)); |
Jooyung Han | 499de89 | 2020-05-12 12:01:05 +0900 | [diff] [blame] | 1408 | ASSERT_THAT(intersection, SizeIs(0)); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1409 | } |
| 1410 | |
| 1411 | TEST_F(ApexServiceTest, GetAllPackages) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1412 | Result<std::vector<ApexInfo>> allPackages = GetAllPackages(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1413 | ASSERT_TRUE(IsOk(allPackages)); |
| 1414 | ASSERT_TRUE(allPackages->size() > 0); |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1415 | Result<std::vector<ApexInfo>> activePackages = GetActivePackages(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1416 | std::vector<std::string> activeStrings = GetPackagesStrings(*activePackages); |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1417 | Result<std::vector<ApexInfo>> factoryPackages = GetFactoryPackages(); |
Gavin Corkery | d6ef030 | 2019-03-21 11:52:06 +0000 | [diff] [blame] | 1418 | std::vector<std::string> factoryStrings = |
| 1419 | GetPackagesStrings(*factoryPackages); |
| 1420 | for (ApexInfo& apexInfo : *allPackages) { |
| 1421 | std::string packageString = GetPackageString(apexInfo); |
| 1422 | bool shouldBeActive = std::find(activeStrings.begin(), activeStrings.end(), |
| 1423 | packageString) != activeStrings.end(); |
| 1424 | bool shouldBeFactory = |
| 1425 | std::find(factoryStrings.begin(), factoryStrings.end(), |
| 1426 | packageString) != factoryStrings.end(); |
| 1427 | ASSERT_EQ(shouldBeActive, apexInfo.isActive); |
| 1428 | ASSERT_EQ(shouldBeFactory, apexInfo.isFactory); |
| 1429 | } |
| 1430 | } |
| 1431 | |
Nikita Ioffe | d49bcd1 | 2019-08-30 11:56:52 +0100 | [diff] [blame] | 1432 | class ApexSameGradeOfPreInstalledVersionTest : public ApexServiceTest { |
| 1433 | public: |
| 1434 | void SetUp() override { |
| 1435 | // TODO(b/136647373): Move this check to environment setup |
| 1436 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 1437 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 1438 | } |
| 1439 | ApexServiceTest::SetUp(); |
| 1440 | ASSERT_NE(nullptr, service_.get()); |
| 1441 | |
| 1442 | installer_ = std::make_unique<PrepareTestApexForInstall>( |
| 1443 | GetTestFile("com.android.apex.cts.shim.apex")); |
| 1444 | if (!installer_->Prepare()) { |
| 1445 | return; |
| 1446 | } |
| 1447 | ASSERT_EQ("com.android.apex.cts.shim", installer_->package); |
| 1448 | // First deactivate currently active shim, otherwise activatePackage will be |
| 1449 | // no-op. |
| 1450 | { |
| 1451 | ApexInfo system_shim; |
| 1452 | ASSERT_TRUE(IsOk(service_->getActivePackage("com.android.apex.cts.shim", |
| 1453 | &system_shim))); |
| 1454 | ASSERT_TRUE(IsOk(service_->deactivatePackage(system_shim.modulePath))); |
| 1455 | } |
| 1456 | ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file}))); |
| 1457 | ASSERT_TRUE( |
| 1458 | IsOk(service_->activatePackage(installer_->test_installed_file))); |
| 1459 | } |
| 1460 | |
| 1461 | void TearDown() override { |
| 1462 | // Attempt to deactivate. |
| 1463 | service_->deactivatePackage(installer_->test_installed_file); |
| 1464 | installer_.reset(); |
| 1465 | // ApexServiceTest::TearDown will wipe out everything under /data/apex. |
| 1466 | // Since some of that information is required for deactivatePackage binder |
| 1467 | // call, it's required to be called after deactivating package. |
| 1468 | ApexServiceTest::TearDown(); |
| 1469 | ASSERT_TRUE(IsOk(service_->activatePackage( |
| 1470 | "/system/apex/com.android.apex.cts.shim.apex"))); |
| 1471 | } |
| 1472 | |
| 1473 | std::unique_ptr<PrepareTestApexForInstall> installer_; |
| 1474 | }; |
| 1475 | |
| 1476 | TEST_F(ApexSameGradeOfPreInstalledVersionTest, VersionOnDataWins) { |
| 1477 | std::vector<ApexInfo> all; |
| 1478 | ASSERT_TRUE(IsOk(service_->getAllPackages(&all))); |
| 1479 | |
| 1480 | ApexInfo on_data; |
| 1481 | on_data.moduleName = "com.android.apex.cts.shim"; |
| 1482 | on_data.modulePath = "/data/apex/active/com.android.apex.cts.shim@1.apex"; |
Dario Freni | 9d57624 | 2019-10-13 10:09:32 +0100 | [diff] [blame] | 1483 | on_data.preinstalledModulePath = |
| 1484 | "/system/apex/com.android.apex.cts.shim.apex"; |
Nikita Ioffe | d49bcd1 | 2019-08-30 11:56:52 +0100 | [diff] [blame] | 1485 | on_data.versionCode = 1; |
| 1486 | on_data.isFactory = false; |
| 1487 | on_data.isActive = true; |
| 1488 | |
| 1489 | ApexInfo preinstalled; |
| 1490 | preinstalled.moduleName = "com.android.apex.cts.shim"; |
| 1491 | preinstalled.modulePath = "/system/apex/com.android.apex.cts.shim.apex"; |
Dario Freni | 9d57624 | 2019-10-13 10:09:32 +0100 | [diff] [blame] | 1492 | preinstalled.preinstalledModulePath = |
| 1493 | "/system/apex/com.android.apex.cts.shim.apex"; |
Nikita Ioffe | d49bcd1 | 2019-08-30 11:56:52 +0100 | [diff] [blame] | 1494 | preinstalled.versionCode = 1; |
| 1495 | preinstalled.isFactory = true; |
| 1496 | preinstalled.isActive = false; |
| 1497 | |
| 1498 | ASSERT_THAT(all, Contains(ApexInfoEq(on_data))); |
| 1499 | ASSERT_THAT(all, Contains(ApexInfoEq(preinstalled))); |
| 1500 | } |
| 1501 | |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1502 | class ApexServiceDeactivationTest : public ApexServiceActivationSuccessTest { |
| 1503 | public: |
| 1504 | void SetUp() override { |
| 1505 | ApexServiceActivationSuccessTest::SetUp(); |
| 1506 | |
| 1507 | ASSERT_TRUE(installer_ != nullptr); |
| 1508 | } |
| 1509 | |
| 1510 | void TearDown() override { |
| 1511 | installer_.reset(); |
| 1512 | ApexServiceActivationSuccessTest::TearDown(); |
| 1513 | } |
| 1514 | |
| 1515 | std::unique_ptr<PrepareTestApexForInstall> installer_; |
| 1516 | }; |
| 1517 | |
Nikita Ioffe | 1fe9624 | 2019-04-05 22:00:00 +0100 | [diff] [blame] | 1518 | TEST_F(ApexServiceActivationSuccessTest, DmDeviceTearDown) { |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1519 | std::string package_id = |
| 1520 | installer_->package + "@" + std::to_string(installer_->version); |
| 1521 | |
| 1522 | auto find_fn = [](const std::string& name) { |
Nikita Ioffe | db8fdbb | 2020-01-02 02:44:44 +0000 | [diff] [blame] | 1523 | auto& dm = DeviceMapper::Instance(); |
| 1524 | std::vector<DeviceMapper::DmBlockDevice> devices; |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1525 | if (!dm.GetAvailableDevices(&devices)) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1526 | return Result<bool>(Errorf("GetAvailableDevices failed")); |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1527 | } |
| 1528 | for (const auto& device : devices) { |
| 1529 | if (device.name() == name) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1530 | return Result<bool>(true); |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1531 | } |
| 1532 | } |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1533 | return Result<bool>(false); |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1534 | }; |
| 1535 | |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1536 | #define ASSERT_FIND(type) \ |
| 1537 | { \ |
| 1538 | Result<bool> res = find_fn(package_id); \ |
Bernie Innocenti | 575b30d | 2020-02-09 19:23:06 +0900 | [diff] [blame] | 1539 | ASSERT_RESULT_OK(res); \ |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1540 | ASSERT_##type(*res); \ |
Andreas Gampe | da5f506 | 2019-03-26 12:19:13 -0700 | [diff] [blame] | 1541 | } |
| 1542 | |
| 1543 | ASSERT_FIND(FALSE); |
| 1544 | |
| 1545 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1546 | << GetDebugStr(installer_.get()); |
| 1547 | |
| 1548 | ASSERT_FIND(TRUE); |
| 1549 | |
| 1550 | ASSERT_TRUE( |
| 1551 | IsOk(service_->deactivatePackage(installer_->test_installed_file))); |
| 1552 | |
| 1553 | ASSERT_FIND(FALSE); |
| 1554 | |
| 1555 | installer_.reset(); // Skip TearDown deactivatePackage. |
| 1556 | } |
| 1557 | |
Nikita Ioffe | 88752d9 | 2020-01-02 21:55:35 +0000 | [diff] [blame] | 1558 | TEST_F(ApexServiceActivationSuccessTest, DeactivateFreesLoopDevices) { |
| 1559 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 1560 | << GetDebugStr(installer_.get()); |
| 1561 | |
| 1562 | std::string package_id = |
| 1563 | installer_->package + "@" + std::to_string(installer_->version); |
| 1564 | std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id); |
| 1565 | ASSERT_EQ(1u, slaves.size()) |
| 1566 | << "Unexpected number of slaves: " << Join(slaves, ","); |
| 1567 | const std::string& loop = slaves[0]; |
| 1568 | |
| 1569 | ASSERT_TRUE( |
| 1570 | IsOk(service_->deactivatePackage(installer_->test_installed_file))); |
| 1571 | |
| 1572 | struct loop_info li; |
| 1573 | unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC))); |
| 1574 | ASSERT_NE(-1, fd.get()) << "Failed to open " << loop << " : " |
| 1575 | << strerror(errno); |
| 1576 | ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li)) |
| 1577 | << loop << " is still alive"; |
| 1578 | ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno); |
| 1579 | |
| 1580 | installer_.reset(); // Skip TearDown deactivatePackage. |
| 1581 | } |
| 1582 | |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1583 | class ApexServicePrePostInstallTest : public ApexServiceTest { |
| 1584 | public: |
| 1585 | template <typename Fn> |
| 1586 | void RunPrePost(Fn fn, const std::vector<std::string>& apex_names, |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1587 | const char* test_message, bool expect_success = true) { |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1588 | // Using unique_ptr is just the easiest here. |
| 1589 | using InstallerUPtr = std::unique_ptr<PrepareTestApexForInstall>; |
| 1590 | std::vector<InstallerUPtr> installers; |
| 1591 | std::vector<std::string> pkgs; |
Andreas Gampe | e1a4039 | 2018-11-30 09:47:17 -0800 | [diff] [blame] | 1592 | |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1593 | for (const std::string& apex_name : apex_names) { |
| 1594 | InstallerUPtr installer( |
| 1595 | new PrepareTestApexForInstall(GetTestFile(apex_name))); |
| 1596 | if (!installer->Prepare()) { |
| 1597 | return; |
| 1598 | } |
| 1599 | pkgs.push_back(installer->test_file); |
| 1600 | installers.emplace_back(std::move(installer)); |
| 1601 | } |
| 1602 | android::binder::Status st = (service_.get()->*fn)(pkgs); |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1603 | if (expect_success) { |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1604 | ASSERT_TRUE(IsOk(st)); |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1605 | } else { |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1606 | ASSERT_FALSE(IsOk(st)); |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1607 | } |
Andreas Gampe | e1a4039 | 2018-11-30 09:47:17 -0800 | [diff] [blame] | 1608 | |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1609 | if (test_message != nullptr) { |
| 1610 | std::string logcat = GetLogcat(); |
Nikita Ioffe | 5bddac0 | 2019-12-30 11:10:20 +0000 | [diff] [blame] | 1611 | EXPECT_THAT(logcat, HasSubstr(test_message)); |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1612 | } |
Andreas Gampe | e44b579 | 2018-12-13 15:48:45 -0800 | [diff] [blame] | 1613 | |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1614 | // Ensure that the package is neither active nor mounted. |
| 1615 | for (const InstallerUPtr& installer : installers) { |
Nikita Ioffe | a26ac42 | 2020-04-24 18:05:44 +0100 | [diff] [blame] | 1616 | Result<bool> active = IsActive(installer->package, installer->version, |
| 1617 | installer->test_file); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1618 | ASSERT_TRUE(IsOk(active)); |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1619 | EXPECT_FALSE(*active); |
| 1620 | } |
| 1621 | for (const InstallerUPtr& installer : installers) { |
Mohammad Samiul Islam | bd6ab0f | 2019-06-20 15:55:27 +0100 | [diff] [blame] | 1622 | Result<ApexFile> apex = ApexFile::Open(installer->test_input); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1623 | ASSERT_TRUE(IsOk(apex)); |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1624 | std::string path = |
| 1625 | apexd_private::GetPackageMountPoint(apex->GetManifest()); |
| 1626 | std::string entry = std::string("[dir]").append(path); |
| 1627 | std::vector<std::string> slash_apex = ListDir(kApexRoot); |
| 1628 | auto it = std::find(slash_apex.begin(), slash_apex.end(), entry); |
| 1629 | EXPECT_TRUE(it == slash_apex.end()) << Join(slash_apex, ','); |
| 1630 | } |
Andreas Gampe | e44b579 | 2018-12-13 15:48:45 -0800 | [diff] [blame] | 1631 | } |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1632 | }; |
| 1633 | |
| 1634 | TEST_F(ApexServicePrePostInstallTest, Preinstall) { |
| 1635 | RunPrePost(&IApexService::preinstallPackages, |
| 1636 | {"apex.apexd_test_preinstall.apex"}, "sh : PreInstall Test"); |
Andreas Gampe | e44b579 | 2018-12-13 15:48:45 -0800 | [diff] [blame] | 1637 | } |
| 1638 | |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1639 | TEST_F(ApexServicePrePostInstallTest, MultiPreinstall) { |
| 1640 | constexpr const char* kLogcatText = |
Andreas Gampe | e44b579 | 2018-12-13 15:48:45 -0800 | [diff] [blame] | 1641 | "sh : /apex/com.android.apex.test_package/etc/sample_prebuilt_file"; |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1642 | RunPrePost(&IApexService::preinstallPackages, |
| 1643 | {"apex.apexd_test_preinstall.apex", "apex.apexd_test.apex"}, |
| 1644 | kLogcatText); |
| 1645 | } |
Andreas Gampe | e1a4039 | 2018-11-30 09:47:17 -0800 | [diff] [blame] | 1646 | |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1647 | TEST_F(ApexServicePrePostInstallTest, PreinstallFail) { |
| 1648 | RunPrePost(&IApexService::preinstallPackages, |
| 1649 | {"apex.apexd_test_prepostinstall.fail.apex"}, |
| 1650 | /* test_message= */ nullptr, /* expect_success= */ false); |
| 1651 | } |
| 1652 | |
Andreas Gampe | f4c7e7c | 2019-01-14 12:33:34 -0800 | [diff] [blame] | 1653 | TEST_F(ApexServicePrePostInstallTest, Postinstall) { |
| 1654 | RunPrePost(&IApexService::postinstallPackages, |
| 1655 | {"apex.apexd_test_postinstall.apex"}, |
| 1656 | "sh : PostInstall Test"); |
| 1657 | } |
| 1658 | |
| 1659 | TEST_F(ApexServicePrePostInstallTest, MultiPostinstall) { |
| 1660 | constexpr const char* kLogcatText = |
| 1661 | "sh : /apex/com.android.apex.test_package/etc/sample_prebuilt_file"; |
| 1662 | RunPrePost(&IApexService::postinstallPackages, |
| 1663 | {"apex.apexd_test_postinstall.apex", "apex.apexd_test.apex"}, |
| 1664 | kLogcatText); |
Andreas Gampe | e1a4039 | 2018-11-30 09:47:17 -0800 | [diff] [blame] | 1665 | } |
| 1666 | |
Andreas Gampe | 1144b18 | 2019-02-04 15:28:12 -0800 | [diff] [blame] | 1667 | TEST_F(ApexServicePrePostInstallTest, PostinstallFail) { |
| 1668 | RunPrePost(&IApexService::postinstallPackages, |
| 1669 | {"apex.apexd_test_prepostinstall.fail.apex"}, |
| 1670 | /* test_message= */ nullptr, /* expect_success= */ false); |
| 1671 | } |
| 1672 | |
Dario Freni | ab5b6c4 | 2019-01-15 11:53:57 +0000 | [diff] [blame] | 1673 | TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) { |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1674 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1675 | "/data/app-staging/session_123", |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1676 | "staging_data_file"); |
| 1677 | if (!installer.Prepare()) { |
| 1678 | FAIL() << GetDebugStr(&installer); |
| 1679 | } |
| 1680 | |
Dario Freni | a6ad33e | 2019-01-09 14:35:43 +0000 | [diff] [blame] | 1681 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1682 | ApexSessionParams params; |
| 1683 | params.sessionId = 123; |
| 1684 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))) |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1685 | << GetDebugStr(&installer); |
Dario Freni | a6ad33e | 2019-01-09 14:35:43 +0000 | [diff] [blame] | 1686 | EXPECT_EQ(1u, list.apexInfos.size()); |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1687 | ApexInfo match; |
Dario Freni | 6425511 | 2019-02-18 22:13:38 +0000 | [diff] [blame] | 1688 | for (const ApexInfo& info : list.apexInfos) { |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1689 | if (info.moduleName == installer.package) { |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1690 | match = info; |
| 1691 | break; |
| 1692 | } |
| 1693 | } |
| 1694 | |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1695 | ASSERT_EQ(installer.package, match.moduleName); |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1696 | ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode)); |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1697 | ASSERT_EQ(installer.test_file, match.modulePath); |
Dario Freni | d243764 | 2019-01-11 14:35:23 +0000 | [diff] [blame] | 1698 | |
| 1699 | ApexSessionInfo session; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1700 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session))) |
| 1701 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1702 | ApexSessionInfo expected = CreateSessionInfo(123); |
| 1703 | expected.isVerified = true; |
| 1704 | EXPECT_THAT(session, SessionInfoEq(expected)); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1705 | |
Nikita Ioffe | 0c1d4b1 | 2019-07-09 20:48:17 +0100 | [diff] [blame] | 1706 | ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123))); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1707 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session))) |
| 1708 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1709 | expected.isVerified = false; |
| 1710 | expected.isStaged = true; |
| 1711 | EXPECT_THAT(session, SessionInfoEq(expected)); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1712 | |
| 1713 | // Call markStagedSessionReady again. Should be a no-op. |
Nikita Ioffe | 0c1d4b1 | 2019-07-09 20:48:17 +0100 | [diff] [blame] | 1714 | ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123))) |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1715 | << GetDebugStr(&installer); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1716 | |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1717 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session))) |
| 1718 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1719 | EXPECT_THAT(session, SessionInfoEq(expected)); |
Martijn Coenen | 4d20642 | 2019-01-31 15:58:55 +0100 | [diff] [blame] | 1720 | |
| 1721 | // See if the session is reported with getSessions() as well |
| 1722 | std::vector<ApexSessionInfo> sessions; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1723 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))) |
| 1724 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1725 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1726 | } |
| 1727 | |
Mohammad Samiul Islam | 5cf48a2 | 2019-11-20 14:40:22 +0000 | [diff] [blame] | 1728 | TEST_F(ApexServiceTest, SubmitSingleStagedSessionKeepsPreviousSessions) { |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1729 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1730 | "/data/app-staging/session_239", |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1731 | "staging_data_file"); |
| 1732 | if (!installer.Prepare()) { |
| 1733 | FAIL() << GetDebugStr(&installer); |
| 1734 | } |
| 1735 | |
| 1736 | // First simulate existence of a bunch of sessions. |
| 1737 | auto session1 = ApexSession::CreateSession(37); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1738 | ASSERT_TRUE(IsOk(session1)); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1739 | auto session2 = ApexSession::CreateSession(57); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1740 | ASSERT_TRUE(IsOk(session2)); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1741 | auto session3 = ApexSession::CreateSession(73); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1742 | ASSERT_TRUE(IsOk(session3)); |
| 1743 | ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED))); |
| 1744 | ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED))); |
Nikita Ioffe | 463d4e8 | 2019-02-10 18:46:20 +0000 | [diff] [blame] | 1745 | ASSERT_TRUE(IsOk(session3->UpdateStateAndCommit(SessionState::SUCCESS))); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1746 | |
| 1747 | std::vector<ApexSessionInfo> sessions; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1748 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1749 | |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1750 | ApexSessionInfo expected_session1 = CreateSessionInfo(37); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1751 | expected_session1.isVerified = true; |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1752 | ApexSessionInfo expected_session2 = CreateSessionInfo(57); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1753 | expected_session2.isStaged = true; |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1754 | ApexSessionInfo expected_session3 = CreateSessionInfo(73); |
Nikita Ioffe | 463d4e8 | 2019-02-10 18:46:20 +0000 | [diff] [blame] | 1755 | expected_session3.isSuccess = true; |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1756 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected_session1), |
| 1757 | SessionInfoEq(expected_session2), |
| 1758 | SessionInfoEq(expected_session3))); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1759 | |
| 1760 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1761 | ApexSessionParams params; |
| 1762 | params.sessionId = 239; |
| 1763 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1764 | |
| 1765 | sessions.clear(); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1766 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1767 | |
Nikita Ioffe | 9bd28b9 | 2019-03-04 22:18:07 +0000 | [diff] [blame] | 1768 | ApexSessionInfo new_session = CreateSessionInfo(239); |
| 1769 | new_session.isVerified = true; |
Mohammad Samiul Islam | 5cf48a2 | 2019-11-20 14:40:22 +0000 | [diff] [blame] | 1770 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(new_session), |
| 1771 | SessionInfoEq(expected_session1), |
| 1772 | SessionInfoEq(expected_session2), |
| 1773 | SessionInfoEq(expected_session3))); |
Nikita Ioffe | 53c3dcd | 2019-02-08 17:39:00 +0000 | [diff] [blame] | 1774 | } |
| 1775 | |
Nikita Ioffe | c55bf63 | 2019-07-03 21:14:05 +0100 | [diff] [blame] | 1776 | TEST_F(ApexServiceTest, SubmitSingleSessionTestFail) { |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1777 | PrepareTestApexForInstall installer( |
Nikita Ioffe | c55bf63 | 2019-07-03 21:14:05 +0100 | [diff] [blame] | 1778 | GetTestFile("apex.apexd_test_corrupt_apex.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1779 | "/data/app-staging/session_456", "staging_data_file"); |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1780 | if (!installer.Prepare()) { |
| 1781 | FAIL() << GetDebugStr(&installer); |
| 1782 | } |
| 1783 | |
Dario Freni | a6ad33e | 2019-01-09 14:35:43 +0000 | [diff] [blame] | 1784 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1785 | ApexSessionParams params; |
| 1786 | params.sessionId = 456; |
| 1787 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))) |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1788 | << GetDebugStr(&installer); |
Dario Freni | d243764 | 2019-01-11 14:35:23 +0000 | [diff] [blame] | 1789 | |
| 1790 | ApexSessionInfo session; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1791 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(456, &session))) |
| 1792 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1793 | ApexSessionInfo expected = CreateSessionInfo(-1); |
| 1794 | expected.isUnknown = true; |
| 1795 | EXPECT_THAT(session, SessionInfoEq(expected)); |
Dario Freni | 56231b4 | 2019-01-04 11:58:17 +0000 | [diff] [blame] | 1796 | } |
| 1797 | |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1798 | TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) { |
| 1799 | // Parent session id: 10 |
| 1800 | // Children session ids: 20 30 |
| 1801 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1802 | "/data/app-staging/session_20", |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1803 | "staging_data_file"); |
| 1804 | PrepareTestApexForInstall installer2( |
| 1805 | GetTestFile("apex.apexd_test_different_app.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1806 | "/data/app-staging/session_30", "staging_data_file"); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1807 | if (!installer.Prepare() || !installer2.Prepare()) { |
| 1808 | FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2); |
| 1809 | } |
| 1810 | |
| 1811 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1812 | ApexSessionParams params; |
| 1813 | params.sessionId = 10; |
| 1814 | params.childSessionIds = {20, 30}; |
| 1815 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))) |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1816 | << GetDebugStr(&installer); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1817 | EXPECT_EQ(2u, list.apexInfos.size()); |
| 1818 | ApexInfo match; |
| 1819 | bool package1_found = false; |
| 1820 | bool package2_found = false; |
Dario Freni | 6425511 | 2019-02-18 22:13:38 +0000 | [diff] [blame] | 1821 | for (const ApexInfo& info : list.apexInfos) { |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1822 | if (info.moduleName == installer.package) { |
| 1823 | ASSERT_EQ(installer.package, info.moduleName); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1824 | ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode)); |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1825 | ASSERT_EQ(installer.test_file, info.modulePath); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1826 | package1_found = true; |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1827 | } else if (info.moduleName == installer2.package) { |
| 1828 | ASSERT_EQ(installer2.package, info.moduleName); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1829 | ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode)); |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1830 | ASSERT_EQ(installer2.test_file, info.modulePath); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1831 | package2_found = true; |
| 1832 | } else { |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 1833 | FAIL() << "Unexpected package found " << info.moduleName |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1834 | << GetDebugStr(&installer) << GetDebugStr(&installer2); |
| 1835 | } |
| 1836 | } |
| 1837 | ASSERT_TRUE(package1_found); |
| 1838 | ASSERT_TRUE(package2_found); |
| 1839 | |
| 1840 | ApexSessionInfo session; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1841 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session))) |
| 1842 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1843 | ApexSessionInfo expected = CreateSessionInfo(10); |
| 1844 | expected.isVerified = true; |
| 1845 | ASSERT_THAT(session, SessionInfoEq(expected)); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1846 | |
Nikita Ioffe | 0c1d4b1 | 2019-07-09 20:48:17 +0100 | [diff] [blame] | 1847 | ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10))) |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1848 | << GetDebugStr(&installer); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1849 | |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1850 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session))) |
| 1851 | << GetDebugStr(&installer); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1852 | expected.isVerified = false; |
| 1853 | expected.isStaged = true; |
| 1854 | ASSERT_THAT(session, SessionInfoEq(expected)); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1855 | } |
| 1856 | |
Nikita Ioffe | c55bf63 | 2019-07-03 21:14:05 +0100 | [diff] [blame] | 1857 | TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) { |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1858 | // Parent session id: 11 |
| 1859 | // Children session ids: 21 31 |
| 1860 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1861 | "/data/app-staging/session_21", |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1862 | "staging_data_file"); |
| 1863 | PrepareTestApexForInstall installer2( |
Nikita Ioffe | c55bf63 | 2019-07-03 21:14:05 +0100 | [diff] [blame] | 1864 | GetTestFile("apex.apexd_test_corrupt_apex.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1865 | "/data/app-staging/session_31", "staging_data_file"); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1866 | if (!installer.Prepare() || !installer2.Prepare()) { |
| 1867 | FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2); |
| 1868 | } |
| 1869 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 1870 | ApexSessionParams params; |
| 1871 | params.sessionId = 11; |
| 1872 | params.childSessionIds = {21, 31}; |
| 1873 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))) |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1874 | << GetDebugStr(&installer); |
Dario Freni | 6dd4dd6 | 2019-01-18 12:45:44 +0000 | [diff] [blame] | 1875 | } |
| 1876 | |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1877 | TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) { |
| 1878 | // We should fail if we ask information about a session we don't know. |
Nikita Ioffe | 0c1d4b1 | 2019-07-09 20:48:17 +0100 | [diff] [blame] | 1879 | ASSERT_FALSE(IsOk(service_->markStagedSessionReady(666))); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1880 | |
| 1881 | ApexSessionInfo session; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1882 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session))); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1883 | ApexSessionInfo expected = CreateSessionInfo(-1); |
| 1884 | expected.isUnknown = true; |
| 1885 | ASSERT_THAT(session, SessionInfoEq(expected)); |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1886 | } |
| 1887 | |
| 1888 | TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) { |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1889 | ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37))); |
| 1890 | |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1891 | ApexSessionInfo session_info; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1892 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info))); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1893 | ApexSessionInfo expected = CreateSessionInfo(-1); |
| 1894 | expected.isUnknown = true; |
| 1895 | ASSERT_THAT(session_info, SessionInfoEq(expected)); |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1896 | } |
| 1897 | |
| 1898 | TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) { |
| 1899 | auto session = ApexSession::CreateSession(73); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1900 | ASSERT_TRUE(IsOk(session)); |
| 1901 | ASSERT_TRUE( |
| 1902 | IsOk(session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED))); |
| 1903 | |
| 1904 | ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73))); |
| 1905 | |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1906 | ApexSessionInfo session_info; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1907 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info))); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1908 | ApexSessionInfo expected = CreateSessionInfo(73); |
| 1909 | expected.isStaged = true; |
| 1910 | ASSERT_THAT(session_info, SessionInfoEq(expected)); |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1911 | } |
| 1912 | |
| 1913 | TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) { |
| 1914 | auto session = ApexSession::CreateSession(239); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1915 | ASSERT_TRUE(IsOk(session)); |
| 1916 | ASSERT_TRUE(IsOk( |
| 1917 | session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED))); |
| 1918 | |
| 1919 | ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239))); |
| 1920 | |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1921 | ApexSessionInfo session_info; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1922 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info))); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1923 | ApexSessionInfo expected = CreateSessionInfo(239); |
| 1924 | expected.isSuccess = true; |
| 1925 | ASSERT_THAT(session_info, SessionInfoEq(expected)); |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1926 | } |
| 1927 | |
| 1928 | TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) { |
| 1929 | auto session = ApexSession::CreateSession(1543); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1930 | ASSERT_TRUE(IsOk(session)); |
| 1931 | ASSERT_TRUE(IsOk( |
| 1932 | session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS))); |
| 1933 | |
| 1934 | ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543))); |
| 1935 | |
Nikita Ioffe | a0c0ccb | 2019-02-12 22:00:41 +0000 | [diff] [blame] | 1936 | ApexSessionInfo session_info; |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 1937 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info))); |
Nikita Ioffe | 904e2d3 | 2019-02-19 01:57:13 +0000 | [diff] [blame] | 1938 | ApexSessionInfo expected = CreateSessionInfo(1543); |
| 1939 | expected.isSuccess = true; |
| 1940 | ASSERT_THAT(session_info, SessionInfoEq(expected)); |
Dario Freni | f36c962 | 2019-01-25 11:30:00 +0000 | [diff] [blame] | 1941 | } |
| 1942 | |
Mohammad Samiul Islam | 4654f77 | 2019-11-20 15:19:07 +0000 | [diff] [blame] | 1943 | // Should be able to abort individual staged session |
| 1944 | TEST_F(ApexServiceTest, AbortStagedSession) { |
| 1945 | auto session1 = ApexSession::CreateSession(239); |
| 1946 | ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED))); |
| 1947 | auto session2 = ApexSession::CreateSession(240); |
| 1948 | ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED))); |
| 1949 | |
| 1950 | std::vector<ApexSessionInfo> sessions; |
| 1951 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
| 1952 | ASSERT_EQ(2u, sessions.size()); |
| 1953 | |
| 1954 | ASSERT_TRUE(IsOk(service_->abortStagedSession(239))); |
| 1955 | |
| 1956 | sessions.clear(); |
| 1957 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
| 1958 | ApexSessionInfo expected = CreateSessionInfo(240); |
| 1959 | expected.isStaged = true; |
| 1960 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); |
| 1961 | } |
| 1962 | |
| 1963 | // abortStagedSession should not abort activated session |
| 1964 | TEST_F(ApexServiceTest, AbortStagedSessionActivatedFail) { |
| 1965 | auto session1 = ApexSession::CreateSession(239); |
| 1966 | ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::ACTIVATED))); |
| 1967 | auto session2 = ApexSession::CreateSession(240); |
| 1968 | ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED))); |
| 1969 | |
| 1970 | std::vector<ApexSessionInfo> sessions; |
| 1971 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
| 1972 | ASSERT_EQ(2u, sessions.size()); |
| 1973 | |
| 1974 | ASSERT_FALSE(IsOk(service_->abortStagedSession(239))); |
| 1975 | |
| 1976 | sessions.clear(); |
| 1977 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
| 1978 | ApexSessionInfo expected1 = CreateSessionInfo(239); |
| 1979 | expected1.isActivated = true; |
| 1980 | ApexSessionInfo expected2 = CreateSessionInfo(240); |
| 1981 | expected2.isStaged = true; |
| 1982 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected1), |
| 1983 | SessionInfoEq(expected2))); |
| 1984 | } |
| 1985 | |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 1986 | TEST_F(ApexServiceTest, BackupActivePackages) { |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 1987 | if (supports_fs_checkpointing_) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 1988 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 1989 | } |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 1990 | PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); |
| 1991 | PrepareTestApexForInstall installer2( |
| 1992 | GetTestFile("apex.apexd_test_different_app.apex")); |
| 1993 | PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 1994 | "/data/app-staging/session_23", |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 1995 | "staging_data_file"); |
| 1996 | |
| 1997 | if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) { |
| 1998 | return; |
| 1999 | } |
| 2000 | |
| 2001 | // Activate some packages, in order to backup them later. |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2002 | std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file}; |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2003 | ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2004 | |
| 2005 | // Make sure that /data/apex/active has activated packages. |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2006 | auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2007 | ASSERT_TRUE(IsOk(active_pkgs)); |
| 2008 | ASSERT_THAT(*active_pkgs, |
| 2009 | UnorderedElementsAre(installer1.test_installed_file, |
| 2010 | installer2.test_installed_file)); |
| 2011 | |
| 2012 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2013 | ApexSessionParams params; |
| 2014 | params.sessionId = 23; |
| 2015 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2016 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2017 | auto backups = ReadEntireDir(kApexBackupDir); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2018 | ASSERT_TRUE(IsOk(backups)); |
| 2019 | auto backup1 = |
| 2020 | StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir); |
| 2021 | auto backup2 = |
| 2022 | StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir); |
| 2023 | ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2)); |
| 2024 | } |
| 2025 | |
| 2026 | TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) { |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2027 | if (supports_fs_checkpointing_) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2028 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2029 | } |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2030 | PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); |
| 2031 | PrepareTestApexForInstall installer2( |
| 2032 | GetTestFile("apex.apexd_test_different_app.apex")); |
| 2033 | PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 2034 | "/data/app-staging/session_43", |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2035 | "staging_data_file"); |
| 2036 | |
| 2037 | if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) { |
| 2038 | return; |
| 2039 | } |
| 2040 | |
| 2041 | // Make sure /data/apex/backups exists. |
| 2042 | ASSERT_TRUE(IsOk(createDirIfNeeded(std::string(kApexBackupDir), 0700))); |
| 2043 | // Create some bogus files in /data/apex/backups. |
| 2044 | std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir)); |
| 2045 | ASSERT_TRUE(old_backup.good()); |
| 2046 | old_backup.close(); |
| 2047 | |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2048 | std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file}; |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2049 | ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2050 | |
| 2051 | // Make sure that /data/apex/active has activated packages. |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2052 | auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2053 | ASSERT_TRUE(IsOk(active_pkgs)); |
| 2054 | ASSERT_THAT(*active_pkgs, |
| 2055 | UnorderedElementsAre(installer1.test_installed_file, |
| 2056 | installer2.test_installed_file)); |
| 2057 | |
| 2058 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2059 | ApexSessionParams params; |
| 2060 | params.sessionId = 43; |
| 2061 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2062 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2063 | auto backups = ReadEntireDir(kApexBackupDir); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2064 | ASSERT_TRUE(IsOk(backups)); |
| 2065 | auto backup1 = |
| 2066 | StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir); |
| 2067 | auto backup2 = |
| 2068 | StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir); |
| 2069 | ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2)); |
| 2070 | } |
| 2071 | |
| 2072 | TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) { |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2073 | if (supports_fs_checkpointing_) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2074 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2075 | } |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2076 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 2077 | "/data/app-staging/session_41", |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2078 | "staging_data_file"); |
| 2079 | |
| 2080 | if (!installer.Prepare()) { |
| 2081 | return; |
| 2082 | } |
| 2083 | |
| 2084 | // Make sure that /data/apex/active exists and is empty |
| 2085 | ASSERT_TRUE( |
Nikita Ioffe | d20d10d | 2020-04-21 21:17:23 +0100 | [diff] [blame] | 2086 | IsOk(createDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755))); |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2087 | auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2088 | ASSERT_TRUE(IsOk(active_pkgs)); |
| 2089 | ASSERT_EQ(0u, active_pkgs->size()); |
| 2090 | |
| 2091 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2092 | ApexSessionParams params; |
| 2093 | params.sessionId = 41; |
| 2094 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2095 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2096 | auto backups = ReadEntireDir(kApexBackupDir); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2097 | ASSERT_TRUE(IsOk(backups)); |
| 2098 | ASSERT_EQ(0u, backups->size()); |
| 2099 | } |
| 2100 | |
| 2101 | TEST_F(ApexServiceTest, ActivePackagesFolderDoesNotExist) { |
| 2102 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"), |
Gavin Corkery | d12ea22 | 2019-02-27 11:26:16 +0000 | [diff] [blame] | 2103 | "/data/app-staging/session_41", |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2104 | "staging_data_file"); |
| 2105 | |
| 2106 | if (!installer.Prepare()) { |
| 2107 | return; |
| 2108 | } |
| 2109 | |
| 2110 | // Make sure that /data/apex/active does not exist |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2111 | std::error_code ec; |
| 2112 | fs::remove_all(fs::path(kActiveApexPackagesDataDir), ec); |
| 2113 | ASSERT_FALSE(ec) << "Failed to delete " << kActiveApexPackagesDataDir; |
| 2114 | |
| 2115 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2116 | ApexSessionParams params; |
| 2117 | params.sessionId = 41; |
| 2118 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2119 | |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2120 | if (!supports_fs_checkpointing_) { |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2121 | auto backups = ReadEntireDir(kApexBackupDir); |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2122 | ASSERT_TRUE(IsOk(backups)); |
| 2123 | ASSERT_EQ(0u, backups->size()); |
| 2124 | } |
Nikita Ioffe | a82b0a8 | 2019-02-15 18:59:47 +0000 | [diff] [blame] | 2125 | } |
| 2126 | |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2127 | TEST_F(ApexServiceTest, UnstagePackagesSuccess) { |
| 2128 | PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); |
| 2129 | PrepareTestApexForInstall installer2( |
| 2130 | GetTestFile("apex.apexd_test_different_app.apex")); |
| 2131 | |
| 2132 | if (!installer1.Prepare() || !installer2.Prepare()) { |
| 2133 | return; |
| 2134 | } |
| 2135 | |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2136 | std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file}; |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2137 | ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2138 | |
| 2139 | pkgs = {installer2.test_installed_file}; |
| 2140 | ASSERT_TRUE(IsOk(service_->unstagePackages(pkgs))); |
| 2141 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2142 | auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2143 | ASSERT_TRUE(IsOk(active_packages)); |
| 2144 | ASSERT_THAT(*active_packages, |
| 2145 | UnorderedElementsAre(installer1.test_installed_file)); |
| 2146 | } |
| 2147 | |
| 2148 | TEST_F(ApexServiceTest, UnstagePackagesFail) { |
| 2149 | PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); |
| 2150 | PrepareTestApexForInstall installer2( |
| 2151 | GetTestFile("apex.apexd_test_different_app.apex")); |
| 2152 | |
| 2153 | if (!installer1.Prepare() || !installer2.Prepare()) { |
| 2154 | return; |
| 2155 | } |
| 2156 | |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2157 | std::vector<std::string> pkgs = {installer1.test_file}; |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2158 | ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2159 | |
| 2160 | pkgs = {installer1.test_installed_file, installer2.test_installed_file}; |
| 2161 | ASSERT_FALSE(IsOk(service_->unstagePackages(pkgs))); |
| 2162 | |
| 2163 | // Check that first package wasn't unstaged. |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2164 | auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | 496a4a4 | 2019-03-05 16:32:51 +0000 | [diff] [blame] | 2165 | ASSERT_TRUE(IsOk(active_packages)); |
| 2166 | ASSERT_THAT(*active_packages, |
| 2167 | UnorderedElementsAre(installer1.test_installed_file)); |
| 2168 | } |
| 2169 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2170 | class ApexServiceRevertTest : public ApexServiceTest { |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2171 | protected: |
| 2172 | void SetUp() override { ApexServiceTest::SetUp(); } |
| 2173 | |
Nikita Ioffe | f71e02f | 2019-03-25 16:19:18 +0000 | [diff] [blame] | 2174 | void PrepareBackup(const std::vector<std::string>& pkgs) { |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2175 | ASSERT_TRUE(IsOk(createDirIfNeeded(std::string(kApexBackupDir), 0700))); |
| 2176 | for (const auto& pkg : pkgs) { |
Nikita Ioffe | a4dc3e8 | 2019-02-23 17:37:04 +0000 | [diff] [blame] | 2177 | PrepareTestApexForInstall installer(pkg); |
| 2178 | ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg; |
| 2179 | const std::string& from = installer.test_file; |
| 2180 | std::string to = std::string(kApexBackupDir) + "/" + installer.package + |
| 2181 | "@" + std::to_string(installer.version) + ".apex"; |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2182 | std::error_code ec; |
Nikita Ioffe | a4dc3e8 | 2019-02-23 17:37:04 +0000 | [diff] [blame] | 2183 | fs::copy(fs::path(from), fs::path(to), |
| 2184 | fs::copy_options::create_hard_links, ec); |
| 2185 | ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : " |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2186 | << ec; |
| 2187 | } |
| 2188 | } |
| 2189 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2190 | void CheckRevertWasPerformed(const std::vector<std::string>& expected_pkgs) { |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2191 | // First check that /data/apex/active exists and has correct permissions. |
| 2192 | struct stat sd; |
| 2193 | ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd)); |
Nikita Ioffe | d20d10d | 2020-04-21 21:17:23 +0100 | [diff] [blame] | 2194 | ASSERT_EQ(0755u, sd.st_mode & ALLPERMS); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2195 | |
| 2196 | // Now read content and check it contains expected values. |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2197 | auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2198 | ASSERT_TRUE(IsOk(active_pkgs)); |
| 2199 | ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs)); |
| 2200 | } |
| 2201 | }; |
| 2202 | |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2203 | // Should be able to revert activated sessions |
| 2204 | TEST_F(ApexServiceRevertTest, RevertActiveSessionsSuccessful) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2205 | if (supports_fs_checkpointing_) { |
| 2206 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
| 2207 | } |
| 2208 | |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2209 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); |
| 2210 | if (!installer.Prepare()) { |
| 2211 | return; |
| 2212 | } |
| 2213 | |
| 2214 | auto session = ApexSession::CreateSession(1543); |
| 2215 | ASSERT_TRUE(IsOk(session)); |
| 2216 | ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); |
| 2217 | |
| 2218 | // Make sure /data/apex/active is non-empty. |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2219 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2220 | |
| 2221 | PrepareBackup({GetTestFile("apex.apexd_test.apex")}); |
| 2222 | |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2223 | ASSERT_TRUE(IsOk(service_->revertActiveSessions())); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2224 | |
| 2225 | auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex", |
| 2226 | kActiveApexPackagesDataDir); |
| 2227 | SCOPED_TRACE(""); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2228 | CheckRevertWasPerformed({pkg}); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2229 | } |
| 2230 | |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2231 | // Should fail to revert active sessions when there are none |
| 2232 | TEST_F(ApexServiceRevertTest, RevertActiveSessionsWithoutActiveSessions) { |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2233 | // This test simulates a situation that should never happen on user builds: |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2234 | // revertActiveSessions was called, but there were no active sessions. |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2235 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); |
| 2236 | if (!installer.Prepare()) { |
| 2237 | return; |
| 2238 | } |
| 2239 | |
| 2240 | // Make sure /data/apex/active is non-empty. |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2241 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2242 | |
| 2243 | PrepareBackup({GetTestFile("apex.apexd_test.apex")}); |
| 2244 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2245 | // Even though backup is there, no sessions are active, hence revert request |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2246 | // should fail. |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2247 | ASSERT_FALSE(IsOk(service_->revertActiveSessions())); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2248 | } |
| 2249 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2250 | TEST_F(ApexServiceRevertTest, RevertFailsNoBackupFolder) { |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2251 | ASSERT_FALSE(IsOk(service_->revertActiveSessions())); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2252 | } |
| 2253 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2254 | TEST_F(ApexServiceRevertTest, RevertFailsNoActivePackagesFolder) { |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2255 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2256 | ASSERT_FALSE(IsOk(service_->revertActiveSessions())); |
Nikita Ioffe | 9ae986a | 2019-02-18 22:39:27 +0000 | [diff] [blame] | 2257 | } |
| 2258 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2259 | TEST_F(ApexServiceRevertTest, MarkStagedSessionSuccessfulCleanupBackup) { |
Nikita Ioffe | a4dc3e8 | 2019-02-23 17:37:04 +0000 | [diff] [blame] | 2260 | PrepareBackup({GetTestFile("apex.apexd_test.apex"), |
| 2261 | GetTestFile("apex.apexd_test_different_app.apex")}); |
| 2262 | |
| 2263 | auto session = ApexSession::CreateSession(101); |
| 2264 | ASSERT_TRUE(IsOk(session)); |
| 2265 | ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); |
| 2266 | |
| 2267 | ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101))); |
| 2268 | |
| 2269 | ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir))); |
| 2270 | } |
| 2271 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2272 | TEST_F(ApexServiceRevertTest, ResumesRevert) { |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2273 | if (supports_fs_checkpointing_) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2274 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2275 | } |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2276 | PrepareBackup({GetTestFile("apex.apexd_test.apex"), |
| 2277 | GetTestFile("apex.apexd_test_different_app.apex")}); |
| 2278 | |
| 2279 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); |
| 2280 | if (!installer.Prepare()) { |
| 2281 | return; |
| 2282 | } |
| 2283 | |
| 2284 | // Make sure /data/apex/active is non-empty. |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2285 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2286 | |
| 2287 | auto session = ApexSession::CreateSession(17239); |
| 2288 | ASSERT_TRUE(IsOk(session)); |
| 2289 | ASSERT_TRUE( |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2290 | IsOk(session->UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS))); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2291 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2292 | ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded())); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2293 | |
| 2294 | auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex", |
| 2295 | kActiveApexPackagesDataDir); |
| 2296 | auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex", |
| 2297 | kActiveApexPackagesDataDir); |
| 2298 | SCOPED_TRACE(""); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2299 | CheckRevertWasPerformed({pkg1, pkg2}); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2300 | |
| 2301 | std::vector<ApexSessionInfo> sessions; |
| 2302 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
| 2303 | ApexSessionInfo expected = CreateSessionInfo(17239); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2304 | expected.isReverted = true; |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2305 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); |
| 2306 | } |
| 2307 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2308 | TEST_F(ApexServiceRevertTest, DoesNotResumeRevert) { |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2309 | if (supports_fs_checkpointing_) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2310 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
Martijn Coenen | 44de00c | 2019-03-22 09:13:17 +0100 | [diff] [blame] | 2311 | } |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2312 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); |
| 2313 | if (!installer.Prepare()) { |
| 2314 | return; |
| 2315 | } |
| 2316 | |
| 2317 | // Make sure /data/apex/active is non-empty. |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2318 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2319 | |
| 2320 | auto session = ApexSession::CreateSession(53); |
| 2321 | ASSERT_TRUE(IsOk(session)); |
| 2322 | ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::SUCCESS))); |
| 2323 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2324 | ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded())); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2325 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2326 | // Check that revert wasn't resumed. |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2327 | auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); |
Nikita Ioffe | 2f6936c | 2019-02-26 20:03:32 +0000 | [diff] [blame] | 2328 | ASSERT_TRUE(IsOk(active_pkgs)); |
| 2329 | ASSERT_THAT(*active_pkgs, |
| 2330 | UnorderedElementsAre(installer.test_installed_file)); |
| 2331 | |
| 2332 | std::vector<ApexSessionInfo> sessions; |
| 2333 | ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); |
| 2334 | ApexSessionInfo expected = CreateSessionInfo(53); |
| 2335 | expected.isSuccess = true; |
| 2336 | ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); |
| 2337 | } |
| 2338 | |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2339 | // Should mark sessions as REVERT_FAILED on failed revert |
| 2340 | TEST_F(ApexServiceRevertTest, SessionsMarkedAsRevertFailed) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2341 | if (supports_fs_checkpointing_) { |
| 2342 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
| 2343 | } |
| 2344 | |
| 2345 | auto session = ApexSession::CreateSession(53); |
| 2346 | ASSERT_TRUE(IsOk(session)); |
| 2347 | ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); |
| 2348 | |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2349 | ASSERT_FALSE(IsOk(service_->revertActiveSessions())); |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2350 | ApexSessionInfo session_info; |
| 2351 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info))); |
| 2352 | ApexSessionInfo expected = CreateSessionInfo(53); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2353 | expected.isRevertFailed = true; |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2354 | ASSERT_THAT(session_info, SessionInfoEq(expected)); |
| 2355 | } |
| 2356 | |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2357 | TEST_F(ApexServiceRevertTest, RevertFailedStateRevertAttemptFails) { |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2358 | if (supports_fs_checkpointing_) { |
| 2359 | GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; |
| 2360 | } |
| 2361 | |
| 2362 | auto session = ApexSession::CreateSession(17239); |
| 2363 | ASSERT_TRUE(IsOk(session)); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2364 | ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::REVERT_FAILED))); |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2365 | |
Mohammad Samiul Islam | 2401ae1 | 2019-11-20 17:12:31 +0000 | [diff] [blame] | 2366 | ASSERT_FALSE(IsOk(service_->revertActiveSessions())); |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2367 | ApexSessionInfo session_info; |
| 2368 | ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info))); |
| 2369 | ApexSessionInfo expected = CreateSessionInfo(17239); |
Mohammad Samiul Islam | ca852e3 | 2019-11-20 13:37:14 +0000 | [diff] [blame] | 2370 | expected.isRevertFailed = true; |
Nikita Ioffe | 54f1844 | 2019-04-09 13:09:26 +0100 | [diff] [blame] | 2371 | ASSERT_THAT(session_info, SessionInfoEq(expected)); |
| 2372 | } |
| 2373 | |
Gavin Corkery | 92cd7b8 | 2020-01-13 12:35:38 +0000 | [diff] [blame] | 2374 | TEST_F(ApexServiceRevertTest, RevertStoresCrashingNativeProcess) { |
Gavin Corkery | 92cd7b8 | 2020-01-13 12:35:38 +0000 | [diff] [blame] | 2375 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); |
| 2376 | if (!installer.Prepare()) { |
| 2377 | return; |
| 2378 | } |
| 2379 | auto session = ApexSession::CreateSession(1543); |
| 2380 | ASSERT_TRUE(IsOk(session)); |
| 2381 | ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); |
| 2382 | |
| 2383 | // Make sure /data/apex/active is non-empty. |
| 2384 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
| 2385 | std::string native_process = "test_process"; |
| 2386 | Result<void> res = ::android::apex::revertActiveSessions(native_process); |
| 2387 | session = ApexSession::GetSession(1543); |
| 2388 | ASSERT_EQ(session->GetCrashingNativeProcess(), native_process); |
| 2389 | } |
| 2390 | |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2391 | static pid_t GetPidOf(const std::string& name) { |
| 2392 | char buf[1024]; |
| 2393 | const std::string cmd = std::string("pidof -s ") + name; |
| 2394 | FILE* cmd_pipe = popen(cmd.c_str(), "r"); |
| 2395 | if (cmd_pipe == nullptr) { |
| 2396 | PLOG(ERROR) << "Cannot open pipe for " << cmd; |
| 2397 | return 0; |
| 2398 | } |
| 2399 | if (fgets(buf, 1024, cmd_pipe) == nullptr) { |
| 2400 | PLOG(ERROR) << "Cannot read pipe for " << cmd; |
| 2401 | pclose(cmd_pipe); |
| 2402 | return 0; |
| 2403 | } |
| 2404 | |
| 2405 | pclose(cmd_pipe); |
| 2406 | return strtoul(buf, nullptr, 10); |
| 2407 | } |
| 2408 | |
Nikita Ioffe | f71e02f | 2019-03-25 16:19:18 +0000 | [diff] [blame] | 2409 | static void ExecInMountNamespaceOf(pid_t pid, |
| 2410 | const std::function<void(pid_t)>& func) { |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2411 | const std::string my_path = "/proc/self/ns/mnt"; |
| 2412 | android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC)); |
| 2413 | ASSERT_TRUE(my_fd.get() >= 0); |
| 2414 | |
| 2415 | const std::string target_path = |
| 2416 | std::string("/proc/") + std::to_string(pid) + "/ns/mnt"; |
| 2417 | android::base::unique_fd target_fd( |
| 2418 | open(target_path.c_str(), O_RDONLY | O_CLOEXEC)); |
| 2419 | ASSERT_TRUE(target_fd.get() >= 0); |
| 2420 | |
| 2421 | int res = setns(target_fd.get(), CLONE_NEWNS); |
| 2422 | ASSERT_NE(-1, res); |
| 2423 | |
| 2424 | func(pid); |
| 2425 | |
| 2426 | res = setns(my_fd.get(), CLONE_NEWNS); |
| 2427 | ASSERT_NE(-1, res); |
| 2428 | } |
| 2429 | |
| 2430 | TEST(ApexdTest, ApexdIsInSameMountNamespaceAsInit) { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 2431 | // TODO(b/136647373): Move this check to environment setup |
| 2432 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 2433 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 2434 | } |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2435 | std::string ns_apexd; |
| 2436 | std::string ns_init; |
| 2437 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2438 | ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) { |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2439 | bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd); |
| 2440 | ASSERT_TRUE(res); |
| 2441 | }); |
| 2442 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2443 | ExecInMountNamespaceOf(1, [&](pid_t /*pid*/) { |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2444 | bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init); |
| 2445 | ASSERT_TRUE(res); |
| 2446 | }); |
| 2447 | |
| 2448 | ASSERT_EQ(ns_apexd, ns_init); |
| 2449 | } |
| 2450 | |
| 2451 | // These are NOT exhaustive list of early processes be should be enough |
| 2452 | static const std::vector<const std::string> kEarlyProcesses = { |
| 2453 | "servicemanager", |
| 2454 | "hwservicemanager", |
| 2455 | "vold", |
| 2456 | "logd", |
| 2457 | }; |
| 2458 | |
| 2459 | TEST(ApexdTest, EarlyProcessesAreInDifferentMountNamespace) { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 2460 | // TODO(b/136647373): Move this check to environment setup |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2461 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 2462 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2463 | } |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2464 | std::string ns_apexd; |
| 2465 | |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2466 | ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) { |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2467 | bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd); |
| 2468 | ASSERT_TRUE(res); |
| 2469 | }); |
| 2470 | |
| 2471 | for (const auto& name : kEarlyProcesses) { |
| 2472 | std::string ns_early_process; |
Nikita Ioffe | 11fa689 | 2019-06-18 05:24:24 +0100 | [diff] [blame] | 2473 | ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t /*pid*/) { |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2474 | bool res = |
| 2475 | android::base::Readlink("/proc/self/ns/mnt", &ns_early_process); |
| 2476 | ASSERT_TRUE(res); |
| 2477 | }); |
| 2478 | ASSERT_NE(ns_apexd, ns_early_process); |
| 2479 | } |
| 2480 | } |
| 2481 | |
| 2482 | TEST(ApexdTest, ApexIsAPrivateMountPoint) { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 2483 | // TODO(b/136647373): Move this check to environment setup |
| 2484 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 2485 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 2486 | } |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2487 | std::string mountinfo; |
| 2488 | ASSERT_TRUE( |
| 2489 | android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo)); |
| 2490 | bool found_apex_mountpoint = false; |
| 2491 | for (const auto& line : android::base::Split(mountinfo, "\n")) { |
| 2492 | std::vector<std::string> tokens = android::base::Split(line, " "); |
| 2493 | // line format: |
| 2494 | // mnt_id parent_mnt_id major:minor source target option propagation_type |
| 2495 | // ex) 33 260:19 / /apex rw,nosuid,nodev - |
| 2496 | if (tokens.size() >= 7 && tokens[4] == "/apex") { |
| 2497 | found_apex_mountpoint = true; |
| 2498 | // Make sure that propagation type is set to - which means private |
| 2499 | ASSERT_EQ("-", tokens[6]); |
| 2500 | } |
| 2501 | } |
| 2502 | ASSERT_TRUE(found_apex_mountpoint); |
| 2503 | } |
| 2504 | |
| 2505 | static const std::vector<const std::string> kEarlyApexes = { |
| 2506 | "/apex/com.android.runtime", |
| 2507 | "/apex/com.android.tzdata", |
| 2508 | }; |
| 2509 | |
| 2510 | TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 2511 | // TODO(b/136647373): Move this check to environment setup |
| 2512 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 2513 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 2514 | } |
Jiyong Park | 715e23d | 2019-02-22 22:14:37 +0900 | [diff] [blame] | 2515 | for (const auto& name : kEarlyProcesses) { |
| 2516 | pid_t pid = GetPidOf(name); |
| 2517 | const std::string path = |
| 2518 | std::string("/proc/") + std::to_string(pid) + "/mountinfo"; |
| 2519 | std::string mountinfo; |
| 2520 | ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo)); |
| 2521 | |
| 2522 | std::unordered_set<std::string> mountpoints; |
| 2523 | for (const auto& line : android::base::Split(mountinfo, "\n")) { |
| 2524 | std::vector<std::string> tokens = android::base::Split(line, " "); |
| 2525 | // line format: |
| 2526 | // mnt_id parent_mnt_id major:minor source target option propagation_type |
| 2527 | // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime - |
| 2528 | if (tokens.size() >= 5) { |
| 2529 | // token[4] is the target mount point |
| 2530 | mountpoints.emplace(tokens[4]); |
| 2531 | } |
| 2532 | } |
| 2533 | for (const auto& apex_name : kEarlyApexes) { |
| 2534 | ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name)); |
| 2535 | } |
| 2536 | } |
| 2537 | } |
| 2538 | |
Nikita Ioffe | df07441 | 2019-03-20 07:56:52 +0000 | [diff] [blame] | 2539 | class ApexShimUpdateTest : public ApexServiceTest { |
| 2540 | protected: |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2541 | void SetUp() override { |
Mohammad Samiul Islam | a8771b2 | 2019-07-02 12:19:52 +0100 | [diff] [blame] | 2542 | // TODO(b/136647373): Move this check to environment setup |
| 2543 | if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { |
| 2544 | GTEST_SKIP() << "Skipping test because device doesn't support APEX"; |
| 2545 | } |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2546 | ApexServiceTest::SetUp(); |
| 2547 | |
Nikita Ioffe | de2c40a | 2019-04-10 12:15:53 +0100 | [diff] [blame] | 2548 | // Assert that shim apex is pre-installed. |
| 2549 | std::vector<ApexInfo> list; |
| 2550 | ASSERT_TRUE(IsOk(service_->getAllPackages(&list))); |
| 2551 | ApexInfo expected; |
Nikita Ioffe | 2cb7f8f | 2019-06-28 15:42:51 +0100 | [diff] [blame] | 2552 | expected.moduleName = "com.android.apex.cts.shim"; |
| 2553 | expected.modulePath = "/system/apex/com.android.apex.cts.shim.apex"; |
Dario Freni | 9d57624 | 2019-10-13 10:09:32 +0100 | [diff] [blame] | 2554 | expected.preinstalledModulePath = |
| 2555 | "/system/apex/com.android.apex.cts.shim.apex"; |
Nikita Ioffe | de2c40a | 2019-04-10 12:15:53 +0100 | [diff] [blame] | 2556 | expected.versionCode = 1; |
| 2557 | expected.isFactory = true; |
| 2558 | expected.isActive = true; |
| 2559 | ASSERT_THAT(list, Contains(ApexInfoEq(expected))); |
Nikita Ioffe | df07441 | 2019-03-20 07:56:52 +0000 | [diff] [blame] | 2560 | } |
| 2561 | }; |
| 2562 | |
| 2563 | TEST_F(ApexShimUpdateTest, UpdateToV2Success) { |
| 2564 | PrepareTestApexForInstall installer( |
| 2565 | GetTestFile("com.android.apex.cts.shim.v2.apex")); |
| 2566 | |
| 2567 | if (!installer.Prepare()) { |
| 2568 | FAIL() << GetDebugStr(&installer); |
| 2569 | } |
| 2570 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2571 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
Nikita Ioffe | df07441 | 2019-03-20 07:56:52 +0000 | [diff] [blame] | 2572 | } |
| 2573 | |
Nikita Ioffe | d9a25d4 | 2019-03-26 01:37:03 +0000 | [diff] [blame] | 2574 | TEST_F(ApexShimUpdateTest, UpdateToV2FailureWrongSHA512) { |
| 2575 | PrepareTestApexForInstall installer( |
| 2576 | GetTestFile("com.android.apex.cts.shim.v2_wrong_sha.apex")); |
| 2577 | |
| 2578 | if (!installer.Prepare()) { |
| 2579 | FAIL() << GetDebugStr(&installer); |
| 2580 | } |
| 2581 | |
Nikita Ioffe | d90eda0 | 2019-07-11 17:56:01 +0100 | [diff] [blame] | 2582 | const auto& status = service_->stagePackages({installer.test_file}); |
Nikita Ioffe | 98054d7 | 2019-04-03 14:18:22 +0100 | [diff] [blame] | 2583 | ASSERT_FALSE(IsOk(status)); |
| 2584 | const std::string& error_message = |
| 2585 | std::string(status.exceptionMessage().c_str()); |
| 2586 | ASSERT_THAT(error_message, HasSubstr("has unexpected SHA512 hash")); |
Nikita Ioffe | d9a25d4 | 2019-03-26 01:37:03 +0000 | [diff] [blame] | 2587 | } |
| 2588 | |
Mohammad Samiul Islam | 5cf48a2 | 2019-11-20 14:40:22 +0000 | [diff] [blame] | 2589 | TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPreInstallHook) { |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2590 | PrepareTestApexForInstall installer( |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2591 | GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"), |
| 2592 | "/data/app-staging/session_23", "staging_data_file"); |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2593 | |
| 2594 | if (!installer.Prepare()) { |
| 2595 | FAIL() << GetDebugStr(&installer); |
| 2596 | } |
| 2597 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2598 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2599 | ApexSessionParams params; |
| 2600 | params.sessionId = 23; |
| 2601 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2602 | } |
| 2603 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2604 | TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) { |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2605 | PrepareTestApexForInstall installer( |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2606 | GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"), |
| 2607 | "/data/app-staging/session_43", "staging_data_file"); |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2608 | |
| 2609 | if (!installer.Prepare()) { |
| 2610 | FAIL() << GetDebugStr(&installer); |
| 2611 | } |
| 2612 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2613 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2614 | ApexSessionParams params; |
| 2615 | params.sessionId = 43; |
| 2616 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 69a1bc5 | 2019-03-29 14:55:29 +0000 | [diff] [blame] | 2617 | } |
| 2618 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2619 | TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) { |
Nikita Ioffe | 2cbca0e | 2019-03-27 19:12:11 +0000 | [diff] [blame] | 2620 | PrepareTestApexForInstall installer( |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2621 | GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"), |
| 2622 | "/data/app-staging/session_41", "staging_data_file"); |
Nikita Ioffe | 2cbca0e | 2019-03-27 19:12:11 +0000 | [diff] [blame] | 2623 | if (!installer.Prepare()) { |
| 2624 | FAIL() << GetDebugStr(&installer); |
| 2625 | } |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2626 | |
| 2627 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2628 | ApexSessionParams params; |
| 2629 | params.sessionId = 41; |
| 2630 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 2cbca0e | 2019-03-27 19:12:11 +0000 | [diff] [blame] | 2631 | } |
| 2632 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2633 | TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) { |
Nikita Ioffe | 2cbca0e | 2019-03-27 19:12:11 +0000 | [diff] [blame] | 2634 | PrepareTestApexForInstall installer( |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2635 | GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"), |
| 2636 | "/data/app-staging/session_42", "staging_data_file"); |
Nikita Ioffe | 2cbca0e | 2019-03-27 19:12:11 +0000 | [diff] [blame] | 2637 | if (!installer.Prepare()) { |
| 2638 | FAIL() << GetDebugStr(&installer); |
| 2639 | } |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2640 | |
| 2641 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2642 | ApexSessionParams params; |
| 2643 | params.sessionId = 42; |
| 2644 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | 2cbca0e | 2019-03-27 19:12:11 +0000 | [diff] [blame] | 2645 | } |
| 2646 | |
Nikita Ioffe | c367f31 | 2019-07-27 15:57:35 +0100 | [diff] [blame] | 2647 | TEST_F(ApexShimUpdateTest, UpdateToV1Success) { |
| 2648 | PrepareTestApexForInstall installer( |
| 2649 | GetTestFile("com.android.apex.cts.shim.apex")); |
| 2650 | |
| 2651 | if (!installer.Prepare()) { |
| 2652 | FAIL() << GetDebugStr(&installer); |
| 2653 | } |
| 2654 | |
| 2655 | ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); |
| 2656 | } |
| 2657 | |
| 2658 | TEST_F(ApexShimUpdateTest, SubmitStagedSessionV1ShimApexSuccess) { |
| 2659 | PrepareTestApexForInstall installer( |
| 2660 | GetTestFile("com.android.apex.cts.shim.apex"), |
| 2661 | "/data/app-staging/session_97", "staging_data_file"); |
| 2662 | if (!installer.Prepare()) { |
| 2663 | FAIL() << GetDebugStr(&installer); |
| 2664 | } |
| 2665 | |
| 2666 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2667 | ApexSessionParams params; |
| 2668 | params.sessionId = 97; |
| 2669 | ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); |
Nikita Ioffe | c367f31 | 2019-07-27 15:57:35 +0100 | [diff] [blame] | 2670 | } |
| 2671 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2672 | TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) { |
Martijn Coenen | 2caabb4 | 2019-04-02 11:42:02 +0200 | [diff] [blame] | 2673 | PrepareTestApexForInstall installer( |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2674 | GetTestFile("apex.apexd_test_corrupt_apex.apex"), |
| 2675 | "/data/app-staging/session_57", "staging_data_file"); |
Martijn Coenen | 2caabb4 | 2019-04-02 11:42:02 +0200 | [diff] [blame] | 2676 | |
| 2677 | if (!installer.Prepare()) { |
| 2678 | FAIL() << GetDebugStr(&installer); |
| 2679 | } |
| 2680 | |
Nikita Ioffe | cd23b64 | 2019-04-05 17:04:11 +0100 | [diff] [blame] | 2681 | ApexInfoList list; |
Oli Lan | 123d9d0 | 2019-12-02 14:08:24 +0000 | [diff] [blame] | 2682 | ApexSessionParams params; |
| 2683 | params.sessionId = 57; |
| 2684 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
Martijn Coenen | 2caabb4 | 2019-04-02 11:42:02 +0200 | [diff] [blame] | 2685 | } |
| 2686 | |
Nikita Ioffe | af157ab | 2020-04-15 22:14:11 +0100 | [diff] [blame] | 2687 | TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails_b146895998) { |
| 2688 | PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"), |
| 2689 | "/data/app-staging/session_71", |
| 2690 | "staging_data_file"); |
| 2691 | |
| 2692 | if (!installer.Prepare()) { |
| 2693 | FAIL() << GetDebugStr(&installer); |
| 2694 | } |
| 2695 | |
| 2696 | ApexInfoList list; |
| 2697 | ApexSessionParams params; |
| 2698 | params.sessionId = 71; |
| 2699 | ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); |
| 2700 | } |
| 2701 | |
| 2702 | TEST_F(ApexServiceTest, StageCorruptApexFails_b146895998) { |
| 2703 | PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex")); |
| 2704 | |
| 2705 | if (!installer.Prepare()) { |
| 2706 | FAIL() << GetDebugStr(&installer); |
| 2707 | } |
| 2708 | |
| 2709 | ASSERT_FALSE(IsOk(service_->stagePackages({installer.test_file}))); |
| 2710 | } |
| 2711 | |
Nikita Ioffe | 78d2bce | 2020-05-02 01:28:30 +0100 | [diff] [blame] | 2712 | TEST_F(ApexServiceTest, RemountPackagesPackageOnSystemChanged) { |
| 2713 | static constexpr const char* kSystemPath = |
| 2714 | "/system_ext/apex/apex.apexd_test.apex"; |
| 2715 | static constexpr const char* kPackageName = "com.android.apex.test_package"; |
| 2716 | if (!fs_mgr_overlayfs_is_setup()) { |
| 2717 | GTEST_SKIP() << "/system_ext is not overlayed into read-write"; |
| 2718 | } |
| 2719 | if (auto res = IsActive(kPackageName); !res.ok()) { |
| 2720 | FAIL() << res.error(); |
| 2721 | } else { |
| 2722 | ASSERT_FALSE(*res) << kPackageName << " is active"; |
| 2723 | } |
| 2724 | ASSERT_EQ(0, access(kSystemPath, F_OK)) |
| 2725 | << "Failed to stat " << kSystemPath << " : " << strerror(errno); |
| 2726 | ASSERT_TRUE(IsOk(service_->activatePackage(kSystemPath))); |
| 2727 | std::string backup_path = GetTestFile("apex.apexd_test.apexd.bak"); |
| 2728 | // Copy original /system_ext apex file. We will need to restore it after test |
| 2729 | // runs. |
| 2730 | ASSERT_RESULT_OK(CopyFile(kSystemPath, backup_path, fs::copy_options::none)); |
| 2731 | |
| 2732 | // Make sure we cleanup after ourselves. |
| 2733 | auto deleter = android::base::make_scope_guard([&]() { |
| 2734 | if (auto ret = service_->deactivatePackage(kSystemPath); !ret.isOk()) { |
| 2735 | LOG(ERROR) << ret.exceptionMessage(); |
| 2736 | } |
| 2737 | auto ret = CopyFile(backup_path, kSystemPath, |
| 2738 | fs::copy_options::overwrite_existing); |
| 2739 | if (!ret.ok()) { |
| 2740 | LOG(ERROR) << ret.error(); |
| 2741 | } |
| 2742 | }); |
| 2743 | |
| 2744 | // Copy v2 version to /system_ext/apex/ and then call remountPackages. |
| 2745 | PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); |
| 2746 | if (!installer.Prepare()) { |
| 2747 | FAIL() << GetDebugStr(&installer); |
| 2748 | } |
| 2749 | ASSERT_RESULT_OK(CopyFile(installer.test_file, kSystemPath, |
| 2750 | fs::copy_options::overwrite_existing)); |
| 2751 | // Don't check that remountPackages succeeded. Most likely it will fail, but |
| 2752 | // it should still remount our test apex. |
| 2753 | service_->remountPackages(); |
| 2754 | |
| 2755 | // Check that v2 is now active. |
| 2756 | auto active_apex = GetActivePackage("com.android.apex.test_package"); |
| 2757 | ASSERT_RESULT_OK(active_apex); |
| 2758 | ASSERT_EQ(2u, active_apex->versionCode); |
| 2759 | // Sanity check that module path didn't change. |
| 2760 | ASSERT_EQ(kSystemPath, active_apex->modulePath); |
| 2761 | } |
| 2762 | |
| 2763 | TEST_F(ApexServiceActivationSuccessTest, RemountPackagesPackageOnDataChanged) { |
| 2764 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 2765 | << GetDebugStr(installer_.get()); |
| 2766 | // Copy v2 version to /data/apex/active and then call remountPackages. |
| 2767 | PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex")); |
| 2768 | if (!installer2.Prepare()) { |
| 2769 | FAIL() << GetDebugStr(&installer2); |
| 2770 | } |
| 2771 | ASSERT_RESULT_OK(CopyFile(installer2.test_file, |
| 2772 | installer_->test_installed_file, |
| 2773 | fs::copy_options::overwrite_existing)); |
| 2774 | // Don't check that remountPackages succeeded. Most likely it will fail, but |
| 2775 | // it should still remount our test apex. |
| 2776 | service_->remountPackages(); |
| 2777 | |
| 2778 | // Check that v2 is now active. |
| 2779 | auto active_apex = GetActivePackage("com.android.apex.test_package"); |
| 2780 | ASSERT_RESULT_OK(active_apex); |
| 2781 | ASSERT_EQ(2u, active_apex->versionCode); |
| 2782 | // Sanity check that module path didn't change. |
| 2783 | ASSERT_EQ(installer_->test_installed_file, active_apex->modulePath); |
| 2784 | } |
| 2785 | |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 2786 | class LogTestToLogcat : public ::testing::EmptyTestEventListener { |
| 2787 | void OnTestStart(const ::testing::TestInfo& test_info) override { |
Andreas Gampe | 5ec47c5 | 2018-11-14 14:33:53 -0800 | [diff] [blame] | 2788 | #ifdef __ANDROID__ |
| 2789 | using base::LogId; |
| 2790 | using base::LogSeverity; |
| 2791 | using base::StringPrintf; |
| 2792 | base::LogdLogger l; |
| 2793 | std::string msg = |
| 2794 | StringPrintf("=== %s::%s (%s:%d)", test_info.test_case_name(), |
| 2795 | test_info.name(), test_info.file(), test_info.line()); |
Nikita Ioffe | ad94bcc | 2020-04-24 15:22:41 +0100 | [diff] [blame] | 2796 | l(LogId::MAIN, LogSeverity::INFO, "ApexTestCases", __FILE__, __LINE__, |
Andreas Gampe | 5ec47c5 | 2018-11-14 14:33:53 -0800 | [diff] [blame] | 2797 | msg.c_str()); |
| 2798 | #else |
Andreas Gampe | 74a8956 | 2018-11-16 14:41:47 -0800 | [diff] [blame] | 2799 | UNUSED(test_info); |
Andreas Gampe | 5ec47c5 | 2018-11-14 14:33:53 -0800 | [diff] [blame] | 2800 | #endif |
| 2801 | } |
| 2802 | }; |
| 2803 | |
Jiyong Park | 361fed2 | 2019-06-03 10:15:50 +0900 | [diff] [blame] | 2804 | struct NoCodeApexNameProvider { |
| 2805 | static std::string GetTestName() { return "apex.apexd_test_nocode.apex"; } |
| 2806 | static std::string GetPackageName() { |
| 2807 | return "com.android.apex.test_package"; |
| 2808 | } |
| 2809 | }; |
| 2810 | |
| 2811 | class ApexServiceActivationNoCode |
| 2812 | : public ApexServiceActivationTest<NoCodeApexNameProvider> {}; |
| 2813 | |
Jooyung Han | 560e40d | 2019-11-15 15:44:08 +0900 | [diff] [blame] | 2814 | TEST_F(ApexServiceActivationNoCode, NoCodeApexIsNotExecutable) { |
Jiyong Park | 361fed2 | 2019-06-03 10:15:50 +0900 | [diff] [blame] | 2815 | ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) |
| 2816 | << GetDebugStr(installer_.get()); |
| 2817 | |
| 2818 | std::string mountinfo; |
| 2819 | ASSERT_TRUE( |
| 2820 | android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo)); |
| 2821 | bool found_apex_mountpoint = false; |
| 2822 | for (const auto& line : android::base::Split(mountinfo, "\n")) { |
| 2823 | std::vector<std::string> tokens = android::base::Split(line, " "); |
| 2824 | // line format: |
| 2825 | // mnt_id parent_mnt_id major:minor source target option propagation_type |
| 2826 | // ex) 33 260:19 / /apex rw,nosuid,nodev - |
| 2827 | if (tokens.size() >= 7 && |
| 2828 | tokens[4] == |
| 2829 | "/apex/" + NoCodeApexNameProvider::GetPackageName() + "@1") { |
| 2830 | found_apex_mountpoint = true; |
| 2831 | // Make sure that option contains noexec |
| 2832 | std::vector<std::string> options = android::base::Split(tokens[5], ","); |
| 2833 | EXPECT_NE(options.end(), |
| 2834 | std::find(options.begin(), options.end(), "noexec")); |
| 2835 | break; |
| 2836 | } |
| 2837 | } |
| 2838 | EXPECT_TRUE(found_apex_mountpoint); |
| 2839 | } |
| 2840 | |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 2841 | } // namespace apex |
| 2842 | } // namespace android |
| 2843 | |
| 2844 | int main(int argc, char** argv) { |
| 2845 | android::base::InitLogging(argv, &android::base::StderrLogger); |
| 2846 | ::testing::InitGoogleTest(&argc, argv); |
Nikita Ioffe | 61a9b53 | 2019-02-14 17:50:00 +0000 | [diff] [blame] | 2847 | ::testing::UnitTest::GetInstance()->listeners().Append( |
Andreas Gampe | 5ec47c5 | 2018-11-14 14:33:53 -0800 | [diff] [blame] | 2848 | new android::apex::LogTestToLogcat()); |
Andreas Gampe | 35e8093 | 2018-10-29 12:56:53 -0700 | [diff] [blame] | 2849 | return RUN_ALL_TESTS(); |
| 2850 | } |