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/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.