hs-proxy: Keep track of clientCtx and client when starting application 36/25136/1 9.99.4 jellyfish/9.99.4 jellyfish_9.99.4
authorMarius Vlad <marius.vlad@collabora.com>
Wed, 19 Aug 2020 10:11:19 +0000 (13:11 +0300)
committerMarius Vlad <marius.vlad@collabora.com>
Wed, 19 Aug 2020 14:00:07 +0000 (17:00 +0300)
The subscribe verb was used in the past to keep track of applications,
which was done in background with the help of event handlers. As
that no longer happens we keep track of the client and its clientCtx
when starting directly from the homescreen binding, faking the subscribe
logic.

As the afb_req_t object is no longer in scope when the async callback
handler returns, we do it before doing the call to af-main, and assume
that we'll succeed.

We use the async callback handler to  verify if the application was
indeed started but any application crashing afterwards will require an
additional check performed, as it will found in the hash table of
clients.

Bug-AGL: SPEC-3524

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Change-Id: I0e417dc5f2953947cd27ca551c0d2a2af5c57e6d

src/hs-clientmanager.cpp
src/hs-proxy.cpp

index 7c2adc5..beac816 100644 (file)
@@ -184,6 +184,7 @@ int HS_ClientManager::handleRequest(afb_req_t request, const char *verb, const c
         std::string id(appid);
         auto ip = client_list.find(id);
         if(ip != client_list.end()) {
+           // FIXME: do another verification here in case the application died
             ret = ip->second->handleRequest(request, verb);
         }
         else {
index a7236b4..33e5d53 100644 (file)
 #include "homescreen.h"
 #include "hs-proxy.h"
 
+struct closure_data {
+       std::string appid;
+       HS_ClientCtxt *clientCtx;
+       struct hs_instance *hs_instance;
+};
+
 const char _afm_main[] = "afm-main";
 
 
@@ -37,6 +43,24 @@ const char _afm_main[] = "afm-main";
 static void api_callback(void *closure, struct json_object *object, const char *error, const char *info, afb_api_t api)
 {
     AFB_INFO("asynchronous call, error=%s, info=%s, object=%s.", error, info, json_object_get_string(object));
+    struct closure_data *cdata = static_cast<struct closure_data *>(closure);
+
+    if (!cdata->hs_instance) {
+           return;
+    }
+
+    struct HS_ClientManager *clientManager = cdata->hs_instance->client_manager;
+    if (!clientManager) {
+           return;
+    }
+
+    /* if we have an error then we couldn't start the application so we remove it */
+    if (error) {
+           clientManager->removeClientCtxt(cdata->clientCtx);
+           clientManager->removeClient(cdata->appid);
+    }
+
+    free(cdata);
 }
 
 /**
@@ -52,10 +76,10 @@ static void api_callback(void *closure, struct json_object *object, const char *
  *  None
  *
  */
-static void api_call(afb_api_t api, const char *service, const char *verb, struct json_object *args)
+static void api_call(afb_api_t api, const char *service, const char *verb, struct json_object *args, struct closure_data *cdata)
 {
     AFB_INFO("service=%s verb=%s, args=%s.", service, verb, json_object_get_string(args));
-    afb_api_call(api, service, verb, args, api_callback, nullptr);
+    afb_api_call(api, service, verb, args, api_callback, cdata);
 }
 
 /**
@@ -131,5 +155,37 @@ int HS_AfmMainProxy::detail(afb_api_t api, const std::string &id, struct json_ob
 void HS_AfmMainProxy::start(struct hs_instance *instance, afb_req_t request, const std::string &id)
 {
     struct json_object *args = json_object_new_string(id.c_str());
-    api_call(request->api, _afm_main, __FUNCTION__, args);
+    struct closure_data *cdata;
+
+    /* tentatively store the client and client context, as the afb_req_t
+     * request will no longer be available in the async callback handler. This
+     * is similar to that is done showWindow(), handleRequest() in
+     * homescreen.cpp, but allows to fake the subscription here as well to
+     * avoid clients create/install dummy event handlers as to 'register' (or
+     * to keep track of applications started).
+     *
+     * In case api_callback() does return an error we'll remove then the client
+     * and client context there. We pass the closure_data with the client context
+     * and the application id to remove it.
+     */
+    if (!instance)
+           return;
+
+    cdata = static_cast<struct closure_data *>(calloc(1, sizeof(*cdata)));
+    cdata->hs_instance = instance;
+    cdata->appid = id;
+
+    struct HS_ClientManager *clientManager = instance->client_manager;
+    if (!clientManager) {
+           return;
+    }
+
+    cdata->clientCtx = clientManager->createClientCtxt(request, id);
+    HS_Client *client = clientManager->addClient(request, id);
+    if (client) {
+           if (client->handleRequest(request, "subscribe"))
+                   AFB_WARNING("Failed to handle subcribe\n");
+    }
+
+    api_call(request->api, _afm_main, __FUNCTION__, args, cdata);
 }