Move all AOSP code out of recovery binary

Improves license compatibility between GPL and Apache

Change-Id: I2b165aa575bb6213af6b07936f99610c113443f0
diff --git a/twinstall.cpp b/twinstall.cpp
index e1133c0..e7d23ec 100644
--- a/twinstall.cpp
+++ b/twinstall.cpp
@@ -1,18 +1,3 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 
 #include <ctype.h>
 #include <errno.h>
@@ -25,7 +10,7 @@
 #include <string.h>
 #include <stdio.h>
 
-#include "common.h"
+#include "twcommon.h"
 #include "mincrypt/rsa.h"
 #include "mincrypt/sha.h"
 #include "minui/minui.h"
@@ -33,290 +18,150 @@
 #include "minzip/Zip.h"
 #include "mtdutils/mounts.h"
 #include "mtdutils/mtdutils.h"
-#include "roots.h"
 #include "verifier.h"
-#include "ui.h"
 #include "variables.h"
 #include "data.hpp"
 #include "partitions.hpp"
 #include "twrpDigest.hpp"
 #include "twrp-functions.hpp"
+extern "C" {
+	#include "gui/gui.h"
+}
 
-extern RecoveryUI* ui;
+static int Run_Update_Binary(const char *path, ZipArchive *Zip, int* wipe_cache) {
+	const ZipEntry* binary_location = mzFindZipEntry(Zip, ASSUMED_UPDATE_BINARY_NAME);
+	string Temp_Binary = "/tmp/updater";
+	int binary_fd, ret_val, pipe_fd[2], status, zip_verify;
+	char buffer[1024];
+	const char** args = (const char**)malloc(sizeof(char*) * 5);
+	FILE* child_data;
 
-#define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary"
-#define PUBLIC_KEYS_FILE "/res/keys"
+	if (binary_location == NULL) {
+		mzCloseZipArchive(Zip);
+		return INSTALL_CORRUPT;
+	}
 
-// Default allocation of progress bar segments to operations
-static const int VERIFICATION_PROGRESS_TIME = 60;
-static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
-static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
-static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
+	// Delete any existing updater
+	if (TWFunc::Path_Exists(Temp_Binary) && unlink(Temp_Binary.c_str()) != 0) {
+		LOGINFO("Unable to unlink '%s'\n", Temp_Binary.c_str());
+	}
 
-enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
+	binary_fd = creat(Temp_Binary.c_str(), 0755);
+	if (binary_fd < 0) {
+		mzCloseZipArchive(Zip);
+		LOGERR("Could not create file for updater extract in '%s'\n", Temp_Binary.c_str());
+		return INSTALL_ERROR;
+	}
 
-// If the package contains an update binary, extract it and run it.
-static int
-try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
-    const ZipEntry* binary_entry =
-            mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
-    if (binary_entry == NULL) {
-        mzCloseZipArchive(zip);
-        return INSTALL_CORRUPT;
-    }
+	ret_val = mzExtractZipEntryToFile(Zip, binary_location, binary_fd);
+	close(binary_fd);
+	mzCloseZipArchive(Zip);
 
-    const char* binary = "/tmp/update_binary";
-    unlink(binary);
-    int fd = creat(binary, 0755);
-    if (fd < 0) {
-        mzCloseZipArchive(zip);
-        LOGE("Can't make %s\n", binary);
-        return INSTALL_ERROR;
-    }
-    bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
-    close(fd);
-    mzCloseZipArchive(zip);
+	if (!ret_val) {
+		LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME);
+		return INSTALL_ERROR;
+	}
 
-    if (!ok) {
-        LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
-        return INSTALL_ERROR;
-    }
+	pipe(pipe_fd);
 
-    int pipefd[2];
-    pipe(pipefd);
+	args[0] = Temp_Binary.c_str();
+	args[1] = EXPAND(RECOVERY_API_VERSION);
+	char* temp = (char*)malloc(10);
+	sprintf(temp, "%d", pipe_fd[1]);
+	args[2] = temp;
+	args[3] = (char*)path;
+	args[4] = NULL;
 
