ipc 理解


一、IPC 描述


ipc 就是跨进程通信。不同进程间为了安全 不能直接互相访问数据。需要通过IPC技术来实现,这里借用底层binder驱动来实现。
android  frameword 层哪些地方需要Binder 机制 呢?
四大组件的创建,运行, 交互,生命周期的管理, 都是通过IPC 来进行的。使用系统服务也是IPC通信的过程。




图片


二、aidl 描述


aidl是进程间通信 定义的语言 。每一个进程当中 都有一个aidl,例如A进程访问B进程,那么A,B两个进程都有相同AIDL对象。
每一个aidl 都包含两个部分:proxy stub.说白了 ,就是一个统一约定的接口。
其结构图如下。


Stub:


Proxy

 

在进程A访问进程B中,访问者 我们这里理解为客户端,被访问者 理解为服务端。
proxy 就是用来向服务端 发送请求的组件。
Stub   就是服务端 用来接收客户端的请求并处理的组件。



三、IPC通信流程 
    这里我以绑定一个Service远程服务来 分析。假如有进程A(activity) 和 B(Service),对应工程A 和 工程B.


假如如下aidl 接口是 工程A 和 工程B 共有的。


package com.braincol.aidl.service;
public interface RemoteWebPage extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.braincol.aidl.service.RemoteWebPage
    {
        private static final java.lang.String DESCRIPTOR = "com.braincol.aidl.service.RemoteWebPage";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.braincol.aidl.service.RemoteWebPage interface,
         * generating a proxy if needed.
         */
        public static com.braincol.aidl.service.RemoteWebPage asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.braincol.aidl.service.RemoteWebPage))) {
                return ((com.braincol.aidl.service.RemoteWebPage)iin);
            }
            return new com.braincol.aidl.service.RemoteWebPage.Stub.Proxy(obj);
        }
        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_getCurrentPageUrl:
            {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _result = this.getCurrentPageUrl();
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
        private static class Proxy implements com.braincol.aidl.service.RemoteWebPage
        {
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote)
            {
                mRemote = remote;
            }
            public android.os.IBinder asBinder()
            {
                return mRemote;
            }
            public java.lang.String getInterfaceDescriptor()
            {
                return DESCRIPTOR;
            }
            public java.lang.String getCurrentPageUrl() 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_getCurrentPageUrl, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_getCurrentPageUrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    public java.lang.String getCurrentPageUrl() throws android.os.RemoteException;
}



工程A:  

import com.ryg.sayhi.aidl.IMyService;  
import com.ryg.sayhi.aidl.Student;  
  
public class MainActivity extends Activity implements OnClickListener {  
  
    private static final String ACTION_BIND_SERVICE = "com.ryg.sayhi.MyService";  
    private IMyService mIMyService;  
  
    private ServiceConnection mServiceConnection = new ServiceConnection()  
    {  
        @Override  
        public void onServiceDisconnected(ComponentName name)  
        {  
            mIMyService = null;  
        }  
  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service)  
        {  
            //通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了  
            mIMyService = IMyService.Stub.asInterface(service);  
            try {  
                Student student = mIMyService.getStudent().get(0);  
                showDialog(student.toString());  
            } catch (RemoteException e) {  
                e.printStackTrace();  
            }  
  
        }  
    };  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Button button1 = (Button) findViewById(R.id.button1);  
        button1.setOnClickListener(new OnClickListener() {  
  
    @Override  
    public void onClick(View view) {  
        if (view.getId() == R.id.button1) {  
            Intent intentService = new Intent(ACTION_BIND_SERVICE);  
            intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
            MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);  
        }  
  
    }  
  
    public void showDialog(String message)  
    {  
        new AlertDialog.Builder(MainActivity.this)  
                .setTitle("scott")  
                .setMessage(message)  
                .setPositiveButton("确定", null)  
                .show();  
    }  
      
    @Override  
    protected void onDestroy() {  
        if (mIMyService != null) {  
            unbindService(mServiceConnection);  
        }  
        super.onDestroy();  
    }  
} 



工程B:

public class MyService extends Service  
{  
    private final static String TAG = "MyService";  
    private static final String PACKAGE_SAYHI = "com.example.test";  
  
    private NotificationManager mNotificationManager;  
    private boolean mCanRun = true;  
    private List<Student> mStudents = new ArrayList<Student>();  
      
