Generic D-Bus introspection support in BlueZ
Update: Some sort of solution is already implemented in common/dbus-helper.[ch]. It is being used already by all hcid interfaces.
A solution is needed to properly generate introspection data in a generic manner. Some parts of this data already exists in a structured form:
- API documentation (e.g. hcid/dbus-api.txt)
- The method call handler lists for different interfaces which contain method names and function pointers to handle those methods.
Currently the method handlers receive a context specific user_data pointer, e.g. Adapter paths receive a struct adapter * while headset paths (in the headset service) receive a struct headset *. Obviously it is not possible to generate introspecion data from these structs in a generic manner.
To create the introspection data the following would be needed:
- List of interfaces
- Method calls
- Name
- Parameter types & names
- Return parameter types & names
- Signals
- Name
- Parameter types & names
- Method calls
- List of properties (not really applicable to us currently since we don't use them)
In addition to this information it would be useful to include function pointers as we currently have to enable automatic dispatching of the right method handler. Having the method call parameter type list available too will also allow automatic checking of message signatures (to return errors to invalid received messages and to detect bugs in code that is returning incorrect method returns).
One solution that I currently have in mind is something like this:
struct parameter { char type; char name[]; }; struct message { char name[]; /* If we decide we don't want to have names for our parameters (optional * according to the D-Bus spec) we could also forget about struct parameter * and have simply char[] for the following two members */ GSList *call_params; /* of type struct parameter */ GSList *return_params; /* of type struct paramter (NULL in the case of signals) */ method_handler_t handler_function; /* NULL in the case of signals */ }; struct interface { char name[]; GSList *methods; /* of type struct message */ GSList *signals; /* of type struct message */ void *user_data; }; struct introspect_data { GSList *interfaces /* of type struct interface */ } void path_add_interface(const char *object_path, const char *name, GSList *methods, GSList *signals, void *user_data);
With this kind of structure all object paths would have to be registered with a struct introspect_data pointer for the object path data and a single function could be made responsible for dispatching the right method handler.
I've put the user_data pointer as part of the interface struct instead of the introspect data struct because we might want to have differenct pointers passed to the method handlers depending on what interface is used. For example in the following audio service example if you have a common struct for describing a remote audio device:
struct audio_device {
bdaddr_t address;
struct headset *hs;
struct sink *sink;
struct source *source;
struct audio_gw *ag;
};
You'd want the hs pointer to be passed if the org.bluez.audio.Headset interface is used and the sink pointer to be passed if the org.bluez.audio.Sink interface is used. The struct audio_device pointer itself would be passed if the generic org.bluez.audio.Device interface is used (which e.g. has the method GetAddress?).
Issues
- Can we automatically generate documentation too out of all this?
- Should the data be used to validate that we send correct signals from each interface (i.e. have a generic signal sending function which takes a struct interface *, etc)
- What about possible error returns (I couldn't find any mention of them in the D-Bus introspection documentation).
