Android Binder框架实现之bindService详解
Android Binder框架实现目录:
Android Binder框架实现之Binder的设计思想Android Binder框架实现之何为匿名/实名BinderAndroid Binder框架实现之Binder中的数据结构Android Binder框架实现之Binder相关的接口和类Android Binder框架实现之Parcel详解之基本数据的读写Android Binder框架实现之Parcel read/writeStrongBinder实现Android Binder框架实现之servicemanager守护进程Android Binder框架实现之defaultServiceManager()的实现Android Binder框架实现之Native层addService详解之请求的发送Android Binder框架实现之Native层addService详解之请求的处理Android Binder框架实现之Native层addService详解之请求的反馈Android Binder框架实现之Binder服务的消息循环Android Binder框架实现之Native层getService详解之请求的发送Android Binder框架实现之Native层getService详解之请求的处理Android Binder框架实现之Native层getService详解之请求的反馈Android Binder框架实现之Binder Native Service的Java调用流程Android Binder框架实现之Java层Binder整体框架设计Android Binder框架实现之Framework层Binder服务注册过程源码分析Android Binder框架实现之Java层Binder服务跨进程调用源码分析Android Binder框架实现之Java层获取Binder服务源码分析Android Binder框架实现之bindService详解
本篇博客编写思路总结和关键点说明:
为了更加方便的读者阅读博客,通过导读思维图的形式将本博客的关键点列举出来,从而方便读者取舍和阅读!
引言
小伙们还记得前面博客Android Binder框架实现之何为匿名/实名Binder中我们分析匿名/实名Binder的时候重点以bindService为例说明了匿名Binder在该调用过程中的运用(上篇的重点主要是匿名Binder在传输中如何在驱动中完成匿名Binder的实体节点的生成和引用的创建),那么在今天的博客中我们重点以bindService为例来分析匿名Binder的实际运用过程。 当然小伙们也可以抛开上面的匿名/实名Binder等相关知识点,单纯当成是bindService的源码分析也不为过,这个就看小伙们的出发点了,是分析匿名Binder的应用还是bindService的流程就看小伙们各取所需了。
- 注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ActiveServices.java
--- ServiceRecord.java
--- ProcessRecord.java
frameworks/base/core/java/android/app/
--- IActivityManager.java
--- ActivityManagerNative.java (内部包含AMP)
--- ActivityManager.java
--- IApplicationThread.java
--- ApplicationThreadNative.java (内部包含ATP)
--- ActivityThread.java (内含ApplicationThread)
--- ContextImpl.java
frameworks/base/core/java/android/app/LoadedApk.java
frameworks/base/core/java/android/app/IServiceConnection.aidl
frameworks/base/core/java/android/content/ServiceConnection.java
frameworks/base/core/java/android/util/Singleton.java
- 并且在后续的源码分析过程中为了简述方便,会将做如下简述:
ApplicationThreadProxy简称为ATP
ActivityManagerProxy简称为AMP
ActivityManagerService简称为AMS
ActivityManagerNative简称AMN
ApplicationThreadNative简称ATN
PackageManagerService简称为PKMS
ApplicationThread简称为AT
ActivityServices简称为AS
一. bindService开篇
在bindService的源码中将要涉及到三个主要的进程,分别是bindService发起端进程,system_server进程和目的端Service进程, 我们将会以这三个进程角度出来阐述bindService是怎么在这三个进程之间辗转腾挪达到远程绑定服务或者说是Binder传递功能的。对于绝大部分小伙们来说遇到一个新的知识点,一定是先从实例入手先使用,然后再深入原理及其实现,我们这里也不例外,先让我们看看bindService的实例怎么使用!
1.1 bindService使用实例
bindService的实例涉及到目的端Service进程和client端发起端进程,让我们来开写,好久没有写过实例了让我们入手一番!
定义aidl文件
bindService能实现的一个前提就是Android为我们提供了一套AIDL(Android Interface Definition Language)即Android接口定义语言,来帮助我们实现远程Binder的通信(当然我们也可以不使用AIDL语言,直接硬编码实现也行可以参见博客Android Binder实战开发指南之不借助AIDL创建Java层Binder服务)。好了前面说了这么多了,直接不如正题,编码一个aidl文件如下:
interface IAidlFun {
void doAction();
}
此时编译器会对aidl文件自动编译生成,IAidlFun.java文件,我们看看其神秘面纱,我想如何小伙们对Binder有过一定的基础,对其中的代码就不会陌生了,这就是Android为了我们快速能使用Binder而做的一个模板啊,即生成通信层代码模板,而用户完全只用关心业务层的逻辑,降低开发难度。
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\workspace\\PaxForAll\\src\\com\\example\\api\\aidl\\IAidlFun.aidl
*/
package com.example.api.aidl;
public interface IAidlFun extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements
com.example.api.aidl.IAidlFun {
private static final java.lang.String DESCRIPTOR = "com.example.api.aidl.IAidlFun";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.api.aidl.IAidlFun
* interface, generating a proxy if needed.
*/
public static com.example.api.aidl.IAidlFun asInterface(
android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.api.aidl.IAidlFun))) {
return ((com.example.api.aidl.IAidlFun) iin);
}
return new com.example.api.aidl.IAidlFun.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_doAction: {
data.enforceInterface(DESCRIPTOR);
this.doAction();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.api.aidl.IAidlFun {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void doAction() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_doAction, _data, _reply,
0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_doAction = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void doAction() throws android.os.RemoteException;
}
目的端(Service进程)
...
public class AidlService extends Service {
private BindService mBindService = null;
private static final String TAG = AidlService.class.getSimpleName();
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,"onBind");
return mBindService;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate");
mBindService = new BindService();
}
//此处的IAidlFun.Stub是由编译器自动实现生成的,帮我们快速实现Binder的开发
public class BindService extends IAidlFun.Stub {
@Override
public void doAction() throws RemoteException {
}
}
...
}
发起端进程
private IAidlFun mRemoteServiceProxy;
private void bindService() {
// 发起端进程绑定远程服务端进程
bindService(new Intent("com.example.aidl.aidlService"), mConnection,
Context.BIND_AUTO_CREATE);
}
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "onServiceConnected");
// 获取远程服务端Service代理端Proxy
mRemoteServiceProxy = IAidlFun.Stub.asInterface(service);
try {
// RPC远程服务端方法,实现跨进程交互
mRemoteServiceProxy.doAction();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
bindService感觉用起来好爽,好简单啊!可是其中涉及的过程调用和源码逻辑各位小伙们都清楚吗,不清楚也没有关系,让我们来一起搞清楚!
1.2 bindService源码分析前期知识储备
还是老套路,在正式开始分析之前我们还是磨刀不误砍柴工,我们还是对即将要分析的源码先来梳理梳理要准备的知识点,这样后续分析起来也会简单顺手一些。
1.2.1 进程创建流程
bindService调用过程中会牵涉到目的端进程的创建(即目的端服务进程没有创建的前提下),这个虽然不是本文的重点,但是还是大概看下其示意图,后面也会大概过下:
1.2.2 binderService时序图
为了不耽误小伙们的时间,如果看了下面的时序图觉得有信心跟下去深入的可以接着往下分析,如果觉得没有毅力深入的可以就此打住了(因为分析源码真的是一件枯燥乏味的事情)!
二. 发起端进程发送bindService请求
在正式开始bindService的分析之前,将要涉及到涉及到Context的继承关系类图,从下面的类图中可以看出,Context是一个接口(提供了很多的接口方法),ContextImp和ContextWrapper都是其实现类,我们常用的Activity、Service、Application都直接或间接继承自ContextWrapper。
2.1 ContextWrapper.bindService
这里我们可以看到bindService会调用到ContextWrapper类的bindService中,源码如下:
@Override
//ContextWrapper.java
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);//这里的mBase指向ContextImpl(怎么来的这里就不分析了,给出结论),其方法bindService见章节2.2
}
这里我们有如下几点需要注意:
- bindService方法第二个入参ServiceConnection为一个接口类型对象
- ServiceConnection内部方法onServiceConnected的一个入参参数为IBinder数据类型,它就是我们最终获取的远程Binder实体的服务代理端(同时它也是一个匿名Binder)。通过我们前面的博客知道IBinder类型是可以跨进程传递的,而这里也运用了IBinder的这个特性从而实现了bindService。
public interface ServiceConnection {
//这里的入参service就是我们最终要获取的远程Binder Service的远程代理端
public void onServiceConnected(ComponentName name, IBinder service);
public void onServiceDisconnected(ComponentName name);
}
2.2 ContextImpl.bindService
//ServiceConnection.java
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();//权限检测
//这里的入参conn是一个interface类型的接口类,供回调使用
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
无需多言,直接调用方法bindServiceCommon进行下一步的处理。
2.3 ContextImpl.bindServiceCommon
//ContextImpl.java
final LoadedApk mPackageInfo;
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;//这是一个aidl生成的Binder接口类
...
if (mPackageInfo != null) {
//获取的是内部静态类InnerConnection
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);//详见章节2.3.1
} else {
...
}
validateServiceIntent(service);//判断参数service的有效性
try {
...
//通过Binder远程调用AMS的bindService方法,详见2.4
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
...
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里的IServiceConnection是一个aidl生成的Binder通讯工具类文件,其定义如下所示(可以看到它被定义为oneway类型的,即是一个非阻塞的Binder调用):
//IServiceConnection.aidl
oneway interface IServiceConnection {
//注意这里的入参IBinder service和ServiceConnection的方法中入参IBinder service,都是相同的入参那么有啥关联,这里先预留一个疑点,到了后续小伙伴们应该就清楚了
void connected(in ComponentName name, IBinder service);
}
我们回过头来看看bindServiceCommon的主要功能,然后对其逐个出击,一一攻破:
- 创建对象内部静态类LoadedApk.ServiceDispatcher.InnerConnection的对象
- 调用AMS的代理端AMP,向AMS服务发起bindService请求
其中bindService的入参mMainThread.getApplicationThread()方法返回的是ApplicationThread对象, 该对象继承于ApplicationThreadNative(Binder服务端),这个ApplicationThread对象很重要,因为正是通过它串联其了AMS对发起端进程的ActivityThread的交互(如果把ApplicationThread当作服务端,那么此时AMS相关于ApplicationThread而言就是客户端)。其两者之间的关系建立详见下述的示意图,即AMS持有ApplicationThread的代理端,而应用端进程持有AMS的代理端AMP,二者相互持有各自Binder服务端的代理端进而完成了二者之间的RPC调用。
2.3.1 getServiceDispatcher
在正式开始介绍getServiceDispatcher获取内部静态类LoadedApk.ServiceDispatcher.InnerConnection的对象之前,我们先看看LoadedApk的类图关系,如下(先熟悉熟悉,这样后续分析源码不会迷失):
//LoadedApk.java
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;//ServiceDispatcher内部类
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);//查找mService中是否存在context的key
if (map != null) {//如果存在这样的map,则继续查找map中是否存在ServiceConnection类型的实例c的key
sd = map.get(c);//
}
if (sd == null) {//没有则创建
//创建服务分发对象,注意这里的参数c是ServiceConnection对象,详见2.3.2
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
//以ServiceConnection为key,ServiceDispatcher为value保存到map中
map.put(c, sd);
} else {
sd.validate(context, handler);
}
//返回内部类对象InnerConnection实例
return sd.getIServiceConnection();
}
}
在正式开始上述的源码分析前,我们先介绍介绍其中涉及的一个重要的数据结构对象mServices:
- 可以看到它是一个Hashmap类型的数据,其key为Context类型对象
- 然后mServices的value也是一个Hasmap,存放着Context对象所对应的ServiceConnection以及所对应的LoadedApk.ServiceDispatcher对象,即一个Context对象可以对应很多个ServiceConnection,但是同一个只会被创建一次
路障扫清了,让我们接着分析该方法,可以该方法返回LoadedApk.ServiceDispatcher.InnerConnection类型对象,该对象继承于IServiceConnection.Stub, 该类是由IServiceConnection.aidl类型文件由编译器怎懂自动生成的作为Binder服务端的实体端类。其中IServiceConnection.aidl在2.2章节已经有给出过了,就不放上了。
2.3.1 ServiceDispatcher
//LoadedApk.java
static final class ServiceDispatcher {
//内部类
private final ServiceDispatcher.InnerConnection mIServiceConnection;
//用户传递的参数
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
//保存第三方进程bindService传递过来的参数
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mForgotten;
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
//注意这里的入参IBinder实例对象service
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
}
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
//创建InnerConnection对象
mIServiceConnection = new InnerConnection(this);
//用户定义的ServiceConnection
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
//保存用户传递的参数,通常为Context.BIND_AUTO_CREATE
mFlags = flags;
}
}
//返回内部类对象InnerConnection实例
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
通过源码我们发现ServiceDispatcher是LoadedApk的内部类。InnerConnection是ServiceDispatcher的静态内部类,是不是有点拗口啊,这就是为什么我在前面先其奉上了LoadedApk的类图的原因。其中ServiceDispatcher有一个重要的方法getIServiceConnection(),通过该方法返回的便是在其构造方法中创建的InnerConnection对象。而这个InnerConnection也是bindService中的关键类,为啥这么说呢,往后分析小伙们就知道了!
2.4 AMN.getDefault()
继续回到章节2.3在获取到InnerConnection实例对象sd之后,调AMN.getDefault().bindService,这里牵涉到一个重要的方法AMN.getDefault(),其实它在我们的博客中Android Binder框架实现之Java层获取Binder服务源码分析已经有详细的介绍和分析了,但是为了博客的连贯性还是简单过下(主要是为了不太熟悉的小伙伴们)。
//ActivityManagerNative.java
static public IActivityManager getDefault() {
return gDefault.get();
}
这里的gDefault是Singleton对象实例,而Singleton我们可以看到是一个模板类对象,并且提供了一个单例方法,其定义如下:
//Singleton.java
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {//采用单例模式
mInstance = create();
}
return mInstance;
}
}
}
我们将IActivityManager带入Singleton,得到如下的create方法过程:
//ActivityManagerNative.java
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
//此处等价于IBinder b = new BinderProxy(new BpBinder(handle));
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
//此处等价于IActivityManager am = new ActivityManagerProxy(new BinderProxy(new BpBinder(handle)))
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
//注意此处我们的入参是BinderProxy类型,所以会走代理端
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
//即会走到此处
return new ActivityManagerProxy(obj);
}
这里即最终经过层层转换得到了AMS服务的代理端ActivityManagerProxy,进而借助它完成对AMS服务的RPC请求。
2.4.1 AMN.getDefault()小结
AMN.getDefault()的调用流程基本分析结束了,我们对其小结一下:
- AMN.getDefault()最终获取了AMS的远程Binder代理端AMP
- AMS的Binder通信过程中提供了一个IActivityManager服务业务层接口,AMP类与AMS类都实现了IActivityManager接口方法,区别不同给的是AMS端显示了真正的具体服务,而AMP端是封装了相关的通信传输逻辑。AMP作为Binder通信的服务代理端,而AMS作为Binder通信的服务端实体,根据Android Binder框架实现之Java层Binder服务跨进程调用源码分析,AMP.bindService()最终调用AMS.bindService(),整个流程图如下:
2.5 AMP.bindService()
//ActivityManagerNative.java
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, String callingPackage, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
//写入AMS Binder服务描述信息即android.app.IActivityManager
data.writeInterfaceToken(IActivityManager.descriptor);
//写入IApplicationThread 匿名Binder服务实体(这个在attachApplication时写入过)
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeStrongBinder(token);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
//此处写入IServiceConnection 匿名Binder服务实体
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
data.writeString(callingPackage);
data.writeInt(userId);
//mRemote指向BinderProxy,而BinderProxy持有C++端的BpBinder,进而借助Binder驱动和AMS通信
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
data.recycle();
reply.recycle();
return res;
}
这里如果对Binder框架熟悉的小伙们应该对上述的调用过程是见怪不怪了,但是有几个点我们需要注意:
- bindService中调用了三次Parcel类的方法writeStrongBinder(),这里我们需要注意writeStrongBinder()这三次写入的是Binder实体代理端还是代理端,是实名Binder还是匿名Binder。
- 这里的mRemote指向BinderProxy,而BinderProxy持有C++端的BpBinder,而BpBinder作为远程Binder实体的通信代理端,最后借助Binder驱动和AMS通信,最后调用到ActivityManagerNative的onTransact()方法中
三. system_server进程处理bindService请求
通过上面的层层冲关,打怪我们跳出了发起端进程,来到了system_server进程,让我们接着分析看看system_server是怎么处理bindService的RPC请求的。
3.1 AMN.onTransact
//ActivityManagerNative.java
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
...
case BIND_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
//此处b为ApplicationThread的代理端,转换后生成即ApplicationThreadProxy对象
IApplicationThread app = ApplicationThreadNative.asInterface(b);
IBinder token = data.readStrongBinder();
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
b = data.readStrongBinder();//注意这里的b被重新赋值了
int fl = data.readInt();
String callingPackage = data.readString();
int userId = data.readInt();
//生成IServiceConnection的代理对象IServiceConnection.Stub.Proxy
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
int res = bindService(app, token, service, resolvedType, conn, fl,
callingPackage, userId);//详见3.2
reply.writeNoException();
reply.writeInt(res);
return true;
}
...
}
}
在正式开始上述的源码分析前,我们先来阐述一个重要的知识点,即在这个调用过程中涉及到两个进程,不妨令bindService的发起进程记为进程Process_A,AMS Service所属进程记为进程Process_B;那么进程Process_A通过Binder机制(采用IActivityManager接口)向进程Process_B发起请求服务,进程Process_B则通过Binder机制(采用IApplicationThread接口)向进程Process_A发起请求服务。也就是说进程Process_A与进程Process_B能相互间主动发起请求,进而完成进程通信,但是这里有一点需要注意IApplicationThread的Binder实体端并没有注册到servicemanager进程中,它是一个依赖于实名Binder的匿名Binder。
这里涉及IApplicationThread很重要,它串联起了AMS对App进程的生命周期及其其它的控制,那么下面直接把其相关的类图展示如下:
这里的IApplicationThread与IActivityManager的Binder通信原理一样,ATP作为Binder通信的客户端,ATN作为Binder通信的服务端,其中ApplicationThread继承ATN类,覆写其中的部分方法。
接着继续分析onTransact方法,其根据AMP传递过来的code值进入BIND_SERVICE_TRANSACTION分支,然后解读取通过Binder驱动传递过来的数据,解析完成之后调用AMN的方法bindService继续未完成之工作(这里的bindService在AMS服务中具体实现),这里从驱动中获取到数据然后解析这里就不重点关注了,我们这里重点关注一下AMN.bindService的几个入参:
- 参数app: 发起端进程通过Binder IPC传递过来的ApplicationThread对象(匿名Binder服务端实体端)的Binder通信层代理端BinderProxy(BinderProxy(BpBinder())), 然后借助ATN.asInterface()方法生成新的代理对象ApplicationThreadProxy类型对象app(这个地方有点拗口,如果实在转不过来就算了,我们只需要知道此处获取了ApplicationThread的远程代理端ATP)
- 参数conn: 根据发起端进程传递过来的InnerConnectiond对象(Binder服务端),同样通过转换后,生成IServiceConnection.Stub.Proxy类型对象conn
- 参数service: 数据类型为Intent, 是指本次要启动的service的意图
- 参数callingPackage: 发起方所属的包名
- 参数fl: 是指flags, 此时等于Context.BIND_AUTO_CREATE, 即值为1
3.2 AMS.bindService
//ActivityManagerService.java
//final ActiveServices mServices;
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
...
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
AMS的担子很大,代码很多,为了的代码的条理性和代码的易阅读性AMS将事务委托给ActiveServices类实例对象进行处理。
3.3 ActiveServices.bindServiceLocked
前方高能预警,小伙们可以趁着现在上个厕所,喝个水啥的,实在不行休息一下也行!因为后续的代码很长,很长,而且中途还不好休息最好是憋着一口气整完,不然又得找自己究竟在那里了!
//ActiveServices.java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
...
//查询发起端对应的进程记录结构
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
...
ActivityRecord activity = null;
//token不为空,代表着发起方具有activiy上下文
if (token != null) {
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;//存在token, 却找不到activity为空,则直接返回
}
}
int clientLabel = 0;
PendingIntent clientIntent = null;
final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;
if (isCallerSystem) {//调用者是否是system_uid用户
...
}
...
//根据发送端所在进程的SchedGroup来决定是否为前台service.
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
//根据第三方进程传递进来的Intent信息来检索相对应的服务,这个retriev单词很契合
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);//详见章节3.3.1
...
//查询到相应的Service
ServiceRecord s = res.record;
if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {//权限检测
...
}
try {
//取消服务的重启调度
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
if ((flags&Context.BIND_AUTO_CREATE) != 0) {//根据前面的分析可知,此处传递过来的flags的值就是Context.BIND_AUTO_CREATE
//更新当前service活动时间
s.lastActivity = SystemClock.uptimeMillis();
if (!s.hasAutoCreateConnections()) {
// This is the first binding, let the tracker know.
ServiceState stracker = s.getTracker();
if (stracker != null) {
stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
s.lastActivity);
}
}
}
mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
s.appInfo.uid, s.name, s.processName);
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);//详见章节3.3.2
//创建对象ConnectionRecord,此处connection来自发起方
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();//这里表示IServiceConnection服务的远程代理端,看来Binder真的是很重要阿
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);// clist是ServiceRecord.connections的成员变量
b.connections.add(c);//b是指AppBindRecord
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
s.whitelistManager = true;
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//启动service,这个过程和startService过程一致
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {//详见章节3.4
return 0;
}
}
if (s.app != null) {//此时表示service所属进程已经启动
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
s.app.treatLikeActivity = true;
}
if (s.whitelistManager) {
s.app.whitelistManager = true;
}
// This could have made the service more important.
//更新service所在进程优先级
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
|| s.app.treatLikeActivity, b.client);
mAm.updateOomAdjLocked(s.app);
}
...
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
//Service已经正在运行,则调用InnerConnection的代理对象
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
...
//当第一个app连接到该binding, 且之前已被bind过, 则回调onRebind()方法
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//最终回调onBind()方法
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
是不是感觉有点懵,这一坨代码的,不要慌!我们理一理这一坨代码的主要功能有哪些:
- 通常第三方进程调用system_server进程中的Java层Binder服务时候会做一些安全和功能的检测,这里也不例外,会判断发起端进程是否存在,是否存在activity上下文等信息
- 调用retrieveServiceLocked查找根据第三方进程传递进来的Intent所对应的服务,即系统中是否存在符合intent携带消息的Service
- 通过retrieveAppBindingLocked()方法创建AppBindRecord对象,该对象记录着当前ServiceRecord, intent以及发起方的进程ProcessRecord信息
- 一切准备就绪之后,调用bringUpServiceLocked拉起目标服务(如果此时目标进程还没有创建的话,得先创建目标进程)
另外可以看到在AMS服务中会将发起端传递过来的connection存储起来,即将发起端进程传递过来的LoadedApk.ServiceDispatcher.InnerConnection的代理对象IServiceConnection.Stub.Proxy类型对象实例connection,保存到新创建的ConnectionRecord对象的成员变量. 再通过clist.add( c ), 将该ConnectionRecord对象添加到clist队列. 后面便可以通过clist来 查询发起方的信息。
3.3.1 ActiveServices.retrieveServiceLocked
//ActiveServices.java
final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
...
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
ServiceMap smap = getServiceMap(userId);
final ComponentName comp = service.getComponent();
if (comp != null) {
//根据服务名查找对应的ServiceRecord
r = smap.mServicesByName.get(comp);
}
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
//根据Intent查找相应的相应的ServiceRecord
r = smap.mServicesByIntent.get(filter);
}
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
...
r = null;
}
if (r == null) {//在smap中没有查找到对应的服务
try {
...
//通过PKMS来查询相应的service
ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
...
}
//组装组件名
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {//声明externalService为true就是让该Service可以绑定并运行在调用方的App中,而不是在声明这个Service的App中
if (isBindExternal) {
if (!sInfo.exported) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
" is not exported");
}
if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
" is not an isolatedProcess");
}
// Run the service under the calling package's application.
ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
if (aInfo == null) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " +
"could not resolve client package " + callingPackage);
}
//其实就是重新设置了一遍ServiceInfo,让此Service改名换姓
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
sInfo.applicationInfo.packageName = aInfo.packageName;
sInfo.applicationInfo.uid = aInfo.uid;
name = new ComponentName(aInfo.packageName, name.getClassName());
service.setComponent(name);
} else {
throw new SecurityException("BIND_EXTERNAL_SERVICE required for " +
name);
}
} else if (isBindExternal) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
" is not an externalService");
}
if (userId > 0) {
//服务是否属于单例模式
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
userId = 0;
smap = getServiceMap(0);
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
BatteryStatsImpl.Uid.Pkg.Serv ss = null;
BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
//创建ServiceRecord
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
//将创建的ServiceRecord信息放入smap列表中,因为之前该service并没有创建过,所以会加入smap哈希列表
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
for (int i=mPendingServices.size()-1; i>=0; i--) {
ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.name.equals(name)) {
mPendingServices.remove(i);
}
}
}
} catch (RemoteException ex) {
}
}
if (r != null) {
//各种权限检查
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported)
!= PackageManager.PERMISSION_GRANTED) {
//当exported=false则不允许启动
if (!r.exported) {
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " that is not exported from uid " + r.appInfo.uid);
return new ServiceLookupResult(null, "not exported from uid "
+ r.appInfo.uid);
}
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null, r.permission);
} else if (r.permission != null && callingPackage != null) {
final int opCode = AppOpsManager.permissionToOpCode(r.permission);
if (opCode != AppOpsManager.OP_NONE && mAm.mAppOpsService.noteOperation(
opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires appop " + AppOpsManager.opToName(opCode));
return null;
}
}
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return null;
}
//创建Service查询结果,并返回
return new ServiceLookupResult(r, null);
}
return null;
}
前方的代码又是大一坨,主要是牵扯到各种数据结构的转换和关联,得数据结构这得天下啊,看来学好数据结构真的很重要啊,好像跑题了啊!前面我们知道retrieveServiceLocked主要是查询我们的目的端服务ServiceLookupResult结构是否存在(如果前面没有调用过,当然不存在得创建),其查询按照如下步骤依次执行(这里不详细展开了,不然那真是没完没了的了,估计你要疯,我也要疯):
- 通过userId查询mServiceMap中是否存在对应的ServiceMap实例,如果没有则创建一个并返回赋给ServiceMap实例smap
- 根据服务名从实例对象smap.mServicesByName中查找相应的ServiceRecord,如果没有找到,则往下执行;
- 根据Intent从实例对象smap.mServicesByIntent中查找相应的ServiceRecord,如果还是没有找到,则往下执行;
- 通过PKMS来查询相应的ServiceInfo,如果仍然没有找到相关信息,则不再往下执行,如若找到则继续执行填充ServiceRecord数据结构
这里还有一个知识点,就是ServiceInfo.FLAG_EXTERNAL_SERVICE这个标志,是干啥的呢,说实话我也没有用过,我多方翻阅发现这是service在AndroidManifest.xml中新增加的属性android:externalService,当它置为true的时候可以让该Service可以绑定并运行在调用方的App中,而不是在声明这个Service的App中,意不意外惊不惊喜,详细的分析可以参见这个博客android:externalService的功能和原理,这个不是我们的重点不过多分析,我们接着继续往下分析!
接着调用AMS.isSingleton判断我们要查询的目的端Service是否是单例模式,其中符合单例模式需要满足下述三个条件之一:
- 目的端组件uid>10000,且同时具有ServiceInfo.FLAG_SINGLE_USER flags和INTERACT_ACROSS_USERS权限,说实话这个地方我有个疑问就是目的端进程都没有创建uid怎么就分配了,特殊的进程除外啊
- 目的端组件运行在system进程的情况
- 目的端具有ServiceInfo.FLAG_SINGLE_USER flags,且uid=Process.PHONE_UID或者persistent app的情况
如果经过如上一顿猛如虎般的操作之后,依然没有找到合适的ServiceRecord对象,那么则会创建ServiceRecord实例,然后将前面解析,组装出来的相关参数填入ServiceRecord实例对象,然后分别以目的端服务的name和filter为key,存入到smap的mServicesByName和smap的mServicesByIntent。娘的这数据结构,左一坨右一坨的,难受!
3.3.2 ServiceRecord.retrieveAppBindingLocked
//ServiceRecord.java
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
//创建AppBindRecord对象记录着当前ServiceRecord, intent以及发起方的进程信息。
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
//创建连接ServiceRecord和fliter的记录
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
//此处app是指调用方所在进程
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
//创建ServiceRecord跟进程绑定的记录信息
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
说实话看着这一大坨的数据结构对象,真的感觉干不动了。不详细分析了,这里我们需要知道AppBindRecord对象记录着当前ServiceRecord,intent以及发起方的进程信息,并且该记录会存在在ArrayMap对象bindings中存起来,供后续查询!
3.4 bringUpServiceLocked
我们回到章节3.3继续未完成实名之bringUpServiceLocked,这也可以说是本篇的高潮部分了,因为该方法将会拉起服务端Service,倘若服务端进程还没有创建则会先创建进程进而再拉起服务。所以bringUpServiceLocked会分为两种情况处理!
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//此种情况前提是要启动的Service所属进程已经创建
if (r.app != null && r.app.thread != null) {
//兜兜转转最终调用到目的端Service.onStartCommand()过程,这个过程就不分析了,最后通过ApplicationThreadProxy调用到目的端ActivityThread进而控制目的端Service生命周期执行
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && r.restartDelay > 0) {
return null;//等待延迟重启的过程,则直接返回
}
// 启动service前,把service从重启服务队列中移除
if (mRestartingServices.remove(r)) {
r.resetRestartCounter();
clearRestartingIfNeededLocked(r);
}
//service正在启动,将delayed设置为false
if (r.delayed) {
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
//确保拥有该服务的user已经启动,否则停止,即多用户情况下
if (mAm.mStartedUsers.get(r.userId) == null) {
String msg = "";
bringDownServiceLocked(r);
return msg;
}
try {
//服务正在启动,设置package停止状态为false
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
...
}
//isolated为true表示Service独立运行到一个特定进程中
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
//根据进程名和uid,查询ProcessRecord
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {//此时
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
//启动服务
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
...
}
}
} else {
app = r.isolatedProc;
}
//对于进程没有启动的情况下,先启动进程
if (app == null && !permissionsReviewRequired) {
//启动service所要运行的进程,这就牵涉到Android应用进程创建的流程了
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {//详见章节3.4.1
bringDownServiceLocked(r);//进程启动失败处理逻辑
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);//注意此处,将ServiceRecord添加到mPendingServices中,后续会遍历此list
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);//停止服务
}
}
return null;
}
前面说过bringUpServiceLocked的启动分为两种情况:
- 当目标进程已存在,则直接执行realStartServiceLocked();
- 这个逻辑我想也是小伙们最关心的, 我们后续从这个地方开撸
3.4.1 AMS.startProcessLocked
startProcessLocked的路漫漫其修远兮吾将上下而求索,这个涉及的代码信息量太大,具体流程小伙们可以参见博客Android应用进程创建流程大揭秘,及最终会调用到目的端进程的ActivityThread.main方法里面,其中的过程大概可以使用如下的流程图表示:
我们就这ActivityThread.main接着分析(在这里我们只挑和我们这里相关的,其它的暂且不予关注),代码如下:
//ActivityThread.java
public static void main(String[] args) {
...
ActivityThread thread = new ActivityThread();
thread.attach(false);//参数false是重点
...
}
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);//老套路了啊,远程调用AMS的attachApplication方法,注意这里的参数是IApplicationThread的Binder实体端,该调用流程详见3.4.2
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} else {//不要问我谁会走此分支,我不会告诉你system_server的创建会走此分支的
...
}
}
3.4.2 AMS.attachApplication
到这里了我们就不详细分析目的端进程怎么通过Binder框架调用到AMS服务来了,大概的调用流程如下:
AMP.attachApplication() --->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
AMN.onTransact()--->
AMS.scheduleCreateService()
这个前面章节有具体分析过了,举一反三即可。我们直捣黄龙直接分析AMS的attachApplication方法。
//ActivityMangerService.java
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid);
...
}
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
if (!badApp) {
try {
//寻找所有需要在该进程中运行的服务
didSomething |= mServices.attachApplicationLocked(app, processName);//详见3.4.3
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
...
}
好吗又调用到了ActiveServices对象实例中去了,我们接着分析其attachApplicationLocked方法。
3.4.2 ActiveServices.attachApplicationLocked
//ActiveServices.java
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
//遍历所有在mPendingServices列表中,等待在该进程中启动的service,此处mPendingServices的添加在3.4章节bringUpServiceLocked的最后,即mPendingServices.add阶段
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
mPendingServices.remove(i);
i--;
//将当前服务的包信息加入到proc
proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
mAm.mProcessStats);
//正常启动service,并开始其的生命周期
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeeded(sr, false, false)) {
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
throw e;
}
}
//对于正在等待重启并需要运行在该进程的服务,现在是启动它们的大好时机
if (mRestartingServices.size() > 0) {
ServiceRecord sr;
for (int i=0; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
mAm.mHandler.removeCallbacks(sr.restarter);
mAm.mHandler.post(sr.restarter);
}
}
return didSomething;
}
兜兜转转,又来到了realStartServiceLocked方法,这个和前面章节总结的前后照应了:
- 即当需要创建新的进程时候,会调用AMS.startProcessLocked启动进程,然后经过千辛万苦的各种辗转最后调用到attachApplicationLocked方法,进而调用realStartServiceLocked方法
- 若不用创建进程,则直接调用realStartServiceLocked方法,进行剩余工作
3.5 ActiveServices.realStartServiceLocked
//ActiveServices.java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
//发送delay消息,ANR预埋雷
bumpServiceExecutingLocked(r, execInFg, "create");//详见3.5.1
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();
boolean created = false;
try {
...
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//这里的app.thread是IApplicationThread服务的远程代理客户端,服务进入onCreate
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);//调用到远程服务端onCreate方法,详见章节3.6
r.postNotification();
created = true;
} catch (DeadObjectException e) {//应用死亡通知
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.services.remove(r);
r.app = null;
if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
Slog.w(TAG, " Failed to create Service !!!! ."
+"This will introduce huge delay... "
+r.shortName + " in " + r.restartDelay + "ms");
}
}
// Retry.
//尝试重新启动服务
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
//通过bindService方式启动service
requestServiceBindingsLocked(r, execInFg);//详见章节5.1
updateServiceClientActivitiesLocked(app, null, true);
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
//开启service的生命周期onStartCommand()
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);
}
}
}
记得我们经常说的Android四大组件中不能执行耗时操作吗,小伙们有想过为什么吗?这是因为有Android ANR的预埋雷机制,关于ANR的机制和原理可以详细参见博客理解Android ANR的触发原理,在bumpServiceExecutingLocked会发送一个延迟处理的消息SERVICE_TIMEOUT_MSG。在方法scheduleCreateService执行完成,也就是onCreate回调执行完成之后,便会remove掉该消息。但是如果没能在延时时间之内remove该消息,则会进入执行service timeout流程触发ANR,这就是为啥Android 四大组件不能执行耗时操作的原因。
3.5.1 ActiveServices.bumpServiceExecutingLocked
//ActiveServices.java
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
if (r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
scheduleServiceTimeoutLocked(r.app);//走入该分支,不要问我为啥,调试打印的结果
}
r.executeFg |= fg;
r.executeNesting++;
r.executingStart = now;
}
不管选择那个分支,最终都会走入scheduleServiceTimeoutLocked方法!
3.5.2 ActiveServices.scheduleServiceTimeoutLocked
//ActiveServices.java
//前台服务timeout时间为20
static final int SERVICE_TIMEOUT = 20*1000;
// 后台服务timeout时间为200s
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
long now = SystemClock.uptimeMillis();
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
//在超时允许的时间内依然没有remove该SERVICE_TIMEOUT_MSG,则会执行SERVICE_TIMEOUT_MSG流程
mAm.mHandler.sendMessageAtTime(msg,
proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}
还记得我们老说的Service的ANR超时时间吗,什么前台服务是多少,后台服务是多少,一切的源头都在于此,这里会延时发送消息SERVICE_TIMEOUT_MSG,而这个延时的时间可以看到分为两种情况:
- 对于前台服务,则超时时间为SERVICE_TIMEOUT,即timeout=20s
- 对于后台服务,则超时间为SERVICE_BACKGROUND_TIMEOUT,即timeout=200s
注意这里的mAm.mHandler是在AMS中进行处理的,其处理逻辑如下所示:
//AMS.java
final class MainHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case SERVICE_TIMEOUT_MSG: {
if (mDidDexOpt) {
mDidDexOpt = false;
Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
nmsg.obj = msg.obj;
mHandler.sendMessageDelayed(nmsg, ActiveServices.SERVICE_TIMEOUT);
return;
}
mServices.serviceTimeout((ProcessRecord)msg.obj);//又调用到ActiveServices中去了,老子不跟了
} break;
...
}
}
}
3.6 ATP.scheduleCreateService
//ApplicationThreadNative.java
public final void scheduleCreateService(IBinder token, ServiceInfo info,
CompatibilityInfo compatInfo, int processState) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
info.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
data.writeInt(processState);
try {
mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
} catch (TransactionTooLargeException e) {
Log.e("CREATE_SERVICE", "Binder failure starting service; service=" + info);
throw e;
}
data.recycle();
}
历史和其的相似,看来在Android源码的学习过程中Binder是一个必须攻克的堡垒啊。这里的ATP是IApplicationThread服务的代理端,然后借助BInder框架会调用到其服务端,而该匿名Binder服务端注册在目的端进程中,其调用过程大概如下:
ATP.scheduleCreateService()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.attachApplication()
四. 目的端进程处理bindService请求
通过ATP的努力和我们的Binder框架的协助,我们跨越万水千山,完成了system_server所在进程到Service所在目的端进程调用过程,让我们接着分析看看目的端进程是怎么处理bindService的RPC请求的。我好难啊!
4.1 ATN.onTransact
@Override
//ApplicationThreadNative.java
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
..
case SCHEDULE_CREATE_SERVICE_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);//常规操作,读取从binder驱动传递过来的业务数据
IBinder token = data.readStrongBinder();
ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data);
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
int processState = data.readInt();
scheduleCreateService(token, info, compatInfo, processState);//由其子类ApplicationThread实现,详见章节4.2
return true;
}
...
}
}
无需多言,直接进入下一关,打怪升级!
4.2 AT.scheduleCreateService
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();//创建CreateServiceData实例对象,为Service的创建准备数据
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
巧用ActivityThread的主线程的Handler发送消息,这里我们可以总结一下规律,通常AMS通过ATP发送过来的消息,遵循如下的处理逻辑,如下:
scheduleXXX() ---> handleXXX()
4.3 H.handleMessage
//ActivityThread.java
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
...
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj); //详见4.4
break;
case BIND_SERVICE:
handleBindService((BindServiceData)msg.obj);//onBind
break;
case UNBIND_SERVICE:
handleUnbindService((BindServiceData)msg.obj);
break;
case SERVICE_ARGS:
handleServiceArgs((ServiceArgsData)msg.obj); // serviceStart
break;
case STOP_SERVICE:
handleStopService((IBinder)msg.obj);
maybeSnapshot();
break;
...
}
}
}
无需多言,直接进入下一关,打怪升级!
4.4 AT.handleCreateService创建目的端Service并执行onCreate()方法
//AT.java
private void handleCreateService(CreateServiceData data) {
//如果应用处于后台即将进行GC,此时我们将其调回到活动状态,并且跳过本次GC
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//通过反射创建目标服务对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
//创建ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//创建Application对象
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//调用service服务的onCreate()方法
service.onCreate();//详见4.4.1
mServices.put(data.token, service);
try {
//调用服务创建完成,将ANR预埋雷除去,看来和AMS的互动很频繁啊
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);//详见章节4.5
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
该段代码,主要执行两个业务逻辑:
- 执行目的端Service的onCreate方法
- 调用AMS的serviceDoneExecuting方法,解除在前面3.5.2章节预埋的ANR雷,不然真的会爆炸的
4.4.1 Services.onCreate
//Services.java
public void onCreate() {
}
我曾跨过山河大海也穿过人山人海,终于来到了目标进程Service的生命周期onCreate方法中,通常Service的子类会重写该方法!不容易啊,终于看到了胜利曙光,但是还没有结束,依然还需要战斗!
4.5 AMS.serviceDoneExecuting
不要问我为啥来到此处,这都是套路,慢慢的套路!
//AMS.java
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
//AMS很闲啊,啥也不干全部扔给了ActivityServices处理了,详见4.5.1
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
无需多言,直接进入下一关,打怪升级!
4.5.1 ActivityServices.serviceDoneExecutingLocked
//ActivityServices.java
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
if (r != null) {
...
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);//详见4.5.2
Binder.restoreCallingIdentity(origId);
...
}
...
}
我感觉Android的开发工程师也很难受,一个方法里面代码太多了吗,小伙们说这个裹脚布,搞方法太多了吗,跳转的难受!
4.5.2 ActivityServices.serviceDoneExecutingLocked
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
//移除服务启动超时的消息,将ANR的雷排除
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
...
}
if (inDestroying) {
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app);
}
r.executeFg = false;
...
if (finishing) {
if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
}
r.app = null;
}
}
}
在此处终于将执行removeMessages将3.5.2章节预埋的ANR雷移除,即将消息息SERVICE_TIMEOUT_MSG从Handler的消息队列中移除。分析至此,小伙们应该了解了Service启动过程出现ANR,”executing service [发送超时serviceRecord信息]”,这往往是service的onCreate()回调方法执行时间过长的原因了。
五. 重返system_server进程
此时的我在那里,该何处何从。此时让我们穿越时空重新回到system_server进程,继续章节3.5之未完成实名,革命仍未成功还需努力啊。
5.1 AS.requestServiceBindingsLocked
//ActivityServices.java
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {//遍历有多少需要bindings的Service
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {//调用另外一个重载的requestServiceBindingLocked方法
break;
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
//发送bind开始的消息,又开始埋雷了
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//服务进入onBind()
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
throw e;
} catch (RemoteException e) {
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
return false;
}
}
return true;
}
通过bindService方式启动的服务, 那么该serviceRecord的bindings则一定不会空,不然后续的工作咋开展呢!而这里的入参ServiceRecord实例对象的创建可以回到章节3.5温故温故。接着继续调用重载的requestServiceBindingLocked方法继续处理,而在该重载的方法中主要执行了两项操作:
- 调用bumpServiceExecutingLocked方法继续埋雷,倘若目标Service的onBind方法没有在指定的时间内执行完毕,则会触发ANR,这个已经在前面有过详细分析了
- 接着调用目标服务端进程的AT代理端ATP的方法scheduleBindService,向AT发送Binder请求
5.2 ATP.scheduleBindService
//ApplicationThreadNative.java
public final void scheduleBindService(IBinder token, Intent intent, boolean rebind,
int processState) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
intent.writeToParcel(data, 0);
data.writeInt(rebind ? 1 : 0);
data.writeInt(processState);
mRemote.transact(SCHEDULE_BIND_SERVICE_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
AMS和AT之间的交互很频繁啊,目的端进程和system_server进程之间通过IApplicationThread和IActivityManager来回的折腾着。这里的ATP是IApplicationThread服务的代理端,然后借助BInder框架会调用到其服务端,而该匿名Binder服务端注册在目的端进程中,其调用过程大概如下:
ATP.scheduleBindService()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.scheduleBindService()
六. 重返目的端服务进程
这么来回的跳转,折腾着感觉心好累啊!但是木有办法,要想深入只能是操起锤子接着干了。
6.1 ATN.onTransact
@Override
//ApplicationThreadNative.java
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
..
case SCHEDULE_BIND_SERVICE_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
Intent intent = Intent.CREATOR.createFromParcel(data);
boolean rebind = data.readInt() != 0;
int processState = data.readInt();
scheduleBindService(token, intent, rebind, processState);//在其子类AT中实现该方法
return true;
}
...
}
}
无需多言,直接进入下一关,打怪升级!
6.2 AT.scheduleBindService
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();//创建BindServiceData实例对象,接收AMS传递过来的Service信息
s.token = token;
s.intent = intent;
s.rebind = rebind;
sendMessage(H.BIND_SERVICE, s);
}
巧用ActivityThread的主线程的Handler发送消息,这里我们可以总结一下规律,通常AMS通过ATP发送过来的消息,遵循如下的处理逻辑,如下:
scheduleXXX() ---> handleXXX()
6.3 H.handleMessage
//ActivityThread.java
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
...
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj); //onCreate
break;
case BIND_SERVICE:
handleBindService((BindServiceData)msg.obj);//onBind,详见6.4
break;
case UNBIND_SERVICE:
handleUnbindService((BindServiceData)msg.obj);
break;
case SERVICE_ARGS:
handleServiceArgs((ServiceArgsData)msg.obj); // serviceStart
break;
case STOP_SERVICE:
handleStopService((IBinder)msg.obj);
maybeSnapshot();
break;
...
}
}
}
无需多言,直接进入下一关,打怪升级!
6.4 AT.handleBindService
//AT.java
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
//执行Service.onBind()回调方法,此时在远程服务进程的主线程中
IBinder binder = s.onBind(data.intent);
//将onBinde返回值传递回去,注意这里的binder还是Binder服务端,只有经过Binder传输以后才变成了代理端
//这里的ActivityManagerNative.getDefault()获取的是AMS的代理端AMP
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
该段代码,主要执行两个业务逻辑:
- 执行目的端Service的onBind方法
- 调用AMS的publishService方法,即将获取到Service中的匿名Binder实体通过Binder传递到AMS中
6.4.1 Services.onBind
//Services.java
@Nullable
public abstract IBinder onBind(Intent intent);
我曾跨过山河大海也穿过人山人海,终于来到了目标进程Service的生命周期onBind方法中,Service的onBind()是抽象方法, 所以大家创建Service子类时必须要覆写该方法, 返回IBinder对象, 也可以直接返回NULL.
6.5 AMP.publishService
//ActivityManagerNative.java
public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
intent.writeToParcel(data, 0);
//将service.onbind的返回值传递给远端进程,这里写入的是bind目的服务端的Binder实体对象,经过Binder传输以后会转变成Binder代理端,并在AMS的内核进程中创建一个binder_ref引用
data.writeStrongBinder(service);
mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
AMS和AT之间的交互很频繁啊,目的端进程和system_server进程之间通过IApplicationThread和IActivityManager来回的折腾着。这里的AMP是IActivityManager服务的代理端,然后借助BInder框架会调用到其服务端AMS,其调用过程大概如下:
AMP.publishService()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
AMN.onTransact()--->
AMN.publishService()
七. 三进system_server进程
是时候展现真正的实力了,怎么从AMP到AMS的过程我们就不细说了,因为本篇博客里面已经有很多次这种操作了。我们直奔主题进入AMS。
7.1 AMS.publishService
//AMS.java
public void publishService(IBinder token, Intent intent, IBinder service) {
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
//这里需要关注的是入参service为目的端IBinder的代理端
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
远程服务的onBind()在目的服务端进程的返回值的IBinder类型是(Bn端), 在AMP.publishService()过程中经过data.writeStrongBinder(service)传递到底层驱动在system_server内核的binder_proc中创建上述IBinder实体的binder_ref引用, 再回到system_server进程中AMN.onTransact()中经过data.readStrongBinder()方法会获取该service所相对应的代理对象(Bp端).总而言之,此处的IBinder类型的service就是远程服务进程中的Bp端对象,并且此处的IBinder类型的service就是一个典型的匿名Binder,它并没有向servicemanager进程注册。
7.2 AS.publishServiceLocked
//AS.java
//注意此处的入参service为我们要启动服务端的代理端即(Bp)
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
...
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
...
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
//c.conn是指通往发起端进程的IServiceConnection.Stub.Proxy代理对象
c.conn.connected(r.name, service);//
} catch (Exception e) {
...
}
}
}
}
//解除章节5.1预先埋雷
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
此处是关键,让我们先缓一缓。这里先取出ServiceRecord 中的ConnectionRecord列表,然后匹配对应的intent消息,如果匹配到则取出ConnectionRecord中的IServiceConnection实例对象conn,先换缓缓,这个ServiceRecord和ConnectionRecord又是啥时候创建的呢,这个就要回到章节3.3和章节3.3.1其中涉及到了ServiceRecord和ConnectionRecord创建。
还有一个核心就是这里的c.conn指代什么呢,关于此处就得回到2.3章节细品了,这里我们给出结论c.conn是指通往发起端进程的IServiceConnection.Stub.Proxy代理对象,其是经由Binder调用从发起端进程传递过来的,而我们此时通过该代理端通过Binder IPC调用到进入发起方进程的IServiceConnection.Stub实体中。关于该匿名Binder的传递路线如下所示:
发起端进程(IServiceConnection.Stub) ---> Binder驱动 ---->system_server进程(IServiceConnection.Stub.Proxy)
并且根据前面的分析可知,由于LoadedApk.ServiceDispatcher.InnerConnection 继承于IServiceConnection.Stub. 所以,接下来便由回到发起方进程中的InnerConnection对象,关于其调用过程这里简单阐述一下:
IServiceConnection.Stub.Proxy.connected()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
IServiceConnection.Stub.onTransact()--->
InnerConnection.connected()
八. 重返发起端进程
来返往复,曲折之路告一段落,我们终于返回了发起端进程。让我们接着来到发起端进程的LoadedApk.ServiceDispatcher.InnerConnection分析之,关于LoadedApk可以回过头到2.3.1章节看看其类图,再巩固巩固!
8.1 InnerConnection.connected
//LoadedApk.java[InnerConnection]
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {//注意此处的sd为LoadedApk.ServiceDispatcher实例
sd.connected(name, service);//详见章节8.2
}
}
}
无需多言,直接进入下一关,打怪升级!
8.2 ServiceDispatcher.connected
//LoadedApk.java[ServiceDispatcher]
public void connected(ComponentName name, IBinder service) {
if (mActivityThread != null) {//走此分支,mActivityThread不为null,并且这里的mActivityThread是一个Handler不是ActivtyThread,可以从章节2.2看到这个Handler是发起端主线程的Handler,接下来详见8.3
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
无需多言,直接进入下一关,打怪升级!
8.3 RunConnection.run
//LoadedApk.java[RunConnection]
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command) {
mName = name;
mService = service;
mCommand = command;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
}
关于Handerl.post用法就不用多讲了,最后会触发RunConnection 的run方法执行,这里我们要注意doConnected方法的两个入参:
- mName指代我们bind的目的端远程Service的组件名对象ComponentName 实例
- mService指代我们bind的目的端远程端服务onBind()返回的返回的Binder实体的代理端对象
8.3 ServiceDispatcher.doConnected
//LoadedApk.java[ServiceDispatcher]
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
//创建死亡监听对象
info.deathMonitor = new DeathMonitor(name, service);
try {
//建立死亡通知,绑定到目的端Service IBinder实体,详见8.4
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (service != null) {
//回调用户的onServiceConnected方法
mConnection.onServiceConnected(name, service);
}
}
到此处分析起来也比较简单了,主要执行了如下两个逻辑:
- 先行创建死亡监听对象,也是内部类:LoadedApk.ServiceDispatcher.DeathMonitor,监听目的端服务Binder的情况
- 调用用户传递过来的回调类ServiceConnection的onServiceConnected方法
8.5 DeathMonitor
LoadedApk.java[DeathMonitor ]
private final class DeathMonitor implements IBinder.DeathRecipient
{
DeathMonitor(ComponentName name, IBinder service) {
mName = name;
mService = service;
}
public void binderDied() {
death(mName, mService);
}
final ComponentName mName;
final IBinder mService;
}
public void doDeath(ComponentName name, IBinder service) {
synchronized (this) {
ConnectionInfo old = mActiveConnections.get(name);
if (old == null || old.binder != service) {
// Death for someone different than who we last
// reported... just ignore it.
return;
}
mActiveConnections.remove(name);
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
mConnection.onServiceDisconnected(name);
}
此处不在本文的分析的重点之内,总之这里会监听目的服务端的情况,如果其发生了异常则会通知到其bind的发起端!关于DeathMonitor强烈推荐参见博客Binder死亡通知机制之linkToDeath
总结
至此,bindService已经基本分析完毕了,是时候重新拿去时序图来重新总结一把了,时序图如下:
- 小伙伴门有没有发现在bindService中牵涉到了大量的Binder IPC,在Android的源码分析里真的是学好Android Binder很重要啊,并且在交互过程中牵涉到了好几处的匿名Binder,小伙们能找出来吗
- 并且关于上述时序图中,红色代表Binder通信,绿色类代表发起端进程持有,黄色类代表system_server进程持有,蓝色代类代表目的端进程持有
从进程交互角度出发
- 发起端进程: 首先通过bindService携带接口回调类ServiceConnection传递到LoadedApk中,接着在该类中通过getServiceDispatcher获取发起端进程的匿名Binder服务端(此为第一处匿名Binder),即LoadedApk.ServiceDispatcher.InnerConnection,该对象继承于IServiceConnection.Stub;再通过bindService调用到system_server进程
- system_server进程: 依次通过scheduleCreateService和scheduleBindService方法, 远程调用到目的端进程进程(这里的前提是目的端进程已经创建,如果服务端进程还没有创建,则还牵涉到目的服务端进程的创建)
- 目的端进程: 依次执行目的端Service的onCreate()和onBind()方法;,然后将onBind()方法的返回值IBinder(作为目的端进程匿名的Binder服务端,此处为第二处匿名Binder服务端),接着通过publishService将该匿名Binder服务端的代理端传递到system_server进程
- system_server进程: 经过上述的一系列处理以后,利用IServiceConnection代理对象向发起端进程发起connected()调用, 并把target进程的onBind返回Binder对象的代理端传递到发起端进程
- 发起端: 回调到onServiceConnection()方法, 该方法的第二个参数便是目的端进程的Binder代理端. 到此便成功地拿到了目的端进程的代理, 可以畅通无阻地进行RPC交互了
从匿名Binder传递角度出发
还记得我们一开篇就说的匿名/实名Binder吗,综管全篇不知小伙们发现没有其实bindService的实质就是匿名Binder跨进程的传递,当然也不全是毕竟还是目的端进程创建的一些操作呢!那么我们站在匿名Binder传递的角度来看看bindService的流程,其最最核心的一点就是目的端Service IBinder匿名BInder服务端怎么传递到发起端,其传递过程大概如下:
目的端Service(IBinder实体) ---->
Binder驱动传递 --->
system_server进程(IBinder实体对应的代理端) --->
发起端进程(IBinder实体对应的代理端)