From c3b14ee2681c1020de9708eff0f7fcaca792ec11 Mon Sep 17 00:00:00 2001
From: Ajay Panicker <apanicke@google.com>
Date: Mon, 2 Apr 2018 18:21:04 -0700
Subject: [PATCH] Persist VFS ID's between directory changes.

Some carkits don't honor the fact that VFS ID's only are consistent to
the folder they are currently browsing. Now a UID will remain valid
until the connection ends.

Bug: 68812037
Test: Run net_test_avrcp
Change-Id: I67898277327b54eaeca2121b9ff173b22bd4ba71
---
 system/packet/avrcp/change_path.cc            | 24 +++++++++++
 system/packet/avrcp/change_path.h             | 24 +++++++++++
 system/packet/avrcp/get_folder_items.cc       | 40 +++++++++++++++++++
 system/packet/avrcp/get_folder_items.h        | 28 +++++++++++++
 .../packet/tests/avrcp/avrcp_test_packets.h   | 22 +++++++++-
 .../tests/avrcp/change_path_packet_test.cc    |  9 +++++
 .../avrcp/get_folder_items_packet_test.cc     | 20 ++++++++++
 system/profile/avrcp/device.cc                |  4 --
 system/profile/avrcp/media_id_map.h           |  4 ++
 .../profile/avrcp/tests/avrcp_device_test.cc  | 36 ++++++++++++-----
 10 files changed, 196 insertions(+), 15 deletions(-)

diff --git a/system/packet/avrcp/change_path.cc b/system/packet/avrcp/change_path.cc
index 94bd237e8bd..3c69903bf42 100644
--- a/system/packet/avrcp/change_path.cc
+++ b/system/packet/avrcp/change_path.cc
@@ -84,5 +84,29 @@ std::string ChangePathRequest::ToString() const {
   return ss.str();
 }
 
+std::unique_ptr<ChangePathRequestBuilder> ChangePathRequestBuilder::MakeBuilder(
+    uint16_t uid_counter, Direction direction, uint64_t folder_uid) {
+  std::unique_ptr<ChangePathRequestBuilder> builder(
+      new ChangePathRequestBuilder(uid_counter, direction, folder_uid));
+
+  return builder;
+}
+
+size_t ChangePathRequestBuilder::size() const {
+  return ChangePathRequest::kMinSize();
+}
+
+bool ChangePathRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets2(pkt, base::ByteSwap(uid_counter_));
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(direction_));
+  AddPayloadOctets8(pkt, base::ByteSwap(folder_uid_));
+  return true;
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/system/packet/avrcp/change_path.h b/system/packet/avrcp/change_path.h
index 12fae7ed9d2..a033aa8271d 100644
--- a/system/packet/avrcp/change_path.h
+++ b/system/packet/avrcp/change_path.h
@@ -69,5 +69,29 @@ class ChangePathRequest : public BrowsePacket {
   using BrowsePacket::BrowsePacket;
 };
 
+class ChangePathRequestBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~ChangePathRequestBuilder() = default;
+
+  static std::unique_ptr<ChangePathRequestBuilder> MakeBuilder(
+      uint16_t uid_counter, Direction direction, uint64_t folder_uid);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ private:
+  ChangePathRequestBuilder(uint16_t uid_counter, Direction direction,
+                           uint64_t folder_uid)
+      : BrowsePacketBuilder(BrowsePdu::CHANGE_PATH),
+        uid_counter_(uid_counter),
+        direction_(direction),
+        folder_uid_(folder_uid){};
+
+  uint16_t uid_counter_;
+  Direction direction_;
+  uint64_t folder_uid_;
+};
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/system/packet/avrcp/get_folder_items.cc b/system/packet/avrcp/get_folder_items.cc
index 319960bbd1c..c95bb4a9c2a 100644
--- a/system/packet/avrcp/get_folder_items.cc
+++ b/system/packet/avrcp/get_folder_items.cc
@@ -301,5 +301,45 @@ std::string GetFolderItemsRequest::ToString() const {
   return ss.str();
 }
 
