diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/adbd-client.cpp | 25 | ||||
| -rw-r--r-- | src/greeter.cpp | 192 | ||||
| -rw-r--r-- | src/greeter.h | 10 | ||||
| -rw-r--r-- | src/usb-manager.cpp | 103 | ||||
| -rw-r--r-- | src/usb-snap.cpp | 1 | 
5 files changed, 206 insertions, 125 deletions
| diff --git a/src/adbd-client.cpp b/src/adbd-client.cpp index 400c7c9..47914cb 100644 --- a/src/adbd-client.cpp +++ b/src/adbd-client.cpp @@ -23,6 +23,7 @@  #include <gio/gunixsocketaddress.h>  #include <algorithm> +#include <atomic>  #include <cctype>  #include <cstring>  #include <chrono> @@ -48,7 +49,9 @@ public:          g_cancellable_cancel(m_cancellable);          m_pkresponse_cv.notify_one();          m_sleep_cv.notify_one(); -        m_worker_thread.join(); +        if (m_worker_thread.joinable()) { +            m_worker_thread.join(); +        }          g_clear_object(&m_cancellable);      } @@ -66,7 +69,7 @@ private:          GCancellable* cancellable = nullptr;          const std::string public_key; -        PKIdleData(Impl* self_, GCancellable* cancellable_, std::string public_key_): +        PKIdleData(Impl* self_, GCancellable* cancellable_, const std::string& public_key_):              self(self_),              cancellable(G_CANCELLABLE(g_object_ref(cancellable_))),              public_key(public_key_) {} @@ -104,8 +107,9 @@ private:      void on_public_key_response(PKResponse response)      { +        g_debug("%s thread %p got response %d", G_STRLOC, g_thread_self(), int(response)); +          // set m_pkresponse and wake up the waiting worker thread -        std::unique_lock<std::mutex> lk(m_pkresponse_mutex);          m_pkresponse = response;          m_pkresponse_ready = true;          m_pkresponse_cv.notify_one(); @@ -121,11 +125,11 @@ private:          while (!g_cancellable_is_cancelled(m_cancellable))          { -            g_debug("%s creating a client socket to '%s'", G_STRLOC, socket_path.c_str()); +            g_debug("%s thread %p creating a client socket to '%s'", G_STRLOC, g_thread_self(), socket_path.c_str());              auto socket = create_client_socket(socket_path);              bool got_valid_req = false; -            g_debug("%s calling read_request", G_STRLOC); +            g_debug("%s thread %p calling read_request", g_thread_self(), G_STRLOC);              std::string reqstr;              if (socket != nullptr)                  reqstr = read_request(socket); @@ -135,22 +139,25 @@ private:              if (reqstr.substr(0,2) == "PK") {                  PKResponse response = PKResponse::DENY;                  const auto public_key = reqstr.substr(2); -                g_debug("%s got pk [%s]", G_STRLOC, public_key.c_str()); +                g_debug("%s thread %p got pk [%s]", G_STRLOC, g_thread_self(), public_key.c_str());                  if (!public_key.empty()) {                      got_valid_req = true;                      std::unique_lock<std::mutex> lk(m_pkresponse_mutex);                      m_pkresponse_ready = false; +                    m_pkresponse = AdbdClient::PKResponse::DENY;                      pass_public_key_to_main_thread(public_key);                      m_pkresponse_cv.wait(lk, [this](){                          return m_pkresponse_ready || g_cancellable_is_cancelled(m_cancellable);                      });                      response = m_pkresponse; -                    g_debug("%s got response '%d', is-cancelled %d", G_STRLOC, +                    g_debug("%s thread %p got response '%d', is-cancelled %d", G_STRLOC, +                            g_thread_self(),                              int(response),                              int(g_cancellable_is_cancelled(m_cancellable)));                  } -                if (!g_cancellable_is_cancelled(m_cancellable)) +                if (!g_cancellable_is_cancelled(m_cancellable)) {                      send_pk_response(socket, response); +                }              } else if (!reqstr.empty()) {                  g_warning("Invalid ADB request: [%s]", reqstr.c_str());              } @@ -270,7 +277,7 @@ private:      std::mutex m_pkresponse_mutex;      std::condition_variable m_pkresponse_cv; -    bool m_pkresponse_ready = false; +    std::atomic<bool> m_pkresponse_ready {false};      PKResponse m_pkresponse = PKResponse::DENY;  }; diff --git a/src/greeter.cpp b/src/greeter.cpp index f9cd965..3d0f347 100644 --- a/src/greeter.cpp +++ b/src/greeter.cpp @@ -26,117 +26,167 @@ class UnityGreeter::Impl  {  public: -    Impl(): -        m_cancellable{g_cancellable_new()} +    Impl()      { -        g_bus_get(G_BUS_TYPE_SESSION, m_cancellable, on_bus_ready_static, this); +        m_cancellable.reset( +            g_cancellable_new(), +            [](GCancellable* o){ +                g_cancellable_cancel(o); +                g_clear_object(&o); +            } +        ); + +        g_bus_get(G_BUS_TYPE_SESSION, m_cancellable.get(), on_bus_ready, this);      } -    ~Impl() -    { -        g_cancellable_cancel(m_cancellable); -        g_clear_object(&m_cancellable); - -        if (m_subscription_id != 0) -            g_dbus_connection_signal_unsubscribe (m_bus, m_subscription_id); +    ~Impl() =default; -        g_clear_object(&m_bus); -    } - -    core::Property<bool>& is_active() +    core::Property<State>& state()      { -        return m_is_active; +        return m_state;      }  private: -    static void on_bus_ready_static(GObject* /*source*/, GAsyncResult* res, gpointer gself) +    void set_state(const State& state) +    { +        m_state.set(state); +    } + +    static void on_bus_ready( +        GObject* /*source*/, +        GAsyncResult* res, +        gpointer gself)      {          GError* error {}; -        auto bus = g_bus_get_finish (res, &error); -        if (error != nullptr) { +        auto bus = g_bus_get_finish(res, &error); +        if (error != nullptr) +        {              if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) -                g_warning("UsbSnap: Error getting session bus: %s", error->message); +                g_warning("Greeter: Error getting bus: %s", error->message);              g_clear_error(&error); -        } else { -            static_cast<Impl*>(gself)->on_bus_ready(bus);          } -        g_clear_object(&bus); +        else +        { +            auto self = static_cast<Impl*>(gself); + +            const auto watcher_id = g_bus_watch_name_on_connection( +                bus, +                DBusNames::UnityGreeter::NAME, +                G_BUS_NAME_WATCHER_FLAGS_AUTO_START, +                on_greeter_appeared, +                on_greeter_vanished, +                gself, +                nullptr); + +            const auto subscription_id = g_dbus_connection_signal_subscribe( +                bus, +                DBusNames::UnityGreeter::NAME, +                DBusNames::Properties::INTERFACE, +                DBusNames::Properties::PropertiesChanged::NAME, +                DBusNames::UnityGreeter::PATH, +                DBusNames::UnityGreeter::INTERFACE, +                G_DBUS_SIGNAL_FLAGS_NONE, +                on_properties_changed_signal, +                gself, +                nullptr); + +            self->m_bus.reset( +                bus, +                [watcher_id, subscription_id](GDBusConnection* o){ +                    g_bus_unwatch_name(watcher_id); +                    g_dbus_connection_signal_unsubscribe(o, subscription_id); +                    g_clear_object(&o); +                } +            ); +        } +    } + +    static void on_greeter_appeared( +        GDBusConnection* bus, +        const char* /*name*/, +        const char* name_owner, +        gpointer gself) +    { +        auto self = static_cast<Impl*>(gself); + +        self->m_owner = name_owner; + +        g_dbus_connection_call( +            bus, +            DBusNames::UnityGreeter::NAME, +            DBusNames::UnityGreeter::PATH, +            DBusNames::Properties::INTERFACE, +            "Get", +            g_variant_new("(ss)", DBusNames::UnityGreeter::INTERFACE, "IsActive"), +            G_VARIANT_TYPE("(v)"), +            G_DBUS_CALL_FLAGS_NONE, +            -1, +            self->m_cancellable.get(), +            on_get_is_active_ready, +            gself);      } -    void on_bus_ready(GDBusConnection* bus) +    static void on_greeter_vanished( +        GDBusConnection* /*bus*/, +        const char* /*name*/, +        gpointer gself)      { -        m_bus = G_DBUS_CONNECTION(g_object_ref(G_OBJECT(bus))); - -        g_dbus_connection_call(m_bus, -                               DBusNames::UnityGreeter::NAME, -                               DBusNames::UnityGreeter::PATH, -                               DBusNames::Properties::INTERFACE, -                               "Get", -                               g_variant_new("(ss)", DBusNames::UnityGreeter::INTERFACE, "IsActive"), -                               G_VARIANT_TYPE("(v)"), -                               G_DBUS_CALL_FLAGS_NONE, -                               -1, -                               m_cancellable, -                               on_get_is_active_ready, -                               this); - -        m_subscription_id = g_dbus_connection_signal_subscribe(m_bus, -                                                               DBusNames::UnityGreeter::NAME, -                                                               DBusNames::Properties::INTERFACE, -                                                               DBusNames::Properties::PropertiesChanged::NAME, -                                                               DBusNames::UnityGreeter::PATH, -                                                               DBusNames::UnityGreeter::INTERFACE, -                                                               G_DBUS_SIGNAL_FLAGS_NONE, -                                                               on_properties_changed_signal, -                                                               this, -                                                               nullptr); +        auto self = static_cast<Impl*>(gself); + +        self->m_owner.clear(); +        self->set_state(State::UNAVAILABLE);      } -    static void on_get_is_active_ready(GObject* source, GAsyncResult* res, gpointer gself) +    static void on_get_is_active_ready( +        GObject* source, +        GAsyncResult* res,  +        gpointer gself)      {          GError* error {};          auto v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);          if (error != nullptr) { -            if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) -                g_warning("UsbSnap: Error getting session bus: %s", error->message); +            if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { +                g_warning("Greeter: Error getting IsActive property: %s", error->message); +            }              g_clear_error(&error);          } else {              GVariant* is_active {};              g_variant_get_child(v, 0, "v", &is_active); -            static_cast<Impl*>(gself)->m_is_active.set(g_variant_get_boolean(is_active)); +            static_cast<Impl*>(gself)->set_state(g_variant_get_boolean(is_active) ? State::ACTIVE : State::INACTIVE);              g_clear_pointer(&is_active, g_variant_unref);          }          g_clear_pointer(&v, g_variant_unref);      } -    static void on_properties_changed_signal(GDBusConnection* /*connection*/, -                                             const gchar* /*sender_name*/, -                                             const gchar* object_path, -                                             const gchar* interface_name, -                                             const gchar* signal_name, -                                             GVariant* parameters, -                                             gpointer gself) +    static void on_properties_changed_signal( +        GDBusConnection* /*bus*/, +        const gchar* sender_name, +        const gchar* object_path, +        const gchar* interface_name, +        const gchar* signal_name, +        GVariant* parameters, +        gpointer gself)      { +        auto self = static_cast<Impl*>(gself); + +        g_return_if_fail(!g_strcmp0(sender_name, self->m_owner.c_str()));          g_return_if_fail(!g_strcmp0(object_path, DBusNames::UnityGreeter::PATH));          g_return_if_fail(!g_strcmp0(interface_name, DBusNames::Properties::INTERFACE));          g_return_if_fail(!g_strcmp0(signal_name, DBusNames::Properties::PropertiesChanged::NAME));          g_return_if_fail(g_variant_is_of_type(parameters, G_VARIANT_TYPE(DBusNames::Properties::PropertiesChanged::ARGS_VARIANT_TYPE))); -        auto v = g_variant_get_child_value (parameters, 1); +        auto v = g_variant_get_child_value(parameters, 1);          gboolean is_active {};          if (g_variant_lookup(v, "IsActive", "b", &is_active)) -        { -            g_debug("%s is_active changed to %d", G_STRLOC, int(is_active)); -            static_cast<Impl*>(gself)->m_is_active.set(is_active); -        } +            self->set_state(is_active ? State::ACTIVE : State::INACTIVE);          g_clear_pointer(&v, g_variant_unref);      } -    core::Property<bool> m_is_active; -    GCancellable* m_cancellable {}; -    GDBusConnection* m_bus {}; -    unsigned int m_subscription_id {}; +    core::Property<State> m_state {State::UNAVAILABLE}; +    std::shared_ptr<GCancellable> m_cancellable; +    std::shared_ptr<GDBusConnection> m_bus; +    std::string m_owner;  };  /*** @@ -154,8 +204,8 @@ UnityGreeter::UnityGreeter():  UnityGreeter::~UnityGreeter() =default; -core::Property<bool>& -UnityGreeter::is_active() +core::Property<Greeter::State>& +UnityGreeter::state()  { -    return impl->is_active(); +    return impl->state();  } diff --git a/src/greeter.h b/src/greeter.h index e084d25..f3012f6 100644 --- a/src/greeter.h +++ b/src/greeter.h @@ -29,7 +29,13 @@ class Greeter  public:      Greeter();      virtual ~Greeter(); -    virtual core::Property<bool>& is_active() =0; + +    enum class State { UNAVAILABLE, INACTIVE, ACTIVE }; +static inline const char* state_str(const State& state) { +    static constexpr char const * state_str[] = { "Unavailable", "Inactive", "Active" }; +    return state_str[int(state)]; +} +    virtual core::Property<State>& state() =0;  }; @@ -38,7 +44,7 @@ class UnityGreeter: public Greeter  public:      UnityGreeter();      virtual ~UnityGreeter(); -    core::Property<bool>& is_active() override; +    core::Property<State>& state() override;  protected:      class Impl; diff --git a/src/usb-manager.cpp b/src/usb-manager.cpp index 4d750c0..f83b5f1 100644 --- a/src/usb-manager.cpp +++ b/src/usb-manager.cpp @@ -46,72 +46,89 @@ public:          m_greeter{greeter}      {          m_usb_monitor->on_usb_disconnected().connect([this](const std::string& /*usb_name*/) { -            restart(); +            m_req.reset();          }); -        m_greeter->is_active().changed().connect([this](bool /*is_active*/) { -            maybe_snap(); +        m_greeter->state().changed().connect([this](const Greeter::State& state) { +            if (state == Greeter::State::INACTIVE) { +                maybe_snap(); +            } else { +                stop_snap(); +            }          }); -        restart(); +        // create a new adbd client +        m_adbd_client.reset(new GAdbdClient{m_socket_path}); +        m_adbd_client->on_pk_request().connect( +            [this](const AdbdClient::PKRequest& req) { +                g_debug("%s got pk request: %s, calling maybe_snap()", G_STRLOC, req.fingerprint.c_str()); + +                m_response = AdbdClient::PKResponse::DENY; // set the fallback response +                m_req.reset( +                    new AdbdClient::PKRequest(req), +                    [this](AdbdClient::PKRequest* r) { +                        stop_snap(); +                        r->respond(m_response); +                        delete r; +                    } +                ); +                maybe_snap(); +            } +        );      }      ~Impl()      { -        if (m_restart_idle_tag) -            g_source_remove(m_restart_idle_tag); - -        clear(); +        if (m_request_complete_idle_tag) { +            g_source_remove(m_request_complete_idle_tag); +        }      }  private: -    void clear() +    void stop_snap()      { -        // clear out old state          m_snap_connections.clear();          m_snap.reset(); -        m_req = decltype(m_req)(); -        m_adbd_client.reset();      } -    void restart() +    void maybe_snap()      { -        clear(); +        // only prompt if there's something to prompt about +        if (!m_req) { +            return; +        } -        // set a new client -        m_adbd_client.reset(new GAdbdClient{m_socket_path}); -        m_adbd_client->on_pk_request().connect( -            [this](const AdbdClient::PKRequest& req) { -                g_debug("%s got pk request: %s", G_STRLOC, req.fingerprint.c_str()); -                m_req = req; -                maybe_snap(); -            } -        ); -    } +        // only prompt in an unlocked session +        if (m_greeter->state().get() != Greeter::State::INACTIVE) { +            return; +        } -    void maybe_snap() -    { -        // don't prompt in the greeter! -        if (!m_req.public_key.empty() && !m_greeter->is_active().get()) -            snap(); +        snap();      }      void snap()      { -        m_snap = std::make_shared<UsbSnap>(m_req.fingerprint); +        m_snap = std::make_shared<UsbSnap>(m_req->fingerprint);          m_snap_connections.insert((*m_snap).on_user_response().connect(              [this](AdbdClient::PKResponse response, bool remember_choice){ -                g_debug("%s user responded! response %d, remember %d", G_STRLOC, int(response), int(remember_choice)); -                m_req.respond(response); -                if (remember_choice && (response == AdbdClient::PKResponse::ALLOW)) -                    write_public_key(m_req.public_key); -                m_restart_idle_tag = g_idle_add([](gpointer gself){ -                    auto self = static_cast<Impl*>(gself); -                    self->m_restart_idle_tag = 0; -                    self->restart(); -                    return G_SOURCE_REMOVE; -                }, this); + +                if (remember_choice && (response == AdbdClient::PKResponse::ALLOW)) { +                    write_public_key(m_req->public_key); +                } + +                m_response = response; + +                // defer finishing the request into an idle func because +                // ScopedConnections can't be destroyed inside their callbacks +                if (m_request_complete_idle_tag == 0) { +                    m_request_complete_idle_tag = g_idle_add([](gpointer gself){ +                        auto self = static_cast<Impl*>(gself); +                        self->m_request_complete_idle_tag = 0; +                        self->m_req.reset(); +                        return G_SOURCE_REMOVE; +                    }, this); +                }              }          ));      } @@ -152,12 +169,13 @@ private:      const std::shared_ptr<UsbMonitor> m_usb_monitor;      const std::shared_ptr<Greeter> m_greeter; -    unsigned int m_restart_idle_tag {}; +    unsigned int m_request_complete_idle_tag {};      std::shared_ptr<GAdbdClient> m_adbd_client; -    AdbdClient::PKRequest m_req;      std::shared_ptr<UsbSnap> m_snap;      std::set<core::ScopedConnection> m_snap_connections; +    AdbdClient::PKResponse m_response {AdbdClient::PKResponse::DENY}; +    std::shared_ptr<AdbdClient::PKRequest> m_req;  };  /*** @@ -177,4 +195,3 @@ UsbManager::UsbManager(  UsbManager::~UsbManager()  {  } - diff --git a/src/usb-snap.cpp b/src/usb-snap.cpp index ba964fb..53db6c4 100644 --- a/src/usb-snap.cpp +++ b/src/usb-snap.cpp @@ -208,6 +208,7 @@ private:          const bool remember_this_choice = response == AdbdClient::PKResponse::ALLOW;          m_on_user_response(response, remember_this_choice); +        m_notification_id = 0;      }      void on_notification_closed(uint32_t close_reason) | 
