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

Commit 5d8dcedc authored by Martin Brabham's avatar Martin Brabham Committed by android-build-merger
Browse files

Device: Initial bluetooth device API am: 6d2776ec am: af616cf0

am: a324d800

Change-Id: I80a24f76bf6b81afffb3f51650b96b8e73e76ae3
parents 86610643 a324d800
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@ filegroup {
        "controller.cc",
        "address.cc",
        "class_of_device.cc",
        "device.cc",
        "device_database.cc",
        "hci_layer.cc",
    ],
}
@@ -19,6 +21,9 @@ filegroup {
        "controller_test.cc",
        "address_unittest.cc",
        "class_of_device_unittest.cc",
        "device_test.cc",
        "device_database_test.cc",
        "dual_device_test.cc",
        "hci_layer_test.cc",
    ],
}
+35 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
#pragma once

#include "hci/device.h"

namespace bluetooth::hci {

/**
 * A device representing a CLASSIC device.
 *
 * <p>This can be a CLASSIC only or a piece of a DUAL MODE device.
 */
class ClassicDevice : public Device {
 protected:
  friend class DeviceDatabase;
  explicit ClassicDevice(Address address) : Device(address, DeviceType::CLASSIC) {}
};

}  // namespace bluetooth::hci
+32 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
#include "hci/device.h"

using namespace bluetooth::hci;

std::string Device::generate_uid() {
  // TODO(optedoblivion): Figure out a good way to do this for what we want
  // to do
  // TODO(optedoblivion): Need to make a way to override something for LE pub addr case
  // Not sure if something like this is needed, but here is the idea (I think it came from mylesgw)
  // CLASSIC: have all 0s in front for classic then have private address
  // LE: have first public address in front then all 0s
  // LE: have first public address in front then private address
  //
  return address_.ToString();
}

system/gd/hci/device.h

0 → 100644
+136 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
#pragma once

#include <string>

#include "hci/address.h"
#include "hci/class_of_device.h"

namespace bluetooth::hci {

/**
 * Used to determine device functionality
 */
enum DeviceType { DUAL, CLASSIC, LE };

/**
 * Represents a physical HCI device.
 *
 * <p>Contains all of the metadata required to represent a phycial device.
 *
 * <p>Devices should only be created and modified by HCI.
 */
class Device {
 public:
  virtual ~Device() = default;

  Address GetAddress() const {
    return address_;
  }

  /**
   * Returns 1 of 3 enum values for device's type (DUAL, CLASSIC, LE)
   */
  DeviceType GetDeviceType() const {
    return device_type_;
  }

  /**
   * Unique identifier for bluetooth devices
   *
   * @return string representation of the uuid
   */
  std::string /** use UUID when ported */ GetUuid() {
    return uid_;
  }

  std::string GetName() {
    return name_;
  }

  ClassOfDevice GetClassOfDevice() {
    return class_of_device_;
  }

  bool IsBonded() {
    return is_bonded_;
  }

  bool operator==(const Device& rhs) const {
    return this->uid_ == rhs.uid_ && this->address_ == rhs.address_ && this->device_type_ == rhs.device_type_ &&
           this->is_bonded_ == rhs.is_bonded_;
  }

 protected:
  friend class DeviceDatabase;
  friend class DualDevice;

  /**
   * @param raw_address the address of the device
   * @param device_type specify the type of device to create
   */
  Device(Address address, DeviceType device_type)
      : address_(address), device_type_(device_type), uid_(generate_uid()), name_(""), class_of_device_() {}

  /**
   * Called only by friend class DeviceDatabase
   *
   * @param address
   */
  virtual void SetAddress(Address address) {
    address_ = address;
    uid_ = generate_uid();
  }

  /**
   * Set the type of the device.
   *
   * <p>Needed by dual mode to arbitrarily set the valure to DUAL for corresponding LE/Classic devices
   *
   * @param type of device
   */
  void SetDeviceType(DeviceType type) {
    device_type_ = type;
  }

  void SetName(std::string& name) {
    name_ = name;
  }

  void SetClassOfDevice(ClassOfDevice class_of_device) {
    class_of_device_ = class_of_device;
  }

  void SetIsBonded(bool is_bonded) {
    is_bonded_ = is_bonded;
  }

 private:
  Address address_{Address::kEmpty};
  DeviceType device_type_;
  std::string uid_;
  std::string name_;
  ClassOfDevice class_of_device_;
  bool is_bonded_ = false;

  /* Uses specific information about the device to calculate a UID */
  std::string generate_uid();
};

}  // namespace bluetooth::hci
+284 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
#include "hci/device_database.h"

