[recovery/qcom]: Add SSD based implementation for image upgrade
After recovery extracts the images to radio folder, for NAND targets, set cookie in FOTA and bootloader message. For eMMC targets, create cookie file in FAT partition. Change-Id: I79990b8f31e64186d8bcef68aa55fc1d8b2ca8b5
This commit is contained in:
parent
bcc4923f00
commit
077f748171
|
@ -36,16 +36,23 @@ def AddBootloaderAssertion(info, input_zip):
|
|||
info.script.AssertSomeBootloader(*bootloaders)
|
||||
info.metadata["pre-bootloader"] = m.group(1)
|
||||
|
||||
def CheckRadiotarget(info, mount_point):
|
||||
fstab = info.script.info.get("fstab", None)
|
||||
if fstab:
|
||||
p = fstab[mount_point]
|
||||
info.script.AppendExtra('assert(qcom.set_radio("%s"));' %
|
||||
(p.fs_type))
|
||||
|
||||
def InstallRadio(radio_img, api_version, input_zip, info):
|
||||
common.ZipWriteStr(info.output_zip, "radio.img", radio_img)
|
||||
def InstallRadio(radio_img, api_version, input_zip, fn, info):
|
||||
fn2 = fn[6:]
|
||||
fn3 = "/sdcard/radio/" + fn2
|
||||
common.ZipWriteStr(info.output_zip, fn2, radio_img)
|
||||
|
||||
if api_version >= 3:
|
||||
|
||||
info.script.UnmountAll()
|
||||
info.script.AppendExtra(('''
|
||||
assert(qcom.install_radio(package_extract_file("radio.img")));
|
||||
''' % locals()).lstrip())
|
||||
assert(package_extract_file("%s", "%s"));
|
||||
''' %(fn2,fn3) % locals()).lstrip())
|
||||
|
||||
elif info.input_version >= 2:
|
||||
info.script.AppendExtra(
|
||||
|
@ -57,15 +64,18 @@ assert(qcom.install_radio(package_extract_file("radio.img")));
|
|||
|
||||
|
||||
def FullOTA_InstallEnd(info):
|
||||
try:
|
||||
radio_img = info.input_zip.read("RADIO/radio.img")
|
||||
except KeyError:
|
||||
if info.files == {}:
|
||||
print "warning sha: no radio image in input target_files; not flashing radio"
|
||||
return
|
||||
|
||||
info.script.Print("Writing radio image...")
|
||||
info.script.UnmountAll()
|
||||
for f in info.files:
|
||||
info.script.Print("Writing radio image...")
|
||||
radio_img = info.input_zip.read(f)
|
||||
InstallRadio(radio_img, info.input_version, info.input_zip, f, info)
|
||||
|
||||
InstallRadio(radio_img, info.input_version, info.input_zip, info)
|
||||
CheckRadiotarget(info, "/recovery")
|
||||
return
|
||||
|
||||
|
||||
def IncrementalOTA_InstallEnd(info):
|
||||
|
|
|
@ -42,6 +42,44 @@ static void dump_data(const char *data, int len) {
|
|||
}
|
||||
#endif
|
||||
|
||||
int get_bootloader_message_emmc(struct bootloader_message *out, Volume *v) {
|
||||
FILE* f = fopen(v->device, "rb");
|
||||
if (f == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct bootloader_message temp;
|
||||
int count = fread(&temp, sizeof(temp), 1, f);
|
||||
if (count != 1) {
|
||||
LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) != 0) {
|
||||
LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memcpy(out, &temp, sizeof(temp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_bootloader_message_emmc(const struct bootloader_message *in, Volume *v) {
|
||||
FILE* f = fopen(v->device, "wb");
|
||||
if (f == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int count = fwrite(in, sizeof(*in), 1, f);
|
||||
if (count != 1) {
|
||||
LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) != 0) {
|
||||
LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_bootloader_message(struct bootloader_message *out) {
|
||||
size_t write_size;
|
||||
const MtdPartition *part = mtd_find_partition_by_name(MISC_NAME);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
/* Bootloader / Recovery Flow
|
||||
*
|
||||
|
@ -57,6 +58,9 @@
|
|||
#undef LOGE
|
||||
#define LOGE(...) fprintf(stderr, "E:" __VA_ARGS__)
|
||||
|
||||
static int num_volumes = 0;
|
||||
static Volume* device_volumes = NULL;
|
||||
|
||||
int install_firmware_update(const char *update_type,
|
||||
const char *update_data,
|
||||
size_t update_length,
|
||||
|
@ -94,6 +98,154 @@ int install_firmware_update(const char *update_type,
|
|||
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
LOGE("Can't reboot\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void load_volume_table() {
|
||||
int alloc = 2;
|
||||
device_volumes = malloc(alloc * sizeof(Volume));
|
||||
|
||||
// Insert an entry for /tmp, which is the ramdisk and is always mounted.
|
||||
device_volumes[0].mount_point = "/tmp";
|
||||
device_volumes[0].fs_type = "ramdisk";
|
||||
device_volumes[0].device = NULL;
|
||||
device_volumes[0].device2 = NULL;
|
||||
num_volumes = 1;
|
||||
|
||||
FILE* fstab;
|
||||
fstab = fopen("/etc/recovery_mmc.fstab", "r");
|
||||
|
||||
if (fstab == NULL) {
|
||||
LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
int i;
|
||||
while (fgets(buffer, sizeof(buffer)-1, fstab)) {
|
||||
for (i = 0; buffer[i] && isspace(buffer[i]); ++i);
|
||||
if (buffer[i] == '\0' || buffer[i] == '#') continue;
|
||||
|
||||
char* original = strdup(buffer);
|
||||
|
||||
char* mount_point = strtok(buffer+i, " \t\n");
|
||||
char* fs_type = strtok(NULL, " \t\n");
|
||||
char* device = strtok(NULL, " \t\n");
|
||||
// lines may optionally have a second device, to use if
|
||||
// mounting the first one fails.
|
||||
char* device2 = strtok(NULL, " \t\n");
|
||||
|
||||
if (mount_point && fs_type && device) {
|
||||
while (num_volumes >= alloc) {
|
||||
alloc *= 2;
|
||||
device_volumes = realloc(device_volumes, alloc*sizeof(Volume));
|
||||
}
|
||||
device_volumes[num_volumes].mount_point = strdup(mount_point);
|
||||
device_volumes[num_volumes].fs_type = strdup(fs_type);
|
||||
device_volumes[num_volumes].device = strdup(device);
|
||||
device_volumes[num_volumes].device2 =
|
||||
device2 ? strdup(device2) : NULL;
|
||||
++num_volumes;
|
||||
} else {
|
||||
LOGE("skipping malformed recovery.fstab line: %s\n", original);
|
||||
}
|
||||
free(original);
|
||||
}
|
||||
|
||||
fclose(fstab);
|
||||
}
|
||||
|
||||
static Volume* volume_for_path(const char* path) {
|
||||
int i;
|
||||
for (i = 0; i < num_volumes; ++i) {
|
||||
Volume* v = device_volumes+i;
|
||||
int len = strlen(v->mount_point);
|
||||
if (strncmp(path, v->mount_point, len) == 0 &&
|
||||
(path[len] == '\0' || path[len] == '/')) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int start_firmware_update(char *update_type, char *part_type)
|
||||
{
|
||||
int result;
|
||||
struct bootloader_message boot;
|
||||
|
||||
memset(&boot, 0, sizeof(boot));
|
||||
|
||||
if(!strcmp(part_type, "mtd"))
|
||||
{
|
||||
mtd_scan_partitions();
|
||||
|
||||
strlcpy(boot.recovery, "recovery\n--radio_status\n", sizeof(boot.command));
|
||||
snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
|
||||
if (set_bootloader_message(&boot)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(part_type, "emmc"))
|
||||
{
|
||||
Volume *v = NULL;
|
||||
|
||||
load_volume_table();
|
||||
|
||||
v = volume_for_path("/sys_boot");
|
||||
if (strcmp(v->fs_type, "vfat"))
|
||||
{
|
||||
LOGE("Error in fs_type for sys_boot partition\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mkdir("/sys_boot", 777);
|
||||
|
||||
/* Try mounting device first */
|
||||
result = mount(v->device, v->mount_point, v->fs_type,
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
|
||||
if(result)
|
||||
{
|
||||
/* Try mounting device2 next */
|
||||
result = mount(v->device2, v->mount_point, v->fs_type,
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
/* Creating cookie file for radio update */
|
||||
FILE *fp = fopen("/sys_boot/upcookie.txt", "w");
|
||||
fclose(fp);
|
||||
|
||||
/* Unmount the sdcard now */
|
||||
if(umount(v->mount_point))
|
||||
{
|
||||
LOGE("Error in unmounting %s\n",v->mount_point);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
LOGI("Created cookie file for eMMC radio update\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("Error in mounting %s\n",v->mount_point);
|
||||
return -1;
|
||||
}
|
||||
strlcpy(boot.recovery, "recovery\n--radio_status\n", sizeof(boot.command));
|
||||
snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
|
||||
v = volume_for_path("/misc");
|
||||
if (set_bootloader_message_emmc(&boot, v)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("Error in part_type %s\n",part_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sync();
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
// Can't reboot? WTF?
|
||||
LOGE("Can't reboot\n");
|
||||
return -1;
|
||||
|
|
|
@ -56,8 +56,32 @@ Value* UpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||
return StringValue(strdup(""));
|
||||
}
|
||||
|
||||
Value* SetRadioFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
char *part_type;
|
||||
|
||||
if (argc != 1) {
|
||||
return ErrorAbort(state, "%s() expects arg, got %d", name, argc);
|
||||
}
|
||||
|
||||
char* type = strrchr(name, '_');
|
||||
if (type == NULL || *(type+1) == '\0') {
|
||||
return ErrorAbort(state, "%s() couldn't get type from function name",
|
||||
name);
|
||||
}
|
||||
++type;
|
||||
|
||||
if (ReadArgs(state, argv, 1, &part_type) <0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
start_firmware_update(type,part_type);
|
||||
|
||||
return StringValue(strdup(""));
|
||||
}
|
||||
|
||||
void Register_librecovery_updater_qcom() {
|
||||
fprintf(stderr, "installing QCOM updater extensions\n");
|
||||
|
||||
RegisterFunction("qcom.install_radio", UpdateFn);
|
||||
RegisterFunction("qcom.set_radio", SetRadioFn);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue