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

Commit dee16ce2 authored by Jakub Rotkiewicz's avatar Jakub Rotkiewicz
Browse files

avrcp/device: Fix nullptr dereference on floss

Player settings commands and notification will only be available if the user
initializes AVRCP service with implementation of Player Settings
Interface as it is currently done in JNI layer.

Test: atest AvrcpDeviceTest
Test: manual running floss tests
Bug: 279194432
Change-Id: Idec5b73cf58b367d3c8084f7ffd34c0dc6d51eea
parent 3cbb18c7
Loading
Loading
Loading
Loading
+47 −4
Original line number Diff line number Diff line
@@ -214,12 +214,29 @@ void Device::VendorPacketHandler(uint8_t label,
    } break;

    case CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES: {
      if (player_settings_interface_ == nullptr) {
        LOG(ERROR) << __func__
                   << ": Player Settings Interface not initialized.";
        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
                                                   Status::INVALID_COMMAND);
        send_message(label, false, std::move(response));
        return;
      }

      player_settings_interface_->ListPlayerSettings(
          base::Bind(&Device::ListPlayerApplicationSettingAttributesResponse,
                     weak_ptr_factory_.GetWeakPtr(), label));
    } break;

    case CommandPdu::LIST_PLAYER_APPLICATION_SETTING_VALUES: {
      if (player_settings_interface_ == nullptr) {
        LOG(ERROR) << __func__
                   << ": Player Settings Interface not initialized.";
        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
                                                   Status::INVALID_COMMAND);
        send_message(label, false, std::move(response));
        return;
      }
      auto list_player_setting_values_request =
          Packet::Specialize<ListPlayerApplicationSettingValuesRequest>(pkt);

@@ -250,6 +267,14 @@ void Device::VendorPacketHandler(uint8_t label,
    } break;

    case CommandPdu::GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE: {
      if (player_settings_interface_ == nullptr) {
        LOG(ERROR) << __func__
                   << ": Player Settings Interface not initialized.";
        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
                                                   Status::INVALID_COMMAND);
        send_message(label, false, std::move(response));
        return;
      }
      auto get_current_player_setting_value_request =
          Packet::Specialize<GetCurrentPlayerApplicationSettingValueRequest>(
              pkt);
@@ -283,6 +308,14 @@ void Device::VendorPacketHandler(uint8_t label,
    } break;

    case CommandPdu::SET_PLAYER_APPLICATION_SETTING_VALUE: {
      if (player_settings_interface_ == nullptr) {
        LOG(ERROR) << __func__
                   << ": Player Settings Interface not initialized.";
        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
                                                   Status::INVALID_COMMAND);
        send_message(label, false, std::move(response));
        return;
      }
      auto set_player_setting_value_request =
          Packet::Specialize<SetPlayerApplicationSettingValueRequest>(pkt);

@@ -379,7 +412,9 @@ void Device::HandleGetCapabilities(
              Event::PLAYBACK_STATUS_CHANGED);
      response->AddEvent(Event::TRACK_CHANGED);
      response->AddEvent(Event::PLAYBACK_POS_CHANGED);
      if (player_settings_interface_ != nullptr) {
        response->AddEvent(Event::PLAYER_APPLICATION_SETTING_CHANGED);
      }

      if (!avrcp13_compatibility_) {
        response->AddEvent(Event::AVAILABLE_PLAYERS_CHANGED);
@@ -434,6 +469,14 @@ void Device::HandleNotification(
    } break;

    case Event::PLAYER_APPLICATION_SETTING_CHANGED: {
      if (player_settings_interface_ == nullptr) {
        LOG(ERROR) << __func__
                   << ": Player Settings Interface not initialized.";
        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
                                                   Status::INVALID_COMMAND);
        send_message(label, false, std::move(response));
        return;
      }
      std::vector<PlayerAttribute> attributes = {
          PlayerAttribute::EQUALIZER, PlayerAttribute::REPEAT,
          PlayerAttribute::SHUFFLE, PlayerAttribute::SCAN};
@@ -1683,7 +1726,7 @@ void Device::HandlePlayerSettingChanged(std::vector<PlayerAttribute> attributes,
  auto response =
      RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
          false, attributes, values);
  send_message(now_playing_changed_.second, false, std::move(response));
  send_message(player_setting_changed_.second, false, std::move(response));
}