+std::unique_ptr<GetFolderItemsRequestBuilder>
+GetFolderItemsRequestBuilder::MakeBuilder(
+    Scope scope, uint32_t start_item, uint32_t end_item,
+    const std::set<Attribute>& requested_attrs) {
+  std::unique_ptr<GetFolderItemsRequestBuilder> builder(
+      new GetFolderItemsRequestBuilder(scope, start_item, end_item,
+                                       requested_attrs));
+
+  return builder;
+}
+
+size_t GetFolderItemsRequestBuilder::size() const {
+  size_t len = GetFolderItemsRequest::kMinSize();
+  len += requested_attrs_.size() * sizeof(Attribute);
+  return len;
+}
+
+bool GetFolderItemsRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(scope_));
+  AddPayloadOctets4(pkt, base::ByteSwap(start_item_));
+  AddPayloadOctets4(pkt, base::ByteSwap(end_item_));
+
+  if (requested_attrs_.size() == 0) {
+    // 0xFF is the value to signify that there are no attributes requested.
+    AddPayloadOctets1(pkt, 0xFF);
+    return true;
+  }
+
+  AddPayloadOctets1(pkt, requested_attrs_.size());
+  for (const auto& attr : requested_attrs_) {
+    AddPayloadOctets4(pkt, base::ByteSwap(static_cast<uint32_t>(attr)));
+  }
+  return true;
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/system/packet/avrcp/get_folder_items.h b/system/packet/avrcp/get_folder_items.h
index 454a3cee56d..f5291afd9ae 100644
--- a/system/packet/avrcp/get_folder_items.h
+++ b/system/packet/avrcp/get_folder_items.h
@@ -97,5 +97,33 @@ class GetFolderItemsRequest : public BrowsePacket {
   using BrowsePacket::BrowsePacket;
 };
 
+class GetFolderItemsRequestBuilder : public BrowsePacketBuilder {
+ public:
+  virtual ~GetFolderItemsRequestBuilder() = default;
+
+  static std::unique_ptr<GetFolderItemsRequestBuilder> MakeBuilder(
+      Scope scope, uint32_t start_item, uint32_t end_item,
+      const std::set<Attribute>& requested_attrs);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  GetFolderItemsRequestBuilder(Scope scope, uint32_t start_item,
+                               uint32_t end_item,
+                               const std::set<Attribute>& requested_attrs)
+      : BrowsePacketBuilder(BrowsePdu::GET_FOLDER_ITEMS),
+        scope_(scope),
+        start_item_(start_item),
+        end_item_(end_item),
+        requested_attrs_(requested_attrs){};
+
+  Scope scope_;
+  uint32_t start_item_;
+  uint32_t end_item_;
+  std::set<Attribute> requested_attrs_;
+};
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/system/packet/tests/avrcp/avrcp_test_packets.h b/system/packet/tests/avrcp/avrcp_test_packets.h
index 9f179c3ec02..cd07de375c1 100644
--- a/system/packet/tests/avrcp/avrcp_test_packets.h
+++ b/system/packet/tests/avrcp/avrcp_test_packets.h
@@ -147,11 +147,31 @@ std::vector<uint8_t> reject_player_app_settings_response = {
 //    scope = 0x00 (Media Player List)
 //    start_item = 0x00
 //    end_item = 0x03
-//    attributes_requested: none
+//    attributes_requested: all
 std::vector<uint8_t> get_folder_items_request = {0x71, 0x00, 0x0a, 0x00, 0x00,
                                                  0x00, 0x00, 0x00, 0x00, 0x00,
                                                  0x00, 0x03, 0x00};
 
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+//    scope = 0x01 (VFS)
+//    start_item = 0x00
+//    end_item = 0x09
+//    attributes_requested: none
+std::vector<uint8_t> get_folder_items_request_no_attrs = {
+    0x71, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x09, 0xff};
+
+// AVRCP Browse Get Folder Items Request packet for media players with
+// the following data:
+//    scope = 0x01 (VFS)
+//    start_item = 0x00
+//    end_item = 0x09
+//    attributes_requested: Title
+std::vector<uint8_t> get_folder_items_request_title = {
+    0x71, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x1};
+
 // AVRCP Browse Get Folder Items Request packet for vfs with
 // the following data:
 //    scope = 0x01 (VFS)
diff --git a/system/packet/tests/avrcp/change_path_packet_test.cc b/system/packet/tests/avrcp/change_path_packet_test.cc
index 1638c282452..b14d57768ee 100644
--- a/system/packet/tests/avrcp/change_path_packet_test.cc
+++ b/system/packet/tests/avrcp/change_path_packet_test.cc
@@ -72,5 +72,14 @@ TEST(ChangePathRequestTest, invalidTest) {
   ASSERT_FALSE(test_packet->IsValid());
 }
 
+TEST(ChangePathRequestBuilder, builderTest) {
+  auto builder = ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 2);
+  ASSERT_EQ(builder->size(), change_path_request.size());
+
+  auto test_packet = TestChangePathReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), change_path_request);
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/system/packet/tests/avrcp/get_folder_items_packet_test.cc b/system/packet/tests/avrcp/get_folder_items_packet_test.cc
index cf97a611008..ec2d7334572 100644
--- a/system/packet/tests/avrcp/get_folder_items_packet_test.cc
+++ b/system/packet/tests/avrcp/get_folder_items_packet_test.cc
@@ -222,5 +222,25 @@ TEST(GetFolderItemsRequestTest, getterTest) {
   ASSERT_EQ(test_packet->GetAttributesRequested(), attribute_list);
 }
 
