首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >借助 AIDL 理解 Android Binder 机制——AIDL 的使用和原理分析

借助 AIDL 理解 Android Binder 机制——AIDL 的使用和原理分析

作者头像
程序亦非猿
发布于 2020-04-15 10:23:40
发布于 2020-04-15 10:23:40
1K00
代码可运行
举报
文章被收录于专栏:程序亦非猿程序亦非猿
运行总次数:0
代码可运行

船长的牢骚

给文章换了个主题样式,感觉更加骚气了一点,应该变好看了一点~有木有?

本文由船员 guanpj 再次赞助投稿,感激!~

在上一篇文章——借助 AIDL 理解 Android Binder 机制——Binder 来龙去脉[1]中我们已经分析了使用 Binder 机制的原因以及分析了 Binder 机制,本章我们将继续从 AIDL 的使用过程体验 Binder 在应用层的使用和原理。

AIDL 使用步骤

1.创建 UserManager.aidl 接口文件,声明作为 Server 端的远程 Service 具有哪些能力

UserManager.aidl:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.me.guanpj.binder;

import com.me.guanpj.binder.User;
// Declare any non-default types here with import statements

interface UserManager {
    void addUser(in User user);

    List<User> getUserList();
}

对于对象引用,还需要引入实体类

User.aidl:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// User.aidl
package com.me.guanpj.binder;

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

parcelable User;

跨进程传输对象必须实现 Parcelable 接口

