Merge commit '0953ab27' into manualmerge

Change-Id: I36dea45f7571096136ea7bda5e2680bd85a0df32
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index ba72cd5..de73254 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1826,6 +1826,9 @@
         const ResTable_config* config,
         Entry* outEntry) const;
 
+    uint32_t findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name,
+            size_t nameLen, uint32_t* outTypeSpecFlags) const;
+
     status_t parsePackage(
         const ResTable_package* const pkg, const Header* const header);
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index a951ffb..e78e4fe 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -4316,6 +4316,9 @@
                 String8(package, packageLen).string());
     }
 
+    const String16 attr("attr");
+    const String16 attrPrivate("^attr-private");
+
     const size_t NG = mPackageGroups.size();
     for (size_t ig=0; ig<NG; ig++) {
         const PackageGroup* group = mPackageGroups[ig];
@@ -4330,66 +4333,72 @@
 
         const size_t packageCount = group->packages.size();
         for (size_t pi = 0; pi < packageCount; pi++) {
-            ssize_t ti = group->packages[pi]->typeStrings.indexOfString(type, typeLen);
-            if (ti < 0) {
-                continue;
-            }
+            const char16_t* targetType = type;
+            size_t targetTypeLen = typeLen;
 
-            ti += group->packages[pi]->typeIdOffset;
-
-            const TypeList& typeList = group->types[ti];
-            if (typeList.isEmpty()) {
-                if (kDebugTableNoisy) {
-                    ALOGI("Expected type structure not found in package %s for index %zd\n",
-                            String8(group->name).string(), ti);
-                }
-                continue;
-            }
-
-            const size_t typeCount = typeList.size();
-            for (size_t i = 0; i < typeCount; i++) {
-                const Type* t = typeList[i];
-                const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen);
-                if (ei < 0) {
+            do {
+                ssize_t ti = group->packages[pi]->typeStrings.indexOfString(
+                        targetType, targetTypeLen);
+                if (ti < 0) {
                     continue;
                 }
 
-                const size_t configCount = t->configs.size();
-                for (size_t j = 0; j < configCount; j++) {
-                    const TypeVariant tv(t->configs[j]);
-                    for (TypeVariant::iterator iter = tv.beginEntries();
-                         iter != tv.endEntries();
-                         iter++) {
-                        const ResTable_entry* entry = *iter;
-                        if (entry == NULL) {
-                            continue;
-                        }
+                ti += group->packages[pi]->typeIdOffset;
 
-                        if (dtohl(entry->key.index) == (size_t) ei) {
-                            uint32_t resId = Res_MAKEID(group->id - 1, ti, iter.index());
-                            if (outTypeSpecFlags) {
-                                Entry result;
-                                if (getEntry(group, ti, iter.index(), NULL, &result) != NO_ERROR) {
-                                    ALOGW("Failed to find spec flags for %s:%s/%s (0x%08x)",
-                                            String8(group->name).string(),
-                                            String8(String16(type, typeLen)).string(),
-                                            String8(String16(name, nameLen)).string(),
-                                            resId);
-                                    return 0;
-                                }
-                                *outTypeSpecFlags = result.specFlags;
-
-                                if (fakePublic) {
-                                    *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
-                                }
-                            }
-                            return resId;
-                        }
+                const uint32_t identifier = findEntry(group, ti, name, nameLen,
+                        outTypeSpecFlags);
+                if (identifier != 0) {
+                    if (fakePublic && outTypeSpecFlags) {
+                        *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
                     }
+                    return identifier;
+                }
+            } while (strzcmp16(attr.string(), attr.size(), targetType, targetTypeLen) == 0
+                    && (targetType = attrPrivate.string())
+                    && (targetTypeLen = attrPrivate.size())
+            );
+        }
+        break;
+    }
+    return 0;
+}
+
+uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name,
+        size_t nameLen, uint32_t* outTypeSpecFlags) const {
+    const TypeList& typeList = group->types[typeIndex];
+    const size_t typeCount = typeList.size();
+    for (size_t i = 0; i < typeCount; i++) {
+        const Type* t = typeList[i];
+        const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen);
+        if (ei < 0) {
+            continue;
+        }
+
+        const size_t configCount = t->configs.size();
+        for (size_t j = 0; j < configCount; j++) {
+            const TypeVariant tv(t->configs[j]);
+            for (TypeVariant::iterator iter = tv.beginEntries();
+                 iter != tv.endEntries();
+                 iter++) {
+                const ResTable_entry* entry = *iter;
+                if (entry == NULL) {
+                    continue;
+                }
+
+                if (dtohl(entry->key.index) == (size_t) ei) {
+                    uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index());
+                    if (outTypeSpecFlags) {
+                        Entry result;
+                        if (getEntry(group, typeIndex, iter.index(), NULL, &result) != NO_ERROR) {
+                            ALOGW("Failed to find spec flags for 0x%08x", resId);
+                            return 0;
+                        }
+                        *outTypeSpecFlags = result.specFlags;
+                    }
+                    return resId;
                 }
             }
         }
-        break;
     }
     return 0;
 }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 69f1ec3..e91a376 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -12,6 +12,7 @@
 #include "ResourceIdCache.h"
 #include "SdkConstants.h"
 
