Android Binder框架实现之bindService详解「建议收藏」

Android Binder框架实现之bindService详解「建议收藏」关于bindService我们将从两个知识点出发,第一就是从进程之间的交互,第二就是匿名Binder之间的传递角度来探讨!当然小伙们也可以抛开上面的匿名/实名Binder等相关知识点,单纯当成是bindService的源码分析也不为过,这个就看小伙们的出发点了,是分析匿名Binder的应用还是bindService的流程就看小伙们各取所需了。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

    Android Binder框架实现之bindService详解

Android Binder框架实现目录:

Android Binder框架实现之Binder的设计思想
Android Binder框架实现之何为匿名/实名Binder
Android 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,我想这样反而小伙们更加容易接受! 在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();
  • 当目标进程不存在,则先执行startProcessLocked创建进程, 经过层层调用最后会调用到AMS.attachApplicationLocked, 然后再执行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实体对应的代理端)

写在最后

  经过此役我想小伙们一定意识到了Android Binder在Android的整个源码界的分量,想深入分析Android框架Binder是一道必须越过的坎。希望小伙们能越过Android Binder这道坎,在Android的道路上越走越远。好了,关于Android Binder框架实现之bindService详解到这里真的告一段落了,如果小伙们喜欢可以关注或者给我点个赞。最后特别鸣谢不在Android界的大神gityuan,因为是他给我了前进的力量!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/192655.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 密宗经典是佛说的吗_华为微信语音加密怎么试听

    密宗经典是佛说的吗_华为微信语音加密怎么试听什么?佛经都能用来加密了?自上次的社会主义核心价值观加密之后,我已经见怪不怪了。题目:夜哆悉諳多苦奢陀奢諦冥神哆盧穆皤三侄三即諸諳即冥迦冥隸數顛耶迦奢若吉怯陀諳怖奢智侄諸若奢數菩奢集遠俱老竟寫明奢若梵等盧皤豆蒙密離怯婆皤礙他哆提哆多缽以南哆心曰姪罰蒙呐神。舍切真怯勝呐得俱沙罰娑是怯遠得呐數罰輸哆遠薩得槃漫夢盧皤亦醯呐娑皤瑟輸諳尼摩罰薩冥大倒參夢侄阿心罰等奢大度地冥殿皤沙蘇輸奢恐豆侄得罰提哆伽諳沙楞缽三死怯摩大蘇者數一遮解析:这题是攻防世界中的一道题目,这一段文字是佛经,按..

    2022年10月23日
  • word文档怎么打印成册子_零基础学word文档

    word文档怎么打印成册子_零基础学word文档Word2003是微软公司提供的一款文字处理软件,可以对文字进行排版和编辑、分段等各种处理,最终将编辑好的内容打印出来,是办公室一族中必备的办公软件之一。Word2003具有一个“书籍折页”的功能,能够在一页纸上打印两页的内容,打印后可以从中缝装订成折叠的小册子,更便于携带和阅读,具体怎么来设置呢?就让Word联盟为大家带来分享!动画演示:①打开“页面设置”对话框,切换到

  • js,timeout,promise执行顺序

    js,timeout,promise执行顺序

  • .NET(c#) 移动APP开发平台 – Smobiler(1)

    .NET(c#) 移动APP开发平台 – Smobiler(1)如果说基于.net的移动开发平台,目前比较流行的可能是xamarin了,不过除了这个,还有一个比xamarin更好用的国内的.net移动开发平台,smobiler,不用学习另外一套开发模式或者搭建复杂的开发环境,smobiler能够让大家像开发传统windows一样去开发移动应用,那么列举一下这个平台的特点。1. 基于VisualStudio的可视化开发。如同开发传统Windows平台一样的…

  • 机器学习之文本分类(附带训练集+数据集+所有代码)

    机器学习之文本分类(附带训练集+数据集+所有代码)我本次对4类文本进行分类((所有截图代码和数据集最后附带免费下载地址))主要步骤:1.各种读文件,写文件2.使用jieba分词将中文文本切割3.对处理之后的文本开始用TF-IDF算法进行单词权值的计算4.去掉停用词5.贝叶斯预测种类文本预处理:除去噪声,如:格式转换,去掉符号,整体规范化遍历的读取一个文件下的每个文本中文分词…

  • 差分曼彻斯特编码详解「建议收藏」

    差分曼彻斯特编码详解「建议收藏」1.确定开始部位:第一个编码为0,表示从低到高第一个编码为1,表示从高到低;每一位由下面代替,表示信号的波动2.其次,下一位编码,遇0则跳动,遇1则不跳动

    2022年10月25日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号