windows下android打包工具

原创 2016年06月01日 13:19:27

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

到此,本文写完了,鉴于第一次写博客,可能表达的不是很清楚,以后多多改进。
工具我已经上传到我的空间中,需要的朋友可以去下载,谢谢。
http://download.csdn.net/detail/snomy/9537628
但是源码太大了,放不下,需要的朋友请留下邮箱地址,我发给你们



相关文章推荐

自制的android多渠道应用打包工具--RyApkTool(1)

关于多渠道的打包,网上流行的ant脚本或者perl制作的工具,我很笨,没搞起来。于是花了一个晚上,自制了多渠道打包工具,我采用了一种自认为更简单的方式来实现。觉得对你有用的话帮忙顶下,谢谢~~ 转载请...
  • rydiy
  • rydiy
  • 2012年08月23日 22:53
  • 10182

Android多种多渠道打包工具对比

多渠道打包只有在Android开发中才会有,iOS中直接放在AppStore。 而渠道也是Android开发中一个比较重要的环节,其主要作用就是方便统计、标记。根据不同的渠道加载不同的数据。 目前市...

Android程序自动化打包

11

Android--打包工具,100个渠道包只需要10秒钟

https://github.com/mcxiaoke/packer-ng-plugin 下一代Android渠道打包工具 最新版本 v1.0.5 - 2016.05.30 - ...

【翻译】Android Support Library Setup(三)

原文地址:http://developer.android.com/tools/support-library/setup.html 如何在你的开发项目中安装Android Support Libra...

Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-...
  • t12x3456
  • t12x3456
  • 2014年11月10日 00:05
  • 149167

解压和生成 system.img&data.img ( ext4格式)

另一篇文章讲述了如何解压和生成system.img, 那是针对yaffs2格式的文件系统镜像。 目前越来越多的Android手机放弃了nand, 更多采用了emmc为内部存储设备。 以em...

Windows软件安装包制作工具汇总

1 Windows Intaller 2 WinRAR 参考资料 [1]图解Windows Installer制作软件安装包 [2]用winrar制作EXE安装包...

QT5打包教程(QT自带Windep打包工具)

软件环境:Qt 5.7.0 操作系统:Win7 X86(32位)第一步:打开QT构建设置成Release状态运行,如下图所示:第二步:打开我们构建之后项目所在的位置,一般位置在C:\Qt\Mypro...

Android批量打包-如何一秒内打完几百个apk渠道包

在国内Android常用渠道可能多达几十个,如: 谷歌市场、腾讯应用宝、百度手机助手、91手机商城、360应用平台、豌豆荚、安卓市场、小米、魅族商店、oppo手机、联想乐商、中兴汇天地、华为、安智、...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:windows下android打包工具
举报原因:
原因补充:

(最多只允许输入30个字)