2014-12-10 21:00:06

by Arman Uguray

[permalink] [raw]
Subject: D-Bus API for GATT Connect/Disconnect

Hi all,

For GATT, applications using bluetoothd currently need to use
Device1.Connect and Device1.Disconnect when they want to initiate a
connection to a peripheral, though these functions are really
primarily meant for UI usage. BlueZ already has a D-Bus API for BR/EDR
profiles such as ConnectProfile/DisconnectProfile and the
ProfileManager API which is more geared towards applications and I
think we'll need something for GATT as well. The basic features that
I'm thinking of are:

1. Sessions per D-Bus connection that provide a reference count for
the ACL connection.
2. Correctly handling the reference count if the connection was
initiated via Device1.Connect or via auto-connect.
3. This would be GATT only at first but it could perhaps expand to
connection-oriented channels eventually?

I don't really have an RFC API proposal at this point but I wanted to
get this discussion going. What would make most sense here?

Thanks,
Arman


2014-12-11 15:35:19

by Arman Uguray

[permalink] [raw]
Subject: Re: D-Bus API for GATT Connect/Disconnect

Hi Johan,

> On Thu, Dec 11, 2014 at 2:01 AM, Johan Hedberg <[email protected]> wrote:
> Hi Arman,
>
> On Wed, Dec 10, 2014, Arman Uguray wrote:
>> For GATT, applications using bluetoothd currently need to use
>> Device1.Connect and Device1.Disconnect when they want to initiate a
>> connection to a peripheral, though these functions are really
>> primarily meant for UI usage. BlueZ already has a D-Bus API for BR/EDR
>> profiles such as ConnectProfile/DisconnectProfile and the
>> ProfileManager API which is more geared towards applications and I
>> think we'll need something for GATT as well. The basic features that
>> I'm thinking of are:
>>
>> 1. Sessions per D-Bus connection that provide a reference count for
>> the ACL connection.
>> 2. Correctly handling the reference count if the connection was
>> initiated via Device1.Connect or via auto-connect.
>> 3. This would be GATT only at first but it could perhaps expand to
>> connection-oriented channels eventually?
>>
>> I don't really have an RFC API proposal at this point but I wanted to
>> get this discussion going. What would make most sense here?
>
> I have nothing to directly contradict what Marcel already replied, but
> I'm curious why you've omitted the kernel-managed passive scanning based
> connection establishment from the description of the issue. I'd expect
> that to be the principal way of connecting to peripheral devices, I'd
> also expect this to work in the same way for bluetoothd-external
> applications as it does for bluetoothd plugins: the application declares
> its support for a UUID and bluetoothd then adds devices supporting the
> UUID to the kernel-side connect list.
>

I didn't specifically mention the passive scanning as I generally
pooled it under "auto-connect". But yes, that definitely counts. In
fact, most of the problems that I run into with connection behavior
stem from bluetoothd not properly managing which devices should remain
in the kernel-side connect list, such as calling
device_set_auto_connect with TRUE in add_attio_callbacks and never
setting it to FALSE on remove_attio_callbacks, or having this logic
work for even the most mundane profiles/plugins such as profiles/gatt
or for profiles that may not be immediately in use to warrant
auto-connections (such as profiles/heartrate).

So this API suggestion would definitely address that case as well, I
just used auto-connect as the term for it :) But as you say, passive
background-scanning based connections will especially apply to all
outgoing connections as we move forward with the previous fixes to
L2CAP connect that we discussed earlier (which I didn't get around do
write any patches for yet).

I'm hoping to revise how auto-connect should work for internal
plugins, by perhaps adding a flag to btd_device_add_attio_callbacks
(and btd_device_add_gatt_callbacks that I proposed in an earlier patch
set) that indicates whether this should enable auto-connect and keep a
reference count in btd_device to determine when it should be disabled
(when a service gets removed via "Service Changed" for instance).

> Johan

Arman

2014-12-11 10:01:58

by Johan Hedberg

[permalink] [raw]
Subject: Re: D-Bus API for GATT Connect/Disconnect

Hi Arman,

On Wed, Dec 10, 2014, Arman Uguray wrote:
> For GATT, applications using bluetoothd currently need to use
> Device1.Connect and Device1.Disconnect when they want to initiate a
> connection to a peripheral, though these functions are really
> primarily meant for UI usage. BlueZ already has a D-Bus API for BR/EDR
> profiles such as ConnectProfile/DisconnectProfile and the
> ProfileManager API which is more geared towards applications and I
> think we'll need something for GATT as well. The basic features that
> I'm thinking of are:
>
> 1. Sessions per D-Bus connection that provide a reference count for
> the ACL connection.
> 2. Correctly handling the reference count if the connection was
> initiated via Device1.Connect or via auto-connect.
> 3. This would be GATT only at first but it could perhaps expand to
> connection-oriented channels eventually?
>
> I don't really have an RFC API proposal at this point but I wanted to
> get this discussion going. What would make most sense here?

