前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学习笔记:插件化Activity

学习笔记:插件化Activity

作者头像
北洋
发布2022-05-06 15:30:08
1840
发布2022-05-06 15:30:08
举报
文章被收录于专栏:北洋csdn

四大组件之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:

一样的操作。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 名词解释
  • 原始流程
    • startActivity交互过程如下:
      • APP中:
      • Hook点
        • 第一个点:
          • 第二个点:
            • 注意点:
            • LaunchMode的支持:
              • 3.1
                • 3.2
                  • 3.3:SingleInstance:
                  相关产品与服务
                  文件存储
                  文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档