[g-a-devel] AT-SPI caching and D-Bus usage



AT-SPI was originally designed around CORBA, specifically ORBit. Its use led to a large amount of inter-process communication. Method calls in ORBit were fairly quick, so this was not a huge problem, although that isn't to say that there were never performance issues. However, ORBit was deprecated for GNOME 3, and Codethink undertook an investigation of the feasibility of porting AT-SPi to D-Bus. Note that the D-Bus libraries were not really designed to be used in cases where a large amount of synchronous method calls are needed. Nevertheless, Codethink undertook an investigation of the feasibility of porting AT-SPI to D-Bus. Their main conclusions were that, although D-Bus method calls are slower than the equivalent CORBA calls, a lot of AT-SPI traffic generated by Orca comes from a handful of method calls--calls to fetch an object's name, parent, children, or state set, for instance. If these data could be cached, then a significant amount of traffic would become unnecessary.

This led to the current design, where some data are cached, and the default assumption is that applications will send notifications when an object's name, description, state, or children are changed. Calls requesting other data, such as attributes or screen coordinates, result in method calls. This design has a few problems:

- It relies on applications sending notifications any time an object's states or children change. If an application fails to do this, then Orca will see stale data, unless it has instructed AT-SPI not to cache certain kinds of data for the given application. It is sometimes difficult for a toolkit implementor to send notifications for every such change, and the result is that AT-SPI2 is made fragile in a way that was not previouisly the case.

- Not all data that an AT may need is cached. For instance, when Orca sees an event, it wants to look at the attributes for the accessible that triggered the event, in order to determine which toolkit sent it, in order to decide which script to use. Attributes are not cached, so this means that Orca always makes a round-trip D-Bus call to retrieve the attributes of the object that just sent the event. Similarly, when building a flat review context, it wants to know the extents of various accessibles on the screen, and extents are not cached, so a significant number of round-trip calls are needed in order to fetch extents for many different objects. One solution would be to add more things to the data that AT-SPI caches (ie, http://bugzilla.gnome.org/show_bug.cgi?id=649771), but this has the downside of making AT-SPI even more reliant on applications to send events when various things change, introducing the possibility for new bugs.

- Sometimes, it is necessary to avoid synchronous D-Bus calls altogether (see https://bugzilla.gnome.org/show_bug.cgi?id=708387).

I think that a good solution would be two-fold:

- Allow an event listener to request particular data be sent along with an event. For instance, Orca could request that an object's attributes be sent. The attributes would be cached probably for the duration of the event callback. While we're modifying the API for event listeners, it would be good to take a look at https://bugzilla.gnome.org/show_bug.cgi?id=640440.

- Add a function to allow various data to be fetched in one go. It would take a callback to be called whtn the data is ready. For instance, perhaps orca would want to know the roles, states, and extents of all (non-transient) objects descending from a particular accessible. All of this data would be stored in a cache that would be valid for the duration of the callback(?). If, say, atspi_accessible_get_attributes is called from within the callback and the attributes have been pre-fetched, then return the attributes we have cached rather than make another D-Bus call. In the long term, this might be able to replace the current caching mechanism. Ie, something like:

typedef void (*AtspiQueryCallback) (void *user_data)

void atspi_query_accessible (AtspiAccessible *obj,
                             const gchar **properties,
                             AtspiQueryCallback *cb,
                             void *user_data,
                             gboolean allow_sync,
                             gboolean include_descendants,
                             GError **error);

If allow_sync is FALSE, then AT-SPI will throw an exception rather than make a synchronous call. This could be used when it is desirable to guarantee that no synchronous calls are made (probably anything running inside gnome-shell would want this, since otherwise it can deadlock if it queries an application which is in turn making a non-AT-SPI-related D-Bus call to gnome-shell).

I'm not sure if having an "include descendants" parameter is best, or if something more fine-grained would be better (perhaps an enum allowing just the accessible, the accesible and its children, or the accessible and all non-transient descendants?) Also, maybe we want a parameter to specify the starting point--it might be useful to be able to specify an ancestor with a given role as a starting point? This gets into whether it might be useful to take a string parameter specifying a predicate. It may be worth investigating whether xpath would be helpful / whether there are libraries that would be useful in terms of parsing it.

Comments welcome.

-Mike


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