diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index 11568d280c24e26fc300be415ccb028989f6a168..c65efe4d4900fa88e8be5715efae23afdf1ec4b7 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 3f014ef5de1ef6e8fe84fb98de431265aa3fc165..90879dd9b677006c68a1e99d499d0c0a98701b75 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 b44e2d139a950b0a41e4839e3965147096017240..117fc24350765d1970d84f579c4be732a527297c 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 0c2576a954b1ca8de0b9bd6378ef718c04e1e8d4..3fc9f815c1a9ab6fa96c18ed72f8be38c8bd5dd4 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 0000000000000000000000000000000000000000..708e4054e63a2a21a733b79338c5f1a81322af11 --- /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 0000000000000000000000000000000000000000..16977f3d9d5d780b50642988edd4f6e64bb26d59 --- /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 4ce504544b91ea491964859353cd81144436a104..2cbabe1cf27b875a3b2bb01460ad533e56abf281 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 af494618d6ce2e1b29f369e53276023af79bcfd5..9bed899423c8b9925f217f7ced5ff07ce3fec6b4 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 a0f0a08bf95c717000b49a105c3bf485d74245d7..fd660bb6528003766c2c5ea75b5eac8fd1ddea74 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 dd40b2011dc8fdd332d441f3a2923c0f9f5e208c..f24a023b70a1d779c7cafbabbcd69f2c4565a9a1 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 7979a1ddf7aec11e4b65dcc033b1ebfd13fe38df..5deeca2e03bce9e6b719d9892e23410807e83e03 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;