}
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;
}
}
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;
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);
#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);
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
#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"
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
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;
" <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'/>"
const char kDBusServiceName[] = "org.tizen.capmgr";
const char kDBusObjectPath[] = "/org/tizen/capmgr";
+std::map<int, GDBusMethodInvocation*> invoc_map_;
+
} // namespace
namespace capmgr {
}
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);
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();
}
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;
}
#include <boost/signals2.hpp>
+#include <map>
#include <string>
namespace capmgr {
class Capability;
+
class DBusService {
typedef std::function<void(unsigned char*, int)> AppControlHandler;
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;
#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"
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,
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. "
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.
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
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;
}
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;
return true;
}
+
void MDGManager::FindDevices() {
int ret = mdg_device_find(mdg_handle_, kRequestTimeout, false,
&MDGManager::DeviceFoundCb, &MDGManager::DeviceFinishCb, this);
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);
}
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);
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;