diff options
author | MÃ¥rten Kongstad <marten.kongstad@sonymobile.com> | 2014-01-31 14:43:27 +0100 |
---|---|---|
committer | Zoran Jovanovic <zoran.jovanovic@sonymobile.com> | 2014-02-03 11:20:30 +0100 |
commit | 48d22323ce39f9aab003dce74456889b6414af55 (patch) | |
tree | 510aa964078d251874e2c0e7c8556f237b5710c4 /libs/androidfw | |
parent | 65a05fd56dbc9fd9c2511a97f49c445a748fb3c5 (diff) | |
download | frameworks_base-48d22323ce39f9aab003dce74456889b6414af55.zip frameworks_base-48d22323ce39f9aab003dce74456889b6414af55.tar.gz frameworks_base-48d22323ce39f9aab003dce74456889b6414af55.tar.bz2 |
Runtime resource overlay, iteration 2
Support any number of overlay packages. Support any target package.
UPDATED PACKAGE MATCHING
------------------------
In Runtime resource overlay, iteration 1, only a single overlay package
was considered. Package matching was based on file paths:
/vendor/overlay/system/framework-res.apk corresponded to
/system/framework-res.apk. Introduce a more flexible matching scheme
where any package is an overlay package if its manifest includes
<overlay targetPackage="com.target.package"/>
For security reasons, an overlay package must fulfill certain criteria
to take effect: see below.
THE IDMAP TOOL AND IDMAP FILES
------------------------------
Idmap files are created by the 'idmap' binary; idmap files must be
present when loading packages. For the Android system, Zygote calls
'idmap' as part of the resource pre-loading. For application packages,
'idmap' is invoked via 'installd' during package installation (similar
to 'dexopt').
UPDATED FLOW
------------
The following is an outline of the start-up sequences for the Android
system and Android apps. Steps marked with '+' are introduced by this
commit.
Zygote initialization
Initial AssetManager object created
+ idmap --scan creates idmaps for overlays targeting 'android', \
stores list of overlays in /data/resource-cache/overlays.list
AssetManager caches framework-res.apk
+ AssetManager caches overlay packages listed in overlays.list
Android boot
New AssetManager's ResTable acquired
AssetManager re-uses cached framework-res.apk
+ AssetManager re-uses cached 'android' overlays (if any)
App boot
ActivityThread prepares AssetManager to load app.apk
+ ActivityThread prepares AssetManager to load app overlays (if any)
New AssetManager's ResTable acquired as per Android boot
SECURITY
--------
Overlay packages are required to be pre-loaded (in /vendor/overlay).
These packages are trusted by definition. A future iteration of runtime
resource overlay may add support for downloaded overlays, which would
likely require target and overlay signatures match for the overlay to
be trusted.
LOOKUP PRIORITY
---------------
During resource lookup, packages are sequentially queried to provide a
best match, given the constraints of the current configuration. If any
package provide a better match than what has been found so far, it
replaces the previous match. The target package is always queried last.
When loading a package with more than one overlay, the order in which
the overlays are added become significant if several packages overlay
the same resource.
Had downloaded overlays been supported, the install time could have been
used to determine the load order. Regardless, for pre-installed
overlays, the install time is randomly determined by the order in which
the Package Manager locates the packages during initial boot. To support
a well-defined order, pre-installed overlay packages are expected to
define an additional 'priority' attribute in their <overlay> tags:
<overlay targetPackage="com.target.package" priority="1234"/>
Pre-installed overlays are loaded in order of their priority attributes,
sorted in ascending order.
Assigning the same priority to several overlays targeting the same base
package leads to undefined behaviour. It is the responsibility of the
vendor to avoid this.
The following example shows the ResTable and PackageGroups after loading
an application and two overlays. The resource lookup framework will
query the packages in the order C, B, A.
+------+------+- -+------+------+
| 0x01 | | ... | | 0x7f |
+------+------+- -+------+------+
| |
"android" Target package A
|
Pre-installed overlay B (priority 1)
|
Pre-installed overlay C (priority 2)
Change-Id: If49c963149369b1957f7d2303b3dd27f669ed24e
Diffstat (limited to 'libs/androidfw')
-rw-r--r-- | libs/androidfw/AssetManager.cpp | 314 | ||||
-rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 76 |
2 files changed, 218 insertions, 172 deletions
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 251d47b..05a948d 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"; @@ -84,15 +82,19 @@ 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); @@ -210,203 +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::createIdmap(const char* targetApkPath, const char* overlayApkPath, - uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, uint32_t* outSize) +bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie) { - AutoMutex _l(mLock); - const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) }; - ResTable tables[2]; + const String8 idmapPath = idmapPathForPackagePath(packagePath); - for (int i = 0; i < 2; ++i) { - asset_path ap; - ap.type = kFileTypeRegular; - 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()); - return false; - } - tables[i].add(ass, (void*)1, false); - } + AutoMutex _l(mLock); - return tables[0].createIdmap(tables[1], targetCrc, overlayCrc, - targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; -} + for (size_t i = 0; i < mAssetPaths.size(); ++i) { + if (mAssetPaths[i].idmap == idmapPath) { + *cookie = static_cast<int32_t>(i + 1); + return true; + } + } -bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath) -{ - 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); + Asset* idmap = NULL; + if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) { + ALOGW("failed to open idmap file %s\n", idmapPath.string()); 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)); - 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, uint32_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; + return false; } tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */); } - 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; - } - } - - 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() @@ -685,6 +583,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)-> @@ -708,6 +610,14 @@ const ResTable* AssetManager::getResTable(bool required) const ALOGV("Creating shared resources for %s", ap.path.string()); sharedRes = new ResTable(); 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); } @@ -791,6 +701,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); @@ -1849,7 +1799,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); @@ -1857,6 +1808,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; @@ -1915,6 +1869,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); @@ -2038,6 +2006,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/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 609ad19..8cc98af 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -284,11 +284,37 @@ 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; } @@ -5334,23 +5360,30 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, 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; @@ -5426,8 +5459,22 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui } uint32_t* data = (uint32_t*)*outData; *data++ = htodl(IDMAP_MAGIC); - *data++ = htodl(originalCrc); + *data++ = htodl(targetCrc); *data++ = htodl(overlayCrc); + const char* paths[] = { targetPath, overlayPath }; + for (int j = 0; j < 2; ++j) { + char* p = (char*)data; + const char* path = paths[j]; + const size_t I = strlen(path); + if (I > 255) { + ALOGV("path exceeds expected 255 characters: %s\n", path); + return UNKNOWN_ERROR; + } + for (size_t i = 0; i < 256; ++i) { + *p++ = i < I ? path[i] : '\0'; + } + data += 256 / sizeof(uint32_t); + } const size_t mapSize = map.size(); *data++ = htodl(mapSize); size_t offset = mapSize; @@ -5442,6 +5489,10 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui offset += N; } } + if (offset == mapSize) { + ALOGW("idmap: no resources in overlay package present in base package\n"); + return UNKNOWN_ERROR; + } for (size_t i = 0; i < mapSize; ++i) { const Vector<uint32_t>& vector = map.itemAt(i); const size_t N = vector.size(); @@ -5463,14 +5514,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; } |