Move function definition to aul header
[platform/core/appfw/aul-1.git] / src / app_signal.cc
1 /*
2  * Copyright (c) 2000 - 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 <gio/gio.h>
18 #include <glib.h>
19
20 #include <memory>
21 #include <mutex>
22 #include <string>
23
24 #include "include/aul.h"
25 #include "aul_api.h"
26
27 #include "log_private.hh"
28
29 namespace {
30
31 constexpr const char AUL_DBUS_PATH[] = "/aul/dbus_handler";
32 constexpr const char AUL_DBUS_SIGNAL_INTERFACE[] = "org.tizen.aul.signal";
33 constexpr const char AUL_DBUS_APPDEAD_SIGNAL[] = "app_dead";
34 constexpr const char AUL_DBUS_APPLAUNCH_SIGNAL[] = "app_launch";
35
36 constexpr const char AUL_APP_STATUS_DBUS_PATH[] = "/Org/Tizen/Aul/AppStatus";
37 constexpr const char AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE[] =
38     "org.tizen.aul.AppStatus";
39 constexpr const char AUL_APP_STATUS_DBUS_LAUNCH_REQUEST[] = "AppLaunch";
40 constexpr const char AUL_APP_STATUS_DBUS_RESUME_REQUEST[] = "AppResume";
41 constexpr const char AUL_APP_STATUS_DBUS_TERMINATE_REQUEST[] = "AppTerminate";
42 constexpr const char AUL_APP_STATUS_DBUS_STATUS_CHANGE[] = "AppStatusChange";
43 constexpr const char AUL_APP_STATUS_DBUS_GROUP[] = "AppGroup";
44 constexpr const char AUL_APP_STATUS_DBUS_TERMINATED[] = "AppTerminated";
45
46 constexpr const char SYSTEM_PATH_CORE[] =  "/org/tizen/system";
47 constexpr const char SYSTEM_INTERFACE_CORE[] = "org.tizen.system.Booting";
48 constexpr const char SYSTEM_SIGNAL_BOOTING_DONE[] = "BootingDone";
49
50 constexpr const char SYSTEM_PATH_THERMAL[] = "/Org/Tizen/System/Thermal";
51 constexpr const char SYSTEM_INTERFACE_THERMAL[] = "org.tizen.system.thermal";
52 constexpr const char SYSTEM_SIGNAL_COOLDOWN_MODE_CHANGED[] =
53     "CoolDownModeChanged";
54
55 constexpr const char RESOURCED_BUS_NAME[] = "org.tizen.resourced";
56 constexpr const char RESOURCED_PROC_PATH[] = "/Org/Tizen/ResourceD/Process";
57 constexpr const char RESOURCED_PROC_INTERFACE[] = "org.tizen.resourced.process";
58 constexpr const char RESOURCED_PROC_STATUS_SIGNAL[] = "ProcStatus";
59 constexpr const char RESOURCED_PROC_METHOD[] = "ProcExclude";
60
61 template <typename T>
62 class Event {
63  public:
64   Event(std::string object_path, std::string interface_name,
65       std::string signal_name)
66       : object_path_(std::move(object_path)),
67         interface_name_(std::move(interface_name)),
68         signal_name_(std::move(signal_name)) {
69   }
70
71   virtual ~Event() {
72     Unsubscribe();
73   }
74
75   const std::string& GetObjectPath() const { return object_path_; }
76
77   const std::string& GetInterfaceName() const { return interface_name_; }
78
79   const std::string& GetSignalName() const { return signal_name_; }
80
81   virtual void Invoke(GVariant* parameters) {}
82
83   T GetCallback() const { return cb_; }
84
85   void* GetUserData() const { return user_data_; }
86
87   bool Subscribe() {
88     std::lock_guard<std::recursive_mutex> lock(GetMutex());
89     if (source_ != 0)
90       return true;
91
92     GError* err = nullptr;
93     conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
94     if (conn_ == nullptr) {
95       _E("g_bus_get_sync() is failed. error(%s)", err ? err->message : "");
96       g_clear_error(&err);
97       return false;
98     }
99
100     source_ = g_dbus_connection_signal_subscribe(
101         conn_, nullptr, interface_name_.c_str(), signal_name_.c_str(),
102         object_path_.c_str(), nullptr, G_DBUS_SIGNAL_FLAGS_NONE, DBusSignalCb,
103         this, nullptr);
104     if (source_ == 0) {
105       _E("g_dbus_connection_signal_subscribe() is failed");
106       g_object_unref(conn_);
107       conn_ = nullptr;
108       return false;
109     }
110
111     return true;
112   }
113
114   bool SetCallback(T cb, void* user_data) {
115     std::lock_guard<std::recursive_mutex> lock(GetMutex());
116     cb_ = cb;
117     user_data_ = user_data;
118
119     if (cb_ == nullptr) {
120       Unsubscribe();
121       return true;
122     }
123
124     return Subscribe();
125   }
126
127  private:
128   void Unsubscribe() {
129     std::lock_guard<std::recursive_mutex> lock(GetMutex());
130     if (source_ == 0)
131       return;
132
133     g_dbus_connection_signal_unsubscribe(conn_, source_);
134     source_ = 0;
135
136     g_object_unref(conn_);
137     conn_ = nullptr;
138   }
139
140   std::recursive_mutex& GetMutex() const {
141     return mutex_;
142   }
143
144   static void DBusSignalCb(GDBusConnection* connection,
145       const gchar* sender_name, const gchar* object_path,
146       const gchar* interface_name, const gchar* signal_name,
147       GVariant* parameters, gpointer user_data) {
148     auto* event = static_cast<Event*>(user_data);
149     std::lock_guard<std::recursive_mutex> lock(event->GetMutex());
150     if (event->source_ != 0)
151       event->Invoke(parameters);
152   }
153
154  private:
155   std::string object_path_;
156   std::string interface_name_;
157   std::string signal_name_;
158   std::remove_pointer_t<T>* cb_ = nullptr;
159   void* user_data_ = nullptr;
160   GDBusConnection* conn_ = nullptr;
161   guint source_ = 0;
162   mutable std::recursive_mutex mutex_;
163 };
164
165 class AppDeadEvent : public Event<aul_app_dead_event_cb> {
166  public:
167   AppDeadEvent() : Event<aul_app_dead_event_cb>(AUL_DBUS_PATH,
168             AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPDEAD_SIGNAL) {
169   }
170
171   void Invoke(GVariant* parameters) override {
172     guint pid;
173     g_variant_get(parameters, "(u)", &pid);
174
175     auto cb = GetCallback();
176     if (cb != nullptr)
177       cb(static_cast<int>(pid), GetUserData());
178   }
179 };
180
181 class AppLaunchEvent : public Event<aul_app_launch_event_cb> {
182  public:
183   AppLaunchEvent() : Event<aul_app_launch_event_cb>(AUL_DBUS_PATH,
184             AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPLAUNCH_SIGNAL) {
185   }
186
187   void Invoke(GVariant* parameters) override {
188     guint pid;
189     gchar* appid;
190     g_variant_get(parameters, "(u&s)", &pid, &appid);
191
192     auto cb = GetCallback();
193     if (cb != nullptr)
194       cb(static_cast<int>(pid), GetUserData());
195   }
196 };
197
198 class AppLaunchEvent2 : public Event<aul_app_launch_event_cb_v2> {
199  public:
200   AppLaunchEvent2() : Event<aul_app_launch_event_cb_v2>(AUL_DBUS_PATH,
201             AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPLAUNCH_SIGNAL) {
202   }
203
204   void Invoke(GVariant* parameters) override {
205     guint pid;
206     gchar* appid;
207     g_variant_get(parameters, "(u&s)", &pid, &appid);
208
209     auto cb = GetCallback();
210     if (cb != nullptr)
211       cb(static_cast<int>(pid), appid, GetUserData());
212   }
213 };
214
215 class BootingDoneEvent : public Event<aul_booting_done_event_cb> {
216  public:
217   BootingDoneEvent() : Event<aul_booting_done_event_cb>(SYSTEM_PATH_CORE,
218             SYSTEM_INTERFACE_CORE, SYSTEM_SIGNAL_BOOTING_DONE) {
219   }
220
221   void Invoke(GVariant* parameters) override {
222     auto cb = GetCallback();
223     if (cb != nullptr)
224       cb(0, GetUserData());
225   }
226 };
227
228 class CooldownEvent : public Event<aul_cooldown_event_cb> {
229  public:
230   CooldownEvent() : Event<aul_cooldown_event_cb>(SYSTEM_PATH_THERMAL,
231             SYSTEM_INTERFACE_THERMAL, SYSTEM_SIGNAL_COOLDOWN_MODE_CHANGED) {
232   }
233
234   void Invoke(GVariant* parameters) override {
235     gchar* cooldown_status;
236     g_variant_get(parameters, "(&s)", &cooldown_status);
237
238     auto cb = GetCallback();
239     if (cb != nullptr)
240       cb(cooldown_status, GetUserData());
241   }
242 };
243
244 class AppStatusChangedEvent : public Event<aul_app_status_changed_cb> {
245  public:
246   AppStatusChangedEvent()
247           : Event<aul_app_status_changed_cb>(RESOURCED_PROC_PATH,
248             RESOURCED_PROC_INTERFACE, RESOURCED_PROC_STATUS_SIGNAL) {
249   }
250
251   void Invoke(GVariant* parameters) override {
252     gint pid = -1;
253     gint status = -1;
254     g_variant_get(parameters, "(ii)", &status, &pid);
255
256     auto cb = GetCallback();
257     if (cb != nullptr)
258       cb(pid, status, GetUserData());
259   }
260 };
261
262 class AppSignalContext {
263  public:
264   AppSignalContext() = default;
265   ~AppSignalContext() {
266   }
267
268   bool AppDeadEventSubscribe(aul_app_dead_event_cb cb, void* user_data) {
269     std::lock_guard<std::recursive_mutex> lock(mutex_);
270     if (app_dead_event_ == nullptr)
271       app_dead_event_ = std::make_unique<AppDeadEvent>();
272
273     return app_dead_event_->SetCallback(cb, user_data);
274   }
275
276   bool AppLaunchEventSubscribe(aul_app_launch_event_cb cb, void* user_data) {
277     std::lock_guard<std::recursive_mutex> lock(mutex_);
278     if (app_launch_event_ == nullptr)
279       app_launch_event_ = std::make_unique<AppLaunchEvent>();
280
281     return app_launch_event_->SetCallback(cb, user_data);
282   }
283
284   bool AppLaunchEvent2Subscribe(aul_app_launch_event_cb_v2 cb,
285       void* user_data) {
286     std::lock_guard<std::recursive_mutex> lock(mutex_);
287     if (app_launch_event2_ == nullptr)
288       app_launch_event2_ = std::make_unique<AppLaunchEvent2>();
289
290     return app_launch_event2_->SetCallback(cb, user_data);
291   }
292
293   bool BootingDoneEventSubscribe(aul_booting_done_event_cb cb,
294       void* user_data) {
295     std::lock_guard<std::recursive_mutex> lock(mutex_);
296     if (app_dead_event_ == nullptr)
297       app_dead_event_ = std::make_unique<AppDeadEvent>();
298
299     return booting_done_event_->SetCallback(cb, user_data);
300   }
301
302   bool CooldownEventSubscribe(aul_cooldown_event_cb cb, void* user_data) {
303     std::lock_guard<std::recursive_mutex> lock(mutex_);
304     if (cooldown_event_ == nullptr)
305       cooldown_event_ = std::make_unique<CooldownEvent>();
306
307     return cooldown_event_->SetCallback(cb, user_data);
308   }
309
310   bool AppStatusChangedEventSubscribe(aul_app_status_changed_cb cb,
311       void* user_data) {
312     std::lock_guard<std::recursive_mutex> lock(mutex_);
313     if (app_status_changed_event_ == nullptr)
314       app_status_changed_event_ = std::make_unique<AppStatusChangedEvent>();
315
316     return app_status_changed_event_->SetCallback(cb, user_data);
317   }
318
319  private:
320   std::recursive_mutex mutex_;
321   std::unique_ptr<AppDeadEvent> app_dead_event_;
322   std::unique_ptr<AppLaunchEvent> app_launch_event_;
323   std::unique_ptr<AppLaunchEvent2> app_launch_event2_;
324   std::unique_ptr<BootingDoneEvent> booting_done_event_;
325   std::unique_ptr<CooldownEvent> cooldown_event_;
326   std::unique_ptr<AppStatusChangedEvent> app_status_changed_event_;
327 };
328
329 AppSignalContext context;
330
331 bool EmitSignal(const std::string& object_path,
332     const std::string& interface_name, const std::string& signal_name,
333     GVariant* parameters) {
334   GError* err = nullptr;
335   auto* conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
336   if (conn == nullptr) {
337     _E("g_bus_get_sync() is failed. error(%s)", err ? err->message : "");
338     g_clear_error(&err);
339     return false;
340   }
341   std::unique_ptr<GDBusConnection, decltype(g_object_unref)*> conn_auto(
342       conn, g_object_unref);
343
344   if (!g_dbus_connection_emit_signal(conn, nullptr, object_path.c_str(),
345         interface_name.c_str(), signal_name.c_str(), parameters, &err)) {
346     _E("g_dbus_connection_emit_signal() is failed. error(%s)",
347         err ? err->message : "");
348     g_clear_error(&err);
349     return false;
350   }
351
352   if (!g_dbus_connection_flush_sync(conn, nullptr, &err)) {
353     _E("g_dbus_connection_flush_sync() is failed. error(%s)",
354         err ? err->message : "");
355     g_clear_error(&err);
356     return false;
357   }
358
359   return true;
360 }
361
362 bool SendMessage(const std::string& name, const std::string& path,
363     const std::string& interface, const std::string& method, GVariant* body) {
364   GError* err = nullptr;
365   auto* conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
366   if (conn == nullptr) {
367     _E("g_bus_get_sync() is failed. error(%s)", err ? err->message : "");
368     g_clear_error(&err);
369     return false;
370   }
371   std::unique_ptr<GDBusConnection, decltype(g_object_unref)*> conn_auto(
372       conn, g_object_unref);
373
374   auto* msg = g_dbus_message_new_method_call(name.c_str(), path.c_str(),
375       interface.c_str(), method.c_str());
376   if (msg == nullptr) {
377     _E("g_dbus_message_new_method_call() is failed");
378     return false;
379   }
380   std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> msg_auto(
381       msg, g_object_unref);
382
383   g_dbus_message_set_body(msg, body);
384   g_dbus_connection_send_message_with_reply(conn, msg,
385       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr,
386       [](GObject* source_object, GAsyncResult* res, gpointer user_data) {
387         auto* conn = static_cast<GDBusConnection*>(user_data);
388         int result;
389         GError* err = nullptr;
390         auto* reply = g_dbus_connection_send_message_with_reply_finish(conn,
391             res, &err);
392         if (reply == nullptr) {
393           _E("No reply. error(%s)", err ? err->message : "");
394           result = -1;
395         } else {
396           result = 0;
397         }
398
399         g_clear_error(&err);
400         if (reply != nullptr)
401           g_object_unref(reply);
402         if (conn != nullptr)
403           g_object_unref(conn);
404
405         _I("Result: %d", result);
406       }, conn);
407   conn_auto.release();
408   return true;
409 }
410
411 }  // namespace
412
413 extern "C" API int aul_listen_app_dead_signal(aul_app_dead_event_cb callback,
414     void* user_data) {
415   if (!context.AppDeadEventSubscribe(callback, user_data))
416     return AUL_R_ERROR;
417
418   return AUL_R_OK;
419 }
420
421 extern "C" API int aul_listen_app_launch_signal(
422     aul_app_launch_event_cb callback, void* user_data) {
423   if (!context.AppLaunchEventSubscribe(callback, user_data))
424     return AUL_R_ERROR;
425
426   return AUL_R_OK;
427 }
428
429 extern "C" API int aul_listen_app_launch_signal_v2(
430     aul_app_launch_event_cb_v2 callback, void* user_data) {
431   if (!context.AppLaunchEvent2Subscribe(callback, user_data))
432     return AUL_R_ERROR;
433
434   return AUL_R_OK;
435 }
436
437 extern "C" API int aul_listen_booting_done_signal(
438     aul_booting_done_event_cb callback, void* user_data) {
439   _W("DEPRECATION WARNING: %s() is deprecated "
440       "and will be remove from next release.", __FUNCTION__);
441   if (!context.BootingDoneEventSubscribe(callback, user_data))
442     return AUL_R_ERROR;
443
444   return AUL_R_OK;
445 }
446
447 extern "C" API int aul_listen_cooldown_signal(aul_cooldown_event_cb callback,
448     void *user_data) {
449   _W("DEPRECATION WARNING: %s() is deprecated "
450       "and will be remove from next release.", __FUNCTION__);
451   if (!context.CooldownEventSubscribe(callback, user_data))
452     return AUL_R_ERROR;
453
454   return AUL_R_OK;
455 }
456
457 extern "C" API int aul_listen_app_status_signal(
458     aul_app_status_changed_cb callback, void *user_data) {
459   if (!context.AppStatusChangedEventSubscribe(callback, user_data))
460     return AUL_R_ERROR;
461
462   return AUL_R_OK;
463 }
464
465 extern "C" API int aul_update_freezer_status(int pid, const char* type) {
466   if (pid <= 1 || type == nullptr) {
467     _E("Invalid parameter");
468     return AUL_R_EINVAL;
469   }
470
471   GVariant* body = g_variant_new("(si)", type, pid);
472   if (body == nullptr) {
473     _E("Out of memory");
474     return AUL_R_ENOMEM;
475   }
476
477   if (!SendMessage(RESOURCED_BUS_NAME, RESOURCED_PROC_PATH,
478         RESOURCED_PROC_INTERFACE, RESOURCED_PROC_METHOD, body)) {
479     g_variant_unref(body);
480     return AUL_R_ERROR;
481   }
482
483   return AUL_R_OK;
484 }
485
486 extern "C" API int aul_send_app_launch_request_signal(int pid,
487     const char* appid, const char* pkgid, const char* type) {
488   if (pid <= 1 || appid == nullptr || pkgid == nullptr || type == nullptr) {
489     _E("Invalid parameter");
490     return AUL_R_EINVAL;
491   }
492
493   GVariant* parameters = g_variant_new("(isss)", pid, appid, pkgid, type);
494   if (parameters == nullptr) {
495     _E("Out of memory");
496     return AUL_R_ENOMEM;
497   }
498
499   if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
500         AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
501         AUL_APP_STATUS_DBUS_LAUNCH_REQUEST, parameters)) {
502     g_variant_unref(parameters);
503     return AUL_R_ERROR;
504   }
505
506   return AUL_R_OK;
507 }
508
509 extern "C" API int aul_send_app_resume_request_signal(int pid,
510     const char* appid, const char* pkgid, const char* type) {
511   if (pid <= 1) {
512     _E("Invalid parameter");
513     return AUL_R_EINVAL;
514   }
515
516   if (appid == nullptr)
517     appid = "";
518   if (pkgid == nullptr)
519     pkgid = "";
520   if (type == nullptr)
521     type = "";
522
523   GVariant* parameters = g_variant_new("(isss)", pid, appid, pkgid, type);
524   if (parameters == nullptr) {
525     _E("Out of memory");
526     return AUL_R_ENOMEM;
527   }
528
529   if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
530         AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
531         AUL_APP_STATUS_DBUS_RESUME_REQUEST, parameters)) {
532     g_variant_unref(parameters);
533     return AUL_R_ERROR;
534   }
535
536   return AUL_R_OK;
537 }
538
539 extern "C" API int aul_send_app_terminate_request_signal(int pid,
540     const char* appid, const char* pkgid, const char* type) {
541   if (pid <= 1) {
542     _E("Invalid parameter");
543     return AUL_R_EINVAL;
544   }
545
546   if (appid == nullptr)
547     appid = "";
548   if (pkgid == nullptr)
549     pkgid = "";
550   if (type == nullptr)
551     type = "";
552
553   GVariant* parameters = g_variant_new("(isss)", pid, appid, pkgid, type);
554   if (parameters == nullptr) {
555     _E("Out of memory");
556     return AUL_R_ENOMEM;
557   }
558
559   if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
560         AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
561         AUL_APP_STATUS_DBUS_TERMINATE_REQUEST, parameters)) {
562     g_variant_unref(parameters);
563     return AUL_R_ERROR;
564   }
565
566   return AUL_R_OK;
567 }
568
569 extern "C" API int aul_send_app_status_change_signal(int pid,
570     const char* appid, const char* pkgid, const char* status,
571     const char* type) {
572   if (pid <= 1 || status == nullptr) {
573     _E("Invalid parameter");
574     return AUL_R_EINVAL;
575   }
576
577   if (appid == nullptr)
578     appid = "";
579   if (pkgid == nullptr)
580     pkgid = "";
581   if (type == nullptr)
582     type = "";
583
584   GVariant* parameters = g_variant_new("(issss)",
585       pid, appid, pkgid, status, type);
586   if (parameters == nullptr) {
587     _E("Out of memory");
588     return AUL_R_ENOMEM;
589   }
590
591   if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
592         AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
593         AUL_APP_STATUS_DBUS_STATUS_CHANGE, parameters)) {
594     g_variant_unref(parameters);
595     return AUL_R_ERROR;
596   }
597
598   return AUL_R_OK;
599 }
600
601 extern "C" API int aul_send_app_terminated_signal(int pid) {
602   if (pid <= 1) {
603     _E("Invalid parameter");
604     return AUL_R_EINVAL;
605   }
606
607   GVariant* parameters = g_variant_new("(i)", pid);
608   if (parameters == nullptr) {
609     _E("Out of memory");
610     return AUL_R_ENOMEM;
611   }
612
613   if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
614         AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
615         AUL_APP_STATUS_DBUS_TERMINATED, parameters)) {
616     g_variant_unref(parameters);
617     return AUL_R_ERROR;
618   }
619
620   return AUL_R_OK;
621 }
622
623 extern "C" API int aul_send_app_group_signal(int owner_pid, int child_pid,
624     const char* child_pkgid) {
625   if (owner_pid <= 1 || child_pid <= 1) {
626     _E("Invalid parameter");
627     return AUL_R_EINVAL;
628   }
629
630   if (child_pkgid == nullptr)
631     child_pkgid = "";
632
633   GVariant* parameters = g_variant_new("(iis)",
634       owner_pid, child_pid, child_pkgid);
635   if (parameters == nullptr) {
636     _E("Out of memory");
637     return AUL_R_ENOMEM;
638   }
639
640   if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
641         AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
642         AUL_APP_STATUS_DBUS_GROUP, parameters)) {
643     g_variant_unref(parameters);
644     return AUL_R_ERROR;
645   }
646
647   return AUL_R_OK;
648 }