脚本之家

电脑版
提示:原网页已由神马搜索转码, 内容由www.jb51.net提供.
您的位置:首页软件编程Android→ Android binder 匿名服务

Android binder 匿名服务实现双向通信的解决方案

  更新时间:2024年04月27日 09:37:50  作者:Kbattery 
这篇文章主要介绍了Android binder 匿名服务实现双向通信的解决方案,当然,这种方案是可行的,只是需要client和server都向servicemanager注册一个服务,实现起来有点麻烦,不太建议这么做,需要的朋友可以参考下

在binder 用户空间通信模型中,涉及client,server和servicemanager进程。一般来说,都是server注册服务到servicemanager中,client从servicemanager中获取服务,然后由client发起,使用服务中的方法。server都是被动的接收client发起的请求。那如果server想主动的发起请求调用client中的方法,应该怎么做呢?
实现上面的需求,首先可以想到的是,client也向servicemanager注册一个服务,server中从servicemanager获取服务,这样client就变成了服务端,server就变成了客户端,不就可以实现吗?
当然,这种方案是可行的,只是需要client和server都向servicemanager注册一个服务,实现起来有点麻烦,不太建议这么做。完全可以使用匿名服务来实现双向通信的需求
1,背景知识
在注册服务时,通过调用Parcel的writeStrongBinder,会构造一个flat_binder_obj结构体,其中的type为BINDER_TYPE_BINDER,binder驱动对于type是BINDER_TYPE_BINDER,则会生成一个binder_node,并为servicemanager创建binder_ref,而且还会将这个flat_binder_obj的type改为BINDER_TYPE_HANDLE,将binder_ref中的desc存入flat_binder_obj的handle,传给servicemanager,在servicemanager中记录其信息。这个过程就是binder实名服务的注册过程。

2,匿名服务是什么?
binder_node代表一个服务的实体。了解了上面的背景知识后知道writeStrongBinder会导致在驱动中创建一个binder_node,那么我们可不可以直接在client和server通信的过程中,调用writeStrongBinder,而不需要通过添加服务在servicemanager中记录这个服务的信息呢?答案是可以的,这就是匿名服务。匿名服务需要依赖于server已经注册好的实名服务

3,匿名服务在系统源码中的使用
应用进程和wms进行通信,通常是借助于一个IWindowSession对象。我们来看一下其构造过程

@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
IWindowManager windowManager = getWindowManagerService();//1
sWindowSession = windowManager.openSession( //2
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}

注释1处获取一个IWindowManager.Stub.Proxy对象,不在本分分析的重点。注释2处通过调用openSession获取一个IWindowSession对象。

@Override public android.view.IWindowSession openSession(android.view.IWindowSessionCallback callback, com.android.internal.view.IInputMethodClient client, com.android.internal.view.IInputContext inputContext) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.view.IWindowSession _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((callback!=null))?(callback.asBinder()):(null)));
_data.writeStrongBinder((((client!=null))?(client.asBinder()):(null)));
_data.writeStrongBinder((((inputContext!=null))?(inputContext.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_openSession, _data, _reply, 0);//1
_reply.readException();
_result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());//2
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}

可以看出,注释1处发起远程调用,然后注释2处从_reply中取出数据,转化之后返回。那我们来看看服务端的处理

case TRANSACTION_openSession:
{
data.enforceInterface(DESCRIPTOR);
android.view.IWindowSessionCallback _arg0;
_arg0 = android.view.IWindowSessionCallback.Stub.asInterface(data.readStrongBinder());
com.android.internal.view.IInputMethodClient _arg1;
_arg1 = com.android.internal.view.IInputMethodClient.Stub.asInterface(data.readStrongBinder());
com.android.internal.view.IInputContext _arg2;
_arg2 = com.android.internal.view.IInputContext.Stub.asInterface(data.readStrongBinder());
android.view.IWindowSession _result = this.openSession(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));//1
return true;
}

注释1处也是调用writeStrongBinder,直接写给客户端。结合前面的背景知识,就知道这是一个binder匿名服务(并没有先向servicemanager获取)。匿名服务的实现也是通过writeStrongBinder来实现的,客户端通过readStrongBinder来取出binder驱动转化过后的flat_binder_obj,取出handle并存入BpBinder中

4,匿名服务双向通信实战

