Offload HAL Service: Utilities

Provides the implementation of utilities to convert between
HIDL format of data types used in Offload HAL service and the format
used by CHRE. Added unit tests to verify conversions.

Bug: 32842314
Test: VTS and Unit tests
Change-Id: I042c49d5f62310c305b557e0f3cdee7ab376d5d8
diff --git a/wifi_offload/Android.bp b/wifi_offload/Android.bp
index 8f466e5..9f6fe4e 100644
--- a/wifi_offload/Android.bp
+++ b/wifi_offload/Android.bp
@@ -22,6 +22,7 @@
         "offload_server.cpp",
         "chre_interface_factory.cpp",
         "offload_status_util.cpp",
+        "offload_utils.cpp",
     ],
     cflags: ["-Wall", "-Wextra"],
     shared_libs: [
@@ -33,7 +34,8 @@
         "android.hardware.wifi.offload@1.0",
     ],
     whole_static_libs: [
-        "chre_client"
+        "chre_client",
+        "wifi_offload_nanoapp",
     ]
 }
 
@@ -68,6 +70,9 @@
         "test/mock_chre_interface.cpp",
         "test/offload_server_test.cpp",
         "test/chre_interface_test.cpp",
+        "test/offload_utils_test.cpp",
+        "test/offload_hal_test_constants.cpp",
+        "test/offload_hal_test_utils.cpp",
     ],
     local_include_dirs: [
         "test",
@@ -87,5 +92,8 @@
         "libgtest",
         "android.hardware.wifi.offload@1.0-lib",
     ],
+    whole_static_libs: [
+        "wifi_offload_nanoapp",
+    ],
 }
 
