Don't re-parse the framework resources all the time.

A small optimization to the resource code, to not re-parse the framework
resources every time we build a new AssetManager.  Instead, you can now
construct a ResTable from a previously created one...  of course, like the
existing code for using the data in-place, you can't delete the original
ResTable until you have deleted the one that has been constructed from it.
This commit is contained in:
Dianne Hackborn 2009-07-06 11:07:40 -07:00 committed by Alex Ray
parent cfd03822f0
commit bd875d2638
5 changed files with 168 additions and 42 deletions

View File

@ -251,6 +251,9 @@ private:
Asset* getResourceTableAsset();
Asset* setResourceTableAsset(Asset* asset);
ResTable* getResourceTable();
ResTable* setResourceTable(ResTable* res);
bool isUpToDate();
protected:
@ -265,6 +268,7 @@ private:
time_t mModWhen;
Asset* mResourceTableAsset;
ResTable* mResourceTable;
static Mutex gLock;
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
@ -288,8 +292,11 @@ private:
*/
ZipFileRO* getZip(const String8& path);
Asset* getZipResourceTable(const String8& path);
Asset* setZipResourceTable(const String8& path, Asset* asset);
Asset* getZipResourceTableAsset(const String8& path);
Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
ResTable* getZipResourceTable(const String8& path);
ResTable* setZipResourceTable(const String8& path, ResTable* res);
// generate path, e.g. "common/en-US-noogle.zip"
static String8 getPathName(const char* path);

View File

@ -1580,6 +1580,7 @@ public:
bool copyData=false);
status_t add(Asset* asset, void* cookie,
bool copyData=false);
status_t add(ResTable* src);
status_t getError() const;

View File

