Merge "Carrier restriction enhancements for Android Q"
diff --git a/power/stats/1.0/default/Android.bp b/power/stats/1.0/default/Android.bp
index 04270c1..b57466d 100644
--- a/power/stats/1.0/default/Android.bp
+++ b/power/stats/1.0/default/Android.bp
@@ -11,7 +11,7 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 
-cc_library_shared {
+cc_binary {
     name: "android.hardware.power.stats@1.0-service",
     relative_install_path: "hw",
     init_rc: ["android.hardware.power.stats@1.0-service.rc"],
diff --git a/power/stats/1.0/default/OWNERS b/power/stats/1.0/default/OWNERS
new file mode 100644
index 0000000..2d95a97
--- /dev/null
+++ b/power/stats/1.0/default/OWNERS
@@ -0,0 +1,3 @@
+krossmo@google.com
+bsschwar@google.com
+tstrudel@google.com
diff --git a/power/stats/1.0/default/PowerStats.cpp b/power/stats/1.0/default/PowerStats.cpp
index 810c575..350aa62 100644
--- a/power/stats/1.0/default/PowerStats.cpp
+++ b/power/stats/1.0/default/PowerStats.cpp
@@ -287,25 +287,218 @@
     return Void();
 }
 
+uint32_t PowerStats::addPowerEntity(const std::string& name, PowerEntityType type) {
+    uint32_t id = mPowerEntityInfos.size();
+    mPowerEntityInfos.push_back({id, name, type});
+    return id;
+}
+
+void PowerStats::addStateResidencyDataProvider(std::shared_ptr<IStateResidencyDataProvider> p) {
+    std::vector<PowerEntityStateSpace> stateSpaces = p->getStateSpaces();
+    for (auto stateSpace : stateSpaces) {
+        mPowerEntityStateSpaces.emplace(stateSpace.powerEntityId, stateSpace);
+        mStateResidencyDataProviders.emplace(stateSpace.powerEntityId, p);
+    }
+}
+
 Return<void> PowerStats::getPowerEntityInfo(getPowerEntityInfo_cb _hidl_cb) {
-    hidl_vec<PowerEntityInfo> eInfo;
-    _hidl_cb(eInfo, Status::NOT_SUPPORTED);
+    // If not configured, return NOT_SUPPORTED
+    if (mPowerEntityInfos.empty()) {
+        _hidl_cb({}, Status::NOT_SUPPORTED);
+        return Void();
+    }
+
+    _hidl_cb(mPowerEntityInfos, Status::SUCCESS);
     return Void();
 }
 
 Return<void> PowerStats::getPowerEntityStateInfo(const hidl_vec<uint32_t>& powerEntityIds,
                                                  getPowerEntityStateInfo_cb _hidl_cb) {
-    (void)powerEntityIds;
-    hidl_vec<PowerEntityStateSpace> powerEntityStateSpaces;
-    _hidl_cb(powerEntityStateSpaces, Status::NOT_SUPPORTED);
+    // If not configured, return NOT_SUPPORTED
+    if (mPowerEntityStateSpaces.empty()) {
+        _hidl_cb({}, Status::NOT_SUPPORTED);
+        return Void();
+    }
+
+    std::vector<PowerEntityStateSpace> stateSpaces;
+
+    // If powerEntityIds is empty then return state space info for all entities
+    if (powerEntityIds.size() == 0) {
+        stateSpaces.reserve(mPowerEntityStateSpaces.size());
+        for (auto i : mPowerEntityStateSpaces) {
+            stateSpaces.emplace_back(i.second);
+        }
+        _hidl_cb(stateSpaces, Status::SUCCESS);
+        return Void();
+    }
+
+    // Return state space information only for valid ids
+    auto ret = Status::SUCCESS;
+    stateSpaces.reserve(powerEntityIds.size());
+    for (const uint32_t id : powerEntityIds) {
+        auto stateSpace = mPowerEntityStateSpaces.find(id);
+        if (stateSpace != mPowerEntityStateSpaces.end()) {
+            stateSpaces.emplace_back(stateSpace->second);
+        } else {
+            ret = Status::INVALID_INPUT;
+        }
+    }
+
+    _hidl_cb(stateSpaces, ret);
     return Void();
 }
 
 Return<void> PowerStats::getPowerEntityStateResidencyData(
-    const hidl_vec<uint32_t>& powerEntityIds, getPowerEntityStateResidencyData_cb _hidl_cb) {
-    (void)powerEntityIds;
+        const hidl_vec<uint32_t>& powerEntityIds, getPowerEntityStateResidencyData_cb _hidl_cb) {
+    // If not configured, return NOT_SUPPORTED
+    if (mStateResidencyDataProviders.empty() || mPowerEntityStateSpaces.empty()) {
+        _hidl_cb({}, Status::NOT_SUPPORTED);
+        return Void();
+    }
+
+    // If powerEntityIds is empty then return data for all supported entities
+    if (powerEntityIds.size() == 0) {
+        std::vector<uint32_t> ids;
+        for (auto stateSpace : mPowerEntityStateSpaces) {
+            ids.emplace_back(stateSpace.first);
+        }
+        return getPowerEntityStateResidencyData(ids, _hidl_cb);
+    }
+
+    std::unordered_map<uint32_t, PowerEntityStateResidencyResult> stateResidencies;
+    std::vector<PowerEntityStateResidencyResult> results;
+    results.reserve(powerEntityIds.size());
+
+    // return results for only the given powerEntityIds
+    bool invalidInput = false;
+    bool filesystemError = false;
+    for (auto id : powerEntityIds) {
+        auto dataProvider = mStateResidencyDataProviders.find(id);
+        // skip if the given powerEntityId does not have an associated StateResidencyDataProvider
+        if (dataProvider == mStateResidencyDataProviders.end()) {
+            invalidInput = true;
+            continue;
+        }
+
+        // get the results if we have not already done so.
+        if (stateResidencies.find(id) == stateResidencies.end()) {
+            if (!dataProvider->second->getResults(stateResidencies)) {
+                filesystemError = true;
+            }
+        }
+
+        // append results
+        auto stateResidency = stateResidencies.find(id);
+        if (stateResidency != stateResidencies.end()) {
+            results.emplace_back(stateResidency->second);
+        }
+    }
+
+    auto ret = Status::SUCCESS;
+    if (filesystemError) {
+        ret = Status::FILESYSTEM_ERROR;
+    } else if (invalidInput) {
+        ret = Status::INVALID_INPUT;
+    }
+
+    _hidl_cb(results, ret);
+    return Void();
+}
+
+bool DumpResidencyDataToFd(const hidl_vec<PowerEntityInfo>& infos,
+                           const hidl_vec<PowerEntityStateSpace>& stateSpaces,
+                           const hidl_vec<PowerEntityStateResidencyResult>& results, int fd) {
+    // construct lookup table of powerEntityId to name
+    std::unordered_map<uint32_t, std::string> entityNames;
+    for (auto info : infos) {
+        entityNames.emplace(info.powerEntityId, info.powerEntityName);
+    }
+
+    // construct lookup table of powerEntityId, powerEntityStateId to state name
+    std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> stateNames;
+    for (auto stateSpace : stateSpaces) {
+        stateNames.emplace(stateSpace.powerEntityId, std::unordered_map<uint32_t, std::string>());
+        for (auto state : stateSpace.states) {
+            stateNames.at(stateSpace.powerEntityId)
+                    .emplace(state.powerEntityStateId, state.powerEntityStateName);
+        }
+    }
+
+    std::ostringstream dumpStats;
+    dumpStats << "\n========== PowerStats HAL 1.0 state residencies ==========\n";
+
+    const char* headerFormat = "  %14s   %14s   %16s   %15s   %16s\n";
+    const char* dataFormat =
+            "  %14s   %14s   %13" PRIu64 " ms   %15" PRIu64 "   %13" PRIu64 " ms\n";
+    dumpStats << android::base::StringPrintf(headerFormat, "Entity", "State", "Total time",
+                                             "Total entries", "Last entry timestamp");
+
+    for (auto result : results) {
+        for (auto stateResidency : result.stateResidencyData) {
+            dumpStats << android::base::StringPrintf(
+                    dataFormat, entityNames.at(result.powerEntityId).c_str(),
+                    stateNames.at(result.powerEntityId)
+                            .at(stateResidency.powerEntityStateId)
+                            .c_str(),
+                    stateResidency.totalTimeInStateMs, stateResidency.totalStateEntryCount,
+                    stateResidency.lastEntryTimestampMs);
+        }
+    }
+
+    dumpStats << "========== End of PowerStats HAL 1.0 state residencies ==========\n";
+
+    return android::base::WriteStringToFd(dumpStats.str(), fd);
+}
+
+Return<void> PowerStats::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+    if (handle == nullptr || handle->numFds < 1) {
+        return Void();
+    }
+
+    int fd = handle->data[0];
+    Status status;
+    hidl_vec<PowerEntityInfo> infos;
+
+    // Get power entity information
+    getPowerEntityInfo([&status, &infos](auto rInfos, auto rStatus) {
+        status = rStatus;
+        infos = rInfos;
+    });
+    if (status != Status::SUCCESS) {
+        LOG(ERROR) << "Error getting power entity info";
+        return Void();
+    }
+
+    // Get power entity state information
+    hidl_vec<PowerEntityStateSpace> stateSpaces;
+    getPowerEntityStateInfo({}, [&status, &stateSpaces](auto rStateSpaces, auto rStatus) {
+        status = rStatus;
+        stateSpaces = rStateSpaces;
+    });
+    if (status != Status::SUCCESS) {
+        LOG(ERROR) << "Error getting state info";
+        return Void();
+    }
+
+    // Get power entity state residency data
     hidl_vec<PowerEntityStateResidencyResult> results;
-    _hidl_cb(results, Status::NOT_SUPPORTED);
+    getPowerEntityStateResidencyData({}, [&status, &results](auto rResults, auto rStatus) {
+        status = rStatus;
+        results = rResults;
+    });
+
+    // This implementation of getPowerEntityStateResidencyData supports the
+    // return of partial results if status == FILESYSTEM_ERROR.
+    if (status != Status::SUCCESS) {
+        LOG(ERROR) << "Error getting residency data -- Some results missing";
+    }
+
+    if (!DumpResidencyDataToFd(infos, stateSpaces, results, fd)) {
+        PLOG(ERROR) << "Failed to dump residency data to fd";
+    }
+
+    fsync(fd);
+
     return Void();
 }
 
