请尊重分享成果,转载请注明出处:

http://blog.csdn.net/hejjunlin/article/details/52264977

在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Service预注册占坑,Service占了坑后又是什么时候开始瞒天过海欺骗AMS的?先看下Agenda:

  • AndroidMainfest.xml中概览
  • Service中关键方法被hook时机
  • startService被hook
  • 瞒天过海流程图
  • 认识ServiceManager

AndroidMainfest.xml中概览

android:process=”:PluginP02” 表示自定义一个名为PluginP02的进程,该属性一旦设置, 那么App启动之后, Service肯定会以远程服务方式启动, —- 可通过adb shell ps 就可以看到有一个独立的进程启动了.

项目 Package为 com.morgoo.droidplugin , 并设置 android:process=”:PluginP02”, 那么App运行时, 通过 adb shell ps | grep com.morgoo.droidplugin , 可以看到有两个进程:

startService被hook

IActivityManagerHookHandle.startService方法

replaceFirstServiceIntentOfArgs()

接下来我们继续回到StartService类中,看下afterInvoke方法

stopService,bindService,unbindService,setServiceForeground都是类似逻辑,可从源码中证实。

在前一篇《插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑》,我们曾了解到,8个进程中的service在预注册占坑,在AndroidManifest.xml中只有一个,那如果插件要启动多个service怎么办?这是第一个问题,而我们知道所有和服务相关的都要在系统的systemServer进程中进行注册,难道DroidPlugin要逆天的本事?这是第二个问题

我们从代码中发现有一个ServceManager,这和android系统中大管家ServiceManager相差一个i,难道要改大管家的职责?又多了一个疑惑

仔细看了下ServceManager中的代码:





以上代码可总结为:(以虚线分上下两部分)

1.上部分主要是ServceManager单例及有一个handleXXX相关的方法,下部分主要是Service的一些生命周期方法。

2.我们基本可以确定之前问题2和问题3的答案了,没有那么逆天的本事来操作ServiceManager,也不能修改大管家ServiceManager的职责

3.那问题又来了,这个类到底是做啥的?还起一个叫ServceManager的名字,

以hanldeOnTaskRemoveOne方法为例看看:

接着再看下ServceManager中的onBind方法:

然后调到handleOnBindOne方法中,我们前面分析了一个handleOnTaskRemovedOne方法,下面1-7步骤套路都是一样,主要在return时,直接调用service自身的onBind了,这和我们平时在Activity中new Intent,然后把这个intent传到onBind中.

那么问题来了,还要这么一个类倒腾来干啥呢?还记得上面有一处逻辑service为null时,就调用了handleCreateServiceOne,好戏在这里:



看了上面的分析后,我们再去回想第一个问题,那如果插件要启动多个service怎么办?不知道不没有注意到mTokenServices,mNameService,mServiceTaskIds这些成员变量,它们都是Map,key不一样,value全是Service,如个有多个service在插件中启动了,mTokenServices,mNameService,mServiceTaskIds这些成员变量分别掌握了Service的Token,name,及任务id(通过token拿到的)。那岂不是已经在管理这些多个service了。至于附属于这个类起的名字,叫什么都无所谓。

以上可用如下流程图表示:

前面一直有个问题解释的不彻底,就是问题3,ServceManager是否担当了修改系统大管家ServiceManager的职责?接下来,我们就稍微了解下系统大管家ServiceManager是做什么的?(PS: ServiceManager和Binder机制一样,不是一天两个就能研究的清楚的)

认识ServiceManager

Android系统Binder机制的总管是ServiceManager,所有的Server(System Server)都需要向它注册,应用程序需要向其查询相应的服务。平时,我们在studio上的DDMS中调试程序时,下图这个就是ServiceManager

这里以Java层加入ServiceManager及getService为数据流分析一下。

复习一下典型的Binder模式,有利于后面的理解:

1、客户端通过某种方式得到服务器端的代理对象。从客户端角度看来代理对象和他的本地对象没有什么差别。它可以像其他本地对象一样调用其方法,访问其变量。

2、客户端通过调用服务器代理对象的方法向服务器端发送请求。

3、代理对象把用户请求通过Android内核(Linux内核)的Binder驱动发送到服务器进程。

4、服务器进程处理用户请求,并通过Android内核(Linux内核)的Binder驱动返回处理结果给客户端的服务器代理对象。

5、客户端收到服务器端的返回结果。

JAVA层代码分析:

ServiceManager.java (frameworks\base\core\java\android\os)

对于xxxManager获取服务端service基本如此用法:

举例:

利用ContextImpl.java中的 public Object getSystemService(String name)

然后再调用:ServiceManager.getService(ServiceName);获取相应的服务端

知道了客户端获取一个Service的方法之后,我们回到ServiceManager的服务端:

BinderInternal.getContextObject() @ BinderInternal.java 是一个native 函数:

android_os_BinderInternal_getContextObject @ android_util_Binder.cpp

返回一个 BinderProxy对象保存到类成员mRemote(ServiceManagerProxy类成员)

public abstract class ServiceManagerNative extends Binder implements IServiceManager

