CSC/ECE 517 Spring 2019 - M1902 Refactor bluetooth support for better maintainability: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 34: Line 34:
*devices/src/bluetooth.rs
*devices/src/bluetooth.rs


===''' Converting BluetoothAdapter to Trait'''===
===''' Converting enum to Trait'''===


* A trait for BluetoothAdapter was defined
* A trait for BluetoothAdapter was defined

Revision as of 22:20, 1 April 2019

Introduction

Servo

Servo is a prototype web browser engine, developed on 64-bit macOS, 64-bit Linux, 64-bit Windows, and Android. The goal is to create a new layout engine using a modern programming language (Rust), and using parallelism and code safety, to achieve greater security and performance versus contemporary browsers.

For more information, click here

Rust

Rust is a new open-source systems programming language created by Mozilla and a community of volunteers, designed to help developers create fast, secure applications which take full advantage of the powerful features of modern multi-core processors. It prevents segmentation faults and guarantees thread safety, all with an easy-to-learn syntax. Rust is syntactically similar to C++, but is designed to provide better memory safety while maintaining high performance.

For more information, click here

WebBluetooth - Problem Statement

The WebBluetooth specification allows websites to interact with active bluetooth devices in the vicinity of a user. Servo is a new, experimental browser that implements this specification; since bluetooth support requires lots of per-platform code, the current implementation is messy. The goal of this project is to implement clean separation of a cross-platform interface from the specific per-platform implementation to make the code more maintainable.

Implementation

The current implementation uses values of type enum and they are to be converted to trait. Traits make it easier to add new implementations to the code than enum. A trait is a rust feature that tells the compiler about functionality a type must provide.

You can get more information on traits here


Steps

  • To convert the BluetoothAdapter type from an enum to a trait.
  • To create a new adapter.rs file (and therefore module) that contains implementations of this new trait for all platforms.
  • To modify Servo's integration to use this new trait, replacing uses of the old BluetoothAdapter enum with a trait object.
  • To convert the BluetoothDiscoverySession type from an enum to a trait.
  • To create a new discovery_session.rs file that contains implementations of this new trait for all platforms.
  • To modify Servo's integration to use this new trait, replacing uses of the old BluetoothDiscoverySession enum with a trait object.

Files(to be)modified

In servo repository,

  • servo/components/bluetooth/lib.rs

In devices repository,

  • devices/src/bluetooth.rs

Converting enum to Trait

  • A trait for BluetoothAdapter was defined
  • A separate structure for each platform (say Android, linux, Mac) was created
  • Functions corresponding to each platform were written in their respective structure

A snippet of the code for platform 'Linux' is given below,

pub trait BluetoothAdapter{
    fn new()-> Result<Box<BluetoothAdapter>, Box<Error>>;
    fn get_id(&self)-> String;
    fn get_devices(&self)-> Result<Vec<BluetoothDevice>, Box<Error>>;
    fn get_device(&self, address: String) -> Result<Option<BluetoothDevice>, Box<Error>>;
    fn get_address(&self) -> Result<String, Box<Error>>;
    fn get_name(&self)-> Result<String, Box<Error>>;
    fn get_alias(&self) -> Result<String, Box<Error>>;
    fn get_class(&self)-> Result<u32, Box<Error>>;
    fn is_powered(&self)-> Result<bool, Box<Error>>;
    fn is_discoverable(&self) -> Result<bool, Box<Error>>;
    fn is_pairable(&self)-> Result<bool, Box<Error>>;
    fn get_pairable_timeout(&self) -> Result<u32, Box<Error>>;
    fn get_discoverable_timeout(&self)-> Result<u32, Box<Error>>;
    fn is_discovering(&self)-> Result<bool, Box<Error>>;
    fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<Error>> ;
    fn get_uuids(&self)-> Result<Vec<String>, Box<Error>>;
    fn get_vendor_id_source(&self)-> Result<String, Box<Error>>;
    fn get_vendor_id(&self)-> Result<u32, Box<Error>>;
    fn get_product_id(&self) -> Result<u32, Box<Error>> ;
    fn get_device_id(&self) -> Result<u32, Box<Error>>;
    fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<Error>>; 
}

