Implement remote app-control reply feature
authorSangyoon Jang <jeremy.jang@samsung.com>
Mon, 20 Aug 2018 11:11:37 +0000 (20:11 +0900)
committer장상윤/Tizen Platform Lab(SR)/Engineer/삼성전자 <jeremy.jang@samsung.com>
Thu, 23 Aug 2018 06:13:58 +0000 (15:13 +0900)
Change-Id: I4677abdbd700e57eb37ff19a35cfc652422ba5d7
Signed-off-by: Sangyoon Jang <jeremy.jang@samsung.com>
src/client/client.cc
src/client/dbus.cc
src/common/appcontrol_manager.cc
src/common/appcontrol_manager.h
src/common/connection_manager.h
src/common/dbus_service.cc
src/common/dbus_service.h
src/common/mdg_manager.cc
src/common/mdg_manager.h
tools/capmgr_test.cc

index 6e21e77cc16157545622c4f81768a453552e9620..a4a3a3b506af5cf3d13f6df3d119b68480885593 100644 (file)
@@ -425,20 +425,52 @@ API int capmgr_app_control_remove_extra_data(capmgr_app_control_h app_control,
 }
 
 struct cbdata {
+  capmgr_app_control_h request;
   capmgr_app_control_reply_cb cb;
   void* user_data;
 };
 
 void capmgr_dbus_callback(GVariant* result, void* user_data) {
+  LOG(DEBUG) << "Dbus callback for client called";
+
   // TODO(jeremy.jang): some data maybe returned
-  gboolean r;
-  g_variant_get(result, "(b)", &r);
-  if (!r)
+  GVariantIter* iter;
+  guchar* data;
+  guint len;
+  g_variant_get(result, "(ayu)", &iter, &len);
+  if (!iter)
     LOG(ERROR) << "Some error occurred";
 
+  data = reinterpret_cast<guchar*>(g_try_malloc(len));
+  if (!data) {
+    LOG(ERROR) << "Out of memory";
+    return;
+  }
+
+  for (unsigned int i = 0; i < len; i++) {
+    if (!g_variant_iter_loop(iter, "y", &data[i])) {
+      LOG(ERROR) << "Failed to get data from GVariant!";
+      break;
+    }
+  }
+  g_variant_iter_free(iter);
+
   struct cbdata* cbdata = reinterpret_cast<struct cbdata*>(user_data);
-  cbdata->cb(nullptr, nullptr, CAPMGR_APP_CONTROL_RESULT_OK, cbdata->user_data);
+  struct capmgr_app_control_s* reply = new struct capmgr_app_control_s;
+  reply->b = bundle_decode(data, len);
+  if (!reply->b) {
+    LOG(ERROR) << "Invalid bundle data!";
+    capmgr_app_control_destroy(cbdata->request);
+    delete cbdata;
+    return;
+  }
+  reply->device = cbdata->request->device;
+
+  // TODO(jeremy.jang): need to receive aul_svc result code
+  cbdata->cb(cbdata->request, reply, CAPMGR_APP_CONTROL_RESULT_OK,
+      cbdata->user_data);
 
+  capmgr_app_control_destroy(cbdata->request);
   delete cbdata;
 }
 
@@ -469,13 +501,23 @@ API int capmgr_app_control_send(capmgr_app_control_h app_control,
   }
   g_variant_ref_sink(gv);
 
+  capmgr_app_control_h clone;
+  r = capmgr_app_control_clone(app_control, &clone);
+  if (r != CAPMGR_ERROR_NONE) {
+    LOG(ERROR) << "Failed to clone app control request: " << r;
+    return r;
+  }
+
   struct cbdata* cbdata = new struct cbdata;