diff --git a/power/stats/1.0/default/PowerStats.h b/power/stats/1.0/default/PowerStats.h
index fb2c6a8..d67fb35 100644
--- a/power/stats/1.0/default/PowerStats.h
+++ b/power/stats/1.0/default/PowerStats.h
@@ -21,6 +21,7 @@
 #include <fmq/MessageQueue.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+#include <unordered_map>
 
 namespace android {
 namespace hardware {
@@ -60,8 +61,19 @@
     std::unique_ptr<MessageQueueSync> fmqSynchronized;
 };
 
+class IStateResidencyDataProvider {
+   public:
+    virtual ~IStateResidencyDataProvider() = default;
+    virtual bool getResults(
+            std::unordered_map<uint32_t, PowerEntityStateResidencyResult>& results) = 0;
+    virtual std::vector<PowerEntityStateSpace> getStateSpaces() = 0;
+};
+
 struct PowerStats : public IPowerStats {
+   public:
     PowerStats();
+    uint32_t addPowerEntity(const std::string& name, PowerEntityType type);
+    void addStateResidencyDataProvider(std::shared_ptr<IStateResidencyDataProvider> p);
     // Methods from ::android::hardware::power::stats::V1_0::IPowerStats follow.
     Return<void> getRailInfo(getRailInfo_cb _hidl_cb) override;
     Return<void> getEnergyData(const hidl_vec<uint32_t>& railIndices,
@@ -75,12 +87,19 @@
         const hidl_vec<uint32_t>& powerEntityIds,
         getPowerEntityStateResidencyData_cb _hidl_cb) override;
 
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
    private:
     OnDeviceMmt mPm;
     void findIioPowerMonitorNodes();
     size_t parsePowerRails();
     int parseIioEnergyNode(std::string devName);
     Status parseIioEnergyNodes();
+    std::vector<PowerEntityInfo> mPowerEntityInfos;
+    std::unordered_map<uint32_t, PowerEntityStateSpace> mPowerEntityStateSpaces;
+    std::unordered_map<uint32_t, std::shared_ptr<IStateResidencyDataProvider>>
+            mStateResidencyDataProviders;
 };
 
 }  // namespace implementation
