blob: 6531ed58f2a57a2c74243eda3563fd18c472ae45 [file] [log] [blame]
mod bluetooth_manager;
mod bluetooth_manager_dbus;
mod config_util;
mod dbus_arg;
mod state_machine;
use crate::bluetooth_manager::BluetoothManager;
use dbus::channel::MatchingReceiver;
use dbus::message::MatchRule;
use dbus::nonblock::SyncConnection;
use dbus_crossroads::Crossroads;
use dbus_projection::DisconnectWatcher;
use dbus_tokio::connection;
use log::LevelFilter;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
use syslog::{BasicLogger, Facility, Formatter3164};
#[derive(Clone)]
struct ManagerContext {
proxy: state_machine::StateMachineProxy,
floss_enabled: Arc<AtomicBool>,
dbus_connection: Arc<SyncConnection>,
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let formatter = Formatter3164 {
facility: Facility::LOG_USER,
hostname: None,
process: "btmanagerd".into(),
pid: 0,
};
let logger = syslog::unix(formatter).expect("could not connect to syslog");
let _ = log::set_boxed_logger(Box::new(BasicLogger::new(logger)))
.map(|()| log::set_max_level(config_util::get_log_level().unwrap_or(LevelFilter::Info)));
// Initialize config util
config_util::fix_config_file_format();
// Connect to the D-Bus system bus (this is blocking, unfortunately).
let (resource, conn) = connection::new_system_sync()?;
// Determine whether to use upstart or systemd
let args: Vec<String> = std::env::args().collect();
let invoker = if args.len() > 1 {
match &args[1][0..] {
"--systemd" | "-s" => state_machine::Invoker::SystemdInvoker,
_ => state_machine::Invoker::UpstartInvoker,
}
} else {
state_machine::Invoker::UpstartInvoker
};
let context = state_machine::start_new_state_machine_context(invoker);
let proxy = context.get_proxy();
let manager_context = ManagerContext {
proxy: proxy,
floss_enabled: Arc::new(AtomicBool::new(config_util::is_floss_enabled())),
dbus_connection: conn.clone(),
};
// The resource is a task that should be spawned onto a tokio compatible
// reactor ASAP. If the resource ever finishes, you lost connection to D-Bus.
tokio::spawn(async {
let err = resource.await;
panic!("Lost connection to D-Bus: {}", err);
});
// Let's request a name on the bus, so that clients can find us.
conn.request_name("org.chromium.bluetooth.Manager", false, true, false).await?;
// Create a new crossroads instance.
// The instance is configured so that introspection and properties interfaces
// are added by default on object path additions.
let mut cr = Crossroads::new();
// Enable async support for the crossroads instance.
cr.set_async_support(Some((
conn.clone(),
Box::new(|x| {
tokio::spawn(x);
}),
)));
// Object manager is necessary for clients (to inform them when Bluetooth is
// available). Create it at root (/) so subsequent additions generate
// InterfaceAdded and InterfaceRemoved signals.
cr.set_object_manager_support(Some(conn.clone()));
cr.insert("/", &[cr.object_manager()], {});
let bluetooth_manager = Arc::new(Mutex::new(Box::new(BluetoothManager::new(manager_context))));
// Set up the disconnect watcher to monitor client disconnects.
let disconnect_watcher = Arc::new(Mutex::new(DisconnectWatcher::new()));
disconnect_watcher.lock().unwrap().setup_watch(conn.clone()).await;
// Let's add the "/org/chromium/bluetooth/Manager" path, which implements
// the org.chromium.bluetooth.Manager interface, to the crossroads instance.
bluetooth_manager_dbus::export_bluetooth_manager_dbus_obj(
"/org/chromium/bluetooth/Manager",
conn.clone(),
&mut cr,
bluetooth_manager.clone(),
disconnect_watcher.clone(),
);
// We add the Crossroads instance to the connection so that incoming method calls will be handled.
conn.start_receive(
MatchRule::new_method_call(),
Box::new(move |msg, conn| {
cr.handle_message(msg, conn).unwrap();
true
}),
);
tokio::spawn(async move {
state_machine::mainloop(context, bluetooth_manager).await;
});
std::future::pending::<()>().await;
// Run forever.
unreachable!()
}