1,所有LA侧的APP与显示相关的调用最终都会交由SurfaceFlinger处理
2,SurfaceFlinger会最终调用android.hardware.graphics.composer@2.4-service服务
3,android.hardware.graphics.composer@2.4-service服务会调用GPU&DRM&Qcom的一些列库文件(很遗憾这些库相当一大部分源码是不开源的)
4,libdrm库调用open/ioctl等函数会经过lib_drm_fe库的转接,当然lib_drm_fe会做很多其他适配的工作
5,lib_drm_fe会调用内核HGSL驱动中的hab通信接口与QNX侧的wfd_be服务进行通信
6,wfd_be服务会解析接收到的LA侧的数据包
7,根据数据包中的命令类型调用不同的openwfd接口,需要注意的是,这里的接口是做了一层转换的,举个例子wfdEnumerateDevices_Host,这个接口会进行转换之后真正调用wfdEnumerateDevices函数
8,所有的操作都执行完成之后,如果有必要会唤醒wfd_be的commit&vsync现场,通知openwfd刷新画面
lib_drm_fe会调用内核HGSL驱动中的hab通信接口与QNX侧的wfd_be服务进行通信
direwolf-vm.dtsi
msm_gpu_hyp: qcom,hgsl@0x3d00000 {
compatible = "qcom,hgsl";
reg = <0x3d00000 0x8>, <0x3d8f000 0x4>;
reg-names = "hgsl_reg_hwinf", "hgsl_reg_gmucx";
qcom,glb-db-senders = <&hgsl_tcsr_sender0
&hgsl_tcsr_sender1>;
qcom,glb-db-receivers = <&hgsl_tcsr_receiver0
&hgsl_tcsr_receiver1>;
};
static const struct of_device_id qcom_hgsl_of_match[] = {
{ .compatible = "qcom,hgsl" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_hgsl_of_match);
static struct platform_driver qcom_hgsl_driver = {
.probe = qcom_hgsl_probe,
.remove = qcom_hgsl_remove,
.driver = {
.name = "qcom-hgsl",
.of_match_table = qcom_hgsl_of_match,
},
};
module_platform_driver(qcom_hgsl_driver);
lagvm/LINUX/android/kernel/msm-5.4/drivers/soc/qcom/hgsl/hgsl.c
static int qcom_hgsl_probe(struct platform_device *pdev)
{
struct qcom_hgsl *hgsl_dev;
int ret;
int i;
hgsl_dev = devm_kzalloc(&pdev->dev, sizeof(*hgsl_dev), GFP_KERNEL);
if (!hgsl_dev)
return -ENOMEM;
hgsl_dev->dev = &pdev->dev;
ret = qcom_hgsl_register(pdev, hgsl_dev);
if (ret < 0) {
dev_err(&pdev->dev, "qcom_hgsl_register failed, ret %d\n",
ret);
return ret;
}
ret = hgsl_init_context(hgsl_dev);
if (ret < 0) {
dev_err(&pdev->dev, "hgsl_init_context failed, ret %d\n",
ret);
goto exit_dereg;
}
//创建hgsl-release-wq workqueue
ret = hgsl_init_release_wq(hgsl_dev);
if (ret < 0) {
dev_err(&pdev->dev, "hgsl_init_release_wq failed, ret %d\n",
ret);
goto exit_dereg;
}
hgsl_dev->db_off = hgsl_is_db_off(pdev);
idr_init(&hgsl_dev->isync_timeline_idr);
spin_lock_init(&hgsl_dev->isync_timeline_lock);
for (i = 0; i < MAX_DB_QUEUE; i++) {
mutex_init(&hgsl_dev->dbq[i].lock);
hgsl_dev->dbq[i].state = DB_STATE_Q_UNINIT;
}
if (!hgsl_dev->db_off)
hgsl_init_global_hyp_channel(hgsl_dev);
platform_set_drvdata(pdev, hgsl_dev);
return 0;
exit_dereg:
qcom_hgsl_deregister(pdev);
return ret;
}
?
static int qcom_hgsl_register(struct platform_device *pdev,
struct qcom_hgsl *hgsl_dev)
{
int ret;
ret = alloc_chrdev_region(&hgsl_dev->device_no, 0,
HGSL_DEV_NUM,
HGSL_DEVICE_NAME);
if (ret < 0) {
dev_err(&pdev->dev, "alloc_chrdev_region failed %d\n", ret);
return ret;
}
//创建一个hgsl class节点
hgsl_dev->driver_class = class_create(THIS_MODULE, HGSL_DEVICE_NAME);
if (IS_ERR(hgsl_dev->driver_class)) {
ret = -ENOMEM;
dev_err(&pdev->dev, "class_create failed %d\n", ret);
goto exit_unreg_chrdev_region;
}
//创建一个hgsl 设备
hgsl_dev->class_dev = device_create(hgsl_dev->driver_class,
NULL,
hgsl_dev->device_no,
hgsl_dev, HGSL_DEVICE_NAME);
if (IS_ERR(hgsl_dev->class_dev)) {
dev_err(&pdev->dev, "class_device_create failed %d\n", ret);
ret = -ENOMEM;
goto exit_destroy_class;
}
//注册hgsl 设备操作接口
cdev_init(&hgsl_dev->cdev, &hgsl_fops);
hgsl_dev->cdev.owner = THIS_MODULE;
//注册hgsl设备
ret = cdev_add(&hgsl_dev->cdev,
MKDEV(MAJOR(hgsl_dev->device_no), 0),
1);
if (ret < 0) {
dev_err(&pdev->dev, "cdev_add failed %d\n", ret);
goto exit_destroy_device;
}
ret = dma_coerce_mask_and_coherent(hgsl_dev->dev, DMA_BIT_MASK(64));
if (ret)
LOGW("Failed to set dma mask to 64 bits, ret = %d", ret);
return 0;
exit_destroy_device:
device_destroy(hgsl_dev->driver_class, hgsl_dev->device_no);
exit_destroy_class:
class_destroy(hgsl_dev->driver_class);
exit_unreg_chrdev_region:
unregister_chrdev_region(hgsl_dev->device_no, 1);
return ret;
}
?
static const struct file_operations hgsl_fops = {
.owner = THIS_MODULE,
.open = hgsl_open,
.release = hgsl_release,
.read = hgsl_read,
.unlocked_ioctl = hgsl_ioctl,
.compat_ioctl = hgsl_compat_ioctl
};
?
static int hgsl_open(struct inode *inodep, struct file *filep)
{
struct hgsl_priv *priv = hgsl_zalloc(sizeof(*priv));
struct qcom_hgsl *hgsl = container_of(inodep->i_cdev,
struct qcom_hgsl, cdev);
//获取当前进程的pid 和task_struct
struct pid *pid = task_tgid(current);
struct task_struct *task = pid_task(pid, PIDTYPE_PID);
int ret = 0;
if (!priv)
return -ENOMEM;
if (!task) {
ret = -EINVAL;
goto out;
}
INIT_LIST_HEAD(&priv->mem_mapped);
INIT_LIST_HEAD(&priv->mem_allocated);
mutex_init(&priv->lock);
priv->pid = task_pid_nr(task);
ret = hgsl_hyp_init(&priv->hyp_priv, hgsl->dev,
priv->pid, task->comm);
if (ret != 0)
goto out;
priv->dev = hgsl;
filep->private_data = priv;
out:
if (ret != 0)
kfree(priv);
return ret;
}
?
int hgsl_hyp_init(struct hgsl_hyp_priv_t *priv, struct device *dev,
int client_pid, const char * const client_name)
{
priv->dev = dev;
return hgsl_hyp_channel_pool_init(priv, client_pid, client_name);
}
//将task_struct 信息与hgsl_hyp_priv_t 绑定
static int hgsl_hyp_channel_pool_init(struct hgsl_hyp_priv_t *priv,
int client_pid, const char * const client_name)
{
INIT_LIST_HEAD(&priv->free_channels);
INIT_LIST_HEAD(&priv->busy_channels);
mutex_init(&priv->lock);
priv->conn_id = 0;
strlcpy(priv->client_name, client_name, sizeof(priv->client_name));
priv->client_pid = client_pid;
idr_init(&priv->channel_idr);
LOGD("pid %d, task name %s"
, (int) priv->client_pid, priv->client_name);
return 0;
}
static long hgsl_compat_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
return hgsl_ioctl(filep, cmd, arg);
}
static long hgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int ret;
switch (cmd) {
case HGSL_IOCTL_ISSUE_IB:
ret = hgsl_ioctl_issueib(filep, arg);
break;
case HGSL_IOCTL_CTXT_CREATE:
ret = hgsl_ioctl_ctxt_create(filep, arg);
break;
case HGSL_IOCTL_CTXT_DESTROY:
ret = hgsl_ioctl_ctxt_destroy(filep, arg);
break;
case HGSL_IOCTL_WAIT_TIMESTAMP:
ret = hgsl_ioctl_wait_timestamp(filep, arg);
break;
case HGSL_IOCTL_READ_TIMESTAMP:
ret = hgsl_ioctl_read_timestamp(filep, arg);
break;
case HGSL_IOCTL_CHECK_TIMESTAMP:
ret = hgsl_ioctl_check_timestamp(filep, arg);
break;
case HGSL_IOCTL_HYP_GENERIC_TRANSACTION:
ret = hgsl_ioctl_hyp_generic_transaction(filep, arg);
break;
case HGSL_IOCTL_GET_SHADOWTS_MEM:
ret = hgsl_ioctl_get_shadowts_mem(filep, arg);
break;
case HGSL_IOCTL_PUT_SHADOWTS_MEM:
ret = hgsl_ioctl_put_shadowts_mem(filep, arg);
break;
case HGSL_IOCTL_MEM_ALLOC:
ret = hgsl_ioctl_mem_alloc(filep, arg);
break;
case HGSL_IOCTL_MEM_FREE:
ret = hgsl_ioctl_mem_free(filep, arg);
break;
case HGSL_IOCTL_MEM_MAP_SMMU:
ret = hgsl_ioctl_mem_map_smmu(filep, arg);
break;
case HGSL_IOCTL_MEM_UNMAP_SMMU:
ret = hgsl_ioctl_mem_unmap_smmu(filep, arg);
break;
case HGSL_IOCTL_MEM_CACHE_OPERATION:
ret = hgsl_ioctl_mem_cache_operation(filep, arg);
break;
case HGSL_IOCTL_ISSUIB_WITH_ALLOC_LIST:
ret = hgsl_ioctl_issueib_with_alloc_list(filep, arg);
break;
case HGSL_IOCTL_GET_SYSTEM_TIME:
ret = hgsl_ioctl_get_system_time(filep, arg);
break;
case HGSL_IOCTL_SYNCOBJ_WAIT_MULTIPLE:
ret = hgsl_ioctl_syncobj_wait_multiple(filep, arg);
break;
case HGSL_IOCTL_PERFCOUNTER_SELECT:
ret = hgsl_ioctl_perfcounter_select(filep, arg);
break;
case HGSL_IOCTL_PERFCOUNTER_DESELECT:
ret = hgsl_ioctl_perfcounter_deselect(filep, arg);
break;
case HGSL_IOCTL_PERFCOUNTER_QUERY_SELECTION:
ret = hgsl_ioctl_perfcounter_query_selection(filep, arg);
break;
case HGSL_IOCTL_PERFCOUNTER_READ:
ret = hgsl_ioctl_perfcounter_read(filep, arg);
break;
case HGSL_IOCTL_SET_METAINFO:
ret = hgsl_ioctl_set_metainfo(filep, arg);
break;
case HGSL_IOCTL_HSYNC_FENCE_CREATE:
ret = hgsl_ioctl_hsync_fence_create(filep, arg);
break;
case HGSL_IOCTL_ISYNC_TIMELINE_CREATE:
ret = hgsl_ioctl_isync_timeline_create(filep, arg);
break;
case HGSL_IOCTL_ISYNC_TIMELINE_DESTROY:
ret = hgsl_ioctl_isync_timeline_destroy(filep, arg);
break;
case HGSL_IOCTL_ISYNC_FENCE_CREATE:
ret = hgsl_ioctl_isync_fence_create(filep, arg);
break;
case HGSL_IOCTL_ISYNC_FENCE_SIGNAL:
ret = hgsl_ioctl_isync_fence_signal(filep, arg);
break;
case HGSL_IOCTL_ISYNC_FORWARD:
ret = hgsl_ioctl_isync_forward(filep, arg);
break;
case HGSL_IOCTL_TIMELINE_CREATE:
ret = hgsl_ioctl_timeline_create(filep, arg);
break;
case HGSL_IOCTL_TIMELINE_SIGNAL:
ret = hgsl_ioctl_timeline_signal(filep, arg);
break;
case HGSL_IOCTL_TIMELINE_QUERY:
ret = hgsl_ioctl_timeline_query(filep, arg);
break;
case HGSL_IOCTL_TIMELINE_WAIT:
ret = hgsl_ioctl_timeline_wait(filep, arg);
break;
default:
ret = -ENOIOCTLCMD;
}
return ret;
}
static int hgsl_ioctl_ctxt_create(struct file *filep, unsigned long arg)
{
struct hgsl_priv *priv = filep->private_data;
struct qcom_hgsl *hgsl = priv->dev;
struct hgsl_ioctl_ctxt_create_params params;
struct hgsl_context *ctxt = NULL;
int ret = 0;
struct hgsl_hab_channel_t *hab_channel = NULL;
bool ctxt_created = false;
if (copy_from_user(¶ms, USRPTR(arg), sizeof(params))) {
LOGE("failed to copy params from user");
ret = -EFAULT;
return ret;
}
//建立hab socket
ret = hgsl_hyp_channel_pool_get(&priv->hyp_priv, 0, &hab_channel);
if (ret) {
LOGE("Failed to get hab channel %d", ret);
goto out;
}
ctxt = hgsl_zalloc(sizeof(*ctxt));
if (ctxt == NULL) {
ret = -ENOMEM;
return ret;
}
if (params.flags & GSL_CONTEXT_FLAG_CLIENT_GENERATED_TS)
params.flags |= GSL_CONTEXT_FLAG_USER_GENERATED_TS;
if (params.flags & GSL_CONTEXT_FLAG_BIND) {
params.flags &= ~GSL_CONTEXT_FLAG_CLIENT_GENERATED_TS;
params.flags |= GSL_CONTEXT_FLAG_USER_GENERATED_TS;
}
//使用hab socket发送数据
ret = hgsl_hyp_ctxt_create(hab_channel, ¶ms);
if (ret)
goto out;
if (params.ctxthandle >= HGSL_CONTEXT_NUM) {
LOGE("invalid ctxt id %d", params.ctxthandle);
ret = -EINVAL;
goto out;
}
ctxt->context_id = params.ctxthandle;
ctxt->devhandle = params.devhandle;
ctxt->pid = priv->pid;
ctxt->priv = priv;
ctxt->flags = params.flags;
hgsl_get_shadowts_mem(hab_channel, ctxt);
if (hgsl->global_hyp_inited && !hgsl->db_off)
hgsl_ctxt_create_dbq(priv, hab_channel, ctxt);
kref_init(&ctxt->kref);
init_waitqueue_head(&ctxt->wait_q);
write_lock(&hgsl->ctxt_lock);
if (hgsl->contexts[ctxt->context_id] != NULL) {
LOGE("context id %d already created",
ctxt->context_id);
ret = -EBUSY;
write_unlock(&hgsl->ctxt_lock);
goto out;
}
hgsl->contexts[ctxt->context_id] = ctxt;
write_unlock(&hgsl->ctxt_lock);
ctxt_created = true;
if (hgsl_ctxt_use_global_dbq(ctxt)) {
ret = hgsl_hsync_timeline_create(ctxt);
if (ret < 0)
LOGE("hsync timeline failed for context %d", params.ctxthandle);
}
if (ctxt->timeline)
params.sync_type = HGSL_SYNC_TYPE_HSYNC;
else
params.sync_type = HGSL_SYNC_TYPE_ISYNC;
if (copy_to_user(USRPTR(arg), ¶ms, sizeof(params))) {
ret = -EFAULT;
goto out;
}
out:
LOGD("%d", params.ctxthandle);
if (ret) {
if (ctxt_created)
hgsl_ctxt_destroy(priv, hab_channel, params.ctxthandle, NULL, false);
else if (ctxt && (params.ctxthandle < HGSL_CONTEXT_NUM)) {
_unmap_shadow(ctxt);
hgsl_hyp_put_shadowts_mem(hab_channel, &ctxt->shadow_ts_node);
hgsl_hyp_ctxt_destroy(hab_channel, ctxt->devhandle, ctxt->context_id, NULL);
kfree(ctxt);
}
LOGE("failed to create context");
}
hgsl_hyp_channel_pool_put(hab_channel);
return ret;
}
int hgsl_hyp_channel_pool_get(
struct hgsl_hyp_priv_t *priv, int id, struct hgsl_hab_channel_t **channel)
{
struct hgsl_hab_channel_t *hab_channel = NULL;
int ret = 0;
if (!channel)
return -EINVAL;
mutex_lock(&priv->lock);
if (id) {
ret = hgsl_hyp_channel_pool_get_by_id(priv, id, &hab_channel);
if (ret)
LOGE("Failed to find channel %d, ret %d", id, ret);
} else {
if (list_empty(&priv->free_channels)) {
//创建一个channel
ret = hgsl_rpc_create_channel(priv, &hab_channel);
LOGD("hgsl_rpc_create_channel returned, ret %d hab_channel %p",
ret, hab_channel);
} else {
hab_channel = container_of(priv->free_channels.next,
struct hgsl_hab_channel_t, node);
if (hab_channel != NULL) {
list_del(&hab_channel->node);
LOGD("get %p from free pool", hab_channel);
} else {
ret = -EINVAL;
LOGE("invalid hab_channel in the list");
}
}
if (!ret)
list_add_tail(&hab_channel->node, &priv->busy_channels);
}
if (!ret) {
*channel = hab_channel;
hab_channel->busy = true;
}
mutex_unlock(&priv->lock);
if ((!ret) && (!id)) {
ret = hgsl_rpc_parcel_reset(hab_channel);
if (ret) {
LOGE("hgsl_rpc_parcel_reset failed %d", ret);
hgsl_hyp_channel_pool_put(hab_channel);
hab_channel = NULL;
}
}
return ret;
}
static int hgsl_rpc_create_channel(
struct hgsl_hyp_priv_t *priv,
struct hgsl_hab_channel_t **channel)
{
int socket = HAB_INVALID_HANDLE;
int ret = -ENOMEM;
struct hgsl_hab_channel_t *hab_channel
= (struct hgsl_hab_channel_t *)hgsl_zalloc(
sizeof(struct hgsl_hab_channel_t));
if (hab_channel == NULL) {
LOGE("Failed to allocate hab_channel");
goto out;
}
hab_channel->socket = HAB_INVALID_HANDLE;
hab_channel->priv = priv;
hab_channel->busy = false;
hab_channel->wait_retry = false;
hab_channel->id = idr_alloc(&priv->channel_idr, hab_channel,
1, 0, GFP_NOWAIT);
if (hab_channel->id < 0) {
LOGE("Failed to allocate id for hab channel");
ret = hab_channel->id;
goto out;
}
//初始化hab_channel
ret = hgsl_rpc_parcel_init(hab_channel);
if (ret) {
LOGE("Failed to init parcel");
goto out;
}
//创建hab socket
if (priv->conn_id == 0) {
ret = hgsl_rpc_connect(priv, &socket);
if (ret) {
LOGE("Failed to open socket %d", ret);
goto out;
}
hab_channel->socket = socket;
//进行数据通讯
ret = rpc_handshake(priv, hab_channel);
if (ret)
LOGE("rpc_handshake failed %d", ret);
gsl_hab_close(socket);
hab_channel->socket = HAB_INVALID_HANDLE;
}
ret = hgsl_rpc_connect(priv, &socket);
if (ret) {
LOGE("Failed to open socket %d", ret);
goto out;
}
hab_channel->socket = socket;
ret = rpc_sub_handshake(priv, hab_channel);
if (ret) {
LOGE("sub handshake failed %d", ret);
gsl_hab_close(socket);
hab_channel->socket = HAB_INVALID_HANDLE;
}
out:
if (ret) {
LOGE("Failed to create channel %d exiting", ret);
if (hab_channel != NULL) {
hgsl_hyp_close_channel(hab_channel);
hab_channel = NULL;
}
} else {
*channel = hab_channel;
}
return ret;
}
static int hgsl_rpc_connect(struct hgsl_hyp_priv_t *priv, int *socket)
{
int err = 0;
int tmp_socket = priv->conn_id;
LOGI("connecting using conn_id %d", tmp_socket);
err = gsl_hab_open(&tmp_socket);
LOGI("socket_open err %d, socket %d", err, tmp_socket);
*socket = tmp_socket;
return err;
}
int gsl_hab_open(int *habfd)
{
int ret = 0;
ret = habmm_socket_open(habfd
, HAB_MMID_CREATE(MM_GFX, (int)*habfd)
, HAB_OPEN_WAIT_TIMEOUT_MS
, HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE);
LOGD("habmm_socket_open returned with %d, %x", ret, *habfd);
return ret;
}
根据p->data_pos获取recv到的数据
#define GSL_RPC_READ_ARG(p, id, p_arg, type) \
152 ({ \
153 void *p_arg_data = NULL; \
154 int ret = gsl_rpc_get_arg_ptr(p, id, &p_arg_data, sizeof(type)); \
155 if (ret == 0) { \
156 *p_arg = *((type *)p_arg_data); \
157 } \
158 \
159 ret; \
160 })
static inline int gsl_rpc_get_arg_ptr(struct gsl_hab_payload *p,
105 uint32_t id, void **p_data, size_t size)
106 {
107 int ret = -EINVAL;
108
109 if ((p->data_pos + size + gsl_rpc_header_size) <= p->data_size) {
110 struct gsl_rpc_header_t *hdr
111 = (struct gsl_rpc_header_t *)(p->data + p->data_pos);
112
113 if ((hdr->magic == GSL_HAB_DATA_MAGIC) &&
114 (hdr->id == id) && (hdr->size == size)) {
115 struct gsl_rpc_footer_t *footer = NULL;
116 uint32_t checksum;
117
118 checksum = gsl_rpc_gen_checksum(&hdr->data, hdr->size);
119 *p_data = (void *)&hdr->data;
120 p->data_pos += size + gsl_rpc_header_size;
121 footer = (struct gsl_rpc_footer_t *)
122 (p->data + p->data_pos);
123 p->data_pos += sizeof(struct gsl_rpc_footer_t);
124
125 if (checksum == footer->checksum)
126 ret = 0;
127 else
128 LOGE("checksum mismatch %d != %d",
129 checksum, footer->checksum);
130 } else {
131 struct gsl_rpc_header_t *call_hdr
132 = (struct gsl_rpc_header_t *)p->data;
133 size_t dump_size
134 = call_hdr->size + gsl_rpc_header_size
135 + sizeof(struct gsl_rpc_footer_t);
136
137 dump_size = (dump_size <= p->data_size) ?
138 dump_size : p->data_size;
139 LOGE("@%d: argument type or size mismatch: call id %d",
140 p->data_pos, call_hdr->id);
141 LOGE("size %d magic 0x%X/0x%X, id %d/%d, size %d/%d",
142 call_hdr->size, hdr->magic, GSL_HAB_DATA_MAGIC,
143 hdr->id, id, hdr->size, size);
144 gsl_hab_payload_dump(p, dump_size);
145 }
146 }
147
148 return ret;
149 }
int gsl_rpc_write(struct gsl_hab_payload *p, const void *data, size_t len)
{
return GSL_RPC_WRITE_DATA(p, GSL_RPC_BLOB_DATA, p_data, len,
do {if (data && len) memcpy(p_data, data, len); } while (0));
}
#define GSL_RPC_WRITE_DATA(p, type, data_ptr, len, action) \
({ \
int status = 0; \
\
if ((p->data_pos + gsl_rpc_header_size + len +\
sizeof(struct gsl_rpc_footer_t) > p->data_size)) { \
status = grow_data(p, len); \
} \
\
if (status == 0) { \
struct gsl_rpc_header_t *hdr = (struct gsl_rpc_header_t *) \
(p->data + p->data_pos); \
struct gsl_rpc_footer_t *ftr = (struct gsl_rpc_footer_t *) \
(p->data + p->data_pos + gsl_rpc_header_size + len); \
void *data_ptr = (void *)&hdr->data; \
uint32_t checksum = 0; \
\
action; \
checksum = gsl_rpc_gen_checksum(data_ptr, len); \
hdr->magic = GSL_HAB_DATA_MAGIC; \
hdr->id = type; \
hdr->version = 2; \
hdr->size = len; \
ftr->checksum = checksum; \
p->data_pos += len + gsl_rpc_header_size \
+ sizeof(struct gsl_rpc_footer_t); \
} \
\
status; \
})
static int gsl_rpc_send_(const char *fname, int line_num, void *data,157 size_t size, struct hgsl_hab_channel_t *hab_channel)
158 {
159 int ret = gsl_hab_send(hab_channel->socket,
160 (unsigned char *)data, size);
161
162 if (ret)
163 LOGE("failed to send @ %s:%d", fname, line_num);
164
165 return ret;
166 }
int gsl_hab_send(int habfd, unsigned char *p, size_t sz)
{
return habmm_socket_send(habfd, p, sz, 0);
}
static int gsl_rpc_recv_(const char *fname, int line_num, void *data,170 size_t size, struct hgsl_hab_channel_t *hab_channel, int interruptible)
171 {
172 int ret = gsl_hab_recv(hab_channel->socket,
173 (unsigned char *)data, size, interruptible);
174 175 return ret;
176 }
static int gsl_rpc_transact_ext(uint32_t opcode, uint32_t version,
struct hgsl_hab_channel_t *hab_channel, bool interruptible)
{
int ret = -EINVAL;
struct gsl_hab_payload *data = &hab_channel->send_buf;
struct gsl_hab_payload *reply = &hab_channel->recv_buf;
if (data && reply) {
void *p_data;
uint32_t data_size, max_size;
uint32_t recv_opcode;
if (hab_channel->wait_retry && interruptible) {
ret = 0;
} else if (hab_channel->wait_retry) {
LOGE("channel is waiting for retry for uninterruptible RPC call");
ret = -EINVAL;
goto out;
} else {
gsl_rpc_set_call_params(data, opcode, version);
ret = gsl_rpc_finalize(data);
if (!ret) {
ret = gsl_rpc_get_data_params(data,
&p_data, &data_size, &max_size);
} else {
LOGE("failed to set footer, err %d", ret);
goto out;
}
if (!ret) {
//通过hab_channel发送数据
ret = gsl_rpc_send(p_data,
data->data_pos, hab_channel);
} else {
LOGE("failed to get data params, err %d", ret);
goto out;
}
}
if (!ret) {
ret = gsl_rpc_get_data_params(reply,
&p_data, &data_size, &max_size);
} else {
LOGE("failed to send data, err %d", ret);
goto out;
}
//接收hab_channel数据
if (!ret) {
ret = gsl_rpc_recv(p_data, max_size, hab_channel, interruptible);
} else {
LOGE("failed to get data params, err %d", ret);
goto out;
}
if (ret == -EINTR) {
goto out;
} else if (!ret) {
//判断是否opcode一致
ret = gsl_rpc_get_call_params(reply,
&recv_opcode, NULL);
} else {
LOGE("failed to recv data, err %d", ret);
goto out;
}
if (!ret) {
if (recv_opcode != opcode) {
if (opcode != RPC_DISCONNECT)
LOGE("recv opcode %d (%s), expected %d (%s)",
recv_opcode,
hgsl_get_rpc_fname(recv_opcode),
opcode,
hgsl_get_rpc_fname(opcode));
ret = -EINVAL;
}
} else {
LOGE("failed to parse data, err %d", ret);
}
}
out:
return ret;
}
static int rpc_handshake(struct hgsl_hyp_priv_t *priv,
struct hgsl_hab_channel_t *hab_channel)
{
int ret = 0;
int rval = GSL_SUCCESS;
struct gsl_hab_payload *send_buf = NULL;
struct gsl_hab_payload *recv_buf = NULL;
struct handshake_params_t params = { 0 };
int tmp = 0;
enum gsl_rpc_server_type_t server_type = GSL_RPC_SERVER_TYPE_LAST;
enum gsl_rpc_server_mode_t server_mode = GSL_RPC_SERVER_MODE_LAST;
RPC_TRACE();
ret = hgsl_rpc_parcel_reset(hab_channel);
if (ret) {
LOGE("hgsl_rpc_parcel_reset failed %d", ret);
goto out;
}
send_buf = &hab_channel->send_buf;
recv_buf = &hab_channel->recv_buf;
params.client_type = g_client_type;
params.client_version = g_client_version;
params.pid = priv->client_pid;
params.size = sizeof(params);
/* send the current process name to the server */
strlcpy(params.name, priv->client_name, sizeof(params.name));
LOGD("client process name is (%s)", params.name);
//将数据写入hab_channel->send_buf中
ret = gsl_rpc_write(send_buf, ¶ms, sizeof(params));
if (ret) {
LOGE("gsl_rpc_write failed %d", ret);
goto out;
}
//将数据发送通过hab发送到qnx端habmm_socket_send
ret = gsl_rpc_transact_ext(RPC_HANDSHAKE, 1, hab_channel, 0);
if (ret) {
LOGE("gsl_rpc_transact_ext failed %d", ret);
goto out;
}
//将recv_buf中的数据hdr->data指向rval
//如果获取到数据rval不等于GSL_SUCCESS,qnx sent侧发送失败
ret = gsl_rpc_read_int32_l(recv_buf, &rval);
if ((!ret) && (rval != GSL_SUCCESS)) {
LOGE("BE sent error %d", rval);
ret = -EINVAL;
}
if (!ret) {
ret = gsl_rpc_read_int32_l(recv_buf, &priv->conn_id);
if (ret) {
LOGE("Failed to read conn_id %d", ret);
goto out;
}
ret = gsl_rpc_read_int32_l(recv_buf, &tmp);
if (ret) {
LOGE("Failed to read server_type %d", ret);
goto out;
}
server_type = (enum gsl_rpc_server_type_t)tmp;
ret = gsl_rpc_read_int32_l(recv_buf, &tmp);
if (ret) {
LOGE("Failed to read server_mode %d", ret);
goto out;
}
server_mode = (enum gsl_rpc_server_mode_t)tmp;
LOGI("Successfully connected to server, got connection id %d",
priv->conn_id);
} else {
LOGE("handshake failed, %d", ret);
}
out:
RPC_TRACE_DONE();
return ret;
}
int hgsl_hyp_ctxt_create(struct hgsl_hab_channel_t *hab_channel,
struct hgsl_ioctl_ctxt_create_params *hgsl_params)
{
struct context_create_params_t rpc_params = { 0 };
struct gsl_hab_payload *send_buf = NULL;
struct gsl_hab_payload *recv_buf = NULL;
int ret = 0;
RPC_TRACE();
if (!hab_channel) {
LOGE("invalid hab_channel");
ret = -EINVAL;
goto out;
}
ret = hgsl_rpc_parcel_reset(hab_channel);
if (ret) {
LOGE("hgsl_rpc_parcel_reset failed %d", ret);
goto out;
}
send_buf = &hab_channel->send_buf;
recv_buf = &hab_channel->recv_buf;
rpc_params.size = sizeof(rpc_params);
rpc_params.devhandle = hgsl_params->devhandle;
rpc_params.type = hgsl_params->type;
rpc_params.flags = hgsl_params->flags;
ret = gsl_rpc_write(send_buf, &rpc_params, sizeof(rpc_params));
if (ret) {
LOGE("gsl_rpc_write failed, %d", ret);
goto out;
}
ret = gsl_rpc_transact(RPC_CONTEXT_CREATE, hab_channel);
if (ret) {
LOGE("gsl_rpc_transact failed, %d", ret);
goto out;
}
ret = gsl_rpc_read_uint32_l(recv_buf, &hgsl_params->ctxthandle);
if (ret) {
LOGE("gsl_rpc_read_uint32_l failed, %d", ret);
goto out;
}
out:
RPC_TRACE_DONE();
return ret;
}
static int gsl_rpc_transact(uint32_t opcode,
struct hgsl_hab_channel_t *hab_channel)
{
int ret = gsl_rpc_transact_ext(opcode, 0, hab_channel, false);
if (ret == -EINTR) {
LOGE("noninterruptible transaction was interrupted");
ret = -EINVAL;
}
return ret;
}