User.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class User implements Parcelable {
    public int id;
    public String name;

    public User() {}

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    protected User(Parcel in) {
        id = in.readInt();
        name = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeString(name);
    }

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

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

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

生成的 UserManager 类如下:

UserManager.java:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.me.guanpj.binder;
// Declare any non-default types here with import statements

public interface UserManager extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.me.guanpj.binder.UserManager
    {
        private static final java.lang.String DESCRIPTOR = "com.me.guanpj.binder.UserManager";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.me.guanpj.binder.UserManager interface,
         * generating a proxy if needed.
         */
        public static com.me.guanpj.binder.UserManager asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.me.guanpj.binder.UserManager))) {
                return ((com.me.guanpj.binder.UserManager)iin);
            }
            return new com.me.guanpj.binder.UserManager.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
        {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_addUser:
                {
                    data.enforceInterface(descriptor);
                    com.me.guanpj.binder.User _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = com.me.guanpj.binder.User.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    this.addUser(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getUserList:
                {
                    data.enforceInterface(descriptor);
                    java.util.List<com.me.guanpj.binder.User> _result = this.getUserList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }
        private static class Proxy implements com.me.guanpj.binder.UserManager
        {
            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 addUser(com.me.guanpj.binder.User user) 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 ((user!=null)) {
                        _data.writeInt(1);
                        user.writeToParcel(_data, 0);
                    }
                    else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
                    _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
            @Override public java.util.List<com.me.guanpj.binder.User> getUserList() throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.me.guanpj.binder.User> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.me.guanpj.binder.User.CREATOR);
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public void addUser(com.me.guanpj.binder.User user) throws android.os.RemoteException;
    public java.util.List<com.me.guanpj.binder.User> getUserList() throws android.os.RemoteException;
}
3.创建 Service,实现 UserManager.Stub 类并将该实现类的实例在 onBind 方法返回

MyService.java:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MyService extends Service {

    class UserManagerNative extends UserManager.Stub {

        List<User> users = new ArrayList<>();

        @Override
        public void addUser(User user) {
            Log.e("gpj", "进程:" + Utils.getProcessName(getApplicationContext())
                    + ",线程:" + Thread.currentThread().getName() + "————" + "Server 执行 addUser");
            users.add(user);
        }

        @Override
        public List<User> getUserList() {
            Log.e("gpj", "进程:" + Utils.getProcessName(getApplicationContext())
                    + ",线程:" + Thread.currentThread().getName() + "————" + "Server 执行 getUserList");
            return users;
        }
    }

    private UserManagerNative mUserManagerNative = new UserManagerNative();

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("gpj", "进程:" + Utils.getProcessName(getApplicationContext())
                + ",线程:" + Thread.currentThread().getName() + "————" + "Server onBind");
        return mUserManagerNative;
    }
}
4.在作为 Client 端的 Activity 中,绑定远程 Service 并得到 Server 的代理对象
5.通过 Server 代理对象,调用 Server 的具体方法

MainActivity.java:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnBind;
    Button btnAddUser;
    Button btnGetSize;
    TextView tvResult;
    IUserManager mUserManager;

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

        btnBind = (Button) findViewById(R.id.btn_bind);
        btnAddUser = (Button) findViewById(R.id.btn_add_user);
        btnGetSize = (Button) findViewById(R.id.btn_get_size);

        btnBind.setOnClickListener(this);
        btnAddUser.setOnClickListener(this);
        btnGetSize.setOnClickListener(this);

        tvResult = (TextView) findViewById(R.id.txt_result);
    }

    @Override
    protected void onDestroy() {
        unbindService(mConn);
        super.onDestroy();
    }

    private ServiceConnection mConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("gpj", "进程:" + Utils.getProcessName(getApplicationContext())
                    + ",线程:" + Thread.currentThread().getName() + "————" + "Client onServiceConnected");
            mUserManager = UserManagerImpl.asInterface(service);
            try {
                //注册远程服务死亡通知
                service.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mUserManager = null;
        }
    };

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (mUserManager != null) {
                mUserManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
                mUserManager = null;
                // 重新绑定服务
                bindService();
            }
        }
    };

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_bind:
                bindService();
                break;
            case R.id.btn_add_user:
                if (null != mUserManager) {
                    try {
                        Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" +"Client 调用 addUser");
                        mUserManager.addUser(new User(111, "gpj"));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(MainActivity.this, "先绑定 Service 才能调用方法", Toast.LENGTH_LONG).show();
                }
                break;
            case R.id.btn_get_size:
                if (null != mUserManager) {
                    try {
                        Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" +"Client 调用 getUserList");
                        List<User> userList = mUserManager.getUserList();
                        tvResult.setText("getUserList size:" + userList.size());
                        Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" +"调用结果:" + userList.size());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(MainActivity.this, "先绑定 Service 才能调用方法", Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }

    private void bindService() {
        Intent intent = new Intent();
        intent.setAction("com.me.guanpj.binder");
        intent.setComponent(new ComponentName("com.me.guanpj.binder", "com.me.guanpj.binder.MyService"));

        Log.e("gpj", "进程:" + Utils.getProcessName(getApplicationContext())
                + ",线程:" + Thread.currentThread().getName() + "————" + "开始绑定服务");
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);
    }
}

AIDL 的实现过程

为了便于理解,这里用一个 Demo 来展示 AIDL 的实现过程:Activity 作为 Client 与作为 Server 端的远程 Service 实现数据交互,在绑定远程 Service 之后,点击 AddUser 后 Service 会将 Client 端传进来的 User 对象加入列表中,点击 GetSize 后远程 Service 将会把列表的长度返回给客户端。建议在继续阅读之前先查看或者运行一下项目源码[2]

Demo

在项目中创建 UserManager.aidl 文件之后,系统会自动在 build 目录生成一个与 UserManager.java 接口类,它继承了 IInterface 接口,UserManager 接口只有一个静态抽象类 Stub,Stub 继承自 Binder 并实现了 UserManager 接口,Stub 里面也有一个静态内部类 Proxy,Proxy 也继承了 UserManager(是不是有点乱,乱就对了,我也很乱)。

如此嵌套是为了避免有多个 .aidl 文件的时候自动生成这些类的类名不会重复,为了提高代码可读性,我们将生成的 UserManager 和 Stub 类 拆解并重新命名成了 IUserManager 类和 UserManagerImpl 类并在关键方法上添加了注释或者 Log。

AIDL

IUserManager.java:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IUserManager extends android.os.IInterface {
    // 唯一性标识
    static final java.lang.String DESCRIPTOR = "com.me.guanpj.binder.IUserManager";

    // 方法标识,用十六进制表示
    int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

    // Server 具有的能力
    void addUser(User user) throws android.os.RemoteException;
    List<User> getUserList() throws android.os.RemoteException;
}

UserManagerImpl.java:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class UserManagerImpl extends Binder implements IUserManager {
    /**
     * Construct the mLocalStub at attach it to the interface.
     */
    public UserManagerImpl() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * 根据 Binder 本地对象或者代理对象返回 IUserManager 接口
     */
    public static IUserManager asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        // 查找本地对象
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof IUserManager))) {
            Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" + "返回本地对象");
            return ((IUserManager) iin);
        }
        Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" + "返回代理对象");
        return new UserManagerImpl.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_addUser: {
                Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" + "本地对象通过 Binder 执行 addUser");
                data.enforceInterface(DESCRIPTOR);
                User arg0;
                if ((0 != data.readInt())) {
                    // 取出客户端传递过来的数据
                    arg0 = User.CREATOR.createFromParcel(data);
                } else {
                    arg0 = null;
                }
                // 调用 Binder 本地对象
                this.addUser(arg0);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getUserList: {
                Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" + "本地对象通过 Binder 执行 getUserList");
                data.enforceInterface(DESCRIPTOR);
                // 调用 Binder 本地对象
                List<User> result = this.getUserList();
                reply.writeNoException();
                // 将结果返回给客户端
                reply.writeTypedList(result);
                return true;
            }
            default:
                break;
        }
        return super.onTransact(code, data, reply, flags);
    }

    private static class Proxy implements IUserManager {
        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 addUser(User user) 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 (user != null) {
                   _data.writeInt(1);
                   user.writeToParcel(_data, 0);
               } else {
                   _data.writeInt(0);
               }
                Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" + "代理对象通过 Binder 调用 addUser");
                mRemote.transact(UserManagerImpl.TRANSACTION_addUser, _data, _reply, 0);
                _reply.readException();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
        }

        @Override
        public List<User> getUserList() throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            List<User> _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                Log.e("gpj", "线程:" + Thread.currentThread().getName() + "————" + "代理对象通过 Binder 调用 getUserList");
                mRemote.transact(UserManagerImpl.TRANSACTION_getUserList, _data, _reply, 0);
                _reply.readException();
                _result = _reply.createTypedArrayList(User.CREATOR);
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }
}