diff --git a/wifi_offload/offload_utils.cpp b/wifi_offload/offload_utils.cpp
new file mode 100644
index 0000000..90d4b9a
--- /dev/null
+++ b/wifi_offload/offload_utils.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016, 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 "offload_utils.h"
+
+#include <android-base/logging.h>
+#include <chre/apps/wifi_offload/error_codes.h>
+
+namespace {
+
+bool ToHidlRecordName(const wifi_offload::RpcLogRecord::RpcLogRecordType& chreRecordType,
+                      android::hardware::wifi::offload::V1_0::RecordName* hidlRecordName) {
+    bool result = true;
+    switch (chreRecordType) {
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_INIT:
+            *hidlRecordName = android::hardware::wifi::offload::V1_0::RecordName::CMD_INT;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_CONFIG_SCANS:
+            *hidlRecordName = android::hardware::wifi::offload::V1_0::RecordName::CMD_CONFIG_SCANS;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_SUBSCRIBE_SCAN_RESULTS:
+            *hidlRecordName =
+                android::hardware::wifi::offload::V1_0::RecordName::CMD_SUBSCRIBE_SCAN_RESULTS;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_UNSUBSCRIBE_SCAN_RESULTS:
+            *hidlRecordName =
+                android::hardware::wifi::offload::V1_0::RecordName::CMD_UNSUBSCRIBE_SCAN_RESULTS;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_GET_SCAN_STATS:
+            *hidlRecordName =
+                android::hardware::wifi::offload::V1_0::RecordName::CMD_GET_SCAN_STATS;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_RESET:
+            *hidlRecordName = android::hardware::wifi::offload::V1_0::RecordName::CMD_RESET;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_RECVD_SCAN_RESULT_ASYNC:
+            *hidlRecordName =
+                android::hardware::wifi::offload::V1_0::RecordName::EVENT_RECVD_SCAN_RESULT_ASYNC;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_RECVD_SCAN_RESULT:
+            *hidlRecordName =
+                android::hardware::wifi::offload::V1_0::RecordName::EVENT_RECVD_SCAN_RESULT;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_SENT_SCAN_RESULT:
+            *hidlRecordName =
+                android::hardware::wifi::offload::V1_0::RecordName::EVENT_SENT_SCAN_RESULT;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_SENT_ABORT:
+            *hidlRecordName = android::hardware::wifi::offload::V1_0::RecordName::EVENT_SENT_ABORT;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_SENT_ERROR:
+            *hidlRecordName = android::hardware::wifi::offload::V1_0::RecordName::EVENT_SENT_ERROR;
+            break;
+        case wifi_offload::RpcLogRecord::RpcLogRecordType::REQ_SCAN:
+            *hidlRecordName = android::hardware::wifi::offload::V1_0::RecordName::REQ_SCAN;
+            break;
+        default:
+            result = false;
+            break;
+    }
+    return result;
+}
+
+uint8_t ToChreSecurityMode(uint8_t hidlSecurityMode) {
+    uint8_t chreSecurityMode = 0;
+    if (hidlSecurityMode & android::hardware::wifi::offload::V1_0::SecurityMode::OPEN) {
+        chreSecurityMode |= wifi_offload::SecurityMode::OPEN;
+    }
+    if (hidlSecurityMode & android::hardware::wifi::offload::V1_0::SecurityMode::WEP) {
+        chreSecurityMode |= wifi_offload::SecurityMode::WEP;
+    }
+    if (hidlSecurityMode & android::hardware::wifi::offload::V1_0::SecurityMode::PSK) {
+        chreSecurityMode |= wifi_offload::SecurityMode::PSK;
+    }
+    if (hidlSecurityMode & android::hardware::wifi::offload::V1_0::SecurityMode::EAP) {
+        chreSecurityMode |= wifi_offload::SecurityMode::EAP;
+    }
+    return chreSecurityMode;
+}
+
+uint8_t ToHidlSecurityMode(uint8_t chreSecurityMode) {
+    uint8_t hidlSecurityMode = 0;
+    if (chreSecurityMode & wifi_offload::SecurityMode::OPEN) {
+        hidlSecurityMode |= android::hardware::wifi::offload::V1_0::SecurityMode::OPEN;
+    }
+    if (chreSecurityMode & wifi_offload::SecurityMode::WEP) {
+        hidlSecurityMode |= android::hardware::wifi::offload::V1_0::SecurityMode::WEP;
+    }
+    if (chreSecurityMode & wifi_offload::SecurityMode::PSK) {
+        hidlSecurityMode |= android::hardware::wifi::offload::V1_0::SecurityMode::PSK;
+    }
+    if (chreSecurityMode & wifi_offload::SecurityMode::EAP) {
+        hidlSecurityMode |= android::hardware::wifi::offload::V1_0::SecurityMode::EAP;
+    }
+    return hidlSecurityMode;
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+namespace offload_utils {
+
+bool ToHidlScanResult(const wifi_offload::ScanResult& chreScanResult, ScanResult* hidlScanResult) {
+    if (hidlScanResult == nullptr) {
+        return false;
+    }
+    hidlScanResult->tsf = chreScanResult.tsf_;
+    hidlScanResult->capability = chreScanResult.capability_;
+    hidlScanResult->rssi = chreScanResult.rssi_dbm_;
+    hidlScanResult->frequency = chreScanResult.frequency_scanned_mhz_;
+    memcpy(&hidlScanResult->bssid[0], &chreScanResult.bssid_[0],
+           wifi_offload::ScanResult::kBssidSize);
+    chreWifiSsidListItem chreWifiSsid;
+    chreScanResult.ssid_.ToChreWifiSsidListItem(&chreWifiSsid);
+    std::vector<uint8_t> ssid;
+    for (size_t i = 0; i < chreWifiSsid.ssidLen; i++) {
+        ssid.push_back(chreWifiSsid.ssid[i]);
+    }
+    hidlScanResult->networkInfo.ssid = ssid;
+    hidlScanResult->networkInfo.flags = ToHidlSecurityMode(chreScanResult.security_modes_);
+    return true;
+}
+
+bool ToHidlScanResults(const std::vector<wifi_offload::ScanResult>& chreScanResults,
+                       std::vector<ScanResult>* hidlScanResults) {
+    LOG(VERBOSE) << "ScanResults from CHRE, size=" << chreScanResults.size();
+    for (const auto& scan_result_from_nano_app : chreScanResults) {
+        ScanResult hidl_scan_result;
+        if (!ToHidlScanResult(scan_result_from_nano_app, &hidl_scan_result)) {
+            return false;
+        }
+        hidlScanResults->push_back(hidl_scan_result);
+    }
+    return true;
+}
+
+bool ToHidlScanStats(const wifi_offload::ScanStats& chreScanStats, ScanStats* hidlScanStats) {
+    hidlScanStats->subscriptionDurationMs = chreScanStats.last_subscription_duration_ms_;
+    hidlScanStats->numScansRequestedByWifi = chreScanStats.num_scans_requested_by_nanoapp_;
+    hidlScanStats->numScansServicedByWifi = chreScanStats.num_scans_serviced_by_hardware_;
+    hidlScanStats->numScansServicedbyCache = chreScanStats.num_scans_serviced_by_cache_;
+    std::vector<ScanRecord> hidlScanRecords;
+    for (const auto& chreScanRecord : chreScanStats.scan_records_) {
+        ScanRecord hidlScanRecord;
+        hidlScanRecord.durationMs = chreScanRecord.time_spent_scanning_ms_;
+        hidlScanRecord.numChannelsScanned = chreScanRecord.num_channels_scanned_;
+        hidlScanRecord.numEntriesAggregated = chreScanRecord.num_entries_aggregated_;
+        hidlScanRecords.push_back(hidlScanRecord);
+    }
+    hidlScanStats->scanRecord = hidlScanRecords;
+    std::vector<LogRecord> logRecords;
+    for (const auto& chreLogRecord : chreScanStats.rpc_log_records_) {
+        LogRecord logRecord;
+        if (!ToHidlRecordName(chreLogRecord.record_type_, &logRecord.recordName)) {
+            return false;
+        }
+        logRecord.logTimeMs = chreLogRecord.timestamp_chre_ms_;
+        logRecords.push_back(logRecord);
+    }
+    hidlScanStats->logRecord = logRecords;
+    for (size_t i = 0; i < hidlScanStats->histogramChannelsScanned.elementCount(); i++) {
+        hidlScanStats->histogramChannelsScanned[i] =
+            chreScanStats.channel_histogram_.GetChannelScanCount(i);
+    }
+    return true;
+}
+
+bool ToChreScanConfig(const ScanParam& param, const ScanFilter& filter,
+                      wifi_offload::ScanConfig* scanConfig) {
+    scanConfig->scan_params_.disconnected_mode_scan_interval_ms_ =
+        param.disconnectedModeScanIntervalMs;
+    for (const auto& ssid : param.ssidList) {
+        wifi_offload::Ssid chreSsid;
+        chreSsid.SetData(ssid.data(), ssid.size());
+        scanConfig->scan_params_.ssids_to_scan_.push_back(chreSsid);
+    }
+    for (const auto& freq : param.frequencyList) {
+        scanConfig->scan_params_.frequencies_to_scan_mhz_.push_back(freq);
+    }
+    scanConfig->scan_filter_.min_rssi_threshold_dbm_ = filter.rssiThreshold;
+    for (const auto& nwInfo : filter.preferredNetworkInfoList) {
+        wifi_offload::PreferredNetwork chreNwInfo;
+        chreNwInfo.security_modes_ = ToChreSecurityMode(nwInfo.flags);
+        chreNwInfo.ssid_.SetData(nwInfo.ssid.data(), nwInfo.ssid.size());
+        scanConfig->scan_filter_.networks_to_match_.push_back(std::move(chreNwInfo));
+    }
+    return true;
+}
+
+bool ToHidlErrorMessage(uint32_t errorCode, std::string* errorMessage) {
+    bool reportError = true;
+    switch (errorCode) {
+        case wifi_offload::ErrorCode::FAILED_TO_ALLOCATE_MESSAGE_BUFFER:
+            *errorMessage = "Failed to allocate message buffer";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SERIALIZE_MESSAGE:
+            *errorMessage = "Failed to serialize message";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SEND_MESSAGE:
+            *errorMessage = "Failed to send message";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_DESERIALIZE_SCAN_CONFIG:
+            *errorMessage = "Failed to deserialize scan config";
+            break;
+        case wifi_offload::ErrorCode::INVALID_SUBSCRIBE_MESSAGE_SIZE:
+            *errorMessage = "Invalid subscribe message size";
+            break;
+        case wifi_offload::ErrorCode::SCAN_CONFIG_NOT_INITIALIZED:
+            *errorMessage = "Scan config not initialized";
+            break;
+        case wifi_offload::ErrorCode::UNSPECIFIED_HOST_ENDPOINT:
+            *errorMessage = "Unspecified host end point";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SEND_SCAN_RESULTS:
+            *errorMessage = "Failed to send scan results";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SEND_SCAN_STATS:
+            *errorMessage = "Failed to send scan stats";
+            break;
+        case wifi_offload::ErrorCode::ONDEMAND_SCAN_NOT_SUPPORTED:
+            *errorMessage = "On demand scans not supported";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST:
+            *errorMessage = "Failed to send on demand scan request";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST_ASYNC:
+            *errorMessage = "Failed to send on demand scan request async";
+            break;
+        case wifi_offload::ErrorCode::OUT_OF_ORDER_SCAN_RESULTS:
+            *errorMessage = "Out of order scan results";
+            break;
+        case wifi_offload::ErrorCode::INCOMPLETE_SCAN_RESULTS_BEFORE_SCAN_REQUEST:
+            *errorMessage = "Incomplete scan results before scan request";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_SET_SCAN_TIMER:
+            *errorMessage = "Failed to set scan timer";
+            break;
+        case wifi_offload::ErrorCode::SCAN_MONITORING_NOT_SUPPORTED:
+            *errorMessage = "Scan Monitoring not supported";
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_START_SCAN_MONITORING:
+            *errorMessage = "Failed to start scan monitoring";
+            reportError = false;
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_STOP_SCAN_MONITORING:
+            *errorMessage = "Failed to stop scan monitoring";
+            reportError = false;
+            break;
+        case wifi_offload::ErrorCode::FAILED_TO_CONFIGURE_SCAN_MONITORING_ASYNC:
+            *errorMessage = "Failed to configure scan monitoring async";
+            reportError = false;
+            break;
+        default:
+            *errorMessage = "Invalid error code";
+            reportError = false;
+            break;
+    }
+    return reportError;
+}
+
+}  // namespace offload_utils
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi_offload/offload_utils.h b/wifi_offload/offload_utils.h
new file mode 100644
index 0000000..ef087c9
--- /dev/null
+++ b/wifi_offload/offload_utils.h
@@ -0,0 +1,30 @@
+#ifndef WIFI_OFFLOAD_SERVER_UTILS_H_
+#define WIFI_OFFLOAD_SERVER_UTILS_H_
+
+#include <android/hardware/wifi/offload/1.0/IOffload.h>
+#include <chre/apps/wifi_offload/flatbuffers_serialization.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+namespace offload_utils {
+
+bool ToHidlScanResults(const std::vector<wifi_offload::ScanResult>& chreScanResults,
+                       std::vector<ScanResult>* hidlScanResults);
+bool ToHidlScanStats(const wifi_offload::ScanStats& chreScanStats, ScanStats* hildScanStats);
+bool ToChreScanConfig(const ScanParam& param, const ScanFilter& filter,
+                      wifi_offload::ScanConfig* scanConfig);
+bool ToHidlErrorMessage(uint32_t errorCode, std::string* errorMessage);
+
+}  //  namespace offload_utils
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_OFFLOAD_SERVER_UTILS_H_
diff --git a/wifi_offload/test/offload_hal_test_constants.cpp b/wifi_offload/test/offload_hal_test_constants.cpp
new file mode 100644
index 0000000..805090d
--- /dev/null
+++ b/wifi_offload/test/offload_hal_test_constants.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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 "offload_hal_test_constants.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+namespace offload_hal_test_constants {
+
+const uint8_t kSsid1[] = {'G', 'o', 'o', 'g', 'l', 'e'};
+const size_t kSsid1_size = sizeof(kSsid1);
+const uint8_t kSsid2[] = {'X', 'f', 'i', 'n', 'i', 't', 'y'};
+const size_t kSsid2_size = sizeof(kSsid2);
+const uint8_t kBssid[6] = {0x12, 0xef, 0xa1, 0x2c, 0x97, 0x8b};
+const int16_t kRssi = -60;
+const int16_t kRssiThreshold = -76;
+const uint32_t kFrequency1 = 2412;
+const uint32_t kFrequency2 = 2437;
+const uint8_t kBssidSize = 6;
+const uint64_t kTsf = 0;
+const uint16_t kCapability = 0;
+const uint8_t kNetworkFlags = 0;
+const uint32_t kDisconnectedModeScanIntervalMs = 5000;
+const uint64_t kSubscriptionDurationMs = 10000;
+const uint64_t kScanDurationMs[2] = {2000, 500};
+const uint32_t kNumChannelsScanned[] = {1, 2};
+const uint8_t kChannelNotScanned = 0;
+const uint32_t kDefaultNumScansRequestedByWifi = 2;
+const uint32_t kDefaultNumScansServicedByWifi = 2;
+const uint64_t kScanDurationTotalMs = 2000;
+const uint32_t kNumChannelsTotalScanned = 3;
+const uint32_t kNumChannelsInHistogram = 256;
+const uint8_t kTestChannels[] = {1, 6, 11};
+const uint32_t kNumTimesChannelScanned[] = {1, 1, 255};
+const uint32_t kSystemStartTime = 32164;
+const uint32_t kIncrementBetweenEvents = 10;
+const size_t kRecordLength = 8;
+const size_t kInvalidRecordLength = 4;
+
+const wifi_offload::RpcLogRecord::RpcLogRecordType kChreRecordTypeList[] = {
+    wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_INIT,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_CONFIG_SCANS,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_SUBSCRIBE_SCAN_RESULTS,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::REQ_SCAN,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_RECVD_SCAN_RESULT,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_SENT_SCAN_RESULT,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_UNSUBSCRIBE_SCAN_RESULTS,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_GET_SCAN_STATS,
+};
+
+const wifi_offload::RpcLogRecord::RpcLogRecordType kInvalidChreRecordTypeLog[] = {
+    wifi_offload::RpcLogRecord::RpcLogRecordType::CMD_LAST_ITEM,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::REQ_LAST_ITEM,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_RECVD_LAST_ITEM,
+    wifi_offload::RpcLogRecord::RpcLogRecordType::EVENT_SENT_LAST_ITEM,
+};
+
+const android::hardware::wifi::offload::V1_0::RecordName kHidlRecordNameList[] = {
+    android::hardware::wifi::offload::V1_0::RecordName::CMD_INT,
+    android::hardware::wifi::offload::V1_0::RecordName::CMD_CONFIG_SCANS,
+    android::hardware::wifi::offload::V1_0::RecordName::CMD_SUBSCRIBE_SCAN_RESULTS,
+    android::hardware::wifi::offload::V1_0::RecordName::REQ_SCAN,
+    android::hardware::wifi::offload::V1_0::RecordName::EVENT_RECVD_SCAN_RESULT,
+    android::hardware::wifi::offload::V1_0::RecordName::EVENT_SENT_SCAN_RESULT,
+    android::hardware::wifi::offload::V1_0::RecordName::CMD_UNSUBSCRIBE_SCAN_RESULTS,
+    android::hardware::wifi::offload::V1_0::RecordName::CMD_GET_SCAN_STATS,
+};
+
+}  // namespace offload_hal_test_constants
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi_offload/test/offload_hal_test_constants.h b/wifi_offload/test/offload_hal_test_constants.h
new file mode 100644
index 0000000..195e0e8
--- /dev/null
+++ b/wifi_offload/test/offload_hal_test_constants.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef OFFLOAD_HAL_TEST_CONSTANTS_
+#define OFFLOAD_HAL_TEST_CONSTANTS_
+
+#include <cstdint>
+
+#include "offload_utils.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+namespace offload_hal_test_constants {
+
+extern const uint8_t kSsid1[];
+extern const size_t kSsid1_size;
+extern const uint8_t kSsid2[];
+extern const size_t kSsid2_size;
+extern const uint8_t kBssid[6];
+extern const int16_t kRssi;
+extern const int16_t kRssiThreshold;
+extern const uint32_t kFrequency1;
+extern const uint32_t kFrequency2;
+extern const uint8_t kBssidSize;
+extern const uint64_t kTsf;
+extern const uint16_t kCapability;
+extern const uint8_t kNetworkFlags;
+extern const uint32_t kDisconnectedModeScanIntervalMs;
+extern const uint64_t kSubscriptionDurationMs;
+extern const uint64_t kScanDurationMs[2];
+extern const uint32_t kNumChannelsScanned[];
+extern const uint8_t kChannelNotScanned;
+extern const uint32_t kDefaultNumScansRequestedByWifi;
+extern const uint32_t kDefaultNumScansServicedByWifi;
+extern const uint64_t kScanDurationTotalMs;
+extern const uint32_t kNumChannelsTotalScanned;
+extern const uint32_t kNumChannelsInHistogram;
+extern const uint64_t kDeathCode;
+extern const uint8_t kTestChannels[];
+extern const uint32_t kNumTimesChannelScanned[];
+extern const uint32_t kSystemStartTime;
+extern const uint32_t kIncrementBetweenEvents;
+extern const size_t kRecordLength;
+extern const size_t kInvalidRecordLength;
+extern const wifi_offload::RpcLogRecord::RpcLogRecordType kChreRecordTypeList[];
+extern const wifi_offload::RpcLogRecord::RpcLogRecordType kInvalidChreRecordTypeLog[];
+extern const android::hardware::wifi::offload::V1_0::RecordName kHidlRecordNameList[];
+
+}  // namespace offload_hal_test_constants
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // OFFLOAD_HAL_TEST_CONSTANTS_
diff --git a/wifi_offload/test/offload_hal_test_utils.cpp b/wifi_offload/test/offload_hal_test_utils.cpp
new file mode 100644
index 0000000..b58ce40
--- /dev/null
+++ b/wifi_offload/test/offload_hal_test_utils.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2017 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 "offload_hal_test_utils.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+namespace offload_hal_test_utils {
+
+using namespace offload_hal_test_constants;
+
+void createChreScanResultsForTest(std::vector<wifi_offload::ScanResult>* chreScanResults) {
+    wifi_offload::ScanResult chreScanResult;
+    chreScanResult.security_modes_ = kNetworkFlags;
+    chreScanResult.capability_ = kCapability;
+    chreScanResult.frequency_scanned_mhz_ = kFrequency1;
+    chreScanResult.rssi_dbm_ = kRssi;
+    chreScanResult.tsf_ = kTsf;
+    chreScanResult.ssid_.SetData(&kSsid1[0], kSsid1_size);
+    memcpy(&chreScanResult.bssid_[0], &kBssid[0], kBssidSize);
+    chreScanResults->push_back(chreScanResult);
+}
+
+void createChreScanStatsForTest(wifi_offload::ScanStats* chreScanStats) {
+    chreScanStats->num_scans_requested_by_nanoapp_ = kDefaultNumScansRequestedByWifi;
+    chreScanStats->num_scans_serviced_by_hardware_ = kDefaultNumScansServicedByWifi;
+    chreScanStats->num_scans_serviced_by_cache_ =
+        (kDefaultNumScansRequestedByWifi - kDefaultNumScansServicedByWifi);
+    for (size_t j = 0; j < kNumChannelsScanned[0] + kNumChannelsScanned[1]; j++) {
+        chreScanStats->channel_histogram_.IncrementScanCountForChannelForTest(
+            kTestChannels[j], static_cast<uint32_t>(kNumTimesChannelScanned[j]));
+    }
+    chreScanStats->last_subscription_duration_ms_ = kSubscriptionDurationMs;
+    wifi_offload::ScanRecord scanRecord1;
+    scanRecord1.time_spent_scanning_ms_ = kScanDurationMs[0];
+    scanRecord1.num_channels_scanned_ = kNumChannelsScanned[0];
+    scanRecord1.num_entries_aggregated_ = 1;
+    chreScanStats->scan_records_.push_back(scanRecord1);
+    wifi_offload::ScanRecord scanRecord2;
+    scanRecord2.time_spent_scanning_ms_ = kScanDurationMs[1];
+    scanRecord2.num_channels_scanned_ = kNumChannelsScanned[1];
+    scanRecord2.num_entries_aggregated_ = 1;
+    chreScanStats->scan_records_.push_back(scanRecord2);
+
+    for (size_t i = 0; i < kRecordLength; i++) {
+        wifi_offload::RpcLogRecord logRecord;
+        logRecord.record_type_ = kChreRecordTypeList[i];
+        logRecord.timestamp_chre_ms_ = kSystemStartTime + i * kIncrementBetweenEvents;
+        chreScanStats->rpc_log_records_.push_back(logRecord);
+    }
+}
+
+void createHidlScanFilterForTest(ScanFilter* scanFilter) {
+    std::vector<NetworkInfo> nw_info_list;
+    NetworkInfo nwInfo1;
+    std::vector<uint8_t> ssid1(kSsid1, kSsid1 + kSsid1_size);
+    nwInfo1.ssid = ssid1;
+    nwInfo1.flags = kNetworkFlags;
+    NetworkInfo nwInfo2;
+    std::vector<uint8_t> ssid2(kSsid2, kSsid2 + kSsid2_size);
+    nwInfo2.ssid = ssid2;
+    nwInfo2.flags = kNetworkFlags;
+    nw_info_list.push_back(nwInfo1);
+    nw_info_list.push_back(nwInfo2);
+    scanFilter->preferredNetworkInfoList = nw_info_list;
+    scanFilter->rssiThreshold = kRssiThreshold;
+}
+
+void createHidlScanParamForTest(ScanParam* scanParam) {
+    scanParam->disconnectedModeScanIntervalMs = kDisconnectedModeScanIntervalMs;
+    std::vector<uint32_t> frequencyList{kFrequency1, kFrequency2};
+    scanParam->frequencyList = frequencyList;
+    std::vector<hidl_vec<uint8_t>> ssidList;
+    std::vector<uint8_t> ssid1(kSsid1, kSsid1 + kSsid1_size);
+    std::vector<uint8_t> ssid2(kSsid2, kSsid2 + kSsid2_size);
+    ssidList.push_back(ssid1);
+    ssidList.push_back(ssid2);
+    scanParam->ssidList = ssidList;
+}
+
+void createChreScanConfigForTest(wifi_offload::ScanConfig* scanConfig) {
+    scanConfig->scan_params_.disconnected_mode_scan_interval_ms_ = kDisconnectedModeScanIntervalMs;
+    wifi_offload::Ssid chreSsid1;
+    chreSsid1.SetData(&kSsid1[0], kSsid1_size);
+    wifi_offload::Ssid chreSsid2;
+    chreSsid2.SetData(&kSsid2[0], kSsid2_size);
+    scanConfig->scan_params_.ssids_to_scan_.push_back(chreSsid1);
+    scanConfig->scan_params_.ssids_to_scan_.push_back(chreSsid2);
+    scanConfig->scan_params_.frequencies_to_scan_mhz_.push_back(kFrequency1);
+    scanConfig->scan_params_.frequencies_to_scan_mhz_.push_back(kFrequency2);
+    scanConfig->scan_filter_.min_rssi_threshold_dbm_ = kRssiThreshold;
+    wifi_offload::PreferredNetwork chreNwInfo1;
+    chreNwInfo1.security_modes_ = kNetworkFlags;
+    chreNwInfo1.ssid_.SetData(&kSsid1[0], kSsid1_size);
+    scanConfig->scan_filter_.networks_to_match_.push_back(std::move(chreNwInfo1));
+    wifi_offload::PreferredNetwork chreNwInfo2;
+    chreNwInfo2.security_modes_ = kNetworkFlags;
+    chreNwInfo2.ssid_.SetData(&kSsid2[0], kSsid2_size);
+    scanConfig->scan_filter_.networks_to_match_.push_back(std::move(chreNwInfo2));
+}
+
+bool validateScanResult(const std::vector<ScanResult>& hidlScanResultsTest,
+                        const std::vector<wifi_offload::ScanResult> chreScanResults) {
+    if (hidlScanResultsTest.size() != chreScanResults.size())
+        return false;
+    uint32_t i = 0;
+    for (const auto& hidlScanResult : hidlScanResultsTest) {
+        if (hidlScanResult.tsf != chreScanResults[i].tsf_)
+            return false;
+        if (hidlScanResult.rssi != chreScanResults[i].rssi_dbm_)
+            return false;
+        if (hidlScanResult.capability != chreScanResults[i].capability_)
+            return false;
+        if (hidlScanResult.frequency != chreScanResults[i].frequency_scanned_mhz_)
+            return false;
+        for (int j = 0; j < kBssidSize; j++) {
+            if (hidlScanResult.bssid[j] != chreScanResults[i].bssid_[j])
+                return false;
+        }
+        chreWifiSsidListItem chreWifiSsid;
+        chreScanResults[i].ssid_.ToChreWifiSsidListItem(&chreWifiSsid);
+        for (size_t k = 0; k < chreWifiSsid.ssidLen; k++) {
+            if (hidlScanResult.networkInfo.ssid[k] != chreWifiSsid.ssid[k])
+                return false;
+        }
+        if (hidlScanResult.networkInfo.flags != kNetworkFlags) {
+            return false;
+        }
+        i++;
+    }
+    return true;
+}
+
+bool validateScanStats(const ScanStats& hidlScanStats,
+                       const wifi_offload::ScanStats& chreScanStats) {
+    if (hidlScanStats.subscriptionDurationMs != chreScanStats.last_subscription_duration_ms_)
+        return false;
+    if (hidlScanStats.numScansRequestedByWifi != chreScanStats.num_scans_requested_by_nanoapp_)
+        return false;
+    if (hidlScanStats.numScansServicedByWifi != chreScanStats.num_scans_serviced_by_hardware_)
+        return false;
+    if (hidlScanStats.numScansServicedbyCache != chreScanStats.num_scans_serviced_by_cache_)
+        return false;
+    for (uint32_t i = 0; i < kNumChannelsInHistogram; i++) {
+        if (hidlScanStats.histogramChannelsScanned[i] !=
+            chreScanStats.channel_histogram_.GetChannelScanCount(i)) {
+            return false;
+        }
+    }
+    if (hidlScanStats.scanRecord.size() != chreScanStats.scan_records_.size())
+        return false;
+    uint32_t i = 0;
+    for (const auto& scanRecord : hidlScanStats.scanRecord) {
+        if (scanRecord.durationMs != chreScanStats.scan_records_[i].time_spent_scanning_ms_)
+            return false;
+        if (scanRecord.numChannelsScanned != chreScanStats.scan_records_[i].num_channels_scanned_)
+            return false;
+        if (scanRecord.numEntriesAggregated !=
+            chreScanStats.scan_records_[i].num_entries_aggregated_)
+            return false;
+        i++;
+    }
+    if (hidlScanStats.logRecord.size() != chreScanStats.rpc_log_records_.size())
+        return false;
+    i = 0;
+
+    for (const auto& logRecord : hidlScanStats.logRecord) {
+        if (logRecord.recordName != kHidlRecordNameList[i]) {
+            return false;
+        }
+        if (logRecord.logTimeMs != chreScanStats.rpc_log_records_[i].timestamp_chre_ms_)
+            return false;
+        i++;
+    }
+    return true;
+}
+
+}  // namespace offload_hal_test_utils
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi_offload/test/offload_hal_test_utils.h b/wifi_offload/test/offload_hal_test_utils.h
new file mode 100644
index 0000000..ba82a1c
--- /dev/null
+++ b/wifi_offload/test/offload_hal_test_utils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef OFFLOAD_HAL_TEST_UTILS_
+#define OFFLOAD_HAL_TEST_UTILS_
+
+#include "offload_hal_test_constants.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+namespace offload_hal_test_utils {
+
+void createChreScanResultsForTest(std::vector<wifi_offload::ScanResult>* chreScanResults);
+void createChreScanStatsForTest(wifi_offload::ScanStats* chreScanStats);
+void createHidlScanFilterForTest(ScanFilter* scanFilter);
+void createHidlScanParamForTest(ScanParam* scanParam);
+void createChreScanConfigForTest(wifi_offload::ScanConfig* scanConfig);
+bool validateScanResult(const std::vector<ScanResult>& hidlScanResultsTest,
+                        const std::vector<wifi_offload::ScanResult> chreScanResults);
+bool validateScanStats(const ScanStats& hidlScanStats,
+                       const wifi_offload::ScanStats& chreScanStats);
+}  // namespace offload_hal_test_utils
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // OFFLOAD_HAL_TEST_UTILS_
diff --git a/wifi_offload/test/offload_utils_test.cpp b/wifi_offload/test/offload_utils_test.cpp
new file mode 100644
index 0000000..7c2e4d5
--- /dev/null
+++ b/wifi_offload/test/offload_utils_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016, 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 <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include "offload_hal_test_utils.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace offload {
+namespace V1_0 {
+namespace implementation {
+
+using namespace offload_hal_test_constants;
+
+class OffloadUtilsTest : public ::testing::Test {
+  protected:
+    virtual void SetUp() {
+    }
+
+    void TearDown() override {
+    }
+};
+
+TEST_F(OffloadUtilsTest, ConvertScanResultToHidlTest) {
+    std::vector<ScanResult> hidlScanResultsTest;
+    std::vector<wifi_offload::ScanResult> chreScanResultsTest;
+    offload_hal_test_utils::createChreScanResultsForTest(&chreScanResultsTest);
+    EXPECT_TRUE(offload_utils::ToHidlScanResults(chreScanResultsTest, &hidlScanResultsTest));
+    EXPECT_TRUE(
+        offload_hal_test_utils::validateScanResult(hidlScanResultsTest, chreScanResultsTest));
+}
+
+TEST_F(OffloadUtilsTest, ConvertScanStatsToHidlTest) {
+    ScanStats hidlScanStatsTest;
+    wifi_offload::ScanStats chreScanStatsTest;
+    offload_hal_test_utils::createChreScanStatsForTest(&chreScanStatsTest);
+    EXPECT_TRUE(offload_utils::ToHidlScanStats(chreScanStatsTest, &hidlScanStatsTest));
+    EXPECT_TRUE(offload_hal_test_utils::validateScanStats(hidlScanStatsTest, chreScanStatsTest));
+}
+
+TEST_F(OffloadUtilsTest, ConvertScanConfigToChreTest) {
+    wifi_offload::ScanConfig scanConfigTest;
+    wifi_offload::ScanConfig scanConfig;
+    ScanParam scanParamTest;
+    ScanFilter scanFilterTest;
+    offload_hal_test_utils::createHidlScanParamForTest(&scanParamTest);
+    offload_hal_test_utils::createHidlScanFilterForTest(&scanFilterTest);
+    offload_hal_test_utils::createChreScanConfigForTest(&scanConfig);
+    EXPECT_TRUE(offload_utils::ToChreScanConfig(scanParamTest, scanFilterTest, &scanConfigTest));
+    EXPECT_TRUE(scanConfig == scanConfigTest);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace offload
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android