1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define LOG_TAG "RadioTest"
17
18 #include "radio_aidl_hal_utils.h"
19 #include "VtsCoreUtil.h"
20 #include "radio_config_utils.h"
21 #include "radio_sim_utils.h"
22
23 #define WAIT_TIMEOUT_PERIOD 75
24
25 sim::CardStatus cardStatus = {};
26 config::SimSlotStatus slotStatus = {};
27 int serial = 0;
28 int count_ = 0;
29
GetRandomSerialNumber()30 int GetRandomSerialNumber() {
31 return rand();
32 }
33
CheckAnyOfErrors(RadioError err,std::vector<RadioError> errors,CheckFlag flag)34 ::testing::AssertionResult CheckAnyOfErrors(RadioError err, std::vector<RadioError> errors,
35 CheckFlag flag) {
36 const static std::vector<RadioError> generalErrors = {
37 RadioError::RADIO_NOT_AVAILABLE, RadioError::NO_MEMORY,
38 RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR,
39 RadioError::REQUEST_NOT_SUPPORTED, RadioError::CANCELLED};
40 if (flag == CHECK_GENERAL_ERROR || flag == CHECK_OEM_AND_GENERAL_ERROR) {
41 for (size_t i = 0; i < generalErrors.size(); i++) {
42 if (err == generalErrors[i]) {
43 return testing::AssertionSuccess();
44 }
45 }
46 }
47 if (flag == CHECK_OEM_ERROR || flag == CHECK_OEM_AND_GENERAL_ERROR) {
48 if (err >= RadioError::OEM_ERROR_1 && err <= RadioError::OEM_ERROR_25) {
49 return testing::AssertionSuccess();
50 }
51 }
52 for (size_t i = 0; i < errors.size(); i++) {
53 if (err == errors[i]) {
54 return testing::AssertionSuccess();
55 }
56 }
57 return testing::AssertionFailure() << "RadioError:" + toString(err) + " is returned";
58 }
59
60 // Runs "pm list features" and attempts to find the specified feature in its output.
deviceSupportsFeature(const char * feature)61 bool deviceSupportsFeature(const char* feature) {
62 bool hasFeature = false;
63 FILE* p = popen("/system/bin/pm list features", "re");
64 if (p) {
65 char* line = NULL;
66 size_t len = 0;
67 while (getline(&line, &len, p) > 0) {
68 if (strstr(line, feature)) {
69 hasFeature = true;
70 break;
71 }
72 }
73 pclose(p);
74 } else {
75 __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "popen failed: %d", errno);
76 _exit(EXIT_FAILURE);
77 }
78 __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Feature %s: %ssupported", feature,
79 hasFeature ? "" : "not ");
80 return hasFeature;
81 }
82
isSsSsEnabled()83 bool isSsSsEnabled() {
84 // Do not use checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "")
85 // until b/148904287 is fixed. We need exact matching instead of partial matching. (i.e.
86 // by definition the empty string "" is a substring of any string).
87 return !isDsDsEnabled() && !isTsTsEnabled() && !isDsDaEnabled();
88 }
89
isDsDsEnabled()90 bool isDsDsEnabled() {
91 return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsds");
92 }
93
isDsDaEnabled()94 bool isDsDaEnabled() {
95 return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsda");
96 }
97
isTsTsEnabled()98 bool isTsTsEnabled() {
99 return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts");
100 }
101
isVoiceInService(RegState state)102 bool isVoiceInService(RegState state) {
103 return RegState::REG_HOME == state || RegState::REG_ROAMING == state;
104 }
105
isVoiceEmergencyOnly(RegState state)106 bool isVoiceEmergencyOnly(RegState state) {
107 return RegState::NOT_REG_MT_NOT_SEARCHING_OP_EM == state ||
108 RegState::NOT_REG_MT_SEARCHING_OP_EM == state || RegState::REG_DENIED_EM == state ||
109 RegState::UNKNOWN_EM == state;
110 }
111
stringEndsWith(std::string const & string,std::string const & end)112 bool stringEndsWith(std::string const& string, std::string const& end) {
113 if (string.size() >= end.size()) {
114 return std::equal(end.rbegin(), end.rend(), string.rbegin());
115 } else {
116 return false;
117 }
118 }
119
isServiceValidForDeviceConfiguration(std::string & serviceName)120 bool isServiceValidForDeviceConfiguration(std::string& serviceName) {
121 if (isSsSsEnabled()) {
122 // Device is configured as SSSS.
123 if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME)) {
124 ALOGI("%s instance is not valid for SSSS device.", serviceName.c_str());
125 return false;
126 }
127 } else if (isDsDsEnabled() || isDsDaEnabled()) {
128 // Device is configured as DSDS or DSDA.
129 if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME) &&
130 !stringEndsWith(serviceName, RADIO_SERVICE_SLOT2_NAME)) {
131 ALOGI("%s instance is not valid for DSDS device.", serviceName.c_str());
132 return false;
133 }
134 } else if (isTsTsEnabled()) {
135 // Device is configured as TSTS.
136 if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME) &&
137 !stringEndsWith(serviceName, RADIO_SERVICE_SLOT2_NAME) &&
138 !stringEndsWith(serviceName, RADIO_SERVICE_SLOT3_NAME)) {
139 ALOGI("%s instance is not valid for TSTS device.", serviceName.c_str());
140 return false;
141 }
142 }
143 return true;
144 }
145
SetUp()146 void RadioServiceTest::SetUp() {
147 ALOGD("BEGIN %s#%s", ::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name(),
148 ::testing::UnitTest::GetInstance()->current_test_info()->name());
149 count_ = 0;
150 serial = -1;
151 }
152
TearDown()153 void RadioServiceTest::TearDown() {
154 count_ = 0;
155 serial = -1;
156 ALOGD("END %s#%s", ::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name(),
157 ::testing::UnitTest::GetInstance()->current_test_info()->name());
158 }
159
160 /*
161 * Notify that the response message is received.
162 */
notify(int receivedSerial)163 void RadioServiceTest::notify(int receivedSerial) {
164 std::lock_guard<std::mutex> lock(mtx_);
165 if (serial == receivedSerial) {
166 count_++;
167 cv_.notify_one();
168 }
169 }
170
171 /*
172 * Wait till the response message is notified or till WAIT_TIMEOUT_PERIOD.
173 */
wait()174 std::cv_status RadioServiceTest::wait() {
175 std::unique_lock<std::mutex> lock(mtx_);
176 std::cv_status status = std::cv_status::no_timeout;
177 auto now = std::chrono::system_clock::now();
178 while (count_ == 0) {
179 status = cv_.wait_until(lock, now + std::chrono::seconds(WAIT_TIMEOUT_PERIOD));
180 if (status == std::cv_status::timeout) {
181 return status;
182 }
183 }
184 count_--;
185 return status;
186 }
187
188 /**
189 * Specific features on the Radio HAL rely on Radio HAL Capabilities.
190 * The VTS test related to those features must not run if the related capability is disabled.
191 * Typical usage within VTS:
192 * if (getRadioHalCapabilities()) return;
193 */
getRadioHalCapabilities()194 bool RadioServiceTest::getRadioHalCapabilities() {
195 // Get HalDeviceCapabilities from RadioConfig
196 std::shared_ptr<RadioConfigResponse> radioConfigRsp =
197 ndk::SharedRefBase::make<RadioConfigResponse>(*this);
198 std::shared_ptr<RadioConfigIndication> radioConfigInd =
199 ndk::SharedRefBase::make<RadioConfigIndication>(*this);
200 radio_config->setResponseFunctions(radioConfigRsp, radioConfigInd);
201 serial = GetRandomSerialNumber();
202 radio_config->getHalDeviceCapabilities(serial);
203 EXPECT_EQ(std::cv_status::no_timeout, wait());
204 return radioConfigRsp->modemReducedFeatureSet1;
205 }
206
207 /**
208 * Some VTS tests require the SIM card status to be present before running.
209 * Update the SIM card status, which can be accessed via the extern cardStatus.
210 */
updateSimCardStatus()211 void RadioServiceTest::updateSimCardStatus() {
212 // Update CardStatus from RadioSim
213 std::shared_ptr<RadioSimResponse> radioSimRsp =
214 ndk::SharedRefBase::make<RadioSimResponse>(*this);
215 std::shared_ptr<RadioSimIndication> radioSimInd =
216 ndk::SharedRefBase::make<RadioSimIndication>(*this);
217 radio_sim->setResponseFunctions(radioSimRsp, radioSimInd);
218 serial = GetRandomSerialNumber();
219 radio_sim->getIccCardStatus(serial);
220 EXPECT_EQ(std::cv_status::no_timeout, wait());
221 EXPECT_EQ(RadioResponseType::SOLICITED, radioSimRsp->rspInfo.type);
222 EXPECT_EQ(serial, radioSimRsp->rspInfo.serial);
223 EXPECT_EQ(RadioError::NONE, radioSimRsp->rspInfo.error);
224 }
225
updateSimSlotStatus(int physicalSlotId)226 void RadioServiceTest::updateSimSlotStatus(int physicalSlotId) {
227 // Update SimSlotStatus from RadioConfig
228 std::shared_ptr<RadioConfigResponse> radioConfigRsp =
229 ndk::SharedRefBase::make<RadioConfigResponse>(*this);
230 std::shared_ptr<RadioConfigIndication> radioConfigInd =
231 ndk::SharedRefBase::make<RadioConfigIndication>(*this);
232 radio_config->setResponseFunctions(radioConfigRsp, radioConfigInd);
233 serial = GetRandomSerialNumber();
234 radio_config->getSimSlotsStatus(serial);
235 EXPECT_EQ(std::cv_status::no_timeout, wait());
236 EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
237 EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
238 EXPECT_EQ(RadioError::NONE, radioConfigRsp->rspInfo.error);
239 if (radioConfigRsp->simSlotStatus.size() > physicalSlotId) {
240 slotStatus = radioConfigRsp->simSlotStatus[physicalSlotId];
241 }
242 }
243
isLteConnected()244 bool isLteConnected(){
245 return testing::checkSubstringInCommandOutput("getprop gsm.network.type", "LTE");
246 }
247