Avoid matching system locales in locale negotiation

Also:
1. Add AssetManager method for finding non-system locales: This is
used in per-app locale negotiation. (Normally,
AssetManager#getLocales() returns both system and non-system
locales.)

2. Match pseudolocales correctly in locale negotiation.

Bug: 25800576
Bug: 26236938
Change-Id: I116caf3a91c290deb4ad68b291c65b7035b18dd4
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 8a03b94..6913f43 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,8 @@
     delete[] mVendor;
 }
 
-bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
+bool AssetManager::addAssetPath(
+        const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
 {
     AutoMutex _l(mLock);
 
@@ -222,6 +223,7 @@
     }
     delete manifestAsset;
 
+    ap.isSystemAsset = isSystemAsset;
     mAssetPaths.add(ap);
 
     // new paths are always added at the end
@@ -233,6 +235,7 @@
     // Load overlays, if any
     asset_path oap;
     for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
+        oap.isSystemAsset = isSystemAsset;
         mAssetPaths.add(oap);
     }
 #endif
@@ -340,7 +343,7 @@
     String8 path(root);
     path.appendPath(kSystemAssets);
 
-    return addAssetPath(path, NULL);
+    return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
 }
 
 int32_t AssetManager::nextAssetPath(const int32_t cookie) const
@@ -682,10 +685,10 @@
         ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
         if (sharedRes != NULL) {
             ALOGV("Copying existing resources for %s", ap.path.string());
-            mResources->add(sharedRes);
+            mResources->add(sharedRes, ap.isSystemAsset);
         } else {
             ALOGV("Parsing resources for %s", ap.path.string());
-            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
+            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
         }
         onlyEmptyResources = false;
 
@@ -831,11 +834,11 @@
     return mZipSet.isUpToDate();
 }
 
-void AssetManager::getLocales(Vector<String8>* locales) const
+void AssetManager::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     ResTable* res = mResources;
     if (res != NULL) {
-        res->getLocales(locales);
+        res->getLocales(locales, includeSystemLocales);
     }
 
     const size_t numLocales = locales->size();
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 21b543e..44f92c7 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3080,13 +3080,16 @@
 // table that defined the package); the ones after are skins on top of it.
 struct ResTable::PackageGroup
 {
-    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
+    PackageGroup(
+            ResTable* _owner, const String16& _name, uint32_t _id,
+            bool appAsLib, bool _isSystemAsset)
         : owner(_owner)
         , name(_name)
         , id(_id)
         , largestTypeId(0)
         , bags(NULL)
         , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
+        , isSystemAsset(_isSystemAsset)
     { }
 
     ~PackageGroup() {
@@ -3178,6 +3181,10 @@
     // by having these tables in a per-package scope rather than
     // per-package-group.
     DynamicRefTable                 dynamicRefTable;
+
+    // If the package group comes from a system asset. Used in
+    // determining non-system locales.
+    const bool                      isSystemAsset;
 };
 
 struct ResTable::bag_set
@@ -3572,8 +3579,9 @@
             copyData);
 }
 
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
-        bool appAsLib) {
+status_t ResTable::add(
+        Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+        bool appAsLib, bool isSystemAsset) {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
         ALOGW("Unable to get buffer of resource asset file");
@@ -3592,20 +3600,21 @@
     }
 
     return addInternal(data, static_cast<size_t>(asset->getLength()),
-            idmapData, idmapSize, appAsLib, cookie, copyData);
+            idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
 }
 
-status_t ResTable::add(ResTable* src)
+status_t ResTable::add(ResTable* src, bool isSystemAsset)
 {
     mError = src->mError;
 
-    for (size_t i=0; i<src->mHeaders.size(); i++) {
+    for (size_t i=0; i < src->mHeaders.size(); i++) {
         mHeaders.add(src->mHeaders[i]);
     }
 
-    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+    for (size_t i=0; i < src->mPackageGroups.size(); i++) {
         PackageGroup* srcPg = src->mPackageGroups[i];
-        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
+        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
+                false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset);
         for (size_t j=0; j<srcPg->packages.size(); j++) {
             pg->packages.add(srcPg->packages[j]);
         }
@@ -3646,7 +3655,7 @@
 }
 
 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
-        bool appAsLib, const int32_t cookie, bool copyData)
+        bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
 {
     if (!data) {
         return NO_ERROR;
@@ -3749,7 +3758,8 @@
                 return (mError=BAD_TYPE);
             }
 
-            if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
+            if (parsePackage(
+                    (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -5663,7 +5673,7 @@
 }
 
 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
-        bool ignoreAndroidPackage) const {
+        bool ignoreAndroidPackage, bool includeSystemConfigs) const {
     const size_t packageCount = mPackageGroups.size();
     String16 android("android");
     for (size_t i = 0; i < packageCount; i++) {
@@ -5671,6 +5681,9 @@
         if (ignoreAndroidPackage && android == packageGroup->name) {
             continue;
         }
+        if (!includeSystemConfigs && packageGroup->isSystemAsset) {
+            continue;
+        }
         const size_t typeCount = packageGroup->types.size();
         for (size_t j = 0; j < typeCount; j++) {
             const TypeList& typeList = packageGroup->types[j];
@@ -5707,11 +5720,14 @@
     }
 }
 
-void ResTable::getLocales(Vector<String8>* locales) const
+void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     Vector<ResTable_config> configs;
     ALOGV("calling getConfigurations");
-    getConfigurations(&configs);
+    getConfigurations(&configs,
+            false /* ignoreMipmap */,
+            false /* ignoreAndroidPackage */,
+            includeSystemLocales /* includeSystemConfigs */);
     ALOGV("called getConfigurations size=%d", (int)configs.size());
     const size_t I = configs.size();
 
@@ -5937,7 +5953,7 @@
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header, bool appAsLib)
+                                const Header* const header, bool appAsLib, bool isSystemAsset)
 {
     const uint8_t* base = (const uint8_t*)pkg;
     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5985,8 +6001,8 @@
     if (id >= 256) {
         LOG_ALWAYS_FATAL("Package id out of range");
         return NO_ERROR;
-    } else if (id == 0 || appAsLib) {
-        // This is a library so assign an ID
+    } else if (id == 0 || appAsLib || isSystemAsset) {
+        // This is a library or a system asset, so assign an ID
         id = mNextPackageId++;
     }
 
@@ -6018,7 +6034,7 @@
 
         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
-        group = new PackageGroup(this, String16(tmpName), id, appAsLib);
+        group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset);
         if (group == NULL) {
             delete package;
             return (mError=NO_MEMORY);