文章目录

    • 系列前言
    • 一. Binder机制
      • 为什么需求Binder
      • Binder模型
      • Binder与插件化
      • 总结
    • 二. ClassLoader
      • 双亲托付模型
      • 总结
    • 参考资料

系列前言

Hello,夸姣的一周又开端啦,让咱们开端愉快的学习吧。

从今天开端,我会花较多的时刻来跟咱们一起学习Android插件化。这一篇文章是Android插件化的发动篇。

Android插件化是之前几年里的一个很火的技能概念。从2012年开端就有人在研讨这门技能。从粗糙的AndroidDynamicLoader框架,到第一代的DroidPlugin等,继而发展到第二代的VirtualApk,Replugin等,再到现如今的VirtualApp,Atlas。插件化在国内逐渐的发展和完善,却也在近几年呈现了RN等替代品以后慢慢会走向弱势。

尽管插件化技能的研讨热潮现已曩昔,可是这门技能本身仍是有着很多的技能实践,关于咱们了解Android机制很有协助。所以从这篇文章开端我会写一系列的文章,加上自己对插件化的实践,最后会去从源码视点分析几个优秀的插件化库,构成一套完好的插件化的理论体系。

下面是插件化的技能框架,也是我这个系列文章的行文思路

【Android插件化系列一】开篇前言:Binder机制,ClassLoader

一. Binder机制

网上分析Binder机制的文章现已很多了,在这篇文章里,我不会去解说Binder的运用,而是会去解说清楚Binder的规划思路,规划原理和关于插件化的运用。

为什么需求Binder

首要咱们知道,Android是基于Linux内核开发的。关于Linux来说,操作体系为一个二进制可履行文件创建了一个载有该文件自己的栈,堆、数据映射以及同享库的内存片段,还为其分配特其他内部管理结构。这便是一个进程。操作体系有必要供给公正的运用机制,使得每个进程能正常的开端,履行和终结。

这样呢,就引入了一个问题。一个进程能不能去操作其他进程的数据呢?咱们能够想一下,这是肯定不能呈现的,尤其是体系级的进程,假如被其他进程影响了可能会形成整个体系的坍塌。所以咱们很自然的想到,咱们应该把进程隔离起来,linux也是这样做的,它的虚拟内存机制为每个进程分配连续的内存空间,进程只能操作自己的虚拟内存空间。一起,还有必要满意进程之间保持通讯的才能,究竟团结力量大,单凭单个进程的独立运作是不能撑起操作体系的功用需求的。

为了解决这个问题,Linux引进了用户空间User Space和内核空间Kernel Space的区别。用户空间要想访问内核空间,唯一办法便是体系调用。内核空间经过接口把应用程序请求传给内核处理后回来给应用程序。一起,用户空间进程假如想升级为内核空间进程,需求进行安全检查。

补充知识:体系调用首要经过两个办法:
copy_from_user():将用户空间的数据拷贝到内核空间
copy_to_user():将内核空间的数据拷贝到用户空间

【Android插件化系列一】开篇前言:Binder机制,ClassLoader

以上便是linux体系的跨进程通讯机制。而咱们立刻要说的Binder,便是跨进程的一种办法

Binder模型

Binder是一种进程间通讯(IPC)办法,Android常见的进程中通讯办法有文件同享,Bundle,AIDL,Messenger,ContentProvider,Socket。其间AIDL,Messenger,ContentProvider都是基于Binder。Linux体系经过Binder驱动来管理Binder机制。

Binder的完成基于mmap()体系调用,只用拷贝一次,比常规文件页操作更快。微信开源的MMKV等也是基于此。有爱好的能够了解一下。

首要Binder机制有四个参加者,Server,Client两个进程,ServiceManager,Binder驱动(内核空间)。其间ServiceManager和Binder驱动都是体系完成的,而Server和Client是需求开发者自己完成的。四者之中只要Binder驱动是运转在内核空间的。

【Android插件化系列一】开篇前言:Binder机制,ClassLoader

这儿的ServiceManager作为Manager,承当着Binder通讯的树立,Binder的注册和传递的才能。Service担任创建Binder,并为他起一个字符形式的名字,然后把Binder和名字经过**经过Binder驱动,借助于ServiceManager自带的Binder向ServiceManager注册。**注意这儿,因为Service和ServiceManager也是跨进程通讯需求Binder,ServerManager是自带Binder的,所以相对ServiceManager来说Service也就相当于Client了。

Service注册了这个Binder以后,Client就能经过名字取得Binder的引证了。这儿的跨进程通讯两边就变成了Client和ServiceManager,然后ServiceManager从Binder表取出Binder的引证返给Client,这样的话假如有多个Client的话,屡次回来引证就行了,可是事实上引证的都是放在ServiceManager中的Service。

当Client经过Binder驱动跟Service通讯的时候,往往需求获取到Service的某个方针object。这时候为了安全考虑,Binder会把object的署理方针proxyobject回来,这个方针具有一模一样的办法,可是没有具体才能,只担任接纳参数传给真正的object运用。

所以完好的Binder通讯进程是

【Android插件化系列一】开篇前言:Binder机制,ClassLoader

OK,跨进程通讯就讲清楚了。接下来咱们讲讲插件化中的Binder。

Binder与插件化

首要,咱们先回忆一下Activity的发动进程,Instrumentation调用了ActivityManagerNative,这个AMN是咱们的本地方针,然后AMN调用getDefault拿到了ActivityManagerProxy,这个人AMP便是AMS在本地的署理。相当于binder模型中的Client,而这个AMP承继的是IActivityManager,具有四大组件的所有需求AMS参加的办法。本地经过调用这个AMP办法来间接地调用AMS。这样,咱们就调用到了AMS发动了Activity。