I have nothing to directly contradict what Marcel already replied, but
I'm curious why you've omitted the kernel-managed passive scanning based
connection establishment from the description of the issue. I'd expect
that to be the principal way of connecting to peripheral devices, I'd
also expect this to work in the same way for bluetoothd-external
applications as it does for bluetoothd plugins: the application declares
its support for a UUID and bluetoothd then adds devices supporting the
UUID to the kernel-side connect list.

Johan

2014-12-11 00:40:17

by Arman Uguray

[permalink] [raw]
Subject: Re: D-Bus API for GATT Connect/Disconnect

Hi Marcel,

> On Wed, Dec 10, 2014 at 1:38 PM, Arman Uguray <[email protected]> wrot=
e:
> Hi Marcel,
>
>> On Wed, Dec 10, 2014 at 1:11 PM, Marcel Holtmann <[email protected]> w=
rote:
>> Hi Arman,
>>
>>> For GATT, applications using bluetoothd currently need to use
>>> Device1.Connect and Device1.Disconnect when they want to initiate a
>>> connection to a peripheral, though these functions are really
>>> primarily meant for UI usage. BlueZ already has a D-Bus API for BR/EDR
>>> profiles such as ConnectProfile/DisconnectProfile and the
>>> ProfileManager API which is more geared towards applications and I
>>> think we'll need something for GATT as well. The basic features that
>>> I'm thinking of are:
>>>
>>> 1. Sessions per D-Bus connection that provide a reference count for
>>> the ACL connection.
>>> 2. Correctly handling the reference count if the connection was
>>> initiated via Device1.Connect or via auto-connect.
>>> 3. This would be GATT only at first but it could perhaps expand to
>>> connection-oriented channels eventually?
>>>
>>> I don't really have an RFC API proposal at this point but I wanted to
>>> get this discussion going. What would make most sense here?
>>
>> the basic concept behind ProfileManager API that we used for BR/EDR work=
ed out pretty nicely. So maybe extend the general idea with the agent and c=
allbacks to GattManager.
>>
>> When looking at the difference then we are talking about accessing remot=
e GATT service via a local GATT profile. So what we want is implement that =
profile handling in an application.
>>
>
> Right, though there are some edge cases to consider. I think that if
> I'm implementing the server-role of a GATT profile (some I'm
> registering GATT services via D-Bus), I probably don't care much about
> the status of the connection, since I'll likely be just sitting and
> listening. So the connection mostly makes sense for central-role
> applications, except if I'm implementing the peripheral end of a CoC.
>
>> If we want to avoid overloading we could use GattProfileManager and Gatt=
Profile as terms to implement that. However the general idea that you get t=
he connection status via the callback (in this case it would be an object p=
ath and not a fd of course) seem still valid. Especially with LE we have to=
handle the auto-connect cases gracefully.
>>
>
> I think this makes sense. What I'm thinking is that if you're in the
> server role, you expose a GattProfile that has all the GattService1
> objects as children of the tree and register with GattProfileManager.
> If you're in the central role, you only register yourself as a profile
> if you want to explicitly initiate a connection. If you don't care
> about the connection (e.g. you're just showing the battery level from
> a secondary Battery Service on already connected peripherals) then you
> can just work with the GattService1 objects already exported under the
> device. Otherwise you register yourself as a GattProfile and get
> updates on the connection.
>
>> And if we have a connection oriented channel assigned with a GATT profil=
e, then that could be just reported via an extra callback. In that case it =
would be exactly like we do within ProfileManager.
>
> Yep, that makes sense.
>
>>
>> Regards
>>
>> Marcel
>>
>
> Cheers,
> Arman

And just following up on my previous response, we would then need
Device1.ConnectGatt and Device1.DisconnectGatt methods that parallel
ConnectProfile/DisconnectProfile? But then ConnectGatt wouldn't accept
a UUID but instead it would invoke the GattProfile callbacks based on
discovered services?

In that case, would the regular Device1.Connect also cause registered
GattProfile's callbacks to be invoked? (This is all while accessing
the remote GATT services).

Thanks,
Arman

2014-12-10 21:38:18

