From ad2d07d2d98a46babb2a9472413fe9ce5080ca76 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Wed, 27 Aug 2014 16:21:08 -0700 Subject: Stamp platform version code into app Apks The versionCode of theframework resources that an app is built against gets stamped inside an app's AndroidManifest.xml in the tag as "platformBuildVersionCode" and "platformBuildVersionName" attributes. Bug:17207635 Change-Id: Id573c3dffcbca38eec9c0eb3e89f4a547e3361d3 --- include/androidfw/ResourceTypes.h | 2 +- libs/androidfw/ResourceTypes.cpp | 2 +- tools/aapt/AaptAssets.cpp | 5 + tools/aapt/AaptAssets.h | 1 + tools/aapt/AaptXml.cpp | 184 +++++++++++++++++++ tools/aapt/AaptXml.h | 123 +++++++++++++ tools/aapt/Android.mk | 1 + tools/aapt/Bundle.h | 6 + tools/aapt/Command.cpp | 371 +++++++++++++------------------------- tools/aapt/Main.h | 3 - tools/aapt/Resource.cpp | 135 +++++++++++++- 11 files changed, 580 insertions(+), 253 deletions(-) create mode 100644 tools/aapt/AaptXml.cpp create mode 100644 tools/aapt/AaptXml.h diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index 11568d280c24..c65efe4d4900 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1557,7 +1557,7 @@ public: }; const char16_t* valueToString(const Res_value* value, size_t stringBlock, char16_t tmpBuffer[TMP_BUFFER_SIZE], - size_t* outLen); + size_t* outLen) const; struct bag_entry { ssize_t stringBlock; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 3f014ef5de1e..90879dd9b677 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -3728,7 +3728,7 @@ ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, const char16_t* ResTable::valueToString( const Res_value* value, size_t stringBlock, - char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen) + char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen) const { if (!value) { return NULL; diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index b44e2d139a95..117fc2435076 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -1594,6 +1594,11 @@ const ResTable& AaptAssets::getIncludedResources() const return mIncludedAssets.getResources(false); } +AssetManager& AaptAssets::getAssetManager() +{ + return mIncludedAssets; +} + void AaptAssets::print(const String8& prefix) const { String8 innerPrefix(prefix); diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 0c2576a954b1..3fc9f815c1a9 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -561,6 +561,7 @@ public: status_t buildIncludedResources(Bundle* bundle); status_t addIncludedResources(const sp& file); const ResTable& getIncludedResources() const; + AssetManager& getAssetManager(); void print(const String8& prefix) const; diff --git a/tools/aapt/AaptXml.cpp b/tools/aapt/AaptXml.cpp new file mode 100644 index 000000000000..708e4054e63a --- /dev/null +++ b/tools/aapt/AaptXml.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014 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. + */ + +#include +#include + +#include "AaptXml.h" + +using namespace android; + +namespace AaptXml { + +static String8 getStringAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex, + String8* outError) { + Res_value value; + if (tree.getAttributeValue(attrIndex, &value) < 0) { + if (outError != NULL) { + *outError = "could not find attribute at index"; + } + return String8(); + } + + if (value.dataType != Res_value::TYPE_STRING) { + if (outError != NULL) { + *outError = "attribute is not a string value"; + } + return String8(); + } + + size_t len; + const uint16_t* str = tree.getAttributeStringValue(attrIndex, &len); + return str ? String8(str, len) : String8(); +} + +static int32_t getIntegerAttributeAtIndex(const ResXMLTree& tree, ssize_t attrIndex, + int32_t defValue, String8* outError) { + Res_value value; + if (tree.getAttributeValue(attrIndex, &value) < 0) { + if (outError != NULL) { + *outError = "could not find attribute at index"; + } + return defValue; + } + + if (value.dataType < Res_value::TYPE_FIRST_INT + || value.dataType > Res_value::TYPE_LAST_INT) { + if (outError != NULL) { + *outError = "attribute is not an integer value"; + } + return defValue; + } + return value.data; +} + + +ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) { + size_t attrCount = tree.getAttributeCount(); + for (size_t i = 0; i < attrCount; i++) { + if (tree.getAttributeNameResID(i) == attrRes) { + return (ssize_t)i; + } + } + return -1; +} + +String8 getAttribute(const ResXMLTree& tree, const char* ns, + const char* attr, String8* outError) { + ssize_t idx = tree.indexOfAttribute(ns, attr); + if (idx < 0) { + return String8(); + } + return getStringAttributeAtIndex(tree, idx, outError); +} + +String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) { + ssize_t idx = indexOfAttribute(tree, attrRes); + if (idx < 0) { + return String8(); + } + return getStringAttributeAtIndex(tree, idx, outError); +} + +String8 getResolvedAttribute(const ResTable& resTable, const ResXMLTree& tree, + uint32_t attrRes, String8* outError) { + ssize_t idx = indexOfAttribute(tree, attrRes); + if (idx < 0) { + return String8(); + } + Res_value value; + if (tree.getAttributeValue(idx, &value) != NO_ERROR) { + if (value.dataType == Res_value::TYPE_STRING) { + size_t len; + const uint16_t* str = tree.getAttributeStringValue(idx, &len); + return str ? String8(str, len) : String8(); + } + resTable.resolveReference(&value, 0); + if (value.dataType != Res_value::TYPE_STRING) { + if (outError != NULL) { + *outError = "attribute is not a string value"; + } + return String8(); + } + } + size_t len; + const Res_value* value2 = &value; + const char16_t* str = resTable.valueToString(value2, 0, NULL, &len); + return str ? String8(str, len) : String8(); +} + +int32_t getIntegerAttribute(const ResXMLTree& tree, const char* ns, + const char* attr, int32_t defValue, String8* outError) { + ssize_t idx = tree.indexOfAttribute(ns, attr); + if (idx < 0) { + return defValue; + } + return getIntegerAttributeAtIndex(tree, idx, defValue, outError); +} + +int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, int32_t defValue, + String8* outError) { + ssize_t idx = indexOfAttribute(tree, attrRes); + if (idx < 0) { + return defValue; + } + return getIntegerAttributeAtIndex(tree, idx, defValue, outError); +} + +int32_t getResolvedIntegerAttribute(const ResTable& resTable, const ResXMLTree& tree, + uint32_t attrRes, int32_t defValue, String8* outError) { + ssize_t idx = indexOfAttribute(tree, attrRes); + if (idx < 0) { + return defValue; + } + Res_value value; + if (tree.getAttributeValue(idx, &value) != NO_ERROR) { + if (value.dataType == Res_value::TYPE_REFERENCE) { + resTable.resolveReference(&value, 0); + } + if (value.dataType < Res_value::TYPE_FIRST_INT + || value.dataType > Res_value::TYPE_LAST_INT) { + if (outError != NULL) { + *outError = "attribute is not an integer value"; + } + return defValue; + } + } + return value.data; +} + +void getResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree, + uint32_t attrRes, Res_value* outValue, String8* outError) { + ssize_t idx = indexOfAttribute(tree, attrRes); + if (idx < 0) { + if (outError != NULL) { + *outError = "attribute could not be found"; + } + return; + } + if (tree.getAttributeValue(idx, outValue) != NO_ERROR) { + if (outValue->dataType == Res_value::TYPE_REFERENCE) { + resTable.resolveReference(outValue, 0); + } + // The attribute was found and was resolved if need be. + return; + } + if (outError != NULL) { + *outError = "error getting resolved resource attribute"; + } +} + +} // namespace AaptXml diff --git a/tools/aapt/AaptXml.h b/tools/aapt/AaptXml.h new file mode 100644 index 000000000000..16977f3d9d5d --- /dev/null +++ b/tools/aapt/AaptXml.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2014 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 __AAPT_XML_H +#define __AAPT_XML_H + +#include +#include + +/** + * Utility methods for dealing with ResXMLTree. + */ +namespace AaptXml { + +/** + * Returns the index of the attribute, or < 0 if it was not found. + */ +ssize_t indexOfAttribute(const android::ResXMLTree& tree, uint32_t attrRes); + +/** + * Returns the string value for the specified attribute. + * The string must be present in the ResXMLTree's string pool (inline in the XML). + */ +android::String8 getAttribute(const android::ResXMLTree& tree, const char* ns, + const char* attr, android::String8* outError = NULL); + +/** + * Returns the string value for the specified attribute, or an empty string + * if the attribute does not exist. + * The string must be present in the ResXMLTree's string pool (inline in the XML). + */ +android::String8 getAttribute(const android::ResXMLTree& tree, uint32_t attrRes, + android::String8* outError = NULL); + +/** + * Returns the integer value for the specified attribute, or the default value + * if the attribute does not exist. + * The integer must be declared inline in the XML. + */ +int32_t getIntegerAttribute(const android::ResXMLTree& tree, const char* ns, + const char* attr, int32_t defValue = -1, android::String8* outError = NULL); + +/** + * Returns the integer value for the specified attribute, or the default value + * if the attribute does not exist. + * The integer must be declared inline in the XML. + */ +inline int32_t getIntegerAttribute(const android::ResXMLTree& tree, const char* ns, + const char* attr, android::String8* outError) { + return getIntegerAttribute(tree, ns, attr, -1, outError); +} + +/** + * Returns the integer value for the specified attribute, or the default value + * if the attribute does not exist. + * The integer must be declared inline in the XML. + */ +int32_t getIntegerAttribute(const android::ResXMLTree& tree, uint32_t attrRes, + int32_t defValue = -1, android::String8* outError = NULL); + +/** + * Returns the integer value for the specified attribute, or the default value + * if the attribute does not exist. + * The integer must be declared inline in the XML. + */ +inline int32_t getIntegerAttribute(const android::ResXMLTree& tree, uint32_t attrRes, + android::String8* outError) { + return getIntegerAttribute(tree, attrRes, -1, outError); +} + +/** + * Returns the integer value for the specified attribute, or the default value + * if the attribute does not exist. + * The integer may be a resource in the supplied ResTable. + */ +int32_t getResolvedIntegerAttribute(const android::ResTable& resTable, + const android::ResXMLTree& tree, uint32_t attrRes, int32_t defValue = -1, + android::String8* outError = NULL); + +/** + * Returns the integer value for the specified attribute, or the default value + * if the attribute does not exist. + * The integer may be a resource in the supplied ResTable. + */ +inline int32_t getResolvedIntegerAttribute(const android::ResTable& resTable, + const android::ResXMLTree& tree, uint32_t attrRes, + android::String8* outError) { + return getResolvedIntegerAttribute(resTable, tree, attrRes, -1, outError); +} + +/** + * Returns the string value for the specified attribute, or an empty string + * if the attribute does not exist. + * The string may be a resource in the supplied ResTable. + */ +android::String8 getResolvedAttribute(const android::ResTable& resTable, + const android::ResXMLTree& tree, uint32_t attrRes, + android::String8* outError = NULL); + +/** + * Returns the resource for the specified attribute in the outValue parameter. + * The resource may be a resource in the supplied ResTable. + */ +void getResolvedResourceAttribute(const android::ResTable& resTable, + const android::ResXMLTree& tree, uint32_t attrRes, android::Res_value* outValue, + android::String8* outError = NULL); + +} // namespace AaptXml + +#endif // __AAPT_XML_H diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk index 4ce504544b91..2cbabe1cf27b 100644 --- a/tools/aapt/Android.mk +++ b/tools/aapt/Android.mk @@ -28,6 +28,7 @@ aaptSources := \ AaptAssets.cpp \ AaptConfig.cpp \ AaptUtil.cpp \ + AaptXml.cpp \ ApkBuilder.cpp \ Command.cpp \ CrunchCache.cpp \ diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index af494618d6ce..9bed899423c8 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -130,6 +130,10 @@ public: void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; } bool getErrorOnMissingConfigEntry() { return mErrorOnMissingConfigEntry; } void setErrorOnMissingConfigEntry(bool val) { mErrorOnMissingConfigEntry = val; } + const android::String8& getPlatformBuildVersionCode() { return mPlatformVersionCode; } + void setPlatformBuildVersionCode(const android::String8& code) { mPlatformVersionCode = code; } + const android::String8& getPlatformBuildVersionName() { return mPlatformVersionName; } + void setPlatformBuildVersionName(const android::String8& name) { mPlatformVersionName = name; } bool getUTF16StringsOption() { return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO); @@ -323,6 +327,8 @@ private: const char* mSingleCrunchInputFile; const char* mSingleCrunchOutputFile; bool mBuildSharedLibrary; + android::String8 mPlatformVersionCode; + android::String8 mPlatformVersionName; /* file specification */ int mArgc; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index a0f0a08bf95c..fd660bb65280 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -3,6 +3,7 @@ // // Android Asset Packaging Tool main entry point. // +#include "AaptXml.h" #include "ApkBuilder.h" #include "Bundle.h" #include "Images.h" @@ -241,162 +242,17 @@ bail: return result; } -static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) -{ - size_t N = tree.getAttributeCount(); - for (size_t i=0; i Res_value::TYPE_LAST_INT) { - if (outError != NULL) { - *outError = "attribute is not an integer value"; - } - return defValue; - } - } - return value.data; -} - -static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree, - uint32_t attrRes, String8* outError, int32_t defValue = -1) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - return defValue; - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType == Res_value::TYPE_REFERENCE) { - resTable->resolveReference(&value, 0); - } - if (value.dataType < Res_value::TYPE_FIRST_INT - || value.dataType > Res_value::TYPE_LAST_INT) { - if (outError != NULL) { - *outError = "attribute is not an integer value"; - } - return defValue; - } - } - return value.data; -} - -static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree, - uint32_t attrRes, String8* outError) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - return String8(); - } - Res_value value; - if (tree.getAttributeValue(idx, &value) != NO_ERROR) { - if (value.dataType == Res_value::TYPE_STRING) { - size_t len; - const uint16_t* str = tree.getAttributeStringValue(idx, &len); - return str ? String8(str, len) : String8(); - } - resTable->resolveReference(&value, 0); - if (value.dataType != Res_value::TYPE_STRING) { - if (outError != NULL) { - *outError = "attribute is not a string value"; - } - return String8(); - } - } - size_t len; - const Res_value* value2 = &value; - const char16_t* str = const_cast(resTable)->valueToString(value2, 0, NULL, &len); - return str ? String8(str, len) : String8(); -} - -static void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable, - const ResXMLTree& tree, uint32_t attrRes, String8* outError) -{ - ssize_t idx = indexOfAttribute(tree, attrRes); - if (idx < 0) { - if (outError != NULL) { - *outError = "attribute could not be found"; - } - return; - } - if (tree.getAttributeValue(idx, value) != NO_ERROR) { - if (value->dataType == Res_value::TYPE_REFERENCE) { - resTable->resolveReference(value, 0); - } - // The attribute was found and was resolved if need be. - return; - } - if (outError != NULL) { - *outError = "error getting resolved resource attribute"; - } -} - -static void printResolvedResourceAttribute(const ResTable* resTable, const ResXMLTree& tree, +static void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree, uint32_t attrRes, String8 attrLabel, String8* outError) { Res_value value; - getResolvedResourceAttribute(&value, resTable, tree, attrRes, outError); + AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError); if (*outError != "") { *outError = "error print resolved resource attribute"; return; } if (value.dataType == Res_value::TYPE_STRING) { - String8 result = getResolvedAttribute(resTable, tree, attrRes, outError); + String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError); printf("%s='%s'", attrLabel.string(), ResTable::normalizeForOutput(result.string()).string()); } else if (Res_value::TYPE_FIRST_INT <= value.dataType && @@ -488,10 +344,10 @@ static void printCompatibleScreens(ResXMLTree& tree, String8* outError) { } String8 tag(ctag16); if (tag == "screen") { - int32_t screenSize = getIntegerAttribute(tree, - SCREEN_SIZE_ATTR, NULL, -1); - int32_t screenDensity = getIntegerAttribute(tree, - SCREEN_DENSITY_ATTR, NULL, -1); + int32_t screenSize = AaptXml::getIntegerAttribute(tree, + SCREEN_SIZE_ATTR); + int32_t screenDensity = AaptXml::getIntegerAttribute(tree, + SCREEN_DENSITY_ATTR); if (screenSize > 0 && screenDensity > 0) { if (!first) { printf(","); @@ -577,7 +433,7 @@ Vector getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool } } else if (depth == 2 && withinApduService) { if (tag == "aid-group") { - String8 category = getAttribute(tree, CATEGORY_ATTR, &error); + String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error); if (error != "") { if (outError != NULL) *outError = error; return Vector(); @@ -876,11 +732,11 @@ int doDump(Bundle* bundle) fprintf(stderr, "ERROR: manifest does not start with tag\n"); goto bail; } - String8 pkg = getAttribute(tree, NULL, "package", NULL); + String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL); printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string()); } else if (depth == 2 && tag == "permission") { String8 error; - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); goto bail; @@ -889,14 +745,14 @@ int doDump(Bundle* bundle) ResTable::normalizeForOutput(name.string()).string()); } else if (depth == 2 && tag == "uses-permission") { String8 error; - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); goto bail; } printUsesPermission(name, - getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0, - getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1)); + AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0, + AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR)); } } } else if (strcmp("badging", option) == 0) { @@ -1151,12 +1007,14 @@ int doDump(Bundle* bundle) fprintf(stderr, "ERROR: manifest does not start with tag\n"); goto bail; } - pkg = getAttribute(tree, NULL, "package", NULL); + pkg = AaptXml::getAttribute(tree, NULL, "package", NULL); printf("package: name='%s' ", ResTable::normalizeForOutput(pkg.string()).string()); - int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); + int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR, + &error); if (error != "") { - fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); + fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", + error.string()); goto bail; } if (versionCode > 0) { @@ -1164,23 +1022,29 @@ int doDump(Bundle* bundle) } else { printf("versionCode='' "); } - String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error); + String8 versionName = AaptXml::getResolvedAttribute(res, tree, + VERSION_NAME_ATTR, &error); if (error != "") { - fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); + fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", + error.string()); goto bail; } printf("versionName='%s'", ResTable::normalizeForOutput(versionName.string()).string()); - String8 splitName = getAttribute(tree, NULL, "split", NULL); + String8 splitName = AaptXml::getAttribute(tree, NULL, "split"); if (!splitName.isEmpty()) { printf(" split='%s'", ResTable::normalizeForOutput( splitName.string()).string()); } + + int32_t platformVersionCode = AaptXml::getIntegerAttribute(tree, NULL, + "platformBuildVersionCode"); + printf(" platformBuildVersionCode='%d'", platformVersionCode); printf("\n"); - int32_t installLocation = getResolvedIntegerAttribute(&res, tree, - INSTALL_LOCATION_ATTR, &error, -1); + int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree, + INSTALL_LOCATION_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n", error.string()); @@ -1215,7 +1079,8 @@ int doDump(Bundle* bundle) for (size_t i=0; i commonFeatures.openGLESVersion) { @@ -1400,7 +1273,7 @@ int doDump(Bundle* bundle) } } } else if (tag == "uses-permission") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { if (name == "android.permission.CAMERA") { addImpliedFeature(&impliedFeatures, "android.hardware.camera", @@ -1478,15 +1351,15 @@ int doDump(Bundle* bundle) } printUsesPermission(name, - getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0, - getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1)); + AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0, + AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR)); } else { fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); goto bail; } } else if (tag == "uses-package") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { printf("uses-package:'%s'\n", ResTable::normalizeForOutput(name.string()).string()); @@ -1496,7 +1369,7 @@ int doDump(Bundle* bundle) goto bail; } } else if (tag == "original-package") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { printf("original-package:'%s'\n", ResTable::normalizeForOutput(name.string()).string()); @@ -1506,7 +1379,7 @@ int doDump(Bundle* bundle) goto bail; } } else if (tag == "supports-gl-texture") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { printf("supports-gl-texture:'%s'\n", ResTable::normalizeForOutput(name.string()).string()); @@ -1524,9 +1397,9 @@ int doDump(Bundle* bundle) } depth--; } else if (tag == "package-verifier") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { - String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error); + String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR, &error); if (publicKey != "" && error == "") { printf("package-verifier: name='%s' publicKey='%s'\n", ResTable::normalizeForOutput(name.string()).string(), @@ -1553,35 +1426,38 @@ int doDump(Bundle* bundle) if (withinApplication) { if(tag == "activity") { withinActivity = true; - activityName = getAttribute(tree, NAME_ATTR, &error); + activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); goto bail; } - activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); + activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, + &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); goto bail; } - activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); + activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, + &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); goto bail; } - activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error); + activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR, + &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n", error.string()); goto bail; } - int32_t orien = getResolvedIntegerAttribute(&res, tree, + int32_t orien = AaptXml::getResolvedIntegerAttribute(res, tree, SCREEN_ORIENTATION_ATTR, &error); if (error == "") { if (orien == 0 || orien == 6 || orien == 8) { @@ -1595,21 +1471,21 @@ int doDump(Bundle* bundle) } } } else if (tag == "uses-library") { - String8 libraryName = getAttribute(tree, NAME_ATTR, &error); + String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library" " %s\n", error.string()); goto bail; } - int req = getIntegerAttribute(tree, - REQUIRED_ATTR, NULL, 1); + int req = AaptXml::getIntegerAttribute(tree, + REQUIRED_ATTR, 1); printf("uses-library%s:'%s'\n", req ? "" : "-not-required", ResTable::normalizeForOutput( libraryName.string()).string()); } else if (tag == "receiver") { withinReceiver = true; - receiverName = getAttribute(tree, NAME_ATTR, &error); + receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, @@ -1618,7 +1494,8 @@ int doDump(Bundle* bundle) goto bail; } - String8 permission = getAttribute(tree, PERMISSION_ATTR, &error); + String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR, + &error); if (error == "") { if (permission == "android.permission.BIND_DEVICE_ADMIN") { hasBindDeviceAdminPermission = true; @@ -1629,7 +1506,7 @@ int doDump(Bundle* bundle) } } else if (tag == "service") { withinService = true; - serviceName = getAttribute(tree, NAME_ATTR, &error); + serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:name' attribute for " @@ -1637,7 +1514,8 @@ int doDump(Bundle* bundle) goto bail; } - String8 permission = getAttribute(tree, PERMISSION_ATTR, &error); + String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR, + &error); if (error == "") { if (permission == "android.permission.BIND_INPUT_METHOD") { hasBindInputMethodPermission = true; @@ -1659,22 +1537,24 @@ int doDump(Bundle* bundle) } else if (tag == "provider") { withinProvider = true; - bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error); + bool exported = AaptXml::getResolvedIntegerAttribute(res, tree, + EXPORTED_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:" " %s\n", error.string()); goto bail; } - bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree, - GRANT_URI_PERMISSIONS_ATTR, &error); + bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute( + res, tree, GRANT_URI_PERMISSIONS_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:" " %s\n", error.string()); goto bail; } - String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error); + String8 permission = AaptXml::getResolvedAttribute(res, tree, + PERMISSION_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:" " %s\n", error.string()); @@ -1685,7 +1565,8 @@ int doDump(Bundle* bundle) permission == "android.permission.MANAGE_DOCUMENTS"; } else if (bundle->getIncludeMetaData() && tag == "meta-data") { - String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error); + String8 metaDataName = AaptXml::getResolvedAttribute(res, tree, + NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:name' attribute for " "meta-data:%s\n", error.string()); @@ -1693,12 +1574,12 @@ int doDump(Bundle* bundle) } printf("meta-data: name='%s' ", ResTable::normalizeForOutput(metaDataName.string()).string()); - printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"), + printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"), &error); if (error != "") { // Try looking for a RESOURCE_ATTR error = ""; - printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR, + printResolvedResourceAttribute(res, tree, RESOURCE_ATTR, String8("resource"), &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:value' or " @@ -1709,7 +1590,7 @@ int doDump(Bundle* bundle) } printf("\n"); } else if (withinSupportsInput && tag == "input-type") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (name != "" && error == "") { supportedInput.add(name); } else { @@ -1721,12 +1602,13 @@ int doDump(Bundle* bundle) } else if (withinFeatureGroup && tag == "uses-feature") { FeatureGroup& top = featureGroups.editTop(); - String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error); + String8 name = AaptXml::getResolvedAttribute(res, tree, NAME_ATTR, &error); if (name != "" && error == "") { top.features.add(name, true); addParentFeatures(&top, name); } else { - int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error); + int vers = AaptXml::getIntegerAttribute(tree, GL_ES_VERSION_ATTR, + &error); if (error == "") { if (vers > top.openGLESVersion) { top.openGLESVersion = vers; @@ -1754,7 +1636,7 @@ int doDump(Bundle* bundle) actCameraSecure = false; catLauncher = false; } else if (withinService && tag == "meta-data") { - String8 name = getAttribute(tree, NAME_ATTR, &error); + String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:name' attribute for" " meta-data tag in service '%s': %s\n", serviceName.string(), error.string()); @@ -1768,7 +1650,8 @@ int doDump(Bundle* bundle) offHost = false; } - String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error); + String8 xmlPath = AaptXml::getResolvedAttribute(res, tree, + RESOURCE_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:resource' attribute for" " meta-data tag in service '%s': %s\n", serviceName.string(), error.string()); @@ -1797,7 +1680,7 @@ int doDump(Bundle* bundle) } else if ((depth == 5) && withinIntentFilter) { String8 action; if (tag == "action") { - action = getAttribute(tree, NAME_ATTR, &error); + action = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); @@ -1849,7 +1732,7 @@ int doDump(Bundle* bundle) } if (tag == "category") { - String8 category = getAttribute(tree, NAME_ATTR, &error); + String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error); if (error != "") { fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string()); diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h index dd40b2011dc8..f24a023b70a1 100644 --- a/tools/aapt/Main.h +++ b/tools/aapt/Main.h @@ -60,9 +60,6 @@ extern status_t filterResources(Bundle* bundle, const sp& assets); int dumpResources(Bundle* bundle); -String8 getAttribute(const ResXMLTree& tree, const char* ns, - const char* attr, String8* outError); - status_t writeDependencyPreReqs(Bundle* bundle, const sp& assets, FILE* fp, bool includeRaw); #endif // __MAIN_H diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 7979a1ddf7ae..5deeca2e03bc 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -4,6 +4,7 @@ // Build resource files from raw assets. // #include "AaptAssets.h" +#include "AaptXml.h" #include "CacheUpdater.h" #include "CrunchCache.h" #include "FileFinder.h" @@ -805,6 +806,20 @@ status_t massageManifest(Bundle* bundle, sp root) } } + if (bundle->getPlatformBuildVersionCode() != "") { + if (!addTagAttribute(root, "", "platformBuildVersionCode", + bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) { + return UNKNOWN_ERROR; + } + } + + if (bundle->getPlatformBuildVersionName() != "") { + if (!addTagAttribute(root, "", "platformBuildVersionName", + bundle->getPlatformBuildVersionName(), errorOnFailedInsert, true)) { + return UNKNOWN_ERROR; + } + } + if (bundle->getDebugMode()) { sp application = root->getChildElement(String16(), String16("application")); if (application != NULL) { @@ -881,6 +896,106 @@ status_t massageManifest(Bundle* bundle, sp root) return NO_ERROR; } +static int32_t getPlatformAssetCookie(const AssetManager& assets) { + // Find the system package (0x01). AAPT always generates attributes + // with the type 0x01, so we're looking for the first attribute + // resource in the system package. + const ResTable& table = assets.getResources(true); + Res_value val; + ssize_t idx = table.getResource(0x01010000, &val, true); + if (idx != NO_ERROR) { + // Try as a bag. + const ResTable::bag_entry* entry; + ssize_t cnt = table.lockBag(0x01010000, &entry); + if (cnt >= 0) { + idx = entry->stringBlock; + } + table.unlockBag(entry); + } + + if (idx < 0) { + return 0; + } + return table.getTableCookie(idx); +} + +enum { + VERSION_CODE_ATTR = 0x0101021b, + VERSION_NAME_ATTR = 0x0101021c, +}; + +static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) { + size_t len; + ResXMLTree::event_code_t code; + while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code != ResXMLTree::START_TAG) { + continue; + } + + const char16_t* ctag16 = tree.getElementName(&len); + if (ctag16 == NULL) { + fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n"); + return UNKNOWN_ERROR; + } + + String8 tag(ctag16, len); + if (tag != "manifest") { + continue; + } + + String8 error; + int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); + if (error != "") { + fprintf(stderr, "ERROR: failed to get platform version code\n"); + return UNKNOWN_ERROR; + } + + if (versionCode >= 0 && bundle->getPlatformBuildVersionCode() == "") { + bundle->setPlatformBuildVersionCode(String8::format("%d", versionCode)); + } + + String8 versionName = AaptXml::getAttribute(tree, VERSION_NAME_ATTR, &error); + if (error != "") { + fprintf(stderr, "ERROR: failed to get platform version name\n"); + return UNKNOWN_ERROR; + } + + if (versionName != "" && bundle->getPlatformBuildVersionName() == "") { + bundle->setPlatformBuildVersionName(versionName); + } + return NO_ERROR; + } + + fprintf(stderr, "ERROR: no tag found in platform AndroidManifest.xml\n"); + return UNKNOWN_ERROR; +} + +static ssize_t extractPlatformBuildVersion(AssetManager& assets, Bundle* bundle) { + int32_t cookie = getPlatformAssetCookie(assets); + if (cookie == 0) { + fprintf(stderr, "ERROR: Platform package not found\n"); + return UNKNOWN_ERROR; + } + + ResXMLTree tree; + Asset* asset = assets.openNonAsset(cookie, "AndroidManifest.xml", Asset::ACCESS_STREAMING); + if (asset == NULL) { + fprintf(stderr, "ERROR: Platform AndroidManifest.xml not found\n"); + return UNKNOWN_ERROR; + } + + ssize_t result = NO_ERROR; + if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { + fprintf(stderr, "ERROR: Platform AndroidManifest.xml is corrupt\n"); + result = UNKNOWN_ERROR; + } else { + result = extractPlatformBuildVersion(tree, bundle); + } + + delete asset; + return result; +} + #define ASSIGN_IT(n) \ do { \ ssize_t index = resources->indexOfKey(String8(#n)); \ @@ -1356,6 +1471,17 @@ status_t buildResources(Bundle* bundle, const sp& assets, spgetPlatformBuildVersionCode() == "" || + bundle->getPlatformBuildVersionName() == "")) { + err = extractPlatformBuildVersion(assets->getAssetManager(), bundle); + if (err != NO_ERROR) { + return UNKNOWN_ERROR; + } + } + const sp manifestFile(androidManifestFile->getFiles().valueAt(0)); String8 manifestPath(manifestFile->getPrintableSource()); @@ -2636,13 +2762,14 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& ass fprintf(stderr, "ERROR: manifest does not start with tag\n"); return -1; } - pkg = getAttribute(tree, NULL, "package", NULL); + pkg = AaptXml::getAttribute(tree, NULL, "package"); } else if (depth == 2) { if (tag == "application") { inApplication = true; keepTag = true; - String8 agent = getAttribute(tree, "http://schemas.android.com/apk/res/android", + String8 agent = AaptXml::getAttribute(tree, + "http://schemas.android.com/apk/res/android", "backupAgent", &error); if (agent.length() > 0) { addProguardKeepRule(keep, agent, pkg.string(), @@ -2658,8 +2785,8 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& ass } } if (keepTag) { - String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android", - "name", &error); + String8 name = AaptXml::getAttribute(tree, + "http://schemas.android.com/apk/res/android", "name", &error); if (error != "") { fprintf(stderr, "ERROR: %s\n", error.string()); return -1; -- cgit v1.2.3-59-g8ed1b