Android 插件化原理解析(4):Hook 机制之 AMS & PMS

651 查看

在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式Binder Hook;插件框架通过AOP实现了插件使用和开发的透明性。在讲述DroidPlugin如何实现四大组件的插件化之前,有必要说明一下它对ActivityManagerServiche以及PackageManagerService的Hook方式(以下简称AMS,PMS)。

ActivityManagerService对于FrameWork层的重要性不言而喻,Android的四大组件无一不与它打交道:

  1. startActivity最终调用了AMS的startActivity系列方法,实现了Activity的启动;Activity的生命周期回调,也在AMS中完成;
  2. startService,bindService最终调用到AMS的startService和bindService方法;
  3. 动态广播的注册和接收在AMS中完成(静态广播在PMS中完成)
  4. getContentResolver最终从AMSgetContentProvider获取到ContentProvider

PMS则完成了诸如权限校捡(checkPermission,checkUidPermission),Apk meta信息获取(getApplicationInfo等),四大组件信息获取(query系列方法)等重要功能。

在上文Android 插件化原理解析(3):Hook 机制之 Binder Hook中讲述了DroidPlugin的Binder Hook机制;我们知道AMSPMS就是以Binder方式提供给应用程序使用的系统服务,理论上我们也可以采用这种方式Hook掉它们。但是由于这两者使用得如此频繁,Framework给他们了一些“特别优待”,这也给了我们相对于Binder Hook更加稳定可靠的hook方式。

阅读本文之前,可以先clone一份 understand-plugin-framework,参考此项目的ams-pms-hook模块。另外,插件框架原理解析系列文章见索引

AMS获取过程

前文提到Android的四大组件无一不与AMS相关,也许读者还有些许疑惑;这里我就挑一个例子,依据Android源码来说明,一个简单的startActivity是如何调用AMS最终通过IPC到system_server的。

不论读者是否知道,我们使用startActivity有两种形式:

  1. 直接调用Context类的startActivity方法;这种方式启动的Activity没有Activity栈,因此不能以standard方式启动,必须加上FLAG_ACTIVITY_NEW_TASK这个Flag。
  2. 调用被Activity类重载过的startActivity方法,通常在我们的Activity中直接调用这个方法就是这种形式;

Context.startActivity

我们查看Context类的startActivity方法,发现这竟然是一个抽象类;查看Context的类继承关系图如下:

1457322345547

我们看到诸如ActivityService等并没有直接继承Context,而是继承了ContextWrapper;继续查看ContextWrapper的实现:

WTF!! 果然人如其名,只是一个wrapper而已;这个mBase是什么呢?这里我先直接告诉你,它的真正实现是ContextImpl类;至于为什么,有一条思路:mBase是在ContextWrapper构造的时候传递进来的,那么在ContextWrapper构造的时候可以找到答案
什么时候会构造ContextWrapper呢?它的子类ApplicationService等被创建的时候。

可以在App的主线程AcitivityThreadperformLaunchActivit方法里面找到答案;更详细的解析可以参考老罗的 Android应用程序启动过程源代码分析

好了,我们姑且当作已经知道Context.startActivity最终使用了ContextImpl里面的方法,代码如下:

代码相当简单;我们知道了两件事:

  1. 其一,我们知道了在Service等非Activity的Context里面启动Activity为什么需要添加FLAG_ACTIVITY_NEW_TASK
  2. 其二,真正的startActivity使用了Instrumentation类的execStartActivity方法;继续跟踪:

到这里我们发现真正调用的是ActivityManagerNativestartActivity方法;如果你不清楚ActivityManagerActivityManagerService以及ActivityManagerNative之间的关系;建议先仔细阅读我之前关于Binder的文章 Binder学习指南

Activity.startActivity

Activity类的startActivity方法相比Context而言直观了很多;这个startActivity通过若干次调用辗转到达startActivityForResult这个方法,在这个方法内部有如下代码:

可以看到,其实通过Activity和ContextImpl类启动Activity并无本质不同,他们都通过Instrumentation这个辅助类调用到了ActivityManagerNative的方法。

