Fix static analysis issue
[platform/core/appfw/aul-1.git] / src / app_com.cc
1 /*
2  * Copyright (c) 2015 - 2022 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 "include/aul_app_com.h"
18
19 #include <bundle_cpp.h>
20 #include <bundle_internal.h>
21
22 #include <list>
23 #include <mutex>
24 #include <string>
25
26 #include "app_request.h"
27 #include "aul_api.h"
28 #include "aul_util.h"
29 #include "include/aul.h"
30 #include "include/aul_cmd.h"
31 #include "launch.h"
32
33 using namespace aul::internal;
34
35 namespace {
36
37 class AppComConnection {
38  public:
39   AppComConnection(std::string endpoint, app_com_cb cb, void* user_data)
40       : endpoint_(std::move(endpoint)),
41         cb_(cb),
42         user_data_(user_data) {
43   }
44
45   ~AppComConnection() = default;
46
47   const std::string& GetEndpoint() const {
48     return endpoint_;
49   }
50
51   void Disable() {
52     disabled_ = true;
53   }
54
55   bool IsDisabled() const {
56     return disabled_;
57   }
58
59   void Invoke(aul_app_com_result_e result, bundle* envelope) {
60     if (!disabled_ && cb_)
61       cb_(endpoint_.c_str(), result, envelope, user_data_);
62   }
63
64  private:
65   bool disabled_ = false;
66   std::string endpoint_;
67   app_com_cb cb_;
68   void* user_data_;
69 };
70
71 class AppComPermission {
72  public:
73   AppComPermission() : option_(AUL_APP_COM_PUBLIC) {}
74   ~AppComPermission() {}
75
76   void SetPrivilege(std::string privilege) {
77     privilege_ = std::move(privilege);
78   }
79
80   void SetPropagationOption(aul_app_com_propagate_option_e option) {
81     option_ = option;
82   }
83
84   const std::string& GetPrivilege() const {
85     return privilege_;
86   }
87
88   aul_app_com_propagate_option_e GetPropagationOption() const {
89     return option_;
90   }
91
92  private:
93   std::string privilege_;
94   aul_app_com_propagate_option_e option_;
95 };
96
97 class Context {
98  public:
99   Context() {}
100   ~Context() {}
101
102   int Receive(bundle* b) {
103     const char* val = bundle_get_val(b, AUL_K_COM_ENDPOINT);
104     if (val == nullptr)
105       return -1;
106
107     size_t result_size = 0;
108     aul_app_com_result_e* result = nullptr;
109     int ret = bundle_get_byte(b, AUL_K_COM_RESULT,
110         reinterpret_cast<void**>(&result), &result_size);
111     if (ret != BUNDLE_ERROR_NONE)
112       return -1;
113
114     std::string endpoint(val);
115
116     std::lock_guard<std::recursive_mutex> lock(mutex_);
117     auto iter = conns_.begin();
118     while (iter != conns_.end()) {
119       auto& conn = *iter;
120       iter++;
121       if (conn->GetEndpoint() == endpoint)
122         conn->Invoke(*result, b);
123     }
124
125     return 0;
126   }
127
128   AppComConnection* AddConnection(std::string endpoint, app_com_cb cb,
129       void* user_data) {
130     auto* conn = new (std::nothrow) AppComConnection(endpoint, cb, user_data);
131     if (conn == nullptr)
132       return nullptr;
133
134     std::lock_guard<std::recursive_mutex> lock(mutex_);
135     conns_.emplace_back(conn);
136     return conn;
137   }
138
139   void RemoveConnection(AppComConnection* conn) {
140     std::lock_guard<std::recursive_mutex> lock(mutex_);
141     auto iter = conns_.begin();
142     while (iter != conns_.end()) {
143       if ((*iter).get() == conn) {
144         iter = conns_.erase(iter);
145         break;
146       } else {
147         iter++;
148       }
149     }
150   }
151
152   bool ExistConnection(const std::string& endpoint) {
153     std::lock_guard<std::recursive_mutex> lock(mutex_);
154     for (auto& conn : conns_) {
155       if (conn->GetEndpoint() == endpoint && !conn->IsDisabled())
156         return true;
157     }
158
159     return false;
160   }
161
162   bool ExistConnection(AppComConnection* conn) {
163     std::lock_guard<std::recursive_mutex> lock(mutex_);
164     if (conn->IsDisabled())
165       return false;
166
167     for (auto& i : conns_) {
168       if (i.get() == conn)
169         return true;
170     }
171
172     return false;
173   }
174
175   std::recursive_mutex& GetMutex() const {
176     return mutex_;
177   }
178
179  private:
180   std::list<std::unique_ptr<AppComConnection>> conns_;
181   mutable std::recursive_mutex mutex_;
182 };
183
184 Context context;
185
186 int AppComCreate(const char* endpoint,
187     aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
188     bool sync, aul_app_com_connection_h* connection) {
189   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
190     _E("Invalid parameter");
191     return AUL_R_EINVAL;
192   }
193
194   if (!aul_is_initialized()) {
195     if (aul_launch_init(nullptr, nullptr) < 0)
196       return AUL_R_ENOINIT;
197   }
198
199   tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
200   if (permission) {
201     auto* handle = static_cast<AppComPermission*>(permission);
202     auto option = handle->GetPropagationOption();
203     if (option) {
204       auto* p = reinterpret_cast<unsigned char*>(&option);
205       std::vector<unsigned char> bytes;
206       std::copy(p, p + sizeof(option), std::back_inserter(bytes));
207       b.Add(AUL_K_COM_PROPAGATE, bytes);
208     }
209
210     if (!handle->GetPrivilege().empty())
211       b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
212   }
213
214   int ret = AppRequest(APP_COM_CREATE, getuid())
215       .With(std::move(b))
216       .SendSimply(sync ? AUL_SOCK_NONE : AUL_SOCK_NOREPLY);
217   if (ret == 0) {
218     *connection = static_cast<aul_app_com_connection_h>(
219         context.AddConnection(endpoint, callback, user_data));
220   }
221
222   return ret;
223 }
224
225 }  // namespace
226
227 int app_com_recv(bundle* b) {
228   if (b == nullptr)
229     return -1;
230
231   return context.Receive(b);
232 }
233
234 extern "C" API aul_app_com_permission_h aul_app_com_permission_create() {
235   auto* handle = new (std::nothrow) AppComPermission();
236   return static_cast<aul_app_com_permission_h>(handle);
237 }
238
239 extern "C" API void aul_app_com_permission_destroy(
240     aul_app_com_permission_h permission) {
241   if (permission == nullptr)
242     return;
243
244   auto* handle = static_cast<AppComPermission*>(permission);
245   delete handle;
246 }
247
248 extern "C" API int aul_app_com_permission_set_propagation(
249     aul_app_com_permission_h permission,
250     aul_app_com_propagate_option_e option) {
251   if (permission == nullptr)
252     return AUL_R_EINVAL;
253
254   auto* handle = static_cast<AppComPermission*>(permission);
255   handle->SetPropagationOption(option);
256   return AUL_R_OK;
257 }
258
259 extern "C" API int aul_app_com_permission_set_privilege(
260     aul_app_com_permission_h permission, const char* privilege) {
261   if (permission == nullptr || privilege == nullptr)
262     return AUL_R_EINVAL;
263
264   auto* handle = static_cast<AppComPermission*>(permission);
265   handle->SetPrivilege(privilege);
266   return AUL_R_OK;
267 }
268
269 extern "C" API int aul_app_com_create(const char* endpoint,
270     aul_app_com_permission_h permission, app_com_cb callback,
271     void* user_data, aul_app_com_connection_h* connection) {
272   return AppComCreate(endpoint, permission, callback, user_data,
273       true, connection);
274 }
275
276 extern "C" API int aul_app_com_create_async(const char* endpoint,
277     aul_app_com_permission_h permission, app_com_cb callback,
278     void* user_data, aul_app_com_connection_h* connection) {
279   return AppComCreate(endpoint, permission, callback, user_data,
280       false, connection);
281 }
282
283 extern "C" API int aul_app_com_join(const char* endpoint, const char* filter,
284     app_com_cb callback, void* user_data,
285     aul_app_com_connection_h* connection) {
286   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
287     _E("Invalid parameter");
288     return AUL_R_EINVAL;
289   }
290
291   if (!aul_is_initialized()) {
292     if (aul_launch_init(nullptr, nullptr) < 0)
293       return AUL_R_ENOINIT;
294   }
295
296   tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
297   if (filter)
298     b.Add(AUL_K_COM_FILTER, filter);
299
300   int ret = AppRequest(APP_COM_JOIN, getuid())
301       .With(std::move(b))
302       .SendSimply();
303   if (ret == 0) {
304     *connection = static_cast<aul_app_com_connection_h>(
305         context.AddConnection(endpoint, callback, user_data));
306   }
307
308   return ret;
309 }
310
311 extern "C" API int aul_app_com_send(const char* endpoint, bundle* envelope) {
312   if (endpoint == nullptr || envelope == nullptr)
313     return AUL_R_EINVAL;
314
315   std::string com_endpoint;
316   tizen_base::Bundle b(envelope, false, false);
317   bundle_type type = b.GetType(AUL_K_COM_ENDPOINT);
318   if (type != BUNDLE_TYPE_NONE) {
319     com_endpoint = b.GetString(AUL_K_COM_ENDPOINT);
320     b.Delete(AUL_K_COM_ENDPOINT);
321   }
322
323   b.Add(AUL_K_COM_ENDPOINT, endpoint);
324
325   int ret = AppRequest(APP_COM_SEND, getuid())
326       .With(std::move(b))
327       .SendSimply();
328   if (type != BUNDLE_TYPE_NONE) {
329     bundle_del(envelope, AUL_K_COM_ENDPOINT);
330     bundle_add_str(envelope, AUL_K_COM_ENDPOINT, com_endpoint.c_str());
331   }
332
333   return ret;
334 }
335
336 extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
337   if (connection == nullptr)
338     return AUL_R_EINVAL;
339
340   auto* conn = static_cast<AppComConnection*>(connection);
341   if (!context.ExistConnection(conn)) {
342     _E("Invalid parameter");
343     return AUL_R_EINVAL;
344   }
345
346   std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
347   conn->Disable();
348
349   g_idle_add_full(G_PRIORITY_HIGH, [](gpointer user_data) -> gboolean {
350         auto* conn = static_cast<AppComConnection*>(user_data);
351         std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
352         std::string endpoint = conn->GetEndpoint();
353         context.RemoveConnection(conn);
354
355         if (context.ExistConnection(endpoint))
356           return G_SOURCE_REMOVE;
357
358         tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
359         int ret = AppRequest(APP_COM_LEAVE, getuid())
360             .With(std::move(b))
361             .SendSimply();
362         if (ret != 0)
363           _E("Failed to send leave request. error(%d)", ret);
364
365         return G_SOURCE_REMOVE;
366       }, connection, nullptr);
367
368   return AUL_R_OK;
369 }