From 0f29f54695e993b365fac2943b40fe2a7e47433b Mon Sep 17 00:00:00 2001 From: Fabien Sanglard Date: Thu, 22 Oct 2020 17:58:12 -0700 Subject: [PATCH] Refactor zipalign to allow unit tests Test: Self-tested Bug: NA Change-Id: I322b78c5e18082f7abf7427cdc62dbabcb18b4a0 --- tools/zipalign/Android.bp | 54 ++++++++-- tools/zipalign/ZipAlign.cpp | 118 +------------------- tools/zipalign/ZipAlignMain.cpp | 136 ++++++++++++++++++++++++ tools/zipalign/ZipEntry.cpp | 4 +- tools/zipalign/ZipFile.cpp | 7 +- tools/zipalign/include/ZipAlign.h | 49 +++++++++ tools/zipalign/tests/data/unaligned.zip | Bin 0 -> 464 bytes tools/zipalign/tests/src/align_test.cpp | 15 +++ 8 files changed, 254 insertions(+), 129 deletions(-) create mode 100644 tools/zipalign/ZipAlignMain.cpp create mode 100644 tools/zipalign/include/ZipAlign.h create mode 100644 tools/zipalign/tests/data/unaligned.zip create mode 100644 tools/zipalign/tests/src/align_test.cpp diff --git a/tools/zipalign/Android.bp b/tools/zipalign/Android.bp index 8e6196d291..3eb660d8ec 100644 --- a/tools/zipalign/Android.bp +++ b/tools/zipalign/Android.bp @@ -4,20 +4,31 @@ // Zip alignment tool // -cc_binary_host { - name: "zipalign", +cc_defaults { + name: "zipalign_defaults", + target: { + windows: { + host_ldlibs: ["-lpthread"], + enabled: true, + }, + }, +} +cc_library_host_static { + name: "libzipalign", srcs: [ "ZipAlign.cpp", "ZipEntry.cpp", "ZipFile.cpp", ], - + export_include_dirs: [ + "include", + ], cflags: ["-Wall", "-Werror"], // NOTE: Do not add any shared_libs dependencies because they will break the // static_sdk_tools target. - static_libs: [ + whole_static_libs: [ "libutils", "libcutils", "liblog", @@ -26,11 +37,32 @@ cc_binary_host { "libbase", "libzopfli", ], - - target: { - windows: { - host_ldlibs: ["-lpthread"], - enabled: true, - }, - }, + defaults: ["zipalign_defaults"], +} + +cc_binary_host { + name: "zipalign", + srcs: [ + "ZipAlignMain.cpp", + ], + cflags: ["-Wall", "-Werror"], + static_libs: [ + "libzipalign", + ], + defaults: ["zipalign_defaults"], +} + +cc_test_host { + name: "zipalign_tests", + srcs: [ + "tests/src/*_test.cpp", + ], + static_libs: [ + "libzipalign", + "libgmock", + ], + data: [ + "tests/data/unaligned.zip", + ], + defaults: ["zipalign_defaults"], } diff --git a/tools/zipalign/ZipAlign.cpp b/tools/zipalign/ZipAlign.cpp index eea1749970..1851ac562c 100644 --- a/tools/zipalign/ZipAlign.cpp +++ b/tools/zipalign/ZipAlign.cpp @@ -14,35 +14,13 @@ * limitations under the License. */ -/* - * Zip alignment tool - */ #include "ZipFile.h" #include #include #include -using namespace android; - -/* - * Show program usage. - */ -void usage(void) -{ - fprintf(stderr, "Zip alignment utility\n"); - fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n"); - fprintf(stderr, - "Usage: zipalign [-f] [-p] [-v] [-z] infile.zip outfile.zip\n" - " zipalign -c [-p] [-v] infile.zip\n\n" ); - fprintf(stderr, - " : alignment in bytes, e.g. '4' provides 32-bit alignment\n"); - fprintf(stderr, " -c: check alignment only (does not modify file)\n"); - fprintf(stderr, " -f: overwrite existing outfile.zip\n"); - fprintf(stderr, " -p: memory page alignment for stored shared object files\n"); - fprintf(stderr, " -v: verbose output\n"); - fprintf(stderr, " -z: recompress using Zopfli\n"); -} +namespace android { static int getAlignment(bool pageAlignSharedLibs, int defaultAlignment, ZipEntry* pEntry) { @@ -126,7 +104,7 @@ static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfl * Process a file. We open the input and output files, failing if the * output file exists and "force" wasn't specified. */ -static int process(const char* inFileName, const char* outFileName, +int process(const char* inFileName, const char* outFileName, int alignment, bool force, bool zopfli, bool pageAlignSharedLibs) { ZipFile zin, zout; @@ -169,7 +147,7 @@ static int process(const char* inFileName, const char* outFileName, /* * Verify the alignment of a zip archive. */ -static int verify(const char* fileName, int alignment, bool verbose, +int verify(const char* fileName, int alignment, bool verbose, bool pageAlignSharedLibs) { ZipFile zipFile; @@ -218,92 +196,4 @@ static int verify(const char* fileName, int alignment, bool verbose, return foundBad ? 1 : 0; } -/* - * Parse args. - */ -int main(int argc, char* const argv[]) -{ - bool wantUsage = false; - bool check = false; - bool force = false; - bool verbose = false; - bool zopfli = false; - bool pageAlignSharedLibs = false; - int result = 1; - int alignment; - char* endp; - - if (argc < 4) { - wantUsage = true; - goto bail; - } - - argc--; - argv++; - - while (argc && argv[0][0] == '-') { - const char* cp = argv[0] +1; - - while (*cp != '\0') { - switch (*cp) { - case 'c': - check = true; - break; - case 'f': - force = true; - break; - case 'v': - verbose = true; - break; - case 'z': - zopfli = true; - break; - case 'p': - pageAlignSharedLibs = true; - break; - default: - fprintf(stderr, "ERROR: unknown flag -%c\n", *cp); - wantUsage = true; - goto bail; - } - - cp++; - } - - argc--; - argv++; - } - - if (!((check && argc == 2) || (!check && argc == 3))) { - wantUsage = true; - goto bail; - } - - alignment = strtol(argv[0], &endp, 10); - if (*endp != '\0' || alignment <= 0) { - fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]); - wantUsage = true; - goto bail; - } - - if (check) { - /* check existing archive for correct alignment */ - result = verify(argv[1], alignment, verbose, pageAlignSharedLibs); - } else { - /* create the new archive */ - result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs); - - /* trust, but verify */ - if (result == 0) { - result = verify(argv[2], alignment, verbose, pageAlignSharedLibs); - } - } - -bail: - if (wantUsage) { - usage(); - result = 2; - } - - return result; -} +} // namespace android diff --git a/tools/zipalign/ZipAlignMain.cpp b/tools/zipalign/ZipAlignMain.cpp new file mode 100644 index 0000000000..49be916b38 --- /dev/null +++ b/tools/zipalign/ZipAlignMain.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Zip alignment tool + */ + +#include "ZipAlign.h" + +#include +#include + +using namespace android; + +/* + * Show program usage. + */ +void usage(void) +{ + fprintf(stderr, "Zip alignment utility\n"); + fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n"); + fprintf(stderr, + "Usage: zipalign [-f] [-p] [-v] [-z] infile.zip outfile.zip\n" + " zipalign -c [-p] [-v] infile.zip\n\n" ); + fprintf(stderr, + " : alignment in bytes, e.g. '4' provides 32-bit alignment\n"); + fprintf(stderr, " -c: check alignment only (does not modify file)\n"); + fprintf(stderr, " -f: overwrite existing outfile.zip\n"); + fprintf(stderr, " -p: memory page alignment for stored shared object files\n"); + fprintf(stderr, " -v: verbose output\n"); + fprintf(stderr, " -z: recompress using Zopfli\n"); +} + + +/* + * Parse args. + */ +int main(int argc, char* const argv[]) +{ + bool wantUsage = false; + bool check = false; + bool force = false; + bool verbose = false; + bool zopfli = false; + bool pageAlignSharedLibs = false; + int result = 1; + int alignment; + char* endp; + + if (argc < 4) { + wantUsage = true; + goto bail; + } + + argc--; + argv++; + + while (argc && argv[0][0] == '-') { + const char* cp = argv[0] +1; + + while (*cp != '\0') { + switch (*cp) { + case 'c': + check = true; + break; + case 'f': + force = true; + break; + case 'v': + verbose = true; + break; + case 'z': + zopfli = true; + break; + case 'p': + pageAlignSharedLibs = true; + break; + default: + fprintf(stderr, "ERROR: unknown flag -%c\n", *cp); + wantUsage = true; + goto bail; + } + + cp++; + } + + argc--; + argv++; + } + + if (!((check && argc == 2) || (!check && argc == 3))) { + wantUsage = true; + goto bail; + } + + alignment = strtol(argv[0], &endp, 10); + if (*endp != '\0' || alignment <= 0) { + fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]); + wantUsage = true; + goto bail; + } + + if (check) { + /* check existing archive for correct alignment */ + result = verify(argv[1], alignment, verbose, pageAlignSharedLibs); + } else { + /* create the new archive */ + result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs); + + /* trust, but verify */ + if (result == 0) { + result = verify(argv[2], alignment, verbose, pageAlignSharedLibs); + } + } + +bail: + if (wantUsage) { + usage(); + result = 2; + } + + return result; +} diff --git a/tools/zipalign/ZipEntry.cpp b/tools/zipalign/ZipEntry.cpp index 810d74a622..5233f0afdf 100644 --- a/tools/zipalign/ZipEntry.cpp +++ b/tools/zipalign/ZipEntry.cpp @@ -29,7 +29,7 @@ #include #include -using namespace android; +namespace android { /* * Initialize a new ZipEntry structure from a FILE* positioned at a @@ -696,3 +696,5 @@ void ZipEntry::CentralDirEntry::dump(void) const ALOGD(" comment: '%s'\n", mFileComment); } +} // namespace android + diff --git a/tools/zipalign/ZipFile.cpp b/tools/zipalign/ZipFile.cpp index 88505b7508..29d1bc6849 100644 --- a/tools/zipalign/ZipFile.cpp +++ b/tools/zipalign/ZipFile.cpp @@ -35,7 +35,7 @@ #include #include -using namespace android; +namespace android { /* * Some environments require the "b", some choke on it. @@ -134,7 +134,7 @@ status_t ZipFile::open(const char* zipFileName, int flags) /* * Return the Nth entry in the archive. */ -android::ZipEntry* ZipFile::getEntryByIndex(int idx) const +ZipEntry* ZipFile::getEntryByIndex(int idx) const { if (idx < 0 || idx >= (int) mEntries.size()) return NULL; @@ -145,7 +145,7 @@ android::ZipEntry* ZipFile::getEntryByIndex(int idx) const /* * Find an entry by name. */ -android::ZipEntry* ZipFile::getEntryByName(const char* fileName) const +ZipEntry* ZipFile::getEntryByName(const char* fileName) const { /* * Do a stupid linear string-compare search. @@ -1397,3 +1397,4 @@ void ZipFile::EndOfCentralDir::dump(void) const mCentralDirSize, mCentralDirOffset, mCommentLen); } +} // namespace android diff --git a/tools/zipalign/include/ZipAlign.h b/tools/zipalign/include/ZipAlign.h new file mode 100644 index 0000000000..ab3608682c --- /dev/null +++ b/tools/zipalign/include/ZipAlign.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ZIPALIGN_H +#define ZIPALIGN_H + +namespace android { + +/* + * Generate a new, aligned, zip "output" from an "input" zip. + * - alignTo: Alignment (in bytes) for uncompressed entries. + * - force : Overwrite output if it exists, fail otherwise. + * - zopfli : Recompress compressed entries with more efficient algorithm. + * Copy compressed entries as-is, and unaligned, otherwise. + * - pageAlignSharedLibs: Align .so files to 4096 and other files to + * alignTo, or all files to alignTo if false.. + * + * Returns 0 on success. + */ +int process(const char* input, const char* output, int alignTo, bool force, + bool zopfli, bool pageAlignSharedLibs); + +/* + * Verify the alignment of a zip archive. + * - alignTo: Alignment (in bytes) for uncompressed entries. + * - pageAlignSharedLibs: Align .so files to 4096 and other files to + * alignTo, or all files to alignTo if false.. + * + * Returns 0 on success. + */ +int verify(const char* fileName, int alignTo, bool verbose, + bool pageAlignSharedLibs); + +} // namespace android + +#endif // ZIPALIGN_H diff --git a/tools/zipalign/tests/data/unaligned.zip b/tools/zipalign/tests/data/unaligned.zip new file mode 100644 index 0000000000000000000000000000000000000000..d572b1a1da20123fae8856f1635567d18409d07a GIT binary patch literal 464 zcmWIWW@h1H00DssVS!)xVCF%+2{aF@7ZL8m^dz!*9We7CUIrS6)w`^0AdfHu;d>x`8pL4$ E0DLJ$asU7T literal 0 HcmV?d00001 diff --git a/tools/zipalign/tests/src/align_test.cpp b/tools/zipalign/tests/src/align_test.cpp new file mode 100644 index 0000000000..b8f2e15768 --- /dev/null +++ b/tools/zipalign/tests/src/align_test.cpp @@ -0,0 +1,15 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "ZipAlign.h" + +#include + +using namespace android; + +TEST(Align, Unaligned) { + const char* src = "tests/data/unaligned.zip"; + const char* dst = "tests/data/unaligned_out.zip"; + int result = process(src, dst, 4, true, false, 4096); + ASSERT_EQ(0, result); +}