diff --git a/power/stats/1.0/default/service.cpp b/power/stats/1.0/default/service.cpp
index 80649f5..a516536 100644
--- a/power/stats/1.0/default/service.cpp
+++ b/power/stats/1.0/default/service.cpp
@@ -31,17 +31,69 @@
 
 // Generated HIDL files
 using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
+using android::hardware::power::stats::V1_0::PowerEntityType;
+using android::hardware::power::stats::V1_0::implementation::IStateResidencyDataProvider;
 using android::hardware::power::stats::V1_0::implementation::PowerStats;
 
+class DefaultStateResidencyDataProvider : public IStateResidencyDataProvider {
+   public:
+    DefaultStateResidencyDataProvider(uint32_t id)
+        : mPowerEntityId(id), mActiveStateId(0), mSleepStateId(1) {}
+    ~DefaultStateResidencyDataProvider() = default;
+
+    bool getResults(std::unordered_map<uint32_t, PowerEntityStateResidencyResult>& results) {
+        PowerEntityStateResidencyResult result = { .powerEntityId = mPowerEntityId };
+        result.stateResidencyData.resize(2);
+
+        // Using fake numbers here for display only. A real implementation would
+        // use actual tracked stats.
+        result.stateResidencyData[0] = {
+            .powerEntityStateId = mActiveStateId,
+            .totalTimeInStateMs = 1,
+            .totalStateEntryCount = 2,
+            .lastEntryTimestampMs = 3
+        };
+        result.stateResidencyData[1] = {
+            .powerEntityStateId = mSleepStateId,
+            .totalTimeInStateMs = 4,
+            .totalStateEntryCount = 5,
+            .lastEntryTimestampMs = 6,
+        };
+        results.emplace(mPowerEntityId, result);
+        return true;
+    }
+
+    std::vector<PowerEntityStateSpace> getStateSpaces() {
+        return {{
+          .powerEntityId = mPowerEntityId,
+          .states = {
+              {.powerEntityStateId = mActiveStateId, .powerEntityStateName = "Active"},
+              {.powerEntityStateId = mSleepStateId, .powerEntityStateName = "Sleep"}
+          }
+        }};
+    }
+
+   private:
+    const uint32_t mPowerEntityId;
+    const uint32_t mActiveStateId;
+    const uint32_t mSleepStateId;
+};
+
 int main(int /* argc */, char** /* argv */) {
     ALOGI("power.stats service 1.0 is starting.");
 
-    android::sp<IPowerStats> service = new PowerStats();
+    PowerStats* service = new PowerStats();
     if (service == nullptr) {
         ALOGE("Can not create an instance of power.stats HAL Iface, exiting.");
         return 1;
     }
 
+    uint32_t defaultId = service->addPowerEntity("DefaultEntity", PowerEntityType::SUBSYSTEM);
+    auto defaultSdp = std::make_shared<DefaultStateResidencyDataProvider>(defaultId);
+    service->addStateResidencyDataProvider(std::move(defaultSdp));
+
     configureRpcThreadpool(1, true /*callerWillJoin*/);
 
     status_t status = service->registerAsService();
diff --git a/radio/config/1.1/Android.bp b/radio/config/1.1/Android.bp
index 056510c..151a0a3 100644
--- a/radio/config/1.1/Android.bp
+++ b/radio/config/1.1/Android.bp
@@ -7,10 +7,10 @@
         enabled: true,
     },
     srcs: [
+        "types.hal",
         "IRadioConfig.hal",
         "IRadioConfigIndication.hal",
         "IRadioConfigResponse.hal",
-        "types.hal",
     ],
     interfaces: [
         "android.hardware.radio.config@1.0",
@@ -19,6 +19,7 @@
     ],
     types: [
         "ModemInfo",
+        "ModemsConfig",
         "PhoneCapability",
     ],
     gen_java: true,
