mirror of
				https://github.com/multirom-nexus6p/multirom_adbd.git
				synced 2025-11-04 05:35:34 +08:00 
			
		
		
		
	Taken from system/core/adb on the omnirom/android-6.0 branch (2b143b247a69deba1577dd1b2ca92138be2b48dc)
		
			
				
	
	
		
			272 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
 | 
						|
--- a replacement for aproto -------------------------------------------
 | 
						|
 | 
						|
When it comes down to it, aproto's primary purpose is to forward
 | 
						|
various streams between the host computer and client device (in either
 | 
						|
direction).
 | 
						|
 | 
						|
This replacement further simplifies the concept, reducing the protocol
 | 
						|
to an extremely straightforward model optimized to accomplish the
 | 
						|
forwarding of these streams and removing additional state or
 | 
						|
complexity.
 | 
						|
 | 
						|
The host side becomes a simple comms bridge with no "UI", which will 
 | 
						|
be used by either commandline or interactive tools to communicate with 
 | 
						|
a device or emulator that is connected to the bridge.
 | 
						|
 | 
						|
The protocol is designed to be straightforward and well-defined enough 
 | 
						|
that if it needs to be reimplemented in another environment (Java 
 | 
						|
perhaps), there should not problems ensuring perfect interoperability.
 | 
						|
 | 
						|
The protocol discards the layering aproto has and should allow the 
 | 
						|
implementation to be much more robust.
 | 
						|
 | 
						|
 | 
						|
--- protocol overview and basics ---------------------------------------
 | 
						|
 | 
						|
The transport layer deals in "messages", which consist of a 24 byte
 | 
						|
header followed (optionally) by a payload.  The header consists of 6
 | 
						|
32 bit words which are sent across the wire in little endian format.
 | 
						|
 | 
						|
struct message {
 | 
						|
    unsigned command;       /* command identifier constant      */
 | 
						|
    unsigned arg0;          /* first argument                   */
 | 
						|
    unsigned arg1;          /* second argument                  */
 | 
						|
    unsigned data_length;   /* length of payload (0 is allowed) */
 | 
						|
    unsigned data_crc32;    /* crc32 of data payload            */
 | 
						|
    unsigned magic;         /* command ^ 0xffffffff             */
 | 
						|
};
 | 
						|
 | 
						|
Receipt of an invalid message header, corrupt message payload, or an
 | 
						|
unrecognized command MUST result in the closing of the remote
 | 
						|
connection.  The protocol depends on shared state and any break in the
 | 
						|
message stream will result in state getting out of sync.
 | 
						|
 | 
						|
The following sections describe the six defined message types in
 | 
						|
detail.  Their format is COMMAND(arg0, arg1, payload) where the payload
 | 
						|
is represented by a quoted string or an empty string if none should be
 | 
						|
sent.
 | 
						|
 | 
						|
The identifiers "local-id" and "remote-id" are always relative to the
 | 
						|
*sender* of the message, so for a receiver, the meanings are effectively
 | 
						|
reversed.
 | 
						|
 | 
						|
 | 
						|
 | 
						|
--- CONNECT(version, maxdata, "system-identity-string") ----------------
 | 
						|
 | 
						|
The CONNECT message establishes the presence of a remote system.
 | 
						|
The version is used to ensure protocol compatibility and maxdata
 | 
						|
declares the maximum message body size that the remote system
 | 
						|
is willing to accept.
 | 
						|
 | 
						|
Currently, version=0x01000000 and maxdata=4096
 | 
						|
 | 
						|
Both sides send a CONNECT message when the connection between them is
 | 
						|
established.  Until a CONNECT message is received no other messages may
 | 
						|
be sent.  Any messages received before a CONNECT message MUST be ignored.
 | 
						|
 | 
						|
If a CONNECT message is received with an unknown version or insufficiently
 | 
						|
large maxdata value, the connection with the other side must be closed.
 | 
						|
 | 
						|
The system identity string should be "<systemtype>:<serialno>:<banner>"
 | 
						|
where systemtype is "bootloader", "device", or "host", serialno is some
 | 
						|
kind of unique ID (or empty), and banner is a human-readable version
 | 
						|
or identifier string.  The banner is used to transmit useful properties.
 | 
						|
 | 
						|
 | 
						|
--- AUTH(type, 0, "data") ----------------------------------------------
 | 
						|
 | 
						|
The AUTH message informs the recipient that authentication is required to
 | 
						|
connect to the sender. If type is TOKEN(1), data is a random token that
 | 
						|
the recipient can sign with a private key. The recipient replies with an
 | 
						|
AUTH packet where type is SIGNATURE(2) and data is the signature. If the
 | 
						|
signature verification succeeds, the sender replies with a CONNECT packet.
 | 
						|
 | 
						|
