Android Binder机制完全解析

概述

之前我写过一篇文章Android Service全面解析,简单实现了如何通过AIDL实现Service的跨进程通信(IPC),其实是通过Binder机制来实现的,本文我们就重点来看看Binder机制的原理。

Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的,下面我们简单看一下Android的Binder的框架:

Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务,那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。

  • 服务器接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。
  • Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。
  • 客户端接口:获得Binder驱动,调用其transact()发送消息至服务器。

实例实现

如果你觉得上面的描述太抽象了,没关系,下面我们通过一个具体的例子来看看Binder机制的原理。例子我仍然使用上一篇文章的例子,不过之前我是使用Eclipse创建工程,今天我们使用Studio来创建项目,效果都是一样的。

(1)Studio创建两个Module,app代表客户端程序,binder_server代表服务器端程序。

(2)创建aidl文件

在app目录上右键,NEW->AIDL->AIDL File,创建一个aidl文件(IMyAidlInterface.aidl),同时必须要指明包名,包名必须和java目录下的包名一致。此aidl文件会默认生成到aidl目录下,aidl目录和java目录同级别。

IMyAidlInterface.aidl文件内容:

interface IMyAidlInterface {
    int plus(int a, int b);
    String toUpperCase(String str);
}

build一下,会自动生成IMyAidlInterface.java文件,不同于Eclipse的gen目录,studio下的java文件目录为:

*(项目名)\app\build\generated\source\aidl\debug\com\hx\binder\IMyAidlInterface.java

关于IMyAidlInterface.java文件内容,我们后面会具体分析,这里先省略。

(3)将aidl文件连同目录一起拷贝到服务器端

(4)服务器端新建服务MyRemoteService

public class MyRemoteService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        MainActivity.showlog("onCreate()");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MainActivity.showlog("onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        MainActivity.showlog("onDestroy()");
    }

    @Override
    public IBinder onBind(Intent intent) {
        MainActivity.showlog("onBind()");
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        MainActivity.showlog("onUnbind()");
        return super.onUnbind(intent);
    }

    IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
        @Override
        public String toUpperCase(String str) throws RemoteException {
            if (str != null) {
                return str.toUpperCase();
            }
            return null;
        }

        @Override
        public int plus(int a, int b) throws RemoteException {
            return a + b;
        }
    };
}

在Manifest中进行注册:

<service android:name=".MyRemoteService"
         android:exported="true">
     <intent-filter>
           <action android:name="com.hx.action.remoteService" />
     </intent-filter>
</service>

(4)编写客户端代码

public class MainActivity extends Activity implements View.OnClickListener {

