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.
25 #include "notification-ex/dbus_connection_manager.h"
26 #include "notification-ex/dbus_event_listener.h"
27 #include "notification-ex/dbus_event_listener_implementation.h"
28 #include "notification-ex/exception.h"
29 #include "notification-ex/ex_util.h"
30 #include "notification-ex/event_info_internal.h"
36 #define LOG_TAG "NOTIFICATION_EX"
37 #define MAX_PACKAGE_STR_SIZE 512
38 #define NORMAL_UID_BASE 5000
39 #define MAX_CACHE_COUNT 20
41 #define DBUS_NAME "org.freedesktop.DBus"
42 #define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
43 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus"
46 using namespace tizen_base;
48 namespace notification {
50 DBusEventListener::DBusEventListener(string path)
51 : impl_(new Impl(this, path)) {
52 LOGW("Created (%s)", path.c_str());
55 DBusEventListener::~DBusEventListener() {
59 DBusEventListener::Impl::~Impl() = default;
61 DBusEventListener::Impl::Impl(DBusEventListener* parent, string path)
62 : subscribe_id_(0), registration_id_(0), path_(path), parent_(parent) {
63 LOGI("Dbus_event_listener impl created");
66 uid_t DBusEventListener::Impl::GetSenderUid(GDBusConnection* connection,
67 const char* sender_name) {
68 static std::map<std::string, uid_t> cache;
69 auto cp = cache.find(sender_name);
70 if (cp != cache.end())
73 GDBusMessage* msg = nullptr;
74 GDBusMessage* reply = nullptr;
75 GError* err = nullptr;
79 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
80 DBUS_INTERFACE_NAME, "GetConnectionUnixUser");
82 LOGE("Failed to alloc new method call");
86 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
87 reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
88 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
92 LOGE("Failed to get uid [%s]", err->message);
98 body = g_dbus_message_get_body(reply);
99 g_variant_get(body, "(u)", &uid);
101 if (cache.size() >= MAX_CACHE_COUNT)
104 cache[sender_name] = uid;
110 g_object_unref(reply);
115 pid_t DBusEventListener::Impl::GetSenderPid(GDBusConnection* connection,
116 const char* sender_name) {
117 static std::map<std::string, pid_t> cache;
118 auto cp = cache.find(sender_name);
119 if (cp != cache.end())
122 GDBusMessage* msg = nullptr;
123 GDBusMessage* reply = nullptr;
124 GError* err = nullptr;
128 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
129 DBUS_INTERFACE_NAME, "GetConnectionUnixProcessID");
131 LOGE("Failed to alloc new method call");
135 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
136 reply = g_dbus_connection_send_message_with_reply_sync(connection, msg,
137 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
140 if (err != nullptr) {
141 LOGE("Failed to get uid [%s]", err->message);
147 body = g_dbus_message_get_body(reply);
148 g_variant_get(body, "(u)", &pid);
150 if (cache.size() >= MAX_CACHE_COUNT)
153 cache[sender_name] = pid;
159 g_object_unref(reply);
164 void DBusEventListener::Impl::SignalCb(GDBusConnection* connection,
165 const gchar* sender_name,
166 const gchar* object_path,
167 const gchar* interface_name,
168 const gchar* signal_name,
169 GVariant* parameters,
171 DBusEventListener::Impl* dl = static_cast<DBusEventListener::Impl*>(user_data);
172 char* appid = nullptr;
173 GVariantIter *iter = nullptr;
174 char* event_info_raw = nullptr;
175 g_variant_get(parameters, "(&s&sa(s))", &appid, &event_info_raw, &iter);
177 LOGI("signal callback!! (%s)", appid);
178 string sender_appid = string(appid);
179 string cur_appid = util::GetAppId();
180 if (sender_appid == cur_appid) {
181 g_variant_iter_free(iter);
184 if ((!DBusConnectionManager::GetInst().IsDataProviderMaster(cur_appid)
185 && !DBusConnectionManager::GetInst().IsDataProviderMaster(sender_appid))
186 || (cur_appid == sender_appid)) {
187 g_variant_iter_free(iter);
191 LOGD("%s : %s", cur_appid.c_str(), sender_appid.c_str());
195 list<Bundle> ret_list;
196 while (g_variant_iter_loop(iter, "(&s)", &raw) && raw != nullptr) {
198 ret_list.emplace_back(ret);
201 g_variant_iter_free(iter);
202 Bundle b(event_info_raw);
204 if (info.GetEventType() == EventInfo::Post
205 || info.GetEventType() == EventInfo::Update) {
206 uid_t uid = GetSenderUid(connection, sender_name);
207 if (uid >= NORMAL_UID_BASE) {
208 pid_t pid = GetSenderPid(connection, sender_name);
209 info.SetValidatedOwner(util::GetAppId(pid));
210 info.SetValidatedUid(uid);
213 dl->parent_->NotifyObserver(info, ret_list);
214 } catch(Exception &ex) {
215 LOGE("%s %d", ex.what(), ex.GetErrorCode());
219 void DBusEventListener::Impl::MethodCallHandler(GVariant* parameters,
220 DBusEventListener::Impl* dl, pid_t pid, uid_t uid) {
221 char* appid = nullptr;
222 GVariantIter* iter = nullptr;
223 char* event_info_raw = nullptr;
225 g_variant_get(parameters, "(&s&sa(s))", &appid, &event_info_raw, &iter);
227 string sender_appid = string(appid);
228 string cur_appid = util::GetAppId();
229 LOGI("MethodCallHandler!! appid(%s), sender(%s), cur(%s)", appid,
230 sender_appid.c_str(), cur_appid.c_str());
232 if (sender_appid == cur_appid) {
233 g_variant_iter_free(iter);
237 if ((!DBusConnectionManager::GetInst().IsDataProviderMaster(cur_appid)
238 && !DBusConnectionManager::GetInst().IsDataProviderMaster(sender_appid))
239 || (cur_appid == sender_appid)) {
240 g_variant_iter_free(iter);
245 list<Bundle> ret_list;
246 while (g_variant_iter_loop(iter, "(&s)", &raw) && raw != nullptr) {
248 ret_list.emplace_back(ret);
251 g_variant_iter_free(iter);
252 Bundle b(event_info_raw);
255 if (info.GetEventType() == EventInfo::Post
256 || info.GetEventType() == EventInfo::Update) {
257 if (uid >= NORMAL_UID_BASE) {
258 info.SetValidatedOwner(util::GetAppId(pid));
259 info.SetValidatedUid(uid);
263 dl->parent_->NotifyObserver(info, ret_list);
266 void DBusEventListener::Impl::OnMethodCall(
267 GDBusConnection* conn, const gchar* sender, const gchar* object_path,
268 const gchar* iface_name, const gchar* method_name,
269 GVariant* parameters, GDBusMethodInvocation* invocation,
270 gpointer user_data) {
271 LOGI("method_name[%s] sender[%s]", method_name, sender);
272 DBusEventListener::Impl* dl = static_cast<DBusEventListener::Impl*>(user_data);
273 GVariant* reply_body = NULL;
276 char* serialized = NULL;
278 uid_t uid = GetSenderUid(conn, sender);
279 pid_t pid = GetSenderPid(conn, sender);
281 if (g_strcmp0(method_name, "Post") == 0
282 || g_strcmp0(method_name, "Update") == 0
283 || g_strcmp0(method_name, "Delete") == 0
284 || g_strcmp0(method_name, "Error") == 0
285 || g_strcmp0(method_name, "DeleteAll") == 0
286 || g_strcmp0(method_name, "Register") == 0
287 || g_strcmp0(method_name, "Unregister") == 0) {
288 parameters = g_variant_ref(parameters);
289 g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", 0));
290 MethodCallHandler(parameters, dl, pid, uid);
291 g_variant_unref(parameters);
293 } else if (g_strcmp0(method_name, "Count") == 0) {
294 g_variant_get(parameters, "(&s&s)", &appid, &serialized);
296 Bundle b(serialized);
298 int num = dl->parent_->NotifyNumberRequest(info);
299 reply_body = g_variant_new("(i)", num);
300 } else if (g_strcmp0(method_name, "Get") == 0) {
301 g_variant_get(parameters, "(&s&s)", &appid, &serialized);
303 Bundle b(serialized);
305 list<Bundle> result = dl->parent_->NotifyObserver(info);
306 GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)"));
307 for (auto& i : result) {
308 g_variant_builder_add(builder, "(s)",
309 reinterpret_cast<char*>(i.ToRaw().first.get()));
311 reply_body = g_variant_new("(a(s))", builder);
312 g_variant_builder_unref(builder);
314 g_dbus_method_invocation_return_error(invocation, noti_ex_error_quark(),
315 ERROR_IO_ERROR, "invalid operation");
319 g_dbus_method_invocation_return_value(invocation, reply_body);
321 } catch (Exception &ex) {
322 LOGE("%s %d", ex.what(), ex.GetErrorCode());
323 g_dbus_method_invocation_return_error(invocation, noti_ex_error_quark(),
324 ERROR_IO_ERROR, "OnMethodCall fail");
328 int DBusEventListener::Impl::RegisterGDBusInterface() {
329 static const GDBusInterfaceVTable interface_vtable = {
334 static gchar introspection_xml[] =
336 " <interface name='org.tizen.notification_ex'>"
337 " <method name='Post'>"
338 " <arg type='s' name='appid' direction='in'/>"
339 " <arg type='s' name='info' direction='in'/>"
340 " <arg type='a(s)' name='serialized' direction='in'/>"
341 " <arg type='i' name='ret' direction='out'/>"
343 " <method name='Update'>"
344 " <arg type='s' name='appid' direction='in'/>"
345 " <arg type='s' name='info' direction='in'/>"
346 " <arg type='a(s)' name='serialized' direction='in'/>"
347 " <arg type='i' name='ret' direction='out'/>"
349 " <method name='Delete'>"
350 " <arg type='s' name='appid' direction='in'/>"
351 " <arg type='s' name='info' direction='in'/>"
352 " <arg type='a(s)' name='serialized' direction='in'/>"
353 " <arg type='i' name='ret' direction='out'/>"
355 " <method name='Get'>"
356 " <arg type='s' name='appid' direction='in'/>"
357 " <arg type='s' name='serialized' direction='in'/>"
358 " <arg type='a(s)' name='noti_arr' direction='out'/>"
360 " <method name='Error'>"
361 " <arg type='s' name='appid' direction='in'/>"
362 " <arg type='s' name='info' direction='in'/>"
363 " <arg type='a(s)' name='serialized' direction='in'/>"
364 " <arg type='i' name='ret' direction='out'/>"
366 " <method name='Count'>"
367 " <arg type='s' name='appid' direction='in'/>"
368 " <arg type='s' name='serialized' direction='in'/>"
369 " <arg type='i' name='num' direction='out'/>"
371 " <method name='DeleteAll'>"
372 " <arg type='s' name='appid' direction='in'/>"
373 " <arg type='s' name='info' direction='in'/>"
374 " <arg type='a(s)' name='serialized' direction='in'/>"
375 " <arg type='i' name='ret' direction='out'/>"
377 " <method name='Register'>"
378 " <arg type='s' name='appid' direction='in'/>"
379 " <arg type='s' name='info' direction='in'/>"
380 " <arg type='a(s)' name='serialized' direction='in'/>"
381 " <arg type='i' name='ret' direction='out'/>"
383 " <method name='Unregister'>"
384 " <arg type='s' name='appid' direction='in'/>"
385 " <arg type='s' name='info' direction='in'/>"
386 " <arg type='a(s)' name='serialized' direction='in'/>"
387 " <arg type='i' name='ret' direction='out'/>"
391 GError *error = NULL;
392 GDBusNodeInfo *introspection_data =
393 g_dbus_node_info_new_for_xml(introspection_xml, &error);
394 if (!introspection_data) {
395 LOGE("g_dbus_node_info_new_for_xml is failed.");
397 LOGE("g_dbus_node_info_new_for_xml err [%s]", error->message);
400 return ERROR_IO_ERROR;
403 registration_id_ = g_dbus_connection_register_object(
404 DBusConnectionManager::GetInst().GetConnection(),
405 path_.c_str(), introspection_data->interfaces[0],
406 &interface_vtable, this, NULL, NULL);
407 g_dbus_node_info_unref(introspection_data);
408 if (registration_id_ == 0) {
409 LOGE("register object fail");
410 return ERROR_IO_ERROR;
413 LOGI("RegisterGDBusInterface success");
417 void DBusEventListener::Impl::UnRegisterGDBusInterface() {
418 g_dbus_connection_unregister_object(
419 DBusConnectionManager::GetInst().GetConnection(),
423 bool DBusEventListener::Impl::SubscribeSignal() {
424 subscribe_id_ = g_dbus_connection_signal_subscribe(
425 DBusConnectionManager::GetInst().GetConnection(),
427 DBusConnectionManager::GetInst().GetInterfaceName().c_str(),
431 G_DBUS_SIGNAL_FLAGS_NONE,
435 return subscribe_id_ > 0;
438 void DBusEventListener::Impl::UnSubscribeSignal() {
439 g_dbus_connection_signal_unsubscribe(
440 DBusConnectionManager::GetInst().GetConnection(), subscribe_id_);
444 void DBusEventListener::RegisterObserver(IEventObserver* observer) {
445 if (impl_->subscribe_id_ == 0) {
446 impl_->SubscribeSignal();
448 impl_->UnSubscribeSignal();
449 impl_->SubscribeSignal();
452 if (impl_->registration_id_ == 0) {
453 impl_->RegisterGDBusInterface();
455 impl_->UnRegisterGDBusInterface();
456 impl_->RegisterGDBusInterface();
458 impl_->observer_ = observer;
461 void DBusEventListener::UnRegisterObserver(IEventObserver* observer) {
462 impl_->UnSubscribeSignal();
463 impl_->observer_ = NULL;
466 void DBusEventListener::NotifyObserver(
467 const IEventInfo& info, list<Bundle> serialized) {
468 impl_->observer_->OnEvent(info, serialized);
471 list<Bundle> DBusEventListener::NotifyObserver(const IEventInfo& info) {
472 return impl_->observer_->OnRequest(info);
475 int DBusEventListener::NotifyNumberRequest(const IEventInfo& info) {
476 return impl_->observer_->OnRequestNumber(info);
479 } // namespace notification