学习笔记:插件化Activity

简介: 学习笔记:插件化Activity

四大组件之Activity:

名词解释

AMS:AMS Binder对象

AMN:app中获取AMS代理的对象

ATP:ApplicationThreadProxy用于AMS和APP通信,AT的代理对象

APT:ApplicationThread APP中的Binder对象。APT中会利用mh这个Handler发送消息做对应处理

AT:APT会调用AT得方法,AT中给mh发消息

mh:App的Handler,用于接受处理AMS等系统服务发送的消息处理

原始流程

startActivity交互过程如下:

App:

ContextTheme—>ContextWrapper—>Context—>ContextImpl:

ContextImpl内部调用Instrumention.startActivity()传入启动Activity的类名(用于校验是否注册过没有注册抛异常)等信息,该方法其中通过AMN获取AMS代理对象和AMS进行通信。

AMS远端:

获取要启动的activity类名,观察是否在清单文件中注册过(PMS在安装时会解析对应APK清单文件存储到本地)。接着给启动activity的进程发送一个pause的消息通过ATP

然后判断该进程是否启动过(没有启动需要先和zygote用socket通信先创建一个进程Process.start)

1.没有启动过(没有启动需要先和zygote用socket通信先创建一个进程Process.start,接着创建ActivityThread,利用AMN把ATP传给AMS(这样AMS就可以和APP通信了)

接着AMS在给ATP发消息 AT收到给mh发送消进行反射创建Application调用onCreate,在接着就是下面2中所说的进程已经启动情况的步骤了)

2.启动过(AMS会封装Activity变成一个ActivityClientRecord,该对象会携带cl后面mh会根据这个cl去反射创建Activity。)

APP中:

ATP中收到AMS发过来的消息取出ActivityClientRecord,调用AT吧这个参数传进去。

AT中调用mh的handlerPerformLaunchActivity。mh其实是一个handler,handleCallBack中来决定调用哪个方法对应于本示例startActivity为下面的逻辑

回调中取出acRecord,利用acRecord的classloader对象来反射创建对应activity,并调用onCreate方法

通知最开始pause的那个activity恢复运行~(利用ATP也是)

至此交互结束

Hook点

我们可以Hook哪些点呢?提炼出精华我们在哪里可以把狸猫换成太子~

第一个点:

Instrumention利用AMN获取到AMS代理,将信息传给AMS校验

(我们在Instrumention中拦截这个代理,替换为我们自定义的对象。检测到startActivity时将Activity换成我们宿主中已经注册了的StubActivity)

好了,现在AMS校验过了,他要通知APP创建Activity对象了。但是这个时候是StubService的Activity。我们需要把他换掉我们真实启动的Activity。

第二个点:

我们怎么知道真实启动的Activity是谁呢?在第一步中其实整个流程传递的都是Intent,包括我们接受到ANS消息时也是Intent。

既然是同一个Intent对象。我们在这个Intent中动手脚(APP调用AMS把真实启动的Activity保存到Intent中,在AMS通知APP创建的时候在取出来)

好,第一个是在Instrumention中换成我们的代理接下来就会和AMS交互(这里是最后一步下一步就要和AMS通信因此选在这里进行Hook)

那么通知ATP,AT,mh中都可以进行还原取出Intent中真实启动的activity。

我们在mh中最后一步反射创建的地方进行修改(和上面一样,在最接近现场的地方进行Hook)。将mh替换为我们的mh。这样我们收到handlerPerformLaunchActivity的消息时,就可以做我们自己的操作了

不同的ClassLoader会加载不同的类,classloader中如果没有这个class是加载不了的。所以我们要用正确的cl去加载对象。这个cl其实就是插件的cl,也就是dexcl。我们在和AMS交互的时候可以传入对应的cl,之后创建再取出正确的cl。

注意点:

由于Activity默认是Standard模式,所以宿主中的一个Activity可以对应插件中的多个标准模式的Activity。每次启动都会创建一个实例。

但是Android中是有LaunchMode的,不同的启动模式对应的效果也不同。那么如何支持LaunchMode呢

LaunchMode的支持:

其实就是Activity栈的变化。我们自己手动保存一份当前启动的Activity信息集合,根据启动Activity的launchmode去操作这个集合并对集合中的Activity实例做处理【这个也是Android原生的处理方式】

