前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[032]Binder远程转本地

[032]Binder远程转本地

作者头像
王小二
发布2020-06-08 12:01:39
4330
发布2020-06-08 12:01:39
举报

前言

[031]Binder线程栈复用中,我们说到Binder驱动通过“线程栈复用”减少线程数,我们来讲一讲另外一个机制“远程转本地”,将远程Binder调用转化成本地方法调用。

一、写个Demo

代码语言:javascript
复制
interface  IServiceB {
    void sendMsg(String msg);
}

1.1 Client端

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获得Service B的服务
        Intent intent = new Intent(this, ServerB.class);
        this.bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.v("KobeWang", "serviceB:" + service);
                IServiceB serviceB = IServiceB.Stub.asInterface(service);
                try {
                    serviceB.sendMsg("hello ServiceB");
                } catch (RemoteException re) {

                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }, Context.BIND_AUTO_CREATE);
    }
}

1.2 Server端

代码语言:javascript
复制
public class ServerB extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return new ServiceB();
    }

    public class ServiceB extends IServiceB.Stub {
        @Override
        public void sendMsg(String msg) throws RemoteException {
            Log.v("KobeWang", "get msg : "  + msg);
        }
    }
}

注意android:process=":server"这个代码,后面要删除对比测试

代码语言:javascript
复制
<service
  android:name=".ServerB"
  android:exported="true"
  android:process=":server"></service>

二、运行结果

2.1 android:process=":server"

此时ServiceB(pid=7120)和Client端(pid=7073)运行在不同进程

Client端拿到的service是ServiceB的远程代理类BinderProxy

ServiceB响应发生pid=7120进程,响应代码也是从Binder驱动中execTransact触发的。

代码语言:javascript
复制
//Client端从Binder驱动中拿到的service是ServiceB的远程代理类BinderProxy
7073  7073 V KobeWang: serviceB:android.os.BinderProxy@4ae510
//ServiceB中响应在另一个进程
7120  7142 V KobeWang: get msg : hello ServiceB
//ServiceB中响应代码堆栈也是从Binder.execTransact开始,Binder驱动触发
7120  7142 V KobeWang: java.lang.Exception: KobeWang
7120  7142 V KobeWang:  at com.kobe.binderlock.ServerB$ServiceB.sendMsg(ServerB.java:20)
7120  7142 V KobeWang:  at com.kobe.binderlock.IServiceB$Stub.onTransact(IServiceB.java:61)
7120  7142 V KobeWang:  at android.os.Binder.execTransactInternal(Binder.java:1035)
7120  7142 V KobeWang:  at android.os.Binder.execTransact(Binder.java:1008)

2.2 删除android:process=":server"之后

此时ServiceB和Client端运行在同一进程(pid=7384)

Client端拿到的service直接是ServiceB的这个类(继承Binder)

响应代码堆栈就像是直接调用ServiceB的sendMsg方法。

代码语言:javascript
复制
//Client端从Binder驱动中拿到的service就是ServiceB的这个类
7384  7384 V KobeWang: serviceB:com.kobe.binderlock.ServerB$ServiceB@1778355
//ServiceB中响应在同一个进程的同一线程
7384  7384 V KobeWang: get msg : hello ServiceB
//ServiceB中响应代码堆栈好像是直接调用ServiceB的sendMsg的方法。
7384  7384 V KobeWang: java.lang.Exception: KobeWang
7384  7384 V KobeWang:  at com.kobe.binderlock.ServerB$ServiceB.sendMsg(ServerB.java:20)
7384  7384 V KobeWang:  at com.kobe.binderlock.MainActivity$1.onServiceConnected(MainActivity.java:28)
7384  7384 V KobeWang:  at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1948)
7384  7384 V KobeWang:  at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1980)
7384  7384 V KobeWang:  at android.os.Handler.handleCallback(Handler.java:883)
7384  7384 V KobeWang:  at android.os.Handler.dispatchMessage(Handler.java:100)
7384  7384 V KobeWang:  at android.os.Looper.loop(Looper.java:214)
7384  7384 V KobeWang:  at android.app.ActivityThread.main(ActivityThread.java:7501)
7384  7384 V KobeWang:  at java.lang.reflect.Method.invoke(Native Method)
7384  7384 V KobeWang:  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
7384  7384 V KobeWang:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

三、总结

大家看明白了吧,这就是Binder远程转本地的机制,一个Binder对象同一个进程中拿到的是Binder对象本身,另一个进程中拿到的是BinderProxy代理类,跨进程调用也就变成了本地方法调用,提升Binder通信效率。

上面是两个进程,这个机制适用于多个进程传递同一个Binder对象。

进程A将Binder A通过Binder方法传递给进程B,进程B拿到的是BinderProxy A

进程B又将BinderProxy A通过Binder方法传递给进程C,进程C拿到的还是BinderProxy A

进程C将BinderProxy A通过Binder方法传递给进程A,进程A拿到的却是Binder A

记住一句话

一个IBinder对象(Binder或者BinderProxy)通过Binder方法传递的时候,Binder驱动就会校验远程转本地这个机制。如果发现这个IBinder对象的服务端(Binder)定义在本进程,就直接返回Binder对象,否则返回BinderProxy对象。

四、思考

AIDL oneway的这个标识符是不是在Binder远程转本地的时候,是不是也就失去了意思?

面试官问你:Binder服务端oneway方法sleep10秒,是否会导致client端sleep10秒?

你应该知道怎么回答了吧。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、写个Demo
    • 1.1 Client端
      • 1.2 Server端
      • 二、运行结果
        • 2.1 android:process=":server"
          • 2.2 删除android:process=":server"之后
          • 三、总结
            • 上面是两个进程,这个机制适用于多个进程传递同一个Binder对象。
            • 四、思考
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档