diff options
Diffstat (limited to 'libs')
31 files changed, 1004 insertions, 516 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..bd9dc76 100644 --- a/libs/androidfw/BackupData.cpp +++ b/libs/androidfw/BackupData.cpp @@ -78,7 +78,7 @@ BackupDataWriter::write_padding_for(int n) paddingSize = padding_extra(n); if (paddingSize > 0) { uint32_t padding = 0xbcbcbcbc; - if (DEBUG) ALOGI("writing %d padding bytes for %d", paddingSize, n); + if (DEBUG) ALOGI("writing %zd padding bytes for %d", paddingSize, n); amt = write(m_fd, &padding, paddingSize); if (amt != paddingSize) { m_status = errno; @@ -112,7 +112,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) k = key; } if (DEBUG) { - ALOGD("Writing header: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), + ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.string(), key.string(), dataSize); } @@ -125,7 +125,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) header.keyLen = tolel(keyLen); header.dataSize = tolel(dataSize); - if (DEBUG) ALOGI("writing entity header, %d bytes", sizeof(entity_header_v1)); + if (DEBUG) ALOGI("writing entity header, %zu bytes", sizeof(entity_header_v1)); amt = write(m_fd, &header, sizeof(entity_header_v1)); if (amt != sizeof(entity_header_v1)) { m_status = errno; @@ -133,7 +133,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) } m_pos += amt; - if (DEBUG) ALOGI("writing entity header key, %d bytes", keyLen+1); + if (DEBUG) ALOGI("writing entity header key, %zd bytes", keyLen+1); amt = write(m_fd, k.string(), keyLen+1); if (amt != keyLen+1) { m_status = errno; @@ -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..52dce9f 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) { @@ -639,7 +639,7 @@ int write_tarfile(const String8& packageName, const String8& domain, // size header -- calc len in digits by actually rendering the number // to a string - brute force but simple - snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size); + snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size); p += write_pax_header_entry(p, "size", sizeStr); // fullname was generated above with the ustar paths @@ -661,7 +661,7 @@ int write_tarfile(const String8& packageName, const String8& domain, // [ 124 : 12 ] size of pax extended header data memset(paxHeader + 124, 0, 12); - snprintf(paxHeader + 124, 12, "%011o", p - paxData); + snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData)); // Checksum and write the pax block header calc_tar_checksum(paxHeader); @@ -681,7 +681,10 @@ int write_tarfile(const String8& packageName, const String8& domain, if (!isdir) { off64_t toWrite = s.st_size; while (toWrite > 0) { - size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE; + size_t toRead = toWrite; + if (toRead > BUFSIZE) { + toRead = BUFSIZE; + } ssize_t nRead = read(fd, buf, toRead); if (nRead < 0) { err = errno; @@ -778,7 +781,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 +1086,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 +1098,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, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n" + " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%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, @@ -1194,7 +1197,7 @@ int test_read_header_and_entity(BackupDataReader& reader, const char* str) { int err; - int bufSize = strlen(str)+1; + size_t bufSize = strlen(str)+1; char* buf = (char*)malloc(bufSize); String8 string; int cookie = 0x11111111; @@ -1229,9 +1232,9 @@ test_read_header_and_entity(BackupDataReader& reader, const char* str) err = EINVAL; goto finished; } - if ((int)actualSize != bufSize) { - fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize, - actualSize); + if (actualSize != bufSize) { + fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n", + bufSize, actualSize); err = EINVAL; goto finished; } diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp index 0f54edb..166863c 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. */ @@ -210,8 +210,8 @@ uint32_t CursorWindow::alloc(size_t size, bool aligned) { uint32_t offset = mHeader->freeOffset + padding; uint32_t nextFreeOffset = offset + size; if (nextFreeOffset > mSize) { - ALOGW("Window is full: requested allocation %d bytes, " - "free space %d bytes, window size %d bytes", + ALOGW("Window is full: requested allocation %zu bytes, " + "free space %zu bytes, window size %zu bytes", size, freeSpace(), mSize); return 0; } diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 990cf9e..9e59a13 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) { @@ -2464,7 +2688,7 @@ struct ResTable::Header size_t size; const uint8_t* dataEnd; size_t index; - void* cookie; + int32_t cookie; ResStringPool values; uint32_t* resourceIDMap; @@ -2496,7 +2720,7 @@ struct ResTable::Package delete types[i]; } } - + ResTable* const owner; const Header* const header; const ResTable_package* const package; @@ -2504,7 +2728,7 @@ struct ResTable::Package ResStringPool typeStrings; ResStringPool keyStrings; - + const Type* getType(size_t idx) const { return idx < types.size() ? types[idx] : NULL; } @@ -2554,18 +2778,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; @@ -2714,7 +2938,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; } @@ -2723,7 +2947,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) { @@ -2753,7 +2977,7 @@ status_t ResTable::Theme::setTo(const Theme& other) //ALOGI("Final theme:"); //dumpToLog(); - + return NO_ERROR; } @@ -2763,7 +2987,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); @@ -2837,12 +3061,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]; @@ -2863,12 +3087,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); } @@ -2884,13 +3108,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) { @@ -2898,17 +3121,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); @@ -2919,14 +3143,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); @@ -2948,9 +3172,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) { @@ -3030,8 +3254,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*) @@ -3247,8 +3471,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; } @@ -3282,7 +3506,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; @@ -3352,7 +3576,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; @@ -3375,7 +3599,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(); @@ -3476,7 +3700,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)); @@ -3523,8 +3747,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; } @@ -3542,7 +3766,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", @@ -3586,7 +3810,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; @@ -3849,7 +4073,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]; @@ -3865,9 +4089,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)); @@ -3881,7 +4105,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)) { @@ -4038,7 +4262,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) { @@ -4189,7 +4413,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", @@ -4302,7 +4526,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! @@ -4389,7 +4613,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; @@ -4489,7 +4713,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); @@ -4654,7 +4878,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString, return true; } } - + } bag++; cnt--; @@ -4933,7 +5157,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; } @@ -4953,18 +5177,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); } } } @@ -4979,9 +5205,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++) { @@ -5016,43 +5243,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 @@ -5062,19 +5289,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=" @@ -5117,29 +5344,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); @@ -5148,12 +5375,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; @@ -5187,7 +5414,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); @@ -5204,10 +5431,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)); @@ -5226,9 +5453,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), @@ -5244,12 +5471,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); } @@ -5265,7 +5492,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, @@ -5273,9 +5500,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), @@ -5283,23 +5510,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); } @@ -5312,7 +5539,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); @@ -5333,27 +5560,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; @@ -5371,7 +5605,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); @@ -5429,8 +5663,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; @@ -5445,6 +5693,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(); @@ -5466,14 +5718,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; } @@ -5497,7 +5760,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; @@ -5572,7 +5835,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) { @@ -5604,9 +5867,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); @@ -5615,7 +5878,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]; @@ -5673,26 +5936,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)); @@ -5717,36 +5980,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: %p\n", (void *)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+%p (size is 0x%x)\n", + entriesStart, thisOffset, (void *)esize, typeSize); continue; } - + const Res_value* valuePtr = NULL; const ResTable_map_entry* bagPtr = NULL; Res_value value; @@ -5761,12 +6022,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/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp index 21e706f..3e11987 100644 --- a/libs/common_time/common_time_server.cpp +++ b/libs/common_time/common_time_server.cpp @@ -590,7 +590,7 @@ static void hexDumpToString(const uint8_t* src, size_t src_len, for (i = 0; (i < src_len) && (offset < dst_len); ++i) { int res; if (0 == (i % 16)) { - res = snprintf(dst + offset, dst_len - offset, "\n%04x :", i); + res = snprintf(dst + offset, dst_len - offset, "\n%04zx :", i); if (res < 0) break; offset += res; diff --git a/libs/common_time/utils.cpp b/libs/common_time/utils.cpp index ed2c77d..ddcdfe7 100644 --- a/libs/common_time/utils.cpp +++ b/libs/common_time/utils.cpp @@ -56,7 +56,7 @@ LogRing::LogRing(const char* header, size_t entries) , mHeader(header) { mRingBuffer = new Entry[mSize]; if (NULL == mRingBuffer) - ALOGE("Failed to allocate log ring with %u entries.", mSize); + ALOGE("Failed to allocate log ring with %zu entries.", mSize); } LogRing::~LogRing() { @@ -150,7 +150,7 @@ void LogRing::dumpLog(int fd) { localtime_r(&mRingBuffer[ndx].first_ts.tv_sec, &t); strftime(timebuf, sizeof(timebuf), kTimeFmt, &t); - res = snprintf(buf, sizeof(buf), "[%2d] %s.%03ld :: %s%s\n", + res = snprintf(buf, sizeof(buf), "[%2zu] %s.%03ld :: %s%s\n", i, timebuf, mRingBuffer[ndx].first_ts.tv_usec / 1000, mRingBuffer[ndx].s.string(), 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/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 0be17ff..8d19ca2 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -735,30 +735,34 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int // a null path is OK because there are no custom kernels used // hence nothing gets cached by RS if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) { + mRs.clear(); ALOGE("blur RS failed to init"); + } else { + mRsElement = RSC::Element::A_8(mRs); + mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement); } - - mRsElement = RSC::Element::A_8(mRs); - mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement); } + if (mRs != 0) { + RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0); + RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, + RS_ALLOCATION_MIPMAP_NONE, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, + *image); + RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, + RS_ALLOCATION_MIPMAP_NONE, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, + outImage); + + mRsScript->setRadius(radius); + mRsScript->setInput(ain); + mRsScript->forEach(aout); + + // replace the original image's pointer, avoiding a copy back to the original buffer + free(*image); + *image = outImage; - RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0); - RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, - RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, - *image); - RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, - RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, - outImage); - - mRsScript->setRadius(radius); - mRsScript->setInput(ain); - mRsScript->forEach(aout); - - // replace the original image's pointer, avoiding a copy back to the original buffer - free(*image); - *image = outImage; - - return; + return; + } } #endif diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 9b023f9..442e9ba 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -36,6 +36,7 @@ Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(f } Patch::~Patch() { + delete[] vertices; } /////////////////////////////////////////////////////////////////////////////// @@ -57,7 +58,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 +80,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..2f2debc 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -119,6 +119,17 @@ void PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* p void PatchCache::removeDeferred(Res_png_9patch* patch) { Mutex::Autolock _l(mLock); + + // Assert that patch is not already garbage + size_t count = mGarbage.size(); + for (size_t i = 0; i < count; i++) { + if (patch == mGarbage[i]) { + patch = NULL; + break; + } + } + LOG_ALWAYS_FATAL_IF(patch == NULL); + mGarbage.push(patch); } @@ -129,7 +140,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(); } @@ -139,8 +154,8 @@ void PatchCache::clearGarbage() { for (size_t i = 0; i < patchesToRemove.size(); i++) { const patch_pair_t& pair = patchesToRemove[i]; - // Add a new free block to the list - const Patch* patch = pair.getSecond(); + // Release the patch and mark the space in the free list + Patch* patch = pair.getSecond(); BufferBlock* block = new BufferBlock(patch->offset, patch->getSize()); block->next = mFreeBlocks; mFreeBlocks = block; @@ -148,6 +163,7 @@ void PatchCache::clearGarbage() { mSize -= patch->getSize(); mCache.remove(*pair.getFirst()); + delete patch; } #if DEBUG_PATCHES @@ -212,6 +228,7 @@ void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) { } else { mFreeBlocks = block->next; } + delete block; } else { // Resize the block now that it's occupied block->offset += size; 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..77292bf 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -31,9 +31,9 @@ void ResourceCache::logCache() { ALOGD("ResourceCache: cacheReport:"); for (size_t i = 0; i < mCache->size(); ++i) { ResourceReference* ref = mCache->valueAt(i); - ALOGD(" ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p", + ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i), mCache->valueAt(i)); - ALOGD(" ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d", + ALOGD(" ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d", i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType); } } @@ -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/Snapshot.h b/libs/hwui/Snapshot.h index cc6d0cd..5bdb18a 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -108,7 +108,7 @@ public: * Returns the current clip in local coordinates. The clip rect is * transformed by the inverse transform matrix. */ - const Rect& getLocalClip(); + ANDROID_API const Rect& getLocalClip(); /** * Resets the clip to the specified rect. 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 e54c61e..d829f58 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -214,18 +214,28 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* int dstY = y + glyph->mBitmapTop; CacheTexture* cacheTexture = glyph->mCacheTexture; + PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); + uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat()); uint32_t cacheWidth = cacheTexture->getWidth(); - uint32_t startY = glyph->mStartY * cacheWidth; - uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth); + uint32_t srcStride = formatSize * cacheWidth; + uint32_t startY = glyph->mStartY * srcStride; + uint32_t endY = startY + (glyph->mBitmapHeight * srcStride); - PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); const uint8_t* cacheBuffer = pixelBuffer->map(); for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY; - cacheY += cacheWidth, bitmapY += bitmapWidth) { - memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth); + cacheY += srcStride, bitmapY += bitmapWidth) { + + if (formatSize == 1) { + memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth); + } else { + for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) { + bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize]; + } + } } + } void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, @@ -406,10 +416,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; diff --git a/libs/input/EventHub.cpp b/libs/input/EventHub.cpp index ed63b2d..e30a772 100644 --- a/libs/input/EventHub.cpp +++ b/libs/input/EventHub.cpp @@ -827,7 +827,7 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d " - "capacity: %d errno: %d)\n", + "capacity: %zu errno: %d)\n", device->fd, readSize, bufferSize, capacity, errno); deviceChanged = true; closeDeviceLocked(device); diff --git a/libs/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp index 7164a13..22d1871 100644 --- a/libs/input/InputDispatcher.cpp +++ b/libs/input/InputDispatcher.cpp @@ -147,7 +147,7 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, return false; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { - ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.", + ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.", pointerCount, MAX_POINTERS); return false; } @@ -3096,14 +3096,14 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.appendFormat(INDENT "TouchStatesByDisplay:\n"); for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { const TouchState& state = mTouchStatesByDisplay.valueAt(i); - dump.appendFormat(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", + dump.appendFormat(INDENT2 "%zu: down=%s, split=%s, deviceId=%d, source=0x%08x\n", state.displayId, toString(state.down), toString(state.split), state.deviceId, state.source); if (!state.windows.isEmpty()) { dump.append(INDENT3 "Windows:\n"); for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump.appendFormat(INDENT4 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + dump.appendFormat(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", i, touchedWindow.windowHandle->getName().string(), touchedWindow.pointerIds.value, touchedWindow.targetFlags); @@ -3122,7 +3122,7 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); - dump.appendFormat(INDENT2 "%d: name='%s', displayId=%d, " + dump.appendFormat(INDENT2 "%zu: name='%s', displayId=%d, " "paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], scale=%f, " @@ -3152,7 +3152,7 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.append(INDENT "MonitoringChannels:\n"); for (size_t i = 0; i < mMonitoringChannels.size(); i++) { const sp<InputChannel>& channel = mMonitoringChannels[i]; - dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string()); + dump.appendFormat(INDENT2 "%zu: '%s'\n", i, channel->getName().string()); } } else { dump.append(INDENT "MonitoringChannels: <none>\n"); @@ -3201,7 +3201,7 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) { dump.append(INDENT "Connections:\n"); for (size_t i = 0; i < mConnectionsByFd.size(); i++) { const sp<Connection>& connection = mConnectionsByFd.valueAt(i); - dump.appendFormat(INDENT2 "%d: channelName='%s', windowName='%s', " + dump.appendFormat(INDENT2 "%zu: channelName='%s', windowName='%s', " "status=%s, monitor=%s, inputPublisherBlocked=%s\n", i, connection->getInputChannelName(), connection->getWindowName(), connection->getStatusLabel(), toString(connection->monitor), diff --git a/libs/input/InputReader.cpp b/libs/input/InputReader.cpp index 48c5223..a4093e9 100644 --- a/libs/input/InputReader.cpp +++ b/libs/input/InputReader.cpp @@ -1992,7 +1992,7 @@ void KeyboardInputMapper::dump(String8& dump) { dumpParameters(dump); dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size()); + dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); } @@ -3389,7 +3389,7 @@ void TouchInputMapper::dumpVirtualKeys(String8& dump) { for (size_t i = 0; i < mVirtualKeys.size(); i++) { const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); - dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, " + dump.appendFormat(INDENT4 "%zu: scanCode=%d, keyCode=%d, " "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, virtualKey.hitRight, @@ -6132,8 +6132,8 @@ void MultiTouchInputMapper::configureRawPointerAxes() { && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { size_t slotCount = mRawPointerAxes.slot.maxValue + 1; if (slotCount > MAX_SLOTS) { - ALOGW("MultiTouch Device %s reported %d slots but the framework " - "only supports a maximum of %d slots at this time.", + ALOGW("MultiTouch Device %s reported %zu slots but the framework " + "only supports a maximum of %zu slots at this time.", getDeviceName().string(), slotCount, MAX_SLOTS); slotCount = MAX_SLOTS; } @@ -6305,7 +6305,7 @@ void JoystickInputMapper::configure(nsecs_t when, // If there are too many axes, start dropping them. // Prefer to keep explicitly mapped axes. if (mAxes.size() > PointerCoords::MAX_AXES) { - ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.", + ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES); pruneAxes(true); pruneAxes(false); diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index fe61918..18cd8eb 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -36,6 +36,7 @@ bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { bool InputWindowInfo::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG + || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; } diff --git a/libs/input/InputWindow.h b/libs/input/InputWindow.h index 28fa7ab..bd325b5 100644 --- a/libs/input/InputWindow.h +++ b/libs/input/InputWindow.h @@ -105,6 +105,7 @@ struct InputWindowInfo { TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, + TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27, LAST_SYSTEM_WINDOW = 2999, }; diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c index 06b477f..57c0320 100644 --- a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c +++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c @@ -32,7 +32,7 @@ struct usb_device *sDevice = NULL; static void* read_thread(void* arg) { - int endpoint = (int)arg; + int endpoint = (int)(uintptr_t)arg; int ret = 0; while (sDevice && ret >= 0) { @@ -52,7 +52,7 @@ static void* read_thread(void* arg) { } static void* write_thread(void* arg) { - int endpoint = (int)arg; + int endpoint = (int)(uintptr_t)arg; int ret = 0; while (ret >= 0) { @@ -136,11 +136,11 @@ static int usb_device_added(const char *devname, void* client_data) { } if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - pthread_create(&th, NULL, read_thread, (void *)ep1->bEndpointAddress); - pthread_create(&th, NULL, write_thread, (void *)ep2->bEndpointAddress); + pthread_create(&th, NULL, read_thread, (void *)(uintptr_t)ep1->bEndpointAddress); + pthread_create(&th, NULL, write_thread, (void *)(uintptr_t)ep2->bEndpointAddress); } else { - pthread_create(&th, NULL, read_thread, (void *)ep2->bEndpointAddress); - pthread_create(&th, NULL, write_thread, (void *)ep1->bEndpointAddress); + pthread_create(&th, NULL, read_thread, (void *)(uintptr_t)ep2->bEndpointAddress); + pthread_create(&th, NULL, write_thread, (void *)(uintptr_t)ep1->bEndpointAddress); } } else { printf("Found possible android device - attempting to switch to accessory mode\n"); |