那么,AMS怎么与Client进行通讯呢?现在咱们经过Launcher发动了Activity,肯定要告诉Launcher “没你什么事了,你洗洗睡吧”。咱们能够看到,这儿两边的人物就发生了改变,AMS需求去发消息,承当Client的人物,而Launcher这时候作为Service供给服务。而这次通讯相同也是运用的Binder机制。AMS这边保存了一个ApplicationThreadProxy方针,这个方针便是Launcher的ApplicationThread的署理。AMS经过ATP给App发消息,App经过ApplicationThread处理。

【Android插件化系列一】开篇前言:Binder机制,ClassLoader

以上,便是Binder机制在Android中的运用,咱们后边会经过hook这个进程完成插件化。

总结

看了这么多,可能仍是很多朋友不明白Binder。我也是这样,很长一段时刻都不知道Binder到底指的是啥。后来我看到了这样一种界说:

  • 从进程间通讯的视点看,Binder 是一种进程间通讯的机制;
  • 从 Server 进程的视点看,Binder 指的是 Server 中的 Binder 实体方针;
  • 从 Client 进程的视点看,Binder 指的是对 Binder 署理方针,是 Binder 实体方针的一个长途署理
  • 从传输进程的视点看,Binder 是一个能够跨进程传输的方针;Binder 驱动会对这个跨过进程鸿沟的方针对一点点特别处理,自动完成署理方针和本地方针之间的转化。

二. ClassLoader

双亲托付模型

Java中默许有三种ClassLoader。分别是:

  • BootStrap ClassLoader:发动类加载器,最顶层的加载器。首要担任加载JDK中的核心类。在JVM发动后也随着发动,并结构Ext ClassLoader和App ClassLoader。
  • Extension ClassLoader:扩展类加载器,担任加载Java的扩展类库。
  • App ClassLoader:体系类加载器,担任加载应用程序的所有jar和class文件。
  • 自界说ClassLoader:需求承继自ClassLoader类。

ClassLoader默许运用双亲托付模型来搜索类。每个ClassLoader都有一个父类的引证。当ClassLoader需求加载某个类时,先判别是否加载过,假如加载过就回来Class方针。不然交给他的父类去加载,持续判别是否加载过。这样 层层判别,就到了最顶层的BootStrap ClassLoader来企图加载。假如连最顶层的Bootstrap ClassLoader都没加载过,那就加载。假如加载失败,就转交给子ClassLoader,层层加载,直到最底层。假如还不能加载的话那就只能抛出异常了。

经过这种双亲托付模型,好处是:

  • 更高效,父类加载一次就能够避免了子类屡次重复加载
  • 更安全,避免了外界伪造java核心类。

Android中的ClassLoader
android从5.0开端运用art虚拟机,这种虚拟机在程序运转时也需求ClassLoader将类加载到内存中,可是与java不同的是,java虚拟机经过读取class字节码来加载,可是art则是经过dex字节码来加载。这是一种优化,能够兼并多个class文件为一个classes.dex文件。

android一共有三种类加载器:

  • BootClassLoader:父类结构器
  • PathClassLoader:一般是加载指定路径/data/app中的apk,也便是装置到手机中的apk。所以一般作为默许的加载器。
  • DexClassLoader:从包括classes.dex的jar或许apk中,加载类的加载器,可用于动态加载。

看PathClassLoader和DexClassLoader源码,都是承继自BaseDexClassLoader。

public DexClassLoader(String dexPath, String optimizedDirectory,
     String librarySearchPath, ClassLoader parent) {
   super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
public class PathClassLoader extends BaseDexClassLoader {
   public PathClassLoader(String dexPath, ClassLoader parent) {
       super(dexPath, null, null, parent);  //见下文
  }
}
public class BaseDexClassLoader extends ClassLoader {
   private final DexPathList pathList;
   public BaseDexClassLoader(String dexPath, File optimizedDirectory,
       String libraryPath, ClassLoader parent) {
       super(parent);  //见下文
       //搜集dex文件和Native动态库
       this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
  }
}

咱们能够看到PathClassLoader的两个参数都为null,标明只能承受固定的dex文件,而这个文件是只能在装置后呈现的。而DexClassLoader中optimizedDirectory,和librarySearchPath都是能够自己界说的,说明咱们能够传入一个jar或许apk包,确保解压缩后是一个dex文件就能够操作了。因而,咱们一般运用DexClassLoader来进行插件化和热修正。

能够看到,BaseDexClassLoader有一个相当重要的进程便是初始化DexPathList。初始化DexPathList的进程首要是搜集dexElements和nativeLibraryPathElements。一个Classloader能够包括多个dex文件,每个dex文件被封装到一个Element方针。这element方针在初始化和热修正逻辑中是相当重要的。当查找某个类时,会遍历dexElements,假如找到就回来,不然持续遍历。所以当多个dex中有相同的类,只会加载前面的dex中的类。下面是这段逻辑的具体完成

public Class findClass(String name, List<Throwable> suppressed) {
   for (Element element : dexElements) {
       DexFile dex = element.dexFile;
       if (dex != null) {
           //找到方针类,则直接回来
           Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
           if (clazz != null) {
               return clazz;
          }
      }
  }
   return null;
}

总结

咱们先是解说了Java中类加载的双亲托付机制,然后介绍了Android中的几种ClassLoader,从源码视点介绍了两种ClassLoader加载机制的不同。以后的插件化实践中,咱们会经常用到DexClassLoader。

参考资料

Android跨进程通讯:图文详解 Binder机制 原理

写给 Android 应用工程师的 Binder 原理剖析

深入了解Android中的ClassLoader

Android类加载器ClassLoader