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(); } Res_value value; if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 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(idx, &len); return str ? String8(str, len) : String8(); }
static bool getAppInfo(const String8& path, AppInfo& outInfo) { memset(&outInfo, 0, sizeof(outInfo)); AssetManager assetManager; int32_t cookie = 0; if (!assetManager.addAssetPath(path, &cookie)) { return false; } Asset* asset = assetManager.openNonAsset(cookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER); if (asset == NULL) { return false; } ResXMLTree xml; if (xml.setTo(asset->getBuffer(true), asset->getLength(), false) != NO_ERROR) { delete asset; return false; } const String16 kAndroidNamespace("http://schemas.android.com/apk/res/android"); const String16 kManifestTag("manifest"); const String16 kApplicationTag("application"); const String16 kUsesSdkTag("uses-sdk"); const String16 kVersionCodeAttr("versionCode"); const String16 kMultiArchAttr("multiArch"); const String16 kMinSdkVersionAttr("minSdkVersion"); ResXMLParser::event_code_t event; while ((event = xml.next()) != ResXMLParser::BAD_DOCUMENT && event != ResXMLParser::END_DOCUMENT) { if (event != ResXMLParser::START_TAG) { continue; } size_t len; const char16_t* name = xml.getElementName(&len); String16 name16(name, len); if (name16 == kManifestTag) { ssize_t idx = xml.indexOfAttribute( kAndroidNamespace.string(), kAndroidNamespace.size(), kVersionCodeAttr.string(), kVersionCodeAttr.size()); if (idx >= 0) { outInfo.versionCode = xml.getAttributeData(idx); } } else if (name16 == kApplicationTag) { ssize_t idx = xml.indexOfAttribute( kAndroidNamespace.string(), kAndroidNamespace.size(), kMultiArchAttr.string(), kMultiArchAttr.size()); if (idx >= 0) { outInfo.multiArch = xml.getAttributeData(idx) != 0; } } else if (name16 == kUsesSdkTag) { ssize_t idx = xml.indexOfAttribute( kAndroidNamespace.string(), kAndroidNamespace.size(), kMinSdkVersionAttr.string(), kMinSdkVersionAttr.size()); if (idx >= 0) { uint16_t type = xml.getAttributeDataType(idx); if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) { outInfo.minSdkVersion = xml.getAttributeData(idx); } else if (type == Res_value::TYPE_STRING) { String8 minSdk8(xml.getStrings().string8ObjectAt(idx)); char* endPtr; int minSdk = strtol(minSdk8.string(), &endPtr, 10); if (endPtr != minSdk8.string() + minSdk8.size()) { fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n", minSdk8.string()); } else { outInfo.minSdkVersion = minSdk; } } else { fprintf(stderr, "warning: unrecognized value for android:minSdkVersion.\n"); } } } } delete asset; return true; }