From 5924e96f5f4d6e7a1492bc446b6a21e03eea2fc1 Mon Sep 17 00:00:00 2001 From: Sergey Ten Date: Mon, 30 Mar 2009 10:08:11 -0700 Subject: Add support for restoring asset paths stack in Asset Manager --- libs/utils/AssetManager.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 447b801..624fd7e 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -122,7 +122,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie) return true; } } - + LOGV("In %p Asset %s path: %s", this, ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); @@ -185,7 +185,7 @@ void AssetManager::setLocaleLocked(const char* locale) delete[] mLocale; } mLocale = strdupNew(locale); - + updateResourceParamsLocked(); } @@ -591,7 +591,7 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m /* look at the filesystem on disk */ String8 path(createPathNameLocked(ap, locale, vendor)); path.appendPath(fileName); - + String8 excludeName(path); excludeName.append(kExcludeExtension); if (::getFileType(excludeName.string()) != kFileTypeNonexistent) { @@ -599,28 +599,28 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m //printf("+++ excluding '%s'\n", (const char*) excludeName); return kExcludedAsset; } - + pAsset = openAssetFromFileLocked(path, mode); - + if (pAsset == NULL) { /* try again, this time with ".gz" */ path.append(".gz"); pAsset = openAssetFromFileLocked(path, mode); } - + if (pAsset != NULL) pAsset->setAssetSource(path); } else { /* find in cache */ String8 path(createPathNameLocked(ap, locale, vendor)); path.appendPath(fileName); - + AssetDir::FileInfo tmpInfo; bool found = false; - + String8 excludeName(path); excludeName.append(kExcludeExtension); - + if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) { /* go no farther */ //printf("+++ Excluding '%s'\n", (const char*) excludeName); @@ -1384,7 +1384,7 @@ bool AssetManager::fncScanAndMergeDirLocked( // XXX This is broken -- the filename cache needs to hold the base // asset path separately from its filename. - + partialPath = createPathNameLocked(ap, locale, vendor); if (dirName[0] != '\0') { partialPath.appendPath(dirName); @@ -1635,3 +1635,22 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } +/* + * Mark asset path "stack" to support un-install from the mAssetPaths. + */ +int AssetManager::markAssetPathStack() +{ + return (int)mAssetPaths.size(); +} + +/* + * Restore asset path "stack" by un-installing from the mAssetPaths + * all assets installed after restoreIndex. + */ +void AssetManager::restoreAssetPathStack(int restoreIndex) +{ + int i = (int)mAssetPaths.size(); + while (i > restoreIndex) { + mAssetPaths.removeAt(--i); + } +} -- cgit v1.1 From fd2649b1b6f5c7750c9cb0f13a6cc80522d09678 Mon Sep 17 00:00:00 2001 From: Sergey Ten Date: Mon, 7 Sep 2009 10:33:56 -0700 Subject: Add support for modifying ResTable on fly. This change allows to either delete or add asset path after a ResTable object has been created for a given AssetManager. In past, the lack of such support forced us to implement update configuration functionality suboptimally, by recreating new AssetManager object from scratch on theme change. With this change, we can simply remove the "old" theme asset path and add the new asset path. We also need to make sure the Resources object nukes internal caches. CR:JoshG. --- libs/utils/AssetManager.cpp | 145 ++++++++++++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 51 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 624fd7e..7681695 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -392,45 +392,13 @@ const ResTable* AssetManager::getResTable(bool required) const if (mCacheMode != CACHE_OFF && !mCacheValid) const_cast(this)->loadFileNameCacheLocked(); - const size_t N = mAssetPaths.size(); - for (size_t i=0; i(this)-> - mZipSet.getZipResourceTable(ap.path); - if (ass == NULL) { - LOGV("loading resource table %s\n", ap.path.string()); - ass = const_cast(this)-> - openNonAssetInPathLocked("resources.arsc", - Asset::ACCESS_BUFFER, - ap); - if (ass != NULL && ass != kExcludedAsset) { - ass = const_cast(this)-> - mZipSet.setZipResourceTable(ap.path, ass); - } - } - } else { - LOGV("loading resource table %s\n", ap.path.string()); - Asset* ass = const_cast(this)-> - openNonAssetInPathLocked("resources.arsc", - Asset::ACCESS_BUFFER, - ap); - shared = false; - } - if (ass != NULL && ass != kExcludedAsset) { - if (rt == NULL) { - mResources = rt = new ResTable(); - updateResourceParamsLocked(); - } - LOGV("Installing resource asset %p in to table %p\n", ass, mResources); - rt->add(ass, (void*)(i+1), !shared); + mResources = rt = new ResTable(); - if (!shared) { - delete ass; - } + if (rt) { + const size_t N = mAssetPaths.size(); + for (size_t i=0; i(this)-> + mZipSet.getZipResourceTable(ap.path); + if (ass == NULL) { + LOGV("loading resource table %s\n", ap.path.string()); + ass = const_cast(this)-> + openNonAssetInPathLocked("resources.arsc", + Asset::ACCESS_BUFFER, + ap); + if (ass != NULL && ass != kExcludedAsset) { + ass = const_cast(this)-> + mZipSet.setZipResourceTable(ap.path, ass); + } + } + } else { + LOGV("loading resource table %s\n", ap.path.string()); + Asset* ass = const_cast(this)-> + openNonAssetInPathLocked("resources.arsc", + Asset::ACCESS_BUFFER, + ap); + shared = false; + } + if (ass != NULL && ass != kExcludedAsset) { + updateResourceParamsLocked(); + LOGV("Installing resource asset %p in to table %p\n", ass, mResources); + rt->add(ass, cookie, !shared); + + if (!shared) { + delete ass; + } + } +} + void AssetManager::updateResourceParamsLocked() const { ResTable* res = mResources; @@ -1635,22 +1642,58 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } -/* - * Mark asset path "stack" to support un-install from the mAssetPaths. - */ -int AssetManager::markAssetPathStack() +bool AssetManager::updateWithAssetPath(const String8& path, void** cookie) { - return (int)mAssetPaths.size(); + bool res = addAssetPath(path, cookie); + ResTable* rt = mResources; + if (res && rt != NULL && ((size_t)*cookie == mAssetPaths.size())) { + AutoMutex _l(mLock); + const asset_path& ap = mAssetPaths.itemAt((size_t)*cookie - 1); + updateResTableFromAssetPath(rt, ap, *cookie); + } + return res; } -/* - * Restore asset path "stack" by un-installing from the mAssetPaths - * all assets installed after restoreIndex. - */ -void AssetManager::restoreAssetPathStack(int restoreIndex) +bool AssetManager::removeAssetPath(const String8 &packageName, const String8 &assetPath) { - int i = (int)mAssetPaths.size(); - while (i > restoreIndex) { - mAssetPaths.removeAt(--i); + AutoMutex _l(mLock); + + String8 realPath(assetPath); + if (kAppZipName) { + realPath.appendPath(kAppZipName); + } + + // Check if the path exists. + size_t cookie = 0; + for (size_t i = 0; i < mAssetPaths.size(); i++) { + if (strcmp(mAssetPaths[i].path, realPath) == 0) { + mAssetPaths.removeAt(i); + cookie = i + 1; + break; + } + } + + if (cookie == 0) { + return false; + } + + ResTable* rt = mResources; + if (rt == NULL) { + LOGV("ResTable must not be NULL"); + return false; + } + + rt->removeAssetsByCookie(packageName, (void *)cookie); + + return true; +} + +void AssetManager::dumpRes() +{ + ResTable* rt = mResources; + if (rt == NULL) { + fprintf(stderr, "ResTable must not be NULL"); + return; } + rt->dump(); } -- cgit v1.1 From 83ad107ff4b2fde7ba39999f7f4f9023b098f9c7 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Thu, 18 Nov 2010 17:51:19 -0800 Subject: Updated copyright headers. Change-Id: I4824be066a98194b4f7fa9a18682bf6701e069a6 --- libs/utils/AssetManager.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 058c76c..4591f3e 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -1,5 +1,6 @@ /* * 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. -- cgit v1.1 From fce264d5ecb0ed901d874fe9e8215c4d0b7f507f Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Mon, 6 Dec 2010 16:29:38 -0800 Subject: Introduced an asset redirection system to the theme engine. Previously, the theme engine required careful redirection of only the highest-level "theme" style element, relying then on the theme attribute lookups to satisfy the demands of all themeable apps. This approach created significant challenges which required, in some cases, heavy modification for existing applications to support the engine. Custom widgets and themed components required special theme support in order to be reachable by the style engine alone. Similarly, a number of clumsy hacks were required around the framework to support certain components such as menus and tab widgets. The asset redirection system allows the theme to specify a redirection table which is consulted for nearly all final resource resolutions. This essentially means that once the theme is applied, any original resource being redirected would no longer be accessible by the AssetManager, instead being redirected to the matching resource in the theme itself. In order for this to function efficiently it is necessary to create cache files mapping resource integers from one package to another, even if those integers will change across releases. For this, one-time name to integer conversions occur, with the results written in a data format suitable for efficient reads for each AssetManager created. Currently this format must be parsed and cannot be directly mmaped though this will be addressed in future commits. Change-Id: Ie36e74314c600a72e03e568675a38801b7acd1ee --- libs/utils/AssetManager.cpp | 459 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 458 insertions(+), 1 deletion(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 4591f3e..eeebe05 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -33,11 +33,16 @@ #include #include #include +#include #include +#include +#include #include #include +#define REDIRECT_NOISY(x) //x + using namespace android; /* @@ -52,6 +57,8 @@ static const char* kSystemAssets = "framework/framework-res.apk"; static const char* kExcludeExtension = ".EXCLUDE"; +static const char* kThemeResCacheDir = "res-cache/"; + static Asset* const kExcludedAsset = (Asset*) 0xd000000d; static volatile int32_t gCount = 0; @@ -70,6 +77,7 @@ int32_t AssetManager::getGlobalCount() AssetManager::AssetManager(CacheMode cacheMode) : mLocale(NULL), mVendor(NULL), + mThemePackageName(NULL), mResources(NULL), mConfig(new ResTable_config), mCacheMode(cacheMode), mCacheValid(false) { @@ -89,6 +97,10 @@ 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) @@ -371,6 +383,429 @@ FileType AssetManager::getFileType(const char* fileName) return kFileTypeRegular; } +static void createDirIfNecessary(const char* path, mode_t mode, struct stat *statbuf) +{ + if (lstat(path, statbuf) != 0) { + if (mkdir(path, mode) != 0) { + LOGE("mkdir(%s,%04o) failed: %s\n", path, (int)mode, strerror(errno)); + } + } +} + +static SharedBuffer* addToEntriesByTypeBuffer(SharedBuffer* buf, uint32_t from, uint32_t to) +{ + size_t currentSize = (buf != NULL) ? buf->size() : 0; + + int type = Res_GETTYPE(from)+1; + int entry = Res_GETENTRY(from); + + size_t typeSize = (type+1) * sizeof(uint32_t*); + unsigned int requestSize = roundUpPower2(typeSize); + if (typeSize > currentSize) { + unsigned int requestSize = roundUpPower2(typeSize); + if (buf == NULL) { + buf = SharedBuffer::alloc(requestSize); + } else { + buf = buf->editResize(requestSize); + } + memset((unsigned char*)buf->data()+currentSize, 0, requestSize-currentSize); + } + + uint32_t** entriesByType = (uint32_t**)buf->data(); + uint32_t* entries = entriesByType[type]; + SharedBuffer* entriesBuf = (entries != NULL) ? SharedBuffer::bufferFromData(entries) : NULL; + currentSize = (entriesBuf != NULL) ? entriesBuf->size() : 0; + size_t entrySize = (entry+1) * sizeof(uint32_t); + if (entrySize > currentSize) { + unsigned int requestSize = roundUpPower2(entrySize); + if (entriesBuf == NULL) { + entriesBuf = SharedBuffer::alloc(requestSize); + } else { + entriesBuf = entriesBuf->editResize(requestSize); + } + memset((unsigned char*)entriesBuf->data()+currentSize, 0, requestSize-currentSize); + entriesByType[type] = (uint32_t*)entriesBuf->data(); + } + entries = (uint32_t*)entriesBuf->data(); + entries[entry] = to; + + 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; isize() / sizeof(uint32_t); + size_t numEntries = 0; + for (size_t j=0; jsize() / sizeof(uint32_t); + for (size_t j=0; j 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, const char* redirPath) +{ + REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s\n", themePackageName)); + + // HACK HACK HACK + if (strcmp(themePackageName, "com.tmobile.theme.Androidian") != 0) { + LOGW("EEP, UNEXPECTED PACKAGE!"); + return entriesByTypeBuf; + } + + rt->lock(); + + // Load up a bag for the user-supplied theme. + String16 type("style"); + String16 name("Androidian"); + String16 package(themePackageName); + uint32_t ident = rt->identifierForName(name.string(), name.size(), type.string(), type.size(), + package.string(), package.size()); + if (ident == 0) { + LOGW("unable to locate theme identifier %s:%s/%s\n", String8(package).string(), + String8(type).string(), String8(name).string()); + rt->unlock(); + return entriesByTypeBuf; + } + + const ResTable::bag_entry* themeEnt = NULL; + ssize_t N = rt->getBagLocked(ident, &themeEnt); + const ResTable::bag_entry* endThemeEnt = themeEnt + N; + + // ...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; + + // The first entry should be for the theme itself. + entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, ident); + + // 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", ident)); + 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, 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) { + // Special framework theme heuristic... + buf = generateFrameworkRedirections(buf, rt, themePackageName, 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(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, &statbuf); + basePath.appendPath(mThemePackageName); + createDirIfNecessary(basePath.string(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, &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; igetBasePackageId(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, + 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, + String16("android").string(), + frameworkRedirPath.string(), true); + } + + rt->addRedirections(0x01, frameworkRedirPath.string()); + } + + themeDirLock->unlock(); + } +} + const ResTable* AssetManager::getResTable(bool required) const { ResTable* rt = mResources; @@ -401,6 +836,7 @@ 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"); @@ -1768,14 +2204,34 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } +/* + * Set the currently applied theme package name. + * + * This information is used when constructing the ResTable's resource + * redirection map. + */ +void AssetManager::setThemePackageName(const char* packageName) +{ + if (mThemePackageName != NULL) { + delete[] mThemePackageName; + } + mThemePackageName = strdupNew(packageName); +} + +const char* AssetManager::getThemePackageName() +{ + return mThemePackageName; +} + bool AssetManager::updateWithAssetPath(const String8& path, void** cookie) { bool res = addAssetPath(path, cookie); ResTable* rt = mResources; - if (res && rt != NULL && ((size_t)*cookie == mAssetPaths.size())) { + if (res && rt != NULL && ((size_t)*cookie == mAssetPaths.size())) { AutoMutex _l(mLock); const asset_path& ap = mAssetPaths.itemAt((size_t)*cookie - 1); updateResTableFromAssetPath(rt, ap, *cookie); + loadRedirectionMappings(rt); } return res; } @@ -1809,6 +2265,7 @@ bool AssetManager::removeAssetPath(const String8 &packageName, const String8 &as return false; } + rt->clearRedirections(); rt->removeAssetsByCookie(packageName, (void *)cookie); return true; -- cgit v1.1 From 63b97570c9efea83b9c0ca1a2d763a8251c059e7 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Mon, 20 Dec 2010 14:46:14 -0800 Subject: Fixed a crash when the currently applied theme is replaced by the PackageManager. When a package is removed but still has active AssetManager's referring to it, a request to retrieve the resource path (the APK) will fail, so the assets cannot be removed. The AssetManager's removeAssetPath API was adjusted to now accept a cookie instead of searching for it by the supplied asset path. This allows us to still remove asset paths that are no longer available. Change-Id: I862c66e7515a1b05ca3e47f82e52cdf2f1d95684 --- libs/utils/AssetManager.cpp | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index eeebe05..0d2c8e0 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -2236,29 +2236,10 @@ bool AssetManager::updateWithAssetPath(const String8& path, void** cookie) return res; } -bool AssetManager::removeAssetPath(const String8 &packageName, const String8 &assetPath) +bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie) { AutoMutex _l(mLock); - String8 realPath(assetPath); - if (kAppZipName) { - realPath.appendPath(kAppZipName); - } - - // Check if the path exists. - size_t cookie = 0; - for (size_t i = 0; i < mAssetPaths.size(); i++) { - if (strcmp(mAssetPaths[i].path, realPath) == 0) { - mAssetPaths.removeAt(i); - cookie = i + 1; - break; - } - } - - if (cookie == 0) { - return false; - } - ResTable* rt = mResources; if (rt == NULL) { LOGV("ResTable must not be NULL"); -- cgit v1.1 From 3e2db8c6e979112da99fc75b384f8d143bf27205 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Wed, 22 Dec 2010 19:26:58 -0800 Subject: Create res-cache folders world-writable for now. This represents a security vulnerability that permits tampering. Should be closed by centralizing write access to this directory to a special system service. --- libs/utils/AssetManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 0d2c8e0..94f0fcd 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -752,9 +752,9 @@ void AssetManager::loadRedirectionMappings(ResTable* rt) const struct stat statbuf; String8 basePath(data); basePath.appendPath(kThemeResCacheDir); - createDirIfNecessary(basePath.string(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, &statbuf); + createDirIfNecessary(basePath.string(), 0777, &statbuf); basePath.appendPath(mThemePackageName); - createDirIfNecessary(basePath.string(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, &statbuf); + createDirIfNecessary(basePath.string(), 0777, &statbuf); String8 themeDirLockPath(basePath); themeDirLockPath.append(".lck"); -- cgit v1.1 From 38544aabce9f9ef56be960483c76bd8c9d9ab3f0 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Thu, 23 Dec 2010 01:04:24 -0800 Subject: Pass the high-level theme resource id into the redirection table layer. This is necessary to provide the high-level style redirection heuristics (previously this was hacked to assume the Androidian's theme style id). --- libs/utils/AssetManager.cpp | 48 +++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 30 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 94f0fcd..eb8e62e 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -515,33 +515,15 @@ static bool writeRedirections(const char* redirPath, SharedBuffer* entriesByType // for testing. This code should be generalized and follow a much better OO // structure. static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBuf, ResTable* rt, - const char* themePackageName, const char* redirPath) + const char* themePackageName, uint32_t styleId, const char* redirPath) { - REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s\n", themePackageName)); - - // HACK HACK HACK - if (strcmp(themePackageName, "com.tmobile.theme.Androidian") != 0) { - LOGW("EEP, UNEXPECTED PACKAGE!"); - return entriesByTypeBuf; - } + REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s, styleId=0x%08x\n", themePackageName, styleId)); rt->lock(); // Load up a bag for the user-supplied theme. - String16 type("style"); - String16 name("Androidian"); - String16 package(themePackageName); - uint32_t ident = rt->identifierForName(name.string(), name.size(), type.string(), type.size(), - package.string(), package.size()); - if (ident == 0) { - LOGW("unable to locate theme identifier %s:%s/%s\n", String8(package).string(), - String8(type).string(), String8(name).string()); - rt->unlock(); - return entriesByTypeBuf; - } - const ResTable::bag_entry* themeEnt = NULL; - ssize_t N = rt->getBagLocked(ident, &themeEnt); + ssize_t N = rt->getBagLocked(styleId, &themeEnt); const ResTable::bag_entry* endThemeEnt = themeEnt + N; // ...and a bag for the framework default. @@ -550,7 +532,7 @@ static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBu const ResTable::bag_entry* endFrameworkEnt = frameworkEnt + N; // The first entry should be for the theme itself. - entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, ident); + 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 @@ -560,7 +542,7 @@ static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBu // 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", ident)); + 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; @@ -723,8 +705,9 @@ SharedBuffer* AssetManager::generateRedirections(SharedBuffer* entriesByTypeBuf, } bool AssetManager::generateAndWriteRedirections(ResTable* rt, - const char* themePackageName, const char16_t* resPackageName, - const char* redirPath, bool isFramework) const + 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; @@ -732,7 +715,8 @@ bool AssetManager::generateAndWriteRedirections(ResTable* rt, SharedBuffer* buf = NULL; if (isFramework) { // Special framework theme heuristic... - buf = generateFrameworkRedirections(buf, rt, themePackageName, redirPath); + buf = generateFrameworkRedirections(buf, rt, themePackageName, + themeStyleId, redirPath); } // Generate redirections from the package XML. buf = am->generateRedirections(buf, rt, themePackageName, resPackageName); @@ -778,7 +762,8 @@ void AssetManager::loadRedirectionMappings(ResTable* rt) const if (lstat(redirPath.string(), &statbuf) != 0) { generateAndWriteRedirections(rt, mThemePackageName, - resPackageName, redirPath.string(), false); + mThemeStyleId, resPackageName, redirPath.string(), + false); } rt->addRedirections(packageId, redirPath.string()); @@ -795,7 +780,7 @@ void AssetManager::loadRedirectionMappings(ResTable* rt) const if (lstat(frameworkRedirPath.string(), &statbuf) != 0) { generateAndWriteRedirections(rt, mThemePackageName, - String16("android").string(), + mThemeStyleId, String16("android").string(), frameworkRedirPath.string(), true); } @@ -2205,17 +2190,20 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const } /* - * Set the currently applied theme package name. + * 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::setThemePackageName(const char* packageName) +void AssetManager::setThemePackageInfo(const char* packageName, uint32_t styleId) { if (mThemePackageName != NULL) { delete[] mThemePackageName; } mThemePackageName = strdupNew(packageName); + mThemeStyleId = styleId; } const char* AssetManager::getThemePackageName() -- cgit v1.1 From 9bdba12edb195fae27ff2915bd618b0fe119bf76 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Mon, 27 Dec 2010 22:18:42 -0800 Subject: Fix issues with theme APKs that do not specify a styleId. --- libs/utils/AssetManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index e0d83b4..28dc6c0 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -530,12 +530,12 @@ static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBu // 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; + 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; + const ResTable::bag_entry* endFrameworkEnt = frameworkEnt + (N >= 0 ? N : 0); // The first entry should be for the theme itself. entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, styleId); @@ -719,7 +719,7 @@ bool AssetManager::generateAndWriteRedirections(ResTable* rt, AssetManager* am = (AssetManager*)this; SharedBuffer* buf = NULL; - if (isFramework) { + if (isFramework && themeStyleId != 0) { // Special framework theme heuristic... buf = generateFrameworkRedirections(buf, rt, themePackageName, themeStyleId, redirPath); -- cgit v1.1 From b58e5ae98ba80cdf7be6ec4e3df1b43d21d771cc Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Thu, 20 Jan 2011 13:31:49 -0800 Subject: Asset redirections are now managed by a system service. Adjusted the asset redirection design to use a common system service (AssetRedirectionManagerService) for synchronization and cache management. This replaces the old /data/res-cache design completely (nothing is written to disk now). This change also moves a large amount of code from the C++ layer to Java for parsing the theme meta data and redirection XML files, though the actual redirection still occurs at the native layer. Change-Id: I8820e39425135269f5e723534c4b9c8dc6841779 --- libs/utils/AssetManager.cpp | 406 ++------------------------------------------ 1 file changed, 14 insertions(+), 392 deletions(-) (limited to 'libs/utils/AssetManager.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 #include #include -#include #include #include @@ -41,8 +40,6 @@ #include #include -#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; isize() / sizeof(uint32_t); - size_t numEntries = 0; - for (size_t j=0; jsize() / sizeof(uint32_t); - for (size_t j=0; j 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; igetBasePackageId(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(); +} -- cgit v1.1 From 7d8b1bbb118cdb71c16c97dbc73390d9351c238c Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Thu, 20 Jan 2011 17:33:16 -0800 Subject: Fixed a regression causing theme switch to fail. This would only occur when switching from one theme APK to another, which apparently was not tested on the experimental branch (??). The bug would not repro if switching between system default and a theme APK. Change-Id: I9fc0b5c50c1dff4a0b2d548980977faaa0a51167 --- libs/utils/AssetManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 4513a06..b34c147 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -1843,6 +1843,13 @@ bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie) { AutoMutex _l(mLock); + const size_t which = ((size_t)cookie)-1; + if (which >= mAssetPaths.size()) { + return false; + } + + mAssetPaths.removeAt(which); + ResTable* rt = mResources; if (rt == NULL) { LOGV("ResTable must not be NULL"); -- cgit v1.1 From b6c3e53c9982ccab438a2a64bf1b0b4e9b42fdc1 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Fri, 4 Feb 2011 11:22:05 -0800 Subject: Corrected whitespace trespasses. Many small whitespace mistakes slipped into the framework as the themes feature was developed. This patch reverts them to make a cleaner patch set against android-2.3.1_r1. Change-Id: I52223c1d572d4f013e37bebc5c11bb7b1c595eb3 --- libs/utils/AssetManager.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index b34c147..8380b67 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -127,7 +127,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie) return true; } } - + LOGV("In %p Asset %s path: %s", this, ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); @@ -190,7 +190,7 @@ void AssetManager::setLocaleLocked(const char* locale) delete[] mLocale; } mLocale = strdupNew(locale); - + updateResourceParamsLocked(); } @@ -685,7 +685,7 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m /* look at the filesystem on disk */ String8 path(createPathNameLocked(ap, locale, vendor)); path.appendPath(fileName); - + String8 excludeName(path); excludeName.append(kExcludeExtension); if (::getFileType(excludeName.string()) != kFileTypeNonexistent) { @@ -693,28 +693,28 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m //printf("+++ excluding '%s'\n", (const char*) excludeName); return kExcludedAsset; } - + pAsset = openAssetFromFileLocked(path, mode); - + if (pAsset == NULL) { /* try again, this time with ".gz" */ path.append(".gz"); pAsset = openAssetFromFileLocked(path, mode); } - + if (pAsset != NULL) pAsset->setAssetSource(path); } else { /* find in cache */ String8 path(createPathNameLocked(ap, locale, vendor)); path.appendPath(fileName); - + AssetDir::FileInfo tmpInfo; bool found = false; - + String8 excludeName(path); excludeName.append(kExcludeExtension); - + if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) { /* go no farther */ //printf("+++ Excluding '%s'\n", (const char*) excludeName); @@ -1533,7 +1533,7 @@ bool AssetManager::fncScanAndMergeDirLocked( // XXX This is broken -- the filename cache needs to hold the base // asset path separately from its filename. - + partialPath = createPathNameLocked(ap, locale, vendor); if (dirName[0] != '\0') { partialPath.appendPath(dirName); -- cgit v1.1 From 7e5b830d1dfba5e2c1f9f2ea29c37773b49b710b Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Fri, 4 Feb 2011 13:02:19 -0800 Subject: Removed dead theme engine code. Change-Id: Ib9581787b7f2a305633c17cebe4404b02c01bee5 --- libs/utils/AssetManager.cpp | 53 --------------------------------------------- 1 file changed, 53 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 8380b67..ec0bb66 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -35,8 +35,6 @@ #include #include -#include -#include #include #include @@ -54,8 +52,6 @@ static const char* kSystemAssets = "framework/framework-res.apk"; static const char* kExcludeExtension = ".EXCLUDE"; -static const char* kThemeResCacheDir = "res-cache/"; - static Asset* const kExcludedAsset = (Asset*) 0xd000000d; static volatile int32_t gCount = 0; @@ -381,55 +377,6 @@ FileType AssetManager::getFileType(const char* fileName) return kFileTypeRegular; } -static void createDirIfNecessary(const char* path, mode_t mode, struct stat *statbuf) -{ - if (lstat(path, statbuf) != 0) { - if (mkdir(path, mode) != 0) { - LOGE("mkdir(%s,%04o) failed: %s\n", path, (int)mode, strerror(errno)); - } - } -} - -static SharedBuffer* addToEntriesByTypeBuffer(SharedBuffer* buf, uint32_t from, uint32_t to) -{ - size_t currentSize = (buf != NULL) ? buf->size() : 0; - - int type = Res_GETTYPE(from)+1; - int entry = Res_GETENTRY(from); - - size_t typeSize = (type+1) * sizeof(uint32_t*); - unsigned int requestSize = roundUpPower2(typeSize); - if (typeSize > currentSize) { - unsigned int requestSize = roundUpPower2(typeSize); - if (buf == NULL) { - buf = SharedBuffer::alloc(requestSize); - } else { - buf = buf->editResize(requestSize); - } - memset((unsigned char*)buf->data()+currentSize, 0, requestSize-currentSize); - } - - uint32_t** entriesByType = (uint32_t**)buf->data(); - uint32_t* entries = entriesByType[type]; - SharedBuffer* entriesBuf = (entries != NULL) ? SharedBuffer::bufferFromData(entries) : NULL; - currentSize = (entriesBuf != NULL) ? entriesBuf->size() : 0; - size_t entrySize = (entry+1) * sizeof(uint32_t); - if (entrySize > currentSize) { - unsigned int requestSize = roundUpPower2(entrySize); - if (entriesBuf == NULL) { - entriesBuf = SharedBuffer::alloc(requestSize); - } else { - entriesBuf = entriesBuf->editResize(requestSize); - } - memset((unsigned char*)entriesBuf->data()+currentSize, 0, requestSize-currentSize); - entriesByType[type] = (uint32_t*)entriesBuf->data(); - } - entries = (uint32_t*)entriesBuf->data(); - entries[entry] = to; - - return buf; -} - const ResTable* AssetManager::getResTable(bool required) const { ResTable* rt = mResources; -- cgit v1.1 From 50e8a31923c0fef5c6672cf69e4f2d9a296bb556 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Fri, 4 Feb 2011 13:18:30 -0800 Subject: Removed AssetManager#dumpResources. This method was used only for debugging and has not been useful for quite a long time. Change-Id: I38f3c60bb6a7400758623ac80faf2350e387d51e --- libs/utils/AssetManager.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index ec0bb66..9dc3f11 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -1808,16 +1808,6 @@ bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie) return true; } -void AssetManager::dumpRes() -{ - ResTable* rt = mResources; - if (rt == NULL) { - fprintf(stderr, "ResTable must not be NULL"); - return; - } - rt->dump(); -} - void AssetManager::addRedirections(PackageRedirectionMap* resMap) { getResources(); -- cgit v1.1 From 41348643dcec2ae0ee672ec25496fd5b0065dc20 Mon Sep 17 00:00:00 2001 From: Josh Guilfoyle Date: Mon, 7 Mar 2011 14:20:22 -0800 Subject: Fixed cyanogenmod issue 2861: asset redirection breaks access to AndroidManifest.xml. Themed asset managers lose the ability to access application assets without a cookie because the search order favors most recently added asset paths (theme apks are added last). So, searching for AndroidManifest.xml would always return the themes manifest, not the application manifest. The solution is to mark the themed asset path and ignore it when searching for cookie-less assets. This should not cause problems with theme application because the theme uses resource identifier based redirections which always retain the asset path cookie that is to be used to load the final resource. --- libs/utils/AssetManager.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'libs/utils/AssetManager.cpp') diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 9dc3f11..19a4873 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -91,7 +91,7 @@ AssetManager::~AssetManager(void) delete[] mVendor; } -bool AssetManager::addAssetPath(const String8& path, void** cookie) +bool AssetManager::addAssetPath(const String8& path, void** cookie, bool asSkin) { AutoMutex _l(mLock); @@ -101,6 +101,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie) if (kAppZipName) { realPath.appendPath(kAppZipName); } + ap.asSkin = asSkin; ap.type = ::getFileType(realPath.string()); if (ap.type == kFileTypeRegular) { ap.path = realPath; @@ -283,9 +284,13 @@ Asset* AssetManager::open(const char* fileName, AccessMode mode) size_t i = mAssetPaths.size(); while (i > 0) { i--; + const asset_path& ap = mAssetPaths.itemAt(i); + if (ap.asSkin) { + continue; + } LOGV("Looking for asset '%s' in '%s'\n", - assetName.string(), mAssetPaths.itemAt(i).path.string()); - Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i)); + assetName.string(), ap.path.string()); + Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, ap); if (pAsset != NULL) { return pAsset != kExcludedAsset ? pAsset : NULL; } @@ -317,9 +322,13 @@ Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode) size_t i = mAssetPaths.size(); while (i > 0) { i--; - LOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string()); + const asset_path& ap = mAssetPaths.itemAt(i); + if (ap.asSkin) { + continue; + } + LOGV("Looking for non-asset '%s' in '%s'\n", fileName, ap.path.string()); Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(i)); + fileName, mode, ap); if (pAsset != NULL) { return pAsset != kExcludedAsset ? pAsset : NULL; } @@ -919,6 +928,9 @@ AssetDir* AssetManager::openDir(const char* dirName) while (i > 0) { i--; const asset_path& ap = mAssetPaths.itemAt(i); + if (ap.asSkin) { + continue; + } if (ap.type == kFileTypeRegular) { LOGV("Adding directory %s from zip %s", dirName, ap.path.string()); scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName); @@ -1774,9 +1786,9 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } -bool AssetManager::updateWithAssetPath(const String8& path, void** cookie) +bool AssetManager::attachThemePath(const String8& path, void** cookie) { - bool res = addAssetPath(path, cookie); + bool res = addAssetPath(path, cookie, true); ResTable* rt = mResources; if (res && rt != NULL && ((size_t)*cookie == mAssetPaths.size())) { AutoMutex _l(mLock); @@ -1786,7 +1798,7 @@ bool AssetManager::updateWithAssetPath(const String8& path, void** cookie) return res; } -bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie) +bool AssetManager::detachThemePath(const String8 &packageName, void* cookie) { AutoMutex _l(mLock); @@ -1795,6 +1807,7 @@ bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie) return false; } + /* TODO: Ensure that this cookie is added with asSkin == true. */ mAssetPaths.removeAt(which); ResTable* rt = mResources; -- cgit v1.1