void Device::PlayerSettingChangedNotificationResponse(
@@ -1712,11 +1755,11 @@ void Device::PlayerSettingChangedNotificationResponse(
  auto response =
      RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
          interim, attributes, values);
  send_message(now_playing_changed_.second, false, std::move(response));
  send_message(player_setting_changed_.second, false, std::move(response));

  if (!interim) {
    active_labels_.erase(label);
    now_playing_changed_ = Notification(false, 0);
    player_setting_changed_ = Notification(false, 0);
  }
}

+189 −1
Original line number Diff line number Diff line
@@ -175,6 +175,67 @@ TEST_F(AvrcpDeviceTest, trackChangedTest) {
  test_device->HandleTrackUpdate();
}

TEST_F(AvrcpDeviceTest, playerSettingsChangedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;
  MockPlayerSettingsInterface player_settings_interface;
  std::vector<PlayerAttribute> attributes = {PlayerAttribute::REPEAT,
                                             PlayerAttribute::SHUFFLE};
  std::vector<uint8_t> attributes_values = {
      static_cast<uint8_t>(PlayerRepeatValue::OFF),
      static_cast<uint8_t>(PlayerShuffleValue::ALL)};

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  &player_settings_interface);

  EXPECT_CALL(player_settings_interface, GetCurrentPlayerSettingValue(_, _))
      .Times(1)
      .WillRepeatedly(InvokeCb<1>(attributes, attributes_values));

  // Test the interim response for player settings changed
  auto interim_response =
      RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
          true, attributes, attributes_values);
  EXPECT_CALL(response_cb,
              Call(1, false, matchPacket(std::move(interim_response))))
      .Times(1);

  auto request = RegisterNotificationRequestBuilder::MakeBuilder(
      Event::PLAYER_APPLICATION_SETTING_CHANGED, 0);
  auto pkt = TestAvrcpPacket::Make();
  request->Serialize(pkt);
  SendMessage(1, pkt);

  // Test the changed response for player settings changed
  auto changed_response =
      RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
          false, attributes, attributes_values);
  EXPECT_CALL(response_cb,
              Call(1, false, matchPacket(std::move(changed_response))))
      .Times(1);

  test_device->HandlePlayerSettingChanged(attributes, attributes_values);
}

TEST_F(AvrcpDeviceTest, playerSettingsChangedNotSupportedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);

  auto response = RejectBuilder::MakeBuilder(CommandPdu::REGISTER_NOTIFICATION,
                                             Status::INVALID_COMMAND);
  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(response))))
      .Times(1);

  auto request = RegisterNotificationRequestBuilder::MakeBuilder(
      Event::PLAYER_APPLICATION_SETTING_CHANGED, 0);
  auto pkt = TestAvrcpPacket::Make();
  request->Serialize(pkt);
  SendMessage(1, pkt);
}

