2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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.
24 #include "notification-ex/dbus_connection_manager.h"
25 #include "notification-ex/dbus_event_listener.h"
26 #include "notification-ex/dbus_event_listener_implementation.h"
27 #include "notification-ex/exception.h"
28 #include "notification-ex/ex_util.h"
29 #include "notification-ex/event_info_internal.h"
35 #define LOG_TAG "NOTIFICATION_EX"
36 #define MAX_PACKAGE_STR_SIZE 512
37 #define NORMAL_UID_BASE 5000
39 #define DBUS_NAME "org.freedesktop.DBus"
40 #define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
41 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus"
44 using namespace tizen_base;
46 namespace notification {
48 DBusEventListener::DBusEventListener(string path)
49 : impl_(new Impl(this, path)) {
50 LOGW("Created (%s)", path.c_str());
53 DBusEventListener::~DBusEventListener() {
57 DBusEventListener::Impl::~Impl() = default;
59 DBusEventListener::Impl::Impl(DBusEventListener* parent, string path)
60 : subscribe_id_(0), registration_id_(0), path_(path), parent_(parent) {
61 LOGI("Dbus_event_listener impl created");
64 uid_t DBusEventListener::Impl::GetSenderUid(GDBusConnection* connection,
65 const char* sender_name) {
66 GDBusMessage* msg = nullptr;
67 GDBusMessage* reply = nullptr;
68 GError* err = nullptr;
72 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
73 DBUS_INTERFACE_NAME, "GetConnectionUnixUser");
75 LOGE("Failed to alloc new method call");
79 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
80 reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
81 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
85 LOGE("Failed to get uid [%s]", err->message);
91 body = g_dbus_message_get_body(reply);
92 g_variant_get(body, "(u)", &uid);
98 g_object_unref(reply);
103 pid_t DBusEventListener::Impl::GetSenderPid(GDBusConnection* connection,
104 const char* sender_name) {
105 GDBusMessage* msg = nullptr;
106 GDBusMessage* reply = nullptr;
107 GError* err = nullptr;
111 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
112 DBUS_INTERFACE_NAME, "GetConnectionUnixProcessID");
114 LOGE("Failed to alloc new method call");
118 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
119 reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
120 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
123 if (err != nullptr) {
124 LOGE("Failed to get uid [%s]", err->message);
130 body = g_dbus_message_get_body(reply);
131 g_variant_get(body, "(u)", &pid);
137 g_object_unref(reply);
142 void DBusEventListener::Impl::SignalCb(GDBusConnection* connection,
143 const gchar* sender_name,
144 const gchar* object_path,
145 const gchar* interface_name,
146 const gchar* signal_name,
147 GVariant* parameters,
149 DBusEventListener::Impl* dl = static_cast<DBusEventListener::Impl*>(user_data);
150 char* appid = nullptr;
151 GVariantIter *iter = nullptr;
152 char* event_info_raw = nullptr;
153 g_variant_get(parameters, "(ssa(s))", &appid, &event_info_raw, &iter);
155 LOGI("signal callback!! (%s)", appid);
156 string sender_appid = string(appid);
157 string cur_appid = util::GetAppId();
158 if (sender_appid == cur_appid)
160 if ((!DBusConnectionManager::GetInst().IsDataProviderMaster(cur_appid)
161 && !DBusConnectionManager::GetInst().IsDataProviderMaster(sender_appid))
162 || (cur_appid == sender_appid))
165 LOGD("%s : %s", cur_appid.c_str(), sender_appid.c_str());
169 list<Bundle> ret_list;
170 while (g_variant_iter_loop(iter, "(s)", &raw) && raw != nullptr) {
172 ret_list.emplace_back(ret);
175 Bundle b(event_info_raw);
177 if (info.GetEventType() == EventInfo::Post
178 || info.GetEventType() == EventInfo::Update) {
179 uid_t uid = GetSenderUid(connection, sender_name);
180 if (uid >= NORMAL_UID_BASE) {
181 pid_t pid = GetSenderPid(connection, sender_name);
182 info.SetValidatedOwner(util::GetAppId(pid));
183 info.SetValidatedUid(uid);
186 dl->parent_->NotifyObserver(info, ret_list);
187 } catch(Exception &ex) {
188 LOGE("%s %d", ex.what(), ex.GetErrorCode());
192 void DBusEventListener::Impl::OnMethodCall(
193 GDBusConnection *conn, const gchar *sender, const gchar *object_path,
194 const gchar *iface_name, const gchar *method_name,
195 GVariant *parameters, GDBusMethodInvocation *invocation,
196 gpointer user_data) {
197 LOGI("method_name[%s] sender[%s]", method_name, sender);
198 DBusEventListener::Impl* dl = static_cast<DBusEventListener::Impl*>(user_data);
199 GVariant *reply_body = NULL;
202 char* serialized = NULL;
203 if (g_strcmp0(method_name, "Get") == 0) {
204 g_variant_get(parameters, "(&s&s)", &appid, &serialized);
206 Bundle b(serialized);
208 list<Bundle> result = dl->parent_->NotifyObserver(info);
209 GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)"));
210 for (auto& i : result) {
211 g_variant_builder_add(builder, "(s)",
212 reinterpret_cast<char*>(i.ToRaw().first.get()));
214 reply_body = g_variant_new("(a(s))", builder);
215 g_variant_builder_unref(builder);
216 } else if (g_strcmp0(method_name, "Count") == 0) {
217 g_variant_get(parameters, "(&s&s)", &appid, &serialized);
219 Bundle b(serialized);
221 int num = dl->parent_->NotifyNumberRequest(info);
222 reply_body = g_variant_new("(i)", num);
224 g_dbus_method_invocation_return_value(invocation, reply_body);
225 } catch (Exception &ex) {
226 LOGE("%s %d", ex.what(), ex.GetErrorCode());
227 g_dbus_method_invocation_return_error(invocation, noti_ex_error_quark(),
228 ERROR_IO_ERROR, "OnMethodCall fail");
232 int DBusEventListener::Impl::RegisterGDBusInterface() {
233 static const GDBusInterfaceVTable interface_vtable = {
238 static gchar introspection_xml[] =
240 " <interface name='org.tizen.notification_ex'>"
241 " <method name='Get'>"
242 " <arg type='s' name='appid' direction='in'/>"
243 " <arg type='s' name='serialized' direction='in'/>"
244 " <arg type='a(s)' name='noti_arr' direction='out'/>"
246 " <method name='Count'>"
247 " <arg type='s' name='appid' direction='in'/>"
248 " <arg type='s' name='serialized' direction='in'/>"
249 " <arg type='i' name='num' direction='out'/>"
253 GError *error = NULL;
254 GDBusNodeInfo *introspection_data =
255 g_dbus_node_info_new_for_xml(introspection_xml, &error);
256 if (!introspection_data) {
257 LOGE("g_dbus_node_info_new_for_xml is failed.");
259 LOGE("g_dbus_node_info_new_for_xml err [%s]", error->message);
262 return ERROR_IO_ERROR;
265 registration_id_ = g_dbus_connection_register_object(
266 DBusConnectionManager::GetInst().GetConnection(),
267 path_.c_str(), introspection_data->interfaces[0],
268 &interface_vtable, this, NULL, NULL);
269 g_dbus_node_info_unref(introspection_data);
270 if (registration_id_ == 0) {
271 LOGE("register object fail");
272 return ERROR_IO_ERROR;
275 LOGI("RegisterGDBusInterface success");
279 void DBusEventListener::Impl::UnRegisterGDBusInterface() {
280 g_dbus_connection_unregister_object(
281 DBusConnectionManager::GetInst().GetConnection(),
285 bool DBusEventListener::Impl::SubscribeSignal() {
286 subscribe_id_ = g_dbus_connection_signal_subscribe(
287 DBusConnectionManager::GetInst().GetConnection(),
289 DBusConnectionManager::GetInst().GetInterfaceName().c_str(),
293 G_DBUS_SIGNAL_FLAGS_NONE,
297 return subscribe_id_ > 0;
300 void DBusEventListener::Impl::UnSubscribeSignal() {
301 g_dbus_connection_signal_unsubscribe(
302 DBusConnectionManager::GetInst().GetConnection(), subscribe_id_);
306 void DBusEventListener::RegisterObserver(IEventObserver* observer) {
307 if (impl_->subscribe_id_ == 0) {
308 impl_->SubscribeSignal();
310 impl_->UnSubscribeSignal();
311 impl_->SubscribeSignal();
314 if (impl_->registration_id_ == 0) {
315 impl_->RegisterGDBusInterface();
317 impl_->UnRegisterGDBusInterface();
318 impl_->RegisterGDBusInterface();
320 impl_->observer_ = observer;
323 void DBusEventListener::UnRegisterObserver(IEventObserver* observer) {
324 impl_->UnSubscribeSignal();
325 impl_->observer_ = NULL;
328 void DBusEventListener::NotifyObserver(
329 const IEventInfo& info, list<Bundle> serialized) {
330 impl_->observer_->OnEvent(info, serialized);
333 list<Bundle> DBusEventListener::NotifyObserver(const IEventInfo& info) {
334 return impl_->observer_->OnRequest(info);
337 int DBusEventListener::NotifyNumberRequest(const IEventInfo& info) {
338 return impl_->observer_->OnRequestNumber(info);
341 } // namespace notification