Browse Source

Add a binary path param to update_binary_command().

This allows writing native tests for non-A/B update_binary_command().
Prior to this CL, it was extracting the updater to a hard-coded
location (/tmp/update_binary) that's not available under the test
environment.

Test: recovery_component_test on angler and marlin respectively.
Test: Sideload OTA packages on angler and marlin respectively.
Change-Id: I78b9cc211d90c0a16a84e94e339b65759300e2a8
Tao Bao 4 years ago
parent
commit
00d5757186
3 changed files with 103 additions and 33 deletions
  1. 23
    21
      install.cpp
  2. 6
    2
      private/install.h
  3. 74
    10
      tests/component/install_test.cpp

+ 23
- 21
install.cpp View File

@@ -51,6 +51,7 @@
51 51
 #include "error_code.h"
52 52
 #include "otautil/SysUtil.h"
53 53
 #include "otautil/ThermalUtil.h"
54
+#include "private/install.h"
54 55
 #include "roots.h"
55 56
 #include "ui.h"
56 57
 #include "verifier.h"
@@ -125,12 +126,6 @@ static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::stri
125 126
   }
126 127
 }
127 128
 
128
-// Extract the update binary from the open zip archive |zip| located at |path| and store into |cmd|
129
-// the command line that should be called. The |status_fd| is the file descriptor the child process
130
-// should use to report back the progress of the update.
131
-int update_binary_command(const std::string& path, ZipArchiveHandle zip, int retry_count,
132
-                          int status_fd, std::vector<std::string>* cmd);
133
-
134 129
 #ifdef AB_OTA_UPDATER
135 130
 
136 131
 // Parses the metadata of the OTA package in |zip| and checks whether we are
@@ -211,8 +206,9 @@ static int check_newer_ab_build(ZipArchiveHandle zip) {
211 206
   return 0;
212 207
 }
213 208
 
