1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agree 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 <stdio.h> 18 #include <unistd.h> 19 20 #include <string> 21 #include <vector> 22 23 #include <android-base/file.h> 24 #include <android-base/properties.h> 25 #include <android-base/strings.h> 26 #include <android-base/test_utils.h> 27 #include <gtest/gtest.h> 28 #include <vintf/VintfObjectRecovery.h> 29 #include <ziparchive/zip_archive.h> 30 #include <ziparchive/zip_writer.h> 31 32 #include "install.h" 33 #include "private/install.h" 34 35 TEST(InstallTest, verify_package_compatibility_no_entry) { 36 TemporaryFile temp_file; 37 FILE* zip_file = fdopen(temp_file.fd, "w"); 38 ZipWriter writer(zip_file); 39 // The archive must have something to be opened correctly. 40 ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0)); 41 ASSERT_EQ(0, writer.FinishEntry()); 42 ASSERT_EQ(0, writer.Finish()); 43 ASSERT_EQ(0, fclose(zip_file)); 44 45 // Doesn't contain compatibility zip entry. 46 ZipArchiveHandle zip; 47 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); 48 ASSERT_TRUE(verify_package_compatibility(zip)); 49 CloseArchive(zip); 50 } 51 52 TEST(InstallTest, verify_package_compatibility_invalid_entry) { 53 TemporaryFile temp_file; 54 FILE* zip_file = fdopen(temp_file.fd, "w"); 55 ZipWriter writer(zip_file); 56 ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0)); 57 ASSERT_EQ(0, writer.FinishEntry()); 58 ASSERT_EQ(0, writer.Finish()); 59 ASSERT_EQ(0, fclose(zip_file)); 60 61 // Empty compatibility zip entry. 62 ZipArchiveHandle zip; 63 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); 64 ASSERT_FALSE(verify_package_compatibility(zip)); 65 CloseArchive(zip); 66 } 67 68 TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) { 69 TemporaryFile compatibility_zip_file; 70 FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w"); 71 ZipWriter compatibility_zip_writer(compatibility_zip); 72 ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated)); 73 std::string malformed_xml = "malformed"; 74 ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(malformed_xml.data(), malformed_xml.size())); 75 ASSERT_EQ(0, compatibility_zip_writer.FinishEntry()); 76 ASSERT_EQ(0, compatibility_zip_writer.Finish()); 77 ASSERT_EQ(0, fclose(compatibility_zip)); 78 79 TemporaryFile temp_file; 80 FILE* zip_file = fdopen(temp_file.fd, "w"); 81 ZipWriter writer(zip_file); 82 ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored)); 83 std::string compatibility_zip_content; 84 ASSERT_TRUE( 85 android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content)); 86 ASSERT_EQ(0, 87 writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size())); 88 ASSERT_EQ(0, writer.FinishEntry()); 89 ASSERT_EQ(0, writer.Finish()); 90 ASSERT_EQ(0, fclose(zip_file)); 91 92 ZipArchiveHandle zip; 93 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); 94 std::vector<std::string> compatibility_info; 95 compatibility_info.push_back(malformed_xml); 96 // Malformed compatibility zip is expected to be rejected by libvintf. But we defer that to 97 // libvintf. 98 std::string err; 99 bool result = 100 android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0; 101 ASSERT_EQ(result, verify_package_compatibility(zip)); 102 CloseArchive(zip); 103 } 104 105 TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml) { 106 static constexpr const char* system_manifest_xml_path = "/system/manifest.xml"; 107 if (access(system_manifest_xml_path, R_OK) == -1) { 108 GTEST_LOG_(INFO) << "Test skipped on devices w/o /system/manifest.xml."; 109 return; 110 } 111 std::string system_manifest_xml_content; 112 ASSERT_TRUE( 113 android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content)); 114 TemporaryFile compatibility_zip_file; 115 FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w"); 116 ZipWriter compatibility_zip_writer(compatibility_zip); 117 ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated)); 118 ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(), 119 system_manifest_xml_content.size())); 120 ASSERT_EQ(0, compatibility_zip_writer.FinishEntry()); 121 ASSERT_EQ(0, compatibility_zip_writer.Finish()); 122 ASSERT_EQ(0, fclose(compatibility_zip)); 123 124 TemporaryFile temp_file; 125 FILE* zip_file = fdopen(temp_file.fd, "w"); 126 ZipWriter writer(zip_file); 127 ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored)); 128 std::string compatibility_zip_content; 129 ASSERT_TRUE( 130 android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content)); 131 ASSERT_EQ(0, 132 writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size())); 133 ASSERT_EQ(0, writer.FinishEntry()); 134 ASSERT_EQ(0, writer.Finish()); 135 ASSERT_EQ(0, fclose(zip_file)); 136 137 ZipArchiveHandle zip; 138 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); 139 std::vector<std::string> compatibility_info; 140 compatibility_info.push_back(system_manifest_xml_content); 141 std::string err; 142 bool result = 143 android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0; 144 // Make sure the result is consistent with libvintf library. 145 ASSERT_EQ(result, verify_package_compatibility(zip)); 146 CloseArchive(zip); 147 } 148 149 TEST(InstallTest, update_binary_command_smoke) { 150 #ifdef AB_OTA_UPDATER 151 TemporaryFile temp_file; 152 FILE* zip_file = fdopen(temp_file.fd, "w"); 153 ZipWriter writer(zip_file); 154 ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored)); 155 ASSERT_EQ(0, writer.FinishEntry()); 156 ASSERT_EQ(0, writer.StartEntry("payload_properties.txt", kCompressStored)); 157 const std::string properties = "some_properties"; 158 ASSERT_EQ(0, writer.WriteBytes(properties.data(), properties.size())); 159 ASSERT_EQ(0, writer.FinishEntry()); 160 // A metadata entry is mandatory. 161 ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored)); 162 std::string device = android::base::GetProperty("ro.product.device", ""); 163 ASSERT_NE("", device); 164 std::string timestamp = android::base::GetProperty("ro.build.date.utc", ""); 165 ASSERT_NE("", timestamp); 166 std::string metadata = android::base::Join( 167 std::vector<std::string>{ 168 "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp, 169 }, 170 "\n"); 171 ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size())); 172 ASSERT_EQ(0, writer.FinishEntry()); 173 ASSERT_EQ(0, writer.Finish()); 174 ASSERT_EQ(0, fclose(zip_file)); 175 176 ZipArchiveHandle zip; 177 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); 178 int status_fd = 10; 179 std::string path = "/path/to/update.zip"; 180 std::vector<std::string> cmd; 181 ASSERT_EQ(0, update_binary_command(path, zip, 0, status_fd, &cmd)); 182 ASSERT_EQ("/sbin/update_engine_sideload", cmd[0]); 183 ASSERT_EQ("--payload=file://" + path, cmd[1]); 184 ASSERT_EQ("--headers=" + properties, cmd[3]); 185 ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]); 186 CloseArchive(zip); 187 #else 188 // Cannot test update_binary_command() because it tries to extract update-binary to /tmp. 189 GTEST_LOG_(INFO) << "Test skipped on non-A/B device."; 190 #endif // AB_OTA_UPDATER 191 } 192 193 TEST(InstallTest, update_binary_command_invalid) { 194 #ifdef AB_OTA_UPDATER 195 TemporaryFile temp_file; 196 FILE* zip_file = fdopen(temp_file.fd, "w"); 197 ZipWriter writer(zip_file); 198 // Missing payload_properties.txt. 199 ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored)); 200 ASSERT_EQ(0, writer.FinishEntry()); 201 // A metadata entry is mandatory. 202 ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored)); 203 std::string device = android::base::GetProperty("ro.product.device", ""); 204 ASSERT_NE("", device); 205 std::string timestamp = android::base::GetProperty("ro.build.date.utc", ""); 206 ASSERT_NE("", timestamp); 207 std::string metadata = android::base::Join( 208 std::vector<std::string>{ 209 "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp, 210 }, 211 "\n"); 212 ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size())); 213 ASSERT_EQ(0, writer.FinishEntry()); 214 ASSERT_EQ(0, writer.Finish()); 215 ASSERT_EQ(0, fclose(zip_file)); 216 217 ZipArchiveHandle zip; 218 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); 219 int status_fd = 10; 220 std::string path = "/path/to/update.zip"; 221 std::vector<std::string> cmd; 222 ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(path, zip, 0, status_fd, &cmd)); 223 CloseArchive(zip); 224 #else 225 // Cannot test update_binary_command() because it tries to extract update-binary to /tmp. 226 GTEST_LOG_(INFO) << "Test skipped on non-A/B device."; 227 #endif // AB_OTA_UPDATER 228 } 229