#include <memory>
#include <utility>

#include "hci/classic_device.h"
#include "hci/dual_device.h"
#include "hci/le_device.h"
#include "os/log.h"

using namespace bluetooth::hci;

std::shared_ptr<ClassicDevice> DeviceDatabase::CreateClassicDevice(Address address) {
  ClassicDevice device(address);
  const std::string uuid = device.GetUuid();
  if (AddDeviceToMap(std::move(device))) {
    return GetClassicDevice(uuid);
  }
  return std::shared_ptr<ClassicDevice>();
}

std::shared_ptr<LeDevice> DeviceDatabase::CreateLeDevice(Address address) {
  LeDevice device(address);
  const std::string uuid = device.GetUuid();
  if (AddDeviceToMap(std::move(device))) {
    return GetLeDevice(uuid);
  }
  return std::shared_ptr<LeDevice>();
}

std::shared_ptr<DualDevice> DeviceDatabase::CreateDualDevice(Address address) {
  auto classic = CreateClassicDevice(address);
  auto le = CreateLeDevice(address);
  if (classic && le) {
    DualDevice device(address, classic, le);
    std::string uuid = device.GetUuid();
    if (AddDeviceToMap(std::move(device))) {
      return GetDualDevice(uuid);
    }
  }
  LOG_WARN("Attempting to instert a DUAL device that already exists!");
  return std::shared_ptr<DualDevice>();
}

bool DeviceDatabase::RemoveDevice(const std::shared_ptr<Device>& device) {
  const DeviceType type = device->GetDeviceType();
  bool success;
  switch (type) {
    case CLASSIC:
      success = false;
      {
        std::lock_guard<std::mutex> lock(device_map_mutex_);
        auto classic_it = classic_device_map_.find(device->GetUuid());
        // If we have a record with the same key
        if (classic_it != classic_device_map_.end()) {
          classic_device_map_.erase(device->GetUuid());
          success = true;
        }
      }
      if (success) {
        ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
      } else {
        LOG_WARN("Device not in database!");
      }
      return success;
    case LE:
      success = false;
      {
        std::lock_guard<std::mutex> lock(device_map_mutex_);
        auto le_it = le_device_map_.find(device->GetUuid());
        // If we have a record with the same key
        if (le_it != le_device_map_.end()) {
          le_device_map_.erase(device->GetUuid());
          success = true;
        }
      }
      if (success) {
        ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
      } else {
        LOG_WARN("Device not in database!");
      }
      return success;
    case DUAL:
      std::shared_ptr<DualDevice> dual_device = nullptr;
      {
        std::lock_guard<std::mutex> lock(device_map_mutex_);
        auto dual_it = dual_device_map_.find(device->GetUuid());
        if (dual_it != dual_device_map_.end()) {
          dual_device = GetDualDevice(device->GetUuid());
        }
      }
      success = false;
      if (dual_device != nullptr) {
        if (RemoveDevice(dual_device->GetClassicDevice()) && RemoveDevice(dual_device->GetLeDevice())) {
          dual_device_map_.erase(device->GetUuid());
          success = true;
        }
      }
      if (success) {
        ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
      } else {
        LOG_WARN("Device not in database!");
      }
      return success;
  }
}

std::shared_ptr<ClassicDevice> DeviceDatabase::GetClassicDevice(const std::string& uuid) {
  std::lock_guard<std::mutex> lock(device_map_mutex_);
  auto it = classic_device_map_.find(uuid);
  if (it != classic_device_map_.end()) {
    return it->second;
  }
  LOG_WARN("Device '%s' not found!", uuid.c_str());
  return std::shared_ptr<ClassicDevice>();
}

std::shared_ptr<LeDevice> DeviceDatabase::GetLeDevice(const std::string& uuid) {
  std::lock_guard<std::mutex> lock(device_map_mutex_);
  auto it = le_device_map_.find(uuid);
  if (it != le_device_map_.end()) {
    return it->second;
  }
  LOG_WARN("Device '%s' not found!", uuid.c_str());
  return std::shared_ptr<LeDevice>();
}

std::shared_ptr<DualDevice> DeviceDatabase::GetDualDevice(const std::string& uuid) {
  std::lock_guard<std::mutex> lock(device_map_mutex_);
  auto it = dual_device_map_.find(uuid);
  if (it != dual_device_map_.end()) {
    return it->second;
  }
  LOG_WARN("Device '%s' not found!", uuid.c_str());
  return std::shared_ptr<DualDevice>();
}