+#include <algorithm>
 #include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
 #include <utils/TypeHelpers.h>
@@ -36,6 +37,8 @@
 static const bool kPrintStringMetrics = false;
 #endif
 
+static const char* kAttrPrivateType = "^attr-private";
+
 status_t compileXmlFile(const Bundle* bundle,
                         const sp<AaptAssets>& assets,
                         const String16& resourceName,
@@ -2153,8 +2156,16 @@
     if (p == NULL) return 0;
     sp<Type> t = p->getTypes().valueFor(type);
     if (t == NULL) return 0;
-    sp<ConfigList> c =  t->getConfigs().valueFor(name);
-    if (c == NULL) return 0;
+    sp<ConfigList> c = t->getConfigs().valueFor(name);
+    if (c == NULL) {
+        if (type != String16("attr")) {
+            return 0;
+        }
+        t = p->getTypes().valueFor(String16(kAttrPrivateType));
+        if (t == NULL) return 0;
+        c = t->getConfigs().valueFor(name);
+        if (c == NULL) return 0;
+    }
     int32_t ei = c->getEntryIndex();
     if (ei < 0) return 0;
 
@@ -2293,7 +2304,15 @@
     sp<Type> t = p->getTypes().valueFor(type);
     if (t == NULL) return 0;
     sp<ConfigList> c =  t->getConfigs().valueFor(name);
-    if (c == NULL) return 0;
+    if (c == NULL) {
+        if (type != String16("attr")) {
+            return 0;
+        }
+        t = p->getTypes().valueFor(String16(kAttrPrivateType));
+        if (t == NULL) return 0;
+        c = t->getConfigs().valueFor(name);
+        if (c == NULL) return 0;
+    }
     int32_t ei = c->getEntryIndex();
     if (ei < 0) return 0;
     return getResId(p, t, ei);
@@ -2497,6 +2516,10 @@
             continue;
         }
 
+        if (mPackageType == System) {
+            p->movePrivateAttrs();
+        }
+
         // This has no sense for packages being built as AppFeature (aka with a non-zero offset).
         status_t err = p->applyPublicTypeOrder();
         if (err != NO_ERROR && firstError == NO_ERROR) {
@@ -2567,15 +2590,20 @@
             }
         }
 
