#include #include #include #include #include #include "log.h" #include #include #include #include "data.h" #include #include "rkimage.h" #include #include #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 Partition = { map::value_type("boot_a", "/dev/block/by-name/boot_a"), map::value_type("boot_b", "/dev/block/by-name/boot_b"), map::value_type("rootfs_a", "/dev/block/by-name/system_a"), map::value_type("rootfs_b", "/dev/block/by-name/system_b"), map::value_type("vbmeta_a", "/dev/block/by-name/vbmeta_a"), map::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::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; }