深入理解Binder机制1-AIDL原理

Binder作为Android系统中重要的进程间通信方式,了解其基本的原理,对于分析问题具有重要的作用。由于Binder架构涉及的内容比较多,后面将会从应用层、框架层、Native层、内核层四个层次来说明Binder的原理。首先将从应用层的AIDL开始逐渐深入到内核层。整个系列的文章如下:

深入理解Binder机制1-AIDL原理
深入理解Binder机制2-注册服务addService
深入理解Binder机制3-获取服务getService
深入理解Binder机制4-bindService过程分析
深入理解Binder机制5-binder驱动分析
深入理解Binder机制6-总结篇

一、AIDL

在进行进程间通信时,需要将接口定义好,定义好之后创建aidl文件,将接口方法放在文件中。客户端和服务端,aidl文件要保持一致,包括包名。在build之后,会在客户端和服务端生成接口类。

1.aidl文件

[->IRemoteService.aidl]

// IRemoteService.aidl
package com.skytoby.server;

interface IRemoteService {
    void addPhone(String name);
    boolean getPhone(String name);
    int getPid();
}

2.服务端

[->PhoneService.java]

package com.skytoby.server;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;

public class PhoneService extends Service {

    List phones = new ArrayList<>();
    
    //实现binder接口
    private IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        @Override
        public void addPhone(String name) throws RemoteException {
            Log.d("phone binder","server add phone:"+name);
            phones.add(name);
        }

        @Override
        public boolean getPhone(String name) throws RemoteException {
            Log.d("phone binder","server get phone:"+name);
            if(phones.contains(name)){
                return true;
            }
            return false;
        }

        @Override
        public int getPid() throws RemoteException {
            Log.d("phone binder","server getPid "+android.os.Process.myPid());
            return android.os.Process.myPid();
        }

        @Override
        public void linkToDeath(IBinder.DeathRecipient recipient, int flags) {
            super.linkToDeath(recipient, flags);
            Log.d("phone binder","server getPid linkToDeath");

        }
    };
    @Override
    public void onCreate() {
        Log.d("phone binder","server onCreate");
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("phone binder","server onBind");
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("phone binder","server onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.d("phone binder","server onDestroy");
        super.onDestroy();
    }
}

3.客户端

[->MainActivity.java]

package com.skytoby.client;

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.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;
import com.skytoby.server.IRemoteService;

public class MainActivity extends AppCompatActivity {
    private TextView mTextMessage;
    private IRemoteService mService;
    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_home:
                    mTextMessage.setText(R.string.title_home);
                    bindService();
                    return true;
                case R.id.navigation_dashboard:
                    mTextMessage.setText(R.string.title_dashboard);
                    unbindService();
                    return true;
                case R.id.navigation_notifications:
                    mTextMessage.setText(R.string.title_notifications);
                    killService();
                    return true;
            }
            return false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        mTextMessage = findViewById(R.id.message);
        navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
        Log.d("phone binder","onCreate");

    }

    void bindService(){
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.skytoby.server","com.skytoby.server.PhoneService"));
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    void unbindService(){
        if(mService!=null){
            unbindService(connection);
        }
    }

    void killService(){
        try {
            if(mService!=null){
                android.os.Process.killProcess(mService.getPid());
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("phone binder","onServiceConnected");
            try {
                //获取代理
                mService = IRemoteService.Stub.asInterface(service);
                Log.d("phone binder","client getphone:"+mService.getPhone("apple"));
                mService.addPhone("apple");
                Log.d("phone binder","client getphone:"+mService.getPhone("apple"));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("binder","onServiceDisconnected");
            mService =  null;
        }
    };

}

4.运行结果

深入理解Binder机制1-AIDL原理_第1张图片

点击客户端相应的控件,完成绑定服务,解绑服务,杀死service进程,日志如下:

16:09:10.394 27006-27006/com.skytoby.server D/phone binder: server onCreate
16:09:10.395 27006-27006/com.skytoby.server D/phone binder: server onBind
16:09:10.405 27006-27018/com.skytoby.server D/phone binder: server get phone:apple
16:09:10.407 27006-27018/com.skytoby.server D/phone binder: server add phone:apple
16:09:10.409 27006-27018/com.skytoby.server D/phone binder: server get phone:apple
16:16:55.497 27006-27006/com.skytoby.server D/phone binder: server onUnbind
16:16:55.502 27006-27006/com.skytoby.server D/phone binder: server onDestroy
16:16:57.955 27006-27020/com.skytoby.server D/phone binder: server getPid 27006

二、AIDL原理分析

1. IRemoteService类

aidl生成一个对应的IRemoteService.java,其原理还是利用了framework binder的架构,具体的内部原理后面介绍,先分析下这个生成类,其流程如下:

深入理解Binder机制1-AIDL原理_第2张图片

  • AIDL接口:继承IInterface。

  • Stub类:Binder的实现类,服务端通过这个类来提供服务。

  • Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。

  • asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。返回对象:

​ 1.若客户端和服务端位于同一进程,则直接返回Stub对象本身;

​ 2.否则,返回的是系统封装后的Stub.proxy对象。

  • asBinder():根据当前调用情况返回代理Proxy的Binder对象。

  • onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。

  • transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: G:\\Android studio\\Aidl\\client\\src\\main\\aidl\\com\\skytoby\\server\\IRemoteService.aidl
 */
package com.skytoby.server;

public interface IRemoteService extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.skytoby.server.IRemoteService {
        private static final java.lang.String DESCRIPTOR = "com.skytoby.server.IRemoteService";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.skytoby.server.IRemoteService interface,
         * generating a proxy if needed.
         */
        public static com.skytoby.server.IRemoteService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.skytoby.server.IRemoteService))) {
                return ((com.skytoby.server.IRemoteService) iin);
            }
            return new com.skytoby.server.IRemoteService.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_addPhone: {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.addPhone(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getPhone: {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    boolean _result = this.getPhone(_arg0);
                    reply.writeNoException();
                    reply.writeInt(((_result) ? (1) : (0)));
                    return true;
                }
                case TRANSACTION_getPid: {
                    data.enforceInterface(descriptor);
                    int _result = this.getPid();
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.skytoby.server.IRemoteService {
            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 addPhone(java.lang.String name) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    mRemote.transact(Stub.TRANSACTION_addPhone, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public boolean getPhone(java.lang.String name) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                boolean _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(name);
                    mRemote.transact(Stub.TRANSACTION_getPhone, _data, _reply, 0);
                    _reply.readException();
                    _result = (0 != _reply.readInt());
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public int getPid() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_addPhone = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPhone = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    }

    public void addPhone(java.lang.String name) throws android.os.RemoteException;

    public boolean getPhone(java.lang.String name) throws android.os.RemoteException;

    public int getPid() throws android.os.RemoteException;
}

2. 原理

对于应用层来说bindService之后就可以和服务端进行交互了,可以不用里面具体的操作如何,这样的设计大大降低了使用了难度,对于binderService的具体的过程将在后面分析,下面是其分层次的调用图。
深入理解Binder机制1-AIDL原理_第3张图片

你可能感兴趣的:(Android进阶)