@ -582,11 +582,14 @@ const void* _FileAsset::ensureAlignment(FileMap* map)
if ((((size_t)data)&0x3) == 0) {
// We can return this directly if it is aligned on a word
// boundary.
LOGV("Returning aligned FileAsset %p (%s).", this,
getAssetSource());
return data;
}
// If not aligned on a word boundary, then we need to copy it into
// our own buffer.
LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength);
LOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
getAssetSource(), (int)mLength);
unsigned char* buf = new unsigned char[mLength];
if (buf == NULL) {
LOGE("alloc of %ld bytes failed\n", (long) mLength);

View File

@ -395,21 +395,41 @@ const ResTable* AssetManager::getResTable(bool required) const
const size_t N = mAssetPaths.size();
for (size_t i=0; i<N; i++) {
Asset* ass = NULL;
ResTable* sharedRes = NULL;
bool shared = true;
const asset_path& ap = mAssetPaths.itemAt(i);
LOGV("Looking for resource asset in '%s'\n", ap.path.string());
if (ap.type != kFileTypeDirectory) {
ass = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTable(ap.path);
if (ass == NULL) {
LOGV("loading resource table %s\n", ap.path.string());
if (i == 0) {
// The first item is typically the framework resources,
// which we want to avoid parsing every time.
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTable(ap.path);
}
if (sharedRes == NULL) {
ass = const_cast<AssetManager*>(this)->
openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER,
ap);
if (ass != NULL && ass != kExcludedAsset) {
mZipSet.getZipResourceTableAsset(ap.path);
if (ass == NULL) {
LOGV("loading resource table %s\n", ap.path.string());
ass = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, ass);
openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER,
ap);
if (ass != NULL && ass != kExcludedAsset) {
ass = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTableAsset(ap.path, ass);
}
}
if (i == 0 && ass != NULL) {
// If this is the first resource table in the asset
// manager, then we are going to cache it so that we
// can quickly copy it out for others.
LOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
sharedRes->add(ass, (void*)(i+1), false);
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
}
} else {
@ -420,13 +440,19 @@ const ResTable* AssetManager::getResTable(bool required) const
ap);
shared = false;
}
if (ass != NULL && ass != kExcludedAsset) {
if ((ass != NULL || sharedRes != 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);
if (sharedRes != NULL) {
LOGV("Copying existing resources for %s", ap.path.string());
rt->add(sharedRes);
} else {
LOGV("Parsing resources for %s", ap.path.string());
rt->add(ass, (void*)(i+1), !shared);
}
if (!shared) {
delete ass;
@ -1510,7 +1536,8 @@ Mutex AssetManager::SharedZip::gLock;
DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
: mPath(path), mZipFile(NULL), mModWhen(modWhen), mResourceTableAsset(NULL)
: mPath(path), mZipFile(NULL), mModWhen(modWhen),
mResourceTableAsset(NULL), mResourceTable(NULL)
{
//LOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
mZipFile = new ZipFileRO;
@ -1563,6 +1590,25 @@ Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
return mResourceTableAsset;
}
ResTable* AssetManager::SharedZip::getResourceTable()
{
LOGV("Getting from SharedZip %p resource table %p\n", this, mResourceTable);
return mResourceTable;
}
ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res)
{
{
AutoMutex _l(gLock);
if (mResourceTable == NULL) {
mResourceTable = res;
return res;
}
}
delete res;
return mResourceTable;
}
bool AssetManager::SharedZip::isUpToDate()
{
time_t modWhen = getFileModDate(mPath.string());
@ -1572,6 +1618,9 @@ bool AssetManager::SharedZip::isUpToDate()
AssetManager::SharedZip::~SharedZip()
{
//LOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
if (mResourceTable != NULL) {
delete mResourceTable;
}
if (mResourceTableAsset != NULL) {
delete mResourceTableAsset;
}
@ -1627,7 +1676,7 @@ ZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
return zip->getZip();
}
Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path)
Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
{
int idx = getIndex(path);
sp<SharedZip> zip = mZipFile[idx];
@ -1638,7 +1687,7 @@ Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path)
return zip->getResourceTableAsset();
}
Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path,
Asset* AssetManager::ZipSet::setZipResourceTableAsset(const String8& path,
Asset* asset)
{
int idx = getIndex(path);
@ -1647,6 +1696,26 @@ Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path,
return zip->setResourceTableAsset(asset);
}
ResTable* AssetManager::ZipSet::getZipResourceTable(const String8& path)
{
int idx = getIndex(path);
sp<SharedZip> zip = mZipFile[idx];
if (zip == NULL) {
zip = SharedZip::get(path);
mZipFile.editItemAt(idx) = zip;
}
return zip->getResourceTable();
}
ResTable* AssetManager::ZipSet::setZipResourceTable(const String8& path,
ResTable* res)
{
int idx = getIndex(path);
sp<SharedZip> zip = mZipFile[idx];
// doesn't make sense to call before previously accessing.
return zip->setResourceTable(res);
}
/*
* Generate the partial pathname for the specified archive. The caller
* gets to prepend the asset root directory.

View File

@ -1136,8 +1136,9 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
struct ResTable::Header
{
Header() : ownedData(NULL), header(NULL) { }
Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
ResTable* const owner;
void* ownedData;
const ResTable_header* header;
size_t size;
@ -1163,8 +1164,8 @@ struct ResTable::Type
struct ResTable::Package
{
Package(const Header* _header, const ResTable_package* _package)
: header(_header), package(_package) { }
Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
: owner(_owner), header(_header), package(_package) { }
~Package()
{
size_t i = types.size();
@ -1174,10 +1175,14 @@ struct ResTable::Package
}
}
ResTable* const owner;
const Header* const header;
const ResTable_package* const package;
Vector<Type*> types;
ResStringPool typeStrings;
ResStringPool keyStrings;
const Type* getType(size_t idx) const {
return idx < types.size() ? types[idx] : NULL;
}
@ -1188,13 +1193,16 @@ struct ResTable::Package
// table that defined the package); the ones after are skins on top of it.
struct ResTable::PackageGroup
{
PackageGroup(const String16& _name, uint32_t _id)
: name(_name), id(_id), typeCount(0), bags(NULL) { }
PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
: owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
~PackageGroup() {
clearBagCache();
const size_t N = packages.size();
for (size_t i=0; i<N; i++) {
delete packages[i];
Package* pkg = packages[i];
if (pkg->owner == owner) {
delete pkg;
}
}
}
@ -1225,15 +1233,17 @@ struct ResTable::PackageGroup
}
}
ResTable* const owner;
String16 const name;
uint32_t const id;
Vector<Package*> packages;
// This is for finding typeStrings and other common package stuff.
Package* basePackage;
// Taken from the root package.
ResStringPool typeStrings;
ResStringPool keyStrings;
// For quick access.
size_t typeCount;
// Computed attribute bags, first indexed by the type and second
// by the entry in that type.
bag_set*** bags;
@ -1560,11 +1570,36 @@ status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
return add(data, size, cookie, asset, copyData);
}
status_t ResTable::add(ResTable* src)
{
mError = src->mError;
mParams = src->mParams;
for (size_t i=0; i<src->mHeaders.size(); i++) {
mHeaders.add(src->mHeaders[i]);
}
for (size_t i=0; i<src->mPackageGroups.size(); i++) {
PackageGroup* srcPg = src->mPackageGroups[i];
PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
for (size_t j=0; j<srcPg->packages.size(); j++) {
pg->packages.add(srcPg->packages[j]);
}
pg->basePackage = srcPg->basePackage;
pg->typeCount = srcPg->typeCount;
mPackageGroups.add(pg);
}
memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
return mError;
}
status_t ResTable::add(const void* data, size_t size, void* cookie,
Asset* asset, bool copyData)
{
if (!data) return NO_ERROR;
Header* header = new Header;
Header* header = new Header(this);
header->index = mHeaders.size();
header->cookie = cookie;
mHeaders.add(header);
@ -1682,10 +1717,12 @@ void ResTable::uninit()
N = mHeaders.size();
for (size_t i=0; i<N; i++) {
Header* header = mHeaders[i];
if (header->ownedData) {
free(header->ownedData);
if (header->owner == this) {
if (header->ownedData) {
free(header->ownedData);
}
delete header;
}
delete header;
}
mPackageGroups.clear();
@ -1728,8 +1765,8 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
outName->package = grp->name.string();
outName->packageLen = grp->name.size();
outName->type = grp->typeStrings.stringAt(t, &outName->typeLen);
outName->name = grp->keyStrings.stringAt(
outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
outName->name = grp->basePackage->keyStrings.stringAt(
dtohl(entry->key.index), &outName->nameLen);
return true;
}
@ -2331,13 +2368,13 @@ nope:
continue;
}
const ssize_t ti = group->typeStrings.indexOfString(type, typeLen);
const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
if (ti < 0) {
TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
continue;
}
const ssize_t ei = group->keyStrings.indexOfString(name, nameLen);
const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
if (ei < 0) {
TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
continue;
@ -3630,25 +3667,36 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
PackageGroup* group = NULL;
uint32_t id = dtohl(pkg->id);
if (id != 0 && id < 256) {
package = new Package(this, header, pkg);
if (package == NULL) {
return (mError=NO_MEMORY);
}
size_t idx = mPackageMap[id];
if (idx == 0) {
idx = mPackageGroups.size()+1;
char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
group = new PackageGroup(String16(tmpName), id);
group = new PackageGroup(this, String16(tmpName), id);
if (group == NULL) {
delete package;
return (mError=NO_MEMORY);
}
err = group->typeStrings.setTo(base+dtohl(pkg->typeStrings),
err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
header->dataEnd-(base+dtohl(pkg->typeStrings)));
if (err != NO_ERROR) {
delete group;
delete package;
return (mError=err);
}
err = group->keyStrings.setTo(base+dtohl(pkg->keyStrings),
err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
header->dataEnd-(base+dtohl(pkg->keyStrings)));
if (err != NO_ERROR) {
delete group;
delete package;
return (mError=err);
}
@ -3657,6 +3705,8 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
if (err < NO_ERROR) {
return (mError=err);
}
group->basePackage = package;
mPackageMap[id] = (uint8_t)idx;
} else {
group = mPackageGroups.itemAt(idx-1);
@ -3664,10 +3714,6 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return (mError=UNKNOWN_ERROR);
}
}
package = new Package(header, pkg);
if (package == NULL) {
return (mError=NO_MEMORY);
}
err = group->packages.add(package);
if (err < NO_ERROR) {
return (mError=err);