再进行分析之前,先了解几个概念:

  1. IInterface : 从注释中的说明看出,声明(自动生成或者手动创建)AIDL 性质的接口必须继承这个接口,这个接口只有一个 IBinder asBinder() 方法,实现它的类代表它能够进程跨进程传输( Binder 本地对象)或者持有能够进程跨进程传输的对象的引用(Binder 代理对象)。
  2. IUserManager : 它同样是一个接口,它继承了 IInterface 类,并声明了 Server 承诺给 Client 的能力
  3. IBinder : 它也是一个接口,实现这个接口的对象就具有了跨进程传输的能力,在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。
  4. Binder : 代表 Binder 本地对象,BinderProxy 类是它的内部类,是 Server 端 Binder 对象的本地代理,它们都继承了 IBinder 接口,因此都能跨进程进行传输,Binder 驱动在跨进程传输的时候会将这两个对象自动进行转换。
  5. UserManagerImpl : 它继承了 Binder 并实现了 IInterface 接口,说明它是 Server 端的 Binder 本地对象,并拥有 Server 承诺给 Client 的能力。

先从 MainActivity 中绑定服务后的回调方法着手:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private ServiceConnection mConn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mUserManager = UserManagerImpl.asInterface(service);
        try {
            // 注册远程服务死亡通知
            service.linkToDeath(mDeathRecipient, 0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mUserManager = null;
    }
};

onServiceConnected 的参数中,第一个是 Service 组件的名字,表示哪个服务被启动了,重点是类型为 IBinder 的第二个参数,在 Service.java 中的 onBind 方法中,已经把 Server 端的本地对象 UserManagerNative 实例返回给 Binder 驱动了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private UserManagerNative mUserManagerNative = new UserManagerNative();

@Override
public IBinder onBind(Intent intent) {
    return mUserManagerNative;
}

因此,当该服务被绑定的时候,Binder 驱动会为根据该服务所在的进程决定 是返回本地对象还是代理对象给客户端,当 Service 与 MainActivity 位于同一个进程当中的时候,onServiceConnected 返回 Binder 本地对象——即 UserManagerNative 对象给客户端;当 Service 运行在不同进程中的时候,返回的是 BinderProxy 对象。

接着,在将这个 IBinder 对象传给 UserManagerImpl 的 asInterface 方法并返回 IUserManager 接口,asInterface 方法实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 根据 Binder 本地对象或者代理对象返回 IUserManager 接口
*/
public static IUserManager asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    // 查找本地对象
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof IUserManager))) {
        return ((IUserManager) iin);
    }
    return new UserManagerImpl.Proxy(obj);
}

首先,会根据 DESCRIPTOR 调用 IBinder 对象的 queryLocalInterface 方法,那么就得看 IBinder 的实现类怎么处理这个方法了:

在 Binder 类中的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    // 判断 mDescriptor 跟参数 DESCRIPTOR 相同,返回 mOwner
    if (mDescriptor != null && mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

那么这个 mOwner 和 mDescriptor 又是什么时候被赋值的呢?答案在 Binder 的子类 UserManagerImpl 的构造方法里面,:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public UserManagerImpl() {
    // 将 UserManagerImpl 和 DESCRIPTOR 注入到父类(Binder)
    this.attachInterface(this, DESCRIPTOR);
}

在 Binder$BinderProxy 类中的实现:

BinderProxy 并不是 Binder 本地对象,而是 Binder 的本地代理,因此 queryLocalInterface 返回的是 null:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public IInterface queryLocalInterface(String descriptor) {
    return null;
}

综上两点可以看出,如果 obj.queryLocalInterface(DESCRIPTOR) 方法存在返回值并且是 IUserManager 类型的对象,那么它就是 Binder 本地对象,将它直接返回给 Client 调用;否则,使用 UserManagerImpl$Proxy 类将其进行包装后再返回,Proxy 类也实现了 IUserManager 接口,因此,在 Client 眼中,它也具有 Server 承诺给 Client 的能力,那么,经过包装后的对象怎么和 Server 进行交互呢?

首先,它会把 BinderProxy 对象保存下来:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Proxy(android.os.IBinder remote) {
    mRemote = remote;
}

然后,实现 IUserManager 的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void addUser(User user) 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 (user != null) {
            _data.writeInt(1);
            // 将 user 对象的值写入 _data
            user.writeToParcel(_data, 0);
        } else {
            _data.writeInt(0);
        }
        // 通过 transact 跟 Server 交互
        mRemote.transact(UserManagerImpl.TRANSACTION_addUser, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

@Override
public List<User> getUserList() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    List<User> _result;
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        // 通过 transact 跟 Server 交互
        mRemote.transact(UserManagerImpl.TRANSACTION_getUserList, _data, _reply, 0);
        _reply.readException();
        // 获取 Server 的返回值并进程转换
        _result = _reply.createTypedArrayList(User.CREATOR);
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

可以看到,不管什么方法,都是是将服务端的方法代号、处理过的参数和接收返回值的对象等通过 mRemote.transact 方法 Server 进行交互,mRemote 是 BinderProxy 类型,在 BinderProxy 类中,最终调用的是 transactNative 方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException;

它的最终实现在 Native 层进行,Binder 驱动会通过 ioctl 系统调用唤醒 Server 进程,并调用 Server 本地对象的 onTransact 函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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_addUser: {
            data.enforceInterface(DESCRIPTOR);
            User arg0;
            if ((0 != data.readInt())) {
                // 取出客户端传递过来的数据
                arg0 = User.CREATOR.createFromParcel(data);
            } else {
                arg0 = null;
            }
            // 调用 Binder 本地对象
            this.addUser(arg0);
            reply.writeNoException();
            return true;
        }
        case TRANSACTION_getUserList: {
            data.enforceInterface(DESCRIPTOR);
            // 调用 Binder 本地对象
            List<User> result = this.getUserList();
            reply.writeNoException();
            // 将结果返回给客户端
            reply.writeTypedList(result);
            return true;
        }
        default:
            break;
    }
    return super.onTransact(code, data, reply, flags);
}

在 Server 进程中,onTransact 会根据 Client 传过来的方法代号决定调用哪个方法,得到结果后又会通过 Binder 驱动返回给 Client。

总结

回溯到 onServiceConnected 回调方法,待服务连接成功后,Client 就需要跟 Server 进行交互了,如果 Server 跟 Client 在同一个进程中,Client 可以直接调用 Server 的本地对象 ,当它们不在同一个进程中的时候,Binder 驱动会自动将 Server 的本地对象转换成 BinderProxy 代理对象,经过一层包装之后,返回一个新的代理对象给 Client。这样,整个 IPC 的过程就完成了。

文章中的代码已经上传至我的 Github[5],如果你对文章内容有疑问或者有不同的意见,欢迎留言,我们一同探讨。

参考资料

[1]

借助 AIDL 理解 Android Binder 机制——Binder 来龙去脉: https://guanpj.cn/2017/08/10/Android-Binder-Principle-Analyze/

[2]

项目源码: https://github.com/guanpj/BinderDemo

[3]

写给 Android 应用工程师的 Binder 原理剖析: https://zhuanlan.zhihu.com/p/35519585

[4]

Binder学习指南: https://cloud.tencent.com/developer/article/1329601

[5]

