diff --git a/system/main/Android.bp b/system/main/Android.bp
index 0586310c63e341e4fbe0204d0fb3ac6ca463a516..68586303bd5201c2d28eba40ab6d01e956785fcb 100644
--- a/system/main/Android.bp
+++ b/system/main/Android.bp
@@ -189,6 +189,7 @@ cc_test {
         "shim/metrics_api.cc",
         "shim/shim.cc",
         "shim/stack.cc",
+        "shim/utils.cc",
         "test/common_stack_test.cc",
         "test/main_shim_dumpsys_test.cc",
         "test/main_shim_test.cc",
diff --git a/system/main/shim/Android.bp b/system/main/shim/Android.bp
index 173ed49c39cd956e4b001a19e20438f7bf294781..bf9a9ab060e2cb616b71a3e4af308b1133ad0434 100644
--- a/system/main/shim/Android.bp
+++ b/system/main/shim/Android.bp
@@ -29,5 +29,6 @@ filegroup {
         "metrics_api.cc",
         "shim.cc",
         "stack.cc",
+        "utils.cc",
     ],
 }
diff --git a/system/main/shim/BUILD.gn b/system/main/shim/BUILD.gn
index 727609e1ca3227ea0c73db6b39e6c9254d01d0bf..2bd11d78fa0d4ea186d4acc701788d3c18b023ed 100644
--- a/system/main/shim/BUILD.gn
+++ b/system/main/shim/BUILD.gn
@@ -35,6 +35,7 @@ source_set("LibBluetoothShimSources") {
     "metrics_api.cc",
     "shim.cc",
     "stack.cc",
+    "utils.cc",
   ]
 
   include_dirs = [
diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc
index 9e00416e5f8c3f47ef00ca93f11c0979b09605ec..cdaa636a06b160c9d362c19c008d5bea83b4107b 100644
--- a/system/main/shim/le_advertising_manager.cc
+++ b/system/main/shim/le_advertising_manager.cc
@@ -17,6 +17,7 @@
 #define LOG_TAG "bt_shim_advertiser"
 
 #include "le_advertising_manager.h"
+#include "utils.h"
 
 #include <base/logging.h>
 #include <hardware/bluetooth.h>
@@ -45,6 +46,7 @@ using bluetooth::hci::AdvertiserAddressType;
 using bluetooth::hci::ErrorCode;
 using bluetooth::hci::GapData;
 using bluetooth::hci::OwnAddressType;
+using bluetooth::shim::parse_gap_data;
 using std::vector;
 
 namespace {
@@ -100,23 +102,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface,
   void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
                StatusCallback cb) override {
     LOG(INFO) << __func__ << " in shim layer";
-
-    size_t offset = 0;
     std::vector<GapData> advertising_data = {};
-
-    while (offset < data.size()) {
-      GapData gap_data;
-      uint8_t len = data[offset];
-      auto begin = data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      advertising_data.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
+    parse_gap_data(data, advertising_data);
     bluetooth::shim::GetAdvertising()->SetData(advertiser_id, set_scan_rsp,
                                                advertising_data);
   }
@@ -140,33 +127,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface,
     bluetooth::hci::AdvertisingConfig config{};
     parse_parameter(config, params);
 
-    size_t offset = 0;
-    while (offset < advertise_data.size()) {
-      GapData gap_data;
-      uint8_t len = advertise_data[offset];
-      auto begin = advertise_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.advertisement.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
-    offset = 0;
-    while (offset < scan_response_data.size()) {
-      GapData gap_data;
-      uint8_t len = scan_response_data[offset];
-      auto begin = scan_response_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.scan_response.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
+    parse_gap_data(advertise_data, config.advertisement);
+    parse_gap_data(scan_response_data, config.scan_response);
 
     bluetooth::shim::GetAdvertising()->StartAdvertising(
         advertiser_id, config, timeout_s * 100, cb, timeout_cb, scan_callback,
@@ -188,47 +150,9 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface,
     parse_periodic_advertising_parameter(config.periodic_advertising_parameters,
                                          periodic_params);
 
-    size_t offset = 0;
-    while (offset < advertise_data.size()) {
-      GapData gap_data;
-      uint8_t len = advertise_data[offset];
-      auto begin = advertise_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.advertisement.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
-    offset = 0;
-    while (offset < scan_response_data.size()) {
-      GapData gap_data;
-      uint8_t len = scan_response_data[offset];
-      auto begin = scan_response_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.scan_response.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
-    offset = 0;
-    while (offset < periodic_data.size()) {
-      GapData gap_data;
-      uint8_t len = periodic_data[offset];
-      auto begin = periodic_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.periodic_data.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
+    parse_gap_data(advertise_data, config.advertisement);
+    parse_gap_data(scan_response_data, config.scan_response);
+    parse_gap_data(periodic_data, config.periodic_data);
 
     bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser(
         reg_id, config, scan_callback, set_terminated_callback, duration,
@@ -257,23 +181,8 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface,
   void SetPeriodicAdvertisingData(int advertiser_id, std::vector<uint8_t> data,
                                   StatusCallback cb) override {
     LOG(INFO) << __func__ << " in shim layer";
-
-    size_t offset = 0;
     std::vector<GapData> advertising_data = {};
-
-    while (offset < data.size()) {
-      GapData gap_data;
-      uint8_t len = data[offset];
-      auto begin = data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      advertising_data.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
+    parse_gap_data(data, advertising_data);
     bluetooth::shim::GetAdvertising()->SetPeriodicData(advertiser_id,
                                                        advertising_data);
   }
diff --git a/system/main/shim/utils.cc b/system/main/shim/utils.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dcf1725beb1f4e4f249f8aa576d2c5fa3e500744
--- /dev/null
+++ b/system/main/shim/utils.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 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 "utils.h"
+
+namespace bluetooth {
+namespace shim {
+void parse_gap_data(const std::vector<uint8_t> &raw_data,
+                    std::vector<hci::GapData> &output) {
+    size_t offset = 0;
+    while (offset < raw_data.size()) {
+      hci::GapData gap_data;
+      uint8_t len = raw_data[offset];
+
+      auto begin = raw_data.begin() + offset;
+      auto end = begin + len + 1;  // 1 byte for len
+      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
+      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
+          data_copy);
+      hci::GapData::Parse(&gap_data, packet.begin());
+      output.push_back(gap_data);
+      offset += len + 1;  // 1 byte for len
+    }
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/system/main/shim/utils.h b/system/main/shim/utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..56da2a0a0ae42740642addd02ed2f2abf935b56e
--- /dev/null
+++ b/system/main/shim/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 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 <vector>
+
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace shim {
+/**
+ * @brief Parsing gap data from raw bytes
+ *
+ * @param raw_data input, raw bytes
+ * @param output vector of GapData
+ */
+void parse_gap_data(const std::vector<uint8_t> &raw_data,
+                    std::vector<hci::GapData> &output);
+}  // namespace shim
+}  // namespace bluetooth