Retrieving arguments from BCB and cache files

As we can see in the main function of recovery, it calls to the get_args function to retrieve arguments from the main system or bootloader. The following is the flow diagram of get_args. It is in the same $AOSP/bootable/recovery/recovery.cpp file as the main function of recovery.

Flow diagram of get_args

From the following code snippet, we can see that it calls to the get_bootloader_message function to get the BCB data structure, boot:

static void 
get_args(int *argc, char ***argv) {
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
get_bootloader_message(&boot); // this may fail, leaving a zeroed
//structure
stage = strndup(boot.stage, sizeof(boot.stage));
...

If there are no arguments, the value of argc will be less or equal to 1. It will try to get the arguments from BCB, as in the following code snippet. In the recovery field of BCB, the command will start with recovery . The content after recovery  is the same format as the cache command file, /cache/recovery/command:

if (*argc <= 1) { 
boot.recovery[sizeof(boot.recovery) - 1] = '';
const char *arg = strtok(boot.recovery, " ");
if (arg != NULL && !strcmp(arg, "recovery")) {
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = strdup(arg);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if ((arg = strtok(NULL, " ")) == NULL) break;
(*argv)[*argc] = strdup(arg);
}
LOGI("Got arguments from boot message ");
} else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
LOGE("Bad boot message "%.20s" ", boot.recovery);
}
}

If the arguments can be retrieved from BCB, it will skip the cache command file. Otherwise, it will try to read arguments from the cache command file as follows:

if (*argc <= 1) { 
FILE *fp = fopen_path(COMMAND_FILE, "r");
if (fp != NULL) {
char *token;
char *argv0 = (*argv)[0];
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = argv0; // use the same program name

char buf[MAX_ARG_LENGTH];
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
token = strtok(buf, " ");
if (token != NULL) {
(*argv)[*argc] = strdup(token);
} else {
--*argc;
}
}

check_and_fclose(fp, COMMAND_FILE);
LOGI("Got arguments from %s ", COMMAND_FILE);
}
}

After processing both BCB and the cache command file, it will write the BCB block to the /misc partition so that if there is any error during the process of update or erase, the same process will continue after the reboot:

strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); 
strlcpy(boot.recovery, "recovery ", sizeof(boot.recovery));
int i;
for (i = 1; i < *argc; ++i) {
strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
strlcat(boot.recovery, " ", sizeof(boot.recovery));
}
set_bootloader_message(&boot);

From the preceding code analysis, we can see that the cache command file is just a normal text file. It can be accessed by just using the standard C functions. To access the /misc partition for BCB data structure, the get_bootloader_message function is used to read BCB and the set_bootloader_message function is used to write BCB. The BCB data structure bootloader_message is defined in the bootloader.h file and related functions are implemented in the bootloader.cpp file.

The /misc partition is a raw partition and it is used by the code in bootloader.cpp as a normal file instead of a filesystem volume.

We can have a quick look at the get_bootloader_message function and its support function, get_bootloader_message_block, as follows:

int get_bootloader_message(struct bootloader_message *out) { 
Volume* v = volume_for_path("/misc");
if (v == NULL) {
LOGE("Cannot load volume /misc! ");
return -1;
}
if (strcmp(v->fs_type, "mtd") == 0) {
return get_bootloader_message_mtd(out, v);
} else if (strcmp(v->fs_type, "emmc") == 0) {
return get_bootloader_message_block(out, v);
}
LOGE("unknown misc partition fs_type "%s" ", v->fs_type);
return -1;
}

In the get_bootloader_message function, it will call another function according to the type of partition, /misc. As we can see, the supported raw filesystem types are mtd and emmc. We can look at the emmc version, get_bootloader_message_block, as follows:

static int get_bootloader_message_block(struct bootloader_message *out, 
const Volume* v) {
wait_for_device(v->blk_device);
FILE* f = fopen(v->blk_device, "rb");
if (f == NULL) {
LOGE("Can't open %s (%s) ", v->blk_device, strerror(errno));
return -1;
}
struct bootloader_message temp;
int count = fread(&temp, sizeof(temp), 1, f);
if (count != 1) {
LOGE("Failed reading %s (%s) ", v->blk_device,
strerror(errno));
return -1;
}
if (fclose(f) != 0) {
LOGE("Failed closing %s (%s) ", v->blk_device,
strerror(errno));
return -1;
}
memcpy(out, &temp, sizeof(temp));
return 0;
}

As we can see, in the get_bootloader_message_block function, it accesses the /misc partition as a normal file using C functions fopen, fread, and fclose.

Now we have done the analysis of BCB and cache file processing. We will look at the following two most important workflows of recovery in the next two sections:

  • Factory data reset
  • OTA update
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.217.194