summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/Asset.cpp18
-rw-r--r--libs/androidfw/AssetManager.cpp335
-rw-r--r--libs/androidfw/BackupData.cpp2
-rw-r--r--libs/androidfw/BackupHelpers.cpp14
-rw-r--r--libs/androidfw/CursorWindow.cpp16
-rw-r--r--libs/androidfw/ResourceTypes.cpp697
-rw-r--r--libs/androidfw/ZipUtils.cpp4
-rw-r--r--libs/androidfw/tests/Android.mk3
-rw-r--r--libs/androidfw/tests/ResourceTypes_test.cpp185
-rw-r--r--libs/hwui/AssetAtlas.cpp15
-rw-r--r--libs/hwui/AssetAtlas.h4
-rw-r--r--libs/hwui/DisplayListOp.h2
-rw-r--r--libs/hwui/Patch.cpp6
-rw-r--r--libs/hwui/Patch.h2
-rw-r--r--libs/hwui/PatchCache.cpp6
-rw-r--r--libs/hwui/PathCache.cpp4
-rw-r--r--libs/hwui/PixelBuffer.cpp2
-rw-r--r--libs/hwui/ResourceCache.cpp30
-rw-r--r--libs/hwui/TextureCache.cpp4
-rw-r--r--libs/hwui/font/Font.cpp6
-rw-r--r--libs/hwui/utils/TinyHashMap.h6
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;