Skip to content

Commit 04d1fa9

Browse files
committed
ApkNormalized support Android 15 with 16KB page size; recode zlib compressor to TZipCompressor_zlib for Zip;
1 parent 7907567 commit 04d1fa9

12 files changed

+329
-154
lines changed

HDiffPatch

src/apk_normalized.cpp

+44-21
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
//apk_normalized是为了diff/patch过程兼容apk的v2版签名而提供;
3030
//该过程对zip\jar\apk包进行规范化处理:
31-
// 输入包文件,重新按固定压缩算法生成对齐的新包文件(扩展字段、注释、jar的签名和apk文件的v1签名会被保留,apk的v2签名数据会被删除)
31+
// 输入包文件,重新按固定压缩算法生成对齐的新包文件(注释、jar的签名和apk文件的v1签名会被保留,扩展字段在未压缩.so文件页面对齐时可能会被修改,apk的v2签名数据会被删除)
3232
// 规范化后可以用Android签名工具对输出的apk文件执行v2签名,比如:
3333
// $apksigner sign --v1-signing-enabled true --v2-signing-enabled true --ks *.keystore --ks-pass pass:* --in normalized.apk --out release.apk
3434

@@ -49,7 +49,7 @@ static void printUsage(){
4949
" ApkNormalized normalized zip file:\n"
5050
" recompress all compressed files's data by zlib,\n"
5151
" align file data offset in zip file (compatible with AndroidSDK#zipalign),\n"
52-
" remove all data descriptor, reserve & normalized Extra field and Comment,\n"
52+
" remove all data descriptor, normalized Extra field & reserve Comment,\n"
5353
" compatible with jar sign(apk v1 sign), etc...\n"
5454
" if apk file only used apk v1 sign, don't re-sign normalizedApk file!\n"
5555
" if apk file used apk v2 sign or later, must re-sign normalizedApk file after ApkNormalized;\n"
@@ -60,14 +60,27 @@ static void printUsage(){
6060
" compress speed is very slow when patching.\n"
6161
" -as-alignSize\n"
6262
" set align size for uncompressed file in zip for optimize app run speed,\n"
63-
" 1 <= alignSize <= 4k, recommended 4,8, DEFAULT -as-8.\n"
64-
" NOTE: if -ap-1, must 4096%%alignSize==0;\n"
65-
" -ap-isPageAlignSoFile\n"
66-
" if found uncompressed .so file in the zip, need align it to 4k page?\n"
67-
" -ap-0 not page-align uncompressed .so files;\n"
68-
" -ap-1 DEFAULT, page-align uncompressed .so files.\n"
69-
" WARNING: if have uncompressed .so file & do page-align,\n"
70-
" it can't patch by old(version<v1.7.0) ZipPatch!\n"
63+
" 1 <= alignSize <= PageSize, recommended 4,8, DEFAULT -as-8.\n"
64+
" NOTE: if not -ap-0, must PageSize%%alignSize==0;\n"
65+
" -ap-pageAlignSoFile\n"
66+
" if found uncompressed .so file in the zip, need align it to page size?\n"
67+
" -ap-0 not page-align uncompressed .so files;\n"
68+
" -ap-4k (or -ap-1) DEFAULT, page-align uncompressed .so files to 4KB;\n"
69+
" compatible with all version of ZipPatch;\n"
70+
" WARNING: if have uncompressed .so file,\n"
71+
" it not compatible with Android 15 with 16KB page size;\n"
72+
" -ap-16k page-align uncompressed .so files to 16KB;\n"
73+
" compatible with Android 15 with 16KB page size;\n"
74+
" WARNING: if have uncompressed .so file,\n"
75+
" it can't patch by old(version<v1.8.0) ZipPatch!\n"
76+
" -ap-c16k page-align uncompressed .so files to 16KB;\n"
77+
" compatible with all version of ZipPatch,\n"
78+
" & compatible with Android 15 with 16KB page size;\n"
79+
" Note: normalized apk file size maybe larger than -ap-16k;\n"
80+
" -ap-64k page-align uncompressed .so files to 64KB;\n"
81+
" compatible with Android 15 with 16KB(or 64KB) page size;\n"
82+
" WARNING: if have uncompressed .so file,\n"
83+
" it can't patch by old(version<v1.8.0) ZipPatch!\n"
7184
" -nce-isNotCompressEmptyFile\n"
7285
" if found compressed empty file in the zip, need change it to not compressed?\n"
7386
" -nce-0 keep the original compress setting for empty file;\n"
@@ -112,7 +125,8 @@ int main(int argc,char* argv[]){
112125

113126
int normalized_cmd_line(int argc, const char * argv[]){
114127
hpatch_BOOL isNotCompressEmptyFile=_kNULL_VALUE;
115-
hpatch_BOOL isPageAlignSoFile=_kNULL_VALUE;
128+
size_t pageAlignSoFile=_kNULL_SIZE;
129+
hpatch_BOOL pageAlignSoFileCompatible=_kNULL_VALUE;
116130
hpatch_BOOL isOutputVersion=_kNULL_VALUE;
117131
size_t compressLevel = _kNULL_SIZE;
118132
size_t alignSize = _kNULL_SIZE;
@@ -137,7 +151,7 @@ int normalized_cmd_line(int argc, const char * argv[]){
137151
} break;
138152
case 'q':{
139153
_options_check((op[2]=='\0'),"-q");
140-
g_isPrintApkNormalizedFileName=false;
154+
g_isPrintNormalizingFileName=false;
141155
} break;
142156
case 'n':{
143157
if ((op[2]=='c')&&(op[3]=='e')&&(op[4]=='-')&&((op[5]=='0')||(op[5]=='1'))){
@@ -158,15 +172,22 @@ int normalized_cmd_line(int argc, const char * argv[]){
158172
}
159173
} break;
160174
case 'a':{
161-
if ((op[2]=='s')&&(op[3]=='-')){
175+
if ((op[2]=='p')&&(op[3]=='-')){
176+
_options_check(pageAlignSoFile==_kNULL_SIZE,"-ap-?");
177+
const char* pnum=op+4;
178+
pageAlignSoFileCompatible=(pnum[0]=='c')||(pnum[0]=='C');
179+
if (pageAlignSoFileCompatible) ++pnum;
180+
_options_check(kmg_to_size(pnum,strlen(pnum),&pageAlignSoFile),"-ap-?");
181+
#define _kMaxPageAlignSize (64*1024)
182+
#define _kDefaultPageAlignSize (4*1024)
183+
if (pageAlignSoFile==1) pageAlignSoFile=_kDefaultPageAlignSize;
184+
_options_check((pageAlignSoFile==0)||(pageAlignSoFile==16*1024)
185+
||(pageAlignSoFile==_kDefaultPageAlignSize)||(pageAlignSoFile==_kMaxPageAlignSize),"-ap-?");
186+
}else if ((op[2]=='s')&&(op[3]=='-')){
162187
_options_check(alignSize==_kNULL_SIZE,"-as-?")
163188
const char* pnum=op+4;
164189
_options_check(kmg_to_size(pnum,strlen(pnum),&alignSize),"-as-?");
165-
const size_t _kMaxAlignSize=4*1024;
166-
_options_check((1<=alignSize)&&(alignSize<=_kMaxAlignSize),"-as-?");
167-
}else if ((op[2]=='p')&&(op[3]=='-')&&((op[4]=='0')||(op[4]=='1'))){
168-
_options_check(isPageAlignSoFile==_kNULL_VALUE,"-ap-?");
169-
isPageAlignSoFile=(hpatch_BOOL)(op[4]=='1');
190+
_options_check((1<=alignSize)&&(alignSize<=_kMaxPageAlignSize),"-as-?");
170191
}else{
171192
_options_check(hpatch_FALSE,"-a?");
172193
}
@@ -178,8 +199,10 @@ int normalized_cmd_line(int argc, const char * argv[]){
178199
}
179200
if (isNotCompressEmptyFile==_kNULL_VALUE)
180201
isNotCompressEmptyFile=hpatch_TRUE;
181-
if (isPageAlignSoFile==_kNULL_VALUE)
182-
isPageAlignSoFile=hpatch_TRUE;
202+
if (pageAlignSoFile==_kNULL_SIZE)
203+
pageAlignSoFile=_kDefaultPageAlignSize;
204+
if (pageAlignSoFile==_kDefaultPageAlignSize)
205+
pageAlignSoFileCompatible=hpatch_TRUE;
183206
if (compressLevel==_kNULL_SIZE)
184207
compressLevel=kDefaultZlibCompressLevel;
185208
if (alignSize==_kNULL_SIZE)
@@ -203,7 +226,7 @@ int normalized_cmd_line(int argc, const char * argv[]){
203226
double time0=clock_s();
204227
int apkFilesRemoved=0;
205228
if (!ZipNormalized(srcApk,dstApk,(int)alignSize,(int)compressLevel,
206-
(bool)isNotCompressEmptyFile,(bool)isPageAlignSoFile,&apkFilesRemoved)){
229+
(bool)isNotCompressEmptyFile,pageAlignSoFile,pageAlignSoFileCompatible,&apkFilesRemoved)){
207230
printf("\nrun ApkNormalized ERROR!\n");
208231
return _kResult_NORMALIZED_ERROR;
209232
}

src/diff/DiffData.cpp

+21-15
Original file line numberDiff line numberDiff line change
@@ -247,22 +247,18 @@ static bool _isAligned(const std::vector<ZipFilePos_t>& offsetList,ZipFilePos_t
247247
}
248248
return true;
249249
}
250-
size_t getZipAlignSize_unsafe(UnZipper* zip){
251-
//note: 该函数对没有Normalized的zip允许获取AlignSize失败;
252-
int fileCount=UnZipper_fileCount(zip);
253-
//ZipFilePos_t maxSkipLen=0;
254-
ZipFilePos_t minOffset=1024*4; //set search max AlignSize
250+
251+
size_t getBaseAlignSize_unsafe(UnZipper* self){
252+
int fCount=UnZipper_fileCount(self);
253+
ZipFilePos_t minOffset=1024*64; //set search max AlignSize
255254
std::vector<ZipFilePos_t> offsetList;
256-
for (int i=0; i<fileCount; ++i){
257-
bool isNeedAlign= (!UnZipper_file_isCompressed(zip,i));
258-
if (!isNeedAlign)
259-
continue;
260-
ZipFilePos_t entryOffset=UnZipper_fileEntry_offset_unsafe(zip,i);
261-
ZipFilePos_t lastEndPos=(i<=0)?0:UnZipper_fileEntry_endOffset(zip,i-1); //unsafe last可能并没有按顺序放置?
262-
if (entryOffset<lastEndPos) return 0; //顺序有误;
263-
ZipFilePos_t skipLen=entryOffset-lastEndPos;
264-
//if (skipLen>maxSkipLen) maxSkipLen=skipLen;
265-
ZipFilePos_t offset=UnZipper_fileData_offset(zip,i);
255+
ZipFilePos_t lastDataPos=0;
256+
for (int i=0; i<fCount; ++i) {
257+
if (UnZipper_file_isCompressed(self,i)) continue;
258+
const ZipFilePos_t dataPos=UnZipper_fileData_offset(self,i);
259+
if (dataPos<=lastDataPos) return 0; // not normalized
260+
ZipFilePos_t offset=dataPos-lastDataPos;
261+
lastDataPos=dataPos;
266262
if (offset<minOffset) minOffset=offset;
267263
offsetList.push_back(offset);
268264
}
@@ -433,7 +429,16 @@ static bool _serializeZipDiffData(std::vector<TByte>& out_data,const ZipDiffData
433429
pushBack(out_data,(const TByte*)compressType,(const TByte*)compressType+compressTypeLen+1); //'\0'
434430
}
435431
//head info
432+
//add an empty normalizeSoPageAlign tag prefix into packed PatchModel, starting with v1.8.0
433+
#define kSoSmallPageAlignSize (1024*4)
434+
size_t tagPageAlign=data->normalizeSoPageAlign;
435+
tagPageAlign=(tagPageAlign==0)?kSoSmallPageAlignSize:((tagPageAlign==kSoSmallPageAlignSize)?0:tagPageAlign);
436+
while (tagPageAlign>=kSoSmallPageAlignSize){
437+
pushBack(out_data,&kPackedEmptyPrefix,1);
438+
tagPageAlign/=4;
439+
}
436440
packUInt(out_data,data->PatchModel);
441+
437442
packUInt(out_data,data->newZipFileCount);
438443
packUInt(out_data,data->newZipIsDataNormalized);
439444
packUInt(out_data,data->newZipAlignSize);
@@ -504,5 +509,6 @@ bool serializeZipDiffData(std::vector<TByte>& out_data, UnZipper* newZip,UnZippe
504509
data.oldRefList=(uint32_t*)oldRefList.data();
505510
data.oldRefCount=oldRefList.size();
506511
data.oldCrc=OldStream_getOldCrc(oldZip,oldRefList.data(),oldRefList.size());
512+
data.normalizeSoPageAlign=UnZipper_getHugePageAlign(newZip,newZipAlignSize);
507513
return _serializeZipDiffData(out_data,&data,hdiffzData,compressPlugin,newZip);
508514
}

src/diff/DiffData.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ bool getCompressedIsNormalized(UnZipper* zip,int* out_zlibCompressLevel,
6666
int* out_zlibCompressMemLevel,bool testReCompressedByApkV2Sign=false); //只检查压缩数据是否标准化;
6767
bool getCompressedIsNormalizedBy(UnZipper* zip,int zlibCompressLevel,
6868
int zlibCompressMemLevel,bool testReCompressedByApkV2Sign=false); //只检查压缩数据是否标准化;
69-
size_t getZipAlignSize_unsafe(UnZipper* zip); //只检查未压缩数据的起始位置对齐值,返回对齐值,0表示错误,否则至少对齐到1;
69+
size_t getBaseAlignSize_unsafe(UnZipper* self);//只检查未压缩数据的起始位置对齐值,返回对齐值,0表示错误,否则至少对齐到1;
7070

7171
static inline std::string zipFile_name(const UnZipper* self,int fileIndex){
7272
int nameLen=UnZipper_file_nameLen(self,fileIndex);

src/diff/Differ.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,21 @@ bool ZipDiffWithStream(const hpatch_TStreamInput* oldZipStream,const hpatch_TStr
140140
UnZipper_init(&oldZip);
141141
UnZipper_init(&newZip);
142142
check(UnZipper_openStream(&oldZip,oldZipStream));
143-
check(UnZipper_openStream(&newZip,newZipStream));
143+
check(UnZipper_openStream(&newZip,newZipStream,false,false,true));
144144

145-
newZipAlignSize=getZipAlignSize_unsafe(&newZip);
145+
newZipAlignSize=getBaseAlignSize_unsafe(&newZip);
146146
if (UnZipper_isHaveApkV2Sign(&newZip)){//precondition (+checkZipIsSame() to complete)
147147
newZip._isDataNormalized=(newZipAlignSize>0)&&(newZip._dataDescriptorCount==0);
148148
}else{
149149
newZip._isDataNormalized=true;
150150
}
151-
if (newZip._isDataNormalized && UnZipper_isHaveApkV2Sign(&newZip)){
151+
//if (newZip._isDataNormalized && UnZipper_isHaveApkV2Sign(&newZip)){
152152
newCompressedDataIsNormalized=getCompressedIsNormalized(&newZip,&newZipNormalized_compressLevel,
153153
&newZipNormalized_compressMemLevel);
154-
}else{
155-
newCompressedDataIsNormalized=getCompressedIsNormalizedBy(&newZip,newZipNormalized_compressLevel,
156-
newZipNormalized_compressMemLevel);
157-
}
154+
//}else{
155+
// newCompressedDataIsNormalized=getCompressedIsNormalizedBy(&newZip,newZipNormalized_compressLevel,
156+
// newZipNormalized_compressMemLevel);
157+
//}
158158
newZip._isDataNormalized&=newCompressedDataIsNormalized;
159159
if (UnZipper_isHaveApkV2Sign(&newZip)){
160160
if (!getCompressedIsNormalized(&newZip,&newZip_otherCompressLevel,&newZip_otherCompressMemLevel,true)){

src/normalized/normalized.cpp

+5-7
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#ifdef __cplusplus
3535
extern "C" {
3636
#endif
37-
bool g_isPrintApkNormalizedFileName=true;
37+
bool g_isPrintNormalizingFileName=true;
3838
#ifdef __cplusplus
3939
}
4040
#endif
@@ -130,7 +130,7 @@ inline static bool isCompressedEmptyFile(const UnZipper* unzipper,int fileIndex)
130130
}
131131

132132
bool ZipNormalized(const char* srcApk,const char* dstApk,int ZipAlignSize,int compressLevel,
133-
bool isNotCompressEmptyFile,bool isPageAlignSoFile,int* out_apkFilesRemoved){
133+
bool isNotCompressEmptyFile,size_t pageAlignSoFile,bool pageAlignCompatible,int* out_apkFilesRemoved){
134134
bool result=true;
135135
bool _isInClear=false;
136136
int fileCount=0;
@@ -147,8 +147,8 @@ bool ZipNormalized(const char* srcApk,const char* dstApk,int ZipAlignSize,int co
147147

148148
check(UnZipper_openFile(&unzipper,srcApk));
149149
fileCount=UnZipper_fileCount(&unzipper);
150-
check(Zipper_openFile(&zipper,dstApk,fileCount,ZipAlignSize,isPageAlignSoFile,
151-
compressLevel,kDefaultZlibCompressMemLevel));
150+
check(Zipper_openFile(&zipper,dstApk,fileCount,ZipAlignSize,compressLevel,kDefaultZlibCompressMemLevel,
151+
pageAlignSoFile,pageAlignCompatible,kPageAlign_inNormalize));
152152
isHaveApkV2Sign=UnZipper_isHaveApkV2Sign(&unzipper);
153153
isHaveApkV3Sign=UnZipper_isHaveApkV3Sign(&unzipper);
154154
{
@@ -184,7 +184,7 @@ bool ZipNormalized(const char* srcApk,const char* dstApk,int ZipAlignSize,int co
184184
for (int i=0; i<(int)fileIndexs.size(); ++i) {
185185
int fileIndex=fileIndexs[i];
186186
std::string fileName=zipFile_name(&unzipper,fileIndex);
187-
if (g_isPrintApkNormalizedFileName)
187+
if (g_isPrintNormalizingFileName)
188188
hpatch_printPath_utf8(("\""+fileName+"\"\n").c_str());
189189
if (compressLevel==0){
190190
check(Zipper_file_append_set_new_isCompress(&zipper,false));
@@ -233,8 +233,6 @@ bool ZipNormalized(const char* srcApk,const char* dstApk,int ZipAlignSize,int co
233233
:"WARNING: src removed ApkV2Sign data (%d Byte, need re-sign)\n",
234234
(int)UnZipper_ApkV2SignSize(&unzipper));
235235
}
236-
if (zipper._normalizeSoPageAlignCount>0)
237-
printf("WARNING: found uncompressed .so file & do page-align, it can't patch by old(version<v1.7.0) ZipPatch!\n");
238236
printf("src fileCount: %d (filseSize: %" PRIu64 ")\n"
239237
"out fileCount: %d (filseSize: %" PRIu64 ")\n\n",
240238
fileCount,unzipper._fileStream.base.streamSize,

src/normalized/normalized.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@
2727
*/
2828
#ifndef ZipNormalized_normalized_h
2929
#define ZipNormalized_normalized_h
30+
#include <string.h> //size_t
3031

3132
//规范化zip包;
3233
bool ZipNormalized(const char* srcApk,const char* dstApk,int ZipAlignSize,int compressLevel,
33-
bool isNotCompressEmptyFile=true,bool isPageAlignSoFile=true,int* out_apkFilesRemoved=0);
34+
bool isNotCompressEmptyFile,size_t pageAlignSoFile,bool pageAlignCompatible,int* out_apkFilesRemoved=0);
3435
#ifdef __cplusplus
3536
extern "C" {
3637
#endif
37-
extern bool g_isPrintApkNormalizedFileName; //default true
38+
extern bool g_isPrintNormalizingFileName; //default true
3839
#ifdef __cplusplus
3940
}
4041
#endif

src/patch/Patcher.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ TPatchResult VirtualZipPatchWithStream(const hpatch_TStreamInput* oldZipStream,c
109109
check(ZipDiffData_openRead(&zipDiffData,zipDiffStream,decompressPlugin),PATCH_ZIPDIFFINFO_ERROR);
110110
isSD=(zipDiffData.PatchModel==1);
111111
check(UnZipper_openStream(&oldZip,oldZipStream,zipDiffData.oldZipIsDataNormalized!=0,
112-
zipDiffData.oldIsFileDataOffsetMatch!=0),PATCH_OPENREAD_ERROR);
112+
zipDiffData.oldIsFileDataOffsetMatch!=0),PATCH_OPENREAD_ERROR);
113113
check(zipDiffData.oldZipCESize==UnZipper_CESize(&oldZip),PATCH_OLDDATA_ERROR);
114114
#if (_IS_NEED_VIRTUAL_ZIP)
115115
if (virtual_in)
@@ -153,9 +153,9 @@ TPatchResult VirtualZipPatchWithStream(const hpatch_TStreamInput* oldZipStream,c
153153
0,0,input_ref _VIRTUAL_IN(virtual_in)), PATCH_OLDSTREAM_ERROR);
154154
check(oldStream.stream->streamSize==diffInfo.oldDataSize,PATCH_OLDDATA_ERROR);
155155

156-
check(Zipper_openStream(&out_newZip,outNewZipStream,(int)zipDiffData.newZipFileCount,
157-
(int)zipDiffData.newZipAlignSize,false,(int)zipDiffData.newCompressLevel,
158-
(int)zipDiffData.newCompressMemLevel),PATCH_OPENWRITE_ERROR);
156+
check(Zipper_openStream(&out_newZip,outNewZipStream,(int)zipDiffData.newZipFileCount,(int)zipDiffData.newZipAlignSize,
157+
(int)zipDiffData.newCompressLevel,(int)zipDiffData.newCompressMemLevel,
158+
zipDiffData.normalizeSoPageAlign,zipDiffData.pageAlignCompatible,kPageAlign_inPatch),PATCH_OPENWRITE_ERROR);
159159
check(NewStream_open(&newStream,&out_newZip,&oldZip, (size_t)diffInfo.newDataSize,
160160
zipDiffData.newZipIsDataNormalized!=0,
161161
zipDiffData.newZipCESize,zipDiffData.extraEdit,

src/patch/ZipDiffData.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ bool ZipDiffData_openRead(ZipDiffData* self,const hpatch_TStreamInput* diffData,
108108
check(diffData->read(diffData,headInoPos,buf,buf+readLen));
109109
//unpack head info
110110
const TByte* curBuf=buf;
111+
#define kSoSmallPageAlignSize (1024*4)
112+
self->normalizeSoPageAlign=kSoSmallPageAlignSize/4;
113+
while ((curBuf<buf+readLen)&&(kPackedEmptyPrefix==(*curBuf))){//test have normalizeSoPageAlign tag? starting with v1.8.0
114+
self->normalizeSoPageAlign*=4;
115+
++curBuf;
116+
}// else old version diffData, not saved normalizeSoPageAlign tag
117+
if (self->normalizeSoPageAlign==kSoSmallPageAlignSize) self->normalizeSoPageAlign=0;
118+
self->pageAlignCompatible=(self->normalizeSoPageAlign==(kSoSmallPageAlignSize/4));
119+
if (self->pageAlignCompatible) self->normalizeSoPageAlign=kSoSmallPageAlignSize;
111120
checkUnpackSize(&curBuf,buf+readLen,&self->PatchModel,size_t);
112121
check(self->PatchModel<=1);//now must 0 or 1
113122
checkUnpackSize(&curBuf,buf+readLen,&self->newZipFileCount,size_t);

0 commit comments

Comments
 (0)