• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include <string>
23 #include <vector>
24 
25 #include <android-base/file.h>
26 #include <android-base/properties.h>
27 #include <android-base/strings.h>
28 #include <android-base/test_utils.h>
29 #include <gtest/gtest.h>
30 #include <vintf/VintfObjectRecovery.h>
31 #include <ziparchive/zip_archive.h>
32 #include <ziparchive/zip_writer.h>
33 
34 #include "install.h"
35 #include "private/install.h"
36 
TEST(InstallTest,verify_package_compatibility_no_entry)37 TEST(InstallTest, verify_package_compatibility_no_entry) {
38   TemporaryFile temp_file;
39   FILE* zip_file = fdopen(temp_file.fd, "w");
40   ZipWriter writer(zip_file);
41   // The archive must have something to be opened correctly.
42   ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
43   ASSERT_EQ(0, writer.FinishEntry());
44   ASSERT_EQ(0, writer.Finish());
45   ASSERT_EQ(0, fclose(zip_file));
46 
47   // Doesn't contain compatibility zip entry.
48   ZipArchiveHandle zip;
49   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
50   ASSERT_TRUE(verify_package_compatibility(zip));
51   CloseArchive(zip);
52 }
53 
TEST(InstallTest,verify_package_compatibility_invalid_entry)54 TEST(InstallTest, verify_package_compatibility_invalid_entry) {
55   TemporaryFile temp_file;
56   FILE* zip_file = fdopen(temp_file.fd, "w");
57   ZipWriter writer(zip_file);
58   ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0));
59   ASSERT_EQ(0, writer.FinishEntry());
60   ASSERT_EQ(0, writer.Finish());
61   ASSERT_EQ(0, fclose(zip_file));
62 
63   // Empty compatibility zip entry.
64   ZipArchiveHandle zip;
65   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
66   ASSERT_FALSE(verify_package_compatibility(zip));
67   CloseArchive(zip);
68 }
69 
TEST(InstallTest,read_metadata_from_package_smoke)70 TEST(InstallTest, read_metadata_from_package_smoke) {
71   TemporaryFile temp_file;
72   FILE* zip_file = fdopen(temp_file.fd, "w");
73   ZipWriter writer(zip_file);
74   ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
75   const std::string content("abcdefg");
76   ASSERT_EQ(0, writer.WriteBytes(content.data(), content.size()));
77   ASSERT_EQ(0, writer.FinishEntry());
78   ASSERT_EQ(0, writer.Finish());
79   ASSERT_EQ(0, fclose(zip_file));
80 
81   ZipArchiveHandle zip;
82   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
83   std::string metadata;
84   ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
85   ASSERT_EQ(content, metadata);
86   CloseArchive(zip);
87 
88   TemporaryFile temp_file2;
89   FILE* zip_file2 = fdopen(temp_file2.fd, "w");
90   ZipWriter writer2(zip_file2);
91   ASSERT_EQ(0, writer2.StartEntry("META-INF/com/android/metadata", kCompressDeflated));
92   ASSERT_EQ(0, writer2.WriteBytes(content.data(), content.size()));
93   ASSERT_EQ(0, writer2.FinishEntry());
94   ASSERT_EQ(0, writer2.Finish());
95   ASSERT_EQ(0, fclose(zip_file2));
96 
97   ASSERT_EQ(0, OpenArchive(temp_file2.path, &zip));
98   metadata.clear();
99   ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
100   ASSERT_EQ(content, metadata);
101   CloseArchive(zip);
102 }
103 
TEST(InstallTest,read_metadata_from_package_no_entry)104 TEST(InstallTest, read_metadata_from_package_no_entry) {
105   TemporaryFile temp_file;
106   FILE* zip_file = fdopen(temp_file.fd, "w");
107   ZipWriter writer(zip_file);
108   ASSERT_EQ(0, writer.StartEntry("dummy_entry", kCompressStored));
109   ASSERT_EQ(0, writer.FinishEntry());
110   ASSERT_EQ(0, writer.Finish());
111   ASSERT_EQ(0, fclose(zip_file));
112 
113   ZipArchiveHandle zip;
114   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
115   std::string metadata;
116   ASSERT_FALSE(read_metadata_from_package(zip, &metadata));
117   CloseArchive(zip);
118 }
119 
TEST(InstallTest,verify_package_compatibility_with_libvintf_malformed_xml)120 TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) {
121   TemporaryFile compatibility_zip_file;
122   FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w");
123   ZipWriter compatibility_zip_writer(compatibility_zip);
124   ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
125   std::string malformed_xml = "malformed";
126   ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(malformed_xml.data(), malformed_xml.size()));
127   ASSERT_EQ(0, compatibility_zip_writer.FinishEntry());
128   ASSERT_EQ(0, compatibility_zip_writer.Finish());
129   ASSERT_EQ(0, fclose(compatibility_zip));
130 
131   TemporaryFile temp_file;
132   FILE* zip_file = fdopen(temp_file.fd, "w");
133   ZipWriter writer(zip_file);
134   ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
135   std::string compatibility_zip_content;
136   ASSERT_TRUE(
137       android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
138   ASSERT_EQ(0,
139             writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size()));
140   ASSERT_EQ(0, writer.FinishEntry());
141   ASSERT_EQ(0, writer.Finish());
142   ASSERT_EQ(0, fclose(zip_file));
143 
144   ZipArchiveHandle zip;
145   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
146   std::vector<std::string> compatibility_info;
147   compatibility_info.push_back(malformed_xml);
148   // Malformed compatibility zip is expected to be rejected by libvintf. But we defer that to
149   // libvintf.
150   std::string err;
151   bool result =
152       android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0;
153   ASSERT_EQ(result, verify_package_compatibility(zip));
154   CloseArchive(zip);
155 }
156 
TEST(InstallTest,verify_package_compatibility_with_libvintf_system_manifest_xml)157 TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml) {
158   static constexpr const char* system_manifest_xml_path = "/system/manifest.xml";
159   if (access(system_manifest_xml_path, R_OK) == -1) {
160     GTEST_LOG_(INFO) << "Test skipped on devices w/o /system/manifest.xml.";
161     return;
162   }
163   std::string system_manifest_xml_content;
164   ASSERT_TRUE(
165       android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content));
166   TemporaryFile compatibility_zip_file;
167   FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w");
168   ZipWriter compatibility_zip_writer(compatibility_zip);
169   ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
170   ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(),
171                                                    system_manifest_xml_content.size()));
172   ASSERT_EQ(0, compatibility_zip_writer.FinishEntry());
173   ASSERT_EQ(0, compatibility_zip_writer.Finish());
174   ASSERT_EQ(0, fclose(compatibility_zip));
175 
176   TemporaryFile temp_file;
177   FILE* zip_file = fdopen(temp_file.fd, "w");
178   ZipWriter writer(zip_file);
179   ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
180   std::string compatibility_zip_content;
181   ASSERT_TRUE(
182       android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
183   ASSERT_EQ(0,
184             writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size()));
185   ASSERT_EQ(0, writer.FinishEntry());
186   ASSERT_EQ(0, writer.Finish());
187   ASSERT_EQ(0, fclose(zip_file));
188 
189   ZipArchiveHandle zip;
190   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
191   std::vector<std::string> compatibility_info;
192   compatibility_info.push_back(system_manifest_xml_content);
193   std::string err;
194   bool result =
195       android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0;
196   // Make sure the result is consistent with libvintf library.
197   ASSERT_EQ(result, verify_package_compatibility(zip));
198   CloseArchive(zip);
199 }
200 
TEST(InstallTest,update_binary_command_smoke)201 TEST(InstallTest, update_binary_command_smoke) {
202 #ifdef AB_OTA_UPDATER
203   TemporaryFile temp_file;
204   FILE* zip_file = fdopen(temp_file.fd, "w");
205   ZipWriter writer(zip_file);
206   ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
207   ASSERT_EQ(0, writer.FinishEntry());
208   ASSERT_EQ(0, writer.StartEntry("payload_properties.txt", kCompressStored));
209   const std::string properties = "some_properties";
210   ASSERT_EQ(0, writer.WriteBytes(properties.data(), properties.size()));
211   ASSERT_EQ(0, writer.FinishEntry());
212   // A metadata entry is mandatory.
213   ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
214   std::string device = android::base::GetProperty("ro.product.device", "");
215   ASSERT_NE("", device);
216   std::string timestamp = android::base::GetProperty("ro.build.date.utc", "");
217   ASSERT_NE("", timestamp);
218   std::string metadata = android::base::Join(
219       std::vector<std::string>{
220           "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp,
221       },
222       "\n");
223   ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size()));
224   ASSERT_EQ(0, writer.FinishEntry());
225   ASSERT_EQ(0, writer.Finish());
226   ASSERT_EQ(0, fclose(zip_file));
227 
228   ZipArchiveHandle zip;
229   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
230   ZipString payload_name("payload.bin");
231   ZipEntry payload_entry;
232   ASSERT_EQ(0, FindEntry(zip, payload_name, &payload_entry));
233   int status_fd = 10;
234   std::string package = "/path/to/update.zip";
235   std::string binary_path = "/sbin/update_engine_sideload";
236   std::vector<std::string> cmd;
237   ASSERT_EQ(0, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
238   ASSERT_EQ(5U, cmd.size());
239   ASSERT_EQ(binary_path, cmd[0]);
240   ASSERT_EQ("--payload=file://" + package, cmd[1]);
241   ASSERT_EQ("--offset=" + std::to_string(payload_entry.offset), cmd[2]);
242   ASSERT_EQ("--headers=" + properties, cmd[3]);
243   ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]);
244   CloseArchive(zip);
245 #else
246   TemporaryFile temp_file;
247   FILE* zip_file = fdopen(temp_file.fd, "w");
248   ZipWriter writer(zip_file);
249   static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
250   ASSERT_EQ(0, writer.StartEntry(UPDATE_BINARY_NAME, kCompressStored));
251   ASSERT_EQ(0, writer.FinishEntry());
252   ASSERT_EQ(0, writer.Finish());
253   ASSERT_EQ(0, fclose(zip_file));
254 
255   ZipArchiveHandle zip;
256   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
257   int status_fd = 10;
258   std::string package = "/path/to/update.zip";
259   TemporaryDir td;
260   std::string binary_path = std::string(td.path) + "/update_binary";
261   std::vector<std::string> cmd;
262   ASSERT_EQ(0, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
263   ASSERT_EQ(4U, cmd.size());
264   ASSERT_EQ(binary_path, cmd[0]);
265   ASSERT_EQ("3", cmd[1]);  // RECOVERY_API_VERSION
266   ASSERT_EQ(std::to_string(status_fd), cmd[2]);
267   ASSERT_EQ(package, cmd[3]);
268   struct stat sb;
269   ASSERT_EQ(0, stat(binary_path.c_str(), &sb));
270   ASSERT_EQ(static_cast<mode_t>(0755), sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
271 
272   // With non-zero retry count. update_binary will be removed automatically.
273   cmd.clear();
274   ASSERT_EQ(0, update_binary_command(package, zip, binary_path, 2, status_fd, &cmd));
275   ASSERT_EQ(5U, cmd.size());
276   ASSERT_EQ(binary_path, cmd[0]);
277   ASSERT_EQ("3", cmd[1]);  // RECOVERY_API_VERSION
278   ASSERT_EQ(std::to_string(status_fd), cmd[2]);
279   ASSERT_EQ(package, cmd[3]);
280   ASSERT_EQ("retry", cmd[4]);
281   sb = {};
282   ASSERT_EQ(0, stat(binary_path.c_str(), &sb));
283   ASSERT_EQ(static_cast<mode_t>(0755), sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
284 
285   CloseArchive(zip);
286 #endif  // AB_OTA_UPDATER
287 }
288 
TEST(InstallTest,update_binary_command_invalid)289 TEST(InstallTest, update_binary_command_invalid) {
290 #ifdef AB_OTA_UPDATER
291   TemporaryFile temp_file;
292   FILE* zip_file = fdopen(temp_file.fd, "w");
293   ZipWriter writer(zip_file);
294   // Missing payload_properties.txt.
295   ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
296   ASSERT_EQ(0, writer.FinishEntry());
297   // A metadata entry is mandatory.
298   ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
299   std::string device = android::base::GetProperty("ro.product.device", "");
300   ASSERT_NE("", device);
301   std::string timestamp = android::base::GetProperty("ro.build.date.utc", "");
302   ASSERT_NE("", timestamp);
303   std::string metadata = android::base::Join(
304       std::vector<std::string>{
305           "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp,
306       },
307       "\n");
308   ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size()));
309   ASSERT_EQ(0, writer.FinishEntry());
310   ASSERT_EQ(0, writer.Finish());
311   ASSERT_EQ(0, fclose(zip_file));
312 
313   ZipArchiveHandle zip;
314   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
315   int status_fd = 10;
316   std::string package = "/path/to/update.zip";
317   std::string binary_path = "/sbin/update_engine_sideload";
318   std::vector<std::string> cmd;
319   ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
320   CloseArchive(zip);
321 #else
322   TemporaryFile temp_file;
323   FILE* zip_file = fdopen(temp_file.fd, "w");
324   ZipWriter writer(zip_file);
325   // The archive must have something to be opened correctly.
326   ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
327   ASSERT_EQ(0, writer.FinishEntry());
328   ASSERT_EQ(0, writer.Finish());
329   ASSERT_EQ(0, fclose(zip_file));
330 
331   // Missing update binary.
332   ZipArchiveHandle zip;
333   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
334   int status_fd = 10;
335   std::string package = "/path/to/update.zip";
336   TemporaryDir td;
337   std::string binary_path = std::string(td.path) + "/update_binary";
338   std::vector<std::string> cmd;
339   ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
340   CloseArchive(zip);
341 #endif  // AB_OTA_UPDATER
342 }
343