1# Delayed ACK 2 3Historically, ADB transport protocol transfer speed was affected by two factors. 4 51. Each `A_WRTE` apacket was CRCed upon write and the CRC was checked upon read on the other end. 62. There could be only one `A_WRTE` apacket in-flight on an asocket. A local asocket 7would not schedule more data to be sent out until it had received an `A_OKAY` apacket response from 8its peer. 9 10The first issue was solved in [aosp/568123](https://android-review.googlesource.com/q/568123). 11In that CL, the protocol was updated to remove the requirement for CRC generation and verification. 12This does not affect the reliability of a transport since both USB and TCP have packet checksums of their own. 13 14The second issue is solved by "delayed ACK" ([aosp/1953877](https://android-review.googlesource.com/q/1953877)), 15an experimental feature controlled by the environment variable `ADB_DELAYED_ACK`. 16 17# How delayed ACK works 18 19The idea is to introduce the concept of a per-asocket "available send bytes" (ASB) integer. 20This integer represent how many bytes we are willing to send without having received any 21`A_OKAY` for them. 22 23While the ASB is positive, the asocket does not wait for an `A_OKAY` before sending 24more `A_WRTE` apackets. A remote asocket can be written to up until the ASB is exhausted. 25 26The ASB capability is first negotiated on `A_OPEN`/`A_OKAY` exchange. After 27that, the ASB is maintained via decrement upon `A_WRTE` and increment 28upon `A_OKAY`. 29 30This approach allows to "burst" `A_WRTE` packet but also "burst" `A_OKAY` packets 31to allow several `A_WRTE` packets to be in-flight on an asocket. This greatly 32increases data transfer throughput. 33 34# Implementation 35 36## Packet update 371. `A_OPEN` unused field (`arg1`) is repurposed to declare the wish to use delayed ACK features. 38If not supported, the receiving end of the `A_OPEN` will `A_CLSE` the connection. 392. `A_OKAY` now has a payload (a int32_t) which acknowledge how much payload was 40received in the last received `A_WRTE` apacket. 41 42## Trace 43 44Here are two traces showing the timing of three A_WRTE. 45 46### Before 47``` 48Host > A_OPEN > Device 49Host > A_WRTE > Device 50The LS removes itself from the fdevent EPOLLIN and nothing is sent. 51Host < A_OKAY < Device 52The LS requests fdevent EPOLLIN for its fd to start reading and send more A_WRTE. 53Host > A_WRTE > Device 54The LS removes itself from the fdevent EPOLLIN and nothing is sent. 55Host < A_OKAY < Device 56The LS requests fdevent EPOLLIN for its fd to start reading and send more A_WRTE. 57Host > A_WRTE > Device 58The LS removes itself from the fdevent EPOLLIN and nothing is sent. 59Host < A_OKAY < Device 60The LS requests fdevent EPOLLIN for its fd to start reading and send more A_WRTE. 61``` 62 63 64## After 65 66With ASB, see how `A_WRTE` and `A_OKAY` are burst instead of being paired. 67 68``` 69Host(ASB=0) > A_OPEN(arg1=1MiB) > Device 70Host(ASB=X) < A_OKAY(<ASB=X>) < Device 71Host<ASB=X-a) > A_WRTE(payload size=a) > Device 72Host<ASB=Y-a-b) > A_WRTE(payload size=b) > Device 73Host<ASB=Z-a-b-c) > A_WRTE(payload size=c) > Device 74ASB is < 0. The LS removes itself from the fdevent EPOLLIN and nothing is sent. 75... 76Host(ASB=X-b-c) < A_OKAY(<a>) < Device 77ASB is > 0. The LS requests fdevent EPOLLIN for its fd to start reading and send more A_WRTE. 78... 79Host(ASB=X-c) < A_OKAY(<b>) < Device 80Host(ASB=X) < A_OKAY(<c>) < Device 81``` 82 83 84