diff --git a/radio/config/1.1/IRadioConfig.hal b/radio/config/1.1/IRadioConfig.hal
index bc63339..7b0c6b6 100644
--- a/radio/config/1.1/IRadioConfig.hal
+++ b/radio/config/1.1/IRadioConfig.hal
@@ -19,6 +19,7 @@
 import @1.0::IRadioConfig;
 import @1.1::IRadioConfigResponse;
 import @1.1::PhoneCapability;
+import @1.1::ModemsConfig;
 
 /**
  * Note: IRadioConfig 1.1 is an intermediate layer between Android P and Android Q.
@@ -56,4 +57,36 @@
      * Response callback is IRadioConfigResponse.setPreferredDataModemResponse()
      */
     oneway setPreferredDataModem(int32_t serial, uint8_t modemId);
+
+   /**
+     * Set modems configurations by specifying the number of live modems (i.e modems that are
+     * enabled and actively working as part of a working telephony stack).
+     *
+     * Example: this interface can be used to switch to single/multi sim mode by specifying
+     * the number of live modems as 1, 2, etc
+     *
+     * Note: by setting the number of live modems in this API, that number of modems will
+     * subsequently get enabled/disabled
+     *
+     * @param serial serial number of request.
+     * @param modemsConfig ModemsConfig object including the number of live modems
+     *
+     * Response callback is IRadioResponse.setModemsConfigResponse()
+     */
+    oneway setModemsConfig(int32_t serial, ModemsConfig modemsConfig);
+
+   /**
+     * Get modems configurations. This interface is used to get modem configurations
+     * which includes the number of live modems (i.e modems that are
+     * enabled and actively working as part of a working telephony stack)
+     *
+     * Note: in order to get the overall number of modems available on the phone,
+     * refer to getPhoneCapability API
+     *
+     * @param serial Serial number of request.
+     *
+     * Response callback is IRadioResponse.getModemsConfigResponse() which
+     * will return <@1.1::ModemsConfig>.
+     */
+    oneway getModemsConfig(int32_t serial);
 };
