From 7e486e3393be690b0541d30339e50177fa07e64b Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 13 May 2009 15:06:13 -0700 Subject: [PATCH] Implement compatibility support for WRITE_SDCARD permission. Now old applications will automatically be granted it. Also renamed it from SDCARD_WRITE to WRITE_SDCARD to be consistent with our other permissions, and re-arranged how we do targetSdkVersion to actually be usuable for this kind of stuff. Note that right now this results in basically all apps being given the WRITE_SDCARD permission, because their targetSdkVersion is not set. I will be dealing with that in a future change. --- Bundle.h | 17 +++++++++++ Main.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++--- Resource.cpp | 62 +++++++++++++++++++++++++++++++++++++++- ResourceTable.cpp | 12 +++++++- ResourceTable.h | 7 +++++ XMLNode.cpp | 61 +++++++++++++++++++++++++++++++++++++++ XMLNode.h | 10 +++++++ 7 files changed, 235 insertions(+), 6 deletions(-) diff --git a/Bundle.h b/Bundle.h index 2d8471b..216ece4 100644 --- a/Bundle.h +++ b/Bundle.h @@ -99,6 +99,17 @@ public: const android::Vector& getNoCompressExtensions() const { return mNoCompressExtensions; } void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); } + const char* getMinSdkVersion() const { return mMinSdkVersion; } + void setMinSdkVersion(const char* val) { mMinSdkVersion = val; } + const char* getTargetSdkVersion() const { return mTargetSdkVersion; } + void setTargetSdkVersion(const char* val) { mTargetSdkVersion = val; } + const char* getMaxSdkVersion() const { return mMaxSdkVersion; } + void setMaxSdkVersion(const char* val) { mMaxSdkVersion = val; } + const char* getVersionCode() const { return mVersionCode; } + void setVersionCode(const char* val) { mVersionCode = val; } + const char* getVersionName() const { return mVersionName; } + void setVersionName(const char* val) { mVersionName = val; } + /* * Set and get the file specification. * @@ -151,6 +162,12 @@ private: android::Vector mNoCompressExtensions; android::Vector mResourceSourceDirs; + const char* mMinSdkVersion; + const char* mTargetSdkVersion; + const char* mMaxSdkVersion; + const char* mVersionCode; + const char* mVersionName; + /* file specification */ int mArgc; char* const* mArgv; diff --git a/Main.cpp b/Main.cpp index 71b1a3c..8bf2b07 100644 --- a/Main.cpp +++ b/Main.cpp @@ -54,9 +54,10 @@ void usage(void) " xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName); fprintf(stderr, " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n" - " [-0 extension [-0 extension ...]] \\\n" - " [-g tolerance] \\\n" - " [-j jarfile] \\\n" + " [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n" + " [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n" + " [--max-sdk-version VAL] [--app-version VAL] \\\n" + " [--app-version-name TEXT] \\\n" " [-I base-package [-I base-package ...]] \\\n" " [-A asset-source-dir] [-P public-definitions-file] \\\n" " [-S resource-sources [-S resource-sources ...]] " @@ -115,7 +116,17 @@ void usage(void) " and the first match found (left to right) will take precedence." " -0 specifies an additional extension for which such files will not\n" " be stored compressed in the .apk. An empty string means to not\n" - " compress any files at all.\n"); + " compress any files at all.\n" + " --min-sdk-version\n" + " inserts android:minSdkVersion in to manifest.\n" + " --target-sdk-version\n" + " inserts android:targetSdkVersion in to manifest.\n" + " --max-sdk-version\n" + " inserts android:maxSdkVersion in to manifest.\n" + " --version-code\n" + " inserts android:versionCode in to manifest.\n" + " --version-name\n" + " inserts android:versionName in to manifest.\n"); } /* @@ -339,6 +350,59 @@ int main(int argc, char* const argv[]) bundle.setCompressionMethod(ZipEntry::kCompressStored); } break; + case '-': + if (strcmp(cp, "-min-sdk-version") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n"); + wantUsage = true; + goto bail; + } + bundle.setMinSdkVersion(argv[0]); + } else if (strcmp(cp, "-target-sdk-version") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n"); + wantUsage = true; + goto bail; + } + bundle.setTargetSdkVersion(argv[0]); + } else if (strcmp(cp, "-max-sdk-version") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n"); + wantUsage = true; + goto bail; + } + bundle.setMaxSdkVersion(argv[0]); + } else if (strcmp(cp, "-version-code") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n"); + wantUsage = true; + goto bail; + } + bundle.setVersionCode(argv[0]); + } else if (strcmp(cp, "-version-name") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n"); + wantUsage = true; + goto bail; + } + bundle.setVersionName(argv[0]); + } else { + fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp); + wantUsage = true; + goto bail; + } + cp += strlen(cp) - 1; + break; default: fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp); wantUsage = true; diff --git a/Resource.cpp b/Resource.cpp index b2bd9ff..49ccf71 100644 --- a/Resource.cpp +++ b/Resource.cpp @@ -495,6 +495,58 @@ static void applyFileOverlay(const sp& assets, return; } +void addTagAttribute(const sp& node, const char* ns8, + const char* attr8, const char* value) +{ + if (value == NULL) { + return; + } + + const String16 ns(ns8); + const String16 attr(attr8); + + if (node->getAttribute(ns, attr) != NULL) { + fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n", + String8(attr).string(), String8(ns).string()); + return; + } + + node->addAttribute(ns, attr, String16(value)); +} + +status_t massageManifest(Bundle* bundle, sp root) +{ + root = root->searchElement(String16(), String16("manifest")); + if (root == NULL) { + fprintf(stderr, "No tag.\n"); + return UNKNOWN_ERROR; + } + + addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode", + bundle->getVersionCode()); + addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName", + bundle->getVersionName()); + + if (bundle->getMinSdkVersion() != NULL + || bundle->getTargetSdkVersion() != NULL + || bundle->getMaxSdkVersion() != NULL) { + sp vers = root->getChildElement(String16(), String16("uses-sdk")); + if (vers == NULL) { + vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk")); + root->insertChildAt(vers, 0); + } + + addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion", + bundle->getMinSdkVersion()); + addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion", + bundle->getTargetSdkVersion()); + addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion", + bundle->getMaxSdkVersion()); + } + + return NO_ERROR; +} + #define ASSIGN_IT(n) \ do { \ ssize_t index = resources->indexOfKey(String8(#n)); \ @@ -1013,7 +1065,15 @@ status_t buildResources(Bundle* bundle, const sp& assets) // Generate final compiled manifest file. manifestFile->clearData(); - err = compileXmlFile(assets, manifestFile, &table); + sp manifestTree = XMLNode::parse(manifestFile); + if (manifestTree == NULL) { + return UNKNOWN_ERROR; + } + err = massageManifest(bundle, manifestTree); + if (err < NO_ERROR) { + return err; + } + err = compileXmlFile(assets, manifestTree, manifestFile, &table); if (err < NO_ERROR) { return err; } diff --git a/ResourceTable.cpp b/ResourceTable.cpp index ef11a83..25ab147 100644 --- a/ResourceTable.cpp +++ b/ResourceTable.cpp @@ -23,6 +23,16 @@ status_t compileXmlFile(const sp& assets, if (root == NULL) { return UNKNOWN_ERROR; } + + return compileXmlFile(assets, root, target, table, options); +} + +status_t compileXmlFile(const sp& assets, + const sp& root, + const sp& target, + ResourceTable* table, + int options) +{ if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) { root->removeWhitespace(true, NULL); } else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) { @@ -1307,7 +1317,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp& assets, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); +status_t compileXmlFile(const sp& assets, + const sp& xmlTree, + const sp& target, + ResourceTable* table, + int options = XML_COMPILE_STANDARD_RESOURCE); + status_t compileResourceFile(Bundle* bundle, const sp& assets, const sp& in, diff --git a/XMLNode.cpp b/XMLNode.cpp index d476567..2a85bc7 100644 --- a/XMLNode.cpp +++ b/XMLNode.cpp @@ -524,12 +524,30 @@ const Vector >& XMLNode::getChildren() const return mChildren; } +const String8& XMLNode::getFilename() const +{ + return mFilename; +} + const Vector& XMLNode::getAttributes() const { return mAttributes; } +const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns, + const String16& name) const +{ + for (size_t i=0; i XMLNode::searchElement(const String16& tagNamespace, const String16& tagName) +{ + if (getType() == XMLNode::TYPE_ELEMENT + && mNamespaceUri == tagNamespace + && mElementName == tagName) { + return this; + } + + for (size_t i=0; i found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName); + if (found != NULL) { + return found; + } + } + + return NULL; +} + +sp XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName) +{ + for (size_t i=0; i child = mChildren.itemAt(i); + if (child->getType() == XMLNode::TYPE_ELEMENT + && child->mNamespaceUri == tagNamespace + && child->mElementName == tagName) { + return child; + } + } + + return NULL; +} + status_t XMLNode::addChild(const sp& child) { if (getType() == TYPE_CDATA) { @@ -561,6 +611,17 @@ status_t XMLNode::addChild(const sp& child) return NO_ERROR; } +status_t XMLNode::insertChildAt(const sp& child, size_t index) +{ + if (getType() == TYPE_CDATA) { + SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node."); + return UNKNOWN_ERROR; + } + //printf("Adding child %p to parent %p\n", child.get(), this); + mChildren.insertAt(child, index); + return NO_ERROR; +} + status_t XMLNode::addAttribute(const String16& ns, const String16& name, const String16& value) { diff --git a/XMLNode.h b/XMLNode.h index 86548a2..a9bea43 100644 --- a/XMLNode.h +++ b/XMLNode.h @@ -68,6 +68,8 @@ public: const String16& getElementName() const; const Vector >& getChildren() const; + const String8& getFilename() const; + struct attribute_entry { attribute_entry() : index(~(uint32_t)0), nameResId(0) { @@ -91,6 +93,8 @@ public: const Vector& getAttributes() const; + const attribute_entry* getAttribute(const String16& ns, const String16& name) const; + const String16& getCData() const; const String16& getComment() const; @@ -98,8 +102,14 @@ public: int32_t getStartLineNumber() const; int32_t getEndLineNumber() const; + sp searchElement(const String16& tagNamespace, const String16& tagName); + + sp getChildElement(const String16& tagNamespace, const String16& tagName); + status_t addChild(const sp& child); + status_t insertChildAt(const sp& child, size_t index); + status_t addAttribute(const String16& ns, const String16& name, const String16& value); -- 2.45.2