+  cbdata->request = clone;
   cbdata->cb = cb;
   cbdata->user_data = user_data;
 
   if (!capmgr::ProxyCallAsync("SendRemoteAppControl", gv, capmgr_dbus_callback,
         cbdata)) {
     LOG(ERROR) << "Failed to dbus method call";
+    delete cbdata;
+    capmgr_app_control_destroy(clone);
     g_variant_unref(gv);
     // errcode?
     return CAPMGR_ERROR_INVALID_PARAMETER;
index 813aa3704c9f8059df4e2478e8720bf4129e8be1..491760ded6c1dcc39d8f0e75a00e054bc6a73d41 100644 (file)
@@ -22,6 +22,7 @@ struct cbdata {
 
 void MethodCallback(GObject* source_object, GAsyncResult* res,
     gpointer user_data) {
+  LOG(DEBUG) << "Got a response from capmgr";
   GDBusProxy* proxy = reinterpret_cast<GDBusProxy*>(source_object);
   GError* error = nullptr;
   GVariant* result = g_dbus_proxy_call_finish(proxy, res, &error);
index 2af45c6ef91573ec75a8754c73fdead11f60ae96..25cfd0a788d9d74d6f770e1ddc153ca2c7fb9b36 100644 (file)
@@ -8,48 +8,47 @@
 #include <aul_svc.h>
 #include <bundle.h>
 
+#include <map>
+
 #include "common/utils/logging.h"
 
 namespace {
 
-void ReplyCb(bundle* b, int request_code, aul_svc_result_val result,
-    void* data) {
-  LOG(DEBUG) << "aul_svc_run_service result code: " << result;
+const std::map<aul_svc_result_val, const char*> kAulSvcResMap = {
+  {AUL_SVC_RES_OK, "AUL_SVC_RES_OK"},
+  {AUL_SVC_RES_NOT_OK, "AUL_SVC_RES_NOT_OK"},
+  {AUL_SVC_RES_CANCEL, "AUL_SVC_RES_CANCEL"},
+};
 
-  // b is reply bundle
-
-  switch (result) {
-    case AUL_SVC_RES_OK:
-      LOG(DEBUG) << "AUL_SVC_RES_OK";
-      break;
-    case AUL_SVC_RES_NOT_OK:
-      LOG(ERROR) << "AUL_SVC_RES_NOT_OK";
-      break;
-    case AUL_SVC_RES_CANCEL:
-      LOG(DEBUG) << "AUL_SVC_RES_CANCEL";
-      break;
-    default:
-      break;
-  }
+}  // namespace
 
-  // TODO(jeremy.jang): need to send reply to remote device
+namespace capmgr {
+
+AppControlManager::AppControlManager() {
+  int ret = aul_launch_init(&AppControlManager::AulHandler, nullptr);
+  if (ret != AUL_R_OK)
+    LOG(ERROR) << "aul_launch_init() failed: " << ret;
 }
 
-}  // namespace
+AppControlManager::~AppControlManager() {}
 
-namespace capmgr {
+void AppControlManager::RegisterAppControlReplyHandler(
+    std::function<void(bundle_raw*, size_t, aul_svc_result_val, void*)>
+        handler) {
+  ReplyHandler().reply.connect(handler);
+}
 
 // TODO(jeremy.jang): handle reply, async?
-bool AppControlManager::LaunchApplication(const unsigned char* data,
-    size_t len) {
-  bundle* b = bundle_decode(data, len);
+bool AppControlManager::LaunchApplication(const unsigned char* bundle_data,
+    size_t len, void* data) {
+  bundle* b = bundle_decode(bundle_data, len);
   if (!b) {
     LOG(ERROR) << "Invalid bundle data!";
     return false;
   }
 
   // FIXME: for uid 5001 is temporary code. request code should be set properly.
-  int ret = aul_svc_run_service_async_for_uid(b, 0, ReplyCb, nullptr, 5001);
+  int ret = aul_svc_run_service_async_for_uid(b, 0, ReplyCb, data, 5001);
   if (ret < AUL_SVC_RET_OK) {
     LOG(ERROR) << "launch failed : " << ret;
     bundle_free(b);
@@ -60,4 +59,29 @@ bool AppControlManager::LaunchApplication(const unsigned char* data,
   return true;
 }
 
+int AppControlManager::AulHandler(aul_type type, bundle* kb, void* data) {
+  return 0;
+}
+
+void AppControlManager::ReplyCb(bundle* b, int request_code,
+    aul_svc_result_val result, void* data) {
+  LOG(DEBUG) << "aul_svc_run_service result code: " << result;
+
+  const auto& it = kAulSvcResMap.find(result);
+  if (it == kAulSvcResMap.end())
+    LOG(ERROR) << "Unknown aul_svc_result_val";
+  else
+    LOG(DEBUG) << it->second;
+
+  bundle_raw* raw;
+  int len;
+  int r = bundle_encode(b, &raw, &len);
+  if (r != BUNDLE_ERROR_NONE) {
+    LOG(ERROR) << "Failed to encode bundle: " << r;
+    return;
+  }
+
+  ReplyHandler().reply(raw, len, result, data);
+}
+
 }  // namespace capmgr
index fdb167289bf6088d8424bcb45d6cd6020f2b4e2d..8ab9027b9b07192f1388e426fa7119d5dc839240 100644 (file)
@@ -5,7 +5,15 @@
 #ifndef COMMON_APPCONTROL_MANAGER_H_
 #define COMMON_APPCONTROL_MANAGER_H_
 
+#include <aul.h>
+#include <aul_svc.h>
+#include <bundle.h>
 #include <glib.h>
+#include <sys/types.h>
+
+#include <boost/signals2.hpp>
+
+#include <functional>
 
 #include "common/capability.h"
 
@@ -16,8 +24,31 @@ class AppControlManager {
   AppControlManager();
   ~AppControlManager();
 
-  static bool LaunchApplication(const unsigned char* data, size_t len);
+  static void RegisterAppControlReplyHandler(
+      std::function<void(bundle_raw*, size_t, aul_svc_result_val, void*)>
+          handler);
+  static AppControlManager& GetAppControlManager() {
+    static AppControlManager manager = AppControlManager();
+    return manager;
+  }
+  bool LaunchApplication(const unsigned char* bundle_data, size_t len,
+      void* data);
+
  private:
+  class AppControlReplyHandler {
+   public:
+    boost::signals2::signal<void(bundle_raw*, size_t, aul_svc_result_val,
+        void*)> reply;
+  };
+
+  static AppControlReplyHandler& ReplyHandler() {
+    static AppControlReplyHandler reply_handler = AppControlReplyHandler();
+    return reply_handler;
+  }
+
+  static int AulHandler(aul_type type, bundle* kb, void* data);
+  static void ReplyCb(bundle* b, int request_code, aul_svc_result_val result,
+      void* data);
 };
 
 }  // namespace capmgr
index 356546de51a48aecfac2827a872f379bb89cb78d..1e34967703f8b486356326d5dc68ed48a78ffd42 100644 (file)
@@ -21,7 +21,7 @@ class ConnectionManager {
   virtual void FindDevices() = 0;
   virtual void RegisterEndpoint() = 0;
   virtual void ExchangeCapabilities() = 0;
-  virtual bool SendAppControl(const std::string& device_id,
+  virtual int SendAppControl(const std::string& device_id,
       const unsigned char* data, size_t len) = 0;
   virtual bool SendFile(const std::string& device_id,
       const std::string& file_path) = 0;
index e7b1c8ebef2ada98c4876c11b36e8f1a4fd38bd5..e8ad633b24d747ae64527f17beb065acfe337bb1 100644 (file)
@@ -29,7 +29,8 @@ const char kDBusInstropectionXml[] =
   "      <arg type='s' name='device_id' direction='in'/>"
   "      <arg type='ay' name='appcontrol' direction='in'/>"
   "      <arg type='u' name='len' direction='in'/>"
-  "      <arg type='b' name='result' direction='out'/>"
+  "      <arg type='ay' name='appcontrol_reply' direction='out'/>"
+  "      <arg type='u' name='reply_len' direction='out'/>"
   "    </method>"
   "    <method name='SendFile'>"
   "      <arg type='s' name='device_id' direction='in'/>"
@@ -40,6 +41,8 @@ const char kDBusInstropectionXml[] =
 const char kDBusServiceName[] = "org.tizen.capmgr";
 const char kDBusObjectPath[] = "/org/tizen/capmgr";
 
+std::map<int, GDBusMethodInvocation*> invoc_map_;
+
 }  // namespace
 
 namespace capmgr {
@@ -76,7 +79,7 @@ void DBusService::RegisterMethodHandler(const std::string& method,
 }
 
 void DBusService::RegisterSendAppcontrolHandler(const std::string& method,
-    std::function<bool(const std::string&, const unsigned char*, size_t len)>
+    std::function<int(const std::string&, const unsigned char*, size_t len)>
     handler) {
   if (method == "SendRemoteAppControl")
     EventHandler().send_app_control_event.connect(handler);
@@ -88,6 +91,23 @@ void DBusService::RegisterSendFileHandler(const std::string& method,
     EventHandler().send_file_event.connect(handler);
 }
 
+void DBusService::SendAppControlReply(int msg_id, const unsigned char* data,
+    size_t len) {
+  auto it = invoc_map_.find(msg_id);
+  if (it == invoc_map_.end()) {
+    LOG(ERROR) << "Cannot find msg_id(" << msg_id << ")";
+    return;
+  } else {
+    LOG(INFO) << "Got a response for msg_id[" << msg_id << "]";
+  }
+
+  GVariantBuilder* array_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+  for (unsigned int i = 0 ; i < len; i++)
+    g_variant_builder_add(array_builder, "y", data[i]);
+  GVariant* gv = g_variant_new("(ayu)", array_builder, len);
+  g_dbus_method_invocation_return_value(it->second, gv);
+}
+
 bool DBusService::HandleDiscoverUnownedDevices(GVariant* params,
     GDBusMethodInvocation* invocation) {
   EventHandler().on_event();
@@ -124,10 +144,17 @@ bool DBusService::HandleSendRemoteAppControl(GVariant* params,
   }
   g_variant_iter_free(iter);
 
-  boost::optional<bool> r =
+  boost::optional<int> r =
       EventHandler().send_app_control_event(device_id, data, len);
-  bool res = r ? *r : false;
-  g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", res));
+  if (!r) {
+    LOG(ERROR) << "Failed to send app control";
+    // need to return error to client
+    return false;
+  }
+
+  int msg_id = *r;
+  LOG(INFO) << "Waiting response for msg_id[" << msg_id << "]";
+  invoc_map_.emplace(*r, invocation);
   return true;
 }
 
index 1f3510d5b87a92b86691d4748327252de68caed1..12e4e82efdd7b12d92cd2884a85203f7a9a12a69 100644 (file)
 
 #include <boost/signals2.hpp>
 
+#include <map>
 #include <string>
 
 namespace capmgr {
 
 class Capability;
 
+
 class DBusService {
   typedef std::function<void(unsigned char*, int)> AppControlHandler;
 
@@ -27,17 +29,20 @@ class DBusService {
   static void RegisterMethodHandler(const std::string& method,
       std::function<void()> handler);
   static void RegisterSendAppcontrolHandler(const std::string& method,
-      std::function<bool(const std::string&, const unsigned char*,
+      std::function<int(const std::string&, const unsigned char*,
           size_t)> handler);
   static void RegisterSendFileHandler(const std::string& method,
       std::function<bool(const std::string&, const std::string&)> handler);
 
+  static void SendAppControlReply(int msg_id, const unsigned char* data,
+      size_t len);
+
  private:
   class DBusMethodHandler {
    public:
     boost::signals2::signal<void()> on_event;
     boost::signals2::signal<void()> on_event2;
-    boost::signals2::signal<bool(const std::string&, const unsigned char*,
+    boost::signals2::signal<int(const std::string&, const unsigned char*,
         size_t)> send_app_control_event;
     boost::signals2::signal<void(const std::string&,
         const std::string&)> send_file_event;
index 98cb0c19804d7604763fe045aa6218c1f8a81e3f..9657757c929854a22f78a0a9e64d765f484e6d59 100644 (file)
@@ -20,6 +20,7 @@
 #include "common/appcontrol_manager.h"
 #include "common/capability.h"
 #include "common/capability_manager.h"
+#include "common/dbus_service.h"
 #include "common/remote_device_manager.h"
 #include "common/utils/glist_range.h"
 #include "common/utils/logging.h"
@@ -63,6 +64,9 @@ void SendDataFinishCb(int result, mdg_device_h device, char* channel_id,
   LOG(INFO) << "SendDataFinishCb called. "
             << "result: " << result
             << ", msg_id: " << msg_id;
+
+  // return to dbus method caller
+  capmgr::DBusService::SendAppControlReply(msg_id, data, len);
 }
 
 void SendFileProgressCb(const char* file_path, int64_t send_size,
@@ -150,9 +154,18 @@ bool MDGManager::Initialize() {
     return false;
   }
 
+  AppControlManager::RegisterAppControlReplyHandler(
+      std::bind(&MDGManager::SendAppControlReply, this, std::placeholders::_1,
+          std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
+
   return true;
 }
 
+struct sender_info {
+  std::string device_id;
+  int msg_id;
+};
+
 void MDGManager::ReceiveDataCb(int result, char* device_id, char* channel_id,
     int msg_id, unsigned char* data, int len, void* user_data) {
   LOG(INFO) << "ReceiveDataCb called. "
@@ -184,8 +197,14 @@ void MDGManager::ReceiveDataCb(int result, char* device_id, char* channel_id,
     RemoteDeviceManager::RegisterRemoteCapabilities(device_id, caps);
   } else if (cmd == Command::SEND_APPCONTROL) {
     unsigned char* data = p;
-    if (!AppControlManager::LaunchApplication(data, datasize))
+    // sender_info will be freed at SendAppControlReply()
+    struct sender_info* info = new struct sender_info;
+    info->device_id = device_id;
+    info->msg_id = msg_id;
+    if (!AppControlManager::GetAppControlManager().LaunchApplication(
+        data, datasize, info))
       LOG(ERROR) << "Failed to launch application";
+    return;
   }
 
   // FIXME(jeremy.jang): temporary code. need to send proper reply packet.
@@ -381,17 +400,25 @@ mdg_device_h MDGManager::GetDeviceHandleFromId(const std::string& device_id) {
   return device;
 }
 
-bool MDGManager::SendData(const std::string& device_id, Command cmd,
-    const unsigned char* data, size_t len) {
-  LOG(INFO) << "SendData to " << device_id;
+void MDGManager::SendAppControlReply(unsigned char* b, size_t len, int result,
+    void* data) {
+  struct sender_info* info = reinterpret_cast<struct sender_info*>(data);
 
-  mdg_device_h device = nullptr;
+  // TODO(jeremy.jang): need to send aul_svc result code...
+  SendReplyData(info->device_id, Command::SEND_APPCONTROL_REPLY, b, len,
+      info->msg_id);
+
+  delete info;
+}
 
-  device = GetDeviceHandleFromId(device_id);
+int MDGManager::SendData(const std::string& device_id, Command cmd,
+    const unsigned char* data, size_t len) {
+  LOG(INFO) << "SendData to " << device_id;
 
+  mdg_device_h device = GetDeviceHandleFromId(device_id);
   if (!device) {
     LOG(ERROR) << "There is no such device in list!";
-    return false;
+    return -1;
   }
 
   // packet format
@@ -417,6 +444,37 @@ bool MDGManager::SendData(const std::string& device_id, Command cmd,
 
   delete buf;
 
+  return msg_id;
+}
+
+bool MDGManager::SendReplyData(const std::string& device_id, Command cmd,
+    const unsigned char* data, size_t len, int msg_id) {
+  LOG(INFO) << "SendReplyData to " << device_id;
+
+  mdg_device_h device = GetDeviceHandleFromId(device_id);
+  if (!device) {
+    LOG(ERROR) << "There is no such device in list!";
+    return false;
+  }
+
+  size_t datasize = sizeof(Command) + sizeof(size_t) + len;
+  unsigned char* buf = new unsigned char[datasize];
+  unsigned char* p = buf;
+
+  memcpy(p, &cmd, sizeof(Command));
+  p = p + sizeof(Command);
+  memcpy(p, &len, sizeof(size_t));
+  p = p + sizeof(size_t);
+  memcpy(p, data, len);
+
+  int ret = mdg_device_send_response(mdg_handle_,
+      const_cast<char*>(device_id.c_str()), const_cast<char*>(kChannelId),
+      msg_id, buf, datasize);
+  if (ret != MDG_ERROR_NONE)
+    LOG(ERROR) << "Failed to send response to " << device_id;
+
+  delete buf;
+
   return true;
 }
 
@@ -425,10 +483,7 @@ bool MDGManager::SendFile(const std::string& device_id,
   LOG(INFO) << "SendFile to " << device_id;
   LOG(INFO) << "File: " << file_path;
 
-  mdg_device_h device = nullptr;
-
-  device = GetDeviceHandleFromId(device_id);
-
+  mdg_device_h device = GetDeviceHandleFromId(device_id);
   if (!device) {
     LOG(ERROR) << "There is no such device in list!";
     return false;
@@ -444,6 +499,7 @@ bool MDGManager::SendFile(const std::string& device_id,
   return true;
 }
 
+
 void MDGManager::FindDevices() {
   int ret = mdg_device_find(mdg_handle_, kRequestTimeout, false,
       &MDGManager::DeviceFoundCb, &MDGManager::DeviceFinishCb, this);
@@ -482,7 +538,7 @@ void MDGManager::ExchangeCapabilities() {
   delete caps_data;
 }
 
-bool MDGManager::SendAppControl(const std::string& device_id,
+int MDGManager::SendAppControl(const std::string& device_id,
     const unsigned char* appcontrol, size_t len) {
   return SendData(device_id, Command::SEND_APPCONTROL, appcontrol, len);
 }
index a2506a08e19475a34926c34048c6b9cbb94d8528..43193726bc2683f25a715378b08ee6e7879f297e 100644 (file)
@@ -27,20 +27,26 @@ class MDGManager : public ConnectionManager {
   void FindDevices() override;
   void RegisterEndpoint() override;
   void ExchangeCapabilities() override;
-  bool SendAppControl(const std::string& device_id,
+  int SendAppControl(const std::string& device_id,
       const unsigned char* appcontrol, size_t len) override;
 
  private:
   enum class Command : unsigned char {
     EXCHANGE_CAPS,
     SEND_APPCONTROL,
+    SEND_APPCONTROL_REPLY,
   };
 
+  void SendAppControlReply(unsigned char* b, size_t len, int result,
+      void* data);
+
   bool Initialize();
   bool CreateGroup();
   bool AddDevice(const mdg_device_h device);
-  bool SendData(const std::string& device_id, Command cmd,
+  int SendData(const std::string& device_id, Command cmd,
       const unsigned char* data, size_t len);
+  bool SendReplyData(const std::string& device_id, Command cmd,
+      const unsigned char* data, size_t len, int msg_id);
   bool SendFile(const std::string& device_id, const std::string& file_path);
   mdg_device_h GetDeviceHandleFromId(const std::string& device_id);
 
index c0dfb239591f74f009aad1693fb1f708918e589e..4d34d83afd046e3e2a0de7ce8ab5a830ebdbe3ff 100644 (file)
@@ -256,6 +256,17 @@ int Client::AppControlCb(const capmgr_app_control_h request,
     const capmgr_app_control_h reply, capmgr_app_control_result_e result,
     void* user_data) {
   std::cout << "AppControlCb called" << std::endl;
+
+  char* data;
+  int ret = capmgr_app_control_get_extra_data(reply, "REPLY", &data);
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "Failed to get extra data from appcontrol reply: " << ret
+              << std::endl;
+  } else {
+    std::cout << "Get reply from remote app: " << data << std::endl;
+    free(data);
+  }
+
   Client* client = static_cast<Client*>(user_data);
   client->Quit();
   return 0;