55use anyhow:: { Context , Result } ;
66use argh:: { ArgsInfo , FromArgs } ;
77use async_net:: { Ipv4Addr , TcpListener , TcpStream } ;
8- use fho:: { Connector , SimpleWriter } ;
8+ use fho:: Connector ;
99use fidl_fuchsia_developer_remotecontrol as rc;
1010use fidl_fuchsia_starnix_container as fstarcontainer;
1111use fuchsia_async as fasync;
@@ -24,6 +24,35 @@ use crate::common::*;
2424
2525const ADB_DEFAULT_PORT : u32 = 5555 ;
2626
27+ #[ derive( ArgsInfo , FromArgs , Debug , PartialEq ) ]
28+ #[ argh(
29+ subcommand,
30+ name = "adb" ,
31+ example = "ffx starnix adb proxy" ,
32+ description = "Bridge from host adb to adbd running inside starnix"
33+ ) ]
34+ pub struct StarnixAdbCommand {
35+ /// path to the adb client command
36+ #[ argh( option, default = "String::from(\" adb\" )" ) ]
37+ adb : String ,
38+ #[ argh( subcommand) ]
39+ subcommand : AdbSubcommand ,
40+ }
41+
42+ #[ derive( ArgsInfo , FromArgs , Debug , PartialEq ) ]
43+ #[ argh( subcommand) ]
44+ enum AdbSubcommand {
45+ Proxy ( AdbProxyArgs ) ,
46+ }
47+
48+ impl StarnixAdbCommand {
49+ pub async fn run ( & self , rcs_connector : & Connector < rc:: RemoteControlProxy > ) -> Result < ( ) > {
50+ match & self . subcommand {
51+ AdbSubcommand :: Proxy ( args) => args. run_proxy ( & self . adb , rcs_connector) . await ,
52+ }
53+ }
54+ }
55+
2756async fn serve_adb_connection ( mut stream : TcpStream , bridge_socket : fidl:: Socket ) -> Result < ( ) > {
2857 let mut bridge = fidl:: AsyncSocket :: from_socket ( bridge_socket) ;
2958 let ( breader, mut bwriter) = ( & mut bridge) . split ( ) ;
@@ -41,32 +70,6 @@ async fn serve_adb_connection(mut stream: TcpStream, bridge_socket: fidl::Socket
4170 copy_result. map ( |_| ( ) ) . map_err ( |e| e. into ( ) )
4271}
4372
44- #[ derive( ArgsInfo , FromArgs , Debug , PartialEq ) ]
45- #[ argh(
46- subcommand,
47- name = "adb" ,
48- example = "ffx starnix adb" ,
49- description = "Bridge from host adb to adbd running inside starnix"
50- ) ]
51- pub struct StarnixAdbCommand {
52- /// the moniker of the container running adbd
53- /// (defaults to looking for a container in the current session)
54- #[ argh( option, short = 'm' ) ]
55- pub moniker : Option < String > ,
56-
57- /// which port to serve the adb server on
58- #[ argh( option, short = 'p' , default = "find_open_port(5556)" ) ]
59- pub port : u16 ,
60-
61- /// path to the adb client command
62- #[ argh( option, default = "String::from(\" adb\" )" ) ]
63- pub adb : String ,
64-
65- /// disable automatically running "adb connect"
66- #[ argh( switch) ]
67- pub no_autoconnect : bool ,
68- }
69-
7073fn find_open_port ( start : u16 ) -> u16 {
7174 let mut addr = SocketAddrV4 :: new ( Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) , start) ;
7275
@@ -88,86 +91,109 @@ fn find_open_port(start: u16) -> u16 {
8891 }
8992}
9093
91- pub async fn starnix_adb (
92- command : & StarnixAdbCommand ,
93- rcs_connector : & Connector < rc:: RemoteControlProxy > ,
94- _writer : SimpleWriter ,
95- ) -> Result < ( ) > {
96- let reconnect = || async {
97- let rcs_proxy = connect_to_rcs ( rcs_connector) . await ?;
98- anyhow:: Ok ( (
99- connect_to_contoller ( & rcs_proxy, command. moniker . clone ( ) ) . await ?,
100- Arc :: new ( AtomicBool :: new ( false ) ) ,
101- ) )
102- } ;
103- let mut controller_proxy = reconnect ( ) . await ?;
104-
105- let mut signals = Signals :: new ( & [ SIGINT ] ) . unwrap ( ) ;
106- let handle = signals. handle ( ) ;
107- let signal_thread = std:: thread:: spawn ( move || {
108- if let Some ( signal) = signals. forever ( ) . next ( ) {
109- assert_eq ! ( signal, SIGINT ) ;
110- eprintln ! ( "Caught interrupt. Shutting down starnix adb bridge..." ) ;
111- std:: process:: exit ( 0 ) ;
112- }
113- } ) ;
114-
115- let listener = TcpListener :: bind ( ( Ipv4Addr :: LOCALHOST , command. port ) )
116- . await
117- . expect ( "cannot bind to adb address" ) ;
118- let listen_address = listener. local_addr ( ) . expect ( "cannot get adb server address" ) ;
119-
120- if !command. no_autoconnect {
121- // It's necessary to run adb connect on a separate thread so it doesn't block the async
122- // executor running the socket listener.
123- let adb_path = command. adb . clone ( ) ;
124- std:: thread:: spawn ( move || {
125- let mut adb_command = Command :: new ( & adb_path) ;
126- adb_command. arg ( "connect" ) . arg ( listen_address. to_string ( ) ) ;
127- match adb_command. status ( ) {
128- Ok ( _) => { }
129- Err ( io_err) if io_err. kind ( ) == ErrorKind :: NotFound => {
130- panic ! ( "Could not find adb binary named `{adb_path}`. If your adb is not in your $PATH, use the --adb flag to specify where to find it." ) ;
131- }
132- Err ( io_err) => {
133- panic ! ( "Failed to run `${adb_command:?}`: {io_err:?}" ) ;
134- }
94+ #[ derive( ArgsInfo , FromArgs , Debug , PartialEq ) ]
95+ #[ argh(
96+ subcommand,
97+ name = "proxy" ,
98+ description = "Bridge from host adb to adbd running inside starnix"
99+ ) ]
100+ struct AdbProxyArgs {
101+ /// the moniker of the container running adbd
102+ /// (defaults to looking for a container in the current session)
103+ #[ argh( option, short = 'm' ) ]
104+ pub moniker : Option < String > ,
105+
106+ /// which port to serve the adb server on
107+ #[ argh( option, short = 'p' , default = "find_open_port(5556)" ) ]
108+ pub port : u16 ,
109+
110+ /// disable automatically running "adb connect"
111+ #[ argh( switch) ]
112+ pub no_autoconnect : bool ,
113+ }
114+
115+ impl AdbProxyArgs {
116+ async fn run_proxy (
117+ & self ,
118+ adb : & str ,
119+ rcs_connector : & Connector < rc:: RemoteControlProxy > ,
120+ ) -> Result < ( ) > {
121+ let reconnect = || async {
122+ let rcs_proxy = connect_to_rcs ( rcs_connector) . await ?;
123+ anyhow:: Ok ( (
124+ connect_to_contoller ( & rcs_proxy, self . moniker . clone ( ) ) . await ?,
125+ Arc :: new ( AtomicBool :: new ( false ) ) ,
126+ ) )
127+ } ;
128+ let mut controller_proxy = reconnect ( ) . await ?;
129+
130+ let mut signals = Signals :: new ( & [ SIGINT ] ) . unwrap ( ) ;
131+ let handle = signals. handle ( ) ;
132+ let signal_thread = std:: thread:: spawn ( move || {
133+ if let Some ( signal) = signals. forever ( ) . next ( ) {
134+ assert_eq ! ( signal, SIGINT ) ;
135+ eprintln ! ( "Caught interrupt. Shutting down starnix adb bridge..." ) ;
136+ std:: process:: exit ( 0 ) ;
135137 }
136138 } ) ;
137- } else {
138- println ! ( "ADB bridge started. To connect: adb connect {listen_address}" ) ;
139- }
140139
141- while let Some ( stream) = listener. incoming ( ) . next ( ) . await {
142- if controller_proxy. 1 . load ( Ordering :: SeqCst ) {
143- controller_proxy = reconnect ( ) . await ?;
140+ let listener = TcpListener :: bind ( ( Ipv4Addr :: LOCALHOST , self . port ) )
141+ . await
142+ . expect ( "cannot bind to adb address" ) ;
143+ let listen_address = listener. local_addr ( ) . expect ( "cannot get adb server address" ) ;
144+
145+ if !self . no_autoconnect {
146+ // It's necessary to run adb connect on a separate thread so it doesn't block the async
147+ // executor running the socket listener.
148+ let adb_path = adb. to_string ( ) ;
149+ std:: thread:: spawn ( move || {
150+ let mut adb_command = Command :: new ( & adb_path) ;
151+ adb_command. arg ( "connect" ) . arg ( listen_address. to_string ( ) ) ;
152+ match adb_command. status ( ) {
153+ Ok ( _) => { }
154+ Err ( io_err) if io_err. kind ( ) == ErrorKind :: NotFound => {
155+ panic ! ( "Could not find adb binary named `{adb_path}`. If your adb is not in your $PATH, use the --adb flag to specify where to find it." ) ;
156+ }
157+ Err ( io_err) => {
158+ panic ! ( "Failed to run `${adb_command:?}`: {io_err:?}" ) ;
159+ }
160+ }
161+ } ) ;
162+ } else {
163+ println ! ( "ADB bridge started. To connect: adb connect {listen_address}" ) ;
144164 }
145165
146- let stream = stream?;
147- let ( sbridge, cbridge) = fidl:: Socket :: create_stream ( ) ;
166+ while let Some ( stream) = listener. incoming ( ) . next ( ) . await {
167+ if controller_proxy. 1 . load ( Ordering :: SeqCst ) {
168+ controller_proxy = reconnect ( ) . await ?;
169+ }
148170
149- controller_proxy
150- . 0
151- . vsock_connect ( fstarcontainer:: ControllerVsockConnectRequest {
152- port : Some ( ADB_DEFAULT_PORT ) ,
153- bridge_socket : Some ( sbridge) ,
154- ..Default :: default ( )
171+ let stream = stream?;
172+ let ( sbridge, cbridge) = fidl:: Socket :: create_stream ( ) ;
173+
174+ controller_proxy
175+ . 0
176+ . vsock_connect ( fstarcontainer:: ControllerVsockConnectRequest {
177+ port : Some ( ADB_DEFAULT_PORT ) ,
178+ bridge_socket : Some ( sbridge) ,
179+ ..Default :: default ( )
180+ } )
181+ . context ( "connecting to adbd" ) ?;
182+
183+ let reconnect_flag = Arc :: clone ( & controller_proxy. 1 ) ;
184+ fasync:: Task :: spawn ( async move {
185+ serve_adb_connection ( stream, cbridge)
186+ . await
187+ . unwrap_or_else ( |e| println ! ( "serve_adb_connection returned with {:?}" , e) ) ;
188+ reconnect_flag. store ( true , std:: sync:: atomic:: Ordering :: SeqCst ) ;
155189 } )
156- . context ( "connecting to adbd" ) ?;
190+ . detach ( ) ;
191+ }
157192
158- let reconnect_flag = Arc :: clone ( & controller_proxy. 1 ) ;
159- fasync:: Task :: spawn ( async move {
160- serve_adb_connection ( stream, cbridge)
161- . await
162- . unwrap_or_else ( |e| println ! ( "serve_adb_connection returned with {:?}" , e) ) ;
163- reconnect_flag. store ( true , std:: sync:: atomic:: Ordering :: SeqCst ) ;
164- } )
165- . detach ( ) ;
193+ handle. close ( ) ;
194+ signal_thread. join ( ) . expect ( "signal thread to shutdown without panic" ) ;
195+ Ok ( ( ) )
166196 }
167-
168- handle. close ( ) ;
169- signal_thread. join ( ) . expect ( "signal thread to shutdown without panic" ) ;
170- Ok ( ( ) )
171197}
172198
173199#[ cfg( test) ]
0 commit comments