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

Commit 859a12c7 authored by Arman Uguray's avatar Arman Uguray
Browse files

service: Introduce Adapter

This CL introduces the Adapter class, which is meant to replace the CoreStack
class. Adapter interfaces with hal::BluetoothInterface rather than calling into
libhardware directly.

Bug: 23169364
Change-Id: Id0a19277d55e83ec3bee3653d5d8795efbd5781b
parent e1d697d6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ LOCAL_PATH:= $(call my-dir)
# ========================================================
btserviceCommonSrc := \
	a2dp_source.cpp \
	adapter.cpp \
	core_stack.cpp \
	daemon.cpp \
	gatt_server.cpp \
@@ -67,6 +68,7 @@ ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
	$(btserviceCommonSrc) \
	test/adapter_unittest.cpp \
	test/fake_hal_bluetooth_interface.cpp \
	test/fake_hal_util.cpp \
	test/ipc_unix_unittest.cpp \
+139 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2015 Google, Inc.
//
//  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 "service/adapter.h"

#include <base/logging.h>

#include "service/logging_helpers.h"

namespace bluetooth {

Adapter::Adapter() : enabled_(false) {
  hal::BluetoothInterface::Get()->AddObserver(this);

  // TODO(armansito): Get all initial adapter properties here and set local
  // state.
}

Adapter::~Adapter() {
  hal::BluetoothInterface::Get()->RemoveObserver(this);
}

bool Adapter::IsEnabled() {
  return enabled_.load();
}

bool Adapter::Enable() {
  if (enabled_.load()) {
    LOG(INFO) << "Adapter already enabled";
    return false;
  }

  int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable();
  if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "Failed to enable Bluetooth - status: "
               << BtStatusText((const bt_status_t)status);
    return false;
  }

  return true;
}

bool Adapter::Disable() {
  if (!enabled_) {
    LOG(INFO) << "Adapter already disabled";
    return false;
  }

  int status = hal::BluetoothInterface::Get()->GetHALInterface()->disable();
  if (status != BT_STATUS_SUCCESS) {
    LOG(ERROR) << "Failed to disable Bluetooth - status: "
               << BtStatusText((const bt_status_t)status);
    return false;
  }

  return true;
}

bool Adapter::SetName(const std::string& name) {
  bt_bdname_t hal_name;
  size_t max_name_len = sizeof(hal_name.name);

  // Include the \0 byte in size measurement.
  if (name.length() >= max_name_len) {
    LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum allowed"
               << " size: " << max_name_len;
    return false;
  }

  strncpy(reinterpret_cast<char*>(hal_name.name), name.c_str(),
          name.length() + 1);

  VLOG(1) << "Setting adapter name: " << name;

  if (!SetAdapterProperty(BT_PROPERTY_BDNAME, &hal_name, sizeof(hal_name))) {
    LOG(ERROR) << "Failed to set adapter name: " << name;
    return false;
  }

  return true;
}

void Adapter::AdapterStateChangedCallback(bt_state_t state) {
  LOG(INFO) << "Adapter state changed: " << BtStateText(state);

  switch (state) {
  case BT_STATE_OFF:
    enabled_ = false;
    break;

  case BT_STATE_ON:
    enabled_ = true;
    break;

  default:
    NOTREACHED();
  }
}

void Adapter::AdapterPropertiesCallback(bt_status_t /* status */,
                                        int /* num_properties */,
                                        bt_property_t* /* properties */) {
  // TODO(armansito): Do something meaningful here.
}

bool Adapter::SetAdapterProperty(bt_property_type_t type,
                                 void* value, int length) {
  CHECK(length > 0);
  CHECK(value);

  bt_property_t property;
  property.len = length;
  property.val = value;
  property.type = type;

  int status = hal::BluetoothInterface::Get()->GetHALInterface()->
      set_adapter_property(&property);
  if (status != BT_STATUS_SUCCESS) {
    VLOG(1) << "Failed to set property";
    return false;
  }

  return true;
}

}  // namespace bluetooth
+69 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2015 Google, Inc.
//
//  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 <atomic>
#include <memory>
#include <string>

#include <base/macros.h>

#include "service/hal/bluetooth_interface.h"

namespace bluetooth {

// Represents the local Bluetooth adapter.
class Adapter : hal::BluetoothInterface::Observer {
 public:
  Adapter();
  ~Adapter();

  // Returns true, if the adapter radio is current powered.
  bool IsEnabled();

  // Enables Bluetooth. This method will send a request to the Bluetooth adapter
  // to power up its radio. Returns true, if the request was successfully sent
  // to the controller, otherwise returns false. A successful call to this
  // method only means that the enable request has been sent to the Bluetooth
  // controller and does not imply that the operation itself succeeded.
  bool Enable();

  // Powers off the Bluetooth radio. Returns true, if the disable request was
  // successfully sent to the Bluetooth controller.
  bool Disable();

  // Sets the name assigned to the local Bluetooth adapter. This is the name
  // that the local controller will present to remote devices.
  bool SetName(const std::string& name);

 private:
  // hal::BluetoothInterface::Observer overrides.
  void AdapterStateChangedCallback(bt_state_t state) override;
  void AdapterPropertiesCallback(bt_status_t status,
                                 int num_properties,
                                 bt_property_t* properties) override;

  // Sends a request to set the given HAL adapter property type and value.
  bool SetAdapterProperty(bt_property_type_t type, void* value, int length);

  // True if the adapter radio is currently powered.
  std::atomic_bool enabled_;

