linuxOS_AP05/external/update_engine/partition.cpp
2025-06-02 13:59:07 +08:00

338 lines
12 KiB
C++

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"
#include <openssl/md5.h>
#include "rkimage.h"
#include <map>
#include <string>
#include "md5sum.h"
using namespace std;
extern double processvalue;
int getNowSlot(){
char cmdline[1024];
int fd = open("/proc/cmdline", O_RDONLY);
read(fd, (char*)cmdline, 1024);
close(fd);
//LOGI("cmdline = %s", cmdline);
char *slot = strstr(cmdline, "androidboot.slot_suffix");
if(slot != NULL){
slot = strstr(slot, "=");
if(slot != NULL){
slot +=2;
if((*slot) == 'a'){
LOGI("boot from slot_a.\n");
return SLOT_A;
}else if((*slot) == 'b'){
LOGI("boot from slot_b.\n");
return SLOT_B;
}
}
}
LOGE("unknow boot from where");
return SLOT_UNKNOW;
}
bool getPartitionType(char* name, char *dest_path){
map<string, string> Partition = {
map<string, string>::value_type("boot_a", "/dev/block/by-name/boot_a"),
map<string, string>::value_type("boot_b", "/dev/block/by-name/boot_b"),
map<string, string>::value_type("rootfs_a", "/dev/block/by-name/system_a"),
map<string, string>::value_type("rootfs_b", "/dev/block/by-name/system_b"),
map<string, string>::value_type("vbmeta_a", "/dev/block/by-name/vbmeta_a"),
map<string, string>::value_type("vbmeta_b", "/dev/block/by-name/vbmeta_b"),
};
//LOGI("item->name is %s", name);
char tmp_name[120];
strcpy(tmp_name, name);
map<string, string>::iterator it;
switch(getNowSlot()){
case SLOT_A:
strcat(tmp_name, "_b");
break;
case SLOT_B:
strcat(tmp_name, "_a");
break;
default:
return false;
break;
}
it = Partition.find(tmp_name);
if(it == Partition.end()){
LOGE("no found");
dest_path = NULL;
return false;
}
LOGI("getPartitionType is %s", it->second.c_str());
strcpy(dest_path, it->second.c_str());
return true;
}
void RKWrite(char *filename, char *data, unsigned int len){
//getfilename
static char last_filename[128];
static int fd;
if(strcmp(last_filename, filename) != 0){
fsync(fd);
close(fd);
fd = -1;
}
if(fd == -1){
char des_name[120];
if(!getPartitionType(filename, des_name)){
LOGE("%s no need write.\n", filename);
return ;
}
// fd = open(filename, O_RDWR | O_CREAT, 0644);
fd = open(des_name, O_RDWR | O_CREAT, 0644);
strcpy(last_filename, filename);
LOGI("open filename is %s\n", filename);
}
if(fd == -1){
LOGE("open %s failed.\n", filename);
return ;
}
write(fd, data, len);
strcpy(last_filename, filename);
}
int writeDataToPartition(struct ImageData *data){
/* Need to read the documents before 512 bytes,
* to determine whether the new way of packing update.
* If not be, according to the way to handle before then
* If the new packaging mode, the firmware of the offset each file to adjust accordingly
*
*/
static unsigned int currentOffset;
static unsigned RKIMAGE_HDR_READ;
unsigned int pos = 0;
static unsigned int gFwOffset;
static unsigned int fwSize;
//1. IMAGE_HEADER
if(data->offset < 512){
static char headTmp[512];
if(data->offset + data->size < 512){
memcpy(headTmp + currentOffset, data->data, data->size);
currentOffset = data->offset + data->size;
}else{
memcpy(headTmp + currentOffset, data->data, 512-data->offset);
currentOffset = 512;
}
if(currentOffset == 512){
/*
if(data->size < 512){
LOGE("OTA file is error.\n");
return -1;
}*/
// Confirm whether the new packaging format
if( *((unsigned int*)headTmp) == 0x57464B52 )
{
gFwOffset = *(unsigned int*)(headTmp + 0x21);
fwSize = *(unsigned int *)(headTmp + 0x25);
}
currentOffset = 512;
pos = 512;
LOGI("gFwOffset = %d, fwSize = %d\n", gFwOffset, fwSize);
if(fwSize <= 0){
LOGE("OTA file is error.\n");
return -1;
}
}
}
//2. BOOT_DATA
//<=gFwOffset
int RKIMAGE_HDR_Len = sizeof(RKIMAGE_HDR);
static RKIMAGE_HDR hdr;
static char hdrTmp[2000];
static bool flag;
if(data->offset + data->size < gFwOffset){
return 0;
}else if (gFwOffset != 0){
if(RKIMAGE_HDR_READ < RKIMAGE_HDR_Len){
unsigned int len_boot = data->offset + data->size;
if(len_boot >= gFwOffset && data->offset <= gFwOffset){
if(data->offset+data->size-gFwOffset >= RKIMAGE_HDR_Len){
memcpy(hdrTmp, data->data+(gFwOffset-data->offset), RKIMAGE_HDR_Len);
RKIMAGE_HDR_READ += RKIMAGE_HDR_Len;
}else{
memcpy(hdrTmp, data->data+(gFwOffset-data->offset), data->offset+data->size-gFwOffset);
RKIMAGE_HDR_READ += data->offset+data->size-gFwOffset;
}
}else if(data->offset > gFwOffset){
if(data->size <= (RKIMAGE_HDR_Len - RKIMAGE_HDR_READ)){
memcpy(hdrTmp + RKIMAGE_HDR_READ, data->data, data->size);
RKIMAGE_HDR_READ += data->size;
}else{
memcpy(hdrTmp + RKIMAGE_HDR_READ, data->data, RKIMAGE_HDR_Len-RKIMAGE_HDR_READ);
RKIMAGE_HDR_READ += RKIMAGE_HDR_Len - RKIMAGE_HDR_READ;
}
}
}
if(RKIMAGE_HDR_READ == RKIMAGE_HDR_Len){
if(!flag){
memcpy(&hdr, hdrTmp, RKIMAGE_HDR_Len);
//display_RKIMAGE_HDR(&hdr);
if(hdr.tag != RKIMAGE_TAG){
LOGE("tag is error\n");
return -1;
}
if(gFwOffset){
adjustFileOffset(&hdr, gFwOffset);
display_RKIMAGE_HDR(&hdr);
}
flag = true;
}
//find Item
RKIMAGE_HDR *pRKImage = &hdr;
unsigned int write_offset;
unsigned int write_len;
for(int i = 0; i < pRKImage->item_count; i++){
if(data->offset < pRKImage->item[i].offset && data->offset + data->size > pRKImage->item[i].offset){
write_offset = pRKImage->item[i].offset - data->offset;
if(data->offset + data->size <= pRKImage->item[i].offset + pRKImage->item[i].size){
write_len = data->offset + data->size - pRKImage->item[i].offset;
RKWrite(pRKImage->item[i].name, data->data + write_offset, write_len);
return 0;
}else{
write_len = pRKImage->item[i].size;
RKWrite(pRKImage->item[i].name, data->data + write_offset, write_len);
struct ImageData tmp;
tmp.size = data->offset + data->size - (pRKImage->item[i].offset + pRKImage->item[i].size);
tmp.offset = pRKImage->item[i].offset + pRKImage->item[i].size;
tmp.data = data->data + (pRKImage->item[i].offset + pRKImage->item[i].size - data->offset);
writeDataToPartition(&tmp);
return 0;
}
}else if(data->offset >= pRKImage->item[i].offset && data->offset < pRKImage->item[i].offset + pRKImage->item[i].size){
if(data->offset + data->size <= pRKImage->item[i].offset + pRKImage->item[i].size){
write_len = data->size;
RKWrite(pRKImage->item[i].name, data->data, write_len);
return 0;
}else{
write_len = pRKImage->item[i].offset + pRKImage->item[i].size - data->offset;
RKWrite(pRKImage->item[i].name, data->data, write_len);
struct ImageData tmp;
tmp.size = data->offset + data->size - pRKImage->item[i].size - pRKImage->item[i].offset;
tmp.offset = pRKImage->item[i].offset + pRKImage->item[i].size;
tmp.data = data->data + write_len;
writeDataToPartition(&tmp);
return 0;
}
}
}
}
}
return 0;
//3. FIRMWARE_DATA
//4. MD5 check
}
bool writeImageToPartition(const char* path){
RKIMAGE_HDR hdr;
char data_buf[16*1024] = {0};
if(CheckImageFile(path, &hdr) != 0){
LOGE("CheckImageFile filed.\n");
return false;
}
processvalue = 95;
for(int i = 0; i < hdr.item_count; i++){
//char name[PART_NAME];
//char file[RELATIVE_PATH];
//unsigned int offset;
//unsigned int flash_offset;
//unsigned int usespace;
//unsigned int size;
char dest_path[256] = {0};
int fd_src = 0;
int fd_dest = 0;
int src_offset, dest_offset;
int src_step, dest_step;
int src_remain, dest_remain;
int src_file_offset = 0;
dest_offset = 0;
if(getPartitionType(hdr.item[i].name, dest_path)){
//write
LOGI("write image of %s to %s.\n", hdr.item[i].name, dest_path);
fd_src = open(path, O_RDONLY);
if (fd_src < 0) {
LOGE("Can't open %s\n", path);
return false;
}
src_offset = hdr.item[i].offset;
dest_remain = src_remain = hdr.item[i].size;
dest_step = src_step = 16*1024;
lseek(fd_src, src_offset, SEEK_SET);
src_file_offset = src_offset;
//???
fd_dest = open(dest_path, O_RDWR | O_CREAT, 0644);
if(fd_dest < 0){
LOGE("Can't open %s\n", path);
return false;
}
lseek(fd_dest, dest_offset, SEEK_SET);
int read_count, write_count;
while(src_remain > 0 && dest_remain > 0){
memset(data_buf, 0, 16*1024);
read_count = src_remain>src_step?src_step:src_remain;
if(read(fd_src, data_buf, read_count) != read_count){
close(fd_src);
close(fd_dest);
LOGE("Read failed(%s)\n", strerror(errno));
return false;
}
src_remain -= read_count;
src_file_offset += read_count;
write_count = (src_remain == 0)?dest_remain:dest_step;
if(write(fd_dest, data_buf, dest_step) != dest_step){
close(fd_src);
close(fd_dest);
LOGE("Write failed(%s)\n", strerror(errno));
return false;
}
dest_remain -= write_count;
}
fsync(fd_dest);
close(fd_src);
close(fd_dest);
//check
LOGI("check image of %s to %s.\n", hdr.item[i].name, dest_path);
if(!comparefile(dest_path, path, 0, src_offset, hdr.item[i].size)){
LOGE("check image of %s to %s. failed.\n", hdr.item[i].name, dest_path);
return false;
}
}
}
processvalue = 100;
return true;
}