Merge "[recovery/qcom]: Add SSD based implementation for image upgrade" into gingerbread
This commit is contained in:
commit
d6db4505a1
|
@ -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