Gbinder

Gbinder service
 // 创建一个服务管理器
    app.sm = gbinder_servicemanager_new(opt.dev);
 // 等待服务管理器
    if (gbinder_servicemanager_wait(app.sm, -1)) {

        // 创建一个本地对象
        app.obj = gbinder_servicemanager_new_local_object
            (app.sm, opt.iface, app_reply, &app);

        // 运行应用程序
        app_run(&app);

        // 释放本地对象
        gbinder_local_object_unref(app.obj);

        // 释放服务管理器
        gbinder_servicemanager_unref(app.sm);
    }
//GBinder如何获取服务管理器
GBinderServiceManager* gbinder_servicemanager_new(
    const char* dev)
{
    return gbinder_servicemanager_new2(dev, NULL, NULL);
}

/* 创建一个新的GBinderServiceManager对象 */

 GBinderServiceManager* gbinder_servicemanager_new2(
    const char* dev, /* 设备名称 */
    const char* sm_protocol, /* 服务管理器协议名称 */
    const char* rpc_protocol) /* 远程rpc调用协议名称,从1.1.20版本开始支持 */
{
    if (!dev) { /* 如果设备名称为空,返回NULL */
        return NULL;
    } else if (!sm_protocol) { /* 如果服务管理器协议名称为空 */
        const GBinderServiceManagerType* type;

        /* 一次性初始化 */
        if (!gbinder_servicemanager_map) {
            gbinder_servicemanager_map = gbinder_servicemanager_load_config();

            /* "Default"是存储在特殊变量中的特殊值 */
            type = g_hash_table_lookup(gbinder_servicemanager_map,
                CONF_DEFAULT);
            if (type) {
                g_hash_table_remove(gbinder_servicemanager_map, CONF_DEFAULT);
                gbinder_servicemanager_default = type;
            } else {
                gbinder_servicemanager_default = SERVICEMANAGER_TYPE_DEFAULT;
            }
        }

        /* 如果没有指定协议,则根据设备名称选择一个协议 */
        type = g_hash_table_lookup(gbinder_servicemanager_map, dev);
        if (type) {
            GDEBUG("使用%s服务管理器为%s", type->name, dev);
        } else {
            type = gbinder_servicemanager_default;
        GDEBUG("使用默认服务管理器%s为%s", type->name, dev);
        }
        return gbinder_servicemanager_new_with_type(type->get_type(), dev,
            rpc_protocol);
    } else { /* 如果指定了协议名称 */
        /* 协议名称必须是有效的 */
        const GBinderServiceManagerType* type =
            gbinder_servicemanager_value_map(sm_protocol);

        if (type) {
            return gbinder_servicemanager_new_with_type(type->get_type(), dev,
                rpc_protocol);
        } else {
            GWARN("未知的服务管理器协议%s", sm_protocol);
            return NULL;
        }
    }
}

这段代码定义了一个名为 gbinder_servicemanager_new2 的函数,用于创建 GBinderServiceManager 对象的新实例。

该函数接受三个参数: devsm_protocolrpc_protocol

如果 dev 为NULL,函数将返回NULL。

如果 sm_protocol 为NULL,函数会在需要时初始化 gbinder_servicemanager_map 。然后根据 dev 参数在 gbinder_servicemanager_map 中查找服务管理器类型。如果找到类型,它将使用该类型创建一个新的 GBinderServiceManager 对象并返回。如果没有找到类型,则使用默认的服务管理器类型创建一个新的 GBinderServiceManager 对象并返回。

如果 sm_protocol 不为NULL,函数将在 gbinder_servicemanager_value_map 中根据 sm_protocol 参数查找服务管理器类型。如果找到类型,它将使用该类型创建一个新的 GBinderServiceManager 对象并返回。如果没有找到类型,它会打印一个警告信息并返回NULL。

