概述
- wayland server提供了由wayland协议文件定义的接口,client通过绑定这些接口后即可调用server的方法。
- 在使用google提供的wayland接口协议(
/wayland-protocols/unstable/remote-shell
)的时候,client完成对server资源的绑定后,调用remote_shell
的SetFrame
方法,调用完成后发现没有效果,并且在client发现与server的连接已经断开,通过调试手段发现server已经不再处理该client的方法调用以及surface_commit()
。
原因
wayland server对socket中的client数据的处理、方法调用的响应
- server在
src/wayland-server.c
中的方法 wl_client_connection_data()
对socket中client发过来的数据进行解析(反序列化)和处理。 - 在解析数据完成后,会调用客户端请求的方法。下面的
closure
就是即将调用的方法,通过invoke方法进行调用,原理是利用了ffi
库进行调用。
message = &object->interface->methods[opcode];
since = wl_message_get_since(message);
if (!(resource_flags & WL_MAP_ENTRY_LEGACY) &&
resource->version > 0 && resource->version < since) {
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid method %d (since %d < %d)"
", object %s@%u",
opcode, resource->version, since,
object->interface->name,
object->id);
break;
}
closure = wl_connection_demarshal(client->connection, size,
&client->objects, message);
if (closure == NULL && errno == ENOMEM) {
wl_resource_post_no_memory(resource);
break;
} else if (closure == NULL ||
wl_closure_lookup_objects(closure, &client->objects) < 0) {
wl_resource_post_error(client->display_resource,
WL_DISPLAY_ERROR_INVALID_METHOD,
"invalid arguments for %s@%u.%s",
object->interface->name,
object->id,
message->name);
wl_closure_destroy(closure);
break;
}
log_closure(resource, closure, false);
if ((resource_flags & WL_MAP_ENTRY_LEGACY) ||
resource->dispatcher == NULL) {
wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
object, opcode, client);
} else {
wl_closure_dispatch(closure, resource->dispatcher,
object, opcode);
}
wl_closure_destroy(closure);
- 调用失败的重点:在解析socket数据之前,会对client发过来的消息进行版本判断,如果检测到client的版本低于server要求的最低版本(即代码中的
since
),那么server就会通过wl_resource_post_error
来终止对该client的处理,并且会释放掉这个client相关的资源。故client会发现在调用一些方法后与server的连接会掉线,其原因就在于server认定版本不符合要求,主动断开了连接。
解决方案
临时解决-特别是快速调试和测试的时候
- 如果能修改server的代码,直接在上面这个文件(
wayland-server.c
)将起始版本(since
)修改为1,这样肯定不会被server认定版本不对而拒绝调用。强制调用会不会出问题就不知道了,反正在remote_shell``协议中强制调用它的
SetFrame```并不会出什么问题。
解决
- 将server和client的协议文件统一一下,并且重新生成接口和实现,统一版本。