android_frameworks_base/tools/aapt/ResourceIdCache.cpp
Adam Lesinski de898ff429 Shared library resource support
Shared libraries can now export resources for applications
to use.

Exporting resources works the same way the framework exports
resources, by defining the public symbols in res/values/public.xml.

Building a shared library requires aapt to be invoked with the
--shared-lib option. Shared libraries will be assigned a package
ID of 0x00 at build-time. At runtime, all loaded shared libraries
will be assigned a new package ID.

Currently, shared libraries should not import other shared libraries,
as those dependencies will not be loaded at runtime.

At runtime, reflection is used to update the package ID of resource
symbols in the shared library's R class file. The package name of
the R class file is assumed to be the same as the shared library's
package name declared in its manifest. This will be customizable in
a future commit.

See /tests/SharedLibrary/ for examples of a shared library and its
client.

Bug:12724178
Change-Id: I60c0cb8ab87849f8f8a1a13431562fe8603020a7
2014-03-25 12:09:56 -07:00

108 lines
2.9 KiB
C++

//
// Copyright 2012 The Android Open Source Project
//
// Manage a resource ID cache.
#define LOG_TAG "ResourceIdCache"
#include <utils/String16.h>
#include <utils/Log.h>
#include "ResourceIdCache.h"
#include <map>
using namespace std;
static size_t mHits = 0;
static size_t mMisses = 0;
static size_t mCollisions = 0;
static const size_t MAX_CACHE_ENTRIES = 2048;
static const android::String16 TRUE16("1");
static const android::String16 FALSE16("0");
struct CacheEntry {
// concatenation of the relevant strings into a single instance
android::String16 hashedName;
uint32_t id;
CacheEntry() {}
CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
};
static map< uint32_t, CacheEntry > mIdMap;
// djb2; reasonable choice for strings when collisions aren't particularly important
static inline uint32_t hashround(uint32_t hash, int c) {
return ((hash << 5) + hash) + c; /* hash * 33 + c */
}
static uint32_t hash(const android::String16& hashableString) {
uint32_t hash = 5381;
const char16_t* str = hashableString.string();
while (int c = *str++) hash = hashround(hash, c);
return hash;
}
namespace android {
static inline String16 makeHashableName(const android::String16& package,
const android::String16& type,
const android::String16& name,
bool onlyPublic) {
String16 hashable = String16(name);
hashable += type;
hashable += package;
hashable += (onlyPublic ? TRUE16 : FALSE16);
return hashable;
}
uint32_t ResourceIdCache::lookup(const android::String16& package,
const android::String16& type,
const android::String16& name,
bool onlyPublic) {
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
const uint32_t hashcode = hash(hashedName);
map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
if (item == mIdMap.end()) {
// cache miss
mMisses++;
return 0;
}
// legit match?
if (hashedName == (*item).second.hashedName) {
mHits++;
return (*item).second.id;
}
// collision
mCollisions++;
mIdMap.erase(hashcode);
return 0;
}
// returns the resource ID being stored, for callsite convenience
uint32_t ResourceIdCache::store(const android::String16& package,
const android::String16& type,
const android::String16& name,
bool onlyPublic,
uint32_t resId) {
if (mIdMap.size() < MAX_CACHE_ENTRIES) {
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
const uint32_t hashcode = hash(hashedName);
mIdMap[hashcode] = CacheEntry(hashedName, resId);
}
return resId;
}
void ResourceIdCache::dump() {
printf("ResourceIdCache dump:\n");
printf("Size: %zd\n", mIdMap.size());
printf("Hits: %zd\n", mHits);
printf("Misses: %zd\n", mMisses);
printf("(Collisions: %zd)\n", mCollisions);
}
}