4.11Android学习

一、今日学习内容

模糊进程间调用

前边就是Binder的使用方式,但是至此还遗留了一个问题,我们的Service只有指定了新的进程名之后才会是远程调用,如果通过bindService 传递过来的IBinder对象是同进程的,那我们就不需要使用IBinder.transact进行内核通信了。我们知道同进程之间利用方法调用方式就可以做到通信。 我们在onServiceConnected打印IBinder类型,如果发现是远程调用,传给我们的 iBinder 是 BinderProxy 类型,BinderProxy是Binder的内部类一样实现了IBinder接口,他在native层会对应一个C++的BpBinder,BpBinder 最终会通过Binder驱动跟Server端通信。如果是本地调用,打印出的类型为Stub,说明本地调用时,onServiceConnected传过来的就是我们在Service的onBinde方法返回的Stub对象本身。基于这个原理,我们可以设计一个转换方法。

首先我们要怎么判断当前是远程调用还是同进程调用呢? 我们使用queryLocalInterface(DESCRIPTOR)方法,Binder中queryLocalInterface不会返回空,而在BinderProxy的实现中,queryLocalInterface返回为null。 Binder:

1
2
3
4
5
6
public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor != null && mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }

mOwner是attachInterface方法传进来的接口本身,后面还会出现这个方法。 BinderProxy:

1
2
3
public IInterface queryLocalInterface(String descriptor) {
        return null;
    }

当发现是远程调用时我们创建上边的Proxy来代理跨进程通信过程。要是本地调用我们直接返回本地Stub对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static IMyInterface asInterface(IBinder iBinder){
        if ((iBinder == null)) {
            return null;
        }
        //获取本地interface
        IInterface iin = iBinder.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof IMyInterface))) {
            //不为空,说明是本地调用,直接强转后返回。
            //IMyInterface封装了test0()、test1()两个方法,本地对象和Proxy都继承自接口
            return ((IMyInterface)iin );
        }
        //为null,远程调用,新建代理
        return new Proxy(iBinder);
    }

把上面相关代码完善之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
public interface IBinderTest extends android.os.IInterface {
    /**
     * 本地Stub对象
     */
    public static abstract class Stub extends android.os.Binder implements IBinderTest {
        private static final java.lang.String DESCRIPTOR = "com.XXX.XXXX.IBinderTest";
 
        public Stub() {
            //绑定DESCRIPTOR,并设置queryLocalInterface方法返回的mOwner
            this.attachInterface(this, DESCRIPTOR);
        }
 
        /**
         * 本地远程转换
         */
        public static IBinderTest asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof IBinderTest))) {
                return ((IBinderTest) iin);
            }
            return new IBinderTest.Stub.Proxy(obj);
        }
 
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }
 
        /**
         * 处理Client调用请求
         */
        @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_testVoidAidl: {
                    data.enforceInterface(descriptor);
                    this.testVoidAidl();
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_testStringAidl: {
                    data.enforceInterface(descriptor);
                    java.lang.String _result = this.testStringAidl();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }
 
        /**
         * 远程调用代理类
         */
        private static class Proxy implements IBinderTest {
            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 testVoidAidl() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_testVoidAidl, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
 
            @Override
            public java.lang.String testStringAidl() 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);
                    mRemote.transact(Stub.TRANSACTION_testStringAidl, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
 
        /**
         * 调用函数code
         */
        static final int TRANSACTION_testVoidAidl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_testStringAidl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
 
    public void testVoidAidl() throws android.os.RemoteException;
 
    public java.lang.String testStringAidl() throws android.os.RemoteException;
}

如果你用过AIDL并且看过AIDL生成的代码,你就会发现上面代码就是AIDL生成的。 换掉Service的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyService extends Service {
 
    private String TAG = "MyService";
 
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
 
    class MyBinder extends IBinderTest.Stub{
 
        @Override
        public void testVoidAidl() throws RemoteException {
            Log.d(TAG, "testVoidAidl");
        }
 
        @Override
        public String testStringAidl() throws RemoteException {
            Log.d(TAG, "testStringAidl");
            return "hello";
        }
    }
}

以上就是Binder的使用方法以及原理的简单介绍。

 

Binder原理

之前介绍了Binder的基本使用,接下来我们来看下Binder的底层原理。

(图片来源gityuan.com/2015/10/31/…),安卓的应用内存是隔离的,但是内核空间是共享的,我们要实现IPC就要靠共享的内核空间来交换数据。

Binder通信模型:

 

ioctl

Binder的通信原理:

由于用户空间的隔离机制(沙盒模式),所以我们要利用内核空间进行IPC操作,用户空间与内核空间的交互使用的是linux内核的ioctl函数,接下来简单了解一下ioctl的使用。 ioctl可以控制I/O设备 (驱动设备),提供了一种获得设备信息和向设备发送控制参数的手段。简单来说就是使用ioctl可以对驱动设备进行操作。由于我们IPC的过程中内核空间使用虚拟驱动设备/dev/binder控制通信过程,我们要跟这个Binder驱动设备交互就要使用ioctl命令。 简单介绍下,Linux要实现驱动设备的使用需要三个角色

  • 应用程序(调用方),使用ioctl来发送操作指令。
  • 驱动程序,用来处理ioctl传来的指令,并完成对驱动设备的操作。驱动程序被注册进内核之后,就会等待应用程序的调用。
  • 驱动设备,在Binder机制中,驱动设备是/dev/binder,这个文件被映射到每个系统Service的虚拟内存中(后边会讲到),驱动程序可以操作这个文件进行进程间数据交互。

下图是Linux中应用程序是怎么通过驱动来操作硬件设备的:

来个图来说一下应用层与驱动程序函数的ioctl之间的联系:

二、遇到的问题

 没办法有效的验证所学知识

三、明日计划

继续binder的学习

原文地址:https://www.cnblogs.com/zyljal/p/14909828.html