1.Binder 是什么?
Binder 是一个工作在Linux层面的驱动,这一段驱动运行在内核态。Binder也是一种进程间通信机制。
2.为什么要多进程?
- Android 系统分配给每个进程的资源空间是有限的,当项目需要申请的资源过于庞大时,比如微信,qq,今日头条就需要多进程。
- 为了解决某些问题,比如WebView使用过程中,会存在内存泄漏,就可以将WebView放在另外一个进程中,就不会影响主进程。
3.进程间通信为什么要用到Binder机制?
由于进程是系统分配资源的基本单位,Android系统将每个进程空间隔离开,进程与进程之间是不能直接交换数据的,但每个进程可以与内核空间直接交互,所以可以借助在内核空间的Binder机制实现进程与进程之间的数据交互。
- Binder是将服务端、内核空间通过mmap同时映射到同一个物理空间,客户端只需要一次拷贝,将数据从客户端拷贝到这个物理空间,即可完成数据传输。
- 共享内存是将客户端,服务端、内核空间通过mmap同时映射到同一个物理空间,就无须拷贝就可实现数据传输。共享内存使用比较复杂,因为物理内存与各端的需要进行同步。
- Socket需要将客户端数据拷贝到内核空间,再将数据从内核空间拷贝到服务端,所以需要两次拷贝,传输效率比较低。
4.AIDL源码分析
客户端连接到服务端的服务后,在客户端可以通过BookManager.Stub.asInterface(service)拿到服务端AIDL在客户端的代理Proxy。(通信中的AIDL在服务端是Stub,在客户端是Proxy)
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
manager = BookManager.Stub.asInterface(service);
isConnected = true;
Log.d(TAG," onServiceConnected");
}
public static com.zzq.service.BookManager asInterface(android.os.IBinder obj){
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.zzq.service.BookManager))) {
return ((com.zzq.service.BookManager)iin);
}
return new com.zzq.service.BookManager.Stub.Proxy(obj);//返回服务端AIDL在客户端的代理
}
当客户端拿到BookManager的代理类调用getbooks()方法时,会调用以下函数
boolean _status = mRemote.transact(Stub.TRANSACTION_getbooks, _data, _reply, 0);
- mRemote是Binder
- Stub.TRANSACTION_getbooks是一个int值,由于客户端和服务端的AIDL完全一样,所以Binder给每个方法都标记了int值,这个值可以告诉服务端服务端想调用哪个方法
- _data是客户端传入参数数据
- _reply是服务端返回数据
- flags取值可以为0和1,0表示数据可以发送到服务端,服务端也可以返回数据,1表示数据可以由客户端发往服务端,但服务端不能返回。
当调用transact方法后,Binder会将数据传入到服务端,服务端AIDL的onTransact方法里面会接收到数据
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getbooks: //注释1 通过code得知客户端想调用这个方法
{
data.enforceInterface(descriptor);
java.util.List<com.zzq.service.Book> _result = this.getbooks();//注释2
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(descriptor);
com.zzq.service.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.zzq.service.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
注释2出的getbooks()方法直接调用到了服务端实现的BookManager.Stub中的getbooks()方法,进而完成从客户端到服务端的调用流程
private BookManager.Stub stub = new BookManager.Stub() {
@Override
public List<Book> getbooks() throws RemoteException {
return books;
}
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
};
客户端绑定服务端Service流程
客户端调用bindService(intent,connection, Context.BIND_AUTO_CREATE)后,会通过AIDL绑定ActivityManagerService。
如果服务端进程已经创建,则直接通过反射创建服务
如果服务端进程没有创建,则会创建进程,再创建服务
绑定服务实在ActivityThread中进行的,服务端每绑定一个服务,如果之前绑定过,就调用onBind,如果之前绑定过,就调用onRebind
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) {
IBinder binder = s.onBind(data.intent);//如果之前没有绑定过,就调用onBind,这里会返回binder ,这个binder是我们在自定义Service的onBind返回的服务端的存根stub。
ActivityManager.getService().publishService(
data.token, data.intent, binder);//在这里ActivityManagerService会将binder返回给客户端
} else {
s.onRebind(data.intent);//如果之前绑定过,就调用onRebind
ActivityManager.getService().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);
}
}
}
}
ActivityManager.getService().publishService(
data.token, data.intent, binder)最终会调到一下代码
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
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)) {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Published intent: " + intent);
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
c.conn.connected(r.name, service, false);//在这里会将服务端的Binder传给客户端的connected方法
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
c.conn.connected(r.name, service, false);方法会将服务端的Binder传给客户端的connected方法,进而完成绑定。