    private Button bindService;
    private Button unbindService;
    private Button plus;
    private Button toUpperCase;
    private IMyAidlInterface myAIDLInterface;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAIDLInterface = null;
            Toast.makeText(MainActivity.this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAIDLInterface = IMyAidlInterface.Stub.asInterface(service);
            Toast.makeText(MainActivity.this, "onServiceConnected", Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        plus = (Button) findViewById(R.id.plus);
        toUpperCase = (Button) findViewById(R.id.toUpperCase);
        //button点击事件
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
        plus.setOnClickListener(this);
        toUpperCase.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bind_service:
                Intent intent = new Intent("com.hx.action.remoteService");
                //5.0以上安卓设备,service intent必须为显式指出
                Intent eintent = new Intent(getExplicitIntent(this,intent));
                bindService(eintent, connection, Context.BIND_AUTO_CREATE);
//              bindService(intent, connection, BIND_AUTO_CREATE);
                break;
            case R.id.unbind_service:
                if(myAIDLInterface != null){
                    unbindService(connection);
                }
                break;
            case R.id.plus:
                if (myAIDLInterface != null) {
                    try {
                        int result = myAIDLInterface.plus(13, 19);
                        Toast.makeText(this, result + "", Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.toUpperCase:
                if (myAIDLInterface != null) {
                    try {
                        String upperStr = myAIDLInterface.toUpperCase("hello aidl service");
                        Toast.makeText(this, upperStr + "", Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

    public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical">

    <Button
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="bind service" />

    <Button
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind service" />

    <Button
        android:id="@+id/plus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="13 + 19" />

    <Button
        android:id="@+id/toUpperCase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="hello aidl service" />
</LinearLayout>

运行程序,看效果:

我们首先点击BIND SERVICE按钮,绑定服务,会弹出“onServiceConnected”的Toast,说明服务绑定成功,获取到了服务器端的Binder驱动。

服务端Log:

然后分别点击13+19和hello aidl service按钮,可以通过Binder驱动调用服务端的代码并返回正确的计算结果。

最后点击UNBIND SERVICE按钮,我们的期望是弹出“onServiceDisconnected”的Toast,解除绑定,实际上呢?很遗憾没有弹出。

服务端Log:

由于我们当前只有一个客户端绑定了此Service,所以Service调用了onUnbind和onDestory。当我们继续点击13+19按钮,发现依然可以正确执行得到结果,也就是说即使onUnbind被调用,连接也是不会断开的,那么什么时候会断开连接呢?

即当服务端被异常终止的时候,比如我们现在在手机的正在执行的程序中找到该服务,并强行停止它:

可以看到这时弹出了“onServiceDisconnected”的Toast,说明连接被断开。之后再次点击13+19按钮,则会弹出Toast提示“服务器被异常杀死,请重新绑定服务端”。

原理分析

还记得我们上面根据aidl文件生成的Java文件吗?我们来看看它的结构吧:

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

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

        /**
         * Cast an IBinder object into an com.hx.binder.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.hx.binder.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.hx.binder.IMyAidlInterface))) {
                return ((com.hx.binder.IMyAidlInterface) iin);
            }
            return new com.hx.binder.IMyAidlInterface.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_plus: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.plus(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_toUpperCase: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = this.toUpperCase(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.hx.binder.IMyAidlInterface {
            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 int plus(int a, int b) 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);
                    _data.writeInt(a);
                    _data.writeInt(b);
                    mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(str);
                    mRemote.transact(Stub.TRANSACTION_toUpperCase, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_plus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_toUpperCase = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public int plus(int a, int b) throws android.os.RemoteException;

    public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException;
}

代码比较长,但思路还是比较清晰的,IMyAidlInterface.java文件包含两个静态内部类—Stub和Proxy(其中Proxy是Stub的内部类)。

public static abstract class Stub extends android.os.Binder implements com.hx.binder.IMyAidlInterface

其中Stub是个抽象类,它继承了Binder,并实现了IMyAidlInterface接口。Stub提供了几个方法:asInterface、asBinder、onTransact,但并没有实现IMyAidlInterface接口的方法,所以需要交给Stub的实现类去实现。

private static class Proxy implements com.hx.binder.IMyAidlInterface

Proxy是Stub的内部类,也实现了IMyAidlInterface接口。并提供了几个方法:asBinder、getInterfaceDescriptor,并实现了IMyAidlInterface接口的方法plus和toUpperCase。

接下来看看服务端和客户端是如何和这个文件建立关联的吧。

服务端:

IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
        @Override
        public String toUpperCase(String str) throws RemoteException {
            if (str != null) {
                return str.toUpperCase();
            }
            return null;
        }

        @Override
        public int plus(int a, int b) throws RemoteException {
            return a + b;
        }
    };

可以看到我们服务端提供的服务是由IMyAidlInterface.Stub来执行的,上面分析过,Stub这个类是Binder的子类,是不是符合我们文章开头所说的服务端其实是一个Binder类的实例。而且mBinder实现了IMyAidlInterface接口的方法。

接下来看Stub的onTransact()方法:

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_plus: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.plus(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_toUpperCase: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = this.toUpperCase(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。

可以看到onTransact有四个参数:code , data ,replay , flags

  • code:是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法
  • data:客户端传递过来的参数
  • reply:服务器返回回去的值
  • flags:标明是否有返回值,0为有(双向),1为没有(单向)

我们仔细看case TRANSACTION_plus中的代码:

data.enforceInterface(DESCRIPTOR); 

与客户端的writeInterfaceToken对应,标识远程服务的名称

int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();

接下来分别读取了客户端传入的两个参数

int _result = this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);

然后执行this.plus,即我们服务端实现的plus方法;返回result由reply写回。

toUpperCase同理,可以看到服务端通过AIDL生成的Stub类,封装了服务端本来需要写的代码。

客户端

客户端主要通过ServiceConnected与服务端连接

private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            isConnected = false;
            Toast.makeText(MainActivity.this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnected = true;
            myAIDLInterface = IMyAidlInterface.Stub.asInterface(service);
            Toast.makeText(MainActivity.this, "onServiceConnected", Toast.LENGTH_SHORT).show();
        }
    };

其实这个onServiceConnected中的IBinder实例,其实就是我们文章开头所说的Binder驱动,也是一个Binder实例。

在IMyAidlInterface.Stub.asInterface中最终调用了:

return new com.hx.binder.IMyAidlInterface.Stub.Proxy(obj);

这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码。

直接看Proxy中的plus方法

            public int plus(int a, int b) 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);
                    _data.writeInt(a);
                    _data.writeInt(b);
                    mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据

_data.writeInterfaceToken(DESCRIPTOR);

与服务器端的enforceInterfac对应

_data.writeInt(a);
_data.writeInt(b);

写入需要传递的参数

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

终于看到了我们的transact方法,第一个对应服务端的code,_data,_reply分别对应服务端的data,reply,0表示是双向的

_reply.readException();
_result = _reply.readInt();

最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。

到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。

AIDL其实通过我们写的aidl文件,帮助我们生成了一个接口,一个Stub类用于服务端,一个Proxy类用于客户端调用。

不依赖AIDL实现IPC通信

那么我们是否可以不通过写aidl文件来实现远程的通信呢?下面向大家展示如何完全不依赖AIDL来实现客户端与服务端的通信。

服务端代码:

public class MyRemoteService extends Service {
    private static final String DESCRIPTOR = "MyRemoteService";
    private static final int TRANSACTION_plus = 0x110;
    private static final int TRANSACTION_toUpperCase = 0x111;

    @Override
    public void onCreate() {
        super.onCreate();
        MainActivity.showlog("onCreate()");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MainActivity.showlog("onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        MainActivity.showlog("onDestroy()");
    }

    @Override
    public IBinder onBind(Intent intent) {
        MainActivity.showlog("onBind()");
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        MainActivity.showlog("onUnbind()");
        return super.onUnbind(intent);
    }

    private MyBinder mBinder = new MyBinder();
    private class MyBinder extends Binder {
        @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_plus: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = _arg0 + _arg1;
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_toUpperCase: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = _arg0.toUpperCase();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

    };
}
<service android:name=".MyRemoteService"
         android:exported="true">
      <intent-filter>
           <action android:name="com.hx.action.remoteService" />
      </intent-filter>
</service>

客户端代码:

public class MainActivity extends Activity implements View.OnClickListener {
    private Button bindService;
    private Button unbindService;
    private Button plus;
    private Button toUpperCase;
    private IBinder myBinder;

    private static final String DESCRIPTOR = "MyRemoteService";
    private static final int TRANSACTION_plus = 0x110;
    private static final int TRANSACTION_toUpperCase = 0x111;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            myBinder = null;
            Toast.makeText(MainActivity.this, "onServiceDisconnected", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = service;
            Toast.makeText(MainActivity.this, "onServiceConnected", Toast.LENGTH_SHORT).show();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        plus = (Button) findViewById(R.id.plus);
        toUpperCase = (Button) findViewById(R.id.toUpperCase);
        //button点击事件
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
        plus.setOnClickListener(this);
        toUpperCase.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bind_service:
                Intent intent = new Intent("com.hx.action.remoteService");
                //5.0以上安卓设备,service intent必须为显式指出
                Intent eintent = new Intent(getExplicitIntent(this,intent));
                bindService(eintent, connection, Context.BIND_AUTO_CREATE);
//              bindService(intent, connection, BIND_AUTO_CREATE);
                break;
            case R.id.unbind_service:
                if(myBinder != null){
                    unbindService(connection);
                }
                break;
            case R.id.plus:
                if (myBinder != null) {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(78);
                        _data.writeInt(95);
                        myBinder.transact(TRANSACTION_plus, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                        Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                } else {
                    Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.toUpperCase:
                if (myBinder != null) {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    java.lang.String _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeString("my new programe");
                        myBinder.transact(TRANSACTION_toUpperCase, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readString();
                        Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                } else {
                    Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

    public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical">

    <Button
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="bind service" />

    <Button
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind service" />

    <Button
        android:id="@+id/plus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="78 + 95" />

    <Button
        android:id="@+id/toUpperCase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="my new programe" />
</LinearLayout>

这里我们并没有写aidl文件,而是将aidl生成的java文件的处理逻辑移动到我们的服务端和客户端来实现。同样会达到和上面一样的效果。

IPC传递自定义Bean

时间: 2024-10-12 04:19:59

Android Binder机制完全解析的相关文章

Android Binder机制分析(5) Binder_ioctl()分析

引言 在博客Android Binder机制(3)本地服务注册过程这篇博客中我们详细讲解了本地服务的注册过程,除了一个地方之外,那就是IPCThreadState::waitForResponse()方法中的talkWithDriver(),而在talkWithDriver()中调用了binder_ioctl(),由于内容太多,所以专门写一篇博客进行分析. 实际上,不只是在服务注册过程中会调用到Binder Driver中的binder_ioctl(),在服务检索.服务使用阶段都会调用到bind

android binder 机制二(client和普通server)

在讲它们之间的通信之前,我们先以MediaServer为例看看普通Server进程都在干些什么. int main() { -- // 获得ProcessState实例 sp<ProcessState> proc(ProcessState::self()); // 得到ServiceManager的Binder客户端实例 sp<IServiceManager> sm = defaultServiceManager(); -- // 通过ServiceManager的Binder客户

【转】Android - Binder机制

以下几篇文章是较深入分析binder机制. 目录 1. Android - Binder机制 - ServiceManager 2. Android - Binder机制 - 普通service注册 3. Android - Binder机制 - 获得普通service 4. Android - Binder机制 - client和普通service交互 5. Android - Binder机制 - Binder框架总结 6. Android - Binder机制 - ProcessState

Android动画机制全解析

导论 本文着重讲解Android3.0后推出的属性动画框架Property Animation--Animator. 产生原因 3.0之前已有的动画框架--Animation存在一些局限性, Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApp

Android Binder机制(3) 本地服务注册过程

本博客将讲解本地服务的注册过程,为了方便大家更好地理解,选择了MediaPlayer Service作为例子. 启动并注册MediaPlayer Service的代码在frameworks/base/media/mediaserver/main_mediaserver.cpp中,如下: main_mediaserver.cpp 1 2 3 4 5 6 7 8 9 10 11 12 int main(int argc, char** argv) { sp<ProcessState>proc(Pr

Android Binder机制(2) ContextManager注册过程分析

引言 Context Manager对应的进程为servicemanager,它先于Service Server与服务客户端运行,首先进入接收IPC数据的状态,处理来自Service Server或服务客户端的请求.在init.rc脚本文件中也可以看到Context Manager在mediaserver与system_server之前运行了. 每当Service Server注册服务时,Context Manager都会把服务的名称与Binder节点编号注册到自身的服务目录中,该服务目录通过根

android binder 机制 (ServiceManager)

Binder机制作为一种IPC通信机制,在android系统中扮演了非常重要的角色,因此我也花了一些时间来研究它,按照我的理解,下面我将从4个方面来讲一下Binder,如有不对的地方,还希望大家多多指教.下面的例子都将以MediaServer来讲. 一.ServiceManager ServiceManager在Binder系统中相当与DNS,Server会先在这里注册,然后Client会在这里查询服务以获得与Service所在的Server进程建立通信的通路. 在与ServiceManager

android Binder机制原理

Android Binder机制原理(史上最强理解,没有之一)(转) 原文地址: http://blog.csdn.net/universus/article/details/6211589 Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe).信号(Signal)和跟踪(Trace).插口(Socket).报文队列(Message).共享内存(Share Memo

浅谈android binder机制

binder机制 是谷歌优化在android上更适合终端的IPC(多进程通信方式),满足系统对通信方式,传输性能和安全性的要求. 特性: 1. 用驱动程序来推进进程间的通信.2. 通过共享内存来提高性能.3. 进程间同步调用以及异步调用 ........................................... IADL是用binder机制进行IPC的典型代表 IADL是一个接口描述文件,规定IPC通信的接口,一般使用于client/server模式 c/s双方写好IADL后,系统会