代码解释的步骤如下:

  1. 定义了函数 gbinder_servicemanager_new2 ,带有三个参数: devsm_protocolrpc_protocol

  2. 如果 dev 为NULL,函数返回NULL。

  3. 如果 sm_protocol 为NULL,函数检查 gbinder_servicemanager_map 是否已初始化。如果尚未初始化,则通过调用 gbinder_servicemanager_load_config() 进行初始化。然后根据 dev 参数在 gbinder_servicemanager_map 中查找服务管理器类型。

  4. 如果找到类型,它会打印一个调试信息,指示正在为设备使用的服务管理器类型。如果没有找到类型,它将使用默认的服务管理器类型,并打印一个调试信息,指示正在为设备使用默认的服务管理器类型。

  5. 然后,它使用获取到的类型以及 devrpc_protocol 参数创建一个新的 GBinderServiceManager 对象,并返回该对象。

  6. 如果 sm_protocol 不为NULL,函数将在 gbinder_servicemanager_value_map 中根据 sm_protocol 参数查找服务管理器类型。

  7. 如果找到类型,它将使用获取到的类型以及 devrpc_protocol 参数创建一个新的 GBinderServiceManager 对象,并返回该对象。

  8. 如果没有找到类型,它将打印一个警告信息,指示指定的服务管理器协议未知,并返回NULL。

/* 等待服务管理器响应,最长等待时间为max_wait_ms毫秒 */
gboolean gbinder_servicemanager_wait(
    GBinderServiceManager* self,
    long max_wait_ms) /* 自1.0.25版本起 */
{
    if (G_LIKELY(self)) {
        GBinderRemoteObject* remote = self->client->remote;

        if (!remote->dead) {
            return TRUE;
        } else if (gbinder_remote_object_reanimate(remote)) {
            gbinder_servicemanager_reanimated(self);
            return TRUE;
        } else if (max_wait_ms != 0) {
            /* 零超时意味着只检查一次,已经完成 */
            long delay_ms = PRESENSE_WAIT_MS_MIN;

            while (max_wait_ms != 0) {
                if (max_wait_ms > 0) {
                    if (max_wait_ms < delay_ms) {
                        delay_ms = max_wait_ms;
                        max_wait_ms = 0;
                    } else {
                        max_wait_ms -= delay_ms;
                    }
                }
                gbinder_servicemanager_sleep_ms(delay_ms);
                if (gbinder_remote_object_reanimate(remote)) {
                    gbinder_servicemanager_reanimated(self);
                    return TRUE;
                }
                if (delay_ms < PRESENSE_WAIT_MS_MAX) {
                    delay_ms += PRESENSE_WAIT_MS_STEP;
                    if (delay_ms > PRESENSE_WAIT_MS_MAX) {
                        delay_ms = PRESENSE_WAIT_MS_MAX;
                    }
                }
            }
            /* 超时 */
            GWARN("等待服务管理器响应超时 %s", self->dev);
        }
    }
    return FALSE;
}

这段代码是一个名为 "gbinder_servicemanager_wait" 的函数,用于等待服务管理器可用。它接受两个参数:一个 GBinderServiceManager 对象的指针和最大等待时间(以毫秒为单位)。

该函数首先检查 GBinderServiceManager 对象是否有效。如果有效,它获取与服务管理器的客户端关联的远程对象。如果远程对象未失效,则立即返回 TRUE。

如果远程对象失效,函数尝试使用 "gbinder_remote_object_reanimate" 函数重新激活它。如果重新激活成功,则调用 "gbinder_servicemanager_reanimated" 函数并返回 TRUE。

如果重新激活失败且最大等待时间不为零,则函数进入一个循环,等待远程对象可用。它从最小延迟时间开始,并反复检查是否达到了最大等待时间。如果最大等待时间为正且小于当前延迟时间,则将延迟时间缩短以匹配剩余等待时间。否则,将延迟时间从最大等待时间中减去。

延迟时间过后,函数检查远程对象是否已重新激活。如果是,则调用 "gbinder_servicemanager_reanimated" 函数并返回 TRUE。

如果延迟时间小于最大允许的延迟时间,它会增加一个步长值来增加延迟时间。如果延迟时间超过最大允许的延迟时间,则将延迟时间设置为最大允许值。

如果达到了最大等待时间,函数会记录一个警告信息并返回 FALSE。

如果 GBinderServiceManager 对象无效,则函数立即返回 FALSE。

总之,该代码通过反复检查关联的远程对象的状态并在检查之间等待一定的时间,等待服务管理器可用。如果远程对象在指定的最大等待时间内可用,函数返回 TRUE。否则,返回 FALSE。