If the signature verification fails, the sender replies with a new AUTH
 | 
						|
packet and a new random token, so that the recipient can retry signing
 | 
						|
with a different private key.
 | 
						|
 | 
						|
Once the recipient has tried all its private keys, it can reply with an
 | 
						|
AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If
 | 
						|
possible, an on-screen confirmation may be displayed for the user to
 | 
						|
confirm they want to install the public key on the device.
 | 
						|
 | 
						|
 | 
						|
--- OPEN(local-id, 0, "destination") -----------------------------------
 | 
						|
 | 
						|
The OPEN message informs the recipient that the sender has a stream
 | 
						|
identified by local-id that it wishes to connect to the named
 | 
						|
destination in the message payload.  The local-id may not be zero.
 | 
						|
 | 
						|
The OPEN message MUST result in either a READY message indicating that
 | 
						|
the connection has been established (and identifying the other end) or
 | 
						|
a CLOSE message, indicating failure.  An OPEN message also implies
 | 
						|
a READY message sent at the same time.
 | 
						|
 | 
						|
Common destination naming conventions include:
 | 
						|
 | 
						|
* "tcp:<host>:<port>" - host may be omitted to indicate localhost
 | 
						|
* "udp:<host>:<port>" - host may be omitted to indicate localhost
 | 
						|
* "local-dgram:<identifier>"
 | 
						|
* "local-stream:<identifier>"
 | 
						|
* "shell" - local shell service
 | 
						|