diff --git a/radio/config/1.1/IRadioConfigResponse.hal b/radio/config/1.1/IRadioConfigResponse.hal
index 42a31b1..d42ff06 100644
--- a/radio/config/1.1/IRadioConfigResponse.hal
+++ b/radio/config/1.1/IRadioConfigResponse.hal
@@ -19,6 +19,7 @@
 import @1.0::IRadioConfigResponse;
 import @1.1::PhoneCapability;
 import android.hardware.radio@1.0::RadioResponseInfo;
+import @1.1::ModemsConfig;
 
 /**
  * Note: IRadioConfig 1.1 is an intermediate layer between Android P and Android Q.
@@ -50,4 +51,27 @@
      *   RadioError:INVALID_ARGUMENTS
      */
     oneway setPreferredDataModemResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_ARGUMENTS
+     */
+    oneway setModemsConfigResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param modemsConfig <@1.1::ModemsConfig> it defines all the modems' configurations
+     *        at this time, only the number of live modems
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway getModemsConfigResponse(RadioResponseInfo info, ModemsConfig modemsConfig);
 };
diff --git a/radio/config/1.1/types.hal b/radio/config/1.1/types.hal
index a7b9f86..89a4723 100644
--- a/radio/config/1.1/types.hal
+++ b/radio/config/1.1/types.hal
@@ -61,3 +61,11 @@
      */
     vec<ModemInfo> logicalModemList;
 };