+TEST(GetFolderItemsRequestBuilderTest, builderZeroAttrsTest) {
+  auto builder =
+      GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 9, {});
+  ASSERT_EQ(builder->size(), get_folder_items_request_no_attrs.size());
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_request_no_attrs);
+}
+
+TEST(GetFolderItemsRequestBuilderTest, builderTest) {
+  auto builder = GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 9,
+                                                           {Attribute::TITLE});
+  ASSERT_EQ(builder->size(), get_folder_items_request_title.size());
+
+  auto test_packet = TestGetFolderItemsReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), get_folder_items_request_title);
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/system/profile/avrcp/device.cc b/system/profile/avrcp/device.cc
index 34e8d212e23..734dc241246 100644
--- a/system/profile/avrcp/device.cc
+++ b/system/profile/avrcp/device.cc
@@ -633,9 +633,6 @@ void Device::HandleChangePath(uint8_t label,
                    << "\"";
   }
 
-  // All of the VFS ID's are no longer valid
-  vfs_ids_.clear();
-
   media_interface_->GetFolderItems(
       curr_browsed_player_id_, CurrentFolder(),
       base::Bind(&Device::ChangePathResponse, base::Unretained(this), label,
@@ -838,7 +835,6 @@ void Device::GetVFSListResponse(uint8_t label,
 
   // TODO (apanicke): Add test that checks if vfs_ids_ is the correct size after
   // an operation.
-  vfs_ids_.clear();
   for (const auto& item : items) {
     if (item.type == ListItem::FOLDER) {
       vfs_ids_.insert(item.folder.media_id);
diff --git a/system/profile/avrcp/media_id_map.h b/system/profile/avrcp/media_id_map.h
index df5a545181e..f282f20d35a 100644
--- a/system/profile/avrcp/media_id_map.h
+++ b/system/profile/avrcp/media_id_map.h
@@ -44,6 +44,10 @@ class MediaIdMap {
   }
 
   uint64_t insert(std::string media_id) {
+    if (media_id_to_uid_.find(media_id) != media_id_to_uid_.end()) {
+      return media_id_to_uid_[media_id];
+    }
+
     uint64_t uid = media_id_to_uid_.size() + 1;
     media_id_to_uid_.insert(std::pair<std::string, uint64_t>(media_id, uid));
     uid_to_media_id_.insert(std::pair<uint64_t, std::string>(uid, media_id));
diff --git a/system/profile/avrcp/tests/avrcp_device_test.cc b/system/profile/avrcp/tests/avrcp_device_test.cc
index bcdcac2878f..e9dde53b077 100644
--- a/system/profile/avrcp/tests/avrcp_device_test.cc
+++ b/system/profile/avrcp/tests/avrcp_device_test.cc
@@ -498,7 +498,7 @@ TEST_F(AvrcpDeviceTest, changePathTest) {
       .Times(1)
       .WillOnce(InvokeCb<2>(list2));
 
-  // Populate the VFS ID map since we don't persist UIDs
+  // Populate the VFS ID map
   auto folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder(
       Status::NO_ERROR, 0x0000, 0xFFFF);
   folder_items_response->AddFolder(FolderItem(1, 0, true, "Test Folder0"));
@@ -506,7 +506,11 @@ TEST_F(AvrcpDeviceTest, changePathTest) {
   EXPECT_CALL(response_cb,
               Call(1, true, matchPacket(std::move(folder_items_response))))
       .Times(1);
-  auto request = TestBrowsePacket::Make(get_folder_items_request_vfs);
+
+  auto folder_request_builder =
+      GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {});
+  auto request = TestBrowsePacket::Make();
+  folder_request_builder->Serialize(request);
   SendBrowseMessage(1, request);
 
   // Change path down into Test Folder1
@@ -514,19 +518,25 @@ TEST_F(AvrcpDeviceTest, changePathTest) {
       ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size());
   EXPECT_CALL(response_cb,
               Call(2, true, matchPacket(std::move(change_path_response))));
-  request = TestBrowsePacket::Make(change_path_request);
+  auto path_request_builder =
+      ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 2);
+  request = TestBrowsePacket::Make();
+  path_request_builder->Serialize(request);
   SendBrowseMessage(2, request);
 
-  // Populate the VFS ID map since we don't persist UIDs
+  // Populate the new VFS ID
   folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder(
       Status::NO_ERROR, 0x0000, 0xFFFF);
-  folder_items_response->AddFolder(FolderItem(1, 0, true, "Test Folder2"));
-  folder_items_response->AddFolder(FolderItem(2, 0, true, "Test Folder3"));
-  folder_items_response->AddFolder(FolderItem(3, 0, true, "Test Folder4"));
+  folder_items_response->AddFolder(FolderItem(3, 0, true, "Test Folder2"));
+  folder_items_response->AddFolder(FolderItem(4, 0, true, "Test Folder3"));
+  folder_items_response->AddFolder(FolderItem(5, 0, true, "Test Folder4"));
   EXPECT_CALL(response_cb,
               Call(3, true, matchPacket(std::move(folder_items_response))))
       .Times(1);
-  request = TestBrowsePacket::Make(get_folder_items_request_vfs);
+  folder_request_builder =
+      GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {});
+  request = TestBrowsePacket::Make();
+  folder_request_builder->Serialize(request);
   SendBrowseMessage(3, request);
 
   // Change path down into Test Folder3
@@ -534,7 +544,10 @@ TEST_F(AvrcpDeviceTest, changePathTest) {
       ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list2.size());
   EXPECT_CALL(response_cb,
               Call(4, true, matchPacket(std::move(change_path_response))));
-  request = TestBrowsePacket::Make(change_path_request);
+  path_request_builder =
+      ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 4);
+  request = TestBrowsePacket::Make();
+  path_request_builder->Serialize(request);
   SendBrowseMessage(4, request);
 
   // Change path up back into Test Folder1
@@ -542,7 +555,10 @@ TEST_F(AvrcpDeviceTest, changePathTest) {
       ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size());
   EXPECT_CALL(response_cb,
               Call(5, true, matchPacket(std::move(change_path_response))));
-  request = TestBrowsePacket::Make(change_path_up_request);
+  path_request_builder =
+      ChangePathRequestBuilder::MakeBuilder(0, Direction::UP, 0);
+  request = TestBrowsePacket::Make();
+  path_request_builder->Serialize(request);
   SendBrowseMessage(5, request);
 }
 
-- 
GitLab