214
-int update_binary_command(const std::string& path, ZipArchiveHandle zip, int /* retry_count */,
215
-                          int status_fd, std::vector<std::string>* cmd) {
209
+int update_binary_command(const std::string& package, ZipArchiveHandle zip,
210
+                          const std::string& binary_path, int /* retry_count */, int status_fd,
211
+                          std::vector<std::string>* cmd) {
216 212
   CHECK(cmd != nullptr);
217 213
   int ret = check_newer_ab_build(zip);
218 214
   if (ret != 0) {
@@ -246,8 +242,8 @@ int update_binary_command(const std::string& path, ZipArchiveHandle zip, int /*
246 242
   }
247 243
   long payload_offset = payload_entry.offset;
248 244
   *cmd = {
249
-    "/sbin/update_engine_sideload",
250
-    "--payload=file://" + path,
245
+    binary_path,
246
+    "--payload=file://" + package,
251 247
     android::base::StringPrintf("--offset=%ld", payload_offset),
252 248
     "--headers=" + std::string(payload_properties.begin(), payload_properties.end()),
253 249
     android::base::StringPrintf("--status_fd=%d", status_fd),
@@ -257,8 +253,9 @@ int update_binary_command(const std::string& path, ZipArchiveHandle zip, int /*
257 253
 
258 254
 #else  // !AB_OTA_UPDATER
259 255
 
260
-int update_binary_command(const std::string& path, ZipArchiveHandle zip, int retry_count,
261
-                          int status_fd, std::vector<std::string>* cmd) {
256
+int update_binary_command(const std::string& package, ZipArchiveHandle zip,
257
+                          const std::string& binary_path, int retry_count, int status_fd,
258
+                          std::vector<std::string>* cmd) {
262 259
   CHECK(cmd != nullptr);
263 260
 
264 261
   // On traditional updates we extract the update binary from the package.
@@ -270,11 +267,10 @@ int update_binary_command(const std::string& path, ZipArchiveHandle zip, int ret
270 267
     return INSTALL_CORRUPT;
271 268
   }
272 269
 
273
-  const char* binary = "/tmp/update_binary";
274
-  unlink(binary);
275
-  int fd = creat(binary, 0755);
270
+  unlink(binary_path.c_str());
271
+  int fd = creat(binary_path.c_str(), 0755);
276 272
   if (fd == -1) {
277
-    PLOG(ERROR) << "Failed to create " << binary;
273
+    PLOG(ERROR) << "Failed to create " << binary_path;
278 274
     return INSTALL_ERROR;
279 275
   }
280 276
 
@@ -286,10 +282,10 @@ int update_binary_command(const std::string& path, ZipArchiveHandle zip, int ret
286 282
   }
287 283
 
288 284
   *cmd = {
289
-    binary,
285
+    binary_path,
290 286
     EXPAND(RECOVERY_API_VERSION),  // defined in Android.mk
291 287
     std::to_string(status_fd),
292
-    path,
288
+    package,
293 289
   };
294 290
   if (retry_count > 0) {
295 291
     cmd->push_back("retry");
@@ -308,7 +304,7 @@ static void log_max_temperature(int* max_temperature) {
308 304
 }
309 305
 
310 306
 // If the package contains an update binary, extract it and run it.
311
-static int try_update_binary(const std::string& path, ZipArchiveHandle zip, bool* wipe_cache,
307
+static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache,
312 308
                              std::vector<std::string>* log_buffer, int retry_count,
313 309
                              int* max_temperature) {
314 310
   read_source_target_build(zip, log_buffer);
@@ -317,7 +313,13 @@ static int try_update_binary(const std::string& path, ZipArchiveHandle zip, bool
317 313
   pipe(pipefd);
318 314
 
319 315
   std::vector<std::string> args;
320
-  int ret = update_binary_command(path, zip, retry_count, pipefd[1], &args);
316
+#ifdef AB_OTA_UPDATER
317
+  int ret = update_binary_command(package, zip, "/sbin/update_engine_sideload", retry_count,
318
+                                  pipefd[1], &args);
319
+#else
320
+  int ret = update_binary_command(package, zip, "/tmp/update-binary", retry_count, pipefd[1],
321
+                                  &args);
322
+#endif
321 323
   if (ret) {
322 324
     close(pipefd[0]);
323 325
     close(pipefd[1]);
@@ -472,7 +474,7 @@ static int try_update_binary(const std::string& path, ZipArchiveHandle zip, bool
472 474
     return INSTALL_RETRY;
473 475
   }
474 476
   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
475
-    LOG(ERROR) << "Error in " << path << " (Status " << WEXITSTATUS(status) << ")";
477
+    LOG(ERROR) << "Error in " << package << " (Status " << WEXITSTATUS(status) << ")";
476 478
     return INSTALL_ERROR;
477 479
   }
478 480
 

+ 6
- 2
private/install.h View File

@@ -23,5 +23,9 @@
23 23
 
24 24
 #include <ziparchive/zip_archive.h>
25 25
 
26
-int update_binary_command(const std::string& path, ZipArchiveHandle zip, int retry_count,
27
-                          int status_fd, std::vector<std::string>* cmd);
26
+// Extract the update binary from the open zip archive |zip| located at |package| to |binary_path|.
27
+// Store the command line that should be called into |cmd|. The |status_fd| is the file descriptor
28
+// the child process should use to report back the progress of the update.
29
+int update_binary_command(const std::string& package, ZipArchiveHandle zip,
30
+                          const std::string& binary_path, int retry_count, int status_fd,
31
+                          std::vector<std::string>* cmd);

+ 74
- 10
tests/component/install_test.cpp View File

@@ -15,6 +15,8 @@
15 15
  */
16 16
 
17 17
 #include <stdio.h>
18
+#include <sys/stat.h>
19
+#include <sys/types.h>
18 20
 #include <unistd.h>
19 21
 
20 22
 #include <string>
@@ -225,18 +227,62 @@ TEST(InstallTest, update_binary_command_smoke) {
225 227
 
226 228
   ZipArchiveHandle zip;
227 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));
228 233
   int status_fd = 10;
229
-  std::string path = "/path/to/update.zip";
234
+  std::string package = "/path/to/update.zip";
235
+  std::string binary_path = "/sbin/update_engine_sideload";
230 236
   std::vector<std::string> cmd;
231
-  ASSERT_EQ(0, update_binary_command(path, zip, 0, status_fd, &cmd));
232
-  ASSERT_EQ("/sbin/update_engine_sideload", cmd[0]);
233
-  ASSERT_EQ("--payload=file://" + path, cmd[1]);
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]);
234 242
   ASSERT_EQ("--headers=" + properties, cmd[3]);
235 243
   ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]);
236 244
   CloseArchive(zip);
237 245
 #else
238
-  // Cannot test update_binary_command() because it tries to extract update-binary to /tmp.
239
-  GTEST_LOG_(INFO) << "Test skipped on non-A/B device.";
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);
240 286
 #endif  // AB_OTA_UPDATER
241 287
 }
242 288
 
@@ -267,12 +313,30 @@ TEST(InstallTest, update_binary_command_invalid) {
267 313
   ZipArchiveHandle zip;
268 314
   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
269 315
   int status_fd = 10;
270
-  std::string path = "/path/to/update.zip";
316
+  std::string package = "/path/to/update.zip";
317
+  std::string binary_path = "/sbin/update_engine_sideload";
271 318
   std::vector<std::string> cmd;
272
-  ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(path, zip, 0, status_fd, &cmd));
319
+  ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
273 320
   CloseArchive(zip);
274 321
 #else
275
-  // Cannot test update_binary_command() because it tries to extract update-binary to /tmp.
276
-  GTEST_LOG_(INFO) << "Test skipped on non-A/B device.";
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);
277 341
 #endif  // AB_OTA_UPDATER
278 342
 }