Refactor legacy C code for pkgmgr_event
[platform/core/appfw/data-provider-master.git] / src / service_common.cc
1 /*
2 * Copyright 2023 Samsung Electronics Co., Ltd
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 <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 #include <gio/gio.h>
22 #include <dlog.h>
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>
29 #include <badge_db.h>
30 #include <package-manager.h>
31 #include <tzplatform_config.h>
32 #include <pkgmgr-info.h>
33
34 #include <list>
35 #include <set>
36 #include <string>
37 #include <string_view>
38 #include <memory>
39
40 #include "debug.h"
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"
46
47 #define DBUS_NAME "org.freedesktop.DBus"
48 #define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
49 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus"
50
51 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
52 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
53
54 using namespace dpm;
55
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_;
62
63 const std::set<std::string_view> pkgmgr_installer_key_list_ = {
64   "install_percent",
65   "start",
66   "end"
67 };
68
69 const std::set<std::string_view> pkgmgr_installer_val_list_ = {
70   "install",
71   "uninstall",
72   "update",
73   "ebable_app",
74   "disable_app"
75 };
76
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);
81
82 class PackageEventListener : public PkgmgrClient::IEvent {
83 public:
84   void OnPkgmgrEvent(std::shared_ptr<PkgmgrEventArgs> args) override;
85   void OnPkgmgrAppEvent(std::shared_ptr<PkgmgrAppEventArgs> args) override;
86 };
87
88 void PackageEventListener::OnPkgmgrEvent(std::shared_ptr<PkgmgrEventArgs> args) {
89   if (pkgmgr_installer_key_list_.find(args->GetEventStatus()) ==
90       pkgmgr_installer_key_list_.end())
91     return;
92
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);
97     return;
98   }
99
100   if (args->GetEventName().compare(std::string("ok")) == 0) {
101     for (auto& a : pkgmgr_event_list_) {
102       if (a->GetTargetUid() == args->GetTargetUid() &&
103           a->GetPkgId().compare(args->GetPkgId()) == 0) {
104         if (a->GetEventName().compare(std::string("install")) == 0)
105           _package_install_cb(args->GetTargetUid(), args->GetPkgId().c_str());
106         else if (a->GetEventName().compare(std::string("uninstall")) == 0)
107           _package_uninstall_cb(args->GetTargetUid(), args->GetPkgId().c_str());
108         else if (a->GetEventName().compare(std::string("enable_app")) == 0)
109           _app_enabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
110         else if (a->GetEventName().compare(std::string("disable_app")) == 0)
111           _app_disabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
112       }
113     }
114   }
115 }
116
117 void PackageEventListener::OnPkgmgrAppEvent(std::shared_ptr<PkgmgrAppEventArgs> args) {
118   if (pkgmgr_installer_key_list_.find(args->GetEventStatus()) ==
119       pkgmgr_installer_key_list_.end())
120     return;
121
122   if (args->GetEventStatus().compare(std::string("start")) == 0 &&
123       pkgmgr_installer_val_list_.find(args->GetEventName()) !=
124       pkgmgr_installer_val_list_.end()) {
125     pkgmgr_app_event_list_.push_back(args);
126     return;
127   }
128
129   if (args->GetEventName().compare(std::string("ok")) == 0) {
130     for (auto& a : pkgmgr_app_event_list_) {
131       if (a->GetTargetUid() == args->GetTargetUid() &&
132           a->GetPkgId().compare(args->GetPkgId()) == 0) {
133         if (a->GetEventName().compare(std::string("install")) == 0)
134           _package_install_cb(args->GetTargetUid(), args->GetPkgId().c_str());
135         else if (a->GetEventName().compare(std::string("uninstall")) == 0)
136           _package_uninstall_cb(args->GetTargetUid(), args->GetPkgId().c_str());
137         else if (a->GetEventName().compare(std::string("enable_app")) == 0)
138           _app_enabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
139         else if (a->GetEventName().compare(std::string("disable_app")) == 0)
140           _app_disabled_cb(args->GetTargetUid(), args->GetPkgId().c_str());
141       }
142     }
143   }
144 }
145
146 uid_t get_sender_uid(const char *sender_name) {
147   GDBusMessage *msg = nullptr;
148   GDBusMessage *reply = nullptr;
149   GError *err = nullptr;
150   GVariant *body;
151   uid_t uid = 0;
152
153   msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
154       DBUS_INTERFACE_NAME, "GetConnectionUnixUser");
155   if (!msg) {
156     LOGE("Failed to alloc new method call");
157     goto out;
158   }
159
160   g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
161   reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
162       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
163
164   if (!reply) {
165     if (err != nullptr) {
166       LOGE("Failed to get uid [%s]", err->message);
167       g_error_free(err);
168     }
169     goto out;
170   }
171
172   body = g_dbus_message_get_body(reply);
173   g_variant_get(body, "(u)", &uid);
174
175 out:
176   if (msg)
177     g_object_unref(msg);
178   if (reply)
179     g_object_unref(reply);
180
181   return uid;
182 }
183
184 pid_t get_sender_pid(const char *sender_name) {
185   GDBusMessage *msg = nullptr;
186   GDBusMessage *reply = nullptr;
187   GError *err = nullptr;
188   GVariant *body;
189   pid_t pid = 0;
190
191   msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
192       DBUS_INTERFACE_NAME, "GetConnectionUnixProcessID");
193   if (!msg) {
194     LOGE("Failed to alloc new method call");
195     goto out;
196   }
197
198   g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
199   reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
200       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
201
202   if (!reply) {
203     if (err != nullptr) {
204       LOGE("Failed to get uid [%s]", err->message);
205       g_error_free(err);
206     }
207     goto out;
208   }
209
210   body = g_dbus_message_get_body(reply);
211   g_variant_get(body, "(u)", &pid);
212
213 out:
214   if (msg)
215     g_object_unref(msg);
216   if (reply)
217     g_object_unref(reply);
218
219   return pid;
220 }
221
222 bool is_existed_busname(const char *sender_name) {
223   GDBusMessage *msg = nullptr;
224   GDBusMessage *reply = nullptr;
225   GError *err = nullptr;
226   GVariant *body;
227   bool is_existed = false;
228
229   msg = g_dbus_message_new_method_call(DBUS_NAME, DBUS_OBJECT_PATH,
230       DBUS_INTERFACE_NAME, "NameHasOwner");
231   if (!msg) {
232     LOGE("Failed to alloc new method call");
233     goto out;
234   }
235
236   g_dbus_message_set_body(msg, g_variant_new("(s)", sender_name));
237   reply = g_dbus_connection_send_message_with_reply_sync(_gdbus_conn, msg,
238       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr, &err);
239
240   if (!reply) {
241     if (err != nullptr) {
242       LOGE("Failed to get uid [%s]", err->message);
243       g_error_free(err);
244     }
245     goto out;
246   }
247
248   body = g_dbus_message_get_body(reply);
249   g_variant_get(body, "(b)", &is_existed);
250
251 out:
252   if (msg)
253     g_object_unref(msg);
254   if (reply)
255     g_object_unref(reply);
256
257   return is_existed;
258 }
259
260 int send_notify(GVariant *body, char *cmd, GHashTable **monitoring_hash,
261     char *interface_name, uid_t uid) {
262   GError *err = nullptr;
263   GList *monitoring_list = nullptr;
264   GList *target_list;
265   char *target_bus_name;
266   int monitoring_count = 0;
267   bool is_existed = false;
268
269   monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid));
270   target_list = g_list_first(monitoring_list);
271   for (; target_list != nullptr; ) {
272     err = nullptr;
273     target_bus_name = static_cast<char*>(target_list->data);
274     target_list = target_list->next;
275
276     if (g_variant_is_floating(body))
277       g_variant_ref(body);
278
279     if (g_dbus_connection_emit_signal(_gdbus_conn,
280           target_bus_name,
281           PROVIDER_OBJECT_PATH,
282           interface_name,
283           cmd,
284           body,
285           &err) == FALSE) {
286       if (err != nullptr) {
287         ERR("Emit signal err [%s]", err->message);
288         g_error_free(err);
289       }
290       is_existed = is_existed_busname(target_bus_name);
291       if (is_existed == false)
292         delete_monitoring_list(monitoring_hash, target_bus_name, uid);
293       ERR("Fail, emit signal to [%s]", target_bus_name);
294     }
295     monitoring_count++;
296     DBG("Success, emit signal to [%s]", target_bus_name);
297   }
298
299   DBG("Success, cmd[%s] monitoring count[%d]", cmd, monitoring_count);
300   return SERVICE_COMMON_ERROR_NONE;
301 }
302
303 int send_event_notify_by_busname(GVariant *body, char *cmd, char *busname,
304     char *interface_name) {
305   GError *err = nullptr;
306
307   if (g_variant_is_floating(body))
308     g_variant_ref(body);
309
310   if (g_dbus_connection_emit_signal(_gdbus_conn,
311             busname,
312             PROVIDER_OBJECT_PATH,
313             interface_name,
314             cmd,
315             body,
316             &err) == FALSE) {
317     if (err != nullptr) {
318       ERR("Emit signal err [%s]",
319           err->message);
320       g_error_free(err);
321     }
322     ERR("Failed to emit signal to [%s]", busname);
323     return SERVICE_COMMON_ERROR_IO_ERROR;
324   }
325   DBG("Success, Emit signal to [%s] cmd[%s]", busname, cmd);
326   return SERVICE_COMMON_ERROR_NONE;
327 }
328
329 /* register service */
330
331 static int _monitoring_app_list_compare_cb(gconstpointer a, gconstpointer b) {
332   return strcmp(static_cast<const char*>(a), reinterpret_cast<const char*>(b));
333 }
334
335 int service_register(GVariant *parameters, GVariant **reply_body, const gchar *sender,
336     GBusNameAppearedCallback name_appeared_handler,
337     GBusNameVanishedCallback name_vanished_handler,
338     GHashTable **monitoring_hash,
339     uid_t uid) {
340   GList *added_list = nullptr;
341   const char *bus_name = sender;
342   monitoring_info_s *m_info = nullptr;
343   uid_t request_uid = 0;
344   GList *monitoring_list = nullptr;
345
346   if (sender == nullptr)
347     return SERVICE_COMMON_ERROR_IO_ERROR;
348
349   g_variant_get(parameters, "(i)", &request_uid);
350   if (uid > NORMAL_UID_BASE && uid != request_uid)
351     return SERVICE_COMMON_ERROR_IO_ERROR;
352
353   DBG("service_register : uid %d , request_uid %d", uid, request_uid);
354   monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid));
355   added_list = g_list_find_custom(monitoring_list, bus_name,
356       (GCompareFunc)_monitoring_app_list_compare_cb);
357
358   if (added_list == nullptr) {
359     DBG("add new sender to list");
360     m_info = (monitoring_info_s *)calloc(1, sizeof(monitoring_info_s));
361     if (m_info == nullptr) {
362       ERR("Failed to alloc memory");
363       return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
364     }
365
366     m_info->bus_name = strdup(bus_name);
367     m_info->uid = request_uid;
368     m_info->watcher_id = g_bus_watch_name_on_connection(
369         _gdbus_conn,
370         bus_name,
371         G_BUS_NAME_WATCHER_FLAGS_NONE,
372         name_appeared_handler,
373         name_vanished_handler,
374         m_info,
375         nullptr);
376     if (m_info->watcher_id == 0) {
377       ERR("Fail to watch name [%s]", bus_name);
378       free(m_info->bus_name);
379       free(m_info);
380       return SERVICE_COMMON_ERROR_IO_ERROR;
381     }
382     DBG("Watch on [%s] success", bus_name);
383
384     monitoring_list = g_list_append(monitoring_list, strdup(bus_name));
385     DBG("Success, sender[%s] length[%d]",
386         sender, g_list_length(monitoring_list));
387     if (g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(request_uid)) == nullptr)
388       g_hash_table_insert(*monitoring_hash, GUINT_TO_POINTER(request_uid), monitoring_list);
389   } else {
390     ERR("Sender [%s] already exist", sender);
391   }
392
393   *reply_body = g_variant_new("()");
394   if (*reply_body == nullptr) {
395     if (m_info) {
396       if (m_info->bus_name)
397         free(m_info->bus_name);
398       free(m_info);
399     }
400     monitoring_list = g_list_remove(monitoring_list, bus_name);
401     ERR("Failed to make reply");
402     return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
403   }
404   return SERVICE_COMMON_ERROR_NONE;
405 }
406
407 int delete_monitoring_list(GHashTable **monitoring_hash, const char *sender,
408     uid_t uid) {
409   GList *monitoring_list = nullptr;
410   GList *del_list = nullptr;
411   char *bus_name;
412
413   monitoring_list = (GList *)g_hash_table_lookup(*monitoring_hash, GUINT_TO_POINTER(uid));
414   if (monitoring_list == nullptr) {
415     ERR("No uid[%d] in monitoring hash", uid);
416     return SERVICE_COMMON_ERROR_IO_ERROR;
417   }
418
419   monitoring_list = g_list_first(monitoring_list);
420   del_list = g_list_find_custom(monitoring_list, sender,
421       (GCompareFunc)_monitoring_app_list_compare_cb);
422
423   if (del_list) {
424     DBG("Find delete list - uid[%d] sender[%s]", uid, sender);
425     bus_name = static_cast<char*>(g_list_nth_data(del_list, 0));
426     if (bus_name)
427       free(bus_name);
428     monitoring_list = g_list_delete_link(monitoring_list, del_list);
429
430     if (monitoring_list == nullptr) {
431       g_hash_table_steal(*monitoring_hash, GUINT_TO_POINTER(uid));
432     } else {
433       monitoring_list = g_list_first(monitoring_list);
434       g_hash_table_replace(*monitoring_hash, GUINT_TO_POINTER(uid), monitoring_list);
435     }
436   }
437   return SERVICE_COMMON_ERROR_NONE;
438 }
439
440 static int _dbus_init(void) {
441   GError *error = nullptr;
442
443   if (_gdbus_conn == nullptr) {
444     _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
445     if (_gdbus_conn == nullptr) {
446       if (error != nullptr) {
447         ERR("Failed to get dbus [%s]", error->message);
448         g_error_free(error);
449       }
450       return SERVICE_COMMON_ERROR_IO_ERROR;
451     }
452   }
453
454   return SERVICE_COMMON_ERROR_NONE;
455 }
456
457 int service_common_register_dbus_interface(char *introspection_xml,
458     GDBusInterfaceVTable interface_vtable) {
459   int result;
460   int owner_id, noti_registration_id;
461   GError *error = nullptr;
462   GDBusNodeInfo *introspection_data = nullptr;
463
464   result = _dbus_init();
465   if (result != SERVICE_COMMON_ERROR_NONE) {
466       ERR("Can't init dbus [%d]", result);
467       result = SERVICE_COMMON_ERROR_IO_ERROR;
468       goto out;
469   }
470
471   owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
472       PROVIDER_BUS_NAME,
473       G_BUS_NAME_OWNER_FLAGS_NONE,
474       nullptr,
475       nullptr,
476       nullptr,
477       nullptr, nullptr);
478   if (!owner_id) {
479     ERR("Failed to own name");
480     result = SERVICE_COMMON_ERROR_IO_ERROR;
481     goto out;
482   }
483
484   DBG("Acquiring the own name [%d]", owner_id);
485   introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error);
486   if (!introspection_data) {
487     ERR("g_dbus_node_info_new_for_xml is failed.");
488     result = SERVICE_COMMON_ERROR_IO_ERROR;
489     if (error != nullptr) {
490       ERR("g_dbus_node_info_new_for_xml err [%s]", error->message);
491       g_error_free(error);
492     }
493     goto out;
494   }
495
496   noti_registration_id = g_dbus_connection_register_object(_gdbus_conn,
497       PROVIDER_OBJECT_PATH, introspection_data->interfaces[0],
498       &interface_vtable, nullptr, nullptr, nullptr);
499
500   DBG("registration id[%d]", noti_registration_id);
501   if (noti_registration_id == 0) {
502     ERR("Failed to g_dbus_connection_register_object");
503     result = SERVICE_COMMON_ERROR_IO_ERROR;
504     goto out;
505   }
506
507 out:
508   if (introspection_data)
509     g_dbus_node_info_unref(introspection_data);
510
511   return result;
512 }
513
514 static int _init_pkg_privilege_info() {
515   if (_noti_pkg_privilege_info != nullptr)
516     return 0;
517
518   _noti_pkg_privilege_info =
519     g_hash_table_new_full(g_str_hash, g_str_equal, free, nullptr);
520   _badge_pkg_privilege_info =
521     g_hash_table_new_full(g_str_hash, g_str_equal, free, nullptr);
522   DBG("init pkg privilege info done");
523   return 0;
524 }
525
526 static int _package_install_cb(uid_t uid, const char *pkgname) {
527   int ret;
528   gpointer tmp;
529   int privilege_info;
530
531   if (uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
532     uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
533
534   _init_pkg_privilege_info();
535   if (g_hash_table_contains(_noti_pkg_privilege_info, pkgname)) {
536     tmp = g_hash_table_lookup(_noti_pkg_privilege_info, pkgname);
537     privilege_info = GPOINTER_TO_UINT(tmp);
538     if (privilege_info == 1)
539       notification_setting_db_update_pkg_disabled(pkgname, false, uid);
540
541     g_hash_table_remove(_noti_pkg_privilege_info, pkgname);
542   } else {
543     /* In consideration of the reboot status, change the disable information. */
544     ret = notification_setting_db_update_pkg_disabled(pkgname, false, uid);
545     if (ret != NOTIFICATION_ERROR_NONE)
546       notification_setting_insert_package_for_uid(pkgname, uid);
547   }
548
549   if (g_hash_table_contains(_badge_pkg_privilege_info, pkgname)) {
550     tmp = g_hash_table_lookup(_badge_pkg_privilege_info, pkgname);
551     privilege_info = GPOINTER_TO_UINT(tmp);
552     if (privilege_info == 1)
553       badge_db_update_pkg_disabled(pkgname, false, uid);
554
555     g_hash_table_remove(_badge_pkg_privilege_info, pkgname);
556   } else {
557     /* In consideration of the reboot status, change the disable information. */
558     ret = badge_db_update_pkg_disabled(pkgname, false, uid);
559     if (ret != BADGE_ERROR_NONE)
560       badge_setting_insert_package_for_uid(pkgname, uid);
561   }
562
563   return 0;
564 }
565
566 static int _package_uninstall_cb(uid_t uid, const char *pkgname) {
567   int ret;
568   pkgmgrinfo_pkginfo_h pkginfo;
569
570   if (uid == tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))
571     uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
572
573   ret = pkgmgrinfo_pkginfo_get_usr_disabled_pkginfo(pkgname, uid, &pkginfo);
574   if (ret == PMINFO_R_OK) {
575     pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
576
577     _init_pkg_privilege_info();
578     ret = notification_setting_db_update_pkg_disabled(pkgname, true, uid);
579     if (ret == NOTIFICATION_ERROR_NONE)
580       g_hash_table_insert(_noti_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(1));
581     else
582       g_hash_table_insert(_noti_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(0));
583
584     ret = badge_db_update_pkg_disabled(pkgname, true, uid);
585     if (ret == BADGE_ERROR_NONE)
586       g_hash_table_insert(_badge_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(1));
587     else
588       g_hash_table_insert(_badge_pkg_privilege_info, strdup(pkgname), GUINT_TO_POINTER(0));
589   } else {
590     notification_setting_delete_package_for_uid(pkgname, uid);
591     badge_db_delete_by_pkgname(pkgname, uid);
592     badge_setting_delete_package_for_uid(pkgname, uid);
593     notification_noti_delete_template(pkgname);
594   }
595
596   return 0;
597 }
598
599 static int _app_enabled_cb(uid_t uid, const char *app_id) {
600   notification_setting_db_update_app_disabled(app_id, false, uid);
601   return 0;
602 }
603
604 static int _app_disabled_cb(uid_t uid, const char *app_id) {
605   notification_delete_noti_by_app_id(app_id, uid);
606   notification_setting_db_update_app_disabled(app_id, true, uid);
607   return 0;
608 }
609
610 std::unique_ptr<PackageEventListener> listener_;
611
612 void service_common_init(void) {
613   pkgmgr_client_ = std::make_unique<PkgmgrClient>();
614   listener_ = std::make_unique<PackageEventListener>();
615   pkgmgr_client_->Listen(listener_.get());
616 }
617
618 void service_common_set_connection(GDBusConnection *conn) {
619   _gdbus_conn = conn;
620 }