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.
diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp
index 91203dd..23cb72d 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/utils/Asset.cpp
@@ -582,11 +582,14 @@
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);
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 4126bfb..5a05e6a 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -395,21 +395,41 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 4a5063a..109f28d 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1136,8 +1136,9 @@
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::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 @@
}
}
+ 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 @@
// 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 @@
}
}
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);