diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/androidfw/Asset.cpp | 18 | ||||
-rw-r--r-- | libs/androidfw/AssetManager.cpp | 335 | ||||
-rw-r--r-- | libs/androidfw/BackupData.cpp | 2 | ||||
-rw-r--r-- | libs/androidfw/BackupHelpers.cpp | 14 | ||||
-rw-r--r-- | libs/androidfw/CursorWindow.cpp | 16 | ||||
-rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 697 | ||||
-rw-r--r-- | libs/androidfw/ZipUtils.cpp | 4 | ||||
-rw-r--r-- | libs/androidfw/tests/Android.mk | 3 | ||||
-rw-r--r-- | libs/androidfw/tests/ResourceTypes_test.cpp | 185 | ||||
-rw-r--r-- | libs/hwui/AssetAtlas.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/AssetAtlas.h | 4 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 2 | ||||
-rw-r--r-- | libs/hwui/Patch.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/Patch.h | 2 | ||||
-rw-r--r-- | libs/hwui/PatchCache.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/PathCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/PixelBuffer.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 30 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/font/Font.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/utils/TinyHashMap.h | 6 |
21 files changed, 908 insertions, 453 deletions
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index ce6cc38..589211f 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -72,7 +72,7 @@ String8 Asset::getAssetAllocations() } cur = cur->mNext; } - + return res; } @@ -84,18 +84,18 @@ Asset::Asset(void) mNext = mPrev = NULL; if (gTail == NULL) { gHead = gTail = this; - } else { - mPrev = gTail; - gTail->mNext = this; - gTail = this; - } + } else { + mPrev = gTail; + gTail->mNext = this; + gTail = this; + } //ALOGI("Creating Asset %p #%d\n", this, gCount); } Asset::~Asset(void) { AutoMutex _l(gAssetLock); - gCount--; + gCount--; if (gHead == this) { gHead = mNext; } @@ -409,7 +409,7 @@ status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, siz } mFileName = fileName != NULL ? strdup(fileName) : NULL; - + return NO_ERROR; } @@ -538,7 +538,7 @@ void _FileAsset::close(void) free(mFileName); mFileName = NULL; } - + if (mFp != NULL) { // can only be NULL when called from destructor // (otherwise we would never return this object) diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 52ab361..b4d482a 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -41,10 +41,8 @@ #include <assert.h> #include <dirent.h> #include <errno.h> -#include <fcntl.h> +#include <string.h> // strerror #include <strings.h> -#include <sys/stat.h> -#include <unistd.h> #ifndef TEMP_FAILURE_RETRY /* Used to retry syscalls that can return EINTR. */ @@ -75,7 +73,7 @@ static const char* kDefaultVendor = "default"; static const char* kAssetsRoot = "assets"; static const char* kAppZipName = NULL; //"classes.jar"; static const char* kSystemAssets = "framework/framework-res.apk"; -static const char* kIdmapCacheDir = "resource-cache"; +static const char* kResourceCache = "resource-cache"; static const char* kExcludeExtension = ".EXCLUDE"; @@ -83,14 +81,20 @@ static Asset* const kExcludedAsset = (Asset*) 0xd000000d; static volatile int32_t gCount = 0; +const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; +const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; +const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; +const char* AssetManager::TARGET_PACKAGE_NAME = "android"; +const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; +const char* AssetManager::IDMAP_DIR = "/data/resource-cache"; + namespace { - // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap String8 idmapPathForPackagePath(const String8& pkgPath) { const char* root = getenv("ANDROID_DATA"); LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set"); String8 path(root); - path.appendPath(kIdmapCacheDir); + path.appendPath(kResourceCache); char buf[256]; // 256 chars should be enough for anyone... strncpy(buf, pkgPath.string(), 255); @@ -208,180 +212,99 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie) *cookie = static_cast<int32_t>(mAssetPaths.size()); } - // add overlay packages for /system/framework; apps are handled by the - // (Java) package manager - if (strncmp(path.string(), "/system/framework/", 18) == 0) { - // When there is an environment variable for /vendor, this - // should be changed to something similar to how ANDROID_ROOT - // and ANDROID_DATA are used in this file. - String8 overlayPath("/vendor/overlay/framework/"); - overlayPath.append(path.getPathLeaf()); - if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) { - asset_path oap; - oap.path = overlayPath; - oap.type = ::getFileType(overlayPath.string()); - bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay - if (addOverlay) { - oap.idmap = idmapPathForPackagePath(overlayPath); - - if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) { - addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap); - } - } - if (addOverlay) { - mAssetPaths.add(oap); - } else { - ALOGW("failed to add overlay package %s\n", overlayPath.string()); - } - } +#ifdef HAVE_ANDROID_OS + // Load overlays, if any + asset_path oap; + for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) { + mAssetPaths.add(oap); } +#endif return true; } -bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath) +bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie) { - struct stat st; - if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) { - if (errno == ENOENT) { - return true; // non-existing idmap is always stale - } else { - ALOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno)); - return false; - } - } - if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) { - ALOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size); - return false; - } - int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY)); - if (fd == -1) { - ALOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno)); + const String8 idmapPath = idmapPathForPackagePath(packagePath); + + AutoMutex _l(mLock); + + for (size_t i = 0; i < mAssetPaths.size(); ++i) { + if (mAssetPaths[i].idmap == idmapPath) { + *cookie = static_cast<int32_t>(i + 1); + return true; + } + } + + Asset* idmap = NULL; + if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) { + ALOGW("failed to open idmap file %s\n", idmapPath.string()); return false; } - char buf[ResTable::IDMAP_HEADER_SIZE_BYTES]; - ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES; - for (;;) { - ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft, - bytesLeft)); - if (r < 0) { - TEMP_FAILURE_RETRY(close(fd)); - return false; - } - bytesLeft -= r; - if (bytesLeft == 0) { - break; - } - } - TEMP_FAILURE_RETRY(close(fd)); - uint32_t cachedOriginalCrc, cachedOverlayCrc; - if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES, - &cachedOriginalCrc, &cachedOverlayCrc)) { + String8 targetPath; + String8 overlayPath; + if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(), + NULL, NULL, &targetPath, &overlayPath)) { + ALOGW("failed to read idmap file %s\n", idmapPath.string()); + delete idmap; return false; } + delete idmap; - uint32_t actualOriginalCrc, actualOverlayCrc; - if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) { + if (overlayPath != packagePath) { + ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n", + idmapPath.string(), packagePath.string(), overlayPath.string()); return false; } - if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) { + if (access(targetPath.string(), R_OK) != 0) { + ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno)); return false; } - return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc; -} - -bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, - uint32_t* pCrc) -{ - asset_path ap; - ap.path = zipPath; - const ZipFileRO* zip = getZipFileLocked(ap); - if (zip == NULL) { + if (access(idmapPath.string(), R_OK) != 0) { + ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno)); return false; } - const ZipEntryRO entry = zip->findEntryByName(entryFilename); - if (entry == NULL) { + if (access(overlayPath.string(), R_OK) != 0) { + ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno)); return false; } - const bool gotInfo = zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc); - zip->releaseEntry(entry); + asset_path oap; + oap.path = overlayPath; + oap.type = ::getFileType(overlayPath.string()); + oap.idmap = idmapPath; +#if 0 + ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n", + targetPath.string(), overlayPath.string(), idmapPath.string()); +#endif + mAssetPaths.add(oap); + *cookie = static_cast<int32_t>(mAssetPaths.size()); - return gotInfo; -} + return true; + } -bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath) +bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath, + uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize) { - ALOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n", - __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string()); + AutoMutex _l(mLock); + const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) }; ResTable tables[2]; - const String8* paths[2] = { &originalPath, &overlayPath }; - uint32_t originalCrc, overlayCrc; - bool retval = false; - ssize_t offset = 0; - int fd = 0; - uint32_t* data = NULL; - size_t size; for (int i = 0; i < 2; ++i) { asset_path ap; ap.type = kFileTypeRegular; - ap.path = *paths[i]; + ap.path = paths[i]; Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); if (ass == NULL) { ALOGW("failed to find resources.arsc in %s\n", ap.path.string()); - goto error; - } - tables[i].add(ass, (void*)1, false); - } - - if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) { - ALOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string()); - goto error; - } - if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) { - ALOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string()); - goto error; - } - - if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc, - (void**)&data, &size) != NO_ERROR) { - ALOGW("failed to generate idmap data for file %s\n", idmapPath.string()); - goto error; - } - - // This should be abstracted (eg replaced by a stand-alone - // application like dexopt, triggered by something equivalent to - // installd). - fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644)); - if (fd == -1) { - ALOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno)); - goto error_free; - } - for (;;) { - ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size)); - if (written < 0) { - ALOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(), - strerror(errno)); - goto error_close; - } - size -= (size_t)written; - offset += written; - if (size == 0) { - break; + return false; } + tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */); } - retval = true; -error_close: - TEMP_FAILURE_RETRY(close(fd)); -error_free: - free(data); -error: - return retval; + return tables[0].createIdmap(tables[1], targetCrc, overlayCrc, + targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; } bool AssetManager::addDefaultAssets() @@ -463,17 +386,8 @@ void AssetManager::setConfiguration(const ResTable_config& config, const char* l if (locale) { setLocaleLocked(locale); } else if (config.language[0] != 0) { - char spec[9]; - spec[0] = config.language[0]; - spec[1] = config.language[1]; - if (config.country[0] != 0) { - spec[2] = '_'; - spec[3] = config.country[0]; - spec[4] = config.country[1]; - spec[5] = 0; - } else { - spec[3] = 0; - } + char spec[RESTABLE_MAX_LOCALE_LEN]; + config.getBcp47Locale(spec); setLocaleLocked(spec); } else { updateResourceParamsLocked(); @@ -660,6 +574,10 @@ const ResTable* AssetManager::getResTable(bool required) const // which we want to avoid parsing every time. sharedRes = const_cast<AssetManager*>(this)-> mZipSet.getZipResourceTable(ap.path); + if (sharedRes != NULL) { + // skip ahead the number of system overlay packages preloaded + i += sharedRes->getTableCount() - 1; + } } if (sharedRes == NULL) { ass = const_cast<AssetManager*>(this)-> @@ -682,7 +600,15 @@ const ResTable* AssetManager::getResTable(bool required) const // can quickly copy it out for others. ALOGV("Creating shared resources for %s", ap.path.string()); sharedRes = new ResTable(); - sharedRes->add(ass, (void*)(i+1), false, idmap); + sharedRes->add(ass, i + 1, false, idmap); +#ifdef HAVE_ANDROID_OS + const char* data = getenv("ANDROID_DATA"); + LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set"); + String8 overlaysListPath(data); + overlaysListPath.appendPath(kResourceCache); + overlaysListPath.appendPath("overlays.list"); + addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, i); +#endif sharedRes = const_cast<AssetManager*>(this)-> mZipSet.setZipResourceTable(ap.path, sharedRes); } @@ -706,7 +632,7 @@ const ResTable* AssetManager::getResTable(bool required) const rt->add(sharedRes); } else { ALOGV("Parsing resources for %s", ap.path.string()); - rt->add(ass, (void*)(i+1), !shared, idmap); + rt->add(ass, i + 1, !shared, idmap); } if (!shared) { @@ -733,20 +659,11 @@ void AssetManager::updateResourceParamsLocked() const return; } - size_t llen = mLocale ? strlen(mLocale) : 0; - mConfig->language[0] = 0; - mConfig->language[1] = 0; - mConfig->country[0] = 0; - mConfig->country[1] = 0; - if (llen >= 2) { - mConfig->language[0] = mLocale[0]; - mConfig->language[1] = mLocale[1]; - } - if (llen >= 5) { - mConfig->country[0] = mLocale[3]; - mConfig->country[1] = mLocale[4]; + if (mLocale) { + mConfig->setBcp47Locale(mLocale); + } else { + mConfig->clearLocale(); } - mConfig->size = sizeof(*mConfig); res->setParameters(mConfig); } @@ -766,6 +683,46 @@ Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const return ass; } +void AssetManager::addSystemOverlays(const char* pathOverlaysList, + const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const +{ + FILE* fin = fopen(pathOverlaysList, "r"); + if (fin == NULL) { + return; + } + + char buf[1024]; + while (fgets(buf, sizeof(buf), fin)) { + // format of each line: + // <path to apk><space><path to idmap><newline> + char* space = strchr(buf, ' '); + char* newline = strchr(buf, '\n'); + asset_path oap; + + if (space == NULL || newline == NULL || newline < space) { + continue; + } + + oap.path = String8(buf, space - buf); + oap.type = kFileTypeRegular; + oap.idmap = String8(space + 1, newline - space - 1); + + Asset* oass = const_cast<AssetManager*>(this)-> + openNonAssetInPathLocked("resources.arsc", + Asset::ACCESS_BUFFER, + oap); + + if (oass != NULL) { + Asset* oidmap = openIdmapLocked(oap); + offset++; + sharedRes->add(oass, offset + 1, false, oidmap); + const_cast<AssetManager*>(this)->mAssetPaths.add(oap); + const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap); + } + } + fclose(fin); +} + const ResTable& AssetManager::getResources(bool required) const { const ResTable* rt = getResTable(required); @@ -1824,7 +1781,8 @@ AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen) } } -sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path) +sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path, + bool createIfNotPresent) { AutoMutex _l(gLock); time_t modWhen = getFileModDate(path); @@ -1832,6 +1790,9 @@ sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path) if (zip != NULL && zip->mModWhen == modWhen) { return zip; } + if (zip == NULL && !createIfNotPresent) { + return NULL; + } zip = new SharedZip(path, modWhen); gOpen.add(path, zip); return zip; @@ -1890,6 +1851,20 @@ bool AssetManager::SharedZip::isUpToDate() return mModWhen == modWhen; } +void AssetManager::SharedZip::addOverlay(const asset_path& ap) +{ + mOverlays.add(ap); +} + +bool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const +{ + if (idx >= mOverlays.size()) { + return false; + } + *out = mOverlays[idx]; + return true; +} + AssetManager::SharedZip::~SharedZip() { //ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath); @@ -2013,6 +1988,22 @@ bool AssetManager::ZipSet::isUpToDate() return true; } +void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay) +{ + int idx = getIndex(path); + sp<SharedZip> zip = mZipFile[idx]; + zip->addOverlay(overlay); +} + +bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const +{ + sp<SharedZip> zip = SharedZip::get(path, false); + if (zip == NULL) { + return false; + } + return zip->getOverlay(idx, out); +} + /* * Compute the zip file's index. * diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp index 4e3b522..2d0f755 100644 --- a/libs/androidfw/BackupData.cpp +++ b/libs/androidfw/BackupData.cpp @@ -289,7 +289,7 @@ BackupDataReader::ReadNextHeader(bool* done, int* type) (int)(m_pos - sizeof(m_header)), (int)m_header.type); m_status = EINVAL; } - + return m_status; } diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp index b8d3f48..ab837ad 100644 --- a/libs/androidfw/BackupHelpers.cpp +++ b/libs/androidfw/BackupHelpers.cpp @@ -568,8 +568,8 @@ int write_tarfile(const String8& packageName, const String8& domain, // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time // [ 116 : 8 ] gid -- ignored in Android format - snprintf(buf + 108, 8, "0%lo", s.st_uid); - snprintf(buf + 116, 8, "0%lo", s.st_gid); + snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid); + snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid); // [ 124 : 12 ] file size in bytes if (s.st_size > 077777777777LL) { @@ -778,7 +778,7 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in) ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno)); return errno; } - + while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) { err = write(fd, buf, amt); if (err != amt) { @@ -1083,7 +1083,7 @@ backup_helper_test_four() } if (readSnapshot.size() != 4) { - fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size()); + fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size()); return 1; } @@ -1095,8 +1095,8 @@ backup_helper_test_four() if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode || states[i].size != state.size || states[i].crc32 != states[i].crc32) { - fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n" - " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i, + fprintf(stderr, "state %zu expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n" + " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3zu} '%s'\n", i, states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size, states[i].crc32, name.length(), filenames[i].string(), state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32, @@ -1230,7 +1230,7 @@ test_read_header_and_entity(BackupDataReader& reader, const char* str) goto finished; } if ((int)actualSize != bufSize) { - fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize, + fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08zx\n", bufSize, actualSize); err = EINVAL; goto finished; diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp index 0f54edb..2b74a33 100644 --- a/libs/androidfw/CursorWindow.cpp +++ b/libs/androidfw/CursorWindow.cpp @@ -1,16 +1,16 @@ /* * Copyright (C) 2006-2007 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 + * 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 + * 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 + * 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. */ diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 1cc3563..652cd4a 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -66,11 +66,6 @@ namespace android { // size measured in sizeof(uint32_t) #define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t)) -static void printToLogFunc(void* cookie, const char* txt) -{ - ALOGV("%s", txt); -} - // Standard C isspace() is only required to look at the low byte of its input, so // produces incorrect results for UTF-16 characters. For safety's sake, assume that // any high-byte UTF-16 code point is not whitespace. @@ -106,24 +101,29 @@ static status_t validate_chunk(const ResChunk_header* chunk, if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) { return NO_ERROR; } - ALOGW("%s data size %p extends beyond resource end %p.", - name, (void*)size, - (void*)(dataEnd-((const uint8_t*)chunk))); + ALOGW("%s data size 0x%x extends beyond resource end %p.", + name, size, (void*)(dataEnd-((const uint8_t*)chunk))); return BAD_TYPE; } ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.", name, (int)size, (int)headerSize); return BAD_TYPE; } - ALOGW("%s size %p is smaller than header size %p.", - name, (void*)size, (void*)(int)headerSize); + ALOGW("%s size 0x%x is smaller than header size 0x%x.", + name, size, headerSize); return BAD_TYPE; } - ALOGW("%s header size %p is too small.", - name, (void*)(int)headerSize); + ALOGW("%s header size 0x%x is too small.", + name, headerSize); return BAD_TYPE; } +static void fill9patchOffsets(Res_png_9patch* patch) { + patch->xDivsOffset = sizeof(Res_png_9patch); + patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t)); + patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t)); +} + inline void Res_value::copyFrom_dtoh(const Res_value& src) { size = dtohs(src.size); @@ -134,9 +134,11 @@ inline void Res_value::copyFrom_dtoh(const Res_value& src) void Res_png_9patch::deviceToFile() { + int32_t* xDivs = getXDivs(); for (int i = 0; i < numXDivs; i++) { xDivs[i] = htonl(xDivs[i]); } + int32_t* yDivs = getYDivs(); for (int i = 0; i < numYDivs; i++) { yDivs[i] = htonl(yDivs[i]); } @@ -144,6 +146,7 @@ void Res_png_9patch::deviceToFile() paddingRight = htonl(paddingRight); paddingTop = htonl(paddingTop); paddingBottom = htonl(paddingBottom); + uint32_t* colors = getColors(); for (int i=0; i<numColors; i++) { colors[i] = htonl(colors[i]); } @@ -151,9 +154,11 @@ void Res_png_9patch::deviceToFile() void Res_png_9patch::fileToDevice() { + int32_t* xDivs = getXDivs(); for (int i = 0; i < numXDivs; i++) { xDivs[i] = ntohl(xDivs[i]); } + int32_t* yDivs = getYDivs(); for (int i = 0; i < numYDivs; i++) { yDivs[i] = ntohl(yDivs[i]); } @@ -161,60 +166,49 @@ void Res_png_9patch::fileToDevice() paddingRight = ntohl(paddingRight); paddingTop = ntohl(paddingTop); paddingBottom = ntohl(paddingBottom); + uint32_t* colors = getColors(); for (int i=0; i<numColors; i++) { colors[i] = ntohl(colors[i]); } } -size_t Res_png_9patch::serializedSize() +size_t Res_png_9patch::serializedSize() const { // The size of this struct is 32 bytes on the 32-bit target system // 4 * int8_t // 4 * int32_t - // 3 * pointer + // 3 * uint32_t return 32 + numXDivs * sizeof(int32_t) + numYDivs * sizeof(int32_t) + numColors * sizeof(uint32_t); } -void* Res_png_9patch::serialize() +void* Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs, + const int32_t* yDivs, const uint32_t* colors) { // Use calloc since we're going to leave a few holes in the data // and want this to run cleanly under valgrind - void* newData = calloc(1, serializedSize()); - serialize(newData); + void* newData = calloc(1, patch.serializedSize()); + serialize(patch, xDivs, yDivs, colors, newData); return newData; } -void Res_png_9patch::serialize(void * outData) +void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs, + const int32_t* yDivs, const uint32_t* colors, void* outData) { - char* data = (char*) outData; - memmove(data, &wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - memmove(data + 12, &paddingLeft, 16); // copy paddingXXXX + uint8_t* data = (uint8_t*) outData; + memcpy(data, &patch.wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors + memcpy(data + 12, &patch.paddingLeft, 16); // copy paddingXXXX data += 32; - memmove(data, this->xDivs, numXDivs * sizeof(int32_t)); - data += numXDivs * sizeof(int32_t); - memmove(data, this->yDivs, numYDivs * sizeof(int32_t)); - data += numYDivs * sizeof(int32_t); - memmove(data, this->colors, numColors * sizeof(uint32_t)); -} + memcpy(data, xDivs, patch.numXDivs * sizeof(int32_t)); + data += patch.numXDivs * sizeof(int32_t); + memcpy(data, yDivs, patch.numYDivs * sizeof(int32_t)); + data += patch.numYDivs * sizeof(int32_t); + memcpy(data, colors, patch.numColors * sizeof(uint32_t)); -static void deserializeInternal(const void* inData, Res_png_9patch* outData) { - char* patch = (char*) inData; - if (inData != outData) { - memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - } - outData->wasDeserialized = true; - char* data = (char*)outData; - data += sizeof(Res_png_9patch); - outData->xDivs = (int32_t*) data; - data += outData->numXDivs * sizeof(int32_t); - outData->yDivs = (int32_t*) data; - data += outData->numYDivs * sizeof(int32_t); - outData->colors = (uint32_t*) data; + fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData)); } static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes) @@ -284,22 +278,48 @@ static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t if (!assertIdmapHeader(map, mapSize)) { return UNKNOWN_ERROR; } + if (mapSize <= IDMAP_HEADER_SIZE + 1) { + ALOGW("corrupt idmap: map size %d too short\n", mapSize); + return UNKNOWN_ERROR; + } + uint32_t typeCount = *(map + IDMAP_HEADER_SIZE); + if (typeCount == 0) { + ALOGW("corrupt idmap: no types\n"); + return UNKNOWN_ERROR; + } + if (IDMAP_HEADER_SIZE + 1 + typeCount > mapSize) { + ALOGW("corrupt idmap: number of types %d extends past idmap size %d\n", typeCount, mapSize); + return UNKNOWN_ERROR; + } const uint32_t* p = map + IDMAP_HEADER_SIZE + 1; + // find first defined type while (*p == 0) { ++p; + if (--typeCount == 0) { + ALOGW("corrupt idmap: types declared, none found\n"); + return UNKNOWN_ERROR; + } + } + + // determine package id from first entry of first type + const uint32_t offset = *p + IDMAP_HEADER_SIZE + 2; + if (offset > mapSize) { + ALOGW("corrupt idmap: entry offset %d points outside map size %d\n", offset, mapSize); + return UNKNOWN_ERROR; } - *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff; + *outId = (map[offset] >> 24) & 0x000000ff; + return NO_ERROR; } -Res_png_9patch* Res_png_9patch::deserialize(const void* inData) +Res_png_9patch* Res_png_9patch::deserialize(void* inData) { - if (sizeof(void*) != sizeof(int32_t)) { - ALOGE("Cannot deserialize on non 32-bit system\n"); - return NULL; - } - deserializeInternal(inData, (Res_png_9patch*) inData); - return (Res_png_9patch*) inData; + + Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(inData); + patch->wasDeserialized = true; + fill9patchOffsets(patch); + + return patch; } // -------------------------------------------------------------------- @@ -1246,7 +1266,7 @@ ResXMLParser::event_code_t ResXMLParser::nextNode() const ResXMLTree_node* next = (const ResXMLTree_node*) (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size)); //ALOGW("Next node: prev=%p, next=%p\n", mCurNode, next); - + if (((const uint8_t*)next) >= mTree.mDataEnd) { mCurNode = NULL; return (mEventCode=END_DOCUMENT); @@ -1283,7 +1303,7 @@ ResXMLParser::event_code_t ResXMLParser::nextNode() (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader))); continue; } - + if ((totalSize-headerSize) < minExtSize) { ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n", (int)dtohs(next->header.type), @@ -1291,10 +1311,10 @@ ResXMLParser::event_code_t ResXMLParser::nextNode() (int)(totalSize-headerSize), (int)minExtSize); return (mEventCode=BAD_DOCUMENT); } - + //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n", // mCurNode, mCurExt, headerSize, minExtSize); - + return eventCode; } while (true); } @@ -1539,6 +1559,71 @@ void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) { } } +/* static */ size_t unpackLanguageOrRegion(const char in[2], const char base, + char out[4]) { + if (in[0] & 0x80) { + // The high bit is "1", which means this is a packed three letter + // language code. + + // The smallest 5 bits of the second char are the first alphabet. + const uint8_t first = in[1] & 0x1f; + // The last three bits of the second char and the first two bits + // of the first char are the second alphabet. + const uint8_t second = ((in[1] & 0xe0) >> 5) + ((in[0] & 0x03) << 3); + // Bits 3 to 7 (inclusive) of the first char are the third alphabet. + const uint8_t third = (in[0] & 0x7c) >> 2; + + out[0] = first + base; + out[1] = second + base; + out[2] = third + base; + out[3] = 0; + + return 3; + } + + if (in[0]) { + memcpy(out, in, 2); + memset(out + 2, 0, 2); + return 2; + } + + memset(out, 0, 4); + return 0; +} + +/* static */ void packLanguageOrRegion(const char* in, const char base, + char out[2]) { + if (in[2] == 0 || in[2] == '-') { + out[0] = in[0]; + out[1] = in[1]; + } else { + uint8_t first = (in[0] - base) & 0x00ef; + uint8_t second = (in[1] - base) & 0x00ef; + uint8_t third = (in[2] - base) & 0x00ef; + + out[0] = (0x80 | (third << 2) | (second >> 3)); + out[1] = ((second << 5) | first); + } +} + + +void ResTable_config::packLanguage(const char* language) { + packLanguageOrRegion(language, 'a', this->language); +} + +void ResTable_config::packRegion(const char* region) { + packLanguageOrRegion(region, '0', this->country); +} + +size_t ResTable_config::unpackLanguage(char language[4]) const { + return unpackLanguageOrRegion(this->language, 'a', language); +} + +size_t ResTable_config::unpackRegion(char region[4]) const { + return unpackLanguageOrRegion(this->country, '0', region); +} + + void ResTable_config::copyFromDtoH(const ResTable_config& o) { copyFromDeviceNoSwap(o); size = sizeof(ResTable_config); @@ -1568,10 +1653,30 @@ void ResTable_config::swapHtoD() { screenHeightDp = htods(screenHeightDp); } +/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) { + if (l.locale != r.locale) { + // NOTE: This is the old behaviour with respect to comparison orders. + // The diff value here doesn't make much sense (given our bit packing scheme) + // but it's stable, and that's all we need. + return l.locale - r.locale; + } + + // The language & region are equal, so compare the scripts and variants. + int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript)); + if (script) { + return script; + } + + // The language, region and script are equal, so compare variants. + // + // This should happen very infrequently (if at all.) + return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant)); +} + int ResTable_config::compare(const ResTable_config& o) const { int32_t diff = (int32_t)(imsi - o.imsi); if (diff != 0) return diff; - diff = (int32_t)(locale - o.locale); + diff = compareLocales(*this, o); if (diff != 0) return diff; diff = (int32_t)(screenType - o.screenType); if (diff != 0) return diff; @@ -1598,18 +1703,15 @@ int ResTable_config::compareLogical(const ResTable_config& o) const { if (mnc != o.mnc) { return mnc < o.mnc ? -1 : 1; } - if (language[0] != o.language[0]) { - return language[0] < o.language[0] ? -1 : 1; - } - if (language[1] != o.language[1]) { - return language[1] < o.language[1] ? -1 : 1; - } - if (country[0] != o.country[0]) { - return country[0] < o.country[0] ? -1 : 1; + + int diff = compareLocales(*this, o); + if (diff < 0) { + return -1; } - if (country[1] != o.country[1]) { - return country[1] < o.country[1] ? -1 : 1; + if (diff > 0) { + return 1; } + if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) { return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1; } @@ -1656,7 +1758,6 @@ int ResTable_config::diff(const ResTable_config& o) const { int diffs = 0; if (mcc != o.mcc) diffs |= CONFIG_MCC; if (mnc != o.mnc) diffs |= CONFIG_MNC; - if (locale != o.locale) diffs |= CONFIG_LOCALE; if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION; if (density != o.density) diffs |= CONFIG_DENSITY; if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN; @@ -1671,9 +1772,44 @@ int ResTable_config::diff(const ResTable_config& o) const { if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE; if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE; if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE; + + const int diff = compareLocales(*this, o); + if (diff) diffs |= CONFIG_LOCALE; + return diffs; } +int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const { + if (locale || o.locale) { + if (language[0] != o.language[0]) { + if (!language[0]) return -1; + if (!o.language[0]) return 1; + } + + if (country[0] != o.country[0]) { + if (!country[0]) return -1; + if (!o.country[0]) return 1; + } + } + + // There isn't a well specified "importance" order between variants and + // scripts. We can't easily tell whether, say "en-Latn-US" is more or less + // specific than "en-US-POSIX". + // + // We therefore arbitrarily decide to give priority to variants over + // scripts since it seems more useful to do so. We will consider + // "en-US-POSIX" to be more specific than "en-Latn-US". + + const int score = ((localeScript[0] != 0) ? 1 : 0) + + ((localeVariant[0] != 0) ? 2 : 0); + + const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) + + ((o.localeVariant[0] != 0) ? 2 : 0); + + return score - oScore; + +} + bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const { // The order of the following tests defines the importance of one // configuration parameter over another. Those tests first are more @@ -1691,14 +1827,13 @@ bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const { } if (locale || o.locale) { - if (language[0] != o.language[0]) { - if (!language[0]) return false; - if (!o.language[0]) return true; + const int diff = isLocaleMoreSpecificThan(o); + if (diff < 0) { + return false; } - if (country[0] != o.country[0]) { - if (!country[0]) return false; - if (!o.country[0]) return true; + if (diff > 0) { + return true; } } @@ -1834,6 +1969,18 @@ bool ResTable_config::isBetterThan(const ResTable_config& o, } } + if (localeScript[0] || o.localeScript[0]) { + if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) { + return localeScript[0]; + } + } + + if (localeVariant[0] || o.localeVariant[0]) { + if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) { + return localeVariant[0]; + } + } + if (screenLayout || o.screenLayout) { if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0 && (requested->screenLayout & MASK_LAYOUTDIR)) { @@ -2054,17 +2201,23 @@ bool ResTable_config::match(const ResTable_config& settings) const { } } if (locale != 0) { + // Don't consider the script & variants when deciding matches. + // + // If we two configs differ only in their script or language, they + // can be weeded out in the isMoreSpecificThan test. if (language[0] != 0 && (language[0] != settings.language[0] || language[1] != settings.language[1])) { return false; } + if (country[0] != 0 && (country[0] != settings.country[0] || country[1] != settings.country[1])) { return false; } } + if (screenConfig != 0) { const int layoutDir = screenLayout&MASK_LAYOUTDIR; const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR; @@ -2166,19 +2319,94 @@ bool ResTable_config::match(const ResTable_config& settings) const { return true; } -void ResTable_config::getLocale(char str[6]) const { - memset(str, 0, 6); +void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const { + memset(str, 0, RESTABLE_MAX_LOCALE_LEN); + + // This represents the "any" locale value, which has traditionally been + // represented by the empty string. + if (!language[0] && !country[0]) { + return; + } + + size_t charsWritten = 0; if (language[0]) { - str[0] = language[0]; - str[1] = language[1]; - if (country[0]) { - str[2] = '_'; - str[3] = country[0]; - str[4] = country[1]; + charsWritten += unpackLanguage(str); + } + + if (localeScript[0]) { + if (charsWritten) { + str[charsWritten++] = '-'; + } + memcpy(str + charsWritten, localeScript, sizeof(localeScript)); + charsWritten += sizeof(localeScript); + } + + if (country[0]) { + if (charsWritten) { + str[charsWritten++] = '-'; + } + charsWritten += unpackRegion(str + charsWritten); + } + + if (localeVariant[0]) { + if (charsWritten) { + str[charsWritten++] = '-'; } + memcpy(str + charsWritten, localeVariant, sizeof(localeVariant)); } } +/* static */ inline bool assignLocaleComponent(ResTable_config* config, + const char* start, size_t size) { + + switch (size) { + case 0: + return false; + case 2: + case 3: + config->language[0] ? config->packRegion(start) : config->packLanguage(start); + break; + case 4: + config->localeScript[0] = toupper(start[0]); + for (size_t i = 1; i < 4; ++i) { + config->localeScript[i] = tolower(start[i]); + } + break; + case 5: + case 6: + case 7: + case 8: + for (size_t i = 0; i < size; ++i) { + config->localeVariant[i] = tolower(start[i]); + } + break; + default: + return false; + } + + return true; +} + +void ResTable_config::setBcp47Locale(const char* in) { + locale = 0; + memset(localeScript, 0, sizeof(localeScript)); + memset(localeVariant, 0, sizeof(localeVariant)); + + const char* separator = in; + const char* start = in; + while ((separator = strchr(start, '-')) != NULL) { + const size_t size = separator - start; + if (!assignLocaleComponent(this, start, size)) { + fprintf(stderr, "Invalid BCP-47 locale string: %s", in); + } + + start = (separator + 1); + } + + const size_t size = in + strlen(in) - start; + assignLocaleComponent(this, start, size); +} + String8 ResTable_config::toString() const { String8 res; @@ -2190,14 +2418,10 @@ String8 ResTable_config::toString() const { if (res.size() > 0) res.append("-"); res.appendFormat("%dmnc", dtohs(mnc)); } - if (language[0] != 0) { - if (res.size() > 0) res.append("-"); - res.append(language, 2); - } - if (country[0] != 0) { - if (res.size() > 0) res.append("-"); - res.append(country, 2); - } + char localeStr[RESTABLE_MAX_LOCALE_LEN]; + getBcp47Locale(localeStr); + res.append(localeStr); + if ((screenLayout&MASK_LAYOUTDIR) != 0) { if (res.size() > 0) res.append("-"); switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) { @@ -2461,7 +2685,7 @@ struct ResTable::Header size_t size; const uint8_t* dataEnd; size_t index; - void* cookie; + int32_t cookie; ResStringPool values; uint32_t* resourceIDMap; @@ -2493,7 +2717,7 @@ struct ResTable::Package delete types[i]; } } - + ResTable* const owner; const Header* const header; const ResTable_package* const package; @@ -2501,7 +2725,7 @@ struct ResTable::Package ResStringPool typeStrings; ResStringPool keyStrings; - + const Type* getType(size_t idx) const { return idx < types.size() ? types[idx] : NULL; } @@ -2551,18 +2775,18 @@ struct ResTable::PackageGroup bags = NULL; } } - + ResTable* const owner; String16 const name; uint32_t const id; Vector<Package*> packages; - + // This is for finding typeStrings and other common package stuff. Package* basePackage; // For quick access. size_t typeCount; - + // Computed attribute bags, first indexed by the type and second // by the entry in that type. bag_set*** bags; @@ -2711,7 +2935,7 @@ status_t ResTable::Theme::applyStyle(uint32_t resID, bool force) //ALOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this); //dumpToLog(); - + return NO_ERROR; } @@ -2720,7 +2944,7 @@ status_t ResTable::Theme::setTo(const Theme& other) //ALOGI("Setting theme %p from theme %p...\n", this, &other); //dumpToLog(); //other.dumpToLog(); - + if (&mTable == &other.mTable) { for (size_t i=0; i<Res_MAXPACKAGE; i++) { if (mPackages[i] != NULL) { @@ -2750,7 +2974,7 @@ status_t ResTable::Theme::setTo(const Theme& other) //ALOGI("Final theme:"); //dumpToLog(); - + return NO_ERROR; } @@ -2760,7 +2984,7 @@ ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue, int cnt = 20; if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0; - + do { const ssize_t p = mTable.getResourcePackageIndex(resID); const uint32_t t = Res_GETTYPE(resID); @@ -2834,12 +3058,12 @@ void ResTable::Theme::dumpToLog() const for (size_t i=0; i<Res_MAXPACKAGE; i++) { package_info* pi = mPackages[i]; if (pi == NULL) continue; - + ALOGI(" Package #0x%02x:\n", (int)(i+1)); for (size_t j=0; j<pi->numTypes; j++) { type_info& ti = pi->types[j]; if (ti.numEntries == 0) continue; - + ALOGI(" Type #0x%02x:\n", (int)(j+1)); for (size_t k=0; k<ti.numEntries; k++) { theme_entry& te = ti.entries[k]; @@ -2860,12 +3084,12 @@ ResTable::ResTable() //ALOGI("Creating ResTable %p\n", this); } -ResTable::ResTable(const void* data, size_t size, void* cookie, bool copyData) +ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData) : mError(NO_INIT) { memset(&mParams, 0, sizeof(mParams)); memset(mPackageMap, 0, sizeof(mPackageMap)); - add(data, size, cookie, copyData); + addInternal(data, size, cookie, NULL /* asset */, copyData, NULL /* idMap */); LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table"); //ALOGI("Creating ResTable %p\n", this); } @@ -2881,13 +3105,12 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1; } -status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData, - const void* idmap) -{ - return add(data, size, cookie, NULL, copyData, reinterpret_cast<const Asset*>(idmap)); +status_t ResTable::add(const void* data, size_t size) { + return addInternal(data, size, 0 /* cookie */, NULL /* asset */, + false /* copyData */, NULL /* idMap */); } -status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap) +status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData, const void* idmap) { const void* data = asset->getBuffer(true); if (data == NULL) { @@ -2895,17 +3118,18 @@ status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* id return UNKNOWN_ERROR; } size_t size = (size_t)asset->getLength(); - return add(data, size, cookie, asset, copyData, reinterpret_cast<const Asset*>(idmap)); + return addInternal(data, size, cookie, asset, copyData, + reinterpret_cast<const Asset*>(idmap)); } status_t ResTable::add(ResTable* src) { mError = src->mError; - + 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++) { PackageGroup* srcPg = src->mPackageGroups[i]; PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id); @@ -2916,14 +3140,14 @@ status_t ResTable::add(ResTable* src) pg->typeCount = srcPg->typeCount; mPackageGroups.add(pg); } - + memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap)); - + return mError; } -status_t ResTable::add(const void* data, size_t size, void* cookie, - Asset* asset, bool copyData, const Asset* idmap) +status_t ResTable::addInternal(const void* data, size_t size, const int32_t cookie, + Asset* /*asset*/, bool copyData, const Asset* idmap) { if (!data) return NO_ERROR; Header* header = new Header(this); @@ -2945,9 +3169,9 @@ status_t ResTable::add(const void* data, size_t size, void* cookie, const bool notDeviceEndian = htods(0xf0) != 0xf0; LOAD_TABLE_NOISY( - ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d " + ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, asset=%p, copy=%d " "idmap=%p\n", data, size, cookie, asset, copyData, idmap)); - + if (copyData || notDeviceEndian) { header->ownedData = malloc(size); if (header->ownedData == NULL) { @@ -3027,8 +3251,8 @@ status_t ResTable::add(const void* data, size_t size, void* cookie, } curPackage++; } else { - ALOGW("Unknown chunk type %p in table at %p.\n", - (void*)(int)(ctype), + ALOGW("Unknown chunk type 0x%x in table at %p.\n", + ctype, (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))); } chunk = (const ResChunk_header*) @@ -3244,8 +3468,8 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) { if (!mayBeBag) { - ALOGW("Requesting resource %p failed because it is complex\n", - (void*)resID); + ALOGW("Requesting resource 0x%x failed because it is complex\n", + resID); } continue; } @@ -3279,7 +3503,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag // are identical (diff == 0), or overlay packages will not take effect. continue; } - + bestItem = thisConfig; bestValue = item; bestPackage = package; @@ -3349,7 +3573,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) { if (!value) { return NULL; @@ -3372,7 +3596,7 @@ ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const return err; } -void ResTable::unlockBag(const bag_entry* bag) const +void ResTable::unlockBag(const bag_entry* /*bag*/) const { //printf("<<< unlockBag %p\n", this); mLock.unlock(); @@ -3473,7 +3697,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, bag_set* set = NULL; TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID)); - + ResTable_config bestConfig; memset(&bestConfig, 0, sizeof(bestConfig)); @@ -3520,8 +3744,8 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, } if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) { - ALOGW("Skipping entry %p in package table %d because it is not complex!\n", - (void*)resID, (int)ip); + ALOGW("Skipping entry 0x%x in package table %zu because it is not complex!\n", + resID, ip); continue; } @@ -3539,7 +3763,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0; const uint32_t count = entrySize >= sizeof(ResTable_map_entry) ? dtohl(((const ResTable_map_entry*)entry)->count) : 0; - + size_t N = count; TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n", @@ -3583,7 +3807,7 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, } else { set->typeSpecFlags = -1; } - + // Now merge in the new attributes... ssize_t curOff = offset; const ResTable_map* map; @@ -3846,7 +4070,7 @@ nope: TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n", String8(group->name).string(), ti)); } - + size_t NTC = typeConfigs->configs.size(); for (size_t tci=0; tci<NTC; tci++) { const ResTable_type* const ty = typeConfigs->configs[tci]; @@ -3862,9 +4086,9 @@ nope: if (offset == ResTable_type::NO_ENTRY) { continue; } - + offset += typeOffset; - + if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) { ALOGW("ResTable_entry at %d is beyond type chunk data %d", offset, dtohl(ty->header.size)); @@ -3878,7 +4102,7 @@ nope: String8(name, nameLen).string()); return 0; } - + const ResTable_entry* const entry = (const ResTable_entry*) (((const uint8_t*)ty) + offset); if (dtohs(entry->size) < sizeof(*entry)) { @@ -4035,7 +4259,7 @@ static bool parse_unit(const char* str, Res_value* outValue, if (*realEnd != 0) { return false; } - + const unit_entry* cur = unitNames; while (cur->name) { if (len == cur->len && strncmp(cur->name, str, len) == 0) { @@ -4186,7 +4410,7 @@ bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue) if (neg) { mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK; } - outValue->data |= + outValue->data |= (radix<<Res_value::COMPLEX_RADIX_SHIFT) | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT); //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n", @@ -4299,7 +4523,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, // Note: we don't check attrType here because the reference can // be to any other type; we just need to count on the client making // sure the referenced type is correct. - + //printf("Looking up ref: %s\n", String8(s, len).string()); // It's a reference! @@ -4386,7 +4610,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, } } } - + if (*s == '#') { // It's a color! Convert to an integer of the form 0xaarrggbb. uint32_t color = 0; @@ -4486,7 +4710,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, // String8(package).string(), String8(type).string(), // String8(name).string()); uint32_t specFlags = 0; - uint32_t rid = + uint32_t rid = identifierForName(name.string(), name.size(), type.string(), type.size(), package.string(), package.size(), &specFlags); @@ -4651,7 +4875,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, return true; } } - + } bag++; cnt--; @@ -4930,7 +5154,7 @@ const ResStringPool* ResTable::getTableStringBlock(size_t index) const return &mHeaders[index]->values; } -void* ResTable::getTableCookie(size_t index) const +int32_t ResTable::getTableCookie(size_t index) const { return mHeaders[index]->cookie; } @@ -4950,18 +5174,20 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs) const const size_t L = type->configs.size(); for (size_t l=0; l<L; l++) { const ResTable_type* config = type->configs[l]; - const ResTable_config* cfg = &config->config; + ResTable_config cfg; + memset(&cfg, 0, sizeof(ResTable_config)); + cfg.copyFromDtoH(config->config); // only insert unique const size_t M = configs->size(); size_t m; for (m=0; m<M; m++) { - if (0 == (*configs)[m].compare(*cfg)) { + if (0 == (*configs)[m].compare(cfg)) { break; } } // if we didn't find it if (m == M) { - configs->add(*cfg); + configs->add(cfg); } } } @@ -4976,9 +5202,10 @@ void ResTable::getLocales(Vector<String8>* locales) const getConfigurations(&configs); ALOGV("called getConfigurations size=%d", (int)configs.size()); const size_t I = configs.size(); + + char locale[RESTABLE_MAX_LOCALE_LEN]; for (size_t i=0; i<I; i++) { - char locale[6]; - configs[i].getLocale(locale); + configs[i].getBcp47Locale(locale); const size_t J = locales->size(); size_t j; for (j=0; j<J; j++) { @@ -5013,43 +5240,43 @@ ssize_t ResTable::getEntry( entryIndex, (int)allTypes->entryCount); return BAD_TYPE; } - + const ResTable_type* type = NULL; uint32_t offset = ResTable_type::NO_ENTRY; ResTable_config bestConfig; memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up - + const size_t NT = allTypes->configs.size(); for (size_t i=0; i<NT; i++) { const ResTable_type* const thisType = allTypes->configs[i]; if (thisType == NULL) continue; - + ResTable_config thisConfig; thisConfig.copyFromDtoH(thisType->config); TABLE_GETENTRY(ALOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n", entryIndex, typeIndex+1, dtohl(thisType->config.size), thisConfig.toString().string())); - + // Check to make sure this one is valid for the current parameters. if (config && !thisConfig.match(*config)) { TABLE_GETENTRY(ALOGI("Does not match config!\n")); continue; } - + // Check if there is the desired entry in this type. - + const uint8_t* const end = ((const uint8_t*)thisType) + dtohl(thisType->header.size); const uint32_t* const eindex = (const uint32_t*) (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize)); - + uint32_t thisOffset = dtohl(eindex[entryIndex]); if (thisOffset == ResTable_type::NO_ENTRY) { TABLE_GETENTRY(ALOGI("Skipping because it is not defined!\n")); continue; } - + if (type != NULL) { // Check if this one is less specific than the last found. If so, // we will skip it. We check starting with things we most care @@ -5059,19 +5286,19 @@ ssize_t ResTable::getEntry( continue; } } - + type = thisType; offset = thisOffset; bestConfig = thisConfig; TABLE_GETENTRY(ALOGI("Best entry so far -- using it!\n")); if (!config) break; } - + if (type == NULL) { TABLE_GETENTRY(ALOGI("No value found for requested entry!\n")); return BAD_INDEX; } - + offset += dtohl(type->entriesStart); TABLE_NOISY(aout << "Looking in resource table " << package->header->header << ", typeOff=" @@ -5114,29 +5341,29 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, return (mError=err); } - const size_t pkgSize = dtohl(pkg->header.size); + const uint32_t pkgSize = dtohl(pkg->header.size); if (dtohl(pkg->typeStrings) >= pkgSize) { - ALOGW("ResTable_package type strings at %p are past chunk size %p.", - (void*)dtohl(pkg->typeStrings), (void*)pkgSize); + ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.", + dtohl(pkg->typeStrings), pkgSize); return (mError=BAD_TYPE); } if ((dtohl(pkg->typeStrings)&0x3) != 0) { - ALOGW("ResTable_package type strings at %p is not on an integer boundary.", - (void*)dtohl(pkg->typeStrings)); + ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.", + dtohl(pkg->typeStrings)); return (mError=BAD_TYPE); } if (dtohl(pkg->keyStrings) >= pkgSize) { - ALOGW("ResTable_package key strings at %p are past chunk size %p.", - (void*)dtohl(pkg->keyStrings), (void*)pkgSize); + ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.", + dtohl(pkg->keyStrings), pkgSize); return (mError=BAD_TYPE); } if ((dtohl(pkg->keyStrings)&0x3) != 0) { - ALOGW("ResTable_package key strings at %p is not on an integer boundary.", - (void*)dtohl(pkg->keyStrings)); + ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.", + dtohl(pkg->keyStrings)); return (mError=BAD_TYPE); } - + Package* package = NULL; PackageGroup* group = NULL; uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id); @@ -5145,12 +5372,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, // always loaded alongside their idmaps, but during idmap creation // the package is temporarily loaded by itself. if (id < 256) { - + package = new Package(this, header, pkg); if (package == NULL) { return (mError=NO_MEMORY); } - + size_t idx = mPackageMap[id]; if (idx == 0) { idx = mPackageGroups.size()+1; @@ -5184,7 +5411,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, return (mError=err); } group->basePackage = package; - + mPackageMap[id] = (uint8_t)idx; } else { group = mPackageGroups.itemAt(idx-1); @@ -5201,10 +5428,10 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, return NO_ERROR; } - + // Iterate through all chunks. size_t curPackage = 0; - + const ResChunk_header* chunk = (const ResChunk_header*)(((const uint8_t*)pkg) + dtohs(pkg->header.headerSize)); @@ -5223,9 +5450,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, if (err != NO_ERROR) { return (mError=err); } - + const size_t typeSpecSize = dtohl(typeSpec->header.size); - + LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n", (void*)(base-(const uint8_t*)chunk), dtohs(typeSpec->header.type), @@ -5241,12 +5468,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, (void*)typeSpecSize); return (mError=BAD_TYPE); } - + if (typeSpec->id == 0) { ALOGW("ResTable_type has an id of 0."); return (mError=BAD_TYPE); } - + while (package->types.size() < typeSpec->id) { package->types.add(NULL); } @@ -5262,7 +5489,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, t->typeSpecFlags = (const uint32_t*)( ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize)); t->typeSpec = typeSpec; - + } else if (ctype == RES_TABLE_TYPE_TYPE) { const ResTable_type* type = (const ResTable_type*)(chunk); err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4, @@ -5270,9 +5497,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, if (err != NO_ERROR) { return (mError=err); } - - const size_t typeSize = dtohl(type->header.size); - + + const uint32_t typeSize = dtohl(type->header.size); + LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n", (void*)(base-(const uint8_t*)chunk), dtohs(type->header.type), @@ -5280,23 +5507,23 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, (void*)typeSize)); if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount)) > typeSize) { - ALOGW("ResTable_type entry index to %p extends beyond chunk end %p.", + ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.", (void*)(dtohs(type->header.headerSize) +(sizeof(uint32_t)*dtohl(type->entryCount))), - (void*)typeSize); + typeSize); return (mError=BAD_TYPE); } if (dtohl(type->entryCount) != 0 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) { - ALOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.", - (void*)dtohl(type->entriesStart), (void*)typeSize); + ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.", + dtohl(type->entriesStart), typeSize); return (mError=BAD_TYPE); } if (type->id == 0) { ALOGW("ResTable_type has an id of 0."); return (mError=BAD_TYPE); } - + while (package->types.size() < type->id) { package->types.add(NULL); } @@ -5309,7 +5536,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, (int)dtohl(type->entryCount), (int)t->entryCount); return (mError=BAD_TYPE); } - + TABLE_GETENTRY( ResTable_config thisConfig; thisConfig.copyFromDtoH(type->config); @@ -5330,27 +5557,34 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, if (group->typeCount == 0) { group->typeCount = package->types.size(); } - + return NO_ERROR; } -status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc, - void** outData, size_t* outSize) const +status_t ResTable::createIdmap(const ResTable& overlay, + uint32_t targetCrc, uint32_t overlayCrc, + const char* targetPath, const char* overlayPath, + void** outData, size_t* outSize) const { // see README for details on the format of map if (mPackageGroups.size() == 0) { + ALOGW("idmap: target package has no package groups, cannot create idmap\n"); return UNKNOWN_ERROR; } if (mPackageGroups[0]->packages.size() == 0) { + ALOGW("idmap: target package has no packages in its first package group, " + "cannot create idmap\n"); return UNKNOWN_ERROR; } Vector<Vector<uint32_t> > map; + // overlaid packages are assumed to contain only one package group const PackageGroup* pg = mPackageGroups[0]; const Package* pkg = pg->packages[0]; size_t typeCount = pkg->types.size(); // starting size is header + first item (number of types in map) *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t); + // overlay packages are assumed to contain only one package group const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name); const uint32_t pkg_id = pkg->package->id << 24; @@ -5368,7 +5602,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); resource_name resName; - if (!this->getResourceName(resID, true, &resName)) { + if (!this->getResourceName(resID, false, &resName)) { ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID); // add dummy value, or trimming leading/trailing zeroes later will fail vector.push(0); @@ -5426,8 +5660,22 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui } uint32_t* data = (uint32_t*)*outData; *data++ = htodl(IDMAP_MAGIC); - *data++ = htodl(originalCrc); + *data++ = htodl(targetCrc); *data++ = htodl(overlayCrc); + const char* paths[] = { targetPath, overlayPath }; + for (int j = 0; j < 2; ++j) { + char* p = (char*)data; + const char* path = paths[j]; + const size_t I = strlen(path); + if (I > 255) { + ALOGV("path exceeds expected 255 characters: %s\n", path); + return UNKNOWN_ERROR; + } + for (size_t i = 0; i < 256; ++i) { + *p++ = i < I ? path[i] : '\0'; + } + data += 256 / sizeof(uint32_t); + } const size_t mapSize = map.size(); *data++ = htodl(mapSize); size_t offset = mapSize; @@ -5442,6 +5690,10 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui offset += N; } } + if (offset == mapSize) { + ALOGW("idmap: no resources in overlay package present in base package\n"); + return UNKNOWN_ERROR; + } for (size_t i = 0; i < mapSize; ++i) { const Vector<uint32_t>& vector = map.itemAt(i); const size_t N = vector.size(); @@ -5463,14 +5715,25 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui } bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, - uint32_t* pOriginalCrc, uint32_t* pOverlayCrc) + uint32_t* pTargetCrc, uint32_t* pOverlayCrc, + String8* pTargetPath, String8* pOverlayPath) { const uint32_t* map = (const uint32_t*)idmap; if (!assertIdmapHeader(map, sizeBytes)) { return false; } - *pOriginalCrc = map[1]; - *pOverlayCrc = map[2]; + if (pTargetCrc) { + *pTargetCrc = map[1]; + } + if (pOverlayCrc) { + *pOverlayCrc = map[2]; + } + if (pTargetPath) { + pTargetPath->setTo(reinterpret_cast<const char*>(map + 3)); + } + if (pOverlayPath) { + pOverlayPath->setTo(reinterpret_cast<const char*>(map + 3 + 256 / sizeof(uint32_t))); + } return true; } @@ -5494,7 +5757,7 @@ static void print_complex(uint32_t complex, bool isFraction) * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT) & Res_value::COMPLEX_RADIX_MASK]; printf("%f", value); - + if (!isFraction) { switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) { case Res_value::COMPLEX_UNIT_PX: printf("px"); break; @@ -5569,7 +5832,7 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const } else { printf("(string) null\n"); } - } + } } else if (value.dataType == Res_value::TYPE_FLOAT) { printf("(float) %g\n", *(const float*)&value.data); } else if (value.dataType == Res_value::TYPE_DIMENSION) { @@ -5601,9 +5864,9 @@ void ResTable::print(bool inclValues) const printf("mError=0x%x (%s)\n", mError, strerror(mError)); } #if 0 - printf("mParams=%c%c-%c%c,\n", - mParams.language[0], mParams.language[1], - mParams.country[0], mParams.country[1]); + char localeStr[RESTABLE_MAX_LOCALE_LEN]; + mParams.getBcp47Locale(localeStr); + printf("mParams=%s,\n" localeStr); #endif size_t pgCount = mPackageGroups.size(); printf("Package Groups (%d)\n", (int)pgCount); @@ -5612,7 +5875,7 @@ void ResTable::print(bool inclValues) const printf("Package Group %d id=%d packageCount=%d name=%s\n", (int)pgIndex, pg->id, (int)pg->packages.size(), String8(pg->name).string()); - + size_t pkgCount = pg->packages.size(); for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) { const Package* pkg = pg->packages[pkgIndex]; @@ -5670,26 +5933,26 @@ void ResTable::print(bool inclValues) const size_t entryCount = dtohl(type->entryCount); uint32_t entriesStart = dtohl(type->entriesStart); if ((entriesStart&0x3) != 0) { - printf(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart); + printf(" NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart); continue; } uint32_t typeSize = dtohl(type->header.size); if ((typeSize&0x3) != 0) { - printf(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize); + printf(" NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize); continue; } for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) { - + const uint8_t* const end = ((const uint8_t*)type) + dtohl(type->header.size); const uint32_t* const eindex = (const uint32_t*) (((const uint8_t*)type) + dtohs(type->header.headerSize)); - + uint32_t thisOffset = dtohl(eindex[entryIndex]); if (thisOffset == ResTable_type::NO_ENTRY) { continue; } - + uint32_t resID = (0xff000000 & ((pkg->package->id)<<24)) | (0x00ff0000 & ((typeIndex+1)<<16)) | (0x0000ffff & (entryIndex)); @@ -5714,36 +5977,34 @@ void ResTable::print(bool inclValues) const printf(" INVALID RESOURCE 0x%08x: ", resID); } if ((thisOffset&0x3) != 0) { - printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset); + printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset); continue; } if ((thisOffset+sizeof(ResTable_entry)) > typeSize) { - printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n", - (void*)entriesStart, (void*)thisOffset, - (void*)typeSize); + printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n", + entriesStart, thisOffset, typeSize); continue; } - + const ResTable_entry* ent = (const ResTable_entry*) (((const uint8_t*)type) + entriesStart + thisOffset); if (((entriesStart + thisOffset)&0x3) != 0) { - printf("NON-INTEGER ResTable_entry OFFSET: %p\n", - (void*)(entriesStart + thisOffset)); + printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n", + (entriesStart + thisOffset)); continue; } - - uint16_t esize = dtohs(ent->size); + + uintptr_t esize = dtohs(ent->size); if ((esize&0x3) != 0) { - printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize); + printf("NON-INTEGER ResTable_entry SIZE: 0x%x\n", esize); continue; } if ((thisOffset+esize) > typeSize) { - printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n", - (void*)entriesStart, (void*)thisOffset, - (void*)esize, (void*)typeSize); + printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+0x%x (size is 0x%x)\n", + entriesStart, thisOffset, esize, typeSize); continue; } - + const Res_value* valuePtr = NULL; const ResTable_map_entry* bagPtr = NULL; Res_value value; @@ -5758,12 +6019,12 @@ void ResTable::print(bool inclValues) const (int)value.dataType, (int)value.data, (int)value.size, (int)value.res0); } - + if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) { printf(" (PUBLIC)"); } printf("\n"); - + if (inclValues) { if (valuePtr != NULL) { printf(" "); diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp index e9ac2fe..6fa0f14 100644 --- a/libs/androidfw/ZipUtils.cpp +++ b/libs/androidfw/ZipUtils.cpp @@ -127,7 +127,7 @@ static const unsigned long kReadBufSize = 32768; goto z_bail; } - /* output buffer holds all, so no need to write the output */ + /* output buffer holds all, so no need to write the output */ } while (zerr == Z_OK); assert(zerr == Z_STREAM_END); /* other errors should've been caught */ @@ -197,7 +197,7 @@ public: { } - long read(unsigned char** nextBuffer, long readSize) { + long read(unsigned char** nextBuffer, long /*readSize*/) { if (!mBufferReturned) { mBufferReturned = true; *nextBuffer = mInput; diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk index 3c55375..977ba80 100644 --- a/libs/androidfw/tests/Android.mk +++ b/libs/androidfw/tests/Android.mk @@ -5,7 +5,8 @@ include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ ObbFile_test.cpp \ - ZipUtils_test.cpp + ZipUtils_test.cpp \ + ResourceTypes_test.cpp shared_libraries := \ libandroidfw \ diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ResourceTypes_test.cpp new file mode 100644 index 0000000..4888b4a --- /dev/null +++ b/libs/androidfw/tests/ResourceTypes_test.cpp @@ -0,0 +1,185 @@ +/* + * 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 <androidfw/ResourceTypes.h> +#include <utils/Log.h> +#include <utils/String8.h> + +#include <gtest/gtest.h> +namespace android { + +TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterLanguage) { + ResTable_config config; + config.packLanguage("en"); + + EXPECT_EQ('e', config.language[0]); + EXPECT_EQ('n', config.language[1]); + + char out[4] = { 1, 1, 1, 1}; + config.unpackLanguage(out); + EXPECT_EQ('e', out[0]); + EXPECT_EQ('n', out[1]); + EXPECT_EQ(0, out[2]); + EXPECT_EQ(0, out[3]); + + memset(out, 1, sizeof(out)); + config.locale = 0; + config.unpackLanguage(out); + EXPECT_EQ(0, out[0]); + EXPECT_EQ(0, out[1]); + EXPECT_EQ(0, out[2]); + EXPECT_EQ(0, out[3]); +} + +TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterRegion) { + ResTable_config config; + config.packRegion("US"); + + EXPECT_EQ('U', config.country[0]); + EXPECT_EQ('S', config.country[1]); + + char out[4] = { 1, 1, 1, 1}; + config.unpackRegion(out); + EXPECT_EQ('U', out[0]); + EXPECT_EQ('S', out[1]); + EXPECT_EQ(0, out[2]); + EXPECT_EQ(0, out[3]); +} + +TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguage) { + ResTable_config config; + config.packLanguage("eng"); + + // 1-00110-01 101-00100 + EXPECT_EQ(0x99, config.language[0]); + EXPECT_EQ(0xa4, config.language[1]); + + char out[4] = { 1, 1, 1, 1}; + config.unpackLanguage(out); + EXPECT_EQ('e', out[0]); + EXPECT_EQ('n', out[1]); + EXPECT_EQ('g', out[2]); + EXPECT_EQ(0, out[3]); +} + +TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) { + ResTable_config config; + config.packRegion("419"); + + char out[4] = { 1, 1, 1, 1}; + config.unpackRegion(out); + + EXPECT_EQ('4', out[0]); + EXPECT_EQ('1', out[1]); + EXPECT_EQ('9', out[2]); +} + +/* static */ void fillIn(const char* lang, const char* country, + const char* script, const char* variant, ResTable_config* out) { + memset(out, 0, sizeof(ResTable_config)); + if (lang != NULL) { + out->packLanguage(lang); + } + + if (country != NULL) { + out->packRegion(country); + } + + if (script != NULL) { + memcpy(out->localeScript, script, 4); + } + + if (variant != NULL) { + memcpy(out->localeVariant, variant, strlen(variant)); + } +} + +TEST(ResourceTypesTest, IsMoreSpecificThan) { + ResTable_config l; + ResTable_config r; + + fillIn("en", NULL, NULL, NULL, &l); + fillIn(NULL, NULL, NULL, NULL, &r); + + EXPECT_TRUE(l.isMoreSpecificThan(r)); + EXPECT_FALSE(r.isMoreSpecificThan(l)); + + fillIn("eng", NULL, NULL, NULL, &l); + EXPECT_TRUE(l.isMoreSpecificThan(r)); + EXPECT_FALSE(r.isMoreSpecificThan(l)); + + fillIn("eng", "419", NULL, NULL, &r); + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_TRUE(r.isMoreSpecificThan(l)); + + fillIn("en", NULL, NULL, NULL, &l); + fillIn("en", "US", NULL, NULL, &r); + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_TRUE(r.isMoreSpecificThan(l)); + + fillIn("en", "US", NULL, NULL, &l); + fillIn("en", "US", "Latn", NULL, &r); + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_TRUE(r.isMoreSpecificThan(l)); + + fillIn("en", "US", NULL, NULL, &l); + fillIn("en", "US", NULL, "POSIX", &r); + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_TRUE(r.isMoreSpecificThan(l)); + + fillIn("en", "US", "Latn", NULL, &l); + fillIn("en", "US", NULL, "POSIX", &r); + EXPECT_FALSE(l.isMoreSpecificThan(r)); + EXPECT_TRUE(r.isMoreSpecificThan(l)); +} + +TEST(ResourceTypesTest, setLocale) { + ResTable_config test; + test.setBcp47Locale("en-US"); + EXPECT_EQ('e', test.language[0]); + EXPECT_EQ('n', test.language[1]); + EXPECT_EQ('U', test.country[0]); + EXPECT_EQ('S', test.country[1]); + EXPECT_EQ(0, test.localeScript[0]); + EXPECT_EQ(0, test.localeVariant[0]); + + test.setBcp47Locale("eng-419"); + char out[4] = { 1, 1, 1, 1}; + test.unpackLanguage(out); + EXPECT_EQ('e', out[0]); + EXPECT_EQ('n', out[1]); + EXPECT_EQ('g', out[2]); + EXPECT_EQ(0, out[3]); + memset(out, 1, 4); + test.unpackRegion(out); + EXPECT_EQ('4', out[0]); + EXPECT_EQ('1', out[1]); + EXPECT_EQ('9', out[2]); + + + test.setBcp47Locale("en-Latn-419"); + memset(out, 1, 4); + EXPECT_EQ('e', test.language[0]); + EXPECT_EQ('n', test.language[1]); + + EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4)); + test.unpackRegion(out); + EXPECT_EQ('4', out[0]); + EXPECT_EQ('1', out[1]); + EXPECT_EQ('9', out[2]); +} + +} // namespace android. diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp index eb8bb9f..e8c3d3c 100644 --- a/libs/hwui/AssetAtlas.cpp +++ b/libs/hwui/AssetAtlas.cpp @@ -28,7 +28,7 @@ namespace uirenderer { // Lifecycle /////////////////////////////////////////////////////////////////////////////// -void AssetAtlas::init(sp<GraphicBuffer> buffer, int* map, int count) { +void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) { if (mImage) { return; } @@ -108,14 +108,19 @@ private: /** * TODO: This method does not take the rotation flag into account */ -void AssetAtlas::createEntries(Caches& caches, int* map, int count) { +void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) { const float width = float(mTexture->width); const float height = float(mTexture->height); for (int i = 0; i < count; ) { - SkBitmap* bitmap = (SkBitmap*) map[i++]; - int x = map[i++]; - int y = map[i++]; + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]); + // NOTE: We're converting from 64 bit signed values to 32 bit + // signed values. This is guaranteed to be safe because the "x" + // and "y" coordinate values are guaranteed to be representable + // with 32 bits. The array is 64 bits wide so that it can carry + // pointers on 64 bit architectures. + const int x = static_cast<int>(map[i++]); + const int y = static_cast<int>(map[i++]); bool rotated = map[i++] > 0; // Bitmaps should never be null, we're just extra paranoid diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h index a28efc6..163bdbc 100644 --- a/libs/hwui/AssetAtlas.h +++ b/libs/hwui/AssetAtlas.h @@ -121,7 +121,7 @@ public: * initialized. To re-initialize the atlas, you must * first call terminate(). */ - ANDROID_API void init(sp<GraphicBuffer> buffer, int* map, int count); + ANDROID_API void init(sp<GraphicBuffer> buffer, int64_t* map, int count); /** * Destroys the atlas texture. This object can be @@ -176,7 +176,7 @@ public: } private: - void createEntries(Caches& caches, int* map, int count); + void createEntries(Caches& caches, int64_t* map, int count); Texture* mTexture; Image* mImage; diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 326805a..842e028 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1444,7 +1444,7 @@ public: DeferredDisplayList::kOpBatch_Text : DeferredDisplayList::kOpBatch_ColorText; - deferInfo.mergeId = (mergeid_t)mPaint->getColor(); + deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor()); // don't merge decorated text - the decorations won't draw in order bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag | diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 9b023f9..b2148b0 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -57,7 +57,7 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig if (vertices) return vertices; int8_t emptyQuads = 0; - mColors = patch->colors; + mColors = patch->getColors(); const int8_t numColors = patch->numColors; if (uint8_t(numColors) < sizeof(uint32_t) * 4) { @@ -79,8 +79,8 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig TextureVertex* tempVertices = new TextureVertex[maxVertices]; TextureVertex* vertex = tempVertices; - const int32_t* xDivs = patch->xDivs; - const int32_t* yDivs = patch->yDivs; + const int32_t* xDivs = patch->getXDivs(); + const int32_t* yDivs = patch->getYDivs(); const uint32_t xStretchCount = (xCount + 1) >> 1; const uint32_t yStretchCount = (yCount + 1) >> 1; diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h index 763a785..b5e8838 100644 --- a/libs/hwui/Patch.h +++ b/libs/hwui/Patch.h @@ -66,7 +66,7 @@ private: void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2, uint32_t& quadCount); - uint32_t* mColors; + const uint32_t* mColors; UvMapper mUvMapper; }; // struct Patch diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index dc0d98c..8a44604 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -129,7 +129,11 @@ void PatchCache::clearGarbage() { Mutex::Autolock _l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - remove(patchesToRemove, mGarbage[i]); + Res_png_9patch* patch = mGarbage[i]; + remove(patchesToRemove, patch); + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + delete[] (int8_t*) patch; } mGarbage.clear(); } diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 5df6408..cf8adf8 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -395,7 +395,9 @@ void PathCache::clearGarbage() { Mutex::Autolock l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - remove(pathsToRemove, mGarbage.itemAt(i)); + const path_pair_t& pair = mGarbage.itemAt(i); + remove(pathsToRemove, pair); + delete pair.getFirst(); } mGarbage.clear(); } diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp index 36e89c6..5b642b9 100644 --- a/libs/hwui/PixelBuffer.cpp +++ b/libs/hwui/PixelBuffer.cpp @@ -151,7 +151,7 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei mCaches.bindPixelBuffer(mBuffer); unmap(); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, - GL_UNSIGNED_BYTE, (void*) offset); + GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 3f77021..d276a29 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -213,8 +213,9 @@ void ResourceCache::destructorLocked(SkPath* resource) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { Caches::getInstance().pathCache.removeDeferred(resource); + } else { + delete resource; } - delete resource; return; } ref->destroyed = true; @@ -235,8 +236,9 @@ void ResourceCache::destructorLocked(SkBitmap* resource) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { Caches::getInstance().textureCache.removeDeferred(resource); + } else { + delete resource; } - delete resource; return; } ref->destroyed = true; @@ -292,13 +294,14 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) { ssize_t index = mCache->indexOfKey(resource); ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { + // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { Caches::getInstance().patchCache.removeDeferred(resource); + } else { + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + delete[] (int8_t*) resource; } - // If we're not tracking this resource, just delete it - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - delete[] (int8_t*) resource; return; } ref->destroyed = true; @@ -355,16 +358,18 @@ void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceRefere SkBitmap* bitmap = (SkBitmap*) resource; if (Caches::hasInstance()) { Caches::getInstance().textureCache.removeDeferred(bitmap); + } else { + delete bitmap; } - delete bitmap; } break; case kPath: { SkPath* path = (SkPath*) resource; if (Caches::hasInstance()) { Caches::getInstance().pathCache.removeDeferred(path); + } else { + delete path; } - delete path; } break; case kShader: { @@ -380,11 +385,12 @@ void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceRefere case kNinePatch: { if (Caches::hasInstance()) { Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); + } else { + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + int8_t* patch = (int8_t*) resource; + delete[] patch; } - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - int8_t* patch = (int8_t*) resource; - delete[] patch; } break; case kLayer: { diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 8d0874f..a9ab2c6 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -184,7 +184,9 @@ void TextureCache::clearGarbage() { Mutex::Autolock _l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - mCache.remove(mGarbage.itemAt(i)); + const SkBitmap* bitmap = mGarbage.itemAt(i); + mCache.remove(bitmap); + delete bitmap; } mGarbage.clear(); } diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index 12a9c23..436dcef 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -405,10 +405,10 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len // If it's still not valid, we couldn't cache it, so we shouldn't // draw garbage; also skip empty glyphs (spaces) if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { - float penX = x + positions[(glyphsCount << 1)]; - float penY = y + positions[(glyphsCount << 1) + 1]; + int penX = x + (int) roundf(positions[(glyphsCount << 1)]); + int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]); - (*this.*render)(cachedGlyph, roundf(penX), roundf(penY), + (*this.*render)(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH, bounds, positions); } diff --git a/libs/hwui/utils/TinyHashMap.h b/libs/hwui/utils/TinyHashMap.h index 8855140..4ff9a42 100644 --- a/libs/hwui/utils/TinyHashMap.h +++ b/libs/hwui/utils/TinyHashMap.h @@ -24,8 +24,6 @@ namespace uirenderer { /** * A very simple hash map that doesn't allow duplicate keys, overwriting the older entry. - * - * Currently, expects simple keys that are handled by hash_t() */ template <typename TKey, typename TValue> class TinyHashMap { @@ -36,7 +34,7 @@ public: * Puts an entry in the hash, removing any existing entry with the same key */ void put(TKey key, TValue value) { - hash_t hash = hash_t(key); + hash_t hash = android::hash_type(key); ssize_t index = mTable.find(-1, hash, key); if (index != -1) { @@ -51,7 +49,7 @@ public: * Return true if key is in the map, in which case stores the value in the output ref */ bool get(TKey key, TValue& outValue) { - hash_t hash = hash_t(key); + hash_t hash = android::hash_type(key); ssize_t index = mTable.find(-1, hash, key); if (index == -1) { return false; |