+
+struct ModemsConfig {
+    /**
+     * variable to indicate the number of live modems i.e modems that are enabled
+     * and actively working as part of a working connectivity stack
+     */
+    uint8_t numOfLiveModems;
+};
\ No newline at end of file
diff --git a/radio/config/1.1/vts/functional/Android.bp b/radio/config/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..de909a3
--- /dev/null
+++ b/radio/config/1.1/vts/functional/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+    name: "VtsHalRadioConfigV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "radio_config_hidl_hal_api.cpp",
+        "radio_config_hidl_hal_test.cpp",
+        "radio_config_response.cpp",
+        "VtsHalRadioConfigV1_1TargetTest.cpp",
+    ],
+    static_libs: [
+        "RadioVtsTestUtilBase",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+    ],
+    header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests"],
+}
diff --git a/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp b/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp
new file mode 100644
index 0000000..2fc6b62
--- /dev/null
+++ b/radio/config/1.1/vts/functional/VtsHalRadioConfigV1_1TargetTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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 <radio_config_hidl_hal_utils.h>
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(RadioConfigHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    RadioConfigHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp
new file mode 100644
index 0000000..a8e939c
--- /dev/null
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_api.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 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 <radio_config_hidl_hal_utils.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+
+/*
+ * Test IRadioConfig.getModemsConfig()
+ */
+TEST_F(RadioConfigHidlTest, getModemsConfig) {
+    serial = GetRandomSerialNumber();
+    Return<void> res = radioConfig->getModemsConfig(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+    ALOGI("getModemsConfig, rspInfo.error = %s\n", toString(radioConfigRsp->rspInfo.error).c_str());
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioConfigRsp->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
+ * Test IRadioConfig.setModemsConfig()
+ */
+TEST_F(RadioConfigHidlTest, setModemsConfig_invalidArgument) {
+    serial = GetRandomSerialNumber();
+    ModemsConfig* mConfig = new ModemsConfig();
+    Return<void> res = radioConfig->setModemsConfig(serial, *mConfig);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+    ALOGI("setModemsConfig, rspInfo.error = %s\n", toString(radioConfigRsp->rspInfo.error).c_str());
+
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioConfigRsp->rspInfo.error,
+                             {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
+ * Test IRadioConfig.setModemsConfig()
+ */
+TEST_F(RadioConfigHidlTest, setModemsConfig_goodRequest) {
+    serial = GetRandomSerialNumber();
+    ModemsConfig* mConfig = new ModemsConfig();
+    mConfig->numOfLiveModems = 1;
+    Return<void> res = radioConfig->setModemsConfig(serial, *mConfig);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+    ALOGI("setModemsConfig, rspInfo.error = %s\n", toString(radioConfigRsp->rspInfo.error).c_str());
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioConfigRsp->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+}
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp
new file mode 100644
index 0000000..6c1b382
--- /dev/null
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 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 <radio_config_hidl_hal_utils.h>
+
+void RadioConfigHidlTest::SetUp() {
+    radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
+            RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
+                    hidl_string(RADIO_SERVICE_NAME)));
+    if (radioConfig == NULL) {
+        sleep(60);
+        radioConfig = ::testing::VtsHalHidlTargetTestBase::getService<IRadioConfig>(
+                RadioConfigHidlEnvironment::Instance()->getServiceName<IRadioConfig>(
+                        hidl_string(RADIO_SERVICE_NAME)));
+    }
+    ASSERT_NE(nullptr, radioConfig.get());
+
+    radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
+    ASSERT_NE(nullptr, radioConfigRsp.get());
+
+    count_ = 0;
+
+    radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioConfigRsp->rspInfo.error);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioConfigHidlTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioConfigHidlTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
\ No newline at end of file
diff --git a/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
new file mode 100644
index 0000000..592555f
--- /dev/null
+++ b/radio/config/1.1/vts/functional/radio_config_hidl_hal_utils.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 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 <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+#include <android/hardware/radio/config/1.1/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.1/types.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::config::V1_1;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::radio::config::V1_0::SimSlotStatus;
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using ::android::hardware::radio::V1_0::RadioResponseType;
+
+#define TIMEOUT_PERIOD 75
+#define RADIO_SERVICE_NAME "slot1"
+
+class RadioConfigHidlTest;
+
+/* Callback class for radio config response */
+class RadioConfigResponse : public IRadioConfigResponse {
+   protected:
+    RadioConfigHidlTest& parent;
+
+   public:
+    RadioResponseInfo rspInfo;
+
+    RadioConfigResponse(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigResponse() = default;
+
+    Return<void> getSimSlotsStatusResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<SimSlotStatus>& slotStatus);
+
+    Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
+
+    Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+                                            const PhoneCapability& phoneCapability);
+
+    Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
+
+    Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+                                         const ModemsConfig& mConfig);
+
+    Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
+};
+
+// Test environment for Radio HIDL HAL.
+class RadioConfigHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static RadioConfigHidlEnvironment* Instance() {
+        static RadioConfigHidlEnvironment* instance = new RadioConfigHidlEnvironment;
+        return instance;
+    }
+    virtual void registerTestServices() override { registerTestService<IRadioConfig>(); }
+
+   private:
+    RadioConfigHidlEnvironment() {}
+};
+
+// The main test class for Radio config HIDL.
+class RadioConfigHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+   public:
+    virtual void SetUp() override;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    void updateSimCardStatus();
+
+    /* Serial number for radio request */
+    int serial;
+
+    /* radio config service handle */
+    sp<IRadioConfig> radioConfig;
+
+    /* radio config response handle */
+    sp<RadioConfigResponse> radioConfigRsp;
+};
diff --git a/radio/config/1.1/vts/functional/radio_config_response.cpp b/radio/config/1.1/vts/functional/radio_config_response.cpp
new file mode 100644
index 0000000..6e41aeb
--- /dev/null
+++ b/radio/config/1.1/vts/functional/radio_config_response.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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 <radio_config_hidl_hal_utils.h>
+
+// SimSlotStatus slotStatus;
+
+RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
+
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& /* info */, const PhoneCapability& /* phoneCapability */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
+                                                          const ModemsConfig& /* mConfig */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
\ No newline at end of file