// 创建一个新的本地对象
GBinderLocalObject* gbinder_servicemanager_new_local_object(
    GBinderServiceManager* self, // GBinderServiceManager对象
    const char* iface, // 接口名称
    GBinderLocalTransactFunc txproc, // 本地事务函数
    void* user_data) // 用户数据
{
    const char* ifaces[2]; // 接口数组

    ifaces[0] = iface; // 将接口名称存储到接口数组中
    ifaces[1] = NULL; // 将接口数组的第二个元素设置为NULL
    return gbinder_servicemanager_new_local_object2
        (self, ifaces, txproc, user_data); // 返回创建的本地对象
}


// 创建一个本地对象
GBinderLocalObject* gbinder_servicemanager_new_local_object2(
    GBinderServiceManager* self,  // GBinderServiceManager对象
    const char* const* ifaces,    // 接口名数组
    GBinderLocalTransactFunc txproc,  // 本地事务处理函数
    void* user_data)              // 用户数据
{
    // 如果GBinderServiceManager对象存在
    if (G_LIKELY(self)) {
        // 创建一个本地对象并返回
        return gbinder_local_object_new(gbinder_client_ipc(self->client),
            ifaces, txproc, user_data);
    }
    // 返回NULL
    return NULL;
}


GBinderLocalObject*
gbinder_local_object_new(
    GBinderIpc* ipc,
    const char* const* ifaces,
    GBinderLocalTransactFunc txproc,
    void* user_data) /* Since 1.0.30 */
{
    return gbinder_local_object_new_with_type(GBINDER_TYPE_LOCAL_OBJECT,
        ipc, ifaces, txproc, user_data);
}

// 创建一个本地对象

GBinderLocalObject* gbinder_local_object_new_with_type(
    GType type, // 对象类型
    GBinderIpc* ipc, // IPC通道
    const char* const* ifaces, // 接口列表
    GBinderLocalTransactFunc txproc, // 本地事务处理函数
    void* arg) // 参数
{
    if (G_LIKELY(ipc)) { // 如果IPC通道存在
        GBinderLocalObject* obj = g_object_new(type, NULL); // 创建一个新对象

        gbinder_local_object_init_base(obj, ipc, ifaces, txproc, arg); // 初始化对象
        gbinder_ipc_register_local_object(ipc, obj); // 注册本地对象
        return obj; // 返回对象
    }
    return NULL; // 返回空
}

// 初始化本地对象
void gbinder_local_object_init_base(
    GBinderLocalObject* self, // 本地对象
    GBinderIpc* ipc, // IPC
    const char* const* ifaces, // 接口
    GBinderLocalTransactFunc txproc, // 本地事务处理函数
    void* user_data) // 用户数据
{
    GBinderLocalObjectPriv* priv = self->priv; // 获取本地对象私有数据
    guint i = 0, n = gutil_strv_length((char**)ifaces); // 获取接口数量
    gboolean append_base_interface; // 是否添加基础接口

    if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) { // 判断接口列表中是否包含基础接口
        append_base_interface = TRUE;
        n++;
    } else {
        append_base_interface = FALSE;
    }

    priv->ifaces = g_new(char*, n + 1); // 分配接口数组内存
    if (ifaces) { // 如果接口列表不为空
        while (*ifaces) { // 遍历接口列表
            priv->ifaces[i++] = g_strdup(*ifaces++); // 复制接口名称
        }
    }
    if (append_base_interface) { // 如果需要添加基础接口
        priv->ifaces[i++] = g_strdup(hidl_base_interface); // 复制基础接口名称
    }
    priv->ifaces[i] = NULL; // 接口数组最后一个元素为NULL

    self->ipc = gbinder_ipc_ref(ipc); // 引用IPC
    self->ifaces = (const char**)priv->ifaces; // 设置接口数组
    priv->txproc = txproc; // 设置本地事务处理函数
    priv->user_data = user_data; // 设置用户数据
    
}

这段代码是一个名为 "gbinder_local_object_init_base" 的函数,用于初始化 GBinderLocalObject 结构体。该结构体表示 GBinder IPC 框架中的本地对象。函数接受多个参数:指向 GBinderLocalObject 结构体的指针、指向 GBinderIpc 结构体的指针、接口名称的数组、事务处理函数和用户数据。

函数首先使用 gutil_strv_length 函数获取 "ifaces" 数组的长度。同时,它检查数组的最后一个元素是否等于 "hidl_base_interface"。如果不等于,则将 "append_base_interface" 变量设置为 TRUE,并将数组长度增加 1。否则,将 "append_base_interface" 设置为 FALSE。

