Binder

        Binder是什么?


机制: Binder 是一种进程间通信的机制


驱动: Binder 是一个虚拟物理设备驱动


应用层: Binder 是一个能发起进程间通信的 JAVA 类


Binder 就是 Android 中的血管,在 Android 中我们使用 Activity,Service 等组件都需要和 AMS


( system_server )进行通信,这种跨进程的通信都是通过 Binder 完成。


Activity,Service 等组件和 AMS 不是同一个进程,其实也是多进程通信。


Android系统中,涉及到多进程间的通信底层都是依赖于Binder IPC机制。



例如当进程 A 中的 Activity 要向进程 B 中的 Service 通信,这便需要依赖于 Binder IPC 。不仅于此,整



个 Android 系统架构中,大量采用了 Binder 机制作为 IPC (进程间通信, Interprocess



Communication )方案。



也存在部分其他的 IPC 方式,如管道、 SystemV 、 Socket 等



        为什么使用Binder



性能方面:



Binder 相对于传统的 Socket 方式,更加高效



Binder 数据拷贝只需要一次,而管道、消息队列、 Socket 都需要 2 次,共享内存方式一次内存拷贝



都不需要,但实现方式又比较复杂。




安全方面:



传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如 Socket 通信的 IP 地址是客户



端手动填入,很容易进行伪造



Binder 机制从协议本身就支持对通信双方做身份校检,从而大大提升了安全性



IPC 原理




android 多个springanimation android 多个进程bindservice_客户端


Binder IPC 实现原理


跨进程通信是需要内核空间做支持的。传统的 IPC 机制如管道、 Socket 都是内核的一部分。


Binder IPC 正是基于内存映射( mmap )来实现的,但是 mmap() 通常是用在有物理介质的文件系统


上,进程中的用户区域是不能直接和物理设备打交道的。


如果想要把磁盘上的数据读取到进程的用户区域,需要两次拷贝(磁盘 –> 内核空间 –> 用户空间) , 通常在


这种场景下 mmap() 就能发挥作用,通过在物理介质和用户空间之间建立映射,减少数据的拷贝次数,


用内存读写取代 I/O 读写,提高文件读取效。


AIDL

 AIDL简介


        AIDL( Android 接口定义语言),可以使用它定义客户端与服务端进程间通信( IPC )的编程接口。在 Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分 隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL 就是为了满 足这种需求而诞生的。通过AIDL ,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法, 从而满足进程间通信的需求。 AIDL是用于定义服务端和客户端通信接口的一种描述语言,可以拿来生产 IPC 代码,从某种意义上说 AIDL其实就是一个模板,因为在使用过程中,实际起作用的并不是 AIDL 文件,而是据此生产的一个 Interface的实例代码, AIDL 其实是为了避免我们重复写代码而出现的一个模板。


注意: 只有在需要不同应用的客户端通过 IPC 方式访问服务,并且希望在服务中进行多线程处理


时,您才有必要使用 AIDL 。如果您无需跨不同应用执行并发 IPC ,则应通过实现 Binder 来创建接


口;或者,如果您想执行 IPC ,但 需要处理多线程,请使用 Messenger 来实现接口。无论如


何,在实现 AIDL 之前,请您务必理解绑定服务。


  使用流程


        1. 在 .aidl 文件中定义 AIDL 接口,并将其添加到应用工程的 src 目录下,创建完成之后 rebuild


        2. Android SDK 工具会自动生成基于该 .aidl 文件的 IBinder 接口,具体的业务对象实现这个接口, 这个具体的业务对象也是 IBinder 对象,当绑定服务的时候会根据实际情况返回具体的通信对象 (本地还是代理)


        3. 将客户端绑定到该服务上,之后就可以调用 IBinder 中的方法来进行进程间通信( IPC )