(要保存两个集合一个是已经启动的集合commentName为key,真实的Activity实例为value(这个模拟的就是Activity栈);一个是当前APK中所有的Activity集合(是否可以通过类名找到对应的Activity信息)name对应ActivityComment)

注:第二个集合需要在Application的attachBaseContext中去完善这个集合。越早越好

流程:

1.先遍历第二个集合中看插件中是否有对应Activity的信息。很好理解如果你启动一个压根就不存在的Activity之后反射也会崩溃~~

这之后的代码逻辑就是mh中Hook那个handlerPerformLaunchActivity的消息时的处理,针对创建Activity实例和调用Activity方法进行额外的逻辑处理

2.首先看下已经启动的集合中Activity的数量,launchmode是针对多Activity才有用,如果栈中只有一个Activity那么launchmode将没用

3.再接着取出这个activity的launchmode是不是非Standard的,默认模式不需要处理,直接把他加到我们的第一个已经启动activity的集合中即可。原生也是这样

3.1

SingleTop:

首先看下原生的这个启动模式是什么样的情况:

如果栈顶是这个Activity那么将不会创建实例也不会调用onCreate,而是会调用他的onNewIntent方法。否则就是按Standard处理

我们怎么处理呢~~

注意:本质上我们还是standard的:

原先:S1–>T1 之后就是S1–>T1(有状态的)—>T1了,

Question:我们可以把之前Top的T1干掉吗也就是中间的那个T1,就是S1—>T1了~

A:不行,这样启动的T1状态会丢失。真实的情况应该仅仅是调用T1(有状态的)的onNewInstance

怎么做呢:不添加这个后来的activity,直接取出栈顶的activity实例调用OnNewInstance即可~~

对应逻辑:

先看下栈顶是不是这个activity。

~如果不是就直接加入到集合中就行,也就是默认Standard模式

~如果是的话,则忽略这个要启动的Activity,把栈顶的Activity取出来调用onNewInstance即可

3.2

SingleTask:

首先看下原生的这个启动模式是什么样的情况:

如果在栈中已经有该Activity实例了,那么清除掉在它上面的所有Activity,并调用这个Activity的onNewInstance方法

根据前面那个mode的处理,应该也能猜出怎么做了

在集合中找出这个Activity实例和他对应的下标。进行对这个范围(下标–集合最大数量)的activity实例进行挨个销毁。

接着在调用这个activity的onNewInstance方法

3.3:SingleInstance:

一样的操作。



目录
相关文章
|
XML Java 程序员
插件化框架设计(二) Android 资源加载机制详解(一)
Android 提供了一种非常灵活的资源系统,可以根据不同的条件提供可替代资源。因此,系统基于很少的改造就能支持新特性,比如 Android N 中的分屏模式。这也是 Android 强大部分之一。本文主要讲述 Android 资源系统的实现原理,以及在应用开发中需要注意的事项。
211 0
|
缓存 JSON ARouter
Android开源系列-组件化框架Arouter-(一)使用方式详解
最近组里需要进行**组件化框架**的改造,用到了`Arouter`这个开源框架,为了更好的对项目进行改造,笔者花了一些时间去了解了下`Arouter
|
存储 Android开发
插件化框架设计(二) Android 资源加载机制详解(二)
Android 提供了一种非常灵活的资源系统,可以根据不同的条件提供可替代资源。因此,系统基于很少的改造就能支持新特性,比如 Android N 中的分屏模式。这也是 Android 强大部分之一。本文主要讲述 Android 资源系统的实现原理,以及在应用开发中需要注意的事项。
295 0
插件化框架设计(二) Android 资源加载机制详解(二)
|
API Android开发
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )(一)
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )(一)
171 0
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )(一)
|
存储 Java Android开发
【Android 插件化】插件化原理 ( 类加载器 )
【Android 插件化】插件化原理 ( 类加载器 )
171 0
【Android 插件化】插件化原理 ( 类加载器 )
|
算法 Java Android开发
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )(一)
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )(一)
115 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )(二)
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )(二)
175 0
|
算法 Java Android开发
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )
198 0
|
Java Android开发 开发者
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )(一)
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )(一)
586 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )(二)
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )(二)
326 0