  DISALLOW_COPY_AND_ASSIGN(Adapter);
};

}  // namespace bluetooth
+159 −0
Original line number Diff line number Diff line
//
//  Copyright (C) 2015 Google, Inc.
//
//  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 <base/macros.h>
#include <gtest/gtest.h>

#include "service/adapter.h"
#include "service/test/fake_hal_bluetooth_interface.h"

namespace bluetooth {
namespace {

// A Fake HAL Bluetooth interface. This is kept as a global singleton as the
// Bluetooth HAL doesn't support anything otherwise.
struct FakeHALManager {
  FakeHALManager()
      : enable_succeed(false),
        disable_succeed(false),
        set_property_succeed(false) {
  }

  // Values that should be returned from bt_interface_t methods.
  bool enable_succeed;
  bool disable_succeed;
  bool set_property_succeed;
};
FakeHALManager g_hal_manager;

int FakeHALEnable() {
  return g_hal_manager.enable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}

int FakeHALDisable() {
  return g_hal_manager.disable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}

int FakeHALSetAdapterProperty(const bt_property_t* /* property */) {
  LOG(INFO) << __func__;
  return (g_hal_manager.set_property_succeed ? BT_STATUS_SUCCESS :
          BT_STATUS_FAIL);
}

bt_interface_t fake_bt_iface = {
  sizeof(bt_interface_t),
  nullptr, /* init */
  FakeHALEnable,
  FakeHALDisable,
  nullptr, /* cleanup */
  nullptr, /* get_adapter_properties */
  nullptr, /* get_adapter_property */
  FakeHALSetAdapterProperty,
  nullptr, /* get_remote_device_properties */
  nullptr, /* get_remote_device_property */
  nullptr, /* set_remote_device_property */
  nullptr, /* get_remote_service_record */
  nullptr, /* get_remote_services */
  nullptr, /* start_discovery */
  nullptr, /* cancel_discovery */
  nullptr, /* create_bond */
  nullptr, /* remove_bond */
  nullptr, /* cancel_bond */
  nullptr, /* get_connection_state */
  nullptr, /* pin_reply */
  nullptr, /* ssp_reply */
  nullptr, /* get_profile_interface */
  nullptr, /* dut_mode_configure */
  nullptr, /* dut_more_send */
  nullptr, /* le_test_mode */
  nullptr, /* config_hci_snoop_log */
  nullptr, /* set_os_callouts */
  nullptr, /* read_energy_info */
  nullptr, /* dump */
};

class AdapterTest : public ::testing::Test {
 public:
  AdapterTest() = default;
  ~AdapterTest() override = default;

  void SetUp() override {
    fake_hal_iface_ = new testing::FakeHALBluetoothInterface(&fake_bt_iface);
    hal::BluetoothInterface::InitializeForTesting(fake_hal_iface_);

    adapter_.reset(new Adapter());
  }

  void TearDown() override {
    adapter_.reset();
    hal::BluetoothInterface::CleanUp();
  }

 protected:
  testing::FakeHALBluetoothInterface* fake_hal_iface_;
  std::unique_ptr<Adapter> adapter_;

 private:
  DISALLOW_COPY_AND_ASSIGN(AdapterTest);
};

TEST_F(AdapterTest, IsEnabled) {
  EXPECT_FALSE(adapter_->IsEnabled());

  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
  EXPECT_TRUE(adapter_->IsEnabled());

  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
  EXPECT_FALSE(adapter_->IsEnabled());
}

TEST_F(AdapterTest, Enable) {
  EXPECT_FALSE(adapter_->IsEnabled());
  EXPECT_FALSE(adapter_->Enable());

  g_hal_manager.enable_succeed = true;
  EXPECT_TRUE(adapter_->Enable());

  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
  EXPECT_FALSE(adapter_->Enable());
}

TEST_F(AdapterTest, Disable) {
  g_hal_manager.disable_succeed = true;
  EXPECT_FALSE(adapter_->IsEnabled());
  EXPECT_FALSE(adapter_->Disable());

  fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
  EXPECT_TRUE(adapter_->Disable());

  g_hal_manager.disable_succeed = false;
  EXPECT_FALSE(adapter_->Disable());
}

TEST_F(AdapterTest, SetName) {
  bt_bdname_t hal_name;

  // Name too large.
  EXPECT_FALSE(adapter_->SetName(std::string(sizeof(hal_name.name), 'a')));

  // Valid length.
  EXPECT_FALSE(adapter_->SetName("Test Name"));
  g_hal_manager.set_property_succeed = true;
  EXPECT_TRUE(adapter_->SetName("Test Name"));
}

}  // namespace
}  // namespace bluetooth
+11 −4
Original line number Diff line number Diff line
@@ -19,17 +19,24 @@
namespace bluetooth {
namespace testing {

FakeHALBluetoothInterface::FakeHALBluetoothInterface(bt_interface_t* hal_iface)
    : hal_iface_(hal_iface) {
}

void FakeHALBluetoothInterface::NotifyAdapterStateChanged(bt_state_t state) {
  FOR_EACH_OBSERVER(Observer, observers_, AdapterStateChangedCallback(state));
}

void FakeHALBluetoothInterface::AddObserver(Observer* observer) {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
  observers_.AddObserver(observer);
}

void FakeHALBluetoothInterface::RemoveObserver(Observer* observer) {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
  observers_.RemoveObserver(observer);
}

const bt_interface_t* FakeHALBluetoothInterface::GetHALInterface() const {
  // TODO(armansito): Do something meaningful here to simulate test behavior.
  return nullptr;
  return hal_iface_;
}

const bluetooth_device_t* FakeHALBluetoothInterface::GetHALAdapter() const {
Loading