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:
parent
cfd03822f0
commit
bd875d2638
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue