summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/utils/Android.mk2
-rw-r--r--libs/utils/AssetManager.cpp406
-rw-r--r--libs/utils/FileLock.cpp96
-rw-r--r--libs/utils/PackageRedirectionMap.cpp191
-rw-r--r--libs/utils/ResourceTypes.cpp249
5 files changed, 213 insertions, 731 deletions
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index d077fec..2726cf2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -25,10 +25,10 @@ commonSources:= \
CallStack.cpp \
Debug.cpp \
FileMap.cpp \
- FileLock.cpp \
Flattenable.cpp \
ObbFile.cpp \
Pool.cpp \
+ PackageRedirectionMap.cpp \
RefBase.cpp \
ResourceTypes.cpp \
SharedBuffer.cpp \
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 28dc6c0..4513a06 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -33,7 +33,6 @@
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/threads.h>
-#include <utils/FileLock.h>
#include <dirent.h>
#include <sys/stat.h>
@@ -41,8 +40,6 @@
#include <errno.h>
#include <assert.h>
-#define REDIRECT_NOISY(x) //x
-
using namespace android;
/*
@@ -77,7 +74,6 @@ int32_t AssetManager::getGlobalCount()
AssetManager::AssetManager(CacheMode cacheMode)
: mLocale(NULL), mVendor(NULL),
- mThemePackageName(NULL),
mResources(NULL), mConfig(new ResTable_config),
mCacheMode(cacheMode), mCacheValid(false)
{
@@ -97,10 +93,6 @@ AssetManager::~AssetManager(void)
// don't have a String class yet, so make sure we clean up
delete[] mLocale;
delete[] mVendor;
-
- if (mThemePackageName != NULL) {
- delete[] mThemePackageName;
- }
}
bool AssetManager::addAssetPath(const String8& path, void** cookie)
@@ -438,365 +430,6 @@ static SharedBuffer* addToEntriesByTypeBuffer(SharedBuffer* buf, uint32_t from,
return buf;
}
-// TODO: Terrible, terrible I/O error handling here!
-static bool writeRedirections(const char* redirPath, SharedBuffer* entriesByTypeBuf)
-{
- REDIRECT_NOISY(LOGW("writing %s\n", redirPath));
-
- FILE* fp = fopen(redirPath, "w");
- if (!fp) {
- LOGE("fopen(%s,r) failed: %s\n", redirPath, strerror(errno));
- return false;
- }
-
- uint16_t version = 1;
- fwrite(&version, sizeof(version), 1, fp);
-
- uint16_t totalTypes = 0;
- size_t typeSize = (entriesByTypeBuf != NULL) ? entriesByTypeBuf->size() / sizeof(uint32_t*) : 0;
- uint32_t** entriesByType = (uint32_t**)entriesByTypeBuf->data();
- for (size_t i=0; i<typeSize; i++) {
- uint32_t* entries = entriesByType[i];
- if (entries != NULL) {
- totalTypes++;
- }
- }
-
- REDIRECT_NOISY(LOGW("writing %d total types\n", (int)totalTypes));
- fwrite(&totalTypes, sizeof(totalTypes), 1, fp);
-
- // Start offset for the first type table.
- uint32_t typeSectionOffset = 4 + (9 * totalTypes);
-
- for (size_t i=0; i<typeSize; i++) {
- uint32_t* entries = entriesByType[i];
- if (entries != NULL) {
- uint8_t type = i;
- fwrite(&type, sizeof(type), 1, fp);
- size_t entrySize = SharedBuffer::bufferFromData(entries)->size() / sizeof(uint32_t);
- size_t numEntries = 0;
- for (size_t j=0; j<entrySize; j++) {
- if (entries[j] != 0) {
- numEntries++;
- }
- }
- REDIRECT_NOISY(LOGW("%d entries for type %d\n", (int)numEntries, (int)type));
- fwrite(&typeSectionOffset, sizeof(typeSectionOffset), 1, fp);
- uint32_t typeSectionLength = numEntries * 6;
- fwrite(&typeSectionLength, sizeof(typeSectionLength), 1, fp);
- typeSectionOffset += typeSectionLength;
- }
- }
-
- for (size_t i=0; i<typeSize; i++) {
- uint32_t* entries = entriesByType[i];
- if (entries != NULL) {
- REDIRECT_NOISY(LOGW("writing for type %d...\n", i));
- size_t entrySize = SharedBuffer::bufferFromData(entries)->size() / sizeof(uint32_t);
- for (size_t j=0; j<entrySize; j++) {
- uint32_t resID = entries[j];
- if (resID != 0) {
- uint16_t entryIndex = j;
- REDIRECT_NOISY(LOGW("writing 0x%04x => 0x%08x\n", entryIndex, resID));
- fwrite(&entryIndex, sizeof(entryIndex), 1, fp);
- fwrite(&resID, sizeof(resID), 1, fp);
- }
- }
- SharedBuffer::bufferFromData(entries)->release();
- }
- }
-
- if (entriesByTypeBuf != NULL) {
- entriesByTypeBuf->release();
- }
-
- fclose(fp);
-
- REDIRECT_NOISY(LOGW("written...\n"));
-
- return true;
-}
-
-// Crude, lame brute force way to generate the initial framework redirections
-// for testing. This code should be generalized and follow a much better OO
-// structure.
-static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBuf, ResTable* rt,
- const char* themePackageName, uint32_t styleId, const char* redirPath)
-{
- REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s, styleId=0x%08x\n", themePackageName, styleId));
-
- rt->lock();
-
- // Load up a bag for the user-supplied theme.
- const ResTable::bag_entry* themeEnt = NULL;
- ssize_t N = rt->getBagLocked(styleId, &themeEnt);
- const ResTable::bag_entry* endThemeEnt = themeEnt + (N >= 0 ? N : 0);
-
- // ...and a bag for the framework default.
- const ResTable::bag_entry* frameworkEnt = NULL;
- N = rt->getBagLocked(0x01030005, &frameworkEnt);
- const ResTable::bag_entry* endFrameworkEnt = frameworkEnt + (N >= 0 ? N : 0);
-
- // The first entry should be for the theme itself.
- entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, styleId);
-
- // Now compare them and infer resource redirections for attributes that
- // remap to different styles. This works by essentially lining up all the
- // sorted attributes from each theme and detected TYPE_REFERENCE entries
- // that point to different resources. When we find such a mismatch, we'll
- // create a resource redirection from the original framework resource ID to
- // the one in the theme. This lets us do things like automatically find
- // redirections for @android:style/Widget.Button by looking at how the
- // theme overrides the android:attr/buttonStyle attribute.
- REDIRECT_NOISY(LOGW("delta between 0x01030005 and 0x%08x:\n", styleId));
- for (; frameworkEnt < endFrameworkEnt; frameworkEnt++) {
- if (frameworkEnt->map.value.dataType != Res_value::TYPE_REFERENCE) {
- continue;
- }
-
- uint32_t curIdent = frameworkEnt->map.name.ident;
-
- // Walk along the theme entry looking for a match.
- while (themeEnt < endThemeEnt && curIdent > themeEnt->map.name.ident) {
- themeEnt++;
- }
- // Match found, compare the references.
- if (themeEnt < endThemeEnt && curIdent == themeEnt->map.name.ident) {
- if (themeEnt->map.value.data != frameworkEnt->map.value.data) {
- entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf,
- frameworkEnt->map.value.data, themeEnt->map.value.data);
- REDIRECT_NOISY(LOGW(" generated mapping from 0x%08x => 0x%08x (by attr 0x%08x)\n", frameworkEnt->map.value.data,
- themeEnt->map.value.data, curIdent));
- }
- themeEnt++;
- }
-
- // Exhausted the theme, bail early.
- if (themeEnt >= endThemeEnt) {
- break;
- }
- }
-
- rt->unlock();
-
- return entriesByTypeBuf;
-}
-
-static SharedBuffer* parseRedirections(SharedBuffer* buf, ResTable* rt,
- ResXMLTree& xml, String16& themePackage, String16& resPackage)
-{
- ResXMLTree::event_code_t eventType = xml.getEventType();
- REDIRECT_NOISY(LOGW("initial eventType=%d\n", (int)eventType));
- size_t len;
- while (eventType != ResXMLTree::END_DOCUMENT) {
- if (eventType == ResXMLTree::START_TAG) {
- String8 outerTag(xml.getElementName(&len));
- if (outerTag == "resource-redirections") {
- REDIRECT_NOISY(LOGW("got resource-redirections tag\n"));
- xml.next();
- while ((eventType = xml.getEventType()) != ResXMLTree::END_TAG) {
- if (eventType == ResXMLTree::START_TAG) {
- String8 itemTag(xml.getElementName(&len));
- if (itemTag == "item") {
- REDIRECT_NOISY(LOGW("got item tag\n"));
- ssize_t nameIdx = xml.indexOfAttribute(NULL, "name");
- size_t fromLen;
- const char16_t* fromName = NULL;
- size_t toLen;
- const char16_t* toName = NULL;
- if (nameIdx >= 0) {
- fromName = xml.getAttributeStringValue(nameIdx, &fromLen);
- REDIRECT_NOISY(LOGW(" got from %s\n", String8(fromName).string()));
- }
- if (xml.next() == ResXMLTree::TEXT) {
- toName = xml.getText(&toLen);
- REDIRECT_NOISY(LOGW(" got to %s\n", String8(toName).string()));
- xml.next();
- }
- if (toName != NULL && fromName != NULL) {
- // fromName should look "drawable/foo", so we'll
- // let identifierForName parse that part of it, but
- // make sure to provide the background ourselves.
- // TODO: we should check that the package isn't
- // already in the string and error out if it is...
- uint32_t fromIdent = rt->identifierForName(fromName, fromLen, NULL, 0,
- resPackage.string(), resPackage.size());
- if (fromIdent == 0) {
- LOGW("Failed to locate identifier for resource %s:%s\n",
- String8(fromName, fromLen).string(), String8(resPackage).string());
- } else {
- uint32_t toIdent = rt->identifierForName(toName, toLen, NULL, 0,
- themePackage.string(), themePackage.size());
- if (toIdent == 0) {
- LOGW("Failed to locate identifier for resource %s:%s\n",
- String8(toName, toLen).string(), String8(themePackage).string());
- } else {
- REDIRECT_NOISY(LOGW("adding fromIdent=0x%08x to toIdent=0x%08x\n", fromIdent, toIdent));
- buf = addToEntriesByTypeBuffer(buf, fromIdent, toIdent);
- }
- }
- }
- } else {
- REDIRECT_NOISY(LOGW("unexpected tag %s\n", itemTag.string()));
- }
- } else if (eventType == ResXMLTree::END_DOCUMENT) {
- return buf;
- }
- xml.next();
- }
- }
- }
-
- eventType = xml.next();
- }
-
- return buf;
-}
-
-// Generate redirections from XML meta data. This code should be moved into
-// the Java space at some point, generated by a special service.
-SharedBuffer* AssetManager::generateRedirections(SharedBuffer* entriesByTypeBuf,
- ResTable* rt, const char* themePackageName,
- const char16_t* resPackageName)
-{
- REDIRECT_NOISY(LOGW("generateRedirections: themePackageName=%s; resPackageName=%s\n",
- themePackageName, String8(resPackageName).string()));
-
- String16 type("xml");
- String16 name(resPackageName);
- name.replaceAll('.', '_');
- String16 package(themePackageName);
- uint32_t xmlIdent = rt->identifierForName(name.string(), name.size(), type.string(), type.size(),
- package.string(), package.size());
- REDIRECT_NOISY(LOGW("xmlIdent=0x%08x from %s:%s/%s\n", xmlIdent,
- String8(package).string(), String8(type).string(), String8(name).string()));
- if (xmlIdent != 0) {
- // All this junk is being simulated from the Java side implementation.
- // This is very clumsy and poorly thought through/tested. This code
- // will eventually be merged into the Java layer.
- Res_value value;
- ssize_t block = rt->getResource(xmlIdent, &value);
- block = rt->resolveReference(&value, block, &xmlIdent);
- if (block < 0 || value.dataType != Res_value::TYPE_STRING) {
- LOGE("Bad redirection XML resource #0x%08x\n", xmlIdent);
- } else {
- size_t len;
- const char16_t* str = rt->valueToString(&value, block, NULL, &len);
- void* cookie = rt->getTableCookie(block);
- const size_t whichAssetPath = ((size_t)cookie)-1;
- Asset* asset = openNonAssetInPathLocked(
- String8(str).string(), Asset::ACCESS_BUFFER,
- mAssetPaths.itemAt(whichAssetPath));
- if (asset == NULL || asset == kExcludedAsset) {
- LOGE("XML resource %s not found in package\n", String8(str).string());
- } else {
- ResXMLTree xml;
- status_t err = xml.setTo(asset->getBuffer(true), asset->getLength());
-
- xml.restart();
-
- String16 resPackage(resPackageName);
- entriesByTypeBuf = parseRedirections(entriesByTypeBuf, rt, xml,
- package, resPackage);
-
- xml.uninit();
-
- asset->close();
- delete asset;
- }
- }
- }
-
- return entriesByTypeBuf;
-}
-
-bool AssetManager::generateAndWriteRedirections(ResTable* rt,
- const char* themePackageName, uint32_t themeStyleId,
- const char16_t* resPackageName, const char* redirPath,
- bool isFramework) const
-{
- // FIXME: the const is a lie!!!
- AssetManager* am = (AssetManager*)this;
-
- SharedBuffer* buf = NULL;
- if (isFramework && themeStyleId != 0) {
- // Special framework theme heuristic...
- buf = generateFrameworkRedirections(buf, rt, themePackageName,
- themeStyleId, redirPath);
- }
- // Generate redirections from the package XML.
- buf = am->generateRedirections(buf, rt, themePackageName, resPackageName);
-
- return writeRedirections(redirPath, buf);
-}
-
-void AssetManager::loadRedirectionMappings(ResTable* rt) const
-{
- rt->clearRedirections();
-
- if (mThemePackageName != NULL) {
- const char* data = getenv("ANDROID_DATA");
- LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
-
- // Create the basic directory structure on demand.
- struct stat statbuf;
- String8 basePath(data);
- basePath.appendPath(kThemeResCacheDir);
- createDirIfNecessary(basePath.string(), 0777, &statbuf);
- basePath.appendPath(mThemePackageName);
- createDirIfNecessary(basePath.string(), 0777, &statbuf);
-
- String8 themeDirLockPath(basePath);
- themeDirLockPath.append(".lck");
-
- FileLock* themeDirLock = new FileLock(themeDirLockPath.string());
- themeDirLock->lock();
-
- // Load (generating if necessary) the cache files for each installed
- // package in this ResTable, excluding the framework's "android"
- // package.
- bool hasFramework = false;
- const size_t N = rt->getBasePackageCount();
- for (size_t i=0; i<N; i++) {
- uint32_t packageId = rt->getBasePackageId(i);
-
- // No need to regenerate the 0x01 framework resources.
- if (packageId == 0x7f) {
- String8 redirPath(basePath);
- const char16_t* resPackageName = rt->getBasePackageName(i);
- redirPath.appendPath(String8(resPackageName));
-
- if (lstat(redirPath.string(), &statbuf) != 0) {
- generateAndWriteRedirections(rt, mThemePackageName,
- mThemeStyleId, resPackageName, redirPath.string(),
- false);
- }
-
- rt->addRedirections(packageId, redirPath.string());
- } else if (packageId == 0x01) {
- hasFramework = true;
- }
- }
-
- // Handle the "android" package space as a special case using some
- // fancy heuristics.
- if (hasFramework) {
- String8 frameworkRedirPath(basePath);
- frameworkRedirPath.appendPath("android");
-
- if (lstat(frameworkRedirPath.string(), &statbuf) != 0) {
- generateAndWriteRedirections(rt, mThemePackageName,
- mThemeStyleId, String16("android").string(),
- frameworkRedirPath.string(), true);
- }
-
- rt->addRedirections(0x01, frameworkRedirPath.string());
- }
-
- themeDirLock->unlock();
- }
-}
-
const ResTable* AssetManager::getResTable(bool required) const
{
ResTable* rt = mResources;
@@ -827,7 +460,6 @@ const ResTable* AssetManager::getResTable(bool required) const
const asset_path& ap = mAssetPaths.itemAt(i);
updateResTableFromAssetPath(rt, ap, (void*)(i+1));
}
- loadRedirectionMappings(rt);
}
if (required && !rt) LOGW("Unable to find resources file resources.arsc");
@@ -2195,28 +1827,6 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const
return mZipPath.size()-1;
}
-/*
- * Set the currently applied theme package name and the high-level theme style
- * identifier (the one to replace @android:style/Theme). May be set to NULL, 0
- * to indicate that this AssetManager does not have an added theme package.
- *
- * This information is used when constructing the ResTable's resource
- * redirection map.
- */
-void AssetManager::setThemePackageInfo(const char* packageName, uint32_t styleId)
-{
- if (mThemePackageName != NULL) {
- delete[] mThemePackageName;
- }
- mThemePackageName = strdupNew(packageName);
- mThemeStyleId = styleId;
-}
-
-const char* AssetManager::getThemePackageName()
-{
- return mThemePackageName;
-}
-
bool AssetManager::updateWithAssetPath(const String8& path, void** cookie)
{
bool res = addAssetPath(path, cookie);
@@ -2225,7 +1835,6 @@ bool AssetManager::updateWithAssetPath(const String8& path, void** cookie)
AutoMutex _l(mLock);
const asset_path& ap = mAssetPaths.itemAt((size_t)*cookie - 1);
updateResTableFromAssetPath(rt, ap, *cookie);
- loadRedirectionMappings(rt);
}
return res;
}
@@ -2240,7 +1849,6 @@ bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie)
return false;
}
- rt->clearRedirections();
rt->removeAssetsByCookie(packageName, (void *)cookie);
return true;
@@ -2255,3 +1863,17 @@ void AssetManager::dumpRes()
}
rt->dump();
}
+
+void AssetManager::addRedirections(PackageRedirectionMap* resMap)
+{
+ getResources();
+ ResTable* rt = mResources;
+ rt->addRedirections(resMap);
+}
+
+void AssetManager::clearRedirections()
+{
+ getResources();
+ ResTable* rt = mResources;
+ rt->clearRedirections();
+}
diff --git a/libs/utils/FileLock.cpp b/libs/utils/FileLock.cpp
deleted file mode 100644
index a25a0e6..0000000
--- a/libs/utils/FileLock.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2010, T-Mobile USA, Inc.
- *
- * 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.
- */
-
-//
-// File locking utility
-//
-
-#define LOG_TAG "filelock"
-
-#include <utils/FileLock.h>
-#include <utils/Log.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Constructor. Create an unlocked object.
- */
-FileLock::FileLock(const char* fileName)
- : mRefCount(0), mFd(-1), mFileName(strdup(fileName))
-{
- assert(mFileName != NULL);
-}
-
-static struct flock fullfileLock(short lockType)
-{
- struct flock lock;
- memset(&lock, 0, sizeof(lock));
-
- lock.l_type = lockType;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
-
- return lock;
-}
-
-/*
- * Destructor.
- */
-FileLock::~FileLock(void)
-{
- assert(mRefCount == 0);
-
- if (mFd >= 0) {
- struct flock lock(fullfileLock(F_UNLCK));
- if (fcntl(mFd, F_SETLK, &lock) == -1) {
- LOGE("error releasing write lock on %s: %s\n", mFileName, strerror(errno));
- }
- if (close(mFd) != 0) {
- LOGE("close(%s) failed: %s\n", mFileName, strerror(errno));
- }
- }
- if (mFileName != NULL) {
- free(mFileName);
- }
-}
-
-bool FileLock::doLock(int openFlags, mode_t fileCreateMode)
-{
- int fd = open(mFileName, openFlags | O_CREAT, fileCreateMode);
- if (fd == -1) {
- return false;
- }
-
- struct flock lock(fullfileLock(F_WRLCK));
- while (fcntl(fd, F_SETLKW, &lock) == -1) {
- if (errno != EINTR) {
- LOGE("error acquiring write lock on %s: %s\n", mFileName, strerror(errno));
- close(fd);
- return false;
- }
- }
-
- mFd = fd;
- return true;
-}
diff --git a/libs/utils/PackageRedirectionMap.cpp b/libs/utils/PackageRedirectionMap.cpp
new file mode 100644
index 0000000..bf1062a
--- /dev/null
+++ b/libs/utils/PackageRedirectionMap.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
+ *
+ * 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.
+ */
+
+//
+// Provide access to read-only assets.
+//
+
+#define LOG_TAG "packageresmap"
+
+#include <utils/PackageRedirectionMap.h>
+#include <utils/ResourceTypes.h>
+#include <utils/misc.h>
+
+using namespace android;
+
+PackageRedirectionMap::PackageRedirectionMap()
+ : mPackage(-1), mEntriesByType(NULL)
+{
+}
+
+static void clearEntriesByType(uint32_t** entriesByType)
+{
+ SharedBuffer* buf = SharedBuffer::bufferFromData(entriesByType);
+ const size_t N = buf->size() / sizeof(entriesByType[0]);
+ for (size_t i = 0; i < N; i++) {
+ uint32_t* entries = entriesByType[i];
+ if (entries != NULL) {
+ SharedBuffer::bufferFromData(entries)->release();
+ }
+ }
+ buf->release();
+}
+
+PackageRedirectionMap::~PackageRedirectionMap()
+{
+ if (mEntriesByType != NULL) {
+ clearEntriesByType(mEntriesByType);
+ }
+}
+
+static void* ensureCapacity(void* data, size_t nmemb, size_t size)
+{
+ SharedBuffer* buf;
+ size_t currentSize;
+
+ if (data != NULL) {
+ buf = SharedBuffer::bufferFromData(data);
+ currentSize = buf->size();
+ } else {
+ buf = NULL;
+ currentSize = 0;
+ }
+
+ size_t minSize = nmemb * size;
+ if (minSize > currentSize) {
+ unsigned int requestSize = roundUpPower2(minSize);
+ if (buf == NULL) {
+ buf = SharedBuffer::alloc(requestSize);
+ } else {
+ buf = buf->editResize(requestSize);
+ }
+ memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize);
+ }
+
+ return buf->data();
+}
+
+bool PackageRedirectionMap::addRedirection(uint32_t fromIdent, uint32_t toIdent)
+{
+ const int package = Res_GETPACKAGE(fromIdent);
+ const int type = Res_GETTYPE(fromIdent);
+ const int entry = Res_GETENTRY(fromIdent);
+
+ // The first time we add a redirection we can infer the package for all
+ // future redirections.
+ if (mPackage == -1) {
+ mPackage = package+1;
+ } else if (mPackage != (package+1)) {
+ LOGW("cannot add redirection for conflicting package 0x%02x (expecting package 0x%02x)\n", package+1, mPackage);
+ return false;
+ }
+
+ mEntriesByType = (uint32_t**)ensureCapacity(mEntriesByType, type + 1, sizeof(uint32_t*));
+ uint32_t* entries = mEntriesByType[type];
+ entries = (uint32_t*)ensureCapacity(entries, entry + 1, sizeof(uint32_t));
+ entries[entry] = toIdent;
+ mEntriesByType[type] = entries;
+
+ return true;
+}
+
+uint32_t PackageRedirectionMap::lookupRedirection(uint32_t fromIdent)
+{
+ if (mPackage == -1 || mEntriesByType == NULL || fromIdent == 0) {
+ return 0;
+ }
+
+ const int package = Res_GETPACKAGE(fromIdent);
+ const int type = Res_GETTYPE(fromIdent);
+ const int entry = Res_GETENTRY(fromIdent);
+
+ if (package+1 != mPackage) {
+ return 0;
+ }
+
+ size_t nTypes = getNumberOfTypes();
+ if (type < 0 || type >= nTypes) {
+ return 0;
+ }
+ uint32_t* entries = mEntriesByType[type];
+ if (entries == NULL) {
+ return 0;
+ }
+ size_t nEntries = getNumberOfEntries(type);
+ if (entry < 0 || entry >= nEntries) {
+ return 0;
+ }
+ return entries[entry];
+}
+
+int PackageRedirectionMap::getPackage()
+{
+ return mPackage;
+}
+
+size_t PackageRedirectionMap::getNumberOfTypes()
+{
+ if (mEntriesByType == NULL) {
+ return 0;
+ } else {
+ return SharedBuffer::bufferFromData(mEntriesByType)->size() /
+ sizeof(mEntriesByType[0]);
+ }
+}
+
+size_t PackageRedirectionMap::getNumberOfUsedTypes()
+{
+ uint32_t** entriesByType = mEntriesByType;
+ size_t N = getNumberOfTypes();
+ size_t count = 0;
+ for (size_t i=0; i<N; i++) {
+ if (entriesByType[i] != NULL) {
+ count++;
+ }
+ }
+ return count;
+}
+
+size_t PackageRedirectionMap::getNumberOfEntries(int type)
+{
+ uint32_t* entries = mEntriesByType[type];
+ if (entries == NULL) {
+ return 0;
+ } else {
+ return SharedBuffer::bufferFromData(entries)->size() /
+ sizeof(entries[0]);
+ }
+}
+
+size_t PackageRedirectionMap::getNumberOfUsedEntries(int type)
+{
+ size_t N = getNumberOfEntries(type);
+ uint32_t* entries = mEntriesByType[type];
+ size_t count = 0;
+ for (size_t i=0; i<N; i++) {
+ if (entries[i] != 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+uint32_t PackageRedirectionMap::getEntry(int type, int entry)
+{
+ uint32_t* entries = mEntriesByType[type];
+ return entries[entry];
+}
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index f7bee02..d9e5012 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -2057,14 +2057,12 @@ uint32_t ResTable::lookupRedirectionMap(uint32_t resID) const
}
const int p = Res_GETPACKAGE(resID)+1;
- const int t = Res_GETTYPE(resID)+1;
- const int e = Res_GETENTRY(resID);
const size_t N = mRedirectionMap.size();
for (size_t i=0; i<N; i++) {
- PackageResMap* resMap = mRedirectionMap[i];
- if (resMap->package == p) {
- return resMap->lookup(t, e);
+ PackageRedirectionMap* resMap = mRedirectionMap[i];
+ if (resMap->getPackage() == p) {
+ return resMap->lookupRedirection(resID);
}
}
return 0;
@@ -4096,127 +4094,6 @@ void ResTable::removeAssetsByCookie(const String8 &packageName, void* cookie)
}
}
-ResTable::PackageResMap::PackageResMap()
- : mEntriesByType(NULL)
-{
-}
-
-ResTable::PackageResMap::~PackageResMap()
-{
- if (mEntriesByType != NULL) {
- SharedBuffer* buf = SharedBuffer::bufferFromData(mEntriesByType);
- const size_t N = buf->size() / sizeof(mEntriesByType[0]);
- for (size_t i = 0; i < N; i++) {
- uint32_t* entries = mEntriesByType[i];
- if (entries != NULL) {
- SharedBuffer::bufferFromData(entries)->release();
- }
- }
- buf->release();
- }
-}
-
-uint32_t* ResTable::PackageResMap::parseMapType(const unsigned char* ptr, const unsigned char* end)
-{
- SharedBuffer* buf = NULL;
- for (; ptr + 6 <= end; ptr += 6) {
- uint16_t entry = *(uint16_t*)ptr;
- uint32_t resID = *(uint32_t*)(ptr + 2);
- REDIRECT_NOISY(LOGW("map type got entry=0x%04x, resID=0x%08x\n", entry, resID));
- size_t currentSize = (buf != NULL) ? buf->size() : 0;
- size_t entrySize = (entry+1) * sizeof(resID);
- if (entrySize > currentSize) {
- unsigned int requestSize = roundUpPower2(entrySize);
- REDIRECT_NOISY(LOGW("allocating buffer (%p) at requestSize=%d\n", buf, (int)requestSize));
- if (buf == NULL) {
- buf = SharedBuffer::alloc(requestSize);
- } else {
- buf = buf->editResize(requestSize);
- }
- memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize);
- REDIRECT_NOISY(LOGW("allocated buf=%p\n", buf));
- }
- uint32_t* entries = (uint32_t*)buf->data();
- entries[entry] = resID;
- }
- return (buf != NULL) ? (uint32_t*)buf->data() : NULL;
-}
-
-/*
- * Parse the resource mappings file.
- *
- * The format of this file begins with a simple header identifying the number
- * of types inside, followed by a table mapping each type to an offset further
- * in the file. At each offset mentioned is a set of resource ID mappings to
- * be parsed out and applied to a sparse array that is ultimately used to
- * lookup resource redirections (the indices are entries in the associated
- * package space and the values are the replacement resID's from the theme
- * itself)
- *
- * Detailed information of each section:
- *
- * | bytes | description
- * |-------+-----------------------
- * | 2 | file format version (first version is 1)
- * | 2 | number of resource types (think Res_GETTYPE) in the mapping
- *
- * For each resource type:
- *
- * +-------+-----------------------
- * | 1 | type identifier
- * | 4 | file offset containing the entry mapping
- * | 4 | length of the entry mapping section for this type
- * ...
- *
- * At each file offset mentioned in the type header:
- *
- * +-------+-----------------------
- * | 2 | entry id to be replaced (combined with the type and package this
- * | | forms a resID)
- * | 4 | resID in the theme space which is to replace the previous entry
- * ...
- */
-bool ResTable::PackageResMap::parseMap(const unsigned char* basePtr,
- const unsigned char* endPtr)
-{
- LOG_FATAL_IF(mEntriesByType != NULL, "parseMap must only be called once");
-
- if (basePtr + 4 > endPtr) {
- return false;
- }
- uint16_t version = *(uint16_t*)basePtr;
- uint16_t numTypes = *(uint16_t*)(basePtr + 2);
- const unsigned char* headerPtr = basePtr + 4;
-
- REDIRECT_NOISY(LOGW("file version=%d\n", version));
- REDIRECT_NOISY(LOGW("read %d numTypes\n", numTypes));
-
- while (numTypes-- > 0) {
- uint8_t type;
- uint32_t* entries = NULL;
- if (headerPtr + 9 < endPtr) {
- type = *(uint8_t*)headerPtr;
- uint32_t offset = *(uint32_t*)(headerPtr + 1);
- uint32_t length = *(uint32_t*)(headerPtr + 5);
- headerPtr += 9;
- REDIRECT_NOISY(LOGW("got type=0x%02x\n", type));
- if (basePtr + offset + length <= endPtr) {
- REDIRECT_NOISY(LOGW("parsing type...\n"));
- const unsigned char* entryStartPtr = basePtr + offset;
- const unsigned char* entryEndPtr = entryStartPtr + length;
- entries = parseMapType(entryStartPtr, entryEndPtr);
- }
- }
- if (entries == NULL) {
- return false;
- }
- REDIRECT_NOISY(LOGW("inserting type 0x%02x with %p\n", type, entries));
- insert(type, entries);
- }
-
- return true;
-}
-
/*
* Load the redirection map from the supplied map path.
*
@@ -4226,130 +4103,18 @@ bool ResTable::PackageResMap::parseMap(const unsigned char* basePtr,
* For this reason, this method should be called only after all resource
* bundles have been added to the table.
*/
-status_t ResTable::addRedirections(int package, const char* cachePath)
+void ResTable::addRedirections(PackageRedirectionMap* resMap)
{
- LOGV("Adding redirections for package 0x%02x at %s\n", package, cachePath);
-
- if (package != 0x01 && package != 0x7f) {
- REDIRECT_NOISY(LOGW("invalid package 0x%02x: should be either 0x01 (android) or 0x7f (application)\n", package));
- return BAD_TYPE;
- }
-
- ResTable::PackageResMap* resMap = ResTable::PackageResMap::createFromCache(package, cachePath);
- if (resMap != NULL) {
- REDIRECT_NOISY(LOGW("loaded cache stuff for cachePath=%s (package=%d)\n", cachePath, package));
- mRedirectionMap.add(resMap);
- return NO_ERROR;
- } else {
- REDIRECT_NOISY(LOGW("failed to parse redirection path at %s\n", cachePath));
- return BAD_TYPE;
- }
+ // TODO: Replace an existing entry matching the same package.
+ mRedirectionMap.add(resMap);
}
void ResTable::clearRedirections()
{
- const size_t N = mRedirectionMap.size();
- for (size_t i=0; i<N; i++) {
- PackageResMap* resMap = mRedirectionMap[i];
- delete resMap;
- }
+ /* This memory is being managed by strong references at the Java layer. */
mRedirectionMap.clear();
}
-ResTable::PackageResMap* ResTable::PackageResMap::createFromCache(int package, const char* cachePath)
-{
- FILE* cacheFile = fopen(cachePath, "r");
- if (cacheFile == NULL) {
- REDIRECT_NOISY(LOGW("unable to open resource mapping path %s: %s\n", cachePath, strerror(errno)));
- return NULL;
- }
-
- if (fseek(cacheFile, 0, SEEK_END) != 0) {
- fclose(cacheFile);
- return NULL;
- }
-
- long length = ftell(cacheFile);
- REDIRECT_NOISY(LOGW("file length is %d\n", (int)length));
- if (length < 4) {
- fclose(cacheFile);
- return NULL;
- }
-
- ResTable::PackageResMap* resMap = NULL;
- FileMap* fileMap = new FileMap;
- if (fileMap != NULL) {
- if (fileMap->create(cachePath, fileno(cacheFile), 0, length, true)) {
- REDIRECT_NOISY(LOGW("successfully mapped %s\n", cachePath));
- resMap = new ResTable::PackageResMap();
- if (resMap != NULL) {
- resMap->package = package;
- const unsigned char* ptr = (const unsigned char*)fileMap->getDataPtr();
- if (!resMap->parseMap(ptr, ptr + length)) {
- REDIRECT_NOISY(LOGW("failed to parse map!\n"));
- delete resMap;
- resMap = NULL;
- }
- }
- } else {
- REDIRECT_NOISY(LOGW("unable to map '%s': %s\n", cachePath, strerror(errno)));
- }
-
- fileMap->release();
- }
-
- fclose(cacheFile);
-
- return resMap;
-}
-
-uint32_t ResTable::PackageResMap::lookup(int type, int entry)
-{
- if (mEntriesByType == NULL) {
- return 0;
- }
- size_t maxTypes = SharedBuffer::bufferFromData(mEntriesByType)->size() /
- sizeof(mEntriesByType[0]);
- if (type < 0 || type >= maxTypes) {
- return 0;
- }
- uint32_t* entries = mEntriesByType[type];
- if (entries == NULL) {
- return 0;
- }
- size_t maxEntries = SharedBuffer::bufferFromData(entries)->size() /
- sizeof(entries[0]);
- if (entry < 0 || entry >= maxEntries) {
- return 0;
- }
- return entries[entry];
-}
-
-void ResTable::PackageResMap::insert(int type, const uint32_t* entries)
-{
- SharedBuffer* buf = NULL;
- size_t currentSize = 0;
- if (mEntriesByType != NULL) {
- buf = SharedBuffer::bufferFromData(mEntriesByType);
- currentSize = buf->size();
- }
- size_t typeSize = (type+1) * sizeof(uint32_t*);
- if (typeSize > currentSize) {
- unsigned int requestSize = roundUpPower2(typeSize);
- REDIRECT_NOISY(LOGW("allocating new type buffer (%p) at size requestSize=%d\n", buf, requestSize));
- if (buf == NULL) {
- buf = SharedBuffer::alloc(requestSize);
- } else {
- buf = buf->editResize(requestSize);
- }
- memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize);
- REDIRECT_NOISY(LOGW("allocated new type buffer %p\n", buf));
- }
- uint32_t** entriesByType = (uint32_t**)buf->data();
- entriesByType[type] = (uint32_t*)entries;
- mEntriesByType = entriesByType;
-}
-
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
#ifndef HAVE_ANDROID_OS