am b2ee9201: allow OTA package to provide binary instead of script
				
					
				
			Merge commit 'b2ee9201be583b17ddbf0eaa69a37545f992b565' * commit 'b2ee9201be583b17ddbf0eaa69a37545f992b565': allow OTA package to provide binary instead of script
This commit is contained in:
		
				
					committed by
					
						 The Android Open Source Project
						The Android Open Source Project
					
				
			
			
				
	
			
			
			
					commit
					825915dc6c
				
			
							
								
								
									
										170
									
								
								install.c
									
									
									
									
									
								
							
							
						
						
									
										170
									
								
								install.c
									
									
									
									
									
								
							| @@ -14,10 +14,13 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "amend/amend.h" | ||||
| #include "common.h" | ||||
| @@ -30,8 +33,10 @@ | ||||
| #include "mtdutils/mtdutils.h" | ||||
| #include "roots.h" | ||||
| #include "verifier.h" | ||||
| #include "firmware.h" | ||||
|  | ||||
| #define ASSUMED_UPDATE_SCRIPT_NAME  "META-INF/com/google/android/update-script" | ||||
| #define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary" | ||||
| #define PUBLIC_KEYS_FILE "/res/keys" | ||||
|  | ||||
| static const ZipEntry * | ||||
| @@ -95,7 +100,7 @@ handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry) | ||||
|     int ret = execCommandList((ExecContext *)1, commands); | ||||
|     if (ret != 0) { | ||||
|         int num = ret; | ||||
|         char *line, *next = script_data; | ||||
|         char *line = NULL, *next = script_data; | ||||
|         while (next != NULL && ret-- > 0) { | ||||
|             line = next; | ||||
|             next = memchr(line, '\n', script_data + script_len - line); | ||||
| @@ -109,6 +114,159 @@ handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry) | ||||
|     return INSTALL_SUCCESS; | ||||
| } | ||||
|  | ||||
| // The update binary ask us to install a firmware file on reboot.  Set | ||||
| // that up.  Takes ownership of type and filename. | ||||
| static int | ||||
| handle_firmware_update(char* type, char* filename) { | ||||
|     struct stat st_data; | ||||
|     if (stat(filename, &st_data) < 0) { | ||||
|         LOGE("Error stat'ing %s: %s\n", filename, strerror(errno)); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|  | ||||
|     LOGI("type is [%s]\n", type); | ||||
|  | ||||
|     char* data = malloc(st_data.st_size); | ||||
|     if (data == NULL) { | ||||
|         LOGE("Can't allocate %d bytes for firmware data\n", st_data.st_size); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|  | ||||
|     FILE* f = fopen(filename, "rb"); | ||||
|     if (f == NULL) { | ||||
|         LOGE("Failed to open %s: %s\n", filename, strerror(errno)); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|     if (fread(data, 1, st_data.st_size, f) != st_data.st_size) { | ||||
|         LOGE("Failed to read firmware data: %s\n", strerror(errno)); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|     fclose(f); | ||||
|  | ||||
|     if (remember_firmware_update(type, data, st_data.st_size)) { | ||||
|         LOGE("Can't store %s image\n", type); | ||||
|         free(data); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|     free(filename); | ||||
|  | ||||
|     return INSTALL_SUCCESS; | ||||
| } | ||||
|  | ||||
| // If the package contains an update binary, extract it and run it. | ||||
| static int | ||||
| try_update_binary(const char *path, ZipArchive *zip) { | ||||
|     const ZipEntry* binary_entry = | ||||
|             mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); | ||||
|     if (binary_entry == NULL) { | ||||
|         return INSTALL_CORRUPT; | ||||
|     } | ||||
|  | ||||
|     char* binary = "/tmp/update_binary"; | ||||
|     unlink(binary); | ||||
|     int fd = creat(binary, 0755); | ||||
|     if (fd < 0) { | ||||
|         LOGE("Can't make %s\n", binary); | ||||
|         return 1; | ||||
|     } | ||||
|     bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); | ||||
|     close(fd); | ||||
|  | ||||
|     if (!ok) { | ||||
|         LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     int pipefd[2]; | ||||
|     pipe(pipefd); | ||||
|  | ||||
|     // When executing the update binary contained in the package, the | ||||
|     // arguments passed are: | ||||
|     // | ||||
|     //   - the version number for this interface (currently 1) | ||||
|     // | ||||
|     //   - an fd to which the program can write in order to update the | ||||
|     //     progress bar.  The program can write single-line commands: | ||||
|     // | ||||
|     //        progress <frac> <secs> | ||||
|     //            fill up <frac> of the progress bar over <secs> seconds. | ||||
|     // | ||||
|     //        firmware <"hboot"|"radio"> <filename> | ||||
|     //            arrange to install the contents of <filename> in the | ||||
|     //            given partition on reboot. | ||||
|     // | ||||
|     //   - the name of the package zip file. | ||||
|     // | ||||
|  | ||||
|     char** args = malloc(sizeof(char*) * 5); | ||||
|     args[0] = binary; | ||||
|     args[1] = "1"; | ||||
|     args[2] = malloc(10); | ||||
|     sprintf(args[2], "%d", pipefd[1]); | ||||
|     args[3] = (char*)path; | ||||
|     args[4] = NULL; | ||||
|  | ||||
|     pid_t pid = fork(); | ||||
|     if (pid == 0) { | ||||
|         close(pipefd[0]); | ||||
|         execv(binary, args); | ||||
|         fprintf(stderr, "E:Can't run %s (%s)\n", binary, strerror(errno)); | ||||
|         _exit(-1); | ||||
|     } | ||||
|     close(pipefd[1]); | ||||
|  | ||||
|     char* firmware_type = NULL; | ||||
|     char* firmware_filename = NULL; | ||||
|  | ||||
|     char buffer[81]; | ||||
|     FILE* from_child = fdopen(pipefd[0], "r"); | ||||
|     while (fgets(buffer, sizeof(buffer), from_child) != NULL) { | ||||
|         LOGI("read: %s", buffer); | ||||
|  | ||||
|         char* command = strtok(buffer, " \n"); | ||||
|         if (command == NULL) { | ||||
|             continue; | ||||
|         } else if (strcmp(command, "progress") == 0) { | ||||
|             char* fraction_s = strtok(NULL, " \n"); | ||||
|             char* seconds_s = strtok(NULL, " \n"); | ||||
|  | ||||
|             float fraction = strtof(fraction_s, NULL); | ||||
|             int seconds = strtol(seconds_s, NULL, 10); | ||||
|  | ||||
|             ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), | ||||
|                              seconds); | ||||
|         } else if (strcmp(command, "firmware") == 0) { | ||||
|             char* type = strtok(NULL, " \n"); | ||||
|             char* filename = strtok(NULL, " \n"); | ||||
|  | ||||
|             if (type != NULL && filename != NULL) { | ||||
|                 if (firmware_type != NULL) { | ||||
|                     LOGE("ignoring attempt to do multiple firmware updates"); | ||||
|                 } else { | ||||
|                     firmware_type = strdup(type); | ||||
|                     firmware_filename = strdup(filename); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             LOGE("unknown command [%s]\n", command); | ||||
|         } | ||||
|     } | ||||
|     fclose(from_child); | ||||
|  | ||||
|     int status; | ||||
|     waitpid(pid, &status, 0); | ||||
|     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | ||||
|         LOGE("Error in %s\n(Status %d)\n", path, status); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|  | ||||
|     if (firmware_type != NULL) { | ||||
|         return handle_firmware_update(firmware_type, firmware_filename); | ||||
|     } else { | ||||
|         return INSTALL_SUCCESS; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int | ||||
| handle_update_package(const char *path, ZipArchive *zip, | ||||
|                       const RSAPublicKey *keys, int numKeys) | ||||
| @@ -127,6 +285,16 @@ handle_update_package(const char *path, ZipArchive *zip, | ||||
|     // Update should take the rest of the progress bar. | ||||
|     ui_print("Installing update...\n"); | ||||
|  | ||||
|     int result = try_update_binary(path, zip); | ||||
|     if (result == INSTALL_SUCCESS || result == INSTALL_ERROR) { | ||||
|         register_package_root(NULL, NULL);  // Unregister package root | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     // if INSTALL_CORRUPT is returned, this package doesn't have an | ||||
|     // update binary.  Fall back to the older mechanism of looking for | ||||
|     // an update script. | ||||
|  | ||||
|     const ZipEntry *script_entry; | ||||
|     script_entry = find_update_script(zip); | ||||
|     if (script_entry == NULL) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user