接下来,函数为 "ifaces" 数组分配内存,额外增加一个元素用于 NULL 终止。然后,它遍历 "ifaces" 数组,并使用 g_strdup 对每个接口名称进行复制,将它们存储在 GBinderLocalObjectPriv 结构体的 "ifaces" 数组中。

如果 "append_base_interface" 为 TRUE,则复制 "hidl_base_interface" 并将其添加到 "ifaces" 数组中。

最后,函数使用参数中的相应值设置 GBinderLocalObject 结构体的 ipc、ifaces、txproc 和 user_data 字段。

总之,该函数通过复制接口名称并设置必要的字段来初始化 GBinderLocalObject 结构体。


static
GBinderLocalReply*
app_reply(
    GBinderLocalObject* obj, // 本地对象
    GBinderRemoteRequest* req, // 远程请求
    guint code, // 请求码
    guint flags, // 标志
    int* status, // 状态
    void* user_data) // 用户数据
{
    App* app = user_data; // 获取应用程序

    GBinderReader reader; // 读取器

    gbinder_remote_request_init_reader(req, &reader); // 初始化远程请求读取器
    if (code == GBINDER_FIRST_CALL_TRANSACTION) { // 如果是第一次调用
        const AppOptions* opt = app->opt; // 获取应用选项
        const char* iface = gbinder_remote_request_interface(req); // 获取接口名称

        if (!g_strcmp0(iface, opt->iface)) { // 如果接口名称匹配
            char* str = gbinder_reader_read_string16(&reader); // 读取字符串
            GBinderLocalReply* reply = gbinder_local_object_new_reply(obj); // 创建本地回复

            GVERBOSE("\"%s\" %u", iface, code); // 输出详细信息
            GDEBUG("\"%s\"", str); // 输出调试信息
            *status = 0; // 设置状态
            gbinder_local_reply_append_string16(reply, str); // 添加字符串到本地回复
            g_free(str); // 释放字符串内存
            if (opt->async) { // 如果是异步请求
                Response* resp = g_new0(Response, 1); // 创建响应

                resp->reply = reply; // 设置响应回复
                resp->req = gbinder_remote_request_ref(req); // 设置响应请求
                g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, app_async_resp,
                    resp, app_async_free); // 添加异步响应
                gbinder_remote_request_block(resp->req); // 阻塞远程请求
                return NULL; // 返回空
            } else { // 如果是同步请求
                return reply; // 返回本地回复
            }
        } else { // 如果接口名称不匹配
             GDEBUG("Unexpected interface \"%s\"", iface); // 输出调试信息
        }
    } else if (code == BINDER_DUMP_TRANSACTION) { // 如果是转储请求
        int fd = gbinder_reader_read_fd(&reader); // 读取文件描述符
        const char* dump = "Sorry, I've got nothing to dump...\n"; // 转储信息
        const gssize dump_len = strlen(dump); // 转储信息长度

        GDEBUG("Dump request from %d", gbinder_remote_request_sender_pid(req)); // 输出调试信息
        if (write(fd, dump, dump_len) != dump_len) { // 写入转储信息
            GERR("Failed to write dump: %s", strerror(errno)); // 输出错误信息
        }
        *status = 0; // 设置状态
        return NULL; // 返回空
    }
    *status = -1; // 设置状态
    return NULL; // 返回空
}

该代码是 GBinder 框架中处理对本地对象的远程请求的函数。它接受各种参数,包括本地对象、远程请求、请求代码、标志、状态和用户数据。

1.它初始化一个GBinderReader对象来从远程请求中读取数据。

  1. 如果请求代码为GBINDER_FIRST_CALL_TRANSACTION,则检查接口名称是否与期望的接口名称匹配。
  2. 如果接口名称匹配,则从阅读器读取字符串,创建本地回复对象,将状态设置为 0,将字符串附加到本地回复,并释放字符串内存。
  3. 如果请求是异步的,则创建一个响应对象,在响应中设置回复和请求,将异步响应函数添加到事件循环中,阻止远程请求,并返回NULL。
  4. 如果请求是同步的,则返回本地回复。
  5. 如果接口名称不匹配,则输出调试消息。
  6. 如果请求代码为 BINDER_DUMP_TRANSACTION,则从读取器读取文件描述符,将转储消息写入文件描述符,将状态设置为 0,并返回 NULL。
  7. 如果请求代码既不是 GBINDER_FIRST_CALL_TRANSACTION 也不是 BINDER_DUMP_TRANSACTION,则将状态设置为 -1 并返回 NULL。
