GVFS monitor device change by gdu module

Summary:

  The device monitor flow looks like:

kernel                                                                                                                                                                ->

udev                       (use cdrom_id/usb_id/... to read HW)                                                                          ->
udisks                    (monitor device change and collect/map device property to dbus)                       ->
gnome-disk-utility(connect udisks dbus and map as libgdu)                                                                  ->
gvfs                         (monitor gdu_pool or mtab/fstab file to generate signal)                                         ->

GVolumeMonitor signal


  gvfs-gdu-volume-monitor can monitor drive/volume/mount change, it depend on libgdu which belong gnome-disk-utility rpm. The libgdu get disks property from dbus of "org.freedesktop.UDisks"(udisks rpm).
1. gdu-volume-monitor-daemon create gduvolumemonitor(real monitor device's status) instance
2. request dbus connection
3. connect gduvolumemonitor signal(drive-changed/volume-added...) dispatch to dbus signal

./monitor/gdu/gdu-volume-monitor-daemon.c:
main(){
  return g_vfs_proxy_volume_monitor_daemon_main (argc,
                                                 argv,
                                                 "org.gtk.Private.GduVolumeMonitor",
                                                 G_TYPE_GDU_VOLUME_MONITOR);
}

./monitor/proxy/gvfsproxyvolumemonitordaemon.c:
g_vfs_proxy_volume_monitor_daemon_main (int argc,
                                        char *argv[],
                                        const char *dbus_name,
                                        GType volume_monitor_type){
  monitor = G_VOLUME_MONITOR (g_object_new (volume_monitor_type, NULL));
  dbus_bus_request_name (connection,
                         dbus_name,
                         DBUS_NAME_FLAG_ALLOW_REPLACEMENT |
                         DBUS_NAME_FLAG_DO_NOT_QUEUE |
                         DBUS_NAME_FLAG_REPLACE_EXISTING,
                         &dbus_error);

  g_signal_connect (monitor, "drive-changed", (GCallback) drive_changed, connection);
  g_signal_connect (monitor, "drive-connected", (GCallback) drive_connected, connection);
  g_signal_connect (monitor, "drive-disconnected", (GCallback) drive_disconnected, connection);
  g_signal_connect (monitor, "drive-eject-button", (GCallback) drive_eject_button, connection);
  g_signal_connect (monitor, "drive-stop-button", (GCallback) drive_stop_button, connection);

  g_signal_connect (monitor, "volume-changed", (GCallback) volume_changed, connection);
  g_signal_connect (monitor, "volume-added", (GCallback) volume_added, connection);
  g_signal_connect (monitor, "volume-removed", (GCallback) volume_removed, connection);

  g_signal_connect (monitor, "mount-changed", (GCallback) mount_changed, connection);
  g_signal_connect (monitor, "mount-added", (GCallback) mount_added, connection);
  g_signal_connect (monitor, "mount-pre-unmount", (GCallback) mount_pre_unmount, connection);
  g_signal_connect (monitor, "mount-removed", (GCallback) mount_removed, connection);

}

static void
drive_disconnected (GVolumeMonitor *monitor, GDrive *drive, DBusConnection *connection)
{
  emit_signal (connection, "DriveDisconnected", drive, (AppendFunc) append_drive);
}

Trace gduvolumemonitor:
1. construct:
   a. init g_unix_mount_monitor instance to monitor mount change
   b. init gdu_pool instance to monitor device change
   c. connect "mounts_changed/presentable_added..." signal for invoke update_all()
2. update_all(drive for example, it's same as volume/mount):
   a. call update_drives() get the current drive list(previous store in monitor->drives)
   b. diff current list(monitor->drives) with the new list(real-time store in monitor->pool and ignor fstab)
   c. if diff list not null, list_emit change signal("drive_connected/drive_disconnected") to outside
   d. gdu-volume-monitor-daemon will catch the signal and send to dbus

g_gdu_volume_monitor_constructor (){
  monitor = G_GDU_VOLUME_MONITOR (object);

  monitor->mount_monitor = g_unix_mount_monitor_new ();

  g_signal_connect (monitor->mount_monitor,
                    "mounts_changed",
                    G_CALLBACK (mounts_changed),
                    monitor);

  g_signal_connect (monitor->mount_monitor,
                    "mountpoints_changed",
                    G_CALLBACK (mountpoints_changed),
                    monitor);
  monitor->pool = gdu_pool_new ();

  g_signal_connect (monitor->pool,
                    "presentable_added",
                    G_CALLBACK (presentable_added),
                    monitor);

  g_signal_connect (monitor->pool,
                    "presentable_removed",
                    G_CALLBACK (presentable_removed),
                    monitor);

  g_signal_connect (monitor->pool,
                    "presentable_changed",
                    G_CALLBACK (presentable_changed),
                    monitor);

  g_signal_connect (monitor->pool,
                    "presentable_job_changed",
                    G_CALLBACK (presentable_job_changed),
                    monitor);
  update_all (monitor, TRUE);
}

update_all (GGduVolumeMonitor *monitor,
            gboolean emit_changes){
  GList *added_drives, *removed_drives;
  GList *added_volumes, *removed_volumes;
  GList *added_mounts, *removed_mounts;

  added_drives = NULL;
  removed_drives = NULL;
  added_volumes = NULL;
  removed_volumes = NULL;
  added_mounts = NULL;
  removed_mounts = NULL;

  update_drives (monitor, &added_drives, &removed_drives);
  update_volumes (monitor, &added_volumes, &removed_volumes);
  update_fstab_volumes (monitor, &added_volumes, &removed_volumes);
  update_mounts (monitor, &added_mounts, &removed_mounts);
  update_discs (monitor,
                &added_volumes, &removed_volumes,
                &added_mounts, &removed_mounts);

  if (emit_changes)
    {
      list_emit (monitor,
                 "drive_disconnected", NULL,
                 removed_drives);
      list_emit (monitor,
                 "drive_connected", NULL,
                 added_drives);

      list_emit (monitor,
                 "volume_removed", "removed",
                added_volumes);

      list_emit (monitor,
                 "mount_removed", "unmounted",
                 removed_mounts);
      list_emit (monitor,
                 "mount_added", NULL,
                 added_mounts);
    }
}

static void
update_drives (GGduVolumeMonitor *monitor,
               GList **added_drives,
               GList **removed_drives){
  cur_drives = NULL;
  for (l = monitor->drives; l != NULL; l = l->next)
    cur_drives = g_list_prepend (cur_drives, g_gdu_drive_get_presentable (G_GDU_DRIVE (l->data)));

  new_drives = gdu_pool_get_presentables (monitor->pool);
  for (l = new_drives; l != NULL; l = ll)
    {
      GduPresentable *p = GDU_PRESENTABLE (l->data);
      ll = l->next;
      if (!GDU_IS_DRIVE (p) || should_drive_be_ignored (monitor->pool, GDU_DRIVE (p), fstab_mount_points))
        {
          g_object_unref (p);
          new_drives = g_list_delete_link (new_drives, l);
        }
    }
  diff_sorted_lists (cur_drives,
                     new_drives, (GCompareFunc) gdu_presentable_compare,
                     &added, &removed);

  for (l = removed; l != NULL; l = l->next)
    {
      GduPresentable *p = GDU_PRESENTABLE (l->data);

      drive = find_drive_by_presentable (monitor, p);
      if (drive != NULL)
        {
          /*g_debug ("removing drive %s", gdu_presentable_get_id (p));*/
          g_gdu_drive_disconnected (drive);
          monitor->drives = g_list_remove (monitor->drives, drive);
          *removed_drives = g_list_prepend (*removed_drives, drive);
        }
    }
  for (l = added; l != NULL; l = l->next)
    {
      GduPresentable *p = GDU_PRESENTABLE (l->data);

      drive = find_drive_by_presentable (monitor, p);
      if (drive == NULL)
        {
          /*g_debug ("adding drive %s", gdu_presentable_get_id (p));*/
          drive = g_gdu_drive_new (G_VOLUME_MONITOR (monitor), p);
          if (drive != NULL)
            {
              monitor->drives = g_list_prepend (monitor->drives, drive);
              *added_drives = g_list_prepend (*added_drives, g_object_ref (drive));
            }
        }
    }
}
 

Trace gdupool:

猜你喜欢

转载自socol.iteye.com/blog/1074052