bool DeviceDatabase::UpdateDeviceAddress(const std::shared_ptr<Device>& device, Address new_address) {
  // Hold onto device
  const DeviceType type = device->GetDeviceType();
  if (type == CLASSIC) {
    auto classic_device = GetClassicDevice(device->GetUuid());
    // This gets rid of the shared_ptr in the map
    ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
    classic_device->SetAddress(new_address);
    // Move the value located at the pointer
    return AddDeviceToMap(std::move(*(classic_device.get())));
  } else if (type == LE) {
    auto le_device = GetLeDevice(device->GetUuid());
    // This gets rid of the shared_ptr in the map
    ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
    le_device->SetAddress(new_address);
    // Move the value located at the pointer
    return AddDeviceToMap(std::move(*(le_device.get())));
  } else if (type == DUAL) {
    auto dual_device = GetDualDevice(device->GetUuid());
    // This gets rid of the shared_ptr in the map
    ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
    dual_device->SetAddress(new_address);
    // Move the value located at the pointer
    return AddDeviceToMap(std::move(*(dual_device.get())));
  }
  LOG_ALWAYS_FATAL("Someone added a device type but didn't account for it here.");
  return false;
}

bool DeviceDatabase::AddDeviceToMap(ClassicDevice&& device) {
  const std::string uuid = device.GetUuid();
  bool success = false;
  {
    std::lock_guard<std::mutex> lock(device_map_mutex_);
    auto it = classic_device_map_.find(device.GetUuid());
    // If we have a record with the same key
    if (it != classic_device_map_.end()) {
      LOG_ERROR("Attempt to re-insert classic device '%s' object with same UUID", uuid.c_str());
      // We don't want to insert and overwrite
      return false;
    }
    std::shared_ptr<ClassicDevice> device_ptr = std::make_shared<ClassicDevice>(std::move(device));
    // returning the boolean value of insert success
    if (classic_device_map_
            .insert(std::pair<std::string, std::shared_ptr<ClassicDevice>>(device_ptr->GetUuid(), device_ptr))
            .second) {
      success = true;
    }
  }
  if (success) {
    ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
  } else {
    LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
  }
  return success;
}

bool DeviceDatabase::AddDeviceToMap(LeDevice&& device) {
  const std::string uuid = device.GetUuid();
  bool success = false;
  {
    std::lock_guard<std::mutex> lock(device_map_mutex_);
    auto it = le_device_map_.find(device.GetUuid());
    // If we have a record with the same key
    if (it != le_device_map_.end()) {
      LOG_ERROR("Attempt to re-insert LE device '%s' object with same UUID", uuid.c_str());
      // We don't want to insert and overwrite
      return false;
    }
    std::shared_ptr<LeDevice> device_ptr = std::make_shared<LeDevice>(std::move(device));
    // returning the boolean value of insert success
    if (le_device_map_.insert(std::pair<std::string, std::shared_ptr<LeDevice>>(device_ptr->GetUuid(), device_ptr))
            .second) {
      success = true;
    }
  }
  if (success) {
    ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
  } else {
    LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
  }
  return success;
}

bool DeviceDatabase::AddDeviceToMap(DualDevice&& device) {
  const std::string uuid = device.GetUuid();
  bool success = false;
  {
    std::lock_guard<std::mutex> lock(device_map_mutex_);
    auto it = dual_device_map_.find(device.GetUuid());
    // If we have a record with the same key
    if (it != dual_device_map_.end()) {
      LOG_ERROR("Attempt to re-insert dual device '%s' object with same UUID", uuid.c_str());
      // We don't want to insert and overwrite
      return false;
    }
    std::shared_ptr<DualDevice> device_ptr = std::make_shared<DualDevice>(std::move(device));
    // returning the boolean value of insert success
    if (dual_device_map_.insert(std::pair<std::string, std::shared_ptr<DualDevice>>(device_ptr->GetUuid(), device_ptr))
            .second) {
      success = true;
    }
  }
  if (success) {
    ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
  } else {
    LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
  }
  return success;
}

bool DeviceDatabase::WriteToDisk() {
  // TODO(optedoblivion): Implement
  // TODO(optedoblivion): FIX ME!
  // If synchronous stack dies before async write, we can miss adding device
  // post(WriteToDisk());
  // Current Solution: Synchronous disk I/O...
  std::lock_guard<std::mutex> lock(device_map_mutex_);
  // Collect information to sync to database
  // Create SQL query for insert/update
  // submit SQL
  return true;
}

bool DeviceDatabase::ReadFromDisk() {
  // TODO(optedoblivion): Implement
  // Current Solution: Synchronous disk I/O...
  std::lock_guard<std::mutex> lock(device_map_mutex_);
  return true;
}
Loading