From 64a827fc06d0c3a1ef326e5704758f5b5a2cd694 Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Wed, 29 Jul 2020 11:22:49 +0800 Subject: [PATCH] Update --- blogs/Android/口水话/插件化、热修复相关口水话.md | 10 ++++++++-- blogs/computer_network/口水话/HTTP、HTTPS、HTTP2.md | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/blogs/Android/口水话/插件化、热修复相关口水话.md b/blogs/Android/口水话/插件化、热修复相关口水话.md index 544d7fe..099b28a 100644 --- a/blogs/Android/口水话/插件化、热修复相关口水话.md +++ b/blogs/Android/口水话/插件化、热修复相关口水话.md @@ -9,10 +9,16 @@ #### 热修复 +热修复,我所了解的一种实现方式就是类加载方案,即 dex 插桩,这种思路在插件化中也会用到。除此之外,还有底层替换方案,即修改 替换 ArtMethod。采用类加载方案的主要是以腾讯系为主,包括微信的 Tinker、饿了么的 Amigo;采用底层替换方案主要是阿里系的 AndFix 等。 + #### 插件化 -插件化有两种实现方式,静态代理式和 Hook 式。 +插件化无非就是解决类加载和资源加载的问题,资源加载一般都是通过反射 AssetManager。所以按照类加载的划分来说,插件化有两种实现方式,静态代理式和 Hook 式。 静态代理式的实现方式很简单,不需要熟悉 Activity 的启动流程啥的,直接采用面向接口的编程方式即可。首先需要宿主 App 加载 plugin.apk 构造 DexClassLoader 和 Resource 对象,有了 DexClassLoader 就可以加载插件里面的类了,Resource 是通过反射 AssetManager 的 addAssetPath 创建一个 AssetManager,再构造 Resource 对象,有了 Resource 对象就可以访问到资源文件了。但是这时插件是没有 Context 的环境的,这个上下文需要宿主提供给它。具体做法是通过 PackageManager 获取插件的入口的 Activity 进行注入宿主的 Context,这就完成了宿主 App 跳插件 App 的步骤。但是插件 App 是没有上下文环境的,所以在插件 App 里面 Activity 直接的跳转是不能直接 startActivity 的,需要拿宿主的 Context 执行 startActivity,同理,其他一些需要获取 Context 执行的操作都要通过宿主的 Context 去执行,比如弹 Toast、解析 layout 文件等等。任玉刚的 dynamic-load-apk 就是采用这种方式,也被称为 that 框架,这个 that 就指向宿主的 Context。 -静态代理式实现简单,也无需考虑版本兼容性,但是每次编写插件类时都要小心要使用宿主的 Context,所以很不方便。Hook 式是把插件里面的 dex 文件直接复制到宿主的 dexElements 里面,这样就有了宿主的上下文环境了。但是现在问题就转变成了如何启动未在 Manifest 中注册的 Activity,所以就需要 Hook AMS 来绕过检查。但是需要注意的是版本兼容性,不同的 Android 版本 Hook 点不同,需要做兼容。在 Android 8 以下版本就是 Hook ActivityManagerNative 拿到 IActivityManager 接口,然后做动态代理,其他版本也是类似思想。在 Android 8-10,是 Hook ActivityManager,Android 10 以上就是 Hook ActivityTaskManager。 \ No newline at end of file +静态代理式实现简单,也无需考虑版本兼容性,但是每次编写插件类时都要小心要使用宿主的 Context,所以很不方便。Hook 式是把插件里面的 dex 文件直接复制到宿主的 dexElements 里面,这样就有了宿主的上下文环境了。但是现在问题就转变成了如何启动未在 Manifest 中注册的 Activity,所以就需要一个占位的 Activity 并且 Hook AMS 来绕过检查。但是需要注意的是版本兼容性,不同的 Android 版本 Hook 点不同,需要做兼容。在 Android 8 以下版本就是 Hook ActivityManagerNative 拿到 IActivityManager 接口,然后做动态代理,其他版本也是类似思想。在 Android 8-10,是 Hook ActivityManager,Android 10 以上就是 Hook ActivityTaskManager。 + +在简单的说这两种方式,静态代理式是自己构造一个 DexClassLoader,所以没有上下文环境,上下文环境需要宿主提供给它。一个 DexClassLoader 就包含一个插件。而 Hook 式是把插件的里面的 dex 文件合并到宿主的 DexClassLoader 里面,但是得绕过 AMS 的未在 Manifest 中注册的 Activity 会抛出的 ClassNotFoundException,所以就需要 Hook startActivity 和 handleLauncherActivity。前者实现简单,兼容性好,而且每个插件是分离,后者兼容性差但是开发方便,但是如果多个插件里面有相同的类,就会 GG 了。 + +显然,每个插件独立的 DexClassLoader 具有先天优势,这其实就引入了另一个 Hook 式的实现方式,即构建 LoadedApk 式。但是这种实现方式困难,而且兼容性巨差,基本上每新出个版本就得兼容 PackageParse 类,这个类其实我们在做静态代理式也用到了,解析静态广播转变为动态广播。 \ No newline at end of file diff --git a/blogs/computer_network/口水话/HTTP、HTTPS、HTTP2.md b/blogs/computer_network/口水话/HTTP、HTTPS、HTTP2.md index 9eb6823..066c26b 100644 --- a/blogs/computer_network/口水话/HTTP、HTTPS、HTTP2.md +++ b/blogs/computer_network/口水话/HTTP、HTTPS、HTTP2.md @@ -42,3 +42,9 @@ RSA 也能作为密钥交换算法,但是因为其性能低下,需要大量 TLS1.3 在 2018 年正式发布,它移除了很多已证明不安全的套件,在第一次握手时客户端把所有的密码套件及其公钥都发给了服务端,也就不再需要 Server Key Exchange 和 Client Key Exchange,从 2 RTT 到 1 RTT。同时,TLS1.3 支持基于会话回复的 0RTT 握手。 +#### HTTP2 + +HTTP2 有三个核心概念,Strem 流、Message 消息、Frame 帧。在一个 TCP 连接上可以有多个流,也就是并发多请求,实现多路复用;以前浏览器是只能对一个域名开启 6 个并发链接;同时流还可以设置优先级,让服务器优先处理;一条流上可以有多个 Message 消息,每个 Message 都可以携带多个 Frame 帧,帧类型包括 HEADER 帧和 DATA 帧,也就对应于 HTTP/1.1 中的 header 和 data。在 HTTP/1.1 中,服务端是没法主动向客户端推送信息的,客户端只能以轮询的方式去请求,在 HTTP2 中有了服务器推送,也就是服务端可以提前将资源推送至浏览器缓存。 + +HTTP2 只在应用层解决了队头阻塞问题,并未在 TCP 层解决队头阻塞问题。TCP 的报文传输时无序,接收时组装。如果队头包没有到达,即使后序数据包已经接受到了也是没办法交给上层应用程序处理的,只能等待重发。而在 HTTP3 采用了 UDP,UDP 先天没有队列的概念,自然就解决了队头阻塞的问题,但是它仍然保留了 TCP 的可靠性,这也需要 QUIC 协议自己去实现重传机制、拥塞控制等机制。 +