TEST_F(AvrcpDeviceTest, playStatusTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;
@@ -1532,9 +1593,10 @@ TEST_F(AvrcpDeviceTest, mediaKeyInactiveDeviceTest) {
TEST_F(AvrcpDeviceTest, getCapabilitiesTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;
  MockPlayerSettingsInterface player_settings_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);
                                  &player_settings_interface);

  // GetCapabilities with CapabilityID COMPANY_ID
  auto request_company_id_response =
@@ -1580,6 +1642,55 @@ TEST_F(AvrcpDeviceTest, getCapabilitiesTest) {
  SendMessage(3, request_unknown);
}

TEST_F(AvrcpDeviceTest, getCapabilitiesPlayerSettingsNotSupportedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);

  // GetCapabilities with CapabilityID COMPANY_ID
  auto request_company_id_response =
      GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x001958);
  request_company_id_response->AddCompanyId(0x002345);
  EXPECT_CALL(
      response_cb,
      Call(1, false, matchPacket(std::move(request_company_id_response))))
      .Times(1);

  auto request_company_id =
      TestAvrcpPacket::Make(get_capabilities_request_company_id);
  SendMessage(1, request_company_id);

  // GetCapabilities with CapabilityID EVENTS_SUPPORTED
  auto request_events_supported_response =
      GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder(
          Event::PLAYBACK_STATUS_CHANGED);
  request_events_supported_response->AddEvent(Event::TRACK_CHANGED);
  request_events_supported_response->AddEvent(Event::PLAYBACK_POS_CHANGED);

  EXPECT_CALL(
      response_cb,
      Call(2, false, matchPacket(std::move(request_events_supported_response))))
      .Times(1);

  auto request_events_supported =
      TestAvrcpPacket::Make(get_capabilities_request);
  SendMessage(2, request_events_supported);

  // GetCapabilities with CapabilityID UNKNOWN
  auto request_unknown_response = RejectBuilder::MakeBuilder(
      CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER);

  EXPECT_CALL(response_cb,
              Call(3, false, matchPacket(std::move(request_unknown_response))))
      .Times(1);

  auto request_unknown =
      TestAvrcpPacket::Make(get_capabilities_request_unknown);
  SendMessage(3, request_unknown);
}

TEST_F(AvrcpDeviceTest, getInvalidItemAttributesTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;
@@ -1647,6 +1758,25 @@ TEST_F(AvrcpDeviceTest, listPlayerSettingsTest) {
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest, listPlayerSettingsNotSupportedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);

  auto response = RejectBuilder::MakeBuilder(
      CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES,
      Status::INVALID_COMMAND);

  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(response))))
      .Times(1);

  auto request =
      TestAvrcpPacket::Make(list_player_application_setting_attributes_request);
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest, listPlayerSettingValuesTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;
@@ -1679,6 +1809,25 @@ TEST_F(AvrcpDeviceTest, listPlayerSettingValuesTest) {
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest, listPlayerSettingValuesNotSupportedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);

  auto response = RejectBuilder::MakeBuilder(
      CommandPdu::LIST_PLAYER_APPLICATION_SETTING_VALUES,
      Status::INVALID_COMMAND);

  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(response))))
      .Times(1);

  auto request = TestAvrcpPacket::Make(
      list_player_application_setting_attribute_values_request);
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest, invalidSettingListPlayerSettingValuesTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;
@@ -1749,6 +1898,26 @@ TEST_F(AvrcpDeviceTest, getCurrentPlayerApplicationSettingValueTest) {
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest,
       getCurrentPlayerApplicationSettingValueNotSupportedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);

  auto response = RejectBuilder::MakeBuilder(
      CommandPdu::GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE,
      Status::INVALID_COMMAND);

  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(response))))
      .Times(1);

  auto request = TestAvrcpPacket::Make(
      get_current_player_application_setting_value_request);
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest,
       invalidSettingGetCurrentPlayerApplicationSettingValueTest) {
  MockMediaInterface interface;
@@ -1819,6 +1988,25 @@ TEST_F(AvrcpDeviceTest, setPlayerApplicationSettingValueTest) {
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest, setPlayerApplicationSettingValueNotSupportedTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;

  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr,
                                  nullptr);

  auto response = RejectBuilder::MakeBuilder(
      CommandPdu::SET_PLAYER_APPLICATION_SETTING_VALUE,
      Status::INVALID_COMMAND);

  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(response))))
      .Times(1);

  auto request =
      TestAvrcpPacket::Make(set_player_application_setting_value_request);
  SendMessage(1, request);
}

TEST_F(AvrcpDeviceTest, invalidSettingSetPlayerApplicationSettingValueTest) {
  MockMediaInterface interface;
  NiceMock<MockA2dpInterface> a2dp_interface;