2 * Copyright (c) 2000 - 2022 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "include/aul.h"
19 #include <sys/types.h>
22 #include <bundle_cpp.h>
30 #include "include/aul_app_com.h"
31 #include "include/aul_error.h"
32 #include "include/aul_sock.h"
35 #include "app_request.h"
36 #include "aul/common/exception.hh"
38 using namespace aul::internal;
40 struct status_listen_s {
47 class AppStatusEvent {
49 AppStatusEvent(std::string appid, uid_t uid, app_status_cb cb,
51 : appid_(std::move(appid)),
54 user_data_(user_data) {
55 std::string endpoint = "app_status_event:" + appid_;
56 if (uid_ < REGULAR_UID_MIN)
57 endpoint += ":" + std::to_string(uid_);
59 int ret = aul_app_com_create(endpoint.c_str(), nullptr, OnAppComCb, this,
61 if (ret != AUL_R_OK) {
62 _E("aul_app_com_create() is failed. endpoint(%s), error(%d)",
63 endpoint.c_str(), ret);
69 if (connection_ != nullptr)
70 aul_app_com_leave(connection_);
74 static int OnAppComCb(const char* endpoint, aul_app_com_result_e res,
75 bundle* envelope, void* user_data) {
76 tizen_base::Bundle b(envelope);
77 aul_app_info app_info = { 0, };
78 app_info.appid = const_cast<char*>(b.GetString(AUL_K_APPID).c_str());
79 app_info.pkgid = const_cast<char*>(b.GetString(AUL_K_PKGID).c_str());
80 app_info.app_path = const_cast<char*>(b.GetString(AUL_K_EXEC).c_str());
81 app_info.instance_id = const_cast<char*>(
82 b.GetString(AUL_K_INSTANCE_ID).c_str());
83 app_info.pid = std::stoi(b.GetString(AUL_K_PID));
84 app_info.status = std::stoi(b.GetString(AUL_K_STATUS));
85 app_info.is_sub_app = std::stoi(b.GetString(AUL_K_IS_SUBAPP));
86 int context_status = std::stoi(b.GetString("__CONTEXT_STATUS__"));
88 auto* event = static_cast<AppStatusEvent*>(user_data);
89 event->cb_(&app_info, context_status, event->user_data_);
98 aul_app_com_connection_h connection_ = nullptr;
101 class StatusLocalCb {
103 StatusLocalCb(aul_status_local_cb cb, void* user_data)
104 : cb_(cb), user_data_(user_data) {
107 aul_status_local_cb GetCb() const {
111 void* GetUserData() const {
115 int Invoke(int status) {
117 return cb_(status, user_data_);
123 aul_status_local_cb cb_;
131 int GetStatus() const {
135 void SetStatus(int status) {
139 void AddLocalCb(aul_status_local_cb cb, void* user_data) {
140 std::lock_guard<std::recursive_mutex> lock(mutex_);
141 cbs_.emplace_back(new StatusLocalCb(cb, user_data));
144 std::size_t RemoveLocalCb(aul_status_local_cb cb, void* user_data) {
145 std::lock_guard<std::recursive_mutex> lock(mutex_);
146 auto count = cbs_.size();
147 cbs_.remove_if([&](const std::unique_ptr<StatusLocalCb>& local_cb) {
148 return local_cb->GetCb() == cb &&
149 local_cb->GetUserData() == user_data;
151 return count - cbs_.size();
154 void InvokeLocalCb(int status) {
155 std::lock_guard<std::recursive_mutex> lock(mutex_);
156 auto iter = cbs_.begin();
157 while (iter != cbs_.end()) {
158 if ((*iter)->Invoke(status) < 0)
159 iter = cbs_.erase(iter);
166 int status_ = STATUS_LAUNCHING;
167 std::list<std::unique_ptr<StatusLocalCb>> cbs_;
168 std::recursive_mutex mutex_;
175 extern "C" API int aul_status_update(int status) {
176 if (status < STATUS_LAUNCHING || status > STATUS_TERMINATE) {
177 _E("Invalid parameter");
181 if (context.GetStatus() == status)
184 context.SetStatus(status);
186 int ret = aul_sock_send_raw(AUL_UTIL_PID, getuid(), APP_STATUS_UPDATE,
187 reinterpret_cast<unsigned char*>(&status), sizeof(status),
190 context.InvokeLocalCb(status);
192 ret = aul_error_convert(ret);
197 extern "C" API int aul_app_get_status_bypid(int pid) {
198 return aul_app_get_status_bypid_for_uid(pid, getuid());
201 extern "C" API int aul_app_get_status_bypid_for_uid(int pid, uid_t uid) {
203 _E("Invalid parameter");
208 return context.GetStatus();
210 return AppRequest(APP_GET_STATUS, uid)
215 extern "C" API int aul_app_get_status(const char* appid) {
216 return aul_app_get_status_for_uid(appid, getuid());
219 extern "C" API int aul_app_get_status_for_uid(const char* appid, uid_t uid) {
220 if (appid == nullptr) {
221 _E("Invalid parameter");
225 return AppRequest(APP_GET_STATUS_BY_APPID, uid)
230 extern "C" API int aul_add_status_local_cb(aul_status_local_cb callback,
232 if (callback == nullptr) {
233 _E("Invalid parameter");
237 context.RemoveLocalCb(callback, user_data);
238 context.AddLocalCb(callback, user_data);
242 extern "C" API int aul_remove_status_local_cb(aul_status_local_cb callback,
244 if (callback == nullptr) {
245 _E("Invalid parameter");
249 if (context.RemoveLocalCb(callback, user_data) > 0)
255 extern "C" API int aul_invoke_status_local_cb(int status) {
256 if (status < STATUS_LAUNCHING || status > STATUS_TERMINATE) {
257 _E("Invalid parameter");
261 context.InvokeLocalCb(status);
265 extern "C" API int aul_set_process_group(int owner_pid, int child_pid) {
266 if (owner_pid < 1 || child_pid < 1) {
267 _E("Invalid parameter");
271 tizen_base::Bundle b {
272 { AUL_K_OWNER_PID, std::to_string(owner_pid) },
273 { AUL_K_CHILD_PID, std::to_string(child_pid) }
276 return AppRequest(APP_SET_PROCESS_GROUP, getuid())
281 extern "C" API int aul_listen_app_status(const char* appid,
282 app_status_cb callback, void* user_data, status_listen_h* handle) {
283 return aul_listen_app_status_for_uid(appid, callback, user_data, handle,
287 extern "C" API int aul_listen_app_status_for_uid(const char* appid,
288 app_status_cb callback, void* user_data, status_listen_h* handle,
290 if (appid == nullptr || callback == nullptr || handle == nullptr) {
291 _E("Invalid parameter");
296 auto* event = new (std::nothrow) AppStatusEvent(
297 appid, uid, callback, user_data);
298 if (event == nullptr) {
303 *handle = reinterpret_cast<status_listen_h>(event);
304 } catch (const Exception& e) {
305 _E("Exception occurs. error(%s)", e.what());
306 return e.GetErrorCode();
312 extern "C" API int aul_ignore_app_status(status_listen_h handle) {
313 if (handle == nullptr) {
314 _E("Invalid parameter");
318 auto* event = reinterpret_cast<AppStatusEvent*>(handle);
323 extern "C" API int aul_notify_exit(void) {
324 return AppRequest(APP_NOTIFY_EXIT, getuid())
325 .SendCmdOnly(AUL_SOCK_NOREPLY);
328 extern "C" API int aul_notify_start(void) {
329 return AppRequest(APP_NOTIFY_START, getuid())
330 .SendCmdOnly(AUL_SOCK_NOREPLY);
333 extern "C" API const char* aul_app_status_convert_to_string(int status) {
335 case STATUS_LAUNCHING:
336 return "STATUS_LAUNCHING";
338 return "STATUS_CREATED";
340 return "STATUS_FOCUS";
342 return "STATUS_VISIBLE";
346 return "STATUS_DYING";
348 return "STATUS_HOME";
349 case STATUS_NORESTART:
350 return "STATUS_NORESTART";
352 return "STATUS_SERVICE";
353 case STATUS_TERMINATE:
354 return "STATUS_TERMINATE";
356 return "Unknown status";
360 extern "C" API int aul_status_update_v2(int status) {
361 if (status < STATUS_LAUNCHING || status > STATUS_TERMINATE) {
362 _E("Invalid parameter");
366 if (context.GetStatus() == status)
369 context.SetStatus(status);
371 tizen_base::Bundle b { { AUL_K_STATUS, std::to_string(status) } };
372 int ret = AppRequest(APP_STATUS_UPDATE_V2, getuid())
376 _E("Failed to update app status. error(%d)", ret);
380 context.InvokeLocalCb(status);