下面从几个方面介绍 AIDL 的使用


        1. 创建 .aildl 文件


        2. 具体的业务对象实现基于 .aidl 文件生成的接口


        3. 向客户端公开接口


        4. 客户端远程调用 5. 验证 AIDL


  创建 .aildl 文件


        在 AIDL 中可以通过可带参数以及返回值的一个或多个方法来声明接口,参数和返回值可以是任意类 型,AIDL 中支持的数据类型如下: java 的 8 种数据类型: byte 、 short 、 int 、 long 、 float 、 double 、 boolean 、 char


        除此之外支持 String 、 charSequence 、 List 、 Map


        自定义数据类型


        如果参数或返回值类型为 List 或 Map 时:


List 中的所有元素都必须是 AIDL 支持的数据类型、其他 AIDL 生成的接口或自己声明的可打包类


型。可选择将 List 用作 “ 通用 ” 类(例如, List )。另一端实际接收的具体类始终是 ArrayList ,但生


成的方法使用的是 List 接口。


Map 中的所有元素都必须是 AIDL 支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类


型。 不支持通用 Map (如 Map<String,Integer> 形式的 Map )。 另一端实际接收的具体类始终


是 HashMap ,但生成的方法使用的是 Map 接口。


具体的业务对象实现基于 .aidl 文件生成的接口


        打开IPersonAidlInterface.aidl ,在 .aidl 文件中添加具体的业务方法,文件内容如下 :


interface IkeyAidlInterface {
    void setName(String name);
        void setAge(int money);
        String getInfo();
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}


. 然后,重新 rebuild project , Android SDK 工具会在相应的目录生成对应的与 .aidl 文件同名的 .java


接口文件,具体目录如下:


android 多个springanimation android 多个进程bindservice_客户端_02


  那么这个业务要体现在什么地方呢,从上面可知 Stub 是一个抽象类,那么它所提供的具体业务必


然需要一个具体的实现类来完成,下面实现这个具体的业务类,具体如下


 

public class IKeyimpl extends IkeyAidlInterface.Stub{
        String name;
        int money;
        @Override
        public void setName(String name) throws RemoteException {
            this.name=name;
        }

        @Override
        public void setAge(int money) throws RemoteException {
            Intent intent = new Intent();
            intent.setClass(KeyService.this,MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            this.money=money;
        }

        @Override
        public String getInfo() throws RemoteException {
            return "交易账户:"+name+"金额是:"+money;
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    }

向客户端公开接口


创建一个 Service 以便对外提供具体的业务,具体如下:


public class KeyService extends Service {
    public KeyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new IKeyimpl();
    }
}

也可以将Stub 抽象类与service复合写如下:

public class KeyService extends Service {
    public KeyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new IKeyimpl();
    }


    public class IKeyimpl extends IkeyAidlInterface.Stub{
        String name;
        int money;
        @Override
        public void setName(String name) throws RemoteException {
            this.name=name;
        }

        @Override
        public void setAge(int money) throws RemoteException {
            Intent intent = new Intent();
            intent.setClass(KeyService.this,MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            this.money=money;
        }

        @Override
        public String getInfo() throws RemoteException {
            return "交易账户:"+name+"金额是:"+money;
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    }
}

客户端远程调用


通过上面几步完成了服务的搭建,并将服务运行在独立进程中,下面主要就是客户端的具体调用了,具 体实现参考如下:


public class MainActivity extends AppCompatActivity {
    private Button button,button2,button3,button4;
    TextInputEditText textField,edt_one;
    private IkeyAidlInterface ikeyAidlInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=findViewById(R.id.button);
        button2=findViewById(R.id.button2);
        button3=findViewById(R.id.button3);
        button4=findViewById(R.id.button4);
        textField=findViewById(R.id.textField);
        edt_one=findViewById(R.id.edt_one);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.example.day36start2","com.example.day36start2.KeyService"));
                bindService(intent,conn,BIND_AUTO_CREATE);

            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    ikeyAidlInterface.setName("a123456");
                    ikeyAidlInterface.setAge(100);
                    String zys=ikeyAidlInterface.getInfo();
                    Log.i("take", zys);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });

    }
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            ikeyAidlInterface = IkeyAidlInterface.Stub.asInterface(service);
            Log.i("TAG" , ""+ikeyAidlInterface);
        }

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

在新版本要在AndroidManifest.xml中写上如下代码:

<queries>
        <package android:name="com.example.day36start2" />
    </queries>