Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7be6035 authored by Hsin-chen Chuang's avatar Hsin-chen Chuang Committed by Automerger Merge Worker
Browse files

Merge "floss: btclient: Allow -c command when adapter is disabled" into main...

Merge "floss: btclient: Allow -c command when adapter is disabled" into main am: ced45544 am: 26614482

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/3158873



Change-Id: Iac63b4e486cbf03a1f28392e4c48f68cb674cb14
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 7b3df936 26614482
Loading
Loading
Loading
Loading
+6 −4
Original line number Original line Diff line number Diff line
@@ -523,6 +523,12 @@ impl CommandHandler {


        let command = get_arg(args, 0)?;
        let command = get_arg(args, 0)?;


        if matches!(&command[..], "show" | "discoverable" | "connectable" | "set-name") {
            if !self.lock_context().adapter_ready {
                return Err(self.adapter_not_ready());
            }
        }

        match &command[..] {
        match &command[..] {
            "enable" => {
            "enable" => {
                if self.lock_context().is_restricted {
                if self.lock_context().is_restricted {
@@ -537,10 +543,6 @@ impl CommandHandler {
                self.lock_context().manager_dbus.stop(default_adapter);
                self.lock_context().manager_dbus.stop(default_adapter);
            }
            }
            "show" => {
            "show" => {
                if !self.lock_context().adapter_ready {
                    return Err(self.adapter_not_ready());
                }

                let enabled = self.lock_context().enabled;
                let enabled = self.lock_context().enabled;
                let address = self.lock_context().adapter_address.unwrap_or_default();
                let address = self.lock_context().adapter_address.unwrap_or_default();
                let context = self.lock_context();
                let context = self.lock_context();
+61 −33
Original line number Original line Diff line number Diff line
@@ -362,7 +362,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
                .help("Specify a timeout in seconds for a non-interactive command"),
                .help("Specify a timeout in seconds for a non-interactive command"),
        )
        )
        .get_matches();
        .get_matches();
    let command = value_t!(matches, "command", String);
    let command = value_t!(matches, "command", String).ok();
    let is_restricted = matches.is_present("restricted");
    let is_restricted = matches.is_present("restricted");
    let timeout_secs = value_t!(matches, "timeout", u64);
    let timeout_secs = value_t!(matches, "timeout", u64);


@@ -433,28 +433,36 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
        // right away.
        // right away.
        let default_adapter = context.lock().unwrap().default_adapter;
        let default_adapter = context.lock().unwrap().default_adapter;


        {
        let default_adapter_enabled = {
            let mut context_locked = context.lock().unwrap();
            let mut context_locked = context.lock().unwrap();
            match context_locked.manager_dbus.rpc.get_adapter_enabled(default_adapter).await {
            match context_locked.manager_dbus.rpc.get_adapter_enabled(default_adapter).await {
                Ok(ret) => {
                Ok(enabled) => {
                    if ret {
                    if enabled {
                        context_locked.set_adapter_enabled(default_adapter, true);
                        context_locked.set_adapter_enabled(default_adapter, true);
                    }
                    }
                    enabled
                }
                }
                Err(e) => {
                Err(e) => {
                    panic!("Bluetooth Manager is not available. Exiting. D-Bus error: {}", e);
                    panic!("Bluetooth Manager is not available. Exiting. D-Bus error: {}", e);
                }
                }
            }
            }
        }
        };


        let handler = CommandHandler::new(context.clone());
        let handler = CommandHandler::new(context.clone());
        if command.is_ok() {
        if command.is_some() {
            // Timeout applies only to non-interactive commands.
            // Timeout applies only to non-interactive commands.
            if let Ok(timeout_secs) = timeout_secs {
            if let Ok(timeout_secs) = timeout_secs {
                let timeout_duration = Duration::from_secs(timeout_secs);
                let timeout_duration = Duration::from_secs(timeout_secs);
                match timeout(
                match timeout(
                    timeout_duration,
                    timeout_duration,
                    handle_client_command(handler, tx, rx, context, command),
                    handle_client_command(
                        handler,
                        tx,
                        rx,
                        context,
                        command,
                        default_adapter_enabled,
                    ),
                )
                )
                .await
                .await
                {
                {
@@ -470,31 +478,50 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
        // There are two scenarios in which handle_client_command is run without a timeout.
        // There are two scenarios in which handle_client_command is run without a timeout.
        // - Interactive commands: none of these commands require a timeout.
        // - Interactive commands: none of these commands require a timeout.
        // - Non-interactive commands that have not specified a timeout.
        // - Non-interactive commands that have not specified a timeout.
        handle_client_command(handler, tx, rx, context, command).await?;
        handle_client_command(handler, tx, rx, context, command, default_adapter_enabled).await?;
        Result::Ok(())
        Result::Ok(())
    })
    })
}
}


// If btclient runs without command arguments, the interactive shell
// If btclient runs without command arguments, the interactive shell actions are performed.
// actions are performed.
// If btclient runs with command arguments, the command is executed once.
// If btclient runs with command arguments, the command is executed
// There are 2 cases to run the command and 2 cases to exit.
// once. There are two cases to exit.
// Run:
//   Case 1: if the command does not need a callback, e.g., "help",
//   Case 1: If |run_command_on_ready|, run the command after the callbacks are registered
//           it will exit after running handler.process_cmd_line().
//           successfully.
//   Case 2: if the command needs a callback, e.g., "media log",
//   Case 2: If not |run_command_on_ready|, run the command immediately.
//           it will exit after the callback has been run in the arm
// Exit:
//           of ForegroundActions::RunCallback(callback).
//   Case 1: if the command does not need a callback, e.g., "help", it will exit after running
//           handler.process_cmd_line().
//   Case 2: if the command needs a callback, e.g., "media log", it will exit after the callback
//           has been run in the arm of ForegroundActions::RunCallback(callback).
async fn handle_client_command(
async fn handle_client_command(
    mut handler: CommandHandler,
    mut handler: CommandHandler,
    tx: mpsc::Sender<ForegroundActions>,
    tx: mpsc::Sender<ForegroundActions>,
    mut rx: mpsc::Receiver<ForegroundActions>,
    mut rx: mpsc::Receiver<ForegroundActions>,
    context: Arc<Mutex<ClientContext>>,
    context: Arc<Mutex<ClientContext>>,
    command: Result<String, clap::Error>,
    command: Option<String>,
    run_command_on_ready: bool,
) -> Result<(), Box<dyn std::error::Error>> {
) -> Result<(), Box<dyn std::error::Error>> {
    if !run_command_on_ready {
        if let Some(command) = command.as_ref() {
            let mut iter = command.split(' ').map(String::from);
            let first = iter.next().unwrap_or(String::from(""));
            // Return immediately if the command fails to execute.
            if !handler.process_cmd_line(&first, &iter.collect::<Vec<String>>()) {
                return Err("failed process command".into());
            }
            // If there is no callback to wait for, we're done.
            if !context.lock().unwrap().client_commands_with_callbacks.contains(&first) {
                return Ok(());
            }
        }
    }

    let semaphore_fg = Arc::new(tokio::sync::Semaphore::new(1));
    let semaphore_fg = Arc::new(tokio::sync::Semaphore::new(1));


    // If there are no command arguments, start the interactive shell.
    // If there are no command arguments, start the interactive shell.
    if command.is_err() {
    if command.is_none() {
        let command_rule_list = handler.get_command_rule_list().clone();
        let command_rule_list = handler.get_command_rule_list().clone();
        let context_for_closure = context.clone();
        let context_for_closure = context.clone();


@@ -544,7 +571,7 @@ async fn handle_client_command(
                callback(context.clone());
                callback(context.clone());


                // Break the loop as a non-interactive command is completed.
                // Break the loop as a non-interactive command is completed.
                if command.is_ok() {
                if command.is_some() {
                    break;
                    break;
                }
                }
            }
            }
@@ -759,9 +786,8 @@ async fn handle_client_command(


                print_info!("Adapter {} is ready", adapter_address.to_string());
                print_info!("Adapter {} is ready", adapter_address.to_string());


                // Run the command with the command arguments as the client is
                if run_command_on_ready {
                // non-interactive.
                    if let Some(command) = command.as_ref() {
                if let Ok(command) = command.as_ref() {
                        let mut iter = command.split(' ').map(String::from);
                        let mut iter = command.split(' ').map(String::from);
                        let first = iter.next().unwrap_or(String::from(""));
                        let first = iter.next().unwrap_or(String::from(""));
                        if !handler.process_cmd_line(&first, &iter.collect::<Vec<String>>()) {
                        if !handler.process_cmd_line(&first, &iter.collect::<Vec<String>>()) {
@@ -771,11 +797,13 @@ async fn handle_client_command(


                        // Break the loop immediately if there is no callback
                        // Break the loop immediately if there is no callback
                        // to wait for.
                        // to wait for.
                    if !context.lock().unwrap().client_commands_with_callbacks.contains(&first) {
                        if !context.lock().unwrap().client_commands_with_callbacks.contains(&first)
                        {
                            break;
                            break;
                        }
                        }
                    }
                    }
                }
                }
            }
            ForegroundActions::Readline(result) => match result {
            ForegroundActions::Readline(result) => match result {
                Err(rustyline::error::ReadlineError::Interrupted) => {
                Err(rustyline::error::ReadlineError::Interrupted) => {
                    // Ctrl-C cancels the currently typed line, do nothing and ready to do next
                    // Ctrl-C cancels the currently typed line, do nothing and ready to do next