• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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