+
         // Assign resource IDs to keys in bags...
         for (size_t ti = 0; ti < typeCount; ti++) {
             sp<Type> t = p->getOrderedTypes().itemAt(ti);
             if (t == NULL) {
                 continue;
             }
+
             const size_t N = t->getOrderedConfigs().size();
             for (size_t ci=0; ci<N; ci++) {
                 sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
+                if (c == NULL) {
+                    continue;
+                }
                 //printf("Ordered config #%d: %p\n", ci, c.get());
                 const size_t N = c->getEntries().size();
                 for (size_t ei=0; ei<N; ei++) {
@@ -2613,9 +2641,15 @@
             if (t == NULL) {
                 continue;
             }
+
             const size_t N = t->getOrderedConfigs().size();
-            sp<AaptSymbols> typeSymbols =
-                    outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+            sp<AaptSymbols> typeSymbols;
+            if (t->getName() == String16(kAttrPrivateType)) {
+                typeSymbols = outSymbols->addNestedSymbol(String8("attr"), t->getPos());
+            } else {
+                typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+            }
+
             if (typeSymbols == NULL) {
                 return UNKNOWN_ERROR;
             }
@@ -2981,6 +3015,10 @@
 
                 for (size_t ei=0; ei<N; ei++) {
                     sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
+                    if (cl == NULL) {
+                        continue;
+                    }
+
                     if (cl->getPublic()) {
                         typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
                     }
@@ -3011,12 +3049,16 @@
 
             // We need to write one type chunk for each configuration for
             // which we have entries in this type.
-            const size_t NC = t != NULL ? t->getUniqueConfigs().size() : 0;
+            SortedVector<ConfigDescription> uniqueConfigs;
+            if (t != NULL) {
+                uniqueConfigs = t->getUniqueConfigs();
+            }
             
             const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N;
             
+            const size_t NC = uniqueConfigs.size();
             for (size_t ci=0; ci<NC; ci++) {
-                ConfigDescription config = t->getUniqueConfigs().itemAt(ci);
+                const ConfigDescription& config = uniqueConfigs[ci];
 
                 if (kIsDebug) {
                     printf("Writing config %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
@@ -3092,7 +3134,10 @@
                 // Build the entries inside of this type.
                 for (size_t ei=0; ei<N; ei++) {
                     sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
-                    sp<Entry> e = cl->getEntries().valueFor(config);
+                    sp<Entry> e = NULL;
+                    if (cl != NULL) {
+                        e = cl->getEntries().valueFor(config);
+                    }
 
                     // Set the offset for this entry in its type.
                     uint32_t* index = (uint32_t*)
@@ -3127,9 +3172,11 @@
                 for (size_t i = 0; i < N; ++i) {
                     if (!validResources[i]) {
                         sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
-                        fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
-                                String8(typeName).string(), String8(c->getName()).string(),
-                                Res_MAKEID(p->getAssignedId() - 1, ti, i));
+                        if (c != NULL) {
+                            fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
+                                    String8(typeName).string(), String8(c->getName()).string(),
+                                    Res_MAKEID(p->getAssignedId() - 1, ti, i));
+                        }
                         missing_entry = true;
                     }
                 }
@@ -3841,11 +3888,45 @@
         */
     }
     
-    mUniqueConfigs.add(cdesc);
-    
     return e;
 }
 
+sp<ResourceTable::ConfigList> ResourceTable::Type::removeEntry(const String16& entry) {
+    ssize_t idx = mConfigs.indexOfKey(entry);
+    if (idx < 0) {
+        return NULL;
+    }
+
+    sp<ConfigList> removed = mConfigs.valueAt(idx);
+    mConfigs.removeItemsAt(idx);
+
+    Vector<sp<ConfigList> >::iterator iter = std::find(
+            mOrderedConfigs.begin(), mOrderedConfigs.end(), removed);
+    if (iter != mOrderedConfigs.end()) {
+        mOrderedConfigs.erase(iter);
+    }
+
+    mPublic.removeItem(entry);
+    return removed;
+}
+
+SortedVector<ConfigDescription> ResourceTable::Type::getUniqueConfigs() const {
+    SortedVector<ConfigDescription> unique;
+    const size_t entryCount = mOrderedConfigs.size();
+    for (size_t i = 0; i < entryCount; i++) {
+        if (mOrderedConfigs[i] == NULL) {
+            continue;
+        }
+        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configs =
+                mOrderedConfigs[i]->getEntries();
+        const size_t configCount = configs.size();
+        for (size_t j = 0; j < configCount; j++) {
+            unique.add(configs.keyAt(j));
+        }
+    }
+    return unique;
+}
+
 status_t ResourceTable::Type::applyPublicEntryOrder()
 {
     size_t N = mOrderedConfigs.size();
@@ -3872,11 +3953,10 @@
             //printf("#%d: \"%s\"\n", i, String8(e->getName()).string());
             if (e->getName() == name) {
                 if (idx >= (int32_t)mOrderedConfigs.size()) {
-                    p.sourcePos.error("Public entry identifier 0x%x entry index "
-                            "is larger than available symbols (index %d, total symbols %d).\n",
-                            p.ident, idx, mOrderedConfigs.size());
-                    hasError = true;
-                } else if (mOrderedConfigs.itemAt(idx) == NULL) {
+                    mOrderedConfigs.resize(idx + 1);
+                }
+
+                if (mOrderedConfigs.itemAt(idx) == NULL) {
                     e->setPublic(true);
                     e->setPublicSourcePos(p.sourcePos);
                     mOrderedConfigs.replaceAt(e, idx);
@@ -4049,6 +4129,61 @@
     return NO_ERROR;
 }
 
+void ResourceTable::Package::movePrivateAttrs() {
+    sp<Type> attr = mTypes.valueFor(String16("attr"));
+    if (attr == NULL) {
+        // Nothing to do.
+        return;
+    }
+
+    Vector<sp<ConfigList> > privateAttrs;
+
+    bool hasPublic = false;
+    const Vector<sp<ConfigList> >& configs = attr->getOrderedConfigs();
+    const size_t configCount = configs.size();
+    for (size_t i = 0; i < configCount; i++) {
+        if (configs[i] == NULL) {
+            continue;
+        }
+
+        if (attr->isPublic(configs[i]->getName())) {
+            hasPublic = true;
+        } else {
+            privateAttrs.add(configs[i]);
+        }
+    }
+
+    // Only if we have public attributes do we create a separate type for
+    // private attributes.
+    if (!hasPublic) {
+        return;
+    }
+
+    // Create a new type for private attributes.
+    sp<Type> privateAttrType = getType(String16(kAttrPrivateType), SourcePos());
+
+    const size_t privateAttrCount = privateAttrs.size();
+    for (size_t i = 0; i < privateAttrCount; i++) {
+        const sp<ConfigList>& cl = privateAttrs[i];
+
+        // Remove the private attributes from their current type.
+        attr->removeEntry(cl->getName());
+
+        // Add it to the new type.
+        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries = cl->getEntries();
+        const size_t entryCount = entries.size();
+        for (size_t j = 0; j < entryCount; j++) {
+            const sp<Entry>& oldEntry = entries[j];
+            sp<Entry> entry = privateAttrType->getEntry(
+                    cl->getName(), oldEntry->getPos(), &entries.keyAt(j));
+            *entry = *oldEntry;
+        }
+
+        // Move the symbols to the new type.
+
+    }
+}
+
 sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
 {
     if (package != mAssetsPackage) {
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index db392c89..81590bc 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -470,6 +470,14 @@
                            bool overlay = false,
                            bool autoAddOverlay = false);
 
+        bool isPublic(const String16& entry) const {
+            return mPublic.indexOfKey(entry) >= 0;
+        }
+
+        sp<ConfigList> removeEntry(const String16& entry);
+
+        SortedVector<ConfigDescription> getUniqueConfigs() const;
+
         const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
 
         int32_t getPublicIndex() const { return mPublicIndex; }
@@ -479,19 +487,16 @@
 
         status_t applyPublicEntryOrder();
 
-        const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; }
-        
         const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
         const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
-
         const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
         
         const SourcePos& getPos() const { return mPos; }
+
     private:
         String16 mName;
         SourcePos* mFirstPublicSourcePos;
         DefaultKeyedVector<String16, Public> mPublic;
-        SortedVector<ConfigDescription> mUniqueConfigs;
         DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
         Vector<sp<ConfigList> > mOrderedConfigs;
         SortedVector<String16> mCanAddEntries;
@@ -527,6 +532,8 @@
         const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; }
         const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; }
 
+        void movePrivateAttrs();
+
     private:
         status_t setStrings(const sp<AaptFile>& data,
                             ResStringPool* strings,