在我们的日常开发中,通常有这样的需求,服务端更新了某种状态需要实时的通知给客户端。那么我们就可以在客户端通过writeStrongBinder创建一个binder匿名服务供服务端使用。

1,在客户端和服务端新建一个用于服务端通知客户端的aidl文件,如:ICallBack.aidl。注意包名需要一致

// ICallBack.aidl
package com.test.testserver;
// Declare any non-default types here with import statements
interface ICallBack {
void onSucess(int code);
void onError();
}

2,在客户端和服务端本来的通信文件中(客户端发起和服务端通信的aidl文件),新增接口

// ITestInterface.aidl
package com.test.testserver;
import com.test.testserver.ICallBack;
// Declare any non-default types here with import statements
interface ITestInterface {
void registerCallBack(ICallBack callback);
}

3,客户端调用 registerCallBack

binder.registerCallBack(new ICallBack.Stub() {
@Override
public void onSucess(int code) throws RemoteException {
Log.d("test", "onSucess code: "+code);
}
@Override
public void onError() throws RemoteException {
Log.d("test", "onError: ");
}
});

4,服务端接收到之后,做自己的处理

@Override
public void registerCallBack(ICallBack callback) throws RemoteException {
this.callBack = callback;
}

我这里只是将客户端传过来的ICallBack 赋值给自己的callBack 对象

5,服务端需要通知时,调用ICallBack 中的方法

callBack.onError();
或者
callBack.onSucess(1);

最后我们来看看,内部实现是不是通过writeStrongBinder和readStrongBinder来实现
客户端发起调用:

@Override public void registerCallBack(com.test.testserver.ICallBack callback) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((callback!=null))?(callback.asBinder()):(null)));//1
boolean _status = mRemote.transact(Stub.TRANSACTION_registerCallBack, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().registerCallBack(callback);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}

注释1处可以看出是通过writeStrongBinder,构建一个匿名服务
服务端:

case TRANSACTION_registerCallBack:
{
data.enforceInterface(descriptor);
com.test.testserver.ICallBack _arg0;
_arg0 = com.test.testserver.ICallBack.Stub.asInterface(data.readStrongBinder());//1
this.registerCallBack(_arg0);
reply.writeNoException();
return true;
}

注释1处是通过readStrongBinder取出来并转化为ICallBack.Stub.proxy对象,用于和客户端通信

到此这篇关于Android binder 匿名服务实现双向通信的文章就介绍到这了,更多相关Android binder 匿名服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

    • 这篇文章主要介绍了Android TextView实现带链接文字事件监听的方法,结合实例形式分析了链接跳转、setMovementMethod及布局属性设置三种常用的实现方式,需要的朋友可以参考下
      2017-08-08
    • 这篇文章主要介绍了Android访问assets本地json文件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
      2017-10-10
    • 对于列表来说,如果想操作某个列表项,一般会采用长按弹出菜单的形式,默认的上下文菜单比较难看,而QQ的上下文菜单就人性化多了,整个菜单给用户一种气泡弹出的感觉,而且会显示在手指按下的位置,接下来通过本文给大家分享Android仿QQ长按删除弹出框功能,一起看看吧
      2017-03-03
    • 这篇文章主要为大家详细介绍了Android自定义控件实现通用验证码输入框的第二篇,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
      2021-01-01
    • 这篇文章主要介绍了Android实现RecyclerView添加分割线的简便方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
      2017-07-07
    • 在我遇到这个实际问题之前,我一直认为启动页的作用是美化产品,提升软件逼格。但实际上,它更重要的是起到了一个拦截器的作用,这篇文章主要介绍了Android启动页设置以及动态权限跳转,需要的朋友可以参考下
      2022-04-04
    • Json是一种类似于XML的通用数据交换格式,具有比XML更高的传输效率;本文将介绍两种方法解析JSON数据,需要的朋友可以参考下
      2012-12-12
    • 这篇文章主要介绍了Android闪屏效果实现方法,结合实例形式分析了Android闪屏效果的实现原理及相关功能与布局设置技巧,需要的朋友可以参考下
      2016-01-01
    • 本篇文章主要介绍了Android下拉刷新PtrFrameLayout的使用实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
      2017-06-06
    • 这篇文章主要给大家介绍了关于Kotlin类型系统的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Kotlin具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
      2019-09-09

    最新评论