summaryrefslogtreecommitdiffstats
path: root/tools/aapt/Package.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt/Package.cpp')
-rw-r--r--tools/aapt/Package.cpp306
1 files changed, 245 insertions, 61 deletions
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index cb244ec..3daf644 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -37,8 +37,10 @@ static const char* kNoCompressExt[] = {
};
/* fwd decls, so I can write this downward */
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet);
bool processFile(Bundle* bundle, ZipFile* zip, String8 storageName, const sp<const AaptFile>& file);
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet, bool isOverlay);
+bool processOverlayFile(Bundle* bundle, ZipFile* zip,
+ String8 storageName, const sp<const AaptFile>& file);
bool okayToCompress(Bundle* bundle, const String8& pathName);
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
@@ -49,7 +51,81 @@ ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
* On success, "bundle->numPackages" will be the number of Zip packages
* we created.
*/
-status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>& outputSet)
+status_t writeAPK(Bundle* bundle, ZipFile* zip, const char* outputFileName,
+ const sp<OutputSet>& outputSet, bool isOverlay)
+{
+ status_t result = NO_ERROR;
+ int count;
+
+ if (bundle->getVerbose()) {
+ printf("Writing all files...\n");
+ }
+
+ count = processAssets(bundle, zip, outputSet, isOverlay);
+ if (count < 0) {
+ fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
+ outputFileName);
+ result = count;
+ goto bail;
+ }
+
+ if (bundle->getVerbose()) {
+ printf("Generated %d file%s\n", count, (count==1) ? "" : "s");
+ }
+
+ if (!isOverlay) {
+ count = processJarFiles(bundle, zip);
+ if (count < 0) {
+ fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
+ outputFileName);
+ result = count;
+ goto bail;
+ }
+
+ if (bundle->getVerbose())
+ printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s");
+ }
+
+ result = NO_ERROR;
+
+ /*
+ * Check for cruft. We set the "marked" flag on all entries we created
+ * or decided not to update. If the entry isn't already slated for
+ * deletion, remove it now.
+ */
+ {
+ if (bundle->getVerbose())
+ printf("Checking for deleted files\n");
+ int i, removed = 0;
+ for (i = 0; i < zip->getNumEntries(); i++) {
+ ZipEntry* entry = zip->getEntryByIndex(i);
+
+ if (!entry->getMarked() && entry->getDeleted()) {
+ if (bundle->getVerbose()) {
+ printf(" (removing crufty '%s')\n",
+ entry->getFileName());
+ }
+ zip->remove(entry);
+ removed++;
+ }
+ }
+ if (bundle->getVerbose() && removed > 0)
+ printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s");
+ }
+
+ /* tell Zip lib to process deletions and other pending changes */
+ result = zip->flush();
+ if (result != NO_ERROR) {
+ fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n");
+ goto bail;
+ }
+
+bail:
+ return result;
+}
+
+status_t writeAPK(Bundle* bundle, const String8& outputFile,
+ const sp<OutputSet>& outputSet, bool isOverlay)
{
#if BENCHMARK
fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
@@ -58,7 +134,6 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
status_t result = NO_ERROR;
ZipFile* zip = NULL;
- int count;
//bundle->setPackageCount(0);
@@ -105,64 +180,10 @@ status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>
goto bail;
}
- if (bundle->getVerbose()) {
- printf("Writing all files...\n");
- }
-
- count = processAssets(bundle, zip, outputSet);
- if (count < 0) {
- fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
- outputFile.string());
- result = count;
- goto bail;
- }
-
- if (bundle->getVerbose()) {
- printf("Generated %d file%s\n", count, (count==1) ? "" : "s");
- }
-
- count = processJarFiles(bundle, zip);
- if (count < 0) {
- fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
- outputFile.string());
- result = count;
- goto bail;
- }
-
- if (bundle->getVerbose())
- printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s");
-
- result = NO_ERROR;
+ result = writeAPK(bundle, zip, outputFile.string(), outputSet, isOverlay);
- /*
- * Check for cruft. We set the "marked" flag on all entries we created
- * or decided not to update. If the entry isn't already slated for
- * deletion, remove it now.
- */
- {
- if (bundle->getVerbose())
- printf("Checking for deleted files\n");
- int i, removed = 0;
- for (i = 0; i < zip->getNumEntries(); i++) {
- ZipEntry* entry = zip->getEntryByIndex(i);
-
- if (!entry->getMarked() && entry->getDeleted()) {
- if (bundle->getVerbose()) {
- printf(" (removing crufty '%s')\n",
- entry->getFileName());
- }
- zip->remove(entry);
- removed++;
- }
- }
- if (bundle->getVerbose() && removed > 0)
- printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s");
- }
-
- /* tell Zip lib to process deletions and other pending changes */
- result = zip->flush();
if (result != NO_ERROR) {
- fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n");
+ fprintf(stderr, "ERROR: Writing apk failed\n");
goto bail;
}
@@ -215,7 +236,98 @@ bail:
return result;
}
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet)
+/*
+ * The directory hierarchy looks like this:
+ * "outputDir" and "assetRoot" are existing directories.
+ *
+ * On success, "bundle->numPackages" will be the number of Zip packages
+ * we created.
+ */
+status_t writeAPK(Bundle* bundle, int fd, const sp<OutputSet>& outputSet, bool isOverlay)
+{
+ #if BENCHMARK
+ fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
+ long startAPKTime = clock();
+ #endif /* BENCHMARK */
+
+ status_t result = NO_ERROR;
+ ZipFile* zip = NULL;
+
+ status_t status;
+ zip = new ZipFile;
+ status = zip->openfd(fd, ZipFile::kOpenReadWrite);
+ if (status != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to open file as Zip file for writing\n");
+ result = PERMISSION_DENIED;
+ goto bail;
+ }
+
+ result = writeAPK(bundle, zip, "file_descriptor", outputSet, isOverlay);
+
+ if (result != NO_ERROR) {
+ fprintf(stderr, "ERROR: Writing apk failed\n");
+ goto bail;
+ }
+
+ /* anything here? */
+ if (zip->getNumEntries() == 0) {
+ if (bundle->getVerbose()) {
+ printf("Archive is empty -- removing\n");
+ }
+ delete zip; // close the file so we can remove it in Win32
+ zip = NULL;
+ close(fd);
+ }
+
+ assert(result == NO_ERROR);
+
+bail:
+ delete zip; // must close before remove in Win32
+ close(fd);
+ if (result != NO_ERROR) {
+ if (bundle->getVerbose()) {
+ printf("Removing archive due to earlier failures\n");
+ }
+ }
+
+ if (result == NO_ERROR && bundle->getVerbose())
+ printf("Done!\n");
+
+ #if BENCHMARK
+ fprintf(stdout, "BENCHMARK: End APK Bundling. Time Elapsed: %f ms \n",(clock() - startAPKTime)/1000.0);
+ #endif /* BENCHMARK */
+ return result;
+}
+
+status_t writeResFile(FILE* fp, const sp<AaptAssets>& /* assets */, sp<ApkBuilder>& builder) {
+ if (fp == NULL) {
+ fprintf(stderr, "Unable to open resFile for writing resTable\n");
+ return PERMISSION_DENIED;
+ }
+
+ sp<ApkSplit> split = builder->getBaseSplit();
+ const std::set<OutputEntry>& entries = split->getEntries();
+ std::set<OutputEntry>::const_iterator iter = entries.begin();
+ for (; iter != entries.end(); iter++) {
+ const OutputEntry& entry = *iter;
+
+ if (entry.getPath() == String8("resources.arsc")) {
+ sp<const AaptFile> resFile = entry.getFile();
+
+ int count = 0;
+ count = fwrite(resFile->getData(), 1, resFile->getSize(), fp);
+
+ if (count == 0) {
+ fprintf(stderr, "Nothing written to resFile\n");
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet,
+ bool isOverlay)
{
ssize_t count = 0;
const std::set<OutputEntry>& entries = outputSet->getEntries();
@@ -227,7 +339,9 @@ ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& o
} else {
String8 storagePath(entry.getPath());
storagePath.convertToResPath();
- if (!processFile(bundle, zip, storagePath, entry.getFile())) {
+ bool ret = isOverlay ? processOverlayFile(bundle, zip, storagePath, entry.getFile())
+ : processFile(bundle, zip, storagePath, entry.getFile());
+ if (!ret) {
return UNKNOWN_ERROR;
}
count++;
@@ -360,6 +474,76 @@ bool processFile(Bundle* bundle, ZipFile* zip,
}
/*
+ * Process a regular file, adding it to the archive if appropriate.
+ *
+ * This function is intended for use when creating a cached overlay package.
+ * Only xml and .9.png files are processed and added to the package.
+ *
+ * If we're in "update" mode, and the file already exists in the archive,
+ * delete the existing entry before adding the new one.
+ */
+bool processOverlayFile(Bundle* bundle, ZipFile* zip,
+ String8 storageName, const sp<const AaptFile>& file)
+{
+ const bool hasData = file->hasData();
+
+ storageName.convertToResPath();
+ ZipEntry* entry;
+ bool fromGzip = false;
+ status_t result;
+
+ if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) {
+ fromGzip = true;
+ storageName = storageName.getBasePath();
+ }
+
+ if (bundle->getUpdate()) {
+ entry = zip->getEntryByName(storageName.string());
+ if (entry != NULL) {
+ /* file already exists in archive; there can be only one */
+ if (entry->getMarked()) {
+ fprintf(stderr,
+ "ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n",
+ file->getPrintableSource().string());
+ return false;
+ }
+ zip->remove(entry);
+ }
+ }
+
+ if (hasData) {
+ const char* name = storageName.string();
+ if (endsWith(name, ".9.png") || endsWith(name, ".xml") || endsWith(name, ".arsc")) {
+ result = zip->add(file->getData(), file->getSize(), storageName.string(),
+ file->getCompressionMethod(), &entry);
+ if (result == NO_ERROR) {
+ if (bundle->getVerbose()) {
+ printf(" '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : "");
+ if (entry->getCompressionMethod() == ZipEntry::kCompressStored) {
+ printf(" (not compressed)\n");
+ } else {
+ printf(" (compressed %d%%)\n", calcPercent(entry->getUncompressedLen(),
+ entry->getCompressedLen()));
+ }
+ }
+ entry->setMarked(true);
+ } else {
+ if (result == ALREADY_EXISTS) {
+ fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n",
+ file->getPrintableSource().string());
+ } else {
+ fprintf(stderr, " Unable to add '%s': Zip add failed\n",
+ file->getPrintableSource().string());
+ }
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/*
* Determine whether or not we want to try to compress this file based
* on the file extension.
*/