static void app_run(App* app)
{
    const char* name = app->opt->name;
    guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
    guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
    gulong presence_id = gbinder_servicemanager_add_presence_handler
        (app->sm, app_sm_presence_handler, app);

    app->loop = g_main_loop_new(NULL, TRUE);

    gbinder_servicemanager_add_service(app->sm, name, app->obj,
        app_add_service_done, app);

    g_main_loop_run(app->loop);

    if (sigtrm) g_source_remove(sigtrm);
    if (sigint) g_source_remove(sigint);
    gbinder_servicemanager_remove_handler(app->sm, presence_id);
    g_main_loop_unref(app->loop);
    app->loop = NULL;
}

给定的代码是一个名为“app_run”的函数,它将“App”类型的对象作为参数。该函数执行以下步骤:

  1. 它从“app”对象的“opt”字段中检索“name”字段的值,并将其分配给“name”变量。

  2. 它使用函数“g_unix_signal_add”添加 SIGTERM 信号的信号处理程序,并将“app_signal”函数和“app”对象作为参数传递。返回值存储在“sigtrm”变量中。

  3. 它使用函数“g_unix_signal_add”添加 SIGINT 信号的信号处理程序,并将“app_signal”函数和“app”对象作为参数传递。返回值存储在“sigint”变量中。

  4. 它使用函数“gbinder_servicemanager_add_presence_handler”将存在处理程序添加到“sm”(服务管理器)对象,并将“app_sm_presence_handler”函数和“app”对象作为参数传递。返回的值存储在“presence_id”变量中。

  5. 它使用函数“g_main_loop_new”创建一个新的主循环,并将其分配给“app”对象的“loop”字段。

  6. 它使用函数“gbinder_servicemanager_add_service”向“sm”对象添加服务,传递“name”、“obj”(对象)、“app_add_service_done”函数和“app”对象作为参数。

  7. 它使用函数“g_main_loop_run”启动主循环。

  8. 如果“sigtrm”变量非零,则使用函数“g_source_remove”删除信号处理程序。

  9. 如果“sigint”变量非零,则使用函数“g_source_remove”删除信号处理程序。

  10. 它使用函数“gbinder_servicemanager_remove_handler”从“sm”对象中删除存在处理程序。

  11. 它使用函数“g_main_loop_unref”释放对主循环的引用。

  12. 它将“app”对象的“loop”字段设置为NULL。

总之,代码设置信号处理程序,添加存在处理程序,创建主循环,添加服务,启动主循环,然后清理添加的处理程序和主循环。

Gbinder Client

   // 如果应用程序初始化成功
    if (app_init(&opt, argc, argv)) {
        //获取service manager ,跟service一样
        app.sm = gbinder_servicemanager_new(opt.dev);
        //检查是否成功创建
        if (app.sm) {
             
            //创建一个本地对象并运行应用程序
            app.local = gbinder_servicemanager_new_local_object(app.sm,
                NULL, NULL, NULL);
            app_run(&app);
            //释放gbinder_servicemanager_new对象
            gbinder_servicemanager_unref(app.sm);
        }
    }
    
static
void
app_run(
   App* app)
{
    const AppOptions* opt = app->opt;
    guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
    guint sigint = g_unix_signal_add(SIGINT, app_signal, app);

    app->fqname = opt->fqname ? g_strdup(opt->fqname) :
        strchr(opt->name, '/') ? g_strdup(opt->name) :
        g_strconcat(opt->iface, "/", opt->name, NULL);

    if (!app_connect_remote(app)) {
        GINFO("Waiting for %s", app->fqname);
        app->wait_id = gbinder_servicemanager_add_registration_handler(app->sm,
            app->fqname, app_registration_handler, app);
    }

    app->loop = g_main_loop_new(NULL, TRUE);
    app->ret = RET_OK;
    g_main_loop_run(app->loop);

    g_source_remove(sigtrm);
    g_source_remove(sigint);
    g_main_loop_unref(app->loop);

    if (app->thread) {
        /* Not the cleanest of exits, just dropping the thread... */
        g_thread_unref(app->thread);
    }
    gbinder_remote_object_remove_handler(app->remote, app->death_id);
    gbinder_remote_object_unref(app->remote);
    gbinder_local_object_drop(app->local);
    gbinder_client_unref(app->client);
    g_free(app->fqname);
}