* "upload" - service for pushing files across (like aproto's /sync)
 | 
						|
* "fs-bridge" - FUSE protocol filesystem bridge
 | 
						|
 | 
						|
 | 
						|
--- READY(local-id, remote-id, "") -------------------------------------
 | 
						|
 | 
						|
The READY message informs the recipient that the sender's stream
 | 
						|
identified by local-id is ready for write messages and that it is
 | 
						|
connected to the recipient's stream identified by remote-id.
 | 
						|
 | 
						|
Neither the local-id nor the remote-id may be zero. 
 | 
						|
 | 
						|
A READY message containing a remote-id which does not map to an open
 | 
						|
stream on the recipient's side is ignored.  The stream may have been
 | 
						|
closed while this message was in-flight.
 | 
						|
 | 
						|
The local-id is ignored on all but the first READY message (where it
 | 
						|
is used to establish the connection).  Nonetheless, the local-id MUST
 | 
						|
not change on later READY messages sent to the same stream.
 | 
						|
 | 
						|
 | 
						|
 | 
						|
--- WRITE(0, remote-id, "data") ----------------------------------------
 | 
						|
 | 
						|
The WRITE message sends data to the recipient's stream identified by
 | 
						|
remote-id.  The payload MUST be <= maxdata in length.
 | 
						|
 | 
						|
A WRITE message containing a remote-id which does not map to an open
 | 
						|
stream on the recipient's side is ignored.  The stream may have been
 | 
						|
closed while this message was in-flight.
 | 
						|
 | 
						|
A WRITE message may not be sent until a READY message is received.
 | 
						|
Once a WRITE message is sent, an additional WRITE message may not be
 | 
						|
sent until another READY message has been received.  Recipients of
 | 
						|
a WRITE message that is in violation of this requirement will CLOSE
 | 
						|
the connection.
 | 
						|
 | 
						|
 | 
						|
--- CLOSE(local-id, remote-id, "") -------------------------------------
 | 
						|
 | 
						|
The CLOSE message informs recipient that the connection between the
 | 
						|
sender's stream (local-id) and the recipient's stream (remote-id) is
 | 
						|
broken.  The remote-id MUST not be zero, but the local-id MAY be zero
 | 
						|
if this CLOSE indicates a failed OPEN.
 | 
						|
 | 
						|
A CLOSE message containing a remote-id which does not map to an open
 | 
						|
stream on the recipient's side is ignored.  The stream may have
 | 
						|
already been closed by the recipient while this message was in-flight.
 | 
						|
 | 
						|
The recipient should not respond to a CLOSE message in any way.  The
 | 
						|
recipient should cancel pending WRITEs or CLOSEs, but this is not a
 | 
						|
requirement, since they will be ignored.
 | 
						|
 | 
						|
 | 
						|
--- SYNC(online, sequence, "") -----------------------------------------
 | 
						|
 | 
						|
The SYNC message is used by the io pump to make sure that stale
 | 
						|
outbound messages are discarded when the connection to the remote side
 | 
						|
is broken.  It is only used internally to the bridge and never valid
 | 
						|
to send across the wire.  
 | 
						|
 | 
						|
* when the connection to the remote side goes offline, the io pump 
 | 
						|
  sends a SYNC(0, 0) and starts discarding all messages
 | 
						|
* when the connection to the remote side is established, the io pump
 | 
						|
  sends a SYNC(1, token) and continues to discard messages
 | 
						|
* when the io pump receives a matching SYNC(1, token), it once again
 | 
						|
  starts accepting messages to forward to the remote side
 | 
						|
 | 
						|
 | 
						|
--- message command constants ------------------------------------------
 | 
						|
 | 
						|
#define A_SYNC 0x434e5953
 | 
						|
#define A_CNXN 0x4e584e43
 | 
						|
#define A_AUTH 0x48545541
 | 
						|
#define A_OPEN 0x4e45504f
 | 
						|
#define A_OKAY 0x59414b4f
 | 
						|
#define A_CLSE 0x45534c43
 | 
						|
#define A_WRTE 0x45545257
 | 
						|
 | 
						|
 | 
						|
 | 
						|
--- implementation details ---------------------------------------------
 | 
						|
 | 
						|
The core of the bridge program will use three threads.  One thread
 | 
						|
will be a select/epoll loop to handle io between various inbound and
 | 
						|
outbound connections and the connection to the remote side.
 | 
						|
 | 
						|
The remote side connection will be implemented as two threads (one for
 | 
						|
reading, one for writing) and a datagram socketpair to provide the
 | 
						|
channel between the main select/epoll thread and the remote connection
 | 
						|
threadpair.  The reason for this is that for usb connections, the
 | 
						|
kernel interface on linux and osx does not allow you to do meaningful
 | 
						|
nonblocking IO.
 | 
						|
 | 
						|
The endian swapping for the message headers will happen (as needed) in
 | 
						|
the remote connection threadpair and that the rest of the program will
 | 
						|
always treat message header values as native-endian.
 | 
						|
 | 
						|
The bridge program will be able to have a number of mini-servers
 | 
						|
compiled in.  They will be published under known names (examples
 | 
						|
"shell", "fs-bridge", etc) and upon receiving an OPEN() to such a
 | 
						|
service, the bridge program will create a stream socketpair and spawn
 | 
						|
a thread or subprocess to handle the io.
 | 
						|
 | 
						|
 | 
						|
--- simplified / embedded implementation -------------------------------
 | 
						|
 | 
						|
For limited environments, like the bootloader, it is allowable to
 | 
						|
support a smaller, fixed number of channels using pre-assigned channel
 | 
						|
ID numbers such that only one stream may be connected to a bootloader
 | 
						|
endpoint at any given time.  The protocol remains unchanged, but the
 | 
						|
"embedded" version of it is less dynamic.
 | 
						|
 | 
						|
The bootloader will support two streams.  A "bootloader:debug" stream,
 | 
						|
which may be opened to get debug messages from the bootloader and a 
 | 
						|
"bootloader:control", stream which will support the set of basic 
 | 
						|
bootloader commands.
 | 
						|
 | 
						|
Example command stream dialogues:  
 | 
						|
  "flash_kernel,2515049,........\n" "okay\n" 
 | 
						|
  "flash_ramdisk,5038,........\n" "fail,flash write error\n" 
 | 
						|
  "bogus_command......" <CLOSE>
 | 
						|
 | 
						|
 | 
						|
--- future expansion ---------------------------------------------------
 | 
						|
 | 
						|
I plan on providing either a message or a special control stream so that
 | 
						|
the client device could ask the host computer to setup inbound socket
 | 
						|
translations on the fly on behalf of the client device.
 | 
						|
 | 
						|
 | 
						|
The initial design does handshaking to provide flow control, with a
 | 
						|
message flow that looks like:
 | 
						|
 | 
						|
  >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE
 | 
						|
 | 
						|
The far side may choose to issue the READY message as soon as it receives
 | 
						|
a WRITE or it may defer the READY until the write to the local stream
 | 
						|
succeeds.  A future version may want to do some level of windowing where
 | 
						|
multiple WRITEs may be sent without requiring individual READY acks.
 | 
						|
 | 
						|
------------------------------------------------------------------------
 | 
						|
 | 
						|
--- smartsockets -------------------------------------------------------
 | 
						|
 | 
						|
Port 5037 is used for smart sockets which allow a client on the host
 | 
						|
side to request access to a service in the host adb daemon or in the
 | 
						|
remote (device) daemon.  The service is requested by ascii name,
 | 
						|
preceeded by a 4 digit hex length.  Upon successful connection an
 | 
						|
"OKAY" response is sent, otherwise a "FAIL" message is returned.  Once
 | 
						|
connected the client is talking to that (remote or local) service.
 | 
						|
 | 
						|
client: <hex4> <service-name>
 | 
						|
server: "OKAY"
 | 
						|
 | 
						|
client: <hex4> <service-name>
 | 
						|
server: "FAIL" <hex4> <reason>
 | 
						|
 |