windows下android打包工具
这是我的第一篇博客,以前总想写点什么,但总是迟迟不见行动,会有各种借口来放弃,最近反思自己,这样真的好吗,呵呵,改变从现在开始。
首先我来说下为什么我要写windows下android打包工具,我们的android4.2项目开发是在windows上的,大家用的是eclipse,各自写好的APK最后交于一人,由他来合成最后的system.img.ext4,然后发于客户升级,合成环境也是在windows上,一开始,我们找到了“ROM助手”这款软件,用来打包apk,以及so,用用还可以,但随着客户的增多,以及其他类型的文件需要打包,这款软件开始出现其弊端,因为需要手工去点击操作,而不是批量化生成,效率比较低而且容易出错,鉴于此我打算写一款工具,用来满足我们的工作需求。
想过几种方案,最简单的莫过于在Ubuntu上写个脚本,直接用现成的make_ext4fs工具来生成,但我们要求在winddows上,所以排除了,至于为什么不用Ubuntu,那理由很low,就不说了。
后来想到了cygwin下能编译Linux上的软件,所以将make_ext4fs的源代码拷出,放于cygwin上编译,编译通过,哈哈,竟然能在windows上生成system.img.ext4了,开心了会,但又发现了问题,权限不对,全部变为0755了,而且不支持链接文件,这不符合我们的要求啊,而且要求系统工程师提供的原始system.img.ext4文件已经全部解压开来,汗。发现了问题,那就要解决问题。
现在需要解决的问题有:
1.system.img.ext4在windows下解压开来,要求记录链接文件以及权限,uid等信息。
2. 修改make_ext4fs程序,使之支持读取我们记录下来的权限等信息。
对于第一个问题,我们知道system.img.ext4其实不是ext4格式的,具体叫什么格式,我也不知道,呵呵,只知道Linux下有个simg2img 工具,可以将system.img.ext4转化为裸的ext4格式的image,暂且就叫system.img.ext4为simg格式吧,这种格式其实就是用一个个的chunk,有CHUNK_TYPE_RAW,CHUNK_TYPE_DONT_CARE类型,CHUNK_TYPE_RAW记录实际的文件数据,CHUNK_TYPE_DONT_CARE记录的是image中的0块,这样就可以实现文件的精简,原理其实和wince的xip格式也差不多,都是为了跳过大块的0区域。
simg2img 工具的实现可以按照实现make_ext4fs在cygwin实现的方式一样。但我自己又实现了一种简单的转化函数,效果一样,看源码:
// 转化函数
bool simg2ext4(char *srcPath, char *desPath)
{
// 打开文件
HANDLE hFile =CreateFile(srcPath, GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hFile ==INVALID_HANDLE_VALUE)
{
printf("%snot exist \r\n", srcPath);
return false;
}
// 得到文件大小
int dwfileSize = GetFileSize(hFile,NULL);
printf("dwfileSize= %d \r\n", dwfileSize);
// 文件映射
HANDLE hFileMapping =CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (NULL ==hFileMapping)
{
printf("CreateFileMappingerror\r\n");
CloseHandle(hFile);
return false;
}
CloseHandle(hFile);
// 得到文件内存指针
unsigned char*lpbMapAddress = (unsigned char *)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0,0, dwfileSize);
if (lpbMapAddress ==NULL)
{
printf("MapViewOfFileerror \r\n");
return false;
}
//--------------------- 解析文件-----------------------
unsigned intblock_size = 0;
unsigned int chunk_cnt= 0;
unsigned int filelen =dwfileSize;
unsigned char*pfileBuffer = NULL;
unsigned int datalen;
unsigned longu8WriteAddr = 0;
sparse_header_t*ptSparseHeader = NULL;
chunk_header_t *ptChunkHeader = NULL;
// 1. 获取sparse的头
ptSparseHeader =(sparse_header_t *)lpbMapAddress;
block_size =ptSparseHeader->blk_sz;
chunk_cnt =ptSparseHeader->total_chunks;
printf("ptSparseHeader->blk_sz = 0X%x\r\n", ptSparseHeader->blk_sz);
printf("ptSparseHeader->total_blks = 0X%x\r\n",ptSparseHeader->total_blks);
printf("ptSparseHeader->total_chunks = 0X%x\r\n",ptSparseHeader->total_chunks);
// 2. 内容开始出
pfileBuffer =lpbMapAddress + sizeof(sparse_header_t);
filelen -=sizeof(sparse_header_t);
// 3. 用0填充文件
HANDLE hFileWrite =CreateFile(desPath, GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_READ,NULL, CREATE_ALWAYS, 0, 0);
void *buff =malloc(ptSparseHeader->blk_sz);
memset(buff, 0x00,ptSparseHeader->blk_sz);
unsigned longdwNumberOfBytesWritten;
for (unsigned int i=0;i<ptSparseHeader->total_blks; i++)
{
WriteFile(hFileWrite,buff, ptSparseHeader->blk_sz, &dwNumberOfBytesWritten, 0);
}
free(buff);
// 4. 将数据写入文件
while((chunk_cnt>0) && (filelen>0))
{
ptChunkHeader =(chunk_header_t *)pfileBuffer;
datalen =ptChunkHeader->chunk_sz * block_size;
printf("ptChunkHeader->chunk_type = %d\r\n",ptChunkHeader->chunk_type);
printf("ptChunkHeader->chunk_sz = 0X%x\r\n",ptChunkHeader->chunk_sz);
printf("datalen = 0X%x\r\n", datalen);
if(CHUNK_TYPE_RAW == ptChunkHeader->chunk_type)
{
pfileBuffer+= CHUNK_HEADER_LEN;
SetFilePointer(hFileWrite,u8WriteAddr, 0, FILE_BEGIN);
WriteFile(hFileWrite,pfileBuffer, datalen, &dwNumberOfBytesWritten, 0);
filelen-= ptChunkHeader->total_sz;
chunk_cnt--;
pfileBuffer+=datalen;
u8WriteAddr+= datalen;
}
else if(CHUNK_TYPE_DONT_CARE == ptChunkHeader->chunk_type)
{
u8WriteAddr+= datalen;
pfileBuffer+= ptChunkHeader->total_sz;
filelen-= ptChunkHeader->total_sz;
chunk_cnt--;
}
else
{
printf("ptChunkHeader->chunk_type error\r\n");
CloseHandle(hFileWrite);
DeleteFile(desPath);
// 撤销文件映像
UnmapViewOfFile(lpbMapAddress);
CloseHandle(hFileMapping);
returnfalse;
}
}
CloseHandle(hFileWrite);
//-------------------- 解析文件结束--------------------
// 撤销文件映像
UnmapViewOfFile(lpbMapAddress);
CloseHandle(hFileMapping);
return true;
}
首先是将system.img.ext4文件做文件映射,然后再生成一个全部是0的system.img文件,接着,就一个一个chunk的写入,哈哈,最后转化成功,还是比较简单的。
我们用simg2img 工具生成system.img,接下来,我们就要实现在windows下读取释放所有system.img中的文件。在github上,我发现了一款人气比较旺的软件ex2read,该软件可以读取system.img的文件信息,已经文件的内容,所以我试着改写其代码,实现文件的读取以及文件信息的保存,其中有点问题的是,ex2read没有实现链接文件的读取,自己实现了下,然后将文件信息写入对应文件夹的linux_files_info.cxj文件中。
// 释放image
bool release_image(Ext2File *dir, char *path)
{
char fileInfo[1024];
char fileInfoName[1024];
char relasePath[1024];
int status;
DWORD dWrited;
// 创建文件夹
memset(relasePath, 0x00, 1024);
strcat(relasePath, path);
strcat(relasePath, "\\");
strcat(relasePath, dir->file_name.c_str());
status = mkdir(relasePath);
if (status != 0)
{
printf("mkdir %s error \n", relasePath);
return false;
}
// 读取文件夹
EXT2DIRENT *dir_rent = app->mPartotion->open_dir(dir);
// 创建文件属性文件
memset(fileInfoName, 0x00, 1024);
strcat(fileInfoName, relasePath);
strcat(fileInfoName, "\\linux_files_info.cxj");
HANDLE hFileinfo = CreateFileA(fileInfoName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
Ext2File *files;
while((files = app->mPartotion->read_dir(dir_rent)) != NULL)
{
if (EXT2_S_ISDIR(files->inode.i_mode))
{
// 将属性写入文件
memset(fileInfo, 0x00, 1024);
sprintf(fileInfo, "%s,D,0x%04x,0x%04x,0x%04x\n", files->file_name.c_str(),
files->inode.i_mode, files->inode.i_uid, files->inode.i_gid);
printf("%s", fileInfo);
WriteFile(hFileinfo, fileInfo, strlen(fileInfo), &dWrited, 0);
// 文件夹递归
release_image(files, relasePath);
}
else if (EXT2_S_ISREG(files->inode.i_mode))
{
// 将属性写入文件
memset(fileInfo, 0x00, 1024);
sprintf(fileInfo, "%s,F,0x%04x,0x%04x,0x%04x\n", files->file_name.c_str(),
files->inode.i_mode, files->inode.i_uid, files->inode.i_gid);
printf("%s", fileInfo);
WriteFile(hFileinfo, fileInfo, strlen(fileInfo), &dWrited, 0);
// 释放文件
char relaseFile[1024];
memset(relaseFile, 0x00, 1024);
strcat(relaseFile, relasePath);
strcat(relaseFile, "\\");
strcat(relaseFile, files->file_name.c_str());
copy_file(files, relaseFile);
}
else if (EXT2_S_ISLINK(files->inode.i_mode))
{
// 将属性写入文件
memset(fileInfo, 0x00, 1024);
sprintf(fileInfo, "%s,L,0x%04x,0x%04x,0x%04x\n", files->file_name.c_str(),
files->inode.i_mode, files->inode.i_uid, files->inode.i_gid);
printf("%s", fileInfo);
WriteFile(hFileinfo, fileInfo, strlen(fileInfo), &dWrited, 0);
// 释放链接文件
char relaseFile[1024];
memset(relaseFile, 0x00, 1024);
strcat(relaseFile, relasePath);
strcat(relaseFile, "\\");
strcat(relaseFile, files->file_name.c_str());
readLinkfile(files, relaseFile);
}
}
// 关闭并保存文件
CloseHandle(hFileinfo);
app->mPartotion->close_dir(dir_rent);
}
// 拷贝文件
bool copy_file(Ext2File *srcfile, char* destfile)
{
DWORD dWrited;
lloff_t blocks, blkindex;
int ret, extra;
int blksize = srcfile->partition->get_blocksize();
char *buffer = new char [blksize];
HANDLE filetosave = CreateFileA(destfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
//printf("blksize=%d \n", blksize);
//printf("file_size=%d \n", srcfile->file_size);
blocks = srcfile->file_size / blksize;
for (blkindex=0; blkindex<blocks; blkindex++)
{
ret = srcfile->partition->read_data_block(&srcfile->inode, blkindex, buffer);
if (ret < 0)
{
CloseHandle(filetosave);
printf("read_data_block error \n");
return false;
}
WriteFile(filetosave, buffer, blksize, &dWrited, 0);
}
extra = srcfile->file_size % blksize;
if(extra)
{
ret = srcfile->partition->read_data_block(&srcfile->inode, blkindex, buffer);
if(ret < 0)
{
CloseHandle(filetosave);
printf("read_data_block error \n");
return false;
}
WriteFile(filetosave, buffer, extra, &dWrited, 0);
}
CloseHandle(filetosave);
delete [] buffer;
return true;
}
// 读取软连接文件
bool readLinkfile(Ext2File *srcfile, char* destfile)
{
DWORD dWrited;
lloff_t blocks, blkindex;
int ret, extra;
int blksize = srcfile->partition->get_blocksize();
char *buffer = new char [blksize];
HANDLE filetosave = CreateFileA(destfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0 );
memcpy(buffer, srcfile->inode.i_block, srcfile->file_size);
WriteFile(filetosave, buffer, srcfile->file_size, &dWrited, 0);
CloseHandle(filetosave);
delete [] buffer;
return true;
}
这样我们就构建好了文件架构,实现了链接文件的保存已经文件信息的记录。
接下来,我们就要改写make_ext4fs工具了,研究make_ext4fs的源码我们发现,其架构是在build_directory_structure函数中完成的,此函数是递归函数,根据文件夹的目录来分配entry_inode,并且通过链表dentries来记录文件所在的路径,在最后写imag的时候可以打开文件实现文件内容的写入。我们的目标就是改写此函数,用我们的linux_files_info.cxj来构建系统,而不是扫描文件夹,具体见代码
/* Read a local directory and create the same tree in the generated filesystem.
Calls itself recursively with each directory in the given directory */
static u32 build_directory_structure(const char *full_path, const char *dir_path,
u32 dir_inode, fs_config_func_t fs_config_func,
struct selabel_handle *sehnd)
{
// cxj modify
#if 0
int entries = 0;
struct dentry *dentries;
struct dirent **namelist = NULL;
struct stat stat;
int ret;
int i;
u32 inode;
u32 entry_inode;
u32 dirs = 0;
bool needs_lost_and_found = false;
if (full_path) {
entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
if (entries < 0) {
error_errno("scandir");
return EXT4_ALLOCATE_FAILED;
}
}
if (dir_inode == 0) {
/* root directory, check if lost+found already exists */
for (i = 0; i < entries; i++)
if (strcmp(namelist[i]->d_name, "lost+found") == 0)
break;
if (i == entries)
needs_lost_and_found = true;
}
dentries = calloc(entries, sizeof(struct dentry));
if (dentries == NULL)
critical_error_errno("malloc");
// cxj add
printf("------------------- \n");
for (i = 0; i < entries; i++) {
dentries[i].filename = strdup(namelist[i]->d_name);
if (dentries[i].filename == NULL)
critical_error_errno("strdup");
asprintf(&dentries[i].path, "%s/%s", dir_path, namelist[i]->d_name);
asprintf(&dentries[i].full_path, "%s/%s", full_path, namelist[i]->d_name);
// cxj add
//printf("------------------- \n");
printf("%s \n", dentries[i].path);
printf("%s \n", dentries[i].full_path);
free(namelist[i]);
ret = lstat(dentries[i].full_path, &stat);
if (ret < 0) {
error_errno("lstat");
i--;
entries--;
continue;
}
dentries[i].size = stat.st_size;
dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
dentries[i].mtime = stat.st_mtime;
if (fs_config_func != NULL) {
#ifdef ANDROID
unsigned int mode = 0;
unsigned int uid = 0;
unsigned int gid = 0;
int dir = S_ISDIR(stat.st_mode);
fs_config_func(dentries[i].path, dir, &uid, &gid, &mode);
dentries[i].mode = mode;
dentries[i].uid = uid;
dentries[i].gid = gid;
#else
error("can't set android permissions - built without android support");
#endif
}
#ifdef HAVE_SELINUX
if (sehnd) {
char *sepath = NULL;
asprintf(&sepath, "/%s", dentries[i].path);
if (selabel_lookup(sehnd, &dentries[i].secon, sepath, stat.st_mode) < 0) {
error("cannot lookup security context for %s", sepath);
}
if (dentries[i].secon)
printf("Labeling %s as %s\n", sepath, dentries[i].secon);
free(sepath);
}
#endif
if (S_ISREG(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_REG_FILE;
} else if (S_ISDIR(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_DIR;
dirs++;
} else if (S_ISCHR(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_CHRDEV;
} else if (S_ISBLK(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_BLKDEV;
} else if (S_ISFIFO(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_FIFO;
} else if (S_ISSOCK(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_SOCK;
} else if (S_ISLNK(stat.st_mode)) {
dentries[i].file_type = EXT4_FT_SYMLINK;
dentries[i].link = calloc(info.block_size, 1);
readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1);
} else {
error("unknown file type on %s", dentries[i].path);
i--;
entries--;
}
}
free(namelist);
if (needs_lost_and_found) {
/* insert a lost+found directory at the beginning of the dentries */
struct dentry *tmp = calloc(entries + 1, sizeof(struct dentry));
memset(tmp, 0, sizeof(struct dentry));
memcpy(tmp + 1, dentries, entries * sizeof(struct dentry));
dentries = tmp;
dentries[0].filename = strdup("lost+found");
asprintf(&dentries[0].path, "%s/lost+found", dir_path);
dentries[0].full_path = NULL;
dentries[0].size = 0;
dentries[0].mode = S_IRWXU;
dentries[0].file_type = EXT4_FT_DIR;
dentries[0].uid = 0;
dentries[0].gid = 0;
#ifdef HAVE_SELINUX
if (sehnd) {
char *sepath = NULL;
asprintf(&sepath, "/%s", dentries[0].path);
if (selabel_lookup(sehnd, &dentries[0].secon, sepath, dentries[0].mode) < 0)
error("cannot lookup security context for %s", dentries[0].path);
free(sepath);
}
#endif
entries++;
dirs++;
}
inode = make_directory(dir_inode, entries, dentries, dirs);
for (i = 0; i < entries; i++) {
if (dentries[i].file_type == EXT4_FT_REG_FILE) {
entry_inode = make_file(dentries[i].full_path, dentries[i].size);
} else if (dentries[i].file_type == EXT4_FT_DIR) {
entry_inode = build_directory_structure(dentries[i].full_path,
dentries[i].path, inode, fs_config_func, sehnd);
} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
entry_inode = make_link(dentries[i].full_path, dentries[i].link);
} else {
error("unknown file type on %s", dentries[i].path);
entry_inode = 0;
}
*dentries[i].inode = entry_inode;
ret = inode_set_permissions(entry_inode, dentries[i].mode,
dentries[i].uid, dentries[i].gid,
dentries[i].mtime);
if (ret)
error("failed to set permissions on %s\n", dentries[i].path);
ret = inode_set_selinux(entry_inode, dentries[i].secon);
if (ret)
error("failed to set SELinux context on %s\n", dentries[i].path);
free(dentries[i].path);
free(dentries[i].full_path);
free(dentries[i].link);
free((void *)dentries[i].filename);
free(dentries[i].secon);
}
free(dentries);
return inode;
#else
int entries = 0;
struct dentry *dentries;
struct dirent **namelist = NULL;
struct stat stat;
int ret;
int i;
u32 inode;
u32 entry_inode;
u32 dirs = 0;
bool needs_lost_and_found = false;
char fileInfoName[1024];
char *fileContent;
int filesize = 0;
int hFile;
char *pLine;
char *token;
int infostep;
// 找出文件属性文件
memset(fileInfoName, 0x00, 1024);
strcat(fileInfoName, full_path);
strcat(fileInfoName, "/linux_files_info.cxj");
printf("fileInfoName=%s \r\n", fileInfoName);
hFile = open(fileInfoName, O_RDONLY);
if (hFile < 0)
{
error_errno("open %s error \n", fileInfoName);
return EXT4_ALLOCATE_FAILED;
}
// 读取属性文件
ret = lstat(fileInfoName, &stat);
if (ret < 0)
{
error_errno("lstat");
return EXT4_ALLOCATE_FAILED;
}
printf("size=%d \n", stat.st_size);
if (stat.st_size == 0)
{
goto KONGDIR;
}
filesize = stat.st_size;
fileContent = calloc(filesize, 1);
if (fileContent == NULL)
{
close(hFile);
critical_error_errno("malloc");
return EXT4_ALLOCATE_FAILED;
}
read(hFile, fileContent, filesize);
close(hFile);
// 一行一行解析
entries = readLines(fileContent, filesize);
printf("entries = %d \r\n", entries);
dentries = calloc(entries, sizeof(struct dentry));
if (dentries == NULL)
{
// 释放分配的内存
free(fileContent);
critical_error_errno("malloc");
return EXT4_ALLOCATE_FAILED;
}
for(i=0; i<entries; i++)
{
char *stopstring;
//printf("%s\n", readLine(fileContent, filesize, i));
pLine = readLine(fileContent, filesize, i);
token=strtok(pLine, ",");
infostep = 0;
while (token != NULL)
{
switch(infostep)
{
// name
case 0:
dentries[i].filename = strdup(token);
asprintf(&dentries[i].path, "%s/%s", dir_path, token);
asprintf(&dentries[i].full_path, "%s/%s", full_path, token);
//printf("%s \n", dentries[i].path);
//printf("%s \n", dentries[i].full_path);
lstat(dentries[i].full_path, &stat);
dentries[i].size = stat.st_size;
dentries[i].mtime = 0;
break;
// type
case 1:
if (token[0] == 'F')
{
dentries[i].file_type = EXT4_FT_REG_FILE;
}
else if (token[0] == 'D')
{
dentries[i].file_type = EXT4_FT_DIR;
dirs++;
}
else if (token[0] == 'L')
{
int hLinkFile;
dentries[i].file_type = EXT4_FT_SYMLINK;
dentries[i].link = calloc(info.block_size, 1);
hLinkFile = open(dentries[i].full_path, O_RDONLY);
read(hLinkFile, dentries[i].link, info.block_size - 1);
close(hLinkFile);
}
break;
// mode
case 2:
dentries[i].mode = strtol(token, &stopstring, 16);
break;
// uid
case 3:
dentries[i].uid = strtol(token, &stopstring, 16);
break;
// gid
case 4:
dentries[i].gid = strtol(token, &stopstring, 16);
break;
}
infostep++;
token = strtok(NULL, ",");
}
}
// 释放分配的内存
free(fileContent);
#if 0
if (dir_inode == 0)
{
for (i=0; i<entries; i++)
{
if (dentries[i].filename, "lost+found") == 0)
break;
}
if (i == entries)
{
needs_lost_and_found = true;
}
}
if (needs_lost_and_found)
{
struct dentry *tmp = calloc(entries + 1, sizeof(struct dentry));
memset(tmp, 0, sizeof(struct dentry));
memcpy(tmp + 1, dentries, entries * sizeof(struct dentry));
free(dentries);
dentries = tmp;
dentries[0].filename = strdup("lost+found");
asprintf(&dentries[0].path, "%s/lost+found", dir_path);
dentries[0].full_path = NULL;
dentries[0].size = 0;
dentries[0].mode = S_IRWXU;
dentries[0].file_type = EXT4_FT_DIR;
dentries[0].uid = 0;
dentries[0].gid = 0;
entries++;
dirs++;
}
#endif
KONGDIR:
inode = make_directory(dir_inode, entries, dentries, dirs);
for (i=0; i<entries; i++)
{
if (dentries[i].file_type == EXT4_FT_REG_FILE)
{
entry_inode = make_file(dentries[i].full_path, dentries[i].size);
}
else if (dentries[i].file_type == EXT4_FT_DIR)
{
entry_inode = build_directory_structure(dentries[i].full_path,
dentries[i].path, inode, fs_config_func, sehnd);
}
else if (dentries[i].file_type == EXT4_FT_SYMLINK)
{
entry_inode = make_link(dentries[i].full_path, dentries[i].link);
}
else
{
error("unknown file type on %s", dentries[i].path);
entry_inode = 0;
}
*dentries[i].inode = entry_inode;
ret = inode_set_permissions(entry_inode, dentries[i].mode,
dentries[i].uid, dentries[i].gid, dentries[i].mtime);
if (ret)
{
error("failed to set permissions on %s\n", dentries[i].path);
}
free(dentries[i].path);
free(dentries[i].full_path);
free(dentries[i].link);
free((void *)dentries[i].filename);
}
// 释放分配的内存
if (dentries != NULL)
{
free(dentries);
}
return inode;
#endif
}
#endif
// ----------------------------- cxj add ------------------------------------
int readLines(char *data, int size)
{
int i;
int lines = 0;
for (i=0; i<size; i++)
{
if (data[i] == '\n')
{
lines++;
}
}
// 最后一行没有回车的情况下
if (data[i-1] != '\n')
{
lines++;
}
return lines;
}
static char pLineData[1024];
char* readLine(char *data, int size, int lineNum)
{
int i, j;
int line = 0;
memset(pLineData, 0x00, 1024);
if (lineNum == 0)
{
for (j=0; j<size; j++)
{
if (data[j] == '\n')
{
return pLineData;
}
pLineData[j] = data[j];
}
return pLineData;
}
// 找到lineNum的开始处
for (i=0; i<size; i++)
{
if (data[i] == '\n')
{
line++;
if (line == lineNum)
{
break;
}
}
}
for (j=i+1; j<size; j++)
{
if (data[j] == '\n')
{
return pLineData;
}
pLineData[j-i-1] = data[j];
}
return pLineData;
}
// ----------------------------- cxj end ------------------------------------
改写make_ext4fs工具成功,这样,我们是不是就实现了一种流程,将原始的system.img.ext4释放全部变成windows下的文件,然后通过make_ext4fs合成,又生成了system.img.ext4文件。 这样,我们就可以在中间步骤中,拷贝自己的文件到system.img.ext4释放出来的文件系统中,修改相应的linux_files_info.cxj就可以了,可以合成我们想要的system.img.ext4,实现了打包功能,中间不需要人为操作了。
最后实现文件拷贝等,我是用python2.7写的,就不多说了,直接上代码
# coding=utf-8
__author__ = 'snomy'
import os
import os.path
import shutil
# ----------------- 全局变量定义 ------------------
android_system_dir = r".\system"
merge_dir = r"..\files\system"
delList_file = r"..\files\delList.txt"
# ------------------- 函数定义 --------------------
# 函数: parseInfofile
# 解析 linux_files_info.cxj文件
def parseInfofile(fineName):
info = []
if not os.path.exists(fineName):
print "not exists", fineName
return info
hInfoFile = open(fineName, "r")
for line in hInfoFile:
info.append(line.strip().split(","))
hInfoFile.close()
return info
# 函数: writeInfo2file
# 回写属性文件
def writeInfo2file(filename, info):
hInfoFile = open(filename, "w")
for infor_item in info:
str_infor_item = "%s,%s,%s,%s,%s\n" % (infor_item[0], infor_item[1], infor_item[2], infor_item[3], infor_item[4])
hInfoFile.write(str_infor_item)
hInfoFile.close()
# 函数:delFilesItem
# 删除属性文件的相应的项
def delFilesItem(delfilename):
filepath, filename = os.path.split(delfilename)
filesinfo = parseInfofile(filepath + r"\linux_files_info.cxj")
for info_item in filesinfo:
if filename == info_item[0]:
filesinfo.remove(info_item)
break
# 回写
writeInfo2file(filepath + r"\linux_files_info.cxj", filesinfo)
# 函数: delFiles_from_list
# 解析要删除的列表,并且删除 linux_files_info.cxj 对应的项
def delFiles_from_list():
if not os.path.exists(delList_file):
print "not exists", delList_file
return
hDelListFile = open(delList_file, "r")
for line in hDelListFile:
if line.find("/system/") == -1:
continue
# 删除在android中对应的文件
delfilename = line[1:].strip()
if os.path.exists(delfilename):
if os.path.isfile(delfilename):
os.remove(delfilename)
print "del file", delfilename
delFilesItem(delfilename)
else:
shutil.rmtree(delfilename)
print "del dir", delfilename
delFilesItem(delfilename)
else:
print "not find", delfilename, ", del fail!"
hDelListFile.close()
# ------------------- main --------------------
# 1. 解析 delList.txt 文件,并删除文件以及对应的属性条目
delFiles_from_list()
# 2. 扫描 system 文件夹,拷贝文件并且添加对应的属性条目
for parent,dirnames,filenames in os.walk(merge_dir):
android_parent = parent[9:]
print android_parent+r"\linux_files_info.cxj"
# 解析 android_parent 目录下的文件属性
infofilename = ".\\" + android_parent + r"\linux_files_info.cxj"
filesinfo = parseInfofile(infofilename)
# 创建不存在的文件夹
for dirname in dirnames:
android_dir = android_parent + "\\" + dirname
if not os.path.exists(android_dir):
os.mkdir(android_dir)
print android_dir
dir_item = [dirname, "D", "0x41ed", "0x0000", "0x0000"]
filesinfo.append(dir_item)
# 拷贝文件
for filename in filenames:
android_filename = android_parent + "\\" + filename
merge_filename = parent + "\\" + filename
shutil.copyfile(merge_filename, android_filename)
print merge_filename
# 存在的条目不改写
fg_exist = 0;
for info_item in filesinfo:
if filename == info_item[0]:
fg_exist = 1
break
# 不存在的条目添加
if fg_exist == 0:
file_item = [filename, "F", "0x81ed", "0x0000", "0x0000"]
filesinfo.append(file_item)
# 将属性文件回写
writeInfo2file(android_parent+"\\linux_files_info.cxj", filesinfo)
# walk end
到此,本文写完了,鉴于第一次写博客,可能表达的不是很清楚,以后多多改进。
工具我已经上传到我的空间中,需要的朋友可以去下载,谢谢。
https://download.youkuaiyun.com/download/snomy/9537628
源码下载
https://download.youkuaiyun.com/download/snomy/9918891
这篇博客介绍了在Windows下开发Android打包工具的过程,因原有工具效率低且不支持批量化操作,作者通过在Cygwin下编译make_ext4fs源码解决了权限和链接文件问题,实现了自动打包功能。文章详细描述了从system.img.ext4解压、记录文件信息到改写make_ext4fs工具的整个流程。
570

被折叠的 条评论
为什么被折叠?