pub struct Bluez(Arc<BluetoothAdapterBluez>);

impl BluetoothAdapter for Bluez{

    fn new() -> Result<Box<BluetoothAdapter>, Box<Error>> {
        let bluez_adapter = try!(BluetoothAdapter::init());
        Ok(BluetoothAdapter::Bluez(Arc::new(bluez_adapter)))
    }

    fn get_id(&self) -> String{
        self.0.get_id()
    }

    fn get_devices(&self) -> Result<Vec<BluetoothDevice>, Box<Error>> {
        let device_list = try!(self.0.get_device_list());
        Ok(device_list.into_iter().map(|device| BluetoothDevice::create_device(self.clone(), device)).collect())
    }

    fn get_device(&self, address: String) -> Result<Option<BluetoothDevice>, Box<Error>> {
        let devices = try!(self.get_devices());
        for device in devices {
            if try!(device.get_address()) == address {
                return Ok(Some(device));
            }
        }
        Ok(None)
    }

    fn get_address(&self) -> Result<String, Box<Error>> {
        self.0.get_address()
    }

    fn get_name(&self) -> Result<String, Box<Error>> {
        self.0.get_name()
    }


    fn get_alias(&self) -> Result<String, Box<Error>> {
        self.0.get_alias()
    }


    fn get_class(&self) -> Result<u32, Box<Error>> {
        self.0.get_class()
    }

    fn is_powered(&self) -> Result<bool, Box<Error>> {
        self.0.is_powered()
    }


    fn is_discoverable(&self) -> Result<bool, Box<Error>> {
       self.0.is_discoverable()
    }


    fn is_pairable(&self) -> Result<bool, Box<Error>> {
       self.0.is_pairable()
    }


    fn get_pairable_timeout(&self) -> Result<u32, Box<Error>> {
       self.0.get_pairable_timeout()
    }

    fn get_discoverable_timeout(&self) -> Result<u32, Box<Error>> {
       self.0.get_discoverable_timeout()
    }

    fn is_discovering(&self) -> Result<bool, Box<Error>> {
       self.0.is_discovering()
    }


    fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<Error>> {
        BluetoothDiscoverySession::create_session(self.clone())
    }

    fn get_uuids(&self) -> Result<Vec<String>, Box<Error>> {
        self.0.get_uuids()
    }


    fn get_vendor_id_source(&self) -> Result<String, Box<Error>> {
        self.0.get_vendor_id_source()
    }

    fn get_vendor_id(&self) -> Result<u32, Box<Error>> {
        self.0.get_vendor_id()
    }

    fn get_product_id(&self) -> Result<u32, Box<Error>> {
        self.0.get_product_id()
    }

    fn get_device_id(&self) -> Result<u32, Box<Error>> {
        self.0.get_device_id()
    }

    fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<Error>> {
        self.0.get_modalias()
    }
}

Build

Servo is built with Cargo, the Rust package manager. We also use Mozilla's Mach tools to orchestrate the build and other tasks.

Normal build

To build Servo in development mode. This is useful for development, but the resulting binary is very slow.

For Mac OS,

git clone https://github.com/servo/servo

cd servo

./mach build --dev

For Windows,

git clone https://github.com/servo/servo

cd servo

mach.bat build --dev

Note that build may take up to 45 minutes. Detailed instructions for setting up the environment and the dependancies are available here

Running

For Mac OS,

Use ./mach test-wpt tests/wpt/mozilla/tests/bluetooth/ to run the existing bluetooth automated tests.

For Windows,

Use mach.bat test-wpt tests/wpt/mozilla/tests/bluetooth/ to run the existing bluetooth automated tests