ServiceManagerNative 继承自 Binder 并实现了 IServiceManager 接口,利用 asInterface()则提供一个 ServiceManagerProxy 代理对象使用

class ServiceManagerProxy implements IServiceManager

定义了类ServiceManagerProxy(代理),ServiceManagerProxy继承自IServiceManager,并实现了其声明的操作函数,只会被ServiceManagerNative创建,它实现了IServiceManager的接口,IServiceManager提供了getService和addService两个成员函数来管理系统中的Service。

上面代码总结如下:Java层先利用Parcel对象将数据进行序列化,然后利用transact将数据传给binder驱动,就是上面mRemote.transact,mRemote在JNI层是一个叫BpBinder的对象:

JNI层代码分析:

android_util_Binder.cpp

每当我们利用BpBinder的transact()函数发起一次跨进程事务时,其内部其实是调用IPCThreadState对象的transact()。BpBinder的transact()代码如下:

到此,不再向下深究,具体想了解可以看Binder机制及IPC相关内容。

所以,到这把第2个问题彻底弄明白了,ServceManager和ServiceManager根本不是一回事。到次,Service的瞒天过海得以实现,接着,就是介绍时候说的那样无需修改源码,多进程,多service等功能。另外ContentProvider及BroadCast原理是类似,不再进行分析。

下篇将开始分析包管理(宿主插件和插件包名有什么规则),APK解析(为什么可以免安装),进程管理(能确保隐藏起来,不会在process轻易被kill)

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

插件开发之360 DroidPlugin源码分析(五)Service预注册占坑的更多相关文章

  1. 插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52258434 在了解系统的activity,service,broa ...

  2. 插件开发之360 DroidPlugin源码分析(一)初识

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52123450 DroidPlugin的是什么? 一种新的插件机制,一种免安装的运行机制 ...

  3. 插件开发之360 DroidPlugin源码分析(三)Binder代理

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52138483 Hook机制中Binder代理类关系图 Hook机制中Binder代理时 ...

  4. 插件开发之360 DroidPlugin源码分析(二)Hook机制

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52124397 前言:新插件的开发,可以说是为插件开发者带来了福音,虽然还很多坑要填补, ...

  5. Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理

    Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...

  6. ABP源码分析五:ABP初始化全过程

    ABP在初始化阶段做了哪些操作,前面的四篇文章大致描述了一下. 为个更清楚的描述其脉络,做了张流程图以辅助说明.其中每一步都涉及很多细节,难以在一张图中全部表现出来.每一步的细节(会涉及到较多接口,类 ...

  7. MPTCP 源码分析(五) 接收端窗口值

    简述:      在TCP协议中影响数据发送的三个因素分别为:发送端窗口值.接收端窗口值和拥塞窗口值. 本文主要分析MPTCP中各个子路径对接收端窗口值rcv_wnd的处理.   接收端窗口值的初始化 ...

  8. Vue系列---理解Vue.nextTick使用及源码分析(五)

    _ 阅读目录 一. 什么是Vue.nextTick()? 二. Vue.nextTick()方法的应用场景有哪些? 2.1 更改数据后,进行节点DOM操作. 2.2 在created生命周期中进行DO ...

  9. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

随机推荐

  1. ●BZOJ 2119 股市的预测

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2119 题解: 这个题很好的. 首先把序列转化为差分序列,问题转化为找到合法的子序列,使得去除 ...

  2. 什么是Hash?

    什么是Hash? Hash中文翻译为散列,又成为"哈希",是一类函数的统称,其特点是定义域无限,值域有限.把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换 ...

  3. Python中模块之shutil及zipfile&tarfile的功能介绍

    shutil的功能介绍及其他打包.压缩模块 1. shutil模块的方法 chown 更改指定路径的属组 2. copy 拷贝文件和权限 方法:shutil.copy(src,dst,*,follow ...

  4. 【linux】---常用命令整理

    linux常用命令整理 一.ls命令 就是list的缩写,通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等 常用参数搭配: l ...

  5. mysql catalog的名字

    def 算是一个一点卵用都没有的知识点 然后tmd各个版本不同 用这个语句查 SELECT * FROM information_schema.SCHEMATA where schema_name=' ...

  6. 常见常用的CSS

    字体属性:(font) 大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位:PX.PD 样式 {font-style: obl ...

  7. 关于mysql安装到最后一步老是停留在starting server,显示无响应

    从昨天晚上到今天安装MySQL花了好长的时间,一直是在后面starting server 这部就显示无响应,查资料了解到是MySQL有残留,有些注册表文件需要手动清理,下面是具体方法. 1.先用卸载软 ...

  8. block的那些事(从懵懂到使用)

    从大学开始自学iOS,在iOS岗位已经两年了,遇到传值等操作,代理和block二选一的话,以前我会毫不犹豫选择代理.久而久之,入职到大公司之后,发现处处是block的天地,才慢慢的了解block并爱上 ...

  9. golang 线程与通道

    首先我们来看线程,在golang里面也叫goroutine 在读这篇文章之前,我们需要了解一下并发与并行.golang的线程是一种并发机制,而不是并行.它们之间的区别大家可以上网搜一下,网上有很多的介 ...

  10. 启动Docker容器

    启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动. 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器. 新建并 ...