/*
- * Copyright (c) 2015 - 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
+#include "include/aul_app_com.h"
+
#include <bundle_cpp.h>
#include <bundle_internal.h>
#include <mutex>
#include <string>
+#include "app_request.h"
#include "aul_api.h"
#include "aul_util.h"
#include "include/aul.h"
-#include "include/aul_app_com.h"
#include "include/aul_cmd.h"
#include "launch.h"
+using namespace aul::internal;
+
namespace {
class AppComConnection {
Context context;
+int AppComCreate(const char* endpoint,
+ aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
+ bool sync, aul_app_com_connection_h* connection) {
+ if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
+ _E("Invalid parameter");
+ return AUL_R_EINVAL;
+ }
+
+ if (!aul_is_initialized()) {
+ if (aul_launch_init(nullptr, nullptr) < 0)
+ return AUL_R_ENOINIT;
+ }
+
+ tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
+ if (permission) {
+ auto* handle = static_cast<AppComPermission*>(permission);
+ auto option = handle->GetPropagationOption();
+ if (option) {
+ auto* p = reinterpret_cast<unsigned char*>(&option);
+ std::vector<unsigned char> bytes;
+ std::copy(p, p + sizeof(option), std::back_inserter(bytes));
+ b.Add(AUL_K_COM_PROPAGATE, bytes);
+ }
+
+ if (!handle->GetPrivilege().empty())
+ b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
+ }
+
+ int ret = AppRequest(APP_COM_CREATE, getuid())
+ .With(std::move(b))
+ .SendSimply(sync ? AUL_SOCK_NONE : AUL_SOCK_NOREPLY);
+ if (ret == 0) {
+ *connection = static_cast<aul_app_com_connection_h>(
+ context.AddConnection(endpoint, callback, user_data));
+ }
+
+ return ret;
+}
+
} // namespace
int app_com_recv(bundle* b) {
return AUL_R_OK;
}
-static int AppComCreate(const char* endpoint,
- aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
- bool sync, aul_app_com_connection_h* connection) {
- if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
- _E("Invalid parameter");
- return AUL_R_EINVAL;
- }
-
- if (!aul_is_initialized()) {
- if (aul_launch_init(nullptr, nullptr) < 0)
- return AUL_R_ENOINIT;
- }
-
- tizen_base::Bundle b;
- b.Add(AUL_K_COM_ENDPOINT, endpoint);
-
- if (permission) {
- auto* handle = static_cast<AppComPermission*>(permission);
- auto option = handle->GetPropagationOption();
- if (option) {
- auto* p = reinterpret_cast<unsigned char*>(&option);
- std::vector<unsigned char> bytes;
- std::copy(p, p + sizeof(option), std::back_inserter(bytes));
- b.Add(AUL_K_COM_PROPAGATE, bytes);
- }
-
- if (!handle->GetPrivilege().empty())
- b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
- }
-
- int ret;
- if (sync) {
- ret = app_send_cmd(AUL_UTIL_PID, APP_COM_CREATE, b.GetHandle());
- } else {
- ret = app_send_cmd_with_noreply(AUL_UTIL_PID, APP_COM_CREATE,
- b.GetHandle());
- }
-
- if (ret == 0) {
- *connection = static_cast<aul_app_com_connection_h>(
- context.AddConnection(endpoint, callback, user_data));
- }
-
- return ret;
-}
-
extern "C" API int aul_app_com_create(const char* endpoint,
aul_app_com_permission_h permission, app_com_cb callback,
void* user_data, aul_app_com_connection_h* connection) {
return AUL_R_ENOINIT;
}
- tizen_base::Bundle b;
- b.Add(AUL_K_COM_ENDPOINT, endpoint);
+ tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
if (filter)
b.Add(AUL_K_COM_FILTER, filter);
- int ret = app_send_cmd(AUL_UTIL_PID, APP_COM_JOIN, b.GetHandle());
+ int ret = AppRequest(APP_COM_JOIN, getuid())
+ .With(std::move(b))
+ .SendSimply();
if (ret == 0) {
*connection = static_cast<aul_app_com_connection_h>(
context.AddConnection(endpoint, callback, user_data));
if (endpoint == nullptr || envelope == nullptr)
return AUL_R_EINVAL;
- bundle_del(envelope, AUL_K_COM_ENDPOINT);
- bundle_add(envelope, AUL_K_COM_ENDPOINT, endpoint);
- return app_send_cmd(AUL_UTIL_PID, APP_COM_SEND, envelope);
+ std::string com_endpoint;
+ tizen_base::Bundle b(envelope, false, false);
+ bundle_type type = b.GetType(AUL_K_COM_ENDPOINT);
+ if (type != BUNDLE_TYPE_NONE) {
+ com_endpoint = b.GetString(AUL_K_COM_ENDPOINT);
+ b.Delete(AUL_K_COM_ENDPOINT);
+ }
+
+ b.Add(AUL_K_COM_ENDPOINT, endpoint);
+
+ int ret = AppRequest(APP_COM_SEND, getuid())
+ .With(std::move(b))
+ .SendSimply();
+ if (type != BUNDLE_TYPE_NONE) {
+ b.Delete(AUL_K_COM_ENDPOINT);
+ b.Add(AUL_K_COM_ENDPOINT, com_endpoint);
+ }
+
+ return ret;
}
extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
conn->Disable();
- std::string endpoint = conn->GetEndpoint();
+
g_idle_add_full(G_PRIORITY_HIGH, [](gpointer user_data) -> gboolean {
auto* conn = static_cast<AppComConnection*>(user_data);
+ std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
+ std::string endpoint = conn->GetEndpoint();
context.RemoveConnection(conn);
+
+ if (context.ExistConnection(endpoint))
+ return G_SOURCE_REMOVE;
+
+ tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
+ int ret = AppRequest(APP_COM_LEAVE, getuid())
+ .With(std::move(b))
+ .SendSimply();
+ if (ret != 0)
+ _E("Failed to send leave request. error(%d)", ret);
+
return G_SOURCE_REMOVE;
}, connection, nullptr);
- if (context.ExistConnection(endpoint))
- return AUL_R_OK;
-
- tizen_base::Bundle b;
- b.Add(AUL_K_COM_ENDPOINT, endpoint);
- return app_send_cmd(AUL_UTIL_PID, APP_COM_LEAVE, b.GetHandle());
+ return AUL_R_OK;
}
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aul.h>
+#include <aul_app_com.h>
+#include <aul_cmd.h>
+#include <aul_sock.h>
+#include <gtest/gtest.h>
+
+#include <bundle_cpp.h>
+
+#include <memory>
+
+#include "mock/mock_hook.h"
+#include "mock/socket_mock.h"
+#include "mock/test_fixture.h"
+#include "src/launch.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::Invoke;
+
+namespace {
+
+constexpr const char kPrivilegeAppmanagerLaunch[] =
+ "http://tizen.org/privilege/appmanager.launch";
+
+class Mocks : virtual public ::testing::NiceMock<SocketMock> {};
+
+int AppComCb(const char* endpoint, aul_app_com_result_e result,
+ bundle* envelope, void* user_data) {
+ return 0;
+}
+
+} // namespace
+
+class AppComTest : public TestFixture {
+ public:
+ AppComTest() : TestFixture(std::make_unique<::Mocks>()) {}
+
+ virtual void SetUp() {
+ loop_ = g_main_loop_new(nullptr, FALSE);
+ permission_ = aul_app_com_permission_create();
+ }
+
+ virtual void TearDown() {
+ if (permission_ != nullptr) {
+ aul_app_com_permission_destroy(permission_);
+ permission_ = nullptr;
+ }
+
+ if (loop_ != nullptr) {
+ g_main_loop_unref(loop_);
+ loop_ = nullptr;
+ }
+ }
+
+ void RunMainLoop() {
+ g_main_loop_run(loop_);
+ }
+
+ void QuitMainLoop() {
+ g_main_loop_quit(loop_);
+ }
+
+ std::shared_ptr<app_pkt_t> MakePacket(tizen_base::Bundle b) {
+ auto raw = b.ToRaw();
+ app_pkt_t* pkt =
+ static_cast<app_pkt_t*>(calloc(1, sizeof(app_pkt_t) + raw.second));
+ if (pkt == nullptr)
+ return nullptr;
+
+ pkt->opt = AUL_SOCK_BUNDLE;
+ pkt->cmd = AUL_R_OK;
+ pkt->len = raw.second;
+ memcpy(pkt->data, raw.first.get(), raw.second);
+
+ return std::shared_ptr<app_pkt_t>(pkt, free);
+ }
+
+ std::shared_ptr<app_pkt_t> MakePacket(std::string str) {
+ app_pkt_t* pkt = static_cast<app_pkt_t*>(
+ calloc(1, sizeof(app_pkt_t) + str.length() + 1));
+ if (pkt == nullptr)
+ return nullptr;
+
+ pkt->opt = AUL_SOCK_NONE;
+ pkt->cmd = APP_GET_INFO_OK;
+ pkt->len = str.length() + 1;
+ memcpy(pkt->data, str.c_str(), str.length());
+
+ return std::shared_ptr<app_pkt_t>(pkt, free);
+ }
+
+ bool touched_ = false;
+ aul_app_com_permission_h permission_ = nullptr;
+
+ private:
+ GMainLoop* loop_ = nullptr;
+};
+
+TEST_F(AppComTest, aul_app_com_permission_create_P) {
+ auto permission = aul_app_com_permission_create();
+ EXPECT_NE(permission, nullptr);
+
+ aul_app_com_permission_destroy(permission);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_destroy_P) {
+ aul_app_com_permission_destroy(permission_);
+ permission_ = nullptr;
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_propagation_P) {
+ int ret = aul_app_com_permission_set_propagation(permission_,
+ AUL_APP_COM_PUBLIC);
+ EXPECT_EQ(ret, AUL_R_OK);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_propagation_N) {
+ int ret = aul_app_com_permission_set_propagation(nullptr, AUL_APP_COM_PUBLIC);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_privilage_P) {
+ int ret = aul_app_com_permission_set_privilege(permission_,
+ kPrivilegeAppmanagerLaunch);
+ EXPECT_EQ(ret, AUL_R_OK);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_privilege_N) {
+ int ret = aul_app_com_permission_set_privilege(nullptr,
+ kPrivilegeAppmanagerLaunch);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ ret = aul_app_com_permission_set_privilege(permission_, nullptr);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_create_P) {
+ int cmd = -1;
+ int opt = -1;
+ bundle* kb = nullptr;
+
+ ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+ .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+ -> ssize_t {
+ const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+ cmd = pkt->cmd;
+ opt = pkt->opt;
+
+ if (cmd == APP_COM_CREATE)
+ kb = bundle_decode(pkt->data, pkt->len);
+
+ if (cmd == APP_COM_LEAVE)
+ QuitMainLoop();
+
+ return n;
+ }));
+ ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+ .WillByDefault(
+ Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+ int ret = 0;
+ memcpy(buf, &ret, sizeof(int));
+ return sizeof(int);
+ }));
+
+ aul_app_com_connection_h connection = nullptr;
+ int ret = aul_app_com_create("app_com_create", nullptr, AppComCb, this,
+ &connection);
+ EXPECT_NE(kb, nullptr);
+ tizen_base::Bundle b(kb, false, true);
+
+ EXPECT_NE(connection, nullptr);
+ EXPECT_EQ(ret, AUL_R_OK);
+ EXPECT_EQ(cmd, APP_COM_CREATE);
+ EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+ EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_create");
+
+ aul_app_com_leave(connection);
+ RunMainLoop();
+}
+
+TEST_F(AppComTest, aul_app_com_create_N) {
+ int ret = aul_app_com_create("app_com_create_N", nullptr, AppComCb, this,
+ nullptr);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ aul_app_com_connection_h connection = nullptr;
+ ret = aul_app_com_create("app_com_create_N", nullptr, nullptr, this,
+ &connection);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ ret = aul_app_com_create(nullptr, nullptr, AppComCb, this, &connection);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_create_async_P) {
+ int cmd = -1;
+ int opt = -1;
+ bundle* kb = nullptr;
+
+ ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+ .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+ -> ssize_t {
+ const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+ cmd = pkt->cmd;
+ opt = pkt->opt;
+
+ if (cmd == APP_COM_CREATE)
+ kb = bundle_decode(pkt->data, pkt->len);
+
+ if (cmd == APP_COM_LEAVE)
+ QuitMainLoop();
+
+ return n;
+ }));
+ ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+ .WillByDefault(
+ Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+ int ret = 0;
+ memcpy(buf, &ret, sizeof(int));
+ return sizeof(int);
+ }));
+
+ aul_app_com_connection_h connection = nullptr;
+ int ret = aul_app_com_create_async("app_com_create_async", nullptr, AppComCb,
+ this, &connection);
+ EXPECT_NE(kb, nullptr);
+ tizen_base::Bundle b(kb, false, true);
+
+ EXPECT_NE(connection, nullptr);
+ EXPECT_EQ(ret, AUL_R_OK);
+ EXPECT_EQ(cmd, APP_COM_CREATE);
+ EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NOREPLY));
+ EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_create_async");
+
+ aul_app_com_leave(connection);
+ RunMainLoop();
+}
+
+TEST_F(AppComTest, aul_app_com_create_async_N) {
+ int ret = aul_app_com_create_async("app_com_create_async_N", nullptr,
+ AppComCb, this, nullptr);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ aul_app_com_connection_h connection = nullptr;
+ ret = aul_app_com_create_async("app_com_create_async_N", nullptr, nullptr,
+ this, &connection);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ ret = aul_app_com_create_async(nullptr, nullptr, AppComCb, this, &connection);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_join_P) {
+ int cmd = -1;
+ int opt = -1;
+ bundle* kb = nullptr;
+
+ ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+ .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+ -> ssize_t {
+ const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+ cmd = pkt->cmd;
+ opt = pkt->opt;
+
+ if (cmd == APP_COM_JOIN)
+ kb = bundle_decode(pkt->data, pkt->len);
+
+ if (cmd == APP_COM_LEAVE)
+ QuitMainLoop();
+
+ return n;
+ }));
+ ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+ .WillByDefault(
+ Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+ int ret = 0;
+ memcpy(buf, &ret, sizeof(int));
+ return sizeof(int);
+ }));
+
+ aul_app_com_connection_h connection = nullptr;
+ int ret = aul_app_com_join("app_com_join", nullptr, AppComCb,
+ this, &connection);
+ EXPECT_NE(kb, nullptr);
+ tizen_base::Bundle b(kb, false, true);
+
+ EXPECT_NE(connection, nullptr);
+ EXPECT_EQ(ret, AUL_R_OK);
+ EXPECT_EQ(cmd, APP_COM_JOIN);
+ EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+ EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_join");
+
+ aul_app_com_leave(connection);
+ RunMainLoop();
+}
+
+TEST_F(AppComTest, aul_app_com_join_N) {
+ int ret = aul_app_com_join("app_com_join_N", nullptr, AppComCb, this,
+ nullptr);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ aul_app_com_connection_h connection = nullptr;
+ ret = aul_app_com_join("app_com_join_N", nullptr, nullptr, this, &connection);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ ret = aul_app_com_join(nullptr, nullptr, AppComCb, this, &connection);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_send_P) {
+ int cmd = -1;
+ int opt = -1;
+ bundle* kb = nullptr;
+
+ ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+ .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+ -> ssize_t {
+ const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+ cmd = pkt->cmd;
+ opt = pkt->opt;
+ kb = bundle_decode(pkt->data, pkt->len);
+ return n;
+ }));
+ ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+ .WillByDefault(
+ Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+ int ret = 0;
+ memcpy(buf, &ret, sizeof(int));
+ return sizeof(int);
+ }));
+
+ tizen_base::Bundle envelope { { "Key", "Value" } };
+ int ret = aul_app_com_send("app_com_send", envelope.GetHandle());
+ EXPECT_NE(kb, nullptr);
+ tizen_base::Bundle b(kb, false, true);
+
+ EXPECT_EQ(ret, AUL_R_OK);
+ EXPECT_EQ(cmd, APP_COM_SEND);
+ EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+ EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_send");
+ EXPECT_EQ(b.GetString("Key"), "Value");
+}
+
+TEST_F(AppComTest, aul_app_com_send_N) {
+ int ret = aul_app_com_send("app_com_send_N", nullptr);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+
+ tizen_base::Bundle envelope;
+ ret = aul_app_com_send(nullptr, envelope.GetHandle());
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_leave_P) {
+ int cmd = -1;
+ int opt = -1;
+ bundle* kb = nullptr;
+
+ ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+ .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+ -> ssize_t {
+ const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+ cmd = pkt->cmd;
+ opt = pkt->opt;
+
+ if (cmd == APP_COM_LEAVE) {
+ kb = bundle_decode(pkt->data, pkt->len);
+ QuitMainLoop();
+ }
+
+ return n;
+ }));
+ ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+ .WillByDefault(
+ Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+ int ret = 0;
+ memcpy(buf, &ret, sizeof(int));
+ return sizeof(int);
+ }));
+
+ aul_app_com_connection_h connection = nullptr;
+ int ret = aul_app_com_join("app_com_leave", nullptr, AppComCb,
+ this, &connection);
+ EXPECT_EQ(ret, AUL_R_OK);
+
+ ret = aul_app_com_leave(connection);
+ RunMainLoop();
+
+ EXPECT_NE(kb, nullptr);
+ tizen_base::Bundle b(kb, false, true);
+
+ EXPECT_NE(connection, nullptr);
+ EXPECT_EQ(ret, AUL_R_OK);
+ EXPECT_EQ(cmd, APP_COM_LEAVE);
+ EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+ EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_leave");
+}
+
+TEST_F(AppComTest, aul_app_com_leave_N) {
+ int ret = aul_app_com_leave(nullptr);
+ EXPECT_EQ(ret, AUL_R_EINVAL);
+}