92a2a420b74e77dbbf98a22c61ecbc096e625ee6
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / dbus.cc
1 /*
2  * Copyright (c) 2023 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 "launchpad-process-pool/dbus.hh"
18
19 #include <gio/gio.h>
20 #include <glib.h>
21
22 #include <chrono>
23 #include <memory>
24 #include <thread>
25 #include <utility>
26
27 #include <shared-queue.hpp>
28
29 #include "launchpad-process-pool/log_private.hh"
30
31 namespace launchpad {
32 namespace {
33
34 constexpr const uint32_t ERROR_THRESHOLD = 10;
35 constexpr const uint32_t ERROR_MODULO = 1000;
36 constexpr const uint32_t PENDING_ITEM_INTERVAL = 1000;
37 constexpr const char AUL_DBUS_PATH[] = "/aul/dbus_handler";
38 constexpr const char AUL_DBUS_SIGNAL_INTERFACE[] = "org.tizen.aul.signal";
39 constexpr const char AUL_DBUS_APPDEAD_SIGNAL[] = "app_dead";
40 constexpr const char AUL_DBUS_APPLAUNCH_SIGNAL[] = "app_launch";
41
42 class DBusMessage {
43  public:
44   DBusMessage(std::string path, std::string interface, std::string signal_name,
45               GVariant *param, std::string log_message)
46       : path_(std::move(path)), interface_(std::move(interface)),
47         signal_name_(std::move(signal_name)), param_(param),
48         log_message_(std::move(log_message)) {}
49
50   explicit DBusMessage(bool done) : done_(done) {}
51
52   ~DBusMessage() {
53     if (param_ != nullptr)
54       g_variant_unref(param_);
55   }
56
57   const std::string& GetPath() const { return path_; }
58
59   const std::string& GetInterface() const { return interface_; }
60
61   const std::string& GetSignalName() const { return signal_name_; }
62
63   GVariant* RemoveParam() {
64     GVariant *param = param_;
65     param_ = nullptr;
66     return param;
67   }
68
69   bool IsDone() const { return done_; }
70
71   const std::string& GetLogMessage() const { return log_message_; }
72
73  private:
74   bool done_ = false;
75   std::string path_;
76   std::string interface_;
77   std::string signal_name_;
78   GVariant *param_ = nullptr;
79   std::string log_message_;
80 };
81
82 class DBusManager {
83  public:
84   DBusManager(const DBusManager&) = delete;
85   DBusManager& operator = (const DBusManager&) = delete;
86   DBusManager(DBusManager&&) = delete;
87   DBusManager& operator = (DBusManager&&) = delete;
88
89   static DBusManager& GetInst() {
90     static DBusManager inst;
91     return inst;
92   }
93
94   void Dispose() {
95     if (disposed_)
96       return;
97
98     if (getpid() == pid_) {
99       queue_->Push(std::make_shared<DBusMessage>(true));
100       thread_.join();
101
102       if (conn_ != nullptr) {
103         g_object_unref(conn_);
104         conn_ = nullptr;
105       }
106
107       delete queue_;
108     } else {
109       thread_.detach();
110     }
111
112     disposed_ = true;
113   }
114
115   void Send(std::shared_ptr<DBusMessage> message) {
116     queue_->Push(std::move(message));
117   }
118
119   void Init() {
120     if (!disposed_)
121       return;
122
123     queue_ = new tizen_base::SharedQueue<std::shared_ptr<DBusMessage>>();
124     thread_ = std::thread([&]() -> void { WorkerThread(); });
125     disposed_ = false;
126   }
127
128  private:
129   DBusManager() = default;
130   ~DBusManager() { Dispose(); }
131
132   GDBusConnection* GetConnection() {
133     if (conn_)
134       return conn_;
135
136     GError* error = nullptr;
137     conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
138     if (conn_ == nullptr) {
139       error_count_++;
140       if (error_count_ < ERROR_THRESHOLD || error_count_ % ERROR_MODULO == 0) {
141         _E("g_bus_get_sync() is failed. error(%s)",
142             error ? error->message : "Unknown");
143       }
144
145       g_clear_error(&error);
146       return nullptr;
147     }
148
149     return conn_;
150   }
151
152   void EmitSignal(std::shared_ptr<DBusMessage> args) {
153     GError* error = nullptr;
154     if (!g_dbus_connection_emit_signal(conn_, nullptr, args->GetPath().c_str(),
155             args->GetInterface().c_str(), args->GetSignalName().c_str(),
156             args->RemoveParam(), &error)) {
157       _E("g_dbus_connection_emit_signal() is failed. error(%s)",
158           error ? error->message : "Unknown");
159       g_clear_error(&error);
160       return;
161     }
162
163     if (!g_dbus_connection_flush_sync(conn_, nullptr, &error)) {
164       _E("g_dbus_connection_flush_sync() is failed. error(%s)",
165           error ? error->message : "Unknown");
166       g_clear_error(&error);
167       return;
168     }
169
170     _W("[DBUS] %s", args->GetLogMessage().c_str());
171   }
172
173   void WorkerThread() {
174     _W("BEGIN");
175     while (true) {
176       auto conn = GetConnection();
177       if (conn == nullptr) {
178         _W("Wait for dbus ready");
179         std::this_thread::sleep_for(
180             std::chrono::milliseconds(PENDING_ITEM_INTERVAL));
181         continue;
182       }
183
184       auto message = queue_->WaitAndPop();
185       if (message->IsDone())
186         break;
187
188       EmitSignal(message);
189     }
190     _W("END");
191   }
192
193  private:
194   bool disposed_ = true;
195   pid_t pid_ = getpid();
196   GDBusConnection* conn_ = nullptr;
197   uint32_t error_count_ = 0;
198   std::thread thread_;
199   tizen_base::SharedQueue<std::shared_ptr<DBusMessage>>* queue_;
200 };
201
202 }  // namespace
203
204 void DBus::SendAppLaunchSignal(pid_t pid, const std::string_view appid) {
205   DBusManager::GetInst().Send(
206       std::make_shared<DBusMessage>(
207           AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPLAUNCH_SIGNAL,
208           g_variant_new("(us)", pid, appid.data()),
209           "App Launch. " + std::to_string(pid) + ":" + std::string(appid)));
210 }
211
212 void DBus::SendAppDeadSignal(pid_t pid, int status) {
213   DBusManager::GetInst().Send(std::make_shared<DBusMessage>(
214       AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPDEAD_SIGNAL,
215       g_variant_new("(ii)", pid, status),
216       "App Dead. pid: " + std::to_string(pid) +
217           ", status: " + std::to_string(status)));
218 }
219
220 void DBus::Init() {
221   DBusManager::GetInst().Init();
222 }
223
224 void DBus::Finish() {
225   DBusManager::GetInst().Dispose();
226 }
227
228 }  // namespace launchpad