-    // When executing the update binary contained in the package, the
-    // arguments passed are:
-    //
-    //   - the version number for this interface
-    //
-    //   - 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 the next <frac> part of of the progress bar
-    //            over <secs> seconds.  If <secs> is zero, use
-    //            set_progress commands to manually control the
-    //            progress of this segment of the bar
-    //
-    //        set_progress <frac>
-    //            <frac> should be between 0.0 and 1.0; sets the
-    //            progress bar within the segment defined by the most
-    //            recent progress command.
-    //
-    //        firmware <"hboot"|"radio"> <filename>
-    //            arrange to install the contents of <filename> in the
-    //            given partition on reboot.
-    //
-    //            (API v2: <filename> may start with "PACKAGE:" to
-    //            indicate taking a file from the OTA package.)
-    //
-    //            (API v3: this command no longer exists.)
-    //
-    //        ui_print <string>
-    //            display <string> on the screen.
-    //
-    //   - the name of the package zip file.
-    //
+	pid_t pid = fork();
+	if (pid == 0) {
+		close(pipe_fd[0]);
+		execv(Temp_Binary.c_str(), (char* const*)args);
+		printf("E:Can't execute '%s'\n", Temp_Binary.c_str());
+		_exit(-1);
+	}
+	close(pipe_fd[1]);
 
-    const char** args = (const char**)malloc(sizeof(char*) * 5);
-    args[0] = binary;
-    args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk
-    char* temp = (char*)malloc(10);
-    sprintf(temp, "%d", pipefd[1]);
-    args[2] = temp;
-    args[3] = (char*)path;
-    args[4] = NULL;
+	*wipe_cache = 0;
 
-    pid_t pid = fork();
-    if (pid == 0) {
-        close(pipefd[0]);
-        execv(binary, (char* const*)args);
-        fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
-        _exit(-1);
-    }
-    close(pipefd[1]);
-
-    *wipe_cache = 0;
-
-    char buffer[1024];
-    FILE* from_child = fdopen(pipefd[0], "r");
-    while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
-        char* command = strtok(buffer, " \n");
+	DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
+	child_data = fdopen(pipe_fd[0], "r");
+	while (fgets(buffer, sizeof(buffer), child_data) != NULL) {
+		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");
+            char* fraction_char = strtok(NULL, " \n");
+            char* seconds_char = strtok(NULL, " \n");
 
-            float fraction = strtof(fraction_s, NULL);
-            int seconds = strtol(seconds_s, NULL, 10);
+            float fraction_float = strtof(fraction_char, NULL);
+            int seconds_float = strtol(seconds_char, NULL, 10);
 
-            ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
+            if (zip_verify)
+				DataManager::ShowProgress(fraction_float * (1 - VERIFICATION_PROGRESS_FRACTION), seconds_float);
+			else
+				DataManager::ShowProgress(fraction_float, seconds_float);
         } else if (strcmp(command, "set_progress") == 0) {
-            char* fraction_s = strtok(NULL, " \n");
-            float fraction = strtof(fraction_s, NULL);
-            ui->SetProgress(fraction);
+            char* fraction_char = strtok(NULL, " \n");
+            float fraction_float = strtof(fraction_char, NULL);
+            DataManager::SetProgress(fraction_float);
         } else if (strcmp(command, "ui_print") == 0) {
-            char* str = strtok(NULL, "\n");
-            if (str) {
-                ui->Print("%s", str);
+            char* display_value = strtok(NULL, "\n");
+            if (display_value) {
+                gui_print("%s", display_value);
             } else {
-                ui->Print("\n");
+                gui_print("\n");
             }
         } else if (strcmp(command, "wipe_cache") == 0) {
             *wipe_cache = 1;
         } else if (strcmp(command, "clear_display") == 0) {
-            //ui->SetBackground(RecoveryUI::NONE);
+            // Do nothing, not supported by TWRP
         } else {
-            LOGE("unknown command [%s]\n", command);
+            LOGERR("unknown command [%s]\n", command);
         }
-    }
-    fclose(from_child);
+	}
+	fclose(child_data);
 
-    int status;
-    waitpid(pid, &status, 0);
-    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-        LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
-        return INSTALL_ERROR;
-    }
+	waitpid(pid, &status, 0);
+	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+		LOGERR("Error executing updater binary in zip '%s'\n", path);
+		return INSTALL_ERROR;
+	}
 