Github: https://github.com/guanpj/BinderDemo

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序亦非猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Android Binder 机制——AIDL 的使用和原理分析
为了便于理解,这里用一个 Demo 来展示 AIDL 的实现过程:Activity 作为 Client 与作为 Server 端的远程 Service 实现数据交互,在绑定远程 Service 之后,点击 AddUser 后 Service 会将 Client 端传进来的 User 对象加入列表中,点击 GetSize 后远程 Service 将会把列表的长度返回给客户端。建议在继续阅读之前先查看或者运行一下项目源码:
没关系再继续努力
2021/12/01
8110
Android--Binder机制与AIDL
Binder机制核心点就是利用mmap开辟一块空间,使得多个进程可以访问,不仅接收端持有该映射,内核空间也持有,由于相当于内存,所以拷贝只需要一次:从发送端进程的工作内存(用户空间)到主内存(内核空间)的内存映射中,接收端也就相当于接收到了,想要深入理解可以查看Java--深入理解JMM模型、Java并发特性
aruba
2021/12/06
9710
Android--Binder机制与AIDL
AIDL初步理解
如果你是普通app开发,有可能遇不到跨进程访问数据。在车厂,智能座舱开发,跨进程访问数据是很平常的事,比如车机账户系统,很多模块都要获取当前车机账户信息,那账户系统就会提供相应数据给其他模块,账户系统和其他模块不属于同一个进程,这个时候就出现跨进程场景,Android系统为我们提供了一种技术方案:AIDL
笔头
2022/10/30
4280
一步步深入解析AIDL
在 Android 系统中,进程间通信 (IPC) 是一种很重要的机制。IPC 产生的原因是某些情况下需要在两个进程之间进行一些数据的交换。而在深入学习 Android 的过程中难免会遇到 IPC 的相关问题,比如常见的有在自己的应用程序中读取手机联系人的信息,这就涉及到 IPC 了。因为自己的应用程序是一个进程,通讯录也是一个进程,只不过获取通讯录的数据信息是通过 Content Provider 的方式来实现的。
俞其荣
2022/07/28
7040
一步步深入解析AIDL
Android 进阶9:进程通信之 AIDL 解析
张拭心 shixinzhang
2018/01/05
1.2K0
Android 进阶9:进程通信之 AIDL 解析
Android进阶必备:跨进程通讯机制
Binder机制是Android系统提供的跨进程通讯机制,这篇文章开始会从Linux相关的基础概念知识开始介绍,从基础概念知识中引出Binder机制,归纳Binder机制与Linux系统的跨进程机制的优缺点,接着分析Binder的通信模型和原理,而Binder机制最佳体现就是AIDL,所以在后面会分析AIDL的实现原理,最后简单的提下AMS的Binder体系,整篇文章中间会穿插有IBinder、Binder、Parcel的介绍,整篇文章阅读难度不大,不会涉及到framework层的Binder原理,AIDL部分需要有AIDL的使用基础
陈宇明
2020/12/15
7240
Android进阶必备:跨进程通讯机制
【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )
右键点击 " aidl " 目录 , 选择 " New / AIDL / AIDL File " 文件 ;
韩曙亮
2023/03/29
1.3K0
【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )
听说你Binder机制学的不错,来面试下这几个问题(三)
很多文章将Binder框架定义了四个角色:Server,Client,ServiceManager、以及Binder驱动,但这容易将人引导到歧途:好像所有的Binder服务都需要去ServiceManager去注册才能使用,其实不是这样。例如,平时APP开发通过bindService启动的服务,以及有些自己定义的AIDL远程调用,都不一定都ServiceManager注册这条路,个人理解:ServiceManager主要功能是:管理系统服务,比如AMS、WMS、PKMS服务等,而APP通过的bindService启动的Binder服务其实是由SystemServer的ActivityManagerService负责管理。这篇主要关注Android APP Java层Binder通信一些奇葩点:
看书的小蜗牛
2018/06/29
2.1K0
听说你Binder机制学的不错,来面试下这几个问题(三)
Android开发之漫漫长途 IX——彻底掌握Binder
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!另外,本系列文章知识可能需要有一定Android开发基础和项目经验的同学才能更好理解,也就是说该系列文章面向的是Android中高级开发工程师。
LoveWFan
2018/08/07
5750
Android开发之漫漫长途 IX——彻底掌握Binder
【Binder 机制】AIDL 分析 ( 分析 AIDL 文件生成的 Java 源文件 | Binder | IBinder | Stub | Proxy )
在上一篇博客 【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 ) 创建了 AIDL 文件 , 并编译生成了 AIDL 文件对应的 Java 源文件 , 现在开始分析生成在 " AIDL_Demo\app\build\generated\aidl_source_output_dir\debug\out\kim\hsl\aidl_demo " 目录 中的 " IMyAidlInterface.java " 源文件 ;
韩曙亮
2023/03/29
1.9K0
不得不说的Android Binder机制与AIDL
说起Android的进程间通信,想必大家都会不约而同的想起Android中的Binder机制。而提起Binder,想必也有不少同学会想起初学Android时被Binder和AIDL支配的恐惧感。但是作为一个Android开发者,Binder是我们必须掌握的知识。因为它是构架整个Android大厦的钢筋和混凝土,连接了Android各个系统服务和上层应用。只有了解了Binder机制才能更加深入的理解Android开发和Android Framework。这也是为什么无论是《Android开发艺术探索》还是《深入理解Android内核涉及思想》这些进阶类书籍把进程间通信和Binder机制放到靠前章节的原因,它太重要了,重要到整个Android Framework都离不开Binder的身影。
没关系再继续努力
2021/12/28
6380
Android aidl流程简单分析
我们通过写一个从服务端(另外一个进程)获取用户名和密码作为demo来进行源码讲解。
曾大稳
2018/09/11
5660
Android aidl流程简单分析
Java源码阅读绘图规范手册--[捷特版]
工欲善其事必先利其器,磨刀不误砍柴工 最近打算去深读源码,感觉不画图去分析源码根本理不清,也说不清 UML是分析类和类的关系,具体的类内部貌似没有图形机制,没有条件就创造条件呗 借此机会本人自定
张风捷特烈
2019/01/28
7650
Android点将台:金科玉律[-AIDL-]
张风捷特烈
2024/02/08
1500
Android点将台:金科玉律[-AIDL-]
【漫画技术】Android跨进程通信
Tips:4个环节,共计约9小时的精心打磨完成上线,同时也非常感谢参与审稿的同学。
用户2802329
2018/08/07
3080
【漫画技术】Android跨进程通信
源码分析——从AIDL的使用开始理解Binder进程间通信的流程
Binder通信是 Android 系统架构的基础。本文尝试从 AIDL 的使用开始理解系统的 Binder通信。
阳仔
2019/07/31
9880
源码分析——从AIDL的使用开始理解Binder进程间通信的流程
AIDL源码解析in、out和inout
为什么会想写这篇文章,只因为一个error idl.exe E 4928 5836 type_namespace.cpp:130] 'Book' can be an out type, so you must declare it as in, out or inout. 看过上一篇文章Android:IPC之AIDL的学习和总结的同学都知道这是因为在AIDL文件中使用非常规类型作为参数传递的时候没有标记指向tag,那么到底为什么会是这样子的呢,作为一个好奇宝宝我想好好看看。
静默加载
2020/05/29
2K0
【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )
AIDL 文件 IMyAidlInterface.aidl 在客户端和服务端都有 , 编译时 , 都会在 " build\generated\aidl_source_output_dir\debug\out\kim\hsl\aidl_demo " 目录生成 IMyAidlInterface.java 源文件 ;
韩曙亮
2023/03/29
1.5K0
架构·微服务架构·ANDROID 源码分析(二)
上一篇的文章架构·微服务架构详细描述微服务架构相关的理论基础,为这一篇文章打好了理论基础。这篇文章将站在 Android Framework 设计者的角度上,剖析在 Android 中应用的微服务架构。
幺鹿
2018/08/21
7260
架构·微服务架构·ANDROID 源码分析(二)
Android AIDL跨进程通信
aidl跨进程通信的步骤: 1、创建aidl文件。 2、build后生成aidl对应的java文件。 3、创建服务端Service。 4、创建客户端Activity,bindService(),获取IBinder的proxy 。
用户9854323
2022/10/04
6600
Android AIDL跨进程通信
相关推荐
Android Binder 机制——AIDL 的使用和原理分析
更多 >
LV.1
阿里资深无线开发工程师
目录
  • AIDL 使用步骤
    • 1.创建 UserManager.aidl 接口文件,声明作为 Server 端的远程 Service 具有哪些能力
    • 3.创建 Service,实现 UserManager.Stub 类并将该实现类的实例在 onBind 方法返回
    • 4.在作为 Client 端的 Activity 中,绑定远程 Service 并得到 Server 的代理对象
    • 5.通过 Server 代理对象,调用 Server 的具体方法
  • AIDL 的实现过程
  • 总结
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档