    //这里实现了aidl中的抽象函数  
    private final IMyService.Stub mBinder = new IMyService.Stub() {  
  
        @Override  
        public List<Student> getStudent() throws RemoteException {  
            synchronized (mStudents) {  
                return mStudents;  
            }  
        }  
  
        @Override  
        public void addStudent(Student student) throws RemoteException {  
            synchronized (mStudents) {  
                if (!mStudents.contains(student)) {  
                    mStudents.add(student);  
                }  
            }  
        }  
  
        //在这里可以做权限认证,return false意味着客户端的调用就会失败,比如下面,只允许包名为com.example.test的客户端通过,  
        //其他apk将无法完成调用过程  
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)  
                throws RemoteException {  
            String packageName = null;  
            String[] packages = MyService.this.getPackageManager().  
                    getPackagesForUid(getCallingUid());  
            if (packages != null && packages.length > 0) {  
                packageName = packages[0];  
            }  
            Log.d(TAG, "onTransact: " + packageName);  
            if (!PACKAGE_SAYHI.equals(packageName)) {  
                return false;  
            }  
  
            return super.onTransact(code, data, reply, flags);  
        }  
  
    };  
  
    @Override  
    public void onCreate()  
    {  
        Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");  
        thr.start();  
  
        synchronized (mStudents) {  
            for (int i = 1; i < 6; i++) {  
                Student student = new Student();  
                student.name = "student#" + i;  
                student.age = i * 5;  
                mStudents.add(student);  
            }  
        }  
  
        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);  
        super.onCreate();  
    }  
  
    @Override  
    public IBinder onBind(Intent intent)  
    {  
        Log.d(TAG, String.format("on bind,intent = %s", intent.toString()));  
        displayNotificationMessage("服务已启动");  
        return mBinder;  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId)  
    {  
        return super.onStartCommand(intent, flags, startId);  
    }  
  
    @Override  
    public void onDestroy()  
    {  
        mCanRun = false;  
        super.onDestroy();  
    }  
  
    private void displayNotificationMessage(String message)  
    {  
        Notification notification = new Notification(R.drawable.icon, message,  
                System.currentTimeMillis());  
        notification.flags = Notification.FLAG_AUTO_CANCEL;  
        notification.defaults |= Notification.DEFAULT_ALL;  
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,  
                new Intent(this, MyActivity.class), 0);  
        notification.setLatestEventInfo(this, "我的通知", message,  
                contentIntent);  
        mNotificationManager.notify(R.id.app_notification_id + 1, notification);  
    }  
  
    class ServiceWorker implements Runnable  
    {  
        long counter = 0;  
  
        @Override  
        public void run()  
        {  
            // do background processing here.....  
            while (mCanRun)  
            {  
                Log.d("scott", "" + counter);  
                counter++;  
                try  
                {  
                    Thread.sleep(2000);  
                } catch (InterruptedException e)  
                {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
  
}

 通过以上两个工程 来理解 跨进程 通信,流程理解如下 。


1:创建 A 进程 和 B进程 的 aidl 对象。

      通过IPC  绑定 (bind)B进程服务时(Service), Service 被创建出来,同时B 进程(Service)的aidl 对象也创建出来。

     B 进程创建aidl 对象:

     注意这是个普通的成员变量,当Service对象被创建出来后,这个mBinder 也会被创建出来。

     或者 在 onCreate 生命周期方法中 实例化 这个aidl对象。

private final IMyService.Stub mBinder = new IMyService.Stub() {  
  
        @Override  
        public List<Student> getStudent() throws RemoteException {  
            synchronized (mStudents) {  
                return mStudents;  
            }  
        }  
  
        @Override  
        public void addStudent(Student student) throws RemoteException {  
            synchronized (mStudents) {  
                if (!mStudents.contains(student)) {  
                    mStudents.add(student);  
                }  
            }  
        }


绑定完远程服务后,(A进程)activity 中的onServiceConnected () 方法被回调, 这里返回一个远程 服务的IBinder 引用。

我们用这个ibinder 引用来初始化本进程的aidl  对象。

   (也就是 初始化 A进程的 aidl对象)
 如下: 
 mIMyService = IMyService.Stub.asInterface(service); 

 @Override    
        public void onServiceConnected(ComponentName name, IBinder service)    
        {    
            //通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了    
            mIMyService = IMyService.Stub.asInterface(service);    
            try {    
                Student student = mIMyService.getStudent().get(0);    
                showDialog(student.toString());    
            } catch (RemoteException e) {    
                e.printStackTrace();    
            }    
    
        }    






2: 在activity 中(A 进程) 调用aidl对象的 方法 和 远程服务通信。

        mIMyService.getStudent()。

    这里的mIMyService 就是 Proxy 对象,当调用getStudent 方法时, 如下:

public java.lang.String getStudent() 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_getCurrentPageUrl, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

注意这里 有个 
  _result = _reply.readString();

用来 读取 远程服务端 的 数据。而不是等待return 回来。


3:  远程服务(B进程) 会被底层驱动 调用,并执行其aidl 中 Stub  的  onTransact  方法

   

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws RemoteException
        {
            switch (code)
         
            case TRANSACTION_getCurrentPageUrl:
            {
                data.enforceInterface(DESCRIPTOR);
                java.lang.String _result = this.getCurrentPageUrl();
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }

在onTransact  方法中根据A进程 中传来的方法ID 来匹配到 相应  的 方法,并调用本进程的实现,

java.lang.String _result = this.getCurrentPageUrl();
                调用完毕后将结果  写入 底层。

reply.writeNoException();
                reply.writeString(_result);

                A 进程 会接收到。

 通信 到此完毕. 






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值