android Ipc----Binder<Aldl>源码分析

在android中进程与之间的通信最常用的是基于binder的Aldl(在ALDL中进行了一部分封装),所以使用起来比较方便

首先来粘贴自己写的一个aidl的demo ,基于此进行源码的探究:
首先在android中service—-client之间的通信

这里写图片描述

ok 下面 来看代码 :

Service:

Book.aidl:

// Book.aidl
package com.example.ipcclient;

// Declare any non-default types here with import statements
// declare class of book for aidl

parcelable Book;

IBookManager.aidl:

// IBookManager.aidl
package com.example.ipcclient;

// Declare any non-default types here with import statements

import com.example.ipcclient.Book;
interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    List<Book> getBookList();
    void addBook(in Book book);
}

Book.java:

package com.example.ipcclient;

import android.os.Parcel;
import android.os.Parcelable;



public class Book implements Parcelable{

    public String bookId;
    public String bookName;

    public Book(String bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }



    public String getBookId() {
        return bookId;
    }

    public void setBookId(String bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }


    protected Book(Parcel in) {
        bookId = in.readString();
        bookName = in.readString();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(bookId);
        dest.writeString(bookName);
    }
}

IBookService:

package com.example.ipcclient;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import java.util.ArrayList;
import java.util.List;


public class IBookservice extends Service{

    private ArrayList<Book> books;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        books = new ArrayList<>();
        return binder;
    }

    IBinder binder = new IBookManager.Stub(){
        @Override
        public List<Book> getBookList() throws RemoteException {
            if (books.size() == 0){
                return null;
            }
            return books;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }
    };
}

Client

service下的aidl Book.java 复制到clent下 <注意包名要一致>
MainActivity.java

package com.example.ipcservice;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.ipcclient.Book;
import com.example.ipcclient.IBookManager;

import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private int index;

    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iBookManager = IBookManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    private IBookManager iBookManager;
    private TextView txt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        initView();
        bindService();
    }

    private void initView() {
        Button btn = findViewById(R.id.btn);
        txt = findViewById(R.id.txt);
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        txt.setText("");
        Book book = new Book(String.valueOf(index), "java 基础");
        index++;
        try {
            iBookManager.addBook(book);
            List<Book> bookList = iBookManager.getBookList();
            for (int i = 0;i < bookList.size();i++){
                txt.append(bookList.get(i).toString() + "---");
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }


    }


    private void bindService() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.ipcclient",
                "com.example.ipcclient.IBookservice"));
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }


}

源码分析

这就是完整代码,在Service下注册服务,然后build之后会在build/generated/source/aidl/debug下生成IBookManager.java
这个是核心的代码

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/houruixiang/myspace/DesignAndroid/ClientIpc/src/main/aidl/com/example/ipcclient/IBookManager.aidl
 */
package com.example.ipcclient;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.ipcclient.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.example.ipcclient.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.ipcclient.IBookManager interface,
 * generating a proxy if needed.
 */
public static com.example.ipcclient.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.ipcclient.IBookManager))) {
return ((com.example.ipcclient.IBookManager)iin);
}
return new com.example.ipcclient.IBookManager.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_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.ipcclient.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.example.ipcclient.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.ipcclient.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.ipcclient.IBookManager
{
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;
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
@Override public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcclient.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.ipcclient.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException;
}

在service下IBookService中实例化IBookManager的静态内部类,初始化服务中自己顶方法体,以备client来调用,然后在IBookService中的onBind方法中返回改Service的IBinder实例对象:

扫描二维码关注公众号,回复: 1697114 查看本文章
IBinder binder = new IBookManager.Stub(){
        @Override
        public List<Book> getBookList() throws RemoteException {
            if (books.size() == 0){
                return null;
            }
            return books;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }
    };

然后在client中的MainActivity中跨进程绑定该service,在bindservice中获取初始化目标方法后的IBookManager的实例化IBinder—Stub

 private void bindService() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.ipcclient",
                "com.example.ipcclient.IBookservice"));
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }

ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iBookManager = IBookManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

ok,现在获取到service端传来的binder对象<目标方法的方法体已经初始化完毕>,下面需要根据其binder来获取IBookManager对象来传入参数,来跨进程调用service端实例化方法
但是在IBookManager中通过binder只能获取其代理对象:

public static com.example.ipcclient.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.ipcclient.IBookManager))) {
return ((com.example.ipcclient.IBookManager)iin);
}
return new com.example.ipcclient.IBookManager.Stub.Proxy(obj);
}

在java中代理的使用比较频繁,那么我们同样使用IBookManager的代理对象Proxy来进行调用其方法:
在client的MainActivity中我们这样调用:

@Override
    public void onClick(View v) {
        txt.setText("");
        Book book = new Book(String.valueOf(index), "java 基础");
        index++;
        try {
            iBookManager.addBook(book);
            List<Book> bookList = iBookManager.getBookList();
            for (int i = 0;i < bookList.size();i++){
                txt.append(bookList.get(i).toString() + "---");
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }


    }

这样直接走到IBookManager的代理的addBook(Book book)和getBookList()方法中:

private static class Proxy implements com.example.ipcclient.IBookManager
{
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;
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
@Override public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcclient.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.ipcclient.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}

上面的代码就是调用poxy的源码,其中mRemote就是service端传来的binder,即service端的IBookManager的静态内部类Stub,其中核心代码:

mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);

就是参数data传入,然后通过transact调用Service中的onTransact方法;下面看源码

  * Default implementation rewinds the parcels and calls onTransact.  On
     * the remote side, transact calls into the binder to do the IPC.
     */
    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

由以上代码可以知道,在transact中调用到onTransact(code, data, reply, flags);
那么继续看service下的IBookManager中Stub的onTransact:

@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_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.ipcclient.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.example.ipcclient.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.ipcclient.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

在Service端的onTransact中进行reply的写入;
到这里大概明白了,transact和onTransact中data是client中参数的传入,如果方法有返回,会有reply的写入并返回在result中;
那么继续看服务端代码IBookManger:

@Override public java.util.List<com.example.ipcclient.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.ipcclient.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.ipcclient.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.ipcclient.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}

是不是 和service交互之后data作为参数传入,reply写入结果,如果方法需要返回,从reply中写入result返回;

android IPC比较晦涩,但是理清的思路还是ok;有想法的朋友可以去看底层的实现

感谢阅读

猜你喜欢

转载自blog.csdn.net/soullines/article/details/79039611