Android 插件化】Hook 插件化框架 ( 从源码角度分析加载资源流程 | Hook 点选择 | 资源冲突解决方案 )(二)

简介: Android 插件化】Hook 插件化框架 ( 从源码角度分析加载资源流程 | Hook 点选择 | 资源冲突解决方案 )(二)

4、ContextImpl


在 ActivityThread 中调用了


     

ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);


方法 , 创建了 ContextImpl ;


下面分析 ContextImpl 的 createActivityContext 方法 ;


class ContextImpl extends Context {
    static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        String[] splitDirs = packageInfo.getSplitResDirs();
        ClassLoader classLoader = packageInfo.getClassLoader();
        if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
            try {
                classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
                splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
            } catch (NameNotFoundException e) {
                // Nothing above us can handle a NameNotFoundException, better crash.
                throw new RuntimeException(e);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
            }
        }
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);
        // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
        displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
        final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
                ? packageInfo.getCompatibilityInfo()
                : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
        final ResourcesManager resourcesManager = ResourcesManager.getInstance();
        // Create the base resources for which all configuration contexts for this Activity
        // will be rebased upon.
        context.setResources(resourcesManager.createBaseActivityResources(activityToken,
                packageInfo.getResDir(),
                splitDirs,
                packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles,
                displayId,
                overrideConfiguration,
                compatInfo,
                classLoader));
        context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                context.getResources());
        return context;
    }
}


源码路径 : /frameworks/base/core/java/android/app/ContextImpl.java


在上述方法中 , 就有创建 Resources 资源的方法 :


       context.setResources(resourcesManager.createBaseActivityResources(activityToken,

               packageInfo.getResDir(),

               splitDirs,

               packageInfo.getOverlayDirs(),

               packageInfo.getApplicationInfo().sharedLibraryFiles,

               displayId,

               overrideConfiguration,

               compatInfo,

               classLoader));

1

2

3

4

5

6

7

8

9





二、Hook 点选择


修改应用 Resources 的 Hook 点有很多 , 通过改变 Activity 的 Resources , 甚至修改 ActivityThread 中创建 Resources 的流程 都可以实现 ;


在插件包中 , 使用了 AppCompatActivity , 可以直接替换 AppCompatActivity 中的 private Resources mResources 成员 ;


public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
    private static final String DELEGATE_TAG = "androidx:appcompat";
    private AppCompatDelegate mDelegate;
    private Resources mResources;
}


只要可以拿到 AppCompatActivity 实例 , 就可以通过反射 , 替换掉 private Resources mResources 成员 ;



在 Instrumentation 中 , 调用了 newActivity 创建 Activity 实例 ;


 

public Activity newActivity(Class<?> clazz, Context context, 
            IBinder token, Application application, Intent intent, ActivityInfo info, 
            CharSequence title, Activity parent, String id,
            Object lastNonConfigurationInstance) throws InstantiationException, 
            IllegalAccessException {
        Activity activity = (Activity)clazz.newInstance();
        ActivityThread aThread = null;
        // Activity.attach expects a non-null Application Object.
        if (application == null) {
            application = new Application();
        }
        activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
                info, title, parent, id,
                (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
                new Configuration(), null /* referrer */, null /* voiceInteractor */,
                null /* window */, null /* activityConfigCallback */);
        return activity;
    }


源码路径 : /frameworks/base/core/java/android/app/Instrumentation.java


在 ActivityThread 中 , 有 Instrumentation mInstrumentation 成员变量 , ActivityThread 本身就是单例 , 通过获取其静态成员 private static volatile ActivityThread sCurrentActivityThread , 就可以获取到 ActivityThread ;


 

/** Reference to singleton {@link ActivityThread} */
    private static volatile ActivityThread sCurrentActivityThread;
    Instrumentation mInstrumentation;




三、资源冲突解决方案


资源的 ID 在 AAPT 编译资源阶段就确定了 ;


固定类型的资源 , 编号是从一定的编号段开始的 , 如 layout 布局资源 , 第一个布局资源总是 2131361820 ;


不同类型的资源 , 布局 , 字符串 , 数值 , 主题 , 图片 , drawable 等 , 都有对应的资源编号范围 , 同时也要兼容系统的资源编号范围 ;


如果宿主应用启动 , 加载第一个布局资源 , 那么编号是 2131361820 ;

如果插件应用启动 , 加载第一个布局资源 , 那么编号也是 2131361820 ;

这样就出现了资源冲突 ;


使用不同的 AssetManager 加载不同的资源 , 可以解决资源冲突问题 ;





目录
相关文章
|
15天前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
1月前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
77 7
|
2月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台解决方案
【9月更文挑战第27天】在移动应用开发的广阔天地中,安卓和iOS两大操作系统如同双子星座般耀眼。开发者们在这两大平台上追逐着创新的梦想,却也面临着选择的难题。如何在保持高效的同时,实现跨平台的开发?本文将带你探索跨平台开发的魅力所在,揭示其背后的技术原理,并通过实际案例展示其应用场景。无论你是安卓的忠实拥趸,还是iOS的狂热粉丝,这篇文章都将为你打开一扇通往跨平台开发新世界的大门。
|
1月前
|
Android开发
Android开发显示头部Bar的需求解决方案--Android应用实战
Android开发显示头部Bar的需求解决方案--Android应用实战
21 0
|
3月前
|
前端开发 开发工具 Android开发
探索安卓与iOS应用开发:跨平台解决方案的崛起
【8月更文挑战第27天】在移动设备日益普及的今天,安卓和iOS系统占据了市场的主导地位。开发者们面临着一个重要问题:是选择专注于单一平台,还是寻找一种能够同时覆盖两大系统的解决方案?本文将探讨跨平台开发工具的优势,分析它们如何改变了移动应用的开发格局,并分享一些实用的开发技巧。无论你是新手还是资深开发者,这篇文章都将为你提供有价值的见解和建议。
|
3月前
|
Android开发
Android编译出现Warning: Mapping new ns to old ns的解决方案
Android编译出现Warning: Mapping new ns to old ns的解决方案
329 3
|
3月前
|
前端开发 JavaScript Android开发
探索Android和iOS开发中的跨平台解决方案
【8月更文挑战第1天】随着移动应用市场的不断扩张,开发者面临一个共同的挑战——如何高效地为多个平台创建和维护应用程序。本文将深入探讨跨平台开发工具,特别是Flutter和React Native,通过比较它们的优势和限制,并辅以实际代码示例,揭示这些工具如何帮助开发者在保持高性能的同时,实现代码的最大化重用。
|
3月前
|
前端开发 JavaScript Android开发
安卓与iOS开发中的跨平台解决方案
【8月更文挑战第24天】在移动应用开发领域,安卓和iOS两大平台占据了主导地位。然而,为这两个平台分别开发和维护应用会带来额外的时间和成本。本文将探讨跨平台开发的概念、优势以及流行的跨平台框架,如React Native和Flutter,并分析它们如何解决多平台开发的挑战。
|
3月前
|
监控 Java 开发工具
### 绝招揭秘!Android平台GB28181设备接入端如何实现资源占用和性能消耗的极限瘦身?
【8月更文挑战第14天】本文介绍在Android平台优化GB28181标准下设备接入的性能方法,涵盖环境搭建、SDK集成与初始化。重点讲解内存管理技巧如软引用、按需加载资源,以及通过硬件加速解码视频数据和图像缩放来减轻CPU与GPU负担。同时采用线程池异步处理视频流,确保UI流畅性。这些策略有助于提高应用效率和用户体验。
46 0
|
Java Android开发 容器