2 * Copyright 2023 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.
23 #include <notification_setting.h>
24 #include <notification_setting_internal.h>
25 #include <notification_setting_service.h>
26 #include <notification_noti.h>
27 #include <badge_setting.h>
28 #include <badge_setting_service.h>
30 #include <package-manager.h>
31 #include <tzplatform_config.h>
32 #include <pkgmgr-info.h>
37 #include <string_view>
41 #include "pkgmgr_client.hh"
42 #include "service_common.h"
43 #include "notification_service.h"
44 #include "badge_service.h"
45 #include "shortcut_service.h"
47 #define DBUS_NAME "org.freedesktop.DBus"
48 #define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
49 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus"
51 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
52 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
56 static GDBusConnection *_gdbus_conn;
57 static GHashTable *_noti_pkg_privilege_info;
58 static GHashTable *_badge_pkg_privilege_info;
59 std::unique_ptr<PkgmgrClient> pkgmgr_client_;
60 std::list<std::shared_ptr<PkgmgrEventArgs>> pkgmgr_event_list_;
61 std::list<std::shared_ptr<PkgmgrAppEventArgs>> pkgmgr_app_event_list_;
63 const std::set<std::string_view> pkgmgr_installer_key_list_ = {
69 const std::set<std::string_view> pkgmgr_installer_val_list_ = {
77 static int _package_install_cb(uid_t uid, const char *pkgname);
78 static int _package_uninstall_cb(uid_t uid, const char *pkgname);
79 static int _app_enabled_cb(uid_t uid, const char *app_id);
80 static int _app_disabled_cb(uid_t uid, const char *app_id);
82 class PackageEventListener : public PkgmgrClient::IEvent {
84 void OnPkgmgrEvent(std::shared_ptr<PkgmgrEventArgs> args) override;
85 void OnPkgmgrAppEvent(std::shared_ptr<PkgmgrAppEventArgs> args) override;
88 void PackageEventListener::OnPkgmgrEvent(std::shared_ptr<PkgmgrEventArgs> args) {
89 if (pkgmgr_installer_key_list_.find(args->GetEventStatus()) ==
90 pkgmgr_installer_key_list_.end())
93 if (args->GetEventStatus().compare(std::string("start")) == 0 &&
94 pkgmgr_installer_val_list_.find(args->GetEventName()) !=
95 pkgmgr_installer_val_list_.end()) {
96 pkgmgr_event_list_.push_back(args);
100 if (args->GetEventName().compare(std::string("ok")) == 0) {
101 auto iter = pkgmgr_event_list_.begin();
102 while(iter != pkgmgr_event_list_.end()) {
103 if ((*iter)->GetTargetUid() == args->GetTargetUid() &&
104 (*iter)->GetPkgId().compare(args->GetPkgId()) == 0) {
105 if ((*iter)->GetEventName().compare(std::string("install")) == 0)
106 _package_install_cb(args->GetTargetUid(), args->GetPkgId().c_str());
107 else if ((*iter)->GetEventName().compare(std::string("uninstall")) == 0)
108 _package_uninstall_cb(args->GetTargetUid(), args->GetPkgId().c_str());
109 else if ((*iter)->GetEventName().compare(std::string("enable_app")) == 0)
110 _app_enabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
111 else if ((*iter)->GetEventName().compare(std::string("disable_app")) == 0)
112 _app_disabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
114 iter = pkgmgr_event_list_.erase(iter);
119 } else if (args->GetEventName().compare(std::string("fail")) == 0) {
120 auto iter = pkgmgr_event_list_.begin();
121 while(iter != pkgmgr_event_list_.end()) {
122 if ((*iter)->GetTargetUid() == args->GetTargetUid() &&
123 (*iter)->GetPkgId().compare(args->GetPkgId()) == 0) {
124 iter = pkgmgr_event_list_.erase(iter);
132 void PackageEventListener::OnPkgmgrAppEvent(std::shared_ptr<PkgmgrAppEventArgs> args) {
133 if (pkgmgr_installer_key_list_.find(args->GetEventStatus()) ==
134 pkgmgr_installer_key_list_.end())
137 if (args->GetEventStatus().compare(std::string("start")) == 0 &&
138 pkgmgr_installer_val_list_.find(args->GetEventName()) !=
139 pkgmgr_installer_val_list_.end()) {
140 pkgmgr_app_event_list_.push_back(args);
144 if (args->GetEventName().compare(std::string("ok")) == 0) {
145 auto iter = pkgmgr_app_event_list_.begin();
146 while(iter != pkgmgr_app_event_list_.end()) {
147 if ((*iter)->GetTargetUid() == args->GetTargetUid() &&
148 (*iter)->GetPkgId().compare(args->GetPkgId()) == 0) {
149 if ((*iter)->GetEventName().compare(std::string("install")) == 0)
150 _package_install_cb(args->GetTargetUid(), args->GetPkgId().c_str());
151 else if ((*iter)->GetEventName().compare(std::string("uninstall")) == 0)
152 _package_uninstall_cb(args->GetTargetUid(), args->GetPkgId().c_str());
153 else if ((*iter)->GetEventName().compare(std::string("enable_app")) == 0)
154 _app_enabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
155 else if ((*iter)->GetEventName().compare(std::string("disable_app")) == 0)
156 _app_disabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
158 iter = pkgmgr_app_event_list_.erase(iter);
163 } else if (args->GetEventName().compare(std::string("fail")) == 0) {
164 auto iter = pkgmgr_app_event_list_.begin();
165 while(iter != pkgmgr_app_event_list_.end()) {
166 if ((*iter)->GetTargetUid() == args->GetTargetUid() &&
167 (*iter)->GetPkgId().compare(args->GetPkgId()) == 0) {
168 iter = pkgmgr_app_event_list_.erase(iter);
176 uid_t get_sender_uid(const char *sender_name) {
177 GDBusMessage *msg = nullptr;
178 GDBusMessage *reply = nullptr;
179 GError *err = nullptr;
183 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
184 DBUS_INTERFACE_NAME, "GetConnectionUnixUser");
186 LOGE("Failed to alloc new method call");
190 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
191 reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
192 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
195 if (err != nullptr) {
196 LOGE("Failed to get uid [%s]", err->message);
202 body = g_dbus_message_get_body(reply);
203 g_variant_get(body, "(u)", &uid);
209 g_object_unref(reply);
214 pid_t get_sender_pid(const char *sender_name) {
215 GDBusMessage *msg = nullptr;
216 GDBusMessage *reply = nullptr;
217 GError *err = nullptr;
221 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
222 DBUS_INTERFACE_NAME, "GetConnectionUnixProcessID");
224 LOGE("Failed to alloc new method call");
228 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
229 reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
230 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
233 if (err != nullptr) {
234 LOGE("Failed to get uid [%s]", err->message);
240 body = g_dbus_message_get_body(reply);
241 g_variant_get(body, "(u)", &pid);
247 g_object_unref(reply);
252 bool is_existed_busname(const char *sender_name) {
253 GDBusMessage *msg = nullptr;
254 GDBusMessage *reply = nullptr;
255 GError *err = nullptr;
257 bool is_existed = false;
259 msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
260 DBUS_INTERFACE_NAME, "NameHasOwner");
262 LOGE("Failed to alloc new method call");
266 g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
267 reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
268 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
271 if (err != nullptr) {
272 LOGE("Failed to get uid [%s]", err->message);
278 body = g_dbus_message_get_body(reply);
279 g_variant_get(body, "(b)", &is_existed);
285 g_object_unref(reply);
290 int send_notify(GVariant *body, char *cmd, GHashTable **monitoring_hash,
291 char *interface_name, uid_t uid) {
292 GError *err = nullptr;
293 GList *monitoring_list = nullptr;
295 char *target_bus_name;
296 int monitoring_count = 0;
297 bool is_existed = false;
299 monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid));
300 target_list = g_list_first(monitoring_list);
301 for (; target_list != nullptr; ) {
303 target_bus_name = static_cast<char*>(target_list->data);
304 target_list = target_list->next;
306 if (g_variant_is_floating(body))
309 if (g_dbus_connection_emit_signal(_gdbus_conn,
311 PROVIDER_OBJECT_PATH,
316 if (err != nullptr) {
317 ERR("Emit signal err [%s]", err->message);
320 is_existed = is_existed_busname(target_bus_name);
321 if (is_existed == false)
322 delete_monitoring_list(monitoring_hash, target_bus_name, uid);
323 ERR("Fail, emit signal to [%s]", target_bus_name);
326 if (g_dbus_connection_flush_sync(_gdbus_conn, NULL, &err) == FALSE) {
327 ERR("Failed to flush connection[%s]", err ? err->message : "");
332 WARN("Success, emit signal to [%s]", target_bus_name);
335 WARN("Success, cmd[%s] monitoring count[%d]", cmd, monitoring_count);
336 return SERVICE_COMMON_ERROR_NONE;
339 int send_event_notify_by_busname(GVariant *body, char *cmd, char *busname,
340 char *interface_name) {
341 GError *err = nullptr;
343 if (g_variant_is_floating(body))
346 if (g_dbus_connection_emit_signal(_gdbus_conn,
348 PROVIDER_OBJECT_PATH,
353 if (err != nullptr) {
354 ERR("Emit signal err [%s]",
358 ERR("Failed to emit signal to [%s]", busname);
359 return SERVICE_COMMON_ERROR_IO_ERROR;
362 if (g_dbus_connection_flush_sync(_gdbus_conn, NULL, &err) == FALSE) {
363 ERR("Failed to flush connection[%s]", err ? err->message : "");
366 return SERVICE_COMMON_ERROR_IO_ERROR;
369 WARN("Success, Emit signal to [%s] cmd[%s]", busname, cmd);
370 return SERVICE_COMMON_ERROR_NONE;
373 /* register service */
375 static int _monitoring_app_list_compare_cb(gconstpointer a, gconstpointer b) {
376 return strcmp(static_cast<const char*>(a), reinterpret_cast<const char*>(b));
379 int service_register(GVariant *parameters, GVariant **reply_body, const gchar *sender,
380 GBusNameAppearedCallback name_appeared_handler,
381 GBusNameVanishedCallback name_vanished_handler,
382 GHashTable **monitoring_hash,
384 GList *added_list = nullptr;
385 const char *bus_name = sender;
386 monitoring_info_s *m_info = nullptr;
387 uid_t request_uid = 0;
388 GList *monitoring_list = nullptr;
390 if (sender == nullptr)
391 return SERVICE_COMMON_ERROR_IO_ERROR;
393 g_variant_get(parameters, "(i)", &request_uid);
394 if (uid > NORMAL_UID_BASE && uid != request_uid)
395 return SERVICE_COMMON_ERROR_IO_ERROR;
397 DBG("service_register : uid %d , request_uid %d", uid, request_uid);
398 monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid));
399 added_list = g_list_find_custom(monitoring_list, bus_name,
400 (GCompareFunc)_monitoring_app_list_compare_cb);
402 if (added_list == nullptr) {
403 DBG("add new sender to list");
404 m_info = (monitoring_info_s *)calloc(1, sizeof(monitoring_info_s));
405 if (m_info == nullptr) {
406 ERR("Failed to alloc memory");
407 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
410 m_info->bus_name = strdup(bus_name);
411 m_info->uid = request_uid;
412 m_info->watcher_id = g_bus_watch_name_on_connection(
415 G_BUS_NAME_WATCHER_FLAGS_NONE,
416 name_appeared_handler,
417 name_vanished_handler,
420 if (m_info->watcher_id == 0) {
421 ERR("Fail to watch name [%s]", bus_name);
422 free(m_info->bus_name);
424 return SERVICE_COMMON_ERROR_IO_ERROR;
426 DBG("Watch on [%s] success", bus_name);
428 monitoring_list = g_list_append(monitoring_list, strdup(bus_name));
429 DBG("Success, sender[%s] length[%d]",
430 sender, g_list_length(monitoring_list));
431 if (g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid)) == nullptr)
432 g_hash_table_insert(*monitoring_hash, GUINT_TO_POINTER(request_uid), monitoring_list);
434 ERR("Sender [%s] already exist", sender);
437 *reply_body = g_variant_new("()");
438 if (*reply_body == nullptr) {
440 if (m_info->bus_name)
441 free(m_info->bus_name);
444 monitoring_list = g_list_remove(monitoring_list, bus_name);
445 ERR("Failed to make reply");
446 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
448 return SERVICE_COMMON_ERROR_NONE;
451 int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender,
453 GList *monitoring_list = nullptr;
454 GList *del_list = nullptr;
457 monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid));
458 if (monitoring_list == nullptr) {
459 ERR("No uid[%d] in monitoring hash", uid);
460 return SERVICE_COMMON_ERROR_IO_ERROR;
463 monitoring_list = g_list_first(monitoring_list);
464 del_list = g_list_find_custom(monitoring_list, sender,
465 (GCompareFunc)_monitoring_app_list_compare_cb);
468 DBG("Find delete list - uid[%d] sender[%s]", uid, sender);
469 bus_name = static_cast<char*>(g_list_nth_data(del_list, 0));
472 monitoring_list = g_list_delete_link(monitoring_list, del_list);
474 if (monitoring_list == nullptr) {
475 g_hash_table_steal(*monitoring_hash, GUINT_TO_POINTER(uid));
477 monitoring_list = g_list_first(monitoring_list);
478 g_hash_table_replace(*monitoring_hash, GUINT_TO_POINTER(uid), monitoring_list);
481 return SERVICE_COMMON_ERROR_NONE;
484 static int _dbus_init(void) {
485 GError *error = nullptr;
487 if (_gdbus_conn == nullptr) {
488 _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
489 if (_gdbus_conn == nullptr) {
490 if (error != nullptr) {
491 ERR("Failed to get dbus [%s]", error->message);
494 return SERVICE_COMMON_ERROR_IO_ERROR;
498 return SERVICE_COMMON_ERROR_NONE;
501 int service_common_register_dbus_interface(char *introspection_xml,
502 GDBusInterfaceVTable interface_vtable) {
504 int owner_id, noti_registration_id;
505 GError *error = nullptr;
506 GDBusNodeInfo *introspection_data = nullptr;
508 result = _dbus_init();
509 if (result != SERVICE_COMMON_ERROR_NONE) {
510 ERR("Can't init dbus [%d]", result);
511 result = SERVICE_COMMON_ERROR_IO_ERROR;
515 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
517 G_BUS_NAME_OWNER_FLAGS_NONE,
523 ERR("Failed to own name");
524 result = SERVICE_COMMON_ERROR_IO_ERROR;
528 DBG("Acquiring the own name [%d]", owner_id);
529 introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error);
530 if (!introspection_data) {
531 ERR("g_dbus_node_info_new_for_xml is failed.");
532 result = SERVICE_COMMON_ERROR_IO_ERROR;
533 if (error != nullptr) {
534 ERR("g_dbus_node_info_new_for_xml err [%s]", error->message);
540 noti_registration_id = g_dbus_connection_register_object(_gdbus_conn,
541 PROVIDER_OBJECT_PATH, introspection_data->interfaces[0],
542 &interface_vtable, nullptr, nullptr, nullptr);
544 DBG("registration id[%d]", noti_registration_id);
545 if (noti_registration_id == 0) {
546 ERR("Failed to g_dbus_connection_register_object");
547 result = SERVICE_COMMON_ERROR_IO_ERROR;
552 if (introspection_data)
553 g_dbus_node_info_unref(introspection_data);
558 static int _init_pkg_privilege_info() {
559 if (_noti_pkg_privilege_info != nullptr)
562 _noti_pkg_privilege_info =
563 g_hash_table_new_full(g_str_hash, g_str_equal, free, nullptr);
564 _badge_pkg_privilege_info =
565 g_hash_table_new_full(g_str_hash, g_str_equal, free, nullptr);
566 DBG("init pkg privilege info done");
570 static int _package_install_cb(uid_t uid, const char *pkgname) {
575 if (uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
576 uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
578 _init_pkg_privilege_info();
579 if (g_hash_table_contains(_noti_pkg_privilege_info, pkgname)) {
580 tmp = g_hash_table_lookup(_noti_pkg_privilege_info, pkgname);
581 privilege_info = GPOINTER_TO_UINT(tmp);
582 if (privilege_info == 1)
583 notification_setting_db_update_pkg_disabled(pkgname, false, uid);
585 g_hash_table_remove(_noti_pkg_privilege_info, pkgname);
587 /* In consideration of the reboot status, change the disable information. */
588 ret = notification_setting_db_update_pkg_disabled(pkgname, false, uid);
589 if (ret != NOTIFICATION_ERROR_NONE)
590 notification_setting_insert_package_for_uid(pkgname, uid);
593 if (g_hash_table_contains(_badge_pkg_privilege_info, pkgname)) {
594 tmp = g_hash_table_lookup(_badge_pkg_privilege_info, pkgname);
595 privilege_info = GPOINTER_TO_UINT(tmp);
596 if (privilege_info == 1)
597 badge_db_update_pkg_disabled(pkgname, false, uid);
599 g_hash_table_remove(_badge_pkg_privilege_info, pkgname);
601 /* In consideration of the reboot status, change the disable information. */
602 ret = badge_db_update_pkg_disabled(pkgname, false, uid);
603 if (ret != BADGE_ERROR_NONE)
604 badge_setting_insert_package_for_uid(pkgname, uid);
610 static int _package_uninstall_cb(uid_t uid, const char *pkgname) {
612 pkgmgrinfo_pkginfo_h pkginfo;
614 if (uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
615 uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
617 ret = pkgmgrinfo_pkginfo_get_usr_disabled_pkginfo(pkgname, uid, &pkginfo);
618 if (ret == PMINFO_R_OK) {
619 pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
621 _init_pkg_privilege_info();
622 ret = notification_setting_db_update_pkg_disabled(pkgname, true, uid);
623 if (ret == NOTIFICATION_ERROR_NONE)
624 g_hash_table_insert(_noti_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(1));
626 g_hash_table_insert(_noti_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(0));
628 ret = badge_db_update_pkg_disabled(pkgname, true, uid);
629 if (ret == BADGE_ERROR_NONE)
630 g_hash_table_insert(_badge_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(1));
632 g_hash_table_insert(_badge_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(0));
634 notification_setting_delete_package_for_uid(pkgname, uid);
635 badge_db_delete_by_pkgname(pkgname, uid);
636 badge_setting_delete_package_for_uid(pkgname, uid);
637 notification_noti_delete_template(pkgname);
643 static int _app_enabled_cb(uid_t uid, const char *app_id) {
644 notification_setting_db_update_app_disabled(app_id, false, uid);
648 static int _app_disabled_cb(uid_t uid, const char *app_id) {
649 notification_delete_noti_by_app_id(app_id, uid);
650 notification_setting_db_update_app_disabled(app_id, true, uid);
654 std::unique_ptr<PackageEventListener> listener_;
656 void service_common_init(void) {
657 pkgmgr_client_ = std::make_unique<PkgmgrClient>();
658 listener_ = std::make_unique<PackageEventListener>();
659 pkgmgr_client_->Listen(listener_.get());
662 void service_common_set_connection(GDBusConnection *conn) {