by Arman Uguray

[permalink] [raw]
Subject: Re: D-Bus API for GATT Connect/Disconnect

Hi Marcel,

> On Wed, Dec 10, 2014 at 1:11 PM, Marcel Holtmann <[email protected]> wr=
ote:
> Hi Arman,
>
>> For GATT, applications using bluetoothd currently need to use
>> Device1.Connect and Device1.Disconnect when they want to initiate a
>> connection to a peripheral, though these functions are really
>> primarily meant for UI usage. BlueZ already has a D-Bus API for BR/EDR
>> profiles such as ConnectProfile/DisconnectProfile and the
>> ProfileManager API which is more geared towards applications and I
>> think we'll need something for GATT as well. The basic features that
>> I'm thinking of are:
>>
>> 1. Sessions per D-Bus connection that provide a reference count for
>> the ACL connection.
>> 2. Correctly handling the reference count if the connection was
>> initiated via Device1.Connect or via auto-connect.
>> 3. This would be GATT only at first but it could perhaps expand to
>> connection-oriented channels eventually?
>>
>> I don't really have an RFC API proposal at this point but I wanted to
>> get this discussion going. What would make most sense here?
>
> the basic concept behind ProfileManager API that we used for BR/EDR worke=
d out pretty nicely. So maybe extend the general idea with the agent and ca=
llbacks to GattManager.
>
> When looking at the difference then we are talking about accessing remote=
GATT service via a local GATT profile. So what we want is implement that p=
rofile handling in an application.
>

Right, though there are some edge cases to consider. I think that if
I'm implementing the server-role of a GATT profile (some I'm
registering GATT services via D-Bus), I probably don't care much about
the status of the connection, since I'll likely be just sitting and
listening. So the connection mostly makes sense for central-role
applications, except if I'm implementing the peripheral end of a CoC.

> If we want to avoid overloading we could use GattProfileManager and GattP=
rofile as terms to implement that. However the general idea that you get th=
e connection status via the callback (in this case it would be an object pa=
th and not a fd of course) seem still valid. Especially with LE we have to =
handle the auto-connect cases gracefully.
>

I think this makes sense. What I'm thinking is that if you're in the
server role, you expose a GattProfile that has all the GattService1
objects as children of the tree and register with GattProfileManager.
If you're in the central role, you only register yourself as a profile
if you want to explicitly initiate a connection. If you don't care
about the connection (e.g. you're just showing the battery level from
a secondary Battery Service on already connected peripherals) then you
can just work with the GattService1 objects already exported under the
device. Otherwise you register yourself as a GattProfile and get
updates on the connection.

> And if we have a connection oriented channel assigned with a GATT profile=
, then that could be just reported via an extra callback. In that case it w=
ould be exactly like we do within ProfileManager.

Yep, that makes sense.

>
> Regards
>
> Marcel
>

Cheers,
Arman

2014-12-10 21:11:53

by Marcel Holtmann

[permalink] [raw]
Subject: Re: D-Bus API for GATT Connect/Disconnect

Hi Arman,

> For GATT, applications using bluetoothd currently need to use
> Device1.Connect and Device1.Disconnect when they want to initiate a
> connection to a peripheral, though these functions are really
> primarily meant for UI usage. BlueZ already has a D-Bus API for BR/EDR
> profiles such as ConnectProfile/DisconnectProfile and the
> ProfileManager API which is more geared towards applications and I
> think we'll need something for GATT as well. The basic features that
> I'm thinking of are:
>
> 1. Sessions per D-Bus connection that provide a reference count for
> the ACL connection.
> 2. Correctly handling the reference count if the connection was
> initiated via Device1.Connect or via auto-connect.
> 3. This would be GATT only at first but it could perhaps expand to
> connection-oriented channels eventually?
>
> I don't really have an RFC API proposal at this point but I wanted to
> get this discussion going. What would make most sense here?

the basic concept behind ProfileManager API that we used for BR/EDR worked out pretty nicely. So maybe extend the general idea with the agent and callbacks to GattManager.

When looking at the difference then we are talking about accessing remote GATT service via a local GATT profile. So what we want is implement that profile handling in an application.

If we want to avoid overloading we could use GattProfileManager and GattProfile as terms to implement that. However the general idea that you get the connection status via the callback (in this case it would be an object path and not a fd of course) seem still valid. Especially with LE we have to handle the auto-connect cases gracefully.

And if we have a connection oriented channel assigned with a GATT profile, then that could be just reported via an extra callback. In that case it would be exactly like we do within ProfileManager.

Regards

Marcel