1 /*
2 * Copyright (C) 2025 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
17 #define FAILURE_DEBUG_PREFIX "RadioConfig"
18
19 #include <aidl/android/hardware/radio/sim/CardStatus.h>
20
21 #include "RadioConfig.h"
22
23 #include "atCmds.h"
24 #include "debug.h"
25 #include "makeRadioResponseInfo.h"
26
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace radio {
31 namespace implementation {
32 constexpr int8_t kLogicalModemId = 0;
33
RadioConfig(std::shared_ptr<AtChannel> atChannel)34 RadioConfig::RadioConfig(std::shared_ptr<AtChannel> atChannel) : mAtChannel(std::move(atChannel)) {
35 }
36
getHalDeviceCapabilities(const int32_t serial)37 ScopedAStatus RadioConfig::getHalDeviceCapabilities(const int32_t serial) {
38 NOT_NULL(mRadioConfigResponse)->getHalDeviceCapabilitiesResponse(
39 makeRadioResponseInfo(serial), false);
40 return ScopedAStatus::ok();
41 }
42
getNumOfLiveModems(const int32_t serial)43 ScopedAStatus RadioConfig::getNumOfLiveModems(const int32_t serial) {
44 NOT_NULL(mRadioConfigResponse)->getNumOfLiveModemsResponse(
45 makeRadioResponseInfo(serial), 1);
46 return ScopedAStatus::ok();
47 }
48
getPhoneCapability(const int32_t serial)49 ScopedAStatus RadioConfig::getPhoneCapability(const int32_t serial) {
50 config::PhoneCapability capability = {
51 .maxActiveData = 1,
52 .maxActiveInternetData = 1,
53 .isInternetLingeringSupported = false,
54 .logicalModemIds = { kLogicalModemId },
55 .maxActiveVoice = 1,
56 };
57 NOT_NULL(mRadioConfigResponse)->getPhoneCapabilityResponse(
58 makeRadioResponseInfo(serial), std::move(capability));
59 return ScopedAStatus::ok();
60 }
61
getSimultaneousCallingSupport(const int32_t serial)62 ScopedAStatus RadioConfig::getSimultaneousCallingSupport(const int32_t serial) {
63 NOT_NULL(mRadioConfigResponse)->getSimultaneousCallingSupportResponse(
64 makeRadioResponseInfoNOP(serial), {});
65 return ScopedAStatus::ok();
66 }
67
getSimSlotsStatus(const int32_t serial)68 ScopedAStatus RadioConfig::getSimSlotsStatus(const int32_t serial) {
69 static const char* const kFunc = __func__;
70 mAtChannel->queueRequester([this, serial](const AtChannel::RequestPipe requestPipe) -> bool {
71 using config::SimSlotStatus;
72 using config::SimPortInfo;
73 using CmeError = AtResponse::CmeError;
74 using CPIN = AtResponse::CPIN;
75
76 SimSlotStatus simSlotStatus;
77
78 AtResponsePtr response =
79 mAtConversation(requestPipe, atCmds::getSimCardStatus,
80 [](const AtResponse& response) -> bool {
81 return response.holds<CPIN>() || response.holds<CmeError>();
82 });
83 if (!response || response->isParseError()) {
84 failed: NOT_NULL(mRadioConfigResponse)->getSimSlotsStatusResponse(
85 makeRadioResponseInfo(serial, FAILURE(RadioError::INTERNAL_ERR)), {});
86 return false;
87 } else if (const CPIN* cpin = response->get_if<CPIN>()) {
88 switch (cpin->state) {
89 case CPIN::State::READY:
90 simSlotStatus.cardState = sim::CardStatus::STATE_PRESENT;
91 simSlotStatus.atr = ""; // TODO 3BF000818000
92 simSlotStatus.eid = ""; // TODO
93 break;
94
95 case CPIN::State::PIN:
96 case CPIN::State::PUK:
97 simSlotStatus.cardState = sim::CardStatus::STATE_RESTRICTED;
98 break;
99
100 default:
101 goto failed;
102 }
103 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
104 switch (cmeError->error) {
105 case RadioError::SIM_ABSENT:
106 simSlotStatus.cardState = sim::CardStatus::STATE_ABSENT;
107 break;
108 case RadioError::SIM_BUSY:
109 case RadioError::SIM_ERR:
110 simSlotStatus.cardState = sim::CardStatus::STATE_ERROR;
111 break;
112
113 default:
114 RLOGE("%s:%s:%s:%d unexpected error: '%s'",
115 FAILURE_DEBUG_PREFIX, kFunc, "CPIN", __LINE__,
116 toString(cmeError->error).c_str());
117 goto failed;
118 }
119 } else {
120 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
121 }
122
123 if (simSlotStatus.cardState != sim::CardStatus::STATE_ABSENT) {
124 SimPortInfo simPortInfo = {
125 .logicalSlotId = 0,
126 .portActive = true,
127 };
128
129 response =
130 mAtConversation(requestPipe, atCmds::getICCID,
131 [](const AtResponse& response) -> bool {
132 return response.holds<std::string>();
133 });
134 if (!response || response->isParseError()) {
135 goto failed;
136 } else if (const std::string* iccid = response->get_if<std::string>()) {
137 simPortInfo.iccId = *iccid;
138 } else {
139 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
140 }
141
142 simSlotStatus.portInfo.push_back(std::move(simPortInfo));
143 }
144
145 NOT_NULL(mRadioConfigResponse)->getSimSlotsStatusResponse(
146 makeRadioResponseInfo(serial), { std::move(simSlotStatus) });
147 return true;
148 });
149
150 return ScopedAStatus::ok();
151 }
152
setNumOfLiveModems(const int32_t serial,const int8_t numOfLiveModems)153 ScopedAStatus RadioConfig::setNumOfLiveModems(const int32_t serial,
154 const int8_t numOfLiveModems) {
155 const RadioError result = (numOfLiveModems == 1) ?
156 RadioError::NONE : FAILURE_V(RadioError::INVALID_ARGUMENTS,
157 "numOfLiveModems=%d", numOfLiveModems);
158
159 NOT_NULL(mRadioConfigResponse)->setNumOfLiveModemsResponse(
160 makeRadioResponseInfo(serial, result));
161 return ScopedAStatus::ok();
162 }
163
setPreferredDataModem(const int32_t serial,const int8_t modemId)164 ScopedAStatus RadioConfig::setPreferredDataModem(const int32_t serial,
165 const int8_t modemId) {
166 const RadioError result = (modemId == kLogicalModemId) ?
167 RadioError::NONE : FAILURE_V(RadioError::INVALID_ARGUMENTS,
168 "modemId=%d", modemId);
169
170 NOT_NULL(mRadioConfigResponse)->setPreferredDataModemResponse(
171 makeRadioResponseInfo(serial, result));
172 return ScopedAStatus::ok();
173 }
174
setSimSlotsMapping(const int32_t serial,const std::vector<config::SlotPortMapping> &)175 ScopedAStatus RadioConfig::setSimSlotsMapping(
176 const int32_t serial, const std::vector<config::SlotPortMapping>& /*slotMap*/) {
177 NOT_NULL(mRadioConfigResponse)->setSimSlotsMappingResponse(
178 makeRadioResponseInfoNOP(serial));
179 return ScopedAStatus::ok();
180 }
181
atResponseSink(const AtResponsePtr & response)182 void RadioConfig::atResponseSink(const AtResponsePtr& response) {
183 if (!mAtConversation.send(response)) {
184 response->visit([this](const auto& msg){ handleUnsolicited(msg); });
185 }
186 }
187
setResponseFunctions(const std::shared_ptr<config::IRadioConfigResponse> & radioConfigResponse,const std::shared_ptr<config::IRadioConfigIndication> & radioConfigIndication)188 ScopedAStatus RadioConfig::setResponseFunctions(
189 const std::shared_ptr<config::IRadioConfigResponse>& radioConfigResponse,
190 const std::shared_ptr<config::IRadioConfigIndication>& radioConfigIndication) {
191 mRadioConfigResponse = NOT_NULL(radioConfigResponse);
192 mRadioConfigIndication = NOT_NULL(radioConfigIndication);
193 return ScopedAStatus::ok();
194 }
195
196 } // namespace implementation
197 } // namespace radio
198 } // namespace hardware
199 } // namespace android
200 } // namespace aidl
201