-    return INSTALL_SUCCESS;
-}
-
-// Reads a file containing one or more public keys as produced by
-// DumpPublicKey:  this is an RSAPublicKey struct as it would appear
-// as a C source literal, eg:
-//
-//  "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
-//
-// (Note that the braces and commas in this example are actual
-// characters the parser expects to find in the file; the ellipses
-// indicate more numbers omitted from this example.)
-//
-// The file may contain multiple keys in this format, separated by
-// commas.  The last key must not be followed by a comma.
-//
-// Returns NULL if the file failed to parse, or if it contain zero keys.
-static RSAPublicKey*
-load_keys(const char* filename, int* numKeys) {
-    RSAPublicKey* out = NULL;
-    *numKeys = 0;
-
-    FILE* f = fopen(filename, "r");
-    if (f == NULL) {
-        LOGE("opening %s: %s\n", filename, strerror(errno));
-        goto exit;
-    }
-
-    {
-        int i;
-        bool done = false;
-        while (!done) {
-            ++*numKeys;
-            out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
-            RSAPublicKey* key = out + (*numKeys - 1);
-            if (fscanf(f, " { %i , 0x%x , { %u",
-                       &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
-                goto exit;
-            }
-            if (key->len != RSANUMWORDS) {
-                LOGE("key length (%d) does not match expected size\n", key->len);
-                goto exit;
-            }
-            for (i = 1; i < key->len; ++i) {
-                if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
-            }
-            if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
-            for (i = 1; i < key->len; ++i) {
-                if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
-            }
-            fscanf(f, " } } ");
-
-            // if the line ends in a comma, this file has more keys.
-            switch (fgetc(f)) {
-            case ',':
-                // more keys to come.
-                break;
-
-            case EOF:
-                done = true;
-                break;
-
-            default:
-                LOGE("unexpected character between keys\n");
-                goto exit;
-            }
-        }
-    }
-
-    fclose(f);
-    return out;
-
-exit:
-    if (f) fclose(f);
-    free(out);
-    *numKeys = 0;
-    return NULL;
+	return INSTALL_SUCCESS;
 }
 
 extern "C" int TWinstall_zip(const char* path, int* wipe_cache) {
-	int err, zip_verify, md5_return;
+	int ret_val, zip_verify, md5_return, key_count;
 	twrpDigest md5sum;
 	string strpath = path;
-	ui_print("Installing '%s'...\n", path);
+	ZipArchive Zip;
 
-	if (!PartitionManager.Mount_By_Path(path, 0)) {
-		LOGE("Failed to mount '%s'\n", path);
-		return -1;
-	}
-
-	ui_print("Checking for MD5 file...\n");
+	gui_print("Installing '%s'...\nChecking for MD5 file...\n", path);
 	md5sum.setfn(strpath);
 	md5_return = md5sum.verify_md5digest();
 	if (md5_return == -2) {
 		// MD5 did not match.
-		LOGE("Zip MD5 does not match.\nUnable to install zip.\n");
+		LOGERR("Zip MD5 does not match.\nUnable to install zip.\n");
 		return INSTALL_CORRUPT;
 	} else if (md5_return == -1) {
-		ui_print("Skipping MD5 check: no MD5 file found.\n");
+		gui_print("Skipping MD5 check: no MD5 file found.\n");
 	} else if (md5_return == 0)
-		ui_print("Zip MD5 matched.\n"); // MD5 found and matched.
+		gui_print("Zip MD5 matched.\n"); // MD5 found and matched.
 
 	DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
+	DataManager::SetProgress(0);
 	if (zip_verify) {
-		ui_print("Verifying zip signature...\n");
-		int numKeys;
-		RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
-		if (loadedKeys == NULL) {
-			LOGE("Failed to load keys\n");
-			return -1;
-		}
-		LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
-
-		// Give verification half the progress bar...
-		ui->Print("Verifying update package...\n");
-		ui->SetProgressType(RecoveryUI::DETERMINATE);
-		ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
-
-		err = verify_file(path, loadedKeys, numKeys);
-		free(loadedKeys);
-		LOGI("verify_file returned %d\n", err);
-		if (err != VERIFY_SUCCESS) {
-			LOGE("signature verification failed\n");
+		gui_print("Verifying zip signature...\n");
+		ret_val = verify_file(path);
+		if (ret_val != VERIFY_SUCCESS) {
+			LOGERR("Zip signature verification failed: %i\n", ret_val);
 			return -1;
 		}
 	}
-	/* Try to open the package.
-     */
-    ZipArchive zip;
-    err = mzOpenZipArchive(path, &zip);
-    if (err != 0) {
-        LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
-        return INSTALL_CORRUPT;
-    }
-
-    /* Verify and install the contents of the package.
-     */
-    return try_update_binary(path, &zip, wipe_cache);
+	ret_val = mzOpenZipArchive(path, &Zip);
+	if (ret_val != 0) {
+		LOGERR("Zip file is corrupt!\n", path);
+		return INSTALL_CORRUPT;
+	}
+	return Run_Update_Binary(path, &Zip, wipe_cache);
 }