学习自
https://www.jianshu.com/p/5eac94143bd6
本文可不看 没啥意义
AssetManager.mObject是native层的AssetManager
/**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
* appropriate asset manager with {@link Resources#getAssets}. Not for
* use by applications.
* {@hide}
*/
public AssetManager() {
synchronized (this) {
if (DEBUG_REFS) {
mNumRefs = 0;
incRefsLocked(this.hashCode());
}
init(false);
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
ensureSystemAssets();
}
}
// ndk的源码路径
// frameworks/base/core/jni/android_util_AssetManager.cpp
// frameworks/base/libs/androidfw/AssetManager.cpp
private native final void init(boolean isSystem);
对应的native的方法为
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
{
if (isSystem) {
verifySystemIdmaps();
}
// AssetManager.cpp
AssetManager* am = new AssetManager();
if (am == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", "");
return;
}
am->addDefaultAssets();
ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
}
bool AssetManager::addDefaultAssets()
{
const char* root = getenv("ANDROID_ROOT");
LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
String8 path(root);
// framework/framework-res.apk
// 初始化的时候会去加载系统的framework-res.apk资源
// 也就是说我们为什么能加载系统的资源如颜色、图片、文字等等
path.appendPath(kSystemAssets);
return addAssetPath(path, NULL);
}
addAssetPath
bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)//path就是我们zip的路径
{
asset_path ap;
// 省略一些校验代码
// judge cache
for (size_t i=0; i<mAssetPaths.size(); i++) {
if (mAssetPaths[i].path == ap.path) {
if (cookie) {
*cookie = static_cast<int32_t>(i+1);
}
return true;
}
}
// 检查路径是否有一个androidmanifest . xml
Asset* manifestAsset = const_cast<AssetManager*>(this)->openNonAssetInPathLocked(
kAndroidManifest, Asset::ACCESS_BUFFER, ap);
if (manifestAsset == NULL) {
// 如果不包含任何资源
delete manifestAsset;
return false;
}
delete manifestAsset;
// 添加
mAssetPaths.add(ap);
// 新路径总是补充到最后
if (cookie) {
*cookie = static_cast<int32_t>(mAssetPaths.size());
}
if (mResources != NULL) {
appendPathToResTable(ap);
}
return true;
}
bool AssetManager::appendPathToResTable(const asset_path& ap) const {
// skip those ap's that correspond to system overlays
if (ap.isSystemOverlay) {
return true;
}
Asset* ass = NULL;
ResTable* sharedRes = NULL;
bool shared = true;
bool onlyEmptyResources = true;
MY_TRACE_BEGIN(ap.path.string());
// 资源覆盖机制,暂不考虑
Asset* idmap = openIdmapLocked(ap);
size_t nextEntryIdx = mResources->getTableCount();
ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
// 资源包路径不是一个文件夹,那就是一个apk文件了
if (ap.type != kFileTypeDirectory) {
// 对于app来说,第一次执行时,肯定为0,因为mResources刚创建,还没对其操作
// 下面的分支 指挥在参数是系统资源包路径时,才执行,
// 而且系统资源包路径是首次被解析的
// 第二次执行appendPathToResTable,nextEntryIdx就不会为0了
if (nextEntryIdx == 0) {
// mAssetPaths中存储的第一个资源包路径是系统资源的路径,
// 即framework-res.apk的路径,它在zygote启动时已经加载了
// 可以通过mZipSet.getZipResourceTable获得其ResTable对象
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTable(ap.path);
// 对于APP来说,肯定不为NULL
if (sharedRes != NULL) {
// 得到系统资源包路径中resources.arsc个数
nextEntryIdx = sharedRes->getTableCount();
}
}
// 当参数是mAssetPaths中除第一个以外的其他资源资源包路径,
// 比如app自己的资源包路径时,走下面的逻辑
if (sharedRes == NULL) {
// 检查该资源包是否被其他进程加载了,这与ZipSet数据结构有关,后面在详细介绍
ass = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTableAsset(ap.path);
// 对于app自己的资源包来说,一般都会都下面的逻辑
if (ass == NULL) {
ALOGV("loading resource table %s\n", ap.path.string());
// 创建Asset对象,就是打开resources.arsc
ass = const_cast<AssetManager*>(this)->
openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER,
ap);
if (ass != NULL && ass != kExcludedAsset) {
ass = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTableAsset(ap.path, ass);
}
}
// 只有在zygote启动时,才会执行下面的逻辑
// 为系统资源创建 ResTable,并加入到mZipSet里。
if (nextEntryIdx == 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.
ALOGV("Creating shared resources for %s", ap.path.string());
// 创建ResTable对象,并把前面与resources.arsc关联的Asset对象,加入到这个ResTabl中
sharedRes = new ResTable();
sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
}
} else {
ALOGV("loading resource table %s\n", ap.path.string());
ass = const_cast<AssetManager*>(this)->
openNonAssetInPathLocked("resources.arsc",
Asset::ACCESS_BUFFER,
ap);
shared = false;
}
if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
// 系统资源包时
if (sharedRes != NULL) {
ALOGV("Copying existing resources for %s", ap.path.string());
mResources->add(sharedRes);
} else {
// 非系统资源包时,将与resources.arsc关联的Asset对象加入到Restable中
// 此过程会解析resources.arsc文件。
ALOGV("Parsing resources for %s", ap.path.string());
mResources->add(ass, idmap, nextEntryIdx + 1, !shared);
}
onlyEmptyResources = false;
if (!shared) {
delete ass;
}
} else {
mResources->addEmpty(nextEntryIdx + 1);
}
if (idmap != NULL) {
delete idmap;
}
MY_TRACE_END();
return onlyEmptyResources;
}
resources.arsc这玩意是资源索引,我们找到资源,都是靠他