Hook AMS

OK,我们到现在知道;其实startActivity最终通过Ac/div>

可以看到,其实通过Activity和ContextImpl类启动Activity并无本质不同,他们都通过Instrumentation这个辅助类调用到了ActivityManagerNative的方法。

Hook AMS

OK,我们到现在知道;其实startActivity最终通过Ac 讲述DroidPlugin如何实现四大组件的插件化之前,有必要说明一下它对ActivityManagerServiche以及PackageManagerService的Hook方式(以下简称AMS,PMS)。

ActivityManagerService对于FrameWork层的重要性不言而喻,Android的四大组件无一不与它打交道:

  1. startActivity最终调用了AMS的startActivity系列方法,实现了Activity的启动;Activity的生命周期回调,也在AMS中完成;
  2. startService,bindService最终调用到AMS的startService和bindService方法;
  3. 动态广播的注册和接收在AMS中完成(静态广播在PMS中完成)
  4. getContentResolver最终从AMSgetContentProvider获取到ContentProvider

PMS则完成了诸如权限校捡(checkPermission,checkUidPermission),Apk meta信息获取(getApplicationInfo等),四大组件信息获取(query系列方法)等重要功能。

在上文Android 插件化原理解析(3):Hook 机制之 Binder Hook中讲述了DroidPlugin的Binder Hook机制;我们知道AMSPMS就是以Binder方式提供给应用程序使用的系统服务,理论上我们也可以采用这种方式Hook掉它们。但是由于这两者使用得如此频繁,Framework给他们了一些“特别优待”,这也给了我们相对于Binder Hook更加稳定可靠的hook方式。

阅读本文之前,可以先clone一份 understand-plugin-framework,参考此项目的ams-pms-hook模块。另外,插件框架原理解析系列文章见索引

AMS获取过程

前文提到Android的四大组件无一不与AMS相关,也许读者还有些许疑惑;这里我就挑一个例子,依据Android源码来说明,一个简单的startActivity是如何调用AMS最终通过IPC到system_server的。

不论读者是否知道,我们使用startActivity有两种形式:

  1. 直接调用Context类的startActivity方法;这种方式启动的Activity没有Activity栈,因此不能以standard方式启动,必须加上FLAG_ACTIVITY_NEW_TASK这个Flag。
  2. 调用被Activity类重载过的startActivity方法,通常在我们的Activity中直接调用这个方法就是这种形式;

Context.startActivity

我们查看Context类的startActivity方法,发现这竟然是一个抽象类;查看Context的类继承关系图如下:

1457322345547

我们看到诸如ActivityService等并没有直接继承Context,而是继承了ContextWrapper;继续查看ContextWrapper的实现:

WTF!! 果然人如其名,只是一个wrapper而已;这个mBase是什么呢?这里我先直接告诉你,它的真正实现是ContextImpl类;至于为什么,有一条思路:mBase是在ContextWrapper构造的时候传递进来的,那么在ContextWrapper构造的时候可以找到答案
什么时候会构造ContextWrapper呢?它的子类ApplicationService等被创建的时候。

可以在App的主线程AcitivityThreadperformLaunchActivit方法里面找到答案;更详细的解析可以参考老罗的 Android应用程序启动过程源代码分析

好了,我们姑且当作已经知道Context.startActivity最终使用了ContextImpl里面的方法,代码如下:

代码相当简单;我们知道了两件事:

  1. 其一,我们知道了在Service等非Activity的Context里面启动Activity为什么需要添加FLAG_ACTIVITY_NEW_TASK
  2. 其二,真正的startActivity使用了Instrumentation类的execStartActivity方法;继续跟踪:

到这里我们发现真正调用的是ActivityManagerNativestartActivity方法;如果你不清楚ActivityManagerActivityManagerService以及ActivityManagerNative之间的关系;建议先仔细阅读我之前关于Binder的文章 Binder学习指南

Activity.startActivity

Activity类的startActivity方法相比Context而言直观了很多;这个startActivity通过若干次调用辗转到达startActivityForResult这个方法,在这个方法内部有如下代码: