Fix app com deletion
[platform/core/appfw/aul-1.git] / src / app_com.cc
1 /*
2  * Copyright (c) 2015 - 2021 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <bundle_cpp.h>
18 #include <bundle_internal.h>
19
20 #include <list>
21 #include <mutex>
22 #include <string>
23
24 #include "aul_api.h"
25 #include "aul_util.h"
26 #include "include/aul.h"
27 #include "include/aul_app_com.h"
28 #include "include/aul_cmd.h"
29 #include "launch.h"
30
31 namespace {
32
33 class AppComConnection {
34  public:
35   AppComConnection(std::string endpoint, app_com_cb cb, void* user_data)
36       : endpoint_(std::move(endpoint)),
37         cb_(cb),
38         user_data_(user_data) {
39   }
40
41   ~AppComConnection() = default;
42
43   const std::string& GetEndpoint() const {
44     return endpoint_;
45   }
46
47   void Disable() {
48     disabled_ = true;
49   }
50
51   bool IsDisabled() const {
52     return disabled_;
53   }
54
55   void Invoke(aul_app_com_result_e result, bundle* envelope) {
56     if (!disabled_ && cb_)
57       cb_(endpoint_.c_str(), result, envelope, user_data_);
58   }
59
60  private:
61   bool disabled_ = false;
62   std::string endpoint_;
63   app_com_cb cb_;
64   void* user_data_;
65 };
66
67 class AppComPermission {
68  public:
69   AppComPermission() : option_(AUL_APP_COM_PUBLIC) {}
70   ~AppComPermission() {}
71
72   void SetPrivilege(std::string privilege) {
73     privilege_ = std::move(privilege);
74   }
75
76   void SetPropagationOption(aul_app_com_propagate_option_e option) {
77     option_ = option;
78   }
79
80   const std::string& GetPrivilege() const {
81     return privilege_;
82   }
83
84   aul_app_com_propagate_option_e GetPropagationOption() const {
85     return option_;
86   }
87
88  private:
89   std::string privilege_;
90   aul_app_com_propagate_option_e option_;
91 };
92
93 class Context {
94  public:
95   Context() {}
96   ~Context() {}
97
98   int Receive(bundle* b) {
99     const char* val = bundle_get_val(b, AUL_K_COM_ENDPOINT);
100     if (val == nullptr)
101       return -1;
102
103     size_t result_size = 0;
104     aul_app_com_result_e* result = nullptr;
105     int ret = bundle_get_byte(b, AUL_K_COM_RESULT,
106         reinterpret_cast<void**>(&result), &result_size);
107     if (ret != BUNDLE_ERROR_NONE)
108       return -1;
109
110     std::string endpoint(val);
111
112     std::lock_guard<std::recursive_mutex> lock(mutex_);
113     auto iter = conns_.begin();
114     while (iter != conns_.end()) {
115       auto& conn = *iter;
116       iter++;
117       if (conn->GetEndpoint() == endpoint)
118         conn->Invoke(*result, b);
119     }
120
121     return 0;
122   }
123
124   AppComConnection* AddConnection(std::string endpoint, app_com_cb cb,
125       void* user_data) {
126     auto* conn = new (std::nothrow) AppComConnection(endpoint, cb, user_data);
127     if (conn == nullptr)
128       return nullptr;
129
130     std::lock_guard<std::recursive_mutex> lock(mutex_);
131     conns_.emplace_back(conn);
132     return conn;
133   }
134
135   void RemoveConnection(AppComConnection* conn) {
136     std::lock_guard<std::recursive_mutex> lock(mutex_);
137     auto iter = conns_.begin();
138     while (iter != conns_.end()) {
139       if ((*iter).get() == conn) {
140         iter = conns_.erase(iter);
141         break;
142       } else {
143         iter++;
144       }
145     }
146   }
147
148   bool ExistConnection(const std::string& endpoint) {
149     std::lock_guard<std::recursive_mutex> lock(mutex_);
150     for (auto& conn : conns_) {
151       if (conn->GetEndpoint() == endpoint && !conn->IsDisabled())
152         return true;
153     }
154
155     return false;
156   }
157
158   bool ExistConnection(AppComConnection* conn) {
159     std::lock_guard<std::recursive_mutex> lock(mutex_);
160     if (conn->IsDisabled())
161       return false;
162
163     for (auto& i : conns_) {
164       if (i.get() == conn)
165         return true;
166     }
167
168     return false;
169   }
170
171   std::recursive_mutex& GetMutex() const {
172     return mutex_;
173   }
174
175  private:
176   std::list<std::unique_ptr<AppComConnection>> conns_;
177   mutable std::recursive_mutex mutex_;
178 };
179
180 Context context;
181
182 }  // namespace
183
184 int app_com_recv(bundle* b) {
185   if (b == nullptr)
186     return -1;
187
188   return context.Receive(b);
189 }
190
191 extern "C" API aul_app_com_permission_h aul_app_com_permission_create() {
192   auto* handle = new (std::nothrow) AppComPermission();
193   return static_cast<aul_app_com_permission_h>(handle);
194 }
195
196 extern "C" API void aul_app_com_permission_destroy(
197     aul_app_com_permission_h permission) {
198   if (permission == nullptr)
199     return;
200
201   auto* handle = static_cast<AppComPermission*>(permission);
202   delete handle;
203 }
204
205 extern "C" API int aul_app_com_permission_set_propagation(
206     aul_app_com_permission_h permission,
207     aul_app_com_propagate_option_e option) {
208   if (permission == nullptr)
209     return AUL_R_EINVAL;
210
211   auto* handle = static_cast<AppComPermission*>(permission);
212   handle->SetPropagationOption(option);
213   return AUL_R_OK;
214 }
215
216 extern "C" API int aul_app_com_permission_set_privilege(
217     aul_app_com_permission_h permission, const char* privilege) {
218   if (permission == nullptr || privilege == nullptr)
219     return AUL_R_EINVAL;
220
221   auto* handle = static_cast<AppComPermission*>(permission);
222   handle->SetPrivilege(privilege);
223   return AUL_R_OK;
224 }
225
226 static int AppComCreate(const char* endpoint,
227     aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
228     bool sync, aul_app_com_connection_h* connection) {
229   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
230     _E("Invalid parameter");
231     return AUL_R_EINVAL;
232   }
233
234   if (!aul_is_initialized()) {
235     if (aul_launch_init(nullptr, nullptr) < 0)
236       return AUL_R_ENOINIT;
237   }
238
239   tizen_base::Bundle b;
240   b.Add(AUL_K_COM_ENDPOINT, endpoint);
241
242   if (permission) {
243     auto* handle = static_cast<AppComPermission*>(permission);
244     auto option = handle->GetPropagationOption();
245     if (option) {
246       auto* p = reinterpret_cast<unsigned char*>(&option);
247       std::vector<unsigned char> bytes;
248       std::copy(p, p + sizeof(option), std::back_inserter(bytes));
249       b.Add(AUL_K_COM_PROPAGATE, bytes);
250     }
251
252     if (!handle->GetPrivilege().empty())
253       b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
254   }
255
256   int ret;
257   if (sync) {
258     ret = app_send_cmd(AUL_UTIL_PID, APP_COM_CREATE, b.GetHandle());
259   } else {
260     ret = app_send_cmd_with_noreply(AUL_UTIL_PID, APP_COM_CREATE,
261         b.GetHandle());
262   }
263
264   if (ret == 0) {
265     *connection = static_cast<aul_app_com_connection_h>(
266         context.AddConnection(endpoint, callback, user_data));
267   }
268
269   return ret;
270 }
271
272 extern "C" API int aul_app_com_create(const char* endpoint,
273     aul_app_com_permission_h permission, app_com_cb callback,
274     void* user_data, aul_app_com_connection_h* connection) {
275   return AppComCreate(endpoint, permission, callback, user_data,
276       true, connection);
277 }
278
279 extern "C" API int aul_app_com_create_async(const char* endpoint,
280     aul_app_com_permission_h permission, app_com_cb callback,
281     void* user_data, aul_app_com_connection_h* connection) {
282   return AppComCreate(endpoint, permission, callback, user_data,
283       false, connection);
284 }
285
286 extern "C" API int aul_app_com_join(const char* endpoint, const char* filter,
287     app_com_cb callback, void* user_data,
288     aul_app_com_connection_h* connection) {
289   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
290     _E("Invalid parameter");
291     return AUL_R_EINVAL;
292   }
293
294   if (!aul_is_initialized()) {
295     if (aul_launch_init(nullptr, nullptr) < 0)
296       return AUL_R_ENOINIT;
297   }
298
299   tizen_base::Bundle b;
300   b.Add(AUL_K_COM_ENDPOINT, endpoint);
301   if (filter)
302     b.Add(AUL_K_COM_FILTER, filter);
303
304   int ret = app_send_cmd(AUL_UTIL_PID, APP_COM_JOIN, b.GetHandle());
305   if (ret == 0) {
306     *connection = static_cast<aul_app_com_connection_h>(
307         context.AddConnection(endpoint, callback, user_data));
308   }
309
310   return ret;
311 }
312
313 extern "C" API int aul_app_com_send(const char* endpoint, bundle* envelope) {
314   if (endpoint == nullptr || envelope == nullptr)
315     return AUL_R_EINVAL;
316
317   bundle_del(envelope, AUL_K_COM_ENDPOINT);
318   bundle_add(envelope, AUL_K_COM_ENDPOINT, endpoint);
319   return app_send_cmd(AUL_UTIL_PID, APP_COM_SEND, envelope);
320 }
321
322 extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
323   if (connection == nullptr)
324     return AUL_R_EINVAL;
325
326   auto* conn = static_cast<AppComConnection*>(connection);
327   if (!context.ExistConnection(conn)) {
328     _E("Invalid parameter");
329     return AUL_R_EINVAL;
330   }
331
332   std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
333   conn->Disable();
334   std::string endpoint = conn->GetEndpoint();
335   g_idle_add_full(G_PRIORITY_HIGH, [](gpointer user_data) -> gboolean {
336         auto* conn = static_cast<AppComConnection*>(user_data);
337         context.RemoveConnection(conn);
338         return G_SOURCE_REMOVE;
339       }, connection, nullptr);
340
341   if (context.ExistConnection(endpoint))
342     return AUL_R_OK;
343
344   tizen_base::Bundle b;
345   b.Add(AUL_K_COM_ENDPOINT, endpoint);
346   return app_send_cmd(AUL_UTIL_PID, APP_COM_LEAVE, b.GetHandle());
347 }