summaryrefslogtreecommitdiffstats
path: root/tools/aapt
diff options
context:
space:
mode:
authorAdam Lesinski <adamlesinski@google.com>2014-09-19 19:08:50 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-09-19 19:08:50 +0000
commit0fa7511db2ec1e2326938f92262d00f23876307e (patch)
tree79fe6be8c92ccf3acef647bbaa3ee85e6f890890 /tools/aapt
parente83bc5932eba4af67e2cd7b76648ae26740b9b01 (diff)
parenta7d1a111c7176fdf853e53e74f6c7c7843c3c81c (diff)
downloadframeworks_base-0fa7511db2ec1e2326938f92262d00f23876307e.zip
frameworks_base-0fa7511db2ec1e2326938f92262d00f23876307e.tar.gz
frameworks_base-0fa7511db2ec1e2326938f92262d00f23876307e.tar.bz2
am 9ee3ba23: am e7e9ad6d: am 863b1a90: am 19f9d54f: Merge "Fix backwards compat problem with AAPT public attrs" into lmp-dev
* commit '9ee3ba23395bd1a13bbfd3fe523ee611a5ca001b': Fix backwards compat problem with AAPT public attrs
Diffstat (limited to 'tools/aapt')
-rw-r--r--tools/aapt/Resource.cpp24
-rw-r--r--tools/aapt/ResourceTable.cpp196
-rw-r--r--tools/aapt/ResourceTable.h8
3 files changed, 225 insertions, 3 deletions
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 3ab3d59..1e6ba74 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -781,12 +781,18 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
bundle->getVersionName(), errorOnFailedInsert, replaceVersion)) {
return UNKNOWN_ERROR;
+ } else {
+ const XMLNode::attribute_entry* attr = root->getAttribute(
+ String16(RESOURCES_ANDROID_NAMESPACE), String16("versionName"));
+ if (attr != NULL) {
+ bundle->setVersionName(strdup(String8(attr->string).string()));
+ }
}
+ sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
if (bundle->getMinSdkVersion() != NULL
|| bundle->getTargetSdkVersion() != NULL
|| bundle->getMaxSdkVersion() != NULL) {
- sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
if (vers == NULL) {
vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
root->insertChildAt(vers, 0);
@@ -806,6 +812,14 @@ status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
}
}
+ if (vers != NULL) {
+ const XMLNode::attribute_entry* attr = vers->getAttribute(
+ String16(RESOURCES_ANDROID_NAMESPACE), String16("minSdkVersion"));
+ if (attr != NULL) {
+ bundle->setMinSdkVersion(strdup(String8(attr->string).string()));
+ }
+ }
+
if (bundle->getPlatformBuildVersionCode() != "") {
if (!addTagAttribute(root, "", "platformBuildVersionCode",
bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) {
@@ -973,8 +987,8 @@ static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
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;
+ // No platform was loaded.
+ return NO_ERROR;
}
ResXMLTree tree;
@@ -1500,6 +1514,10 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
return err;
}
+ if (table.modifyForCompat(bundle) != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ }
+
//block.restart();
//printXMLBlock(&block);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index dccc363..f66ed08 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -12,6 +12,7 @@
#include <androidfw/ResourceTypes.h>
#include <utils/ByteOrder.h>
+#include <utils/TypeHelpers.h>
#include <stdarg.h>
#define NOISY(x) //x
@@ -3287,6 +3288,18 @@ ResourceTable::Item::Item(const SourcePos& _sourcePos,
}
}
+ResourceTable::Entry::Entry(const Entry& entry)
+ : RefBase()
+ , mName(entry.mName)
+ , mParent(entry.mParent)
+ , mType(entry.mType)
+ , mItem(entry.mItem)
+ , mItemFormat(entry.mItemFormat)
+ , mBag(entry.mBag)
+ , mNameIndex(entry.mNameIndex)
+ , mParentId(entry.mParentId)
+ , mPos(entry.mPos) {}
+
status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos)
{
if (mType == TYPE_BAG) {
@@ -3372,6 +3385,17 @@ status_t ResourceTable::Entry::addToBag(const SourcePos& sourcePos,
return NO_ERROR;
}
+status_t ResourceTable::Entry::removeFromBag(const String16& key) {
+ if (mType != Entry::TYPE_BAG) {
+ return NO_ERROR;
+ }
+
+ if (mBag.removeItem(key) >= 0) {
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+}
+
status_t ResourceTable::Entry::emptyBag(const SourcePos& sourcePos)
{
status_t err = makeItABag(sourcePos);
@@ -4113,3 +4137,175 @@ bool ResourceTable::getItemValue(
}
return res;
}
+
+/**
+ * Returns true if the given attribute ID comes from
+ * a platform version from or after L.
+ */
+bool ResourceTable::isAttributeFromL(uint32_t attrId) {
+ const uint32_t baseAttrId = 0x010103f7;
+ if ((attrId & 0xffff0000) != (baseAttrId & 0xffff0000)) {
+ return false;
+ }
+
+ uint32_t specFlags;
+ if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
+ return false;
+ }
+
+ return (specFlags & ResTable_typeSpec::SPEC_PUBLIC) != 0 &&
+ (attrId & 0x0000ffff) >= (baseAttrId & 0x0000ffff);
+}
+
+/**
+ * Modifies the entries in the resource table to account for compatibility
+ * issues with older versions of Android.
+ *
+ * This primarily handles the issue of private/public attribute clashes
+ * in framework resources.
+ *
+ * AAPT has traditionally assigned resource IDs to public attributes,
+ * and then followed those public definitions with private attributes.
+ *
+ * --- PUBLIC ---
+ * | 0x01010234 | attr/color
+ * | 0x01010235 | attr/background
+ *
+ * --- PRIVATE ---
+ * | 0x01010236 | attr/secret
+ * | 0x01010237 | attr/shhh
+ *
+ * Each release, when attributes are added, they take the place of the private
+ * attributes and the private attributes are shifted down again.
+ *
+ * --- PUBLIC ---
+ * | 0x01010234 | attr/color
+ * | 0x01010235 | attr/background
+ * | 0x01010236 | attr/shinyNewAttr
+ * | 0x01010237 | attr/highlyValuedFeature
+ *
+ * --- PRIVATE ---
+ * | 0x01010238 | attr/secret
+ * | 0x01010239 | attr/shhh
+ *
+ * Platform code may look for private attributes set in a theme. If an app
+ * compiled against a newer version of the platform uses a new public
+ * attribute that happens to have the same ID as the private attribute
+ * the older platform is expecting, then the behavior is undefined.
+ *
+ * We get around this by detecting any newly defined attributes (in L),
+ * copy the resource into a -v21 qualified resource, and delete the
+ * attribute from the original resource. This ensures that older platforms
+ * don't see the new attribute, but when running on L+ platforms, the
+ * attribute will be respected.
+ */
+status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
+ if (bundle->getMinSdkVersion() != NULL) {
+ // If this app will only ever run on L+ devices,
+ // we don't need to do any compatibility work.
+
+ if (String8("L") == bundle->getMinSdkVersion()) {
+ // Code-name for the v21 release.
+ return NO_ERROR;
+ }
+
+ const int minSdk = atoi(bundle->getMinSdkVersion());
+ if (minSdk >= SDK_L) {
+ return NO_ERROR;
+ }
+ }
+
+ const String16 attr16("attr");
+
+ const size_t packageCount = mOrderedPackages.size();
+ for (size_t pi = 0; pi < packageCount; pi++) {
+ sp<Package> p = mOrderedPackages.itemAt(pi);
+ if (p == NULL || p->getTypes().size() == 0) {
+ // Empty, skip!
+ continue;
+ }
+
+ const size_t typeCount = p->getOrderedTypes().size();
+ for (size_t ti = 0; ti < typeCount; ti++) {
+ sp<Type> t = p->getOrderedTypes().itemAt(ti);
+ if (t == NULL) {
+ continue;
+ }
+
+ const size_t configCount = t->getOrderedConfigs().size();
+ for (size_t ci = 0; ci < configCount; ci++) {
+ sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
+ if (c == NULL) {
+ continue;
+ }
+
+ Vector<key_value_pair_t<ConfigDescription, sp<Entry> > > entriesToAdd;
+ const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries =
+ c->getEntries();
+ const size_t entryCount = entries.size();
+ for (size_t ei = 0; ei < entryCount; ei++) {
+ sp<Entry> e = entries.valueAt(ei);
+ if (e == NULL || e->getType() != Entry::TYPE_BAG) {
+ continue;
+ }
+
+ const ConfigDescription& config = entries.keyAt(ei);
+ if (config.sdkVersion >= SDK_L) {
+ // We don't need to do anything if the resource is
+ // already qualified for version 21 or higher.
+ continue;
+ }
+
+ Vector<String16> attributesToRemove;
+ const KeyedVector<String16, Item>& bag = e->getBag();
+ const size_t bagCount = bag.size();
+ for (size_t bi = 0; bi < bagCount; bi++) {
+ const Item& item = bag.valueAt(bi);
+ const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
+ if (isAttributeFromL(attrId)) {
+ attributesToRemove.add(bag.keyAt(bi));
+ }
+ }
+
+ if (attributesToRemove.isEmpty()) {
+ continue;
+ }
+
+ // Duplicate the entry under the same configuration
+ // but with sdkVersion == SDK_L.
+ ConfigDescription newConfig(config);
+ newConfig.sdkVersion = SDK_L;
+ entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
+ newConfig, new Entry(*e)));
+
+ // Remove the attribute from the original.
+ for (size_t i = 0; i < attributesToRemove.size(); i++) {
+ e->removeFromBag(attributesToRemove[i]);
+ }
+ }
+
+ const size_t entriesToAddCount = entriesToAdd.size();
+ for (size_t i = 0; i < entriesToAddCount; i++) {
+ if (entries.indexOfKey(entriesToAdd[i].key) >= 0) {
+ // An entry already exists for this config.
+ // That means that any attributes that were
+ // defined in L in the original bag will be overriden
+ // anyways on L devices, so we do nothing.
+ continue;
+ }
+
+ entriesToAdd[i].value->getPos()
+ .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
+ SDK_L,
+ String8(p->getName()).string(),
+ String8(t->getName()).string(),
+ String8(entriesToAdd[i].value->getName()).string(),
+ entriesToAdd[i].key.toString().string());
+
+ c->addEntry(entriesToAdd[i].key, entriesToAdd[i].value);
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 3721de4..025a868 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -165,6 +165,8 @@ public:
size_t numLocalResources() const;
bool hasResources() const;
+ status_t modifyForCompat(const Bundle* bundle);
+
sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
const bool isBase);
@@ -281,6 +283,9 @@ public:
: mName(name), mType(TYPE_UNKNOWN),
mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos)
{ }
+
+ Entry(const Entry& entry);
+
virtual ~Entry() { }
enum type {
@@ -311,6 +316,8 @@ public:
bool replace=false, bool isId = false,
int32_t format = ResTable_map::TYPE_ANY);
+ status_t removeFromBag(const String16& key);
+
// Index of the entry's name string in the key pool.
int32_t getNameIndex() const { return mNameIndex; }
void setNameIndex(int32_t index) { mNameIndex = index; }
@@ -523,6 +530,7 @@ private:
const Item* getItem(uint32_t resID, uint32_t attrID) const;
bool getItemValue(uint32_t resID, uint32_t attrID,
Res_value* outValue);
+ bool isAttributeFromL(uint32_t attrId);
String16 mAssetsPackage;