• 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的学习

  • 相关阅读:
    一条长为L的绳子,一面靠墙,另外三边组成矩形,问此矩形最大面积能是多少?
    幸运的背后,总是靠自身的努力在支撑
    ZT:没有谁的成功是横空出世
    Node.js abaike图片批量下载爬虫1.02
    Node.js nvshens图片批量下载爬虫1.01
    Node.js meitulu图片批量下载爬虫1.051
    JDBC学习再小结
    JDBC学习小结
    day06_JDBC学习笔记
    MySQL学习小结
  • 原文地址:https://www.cnblogs.com/zyljal/p/14909828.html
Copyright © 2020-2023  润新知