从ActivityThread 分析Resources和AssetsManager资源创建和初始化过程

前面我写过一篇名为 Android资源管理器过程分析 & 插件化实现Hook 资源管理器的实现,在片文章中主要讲解了一些基础知识,其中包括:资源的分类、资源的打包过程、自定义资源的ID范围及使用场景、插件化框架Android-Framework-Plugin是如何实现Hook AssetsManager的等,主要讲解的是使用过程;而我们今天这一篇是对资源初始化过程的源码分析.

知识铺垫

Activity在进程加载过程中都会创建一个对应的ContextImpl,并通过调用ContextImpl对象的成员函数init()来初始化Activity组件运行上下文环境的工作,其中就包括创建Resources类和AssetsManager类用来访问对程序资源。

详细步骤

1.调用performLaunchActivity()创建Activity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    ...
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    ...
    Context appContext = createBaseContextForActivity(r, activity, r.displayId);
    ...
}
  • 在performLaunchActivity中首先通过反射创建Activity对象
  • 调用LoadedApk对象的makeApplication(),获取Activity所属应用的Application对象
  • 为Activity创建Base Context也就是ContextImpl对象,AssetManager对象就是在这里创建的。

2.分析createBaseContextForActivity()的实现

private Context createBaseContextForActivity(ActivityClientRecord r,
        final Activity activity, int activityDisplayId) {
    ...
    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, displayId, r.overrideConfig/* { Multi-Window */, r.token/* Multi-Window } */);
    appContext.setOuterContext(activity);
    ...
}

3.接下来分析ResourcesManager的getTopLevelResources()

private final ArrayMap > mActiveResources =
        new ArrayMap<>();
...        
/**
 * Creates the top level Resources for applications with the given compatibility info.
 *
 * @param resDir the resource directory.
 * @param splitResDirs split resource directories.
 * @param overlayDirs the resource overlay directories.
 * @param libDirs the shared library resource dirs this app references.
 * @param displayId display Id.
 * @param overrideConfiguration override configurations.
 * @param compatInfo the compatibility info. Must not be null.
 */
Resources getTopLevelResources(String resDir, String[] splitResDirs,
        String[] overlayDirs, String[] libDirs, int displayId,
        Configuration overrideConfiguration, CompatibilityInfo compatInfo) {
    ...
    ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
    Resources r;
    synchronized (this) {
        // Resources is app scale dependent.
        if (DEBUG) Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
        WeakReference wr = mActiveResources.get(key);
        r = wr != null ? wr.get() : null;
        //if (r != null) Log.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
        if (r != null && r.getAssets().isUpToDate()) {
        if (DEBUG) Slog.w(TAG, "Returning cached resources " + r + " " + resDir
                + ": appScale=" + r.getCompatibilityInfo().applicationScale
                + " key=" + key + " overrideConfig=" + overrideConfiguration);
             return r;
         }
     }
     ...
     AssetManager assets = new AssetManager();
     if (resDir != null) {
         if (assets.addAssetPath(resDir) == 0) {
             return null;
         }
     }
     ...
     r = new Resources(assets, dm, config, compatInfo);
     ...
     synchronized (this) {
        WeakReference wr = mActiveResources.get(key);
        Resources existing = wr != null ? wr.get() : null;
        if (existing != null && existing.getAssets().isUpToDate()) {
            r.getAssets().close();
            return existing;
        }
        mActiveResources.put(key, new WeakReference<>(r));
        return r;
     }
}

4.重点分析AssetManager以及Resources的构造函数

  • 4.1 AssetManager的构造函数

public AssetManager() {
    synchronized (this) {
        ...
        init(false);
        ensureSystemAssets();
    }
}
  • 4.1.1 调用native方法init()来创建并初始化Native层的AssetManager对象。
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
{
 ...
AssetManager* am = new AssetManager();
...
am->addDefaultAssets();
env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast(am));
}
4.1.1.1 在android_content_AssetManager_init()中首先创建Native层AssetManager对象
4.1.1.2 调用AssetManager对象的addDefaultAssets添加系统资源
bool AssetManager::addDefaultAssets()
{
   const char* root = getenv("ANDROID_ROOT");
   String8 path(root);
   path.appendPath(kSystemAssets);
   return addAssetPath(path, NULL);
}
bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
{
...
asset_path ap;
...
for (size_t i=0; i(i+1);
 }
 return true;
  }
}
...
mAssetPaths.add(ap);
// new paths are always added at the end
if (cookie) {
*cookie = static_cast(mAssetPaths.size());
}
...
if (mResources != NULL) {
appendPathToResTable(ap);
}
 return true;
}
  • 在addDefaultAssets()中首先创建系统资源路径,一般ANDROID_ROOT环境变量为"/system"
  • kSystemAssets为"framework/framework-res.apk",所以系统资源路径为"/system/framework/framework-res.apk"。然后调用addAssetPath()。
  • 在addAssetPath()中,首先检查mAssetPaths中是否已经包含了当前资源路径对应的asset_path对象,如果已经存在,返回asset_path在
  • mAssetPaths中的索引值+1,所以*cookie的值从1开始。
  • 否则,将asset_path添加到mAssetPaths中,同时给*cookie赋值。
  • 如果资源表不为NULL,将asset_path添加到资源表。
  • 4.1.1.3 最后将Native层的AssetManager对象地址保存在相应的Java对象的mObject中
  • 4.1.2调用ensureSystemAssets()来确保系统资源管理对象已经创建并初始化。

4.2 Resources的构造函数

public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
        CompatibilityInfo compatInfo) {
    mAssets = assets;
    ...
    updateConfiguration(config, metrics);
    assets.ensureStringBlocks();
}
  • 在Reosurces的构造函数中,首先将之前创建的AssetManager对象保存到mAssets中。
  • 调用updateConfiguration()更新设备配置信息,如设备屏幕信息、国家地区网络信息以及键盘配置信息等,最终会将这些信息
  • 保存到Native层的AssetManager对象中去。
  • 调用ensureStringBlocks将系统资源表以及应用资源表中的字符串资源池地址保存到AssetManager的mStringBlocks中。

This ALL! Thanks EveryBody!

你可能感兴趣的:(从ActivityThread 分析Resources和AssetsManager资源创建和初始化过程)