给定的代码是一个名为“app_run”的函数,它采用 App 对象作为参数。以下是该代码功能的分步说明:

  1. 该函数首先将“opt”变量分配给 App 对象的“opt”字段。
  2. 然后使用“g_unix_signal_add”函数添加 SIGTERM 和 SIGINT 的信号处理程序。信号处理程序设置为使用“app”对象作为参数来调用“app_signal”函数。
  3. 下一行代码为 App 对象的“fqname”字段分配一个值。如果“opt->fqname”不为空,则会将重复的“opt->fqname”字符串分配给“app->fqname”。否则,它检查“opt->name”是否包含正斜杠(“/”)。如果是,它会将重复的“opt->name”字符串分配给“app->fqname”。否则,它使用“g_strconcat”函数连接“opt->iface”、“/”和“opt->name”,并将结果分配给“app->fqname”。
  4. 如果未建立远程连接,则会记录一条消息并使用“gbinder_servicemanager_add_registration_handler”函数为“app->fqname”添加注册处理程序。该处理程序设置为使用“app”对象作为参数来调用“app_registration_handler”函数。
  5. 该函数使用“g_main_loop_new”函数创建一个新的主循环,并将其分配给“app->loop”。
  6. App对象的“ret”字段设置为“RET_OK”。
  7. 使用“g_main_loop_run”函数运行主循环。
  8. 使用“g_source_remove”函数删除 SIGTERM 和 SIGINT 的信号处理程序。
  9. 使用“g_main_loop_unref”函数取消引用主循环。
    10.如果App对象的“thread”字段不为空,则使用“g_thread_unref”函数删除该线程。
  10. 使用“gbinder_remote_object_remove_handler”函数删除远程对象死亡通知的处理程序。
  11. 使用“gbinder_remote_object_unref”函数取消引用远程对象。
  12. 使用“gbinder_local_object_drop”函数删除本地对象。
  13. 使用“gbinder_client_unref”函数取消对客户端的引用。
  14. 使用“g_free”函数释放为“app->fqname”分配的内存。

总之,代码设置信号处理程序,在必要时建立远程连接,运行主循环,并在循环退出时执行清理操作。

// 通过fqname获取GinderRemoteObject对象
// 如果获取成功,则创建客户端连接并启动输入线程
// 如果获取失败,则返回FALSE
static
gboolean
app_connect_remote(
    App* app)
{

    app->remote =gbinder_servicemanager_get_service_sync(app->sm,
        app->fqname, NULL); /* 自动释放指针 */

    if (app->remote) {
        const AppOptions* opt = app->opt;

        GINFO("已连接到 %s", app->fqname);
        gbinder_remote_object_ref(app->remote);
        app->client = gbinder_client_new(app->remote, opt->iface);
        app->death_id = gbinder_remote_object_add_death_handler(app->remote,
            app_remote_died, app);
        app->thread = g_thread_new("input", app_input_thread, app);
        return TRUE;
    }
    return FALSE;
}

此代码是一个名为“app_connect_remote”的函数,用于连接到远程服务。它采用“App”结构的实例作为参数并返回一个布尔值。

这是代码的逐步解释:

  1. 该函数首先将从服务管理器获取的远程服务分配给“App”结构体的“remote”字段。使用“gbinder_servicemanager_get_service_sync”函数同步获取服务。

  2. 如果成功获取“远程”服务(即不为 NULL),则代码将继续执行以下步骤:

  3. 它从“App”结构中检索“opt”字段并将其分配给“opt”变量。

  4. 它记录一条消息,表明它已使用“GINFO”宏成功连接到远程服务。

  5. 通过调用“gbinder_remote_object_ref”函数来增加“远程”对象的引用计数。

  6. 它通过使用“remote”对象和“opt”变量中的“iface”字段调用“gbinder_client_new”函数来创建一个新的客户端对象。

  7. 它通过调用“gbinder_remote_object_add_death_handler”函数向“远程”对象添加死亡处理程序。如果远程服务不可用,将触发此死亡处理程序。

  8. 它通过调用“g_thread_new”函数创建一个名为“input”的新线程,其中“app_input_thread”函数作为线程函数,“app”对象作为线程数据。

  9. 最后返回TRUE,表示连接远程服务成功。

  10. 如果未获得“远程”服务(即,它为 NULL),则代码仅返回 FALSE 以指示连接尝试失败。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容