[sysprof] perf: delay source start until polkit has authorized



commit a7982ad1e85ddef64e059bf5a107dc0d423fa8e6
Author: Christian Hergert <christian hergert me>
Date:   Thu Apr 14 04:36:18 2016 -0700

    perf: delay source start until polkit has authorized
    
    Without this, after logging in you are already multiple seconds into your
    profiling session recording. Not ideal. So instead, we do the async polkit
    auth upfront during SpSource::prepare(), and then toggle ready after we
    have received notification.

 lib/sp-perf-counter.c |  130 +++++++++++++++++++++++++++++++++++++++++++++++--
 lib/sp-perf-counter.h |    8 +++-
 lib/sp-perf-source.c  |   46 +++++++++++++++++
 3 files changed, 179 insertions(+), 5 deletions(-)
---
diff --git a/lib/sp-perf-counter.c b/lib/sp-perf-counter.c
index d400d5f..dd01539 100644
--- a/lib/sp-perf-counter.c
+++ b/lib/sp-perf-counter.c
@@ -118,6 +118,10 @@ G_DEFINE_BOXED_TYPE (SpPerfCounter,
                      (GBoxedCopyFunc)sp_perf_counter_ref,
                      (GBoxedFreeFunc)sp_perf_counter_unref)
 
+#if ENABLE_SYSPROFD
+static GDBusConnection *shared_conn;
+#endif
+
 static gboolean
 perf_gsource_dispatch (GSource     *source,
                        GSourceFunc  callback,
@@ -413,16 +417,17 @@ static GDBusProxy *
 get_proxy (void)
 {
   static GDBusProxy *proxy;
-  GDBusConnection *bus = NULL;
 
   if (proxy != NULL)
     return g_object_ref (proxy);
 
-  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
-  if (bus == NULL)
+  if (shared_conn == NULL)
+    shared_conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
+
+  if (shared_conn == NULL)
     return NULL;
 
-  proxy = g_dbus_proxy_new_sync (bus,
+  proxy = g_dbus_proxy_new_sync (shared_conn,
                                  (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                                   G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
                                   G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION),
@@ -490,7 +495,124 @@ get_authorized_proxy (void)
 
   return NULL;
 }
+
+
+static void
+sp_perf_counter_acquire_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
+{
+  g_autoptr(GTask) task = user_data;
+  GPermission *permission = (GPermission *)object;
+  GError *error = NULL;
+
+  g_assert (G_IS_PERMISSION (permission));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!g_permission_acquire_finish (permission, result, &error))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  g_task_return_boolean (task, TRUE);
+}
+
+static void
+sp_perf_counter_permission_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
+{
+  g_autoptr(GTask) task = user_data;
+  GPermission *permission;
+  GError *error = NULL;
+
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (NULL == (permission = polkit_permission_new_finish (result, &error)))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  g_permission_acquire_async (permission,
+                              g_task_get_cancellable (task),
+                              sp_perf_counter_acquire_cb,
+                              g_object_ref (task));
+
+  g_object_unref (permission);
+}
+
+static void
+sp_perf_counter_get_bus_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
+{
+  g_autoptr(GDBusConnection) bus = NULL;
+  g_autoptr(GTask) task = user_data;
+  PolkitSubject *subject = NULL;
+  const gchar *name;
+  GError *error = NULL;
+
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (NULL == (bus = g_bus_get_finish (result, &error)))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  shared_conn = g_object_ref (bus);
+
+  name = g_dbus_connection_get_unique_name (bus);
+  subject = polkit_system_bus_name_new (name);
+
+  polkit_permission_new ("org.gnome.sysprof2.perf-event-open",
+                         subject,
+                         g_task_get_cancellable (task),
+                         sp_perf_counter_permission_cb,
+                         g_object_ref (task));
+
+  g_object_unref (subject);
+}
+
+#endif
+
+void
+sp_perf_counter_authorize_async (GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (NULL, cancellable, callback, user_data);
+
+#if ENABLE_SYSPROFD
+  g_bus_get (G_BUS_TYPE_SYSTEM,
+             cancellable,
+             sp_perf_counter_get_bus_cb,
+             g_object_ref (task));
+#else
+  g_task_return_new_error (error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "Sysprofd is not supported in current configuration");
 #endif
+}
+
+gboolean
+sp_perf_counter_authorize_finish (GAsyncResult  *result,
+                                  GError       **error)
+{
+  g_assert (G_IS_TASK (result));
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
 
 gint
 sp_perf_counter_open (SpPerfCounter          *self,
diff --git a/lib/sp-perf-counter.h b/lib/sp-perf-counter.h
index d90f8b9..2d870ad 100644
--- a/lib/sp-perf-counter.h
+++ b/lib/sp-perf-counter.h
@@ -19,7 +19,7 @@
 #ifndef SP_PERF_COUNTER_H
 #define SP_PERF_COUNTER_H
 
-#include <glib-object.h>
+#include <gio/gio.h>
 #include <linux/perf_event.h>
 
 
@@ -110,6 +110,12 @@ typedef void (*SpPerfCounterCallback) (SpPerfCounterEvent *event,
                                        guint               cpu,
                                        gpointer            user_data);
 
+void     sp_perf_counter_authorize_async  (GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data);
+gboolean sp_perf_counter_authorize_finish (GAsyncResult         *result,
+                                           GError              **error);
+
 GType          sp_perf_counter_get_type     (void);
 SpPerfCounter *sp_perf_counter_new          (GMainContext           *context);
 void           sp_perf_counter_set_callback (SpPerfCounter          *self,
diff --git a/lib/sp-perf-source.c b/lib/sp-perf-source.c
index 8a4f754..e5d4455 100644
--- a/lib/sp-perf-source.c
+++ b/lib/sp-perf-source.c
@@ -55,6 +55,7 @@ struct _SpPerfSource
   GHashTable      *pids;
 
   guint            running : 1;
+  guint            is_ready : 1;
 };
 
 static void source_iface_init (SpSourceInterface *iface);
@@ -431,12 +432,57 @@ sp_perf_source_add_pid (SpSource *source,
 }
 
 static void
+sp_perf_source_authorize_cb (GObject      *object,
+                             GAsyncResult *result,
+                             gpointer      user_data)
+{
+  g_autoptr(SpPerfSource) self = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (G_IS_ASYNC_RESULT (result));
+
+  if (!sp_perf_counter_authorize_finish (result, &error))
+    {
+      sp_source_emit_failed (SP_SOURCE (self), error);
+      return;
+    }
+
+  self->is_ready = TRUE;
+
+  sp_source_emit_ready (SP_SOURCE (self));
+}
+
+static void
+sp_perf_source_prepare (SpSource *source)
+{
+  SpPerfSource *self = (SpPerfSource *)source;
+
+  g_assert (SP_IS_PERF_SOURCE (self));
+
+  sp_perf_counter_authorize_async (NULL,
+                                   sp_perf_source_authorize_cb,
+                                   g_object_ref (self));
+}
+
+static gboolean
+sp_perf_source_get_is_ready (SpSource *source)
+{
+  SpPerfSource *self = (SpPerfSource *)source;
+
+  g_assert (SP_IS_PERF_SOURCE (self));
+
+  return self->is_ready;
+}
+
+static void
 source_iface_init (SpSourceInterface *iface)
 {
   iface->start = sp_perf_source_start;
   iface->stop = sp_perf_source_stop;
   iface->set_writer = sp_perf_source_set_writer;
   iface->add_pid = sp_perf_source_add_pid;
+  iface->prepare = sp_perf_source_prepare;
+  iface->get_is_ready = sp_perf_source_get_is_ready;
 }
 
 SpSource *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]