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 "RadioMessaging"
18
19 #include "RadioMessaging.h"
20
21 #include "atCmds.h"
22 #include "debug.h"
23 #include "makeRadioResponseInfo.h"
24
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace radio {
29 namespace implementation {
30 namespace {
31 using messaging::GsmBroadcastSmsConfigInfo;
32
33 using namespace std::literals;
34 constexpr std::string_view kCtrlZ = "\032"sv;
35 } // namespace
36
RadioMessaging(std::shared_ptr<AtChannel> atChannel)37 RadioMessaging::RadioMessaging(std::shared_ptr<AtChannel> atChannel) : mAtChannel(std::move(atChannel)) {
38 }
39
acknowledgeIncomingGsmSmsWithPdu(const int32_t serial,const bool,const std::string &)40 ScopedAStatus RadioMessaging::acknowledgeIncomingGsmSmsWithPdu(const int32_t serial,
41 const bool /*success*/,
42 const std::string& /*ackPdu*/) {
43 // unsupported in reference-ril.c
44 NOT_NULL(mRadioMessagingResponse)->acknowledgeIncomingGsmSmsWithPduResponse(
45 makeRadioResponseInfo(serial));
46 return ScopedAStatus::ok();
47 }
48
acknowledgeLastIncomingCdmaSms(const int32_t serial,const messaging::CdmaSmsAck &)49 ScopedAStatus RadioMessaging::acknowledgeLastIncomingCdmaSms(const int32_t serial,
50 const messaging::CdmaSmsAck& /*smsAck*/) {
51 // unsupported in reference-ril.c
52 NOT_NULL(mRadioMessagingResponse)->acknowledgeLastIncomingCdmaSmsResponse(
53 makeRadioResponseInfo(serial));
54 return ScopedAStatus::ok();
55 }
56
acknowledgeLastIncomingGsmSms(const int32_t serial,const bool success,const messaging::SmsAcknowledgeFailCause)57 ScopedAStatus RadioMessaging::acknowledgeLastIncomingGsmSms(const int32_t serial,
58 const bool success,
59 const messaging::SmsAcknowledgeFailCause /*cause*/) {
60 static const char* const kFunc = __func__;
61 mAtChannel->queueRequester([this, serial, success]
62 (const AtChannel::RequestPipe requestPipe) -> bool {
63 RadioError status = RadioError::NONE;
64
65 AtResponsePtr response =
66 mAtConversation(requestPipe, std::format("AT+CNMA={0:d}", (success ? 1 : 2)),
67 [](const AtResponse& response) -> bool {
68 return response.isOK();
69 });
70 if (!response || response->isParseError()) {
71 status = FAILURE(RadioError::INTERNAL_ERR);
72 }
73
74 NOT_NULL(mRadioMessagingResponse)->acknowledgeLastIncomingGsmSmsResponse(
75 makeRadioResponseInfo(serial, status));
76 return status != RadioError::INTERNAL_ERR;
77 });
78
79 return ScopedAStatus::ok();
80 }
81
deleteSmsOnRuim(const int32_t serial,const int32_t)82 ScopedAStatus RadioMessaging::deleteSmsOnRuim(const int32_t serial,
83 const int32_t /*index*/) {
84 NOT_NULL(mRadioMessagingResponse)->deleteSmsOnRuimResponse(
85 makeRadioResponseInfoUnsupported( // matches reference-ril.c
86 serial, FAILURE_DEBUG_PREFIX, __func__));
87 return ScopedAStatus::ok();
88 }
89
deleteSmsOnSim(const int32_t serial,const int32_t index)90 ScopedAStatus RadioMessaging::deleteSmsOnSim(const int32_t serial,
91 const int32_t index) {
92 static const char* const kFunc = __func__;
93 mAtChannel->queueRequester([this, serial, index]
94 (const AtChannel::RequestPipe requestPipe) -> bool {
95 using CmeError = AtResponse::CmeError;
96
97 RadioError status = RadioError::NONE;
98
99 AtResponsePtr response =
100 mAtConversation(requestPipe, std::format("AT+CMGD={0:d}", index),
101 [](const AtResponse& response) -> bool {
102 return response.isOK() ||
103 response.holds<CmeError>();
104 });
105 if (!response || response->isParseError()) {
106 status = FAILURE(RadioError::INTERNAL_ERR);
107 } else if (response->get_if<CmeError>()) {
108 status = FAILURE(RadioError::INVALID_ARGUMENTS);
109 } else if (!response->isOK()) {
110 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
111 }
112
113 NOT_NULL(mRadioMessagingResponse)->deleteSmsOnSimResponse(
114 makeRadioResponseInfo(serial, status));
115 return status != RadioError::INTERNAL_ERR;
116 });
117
118 return ScopedAStatus::ok();
119 }
120
getCdmaBroadcastConfig(const int32_t serial)121 ScopedAStatus RadioMessaging::getCdmaBroadcastConfig(const int32_t serial) {
122 NOT_NULL(mRadioMessagingResponse)->getCdmaBroadcastConfigResponse(
123 makeRadioResponseInfoUnsupported( // matches reference-ril.c
124 serial, FAILURE_DEBUG_PREFIX, __func__), {});
125 return ScopedAStatus::ok();
126 }
127
getGsmBroadcastConfig(const int32_t serial)128 ScopedAStatus RadioMessaging::getGsmBroadcastConfig(const int32_t serial) {
129 static const char* const kFunc = __func__;
130 mAtChannel->queueRequester([this, serial]
131 (const AtChannel::RequestPipe requestPipe) -> bool {
132 using CSCB = AtResponse::CSCB;
133 using messaging::GsmBroadcastSmsConfigInfo;
134
135 RadioError status = RadioError::NONE;
136 std::vector<GsmBroadcastSmsConfigInfo> gbsci;
137
138 AtResponsePtr response =
139 mAtConversation(requestPipe, atCmds::getBroadcastConfig,
140 [](const AtResponse& response) -> bool {
141 return response.holds<CSCB>();
142 });
143 if (!response || response->isParseError()) {
144 status = FAILURE(RadioError::INTERNAL_ERR);
145 } else if (const CSCB* cscb = response->get_if<CSCB>()) {
146 const size_t size = std::min(cscb->serviceId.size(),
147 cscb->codeScheme.size());
148 gbsci.resize(size);
149
150 const bool selected = (cscb->mode != 0);
151
152 for (size_t i = 0; i < size; ++i) {
153 gbsci[i].selected = selected;
154 gbsci[i].fromServiceId = cscb->serviceId[i].from;
155 gbsci[i].toServiceId = cscb->serviceId[i].to;
156 gbsci[i].fromCodeScheme = cscb->codeScheme[i].from;
157 gbsci[i].toCodeScheme = cscb->codeScheme[i].to;
158 }
159 } else {
160 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
161 }
162
163 NOT_NULL(mRadioMessagingResponse)->getGsmBroadcastConfigResponse(
164 makeRadioResponseInfo(serial, status), std::move(gbsci));
165 return status != RadioError::INTERNAL_ERR;
166 });
167
168 return ScopedAStatus::ok();
169 }
170
getSmscAddress(const int32_t serial)171 ScopedAStatus RadioMessaging::getSmscAddress(const int32_t serial) {
172 static const char* const kFunc = __func__;
173 mAtChannel->queueRequester([this, serial](const AtChannel::RequestPipe requestPipe) -> bool {
174 using CSCA = AtResponse::CSCA;
175 RadioError status = RadioError::NONE;
176 std::string smscAddress;
177
178 AtResponsePtr response =
179 mAtConversation(requestPipe, atCmds::getSmscAddress,
180 [](const AtResponse& response) -> bool {
181 return response.holds<CSCA>();
182 });
183 if (!response || response->isParseError()) {
184 NOT_NULL(mRadioMessagingResponse)->getSmscAddressResponse(
185 makeRadioResponseInfo(serial, FAILURE(RadioError::INTERNAL_ERR)),
186 "");
187 return false;
188 } else if (const CSCA* csca = response->get_if<CSCA>()) {
189 smscAddress = csca->sca;
190 } else {
191 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
192 }
193
194 NOT_NULL(mRadioMessagingResponse)->getSmscAddressResponse(
195 makeRadioResponseInfo(serial), std::move(smscAddress));
196 return true;
197 });
198
199 return ScopedAStatus::ok();
200 }
201
reportSmsMemoryStatus(const int32_t serial,const bool)202 ScopedAStatus RadioMessaging::reportSmsMemoryStatus(const int32_t serial,
203 const bool /*available*/) {
204 NOT_NULL(mRadioMessagingResponse)->reportSmsMemoryStatusResponse(
205 makeRadioResponseInfoUnsupported( // matches reference-ril.c
206 serial, FAILURE_DEBUG_PREFIX, __func__));
207 return ScopedAStatus::ok();
208 }
209
sendCdmaSms(const int32_t serial,const messaging::CdmaSmsMessage &)210 ScopedAStatus RadioMessaging::sendCdmaSms(const int32_t serial,
211 const messaging::CdmaSmsMessage& /*sms*/) {
212 NOT_NULL(mRadioMessagingResponse)->sendCdmaSmsResponse(
213 makeRadioResponseInfoUnsupported( // reference-ril.c returns OK but does nothing
214 serial, FAILURE_DEBUG_PREFIX, __func__), {});
215 return ScopedAStatus::ok();
216 }
217
sendCdmaSmsExpectMore(const int32_t serial,const messaging::CdmaSmsMessage &)218 ScopedAStatus RadioMessaging::sendCdmaSmsExpectMore(const int32_t serial,
219 const messaging::CdmaSmsMessage& /*sms*/) {
220 NOT_NULL(mRadioMessagingResponse)->sendCdmaSmsExpectMoreResponse(
221 makeRadioResponseInfoUnsupported( // reference-ril.c returns OK but does nothing
222 serial, FAILURE_DEBUG_PREFIX, __func__), {});
223 return ScopedAStatus::ok();
224 }
225
sendImsSms(const int32_t serial,const messaging::ImsSmsMessage &)226 ScopedAStatus RadioMessaging::sendImsSms(const int32_t serial,
227 const messaging::ImsSmsMessage& /*message*/) {
228 NOT_NULL(mRadioMessagingResponse)->sendImsSmsResponse(
229 makeRadioResponseInfoUnsupported( // <TODO>
230 serial, FAILURE_DEBUG_PREFIX, __func__), {});
231 return ScopedAStatus::ok();
232 }
233
234 std::pair<RadioResponseInfo, messaging::SendSmsResult>
sendSmsImpl(const AtChannel::RequestPipe requestPipe,const int serial,const messaging::GsmSmsMessage & message)235 RadioMessaging::sendSmsImpl(const AtChannel::RequestPipe requestPipe,
236 const int serial,
237 const messaging::GsmSmsMessage &message) {
238 using messaging::SendSmsResult;
239 using SmsPrompt = AtResponse::SmsPrompt;
240 using CMGS = AtResponse::CMGS;
241
242 RadioError status = RadioError::NONE;
243 std::string request = std::format("AT+CMGS={0:d}", message.pdu.size() / 2);
244
245 AtResponsePtr response =
246 mAtConversation(requestPipe, request,
247 [](const AtResponse& response) -> bool {
248 return response.holds<SmsPrompt>();
249 });
250 if (!response || response->isParseError()) {
251 status = FAILURE(RadioError::INTERNAL_ERR);
252 done: return {makeRadioResponseInfo(serial, status), {}};
253 } else if (!response->holds<SmsPrompt>()) {
254 response->unexpected(FAILURE_DEBUG_PREFIX, __func__);
255 }
256
257 SendSmsResult sendSmsResult;
258
259 const std::string_view smsc =
260 message.smscPdu.empty() ? "00"sv : std::string_view(message.smscPdu);
261
262 request = std::format("{0:s}{1:s}{2:s}", smsc, message.pdu, kCtrlZ);
263 response =
264 mAtConversation(requestPipe, request,
265 [](const AtResponse& response) -> bool {
266 return response.holds<CMGS>();
267 });
268 if (!response || response->isParseError()) {
269 status = FAILURE(RadioError::INTERNAL_ERR);
270 goto done;
271 } else if (const CMGS* cmgs = response->get_if<CMGS>()) {
272 sendSmsResult.messageRef = cmgs->messageRef;
273 } else {
274 response->unexpected(FAILURE_DEBUG_PREFIX, __func__);
275 }
276
277 return {makeRadioResponseInfo(serial), std::move(sendSmsResult)};
278 }
279
280
sendSms(const int32_t serial,const messaging::GsmSmsMessage & message)281 ScopedAStatus RadioMessaging::sendSms(
282 const int32_t serial, const messaging::GsmSmsMessage& message) {
283 mAtChannel->queueRequester([this, serial, message]
284 (const AtChannel::RequestPipe requestPipe) -> bool {
285 auto [response, sendSmsResult] = sendSmsImpl(requestPipe, serial, message);
286
287 NOT_NULL(mRadioMessagingResponse)->sendSmsResponse(
288 response, std::move(sendSmsResult));
289
290 return response.error != RadioError::INTERNAL_ERR;
291 });
292
293 return ScopedAStatus::ok();
294 }
295
sendSmsExpectMore(const int32_t serial,const messaging::GsmSmsMessage & message)296 ScopedAStatus RadioMessaging::sendSmsExpectMore(
297 const int32_t serial, const messaging::GsmSmsMessage& message) {
298 mAtChannel->queueRequester([this, serial, message]
299 (const AtChannel::RequestPipe requestPipe) -> bool {
300 auto [response, sendSmsResult] = sendSmsImpl(requestPipe, serial, message);
301
302 NOT_NULL(mRadioMessagingResponse)->sendSmsExpectMoreResponse(
303 response, std::move(sendSmsResult));
304
305 return response.error != RadioError::INTERNAL_ERR;
306 });
307
308 return ScopedAStatus::ok();
309 }
310
setCdmaBroadcastConfig(const int32_t serial,const std::vector<messaging::CdmaBroadcastSmsConfigInfo> &)311 ScopedAStatus RadioMessaging::setCdmaBroadcastConfig(const int32_t serial,
312 const std::vector<messaging::CdmaBroadcastSmsConfigInfo>& /*configInfo*/) {
313 NOT_NULL(mRadioMessagingResponse)->setCdmaBroadcastConfigResponse(
314 makeRadioResponseInfoNOP(serial));
315 return ScopedAStatus::ok();
316 }
317
setCdmaBroadcastActivation(const int32_t serial,const bool)318 ScopedAStatus RadioMessaging::setCdmaBroadcastActivation(const int32_t serial,
319 const bool /*activate*/) {
320 NOT_NULL(mRadioMessagingResponse)->setCdmaBroadcastActivationResponse(
321 makeRadioResponseInfoNOP(serial));
322 return ScopedAStatus::ok();
323 }
324
setGsmBroadcastConfig(int32_t serial,const std::vector<GsmBroadcastSmsConfigInfo> & configInfo)325 ScopedAStatus RadioMessaging::setGsmBroadcastConfig(
326 int32_t serial, const std::vector<GsmBroadcastSmsConfigInfo>& configInfo) {
327 if (configInfo.empty()) {
328 NOT_NULL(mRadioMessagingResponse)->setGsmBroadcastConfigResponse(
329 makeRadioResponseInfo(serial, FAILURE(RadioError::INVALID_ARGUMENTS)));
330 return ScopedAStatus::ok();
331 }
332
333 const int mode = configInfo.front().selected ? 0 : 1;
334 std::string channel;
335 std::string language;
336
337 for (const GsmBroadcastSmsConfigInfo& ci : configInfo) {
338 if (!channel.empty()) {
339 channel += ",";
340 language += ",";
341 }
342
343 if (ci.fromServiceId == ci.toServiceId) {
344 channel += std::to_string(ci.fromServiceId);
345 } else {
346 channel += std::format("{0:d}-{1:d}", ci.fromServiceId,
347 ci.toServiceId);
348 }
349
350 if (ci.fromCodeScheme == ci.toCodeScheme) {
351 language += std::to_string(ci.fromCodeScheme);
352 } else {
353 language += std::format("{0:d}-{1:d}", ci.fromCodeScheme,
354 ci.toCodeScheme);
355 }
356 }
357
358 std::string request = std::format("AT+CSCB={0:d},\"{1:s}\",\"{2:s}\"",
359 mode, channel, language);
360
361 static const char* const kFunc = __func__;
362 mAtChannel->queueRequester([this, serial, request = std::move(request)]
363 (const AtChannel::RequestPipe requestPipe) -> bool {
364 using OK = AtResponse::OK;
365 RadioError status = RadioError::NONE;
366
367 AtResponsePtr response =
368 mAtConversation(requestPipe, request,
369 [](const AtResponse& response) -> bool {
370 return response.holds<OK>();
371 });
372 if (!response || response->isParseError()) {
373 status = FAILURE(RadioError::INTERNAL_ERR);
374 } else if (!response->holds<OK>()) {
375 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
376 }
377
378 NOT_NULL(mRadioMessagingResponse)->setSmscAddressResponse(
379 makeRadioResponseInfo(serial, status));
380 return status != RadioError::INTERNAL_ERR;
381 });
382
383 return ScopedAStatus::ok();
384 }
385
setGsmBroadcastActivation(const int32_t serial,const bool)386 ScopedAStatus RadioMessaging::setGsmBroadcastActivation(const int32_t serial,
387 const bool /*activate*/) {
388 NOT_NULL(mRadioMessagingResponse)->setGsmBroadcastActivationResponse(
389 makeRadioResponseInfoNOP(serial));
390 return ScopedAStatus::ok();
391 }
392
setSmscAddress(const int32_t serial,const std::string & smsc)393 ScopedAStatus RadioMessaging::setSmscAddress(const int32_t serial, const std::string& smsc) {
394 static const char* const kFunc = __func__;
395 mAtChannel->queueRequester([this, serial, smsc]
396 (const AtChannel::RequestPipe requestPipe) -> bool {
397 using OK = AtResponse::OK;
398 RadioError status = RadioError::NONE;
399
400 const std::string request = std::format("AT+CSCA={0:s},{1:d}", smsc, 0);
401 AtResponsePtr response =
402 mAtConversation(requestPipe, request,
403 [](const AtResponse& response) -> bool {
404 return response.holds<OK>();
405 });
406 if (!response || response->isParseError()) {
407 status = FAILURE(RadioError::INTERNAL_ERR);
408 } else if (!response->holds<OK>()) {
409 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
410 }
411
412 NOT_NULL(mRadioMessagingResponse)->setSmscAddressResponse(
413 makeRadioResponseInfo(serial, status));
414 return status != RadioError::INTERNAL_ERR;
415 });
416
417 return ScopedAStatus::ok();
418 }
419
writeSmsToRuim(const int32_t serial,const messaging::CdmaSmsWriteArgs &)420 ScopedAStatus RadioMessaging::writeSmsToRuim(const int32_t serial,
421 const messaging::CdmaSmsWriteArgs& /*cdmaSms*/) {
422 NOT_NULL(mRadioMessagingResponse)->writeSmsToRuimResponse(
423 makeRadioResponseInfoUnsupported( // matches reference-ril.c
424 serial, FAILURE_DEBUG_PREFIX, __func__), 0);
425 return ScopedAStatus::ok();
426 }
427
writeSmsToSim(const int32_t serial,const messaging::SmsWriteArgs & smsWriteArgs)428 ScopedAStatus RadioMessaging::writeSmsToSim(const int32_t serial,
429 const messaging::SmsWriteArgs& smsWriteArgs) {
430 static const char* const kFunc = __func__;
431 mAtChannel->queueRequester([this, serial, smsWriteArgs]
432 (const AtChannel::RequestPipe requestPipe) -> bool {
433 using SmsPrompt = AtResponse::SmsPrompt;
434 using CMGW = AtResponse::CMGW;
435
436 RadioError status = RadioError::NONE;
437 int messageRef = -1;
438
439 std::string request = std::format("AT+CMGW=%d,%d",
440 smsWriteArgs.pdu.size() / 2, smsWriteArgs.status);
441
442 AtResponsePtr response =
443 mAtConversation(requestPipe, request,
444 [](const AtResponse& response) -> bool {
445 return response.holds<SmsPrompt>();
446 });
447 if (!response || response->isParseError()) {
448 status = FAILURE(RadioError::INTERNAL_ERR);
449 goto done;
450 } else if (!response->holds<SmsPrompt>()) {
451 response->unexpected(FAILURE_DEBUG_PREFIX, __func__);
452 }
453
454 request = std::format("{0:s}{1:s}", smsWriteArgs.pdu, kCtrlZ);
455 response =
456 mAtConversation(requestPipe, request,
457 [](const AtResponse& response) -> bool {
458 return response.holds<CMGW>();
459 });
460 if (!response || response->isParseError()) {
461 status = FAILURE(RadioError::INTERNAL_ERR);
462 goto done;
463 } else if (const CMGW* cmgw = response->get_if<CMGW>()) {
464 messageRef = cmgw->messageRef;
465 } else {
466 response->unexpected(FAILURE_DEBUG_PREFIX, __func__);
467 }
468
469 done: NOT_NULL(mRadioMessagingResponse)->writeSmsToSimResponse(
470 makeRadioResponseInfo(serial, status), messageRef);
471 return status != RadioError::INTERNAL_ERR;
472 });
473
474 return ScopedAStatus::ok();
475 }
476
atResponseSink(const AtResponsePtr & response)477 void RadioMessaging::atResponseSink(const AtResponsePtr& response) {
478 if (!mAtConversation.send(response)) {
479 response->visit([this](const auto& msg){ handleUnsolicited(msg); });
480 }
481 }
482
handleUnsolicited(const AtResponse::CMT & cmt)483 void RadioMessaging::handleUnsolicited(const AtResponse::CMT& cmt) {
484 if (mRadioMessagingIndication) {
485 mRadioMessagingIndication->newSms(
486 RadioIndicationType::UNSOLICITED, cmt.pdu);
487 }
488 }
489
handleUnsolicited(const AtResponse::CDS & cds)490 void RadioMessaging::handleUnsolicited(const AtResponse::CDS& cds) {
491 if (mRadioMessagingIndication) {
492 mRadioMessagingIndication->newSmsStatusReport(
493 RadioIndicationType::UNSOLICITED, cds.pdu);
494 }
495 }
496
responseAcknowledgement()497 ScopedAStatus RadioMessaging::responseAcknowledgement() {
498 return ScopedAStatus::ok();
499 }
500
setResponseFunctions(const std::shared_ptr<messaging::IRadioMessagingResponse> & radioMessagingResponse,const std::shared_ptr<messaging::IRadioMessagingIndication> & radioMessagingIndication)501 ScopedAStatus RadioMessaging::setResponseFunctions(
502 const std::shared_ptr<messaging::IRadioMessagingResponse>& radioMessagingResponse,
503 const std::shared_ptr<messaging::IRadioMessagingIndication>& radioMessagingIndication) {
504 mRadioMessagingResponse = NOT_NULL(radioMessagingResponse);
505 mRadioMessagingIndication = NOT_NULL(radioMessagingIndication);
506 return ScopedAStatus::ok();
507 }
508
509 } // namespace implementation
510 } // namespace radio
511 } // namespace hardware
512 } // namespace android
513 } // namespace aidl
514