1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "napi_send_recv_mms.h"
16 
17 #include "ability.h"
18 #include "napi_base_context.h"
19 #include "napi_mms_pdu.h"
20 #include "napi_mms_pdu_helper.h"
21 #include "sms_constants_utils.h"
22 #include "telephony_permission.h"
23 
24 namespace OHOS {
25 namespace Telephony {
26 namespace {
27 const std::string SMS_PROFILE_URI = "datashare:///com.ohos.smsmmsability";
28 static const int32_t DEFAULT_REF_COUNT = 1;
29 const bool STORE_MMS_PDU_TO_FILE = false;
30 const int32_t ARGS_ONE = 1;
31 std::shared_ptr<DataShare::DataShareHelper> g_datashareHelper = nullptr;
32 constexpr static uint32_t WAIT_PDN_TOGGLE_TIME = 3000;
33 } // namespace
34 std::mutex NapiSendRecvMms::downloadCtx_;
35 std::mutex NapiSendRecvMms::countCtx_;
36 int32_t NapiSendRecvMms::reqCount_ = 0;
37 bool NapiSendRecvMms::waitFlag = false;
38 
GetDataShareHelper(napi_env env,napi_callback_info info)39 std::shared_ptr<OHOS::DataShare::DataShareHelper> GetDataShareHelper(napi_env env, napi_callback_info info)
40 {
41     size_t argc = ARGS_ONE;
42     napi_value argv[ARGS_ONE] = { 0 };
43     napi_value thisVar = nullptr;
44     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
45 
46     std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
47     bool isStageMode = false;
48     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, argv[0], isStageMode);
49     if (status != napi_ok || !isStageMode) {
50         auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
51         if (ability == nullptr) {
52             TELEPHONY_LOGE("Failed to get native ability instance");
53             return nullptr;
54         }
55         auto context = ability->GetContext();
56         if (context == nullptr) {
57             TELEPHONY_LOGE("Failed to get native context instance");
58             return nullptr;
59         }
60         dataShareHelper = DataShare::DataShareHelper::Creator(context->GetToken(), SMS_PROFILE_URI);
61     } else {
62         auto context = OHOS::AbilityRuntime::GetStageModeContext(env, argv[0]);
63         if (context == nullptr) {
64             TELEPHONY_LOGE("Failed to get native stage context instance");
65             return nullptr;
66         }
67         dataShareHelper = DataShare::DataShareHelper::Creator(context->GetToken(), SMS_PROFILE_URI);
68     }
69     return dataShareHelper;
70 }
71 
GetMmsPduFromFile(const std::string & fileName,std::string & mmsPdu)72 bool GetMmsPduFromFile(const std::string &fileName, std::string &mmsPdu)
73 {
74     char realPath[PATH_MAX] = { 0 };
75     if (fileName.empty() || realpath(fileName.c_str(), realPath) == nullptr) {
76         TELEPHONY_LOGE("path or realPath is nullptr");
77         return false;
78     }
79 
80     FILE *pFile = fopen(realPath, "rb");
81     if (pFile == nullptr) {
82         TELEPHONY_LOGE("openFile Error");
83         return false;
84     }
85 
86     (void)fseek(pFile, 0, SEEK_END);
87     long fileLen = ftell(pFile);
88     if (fileLen <= 0 || fileLen > static_cast<long>(MMS_PDU_MAX_SIZE)) {
89         (void)fclose(pFile);
90         TELEPHONY_LOGE("fileLen Over Max Error");
91         return false;
92     }
93 
94     std::unique_ptr<char[]> pduBuffer = std::make_unique<char[]>(fileLen);
95     if (!pduBuffer) {
96         (void)fclose(pFile);
97         TELEPHONY_LOGE("make unique pduBuffer nullptr Error");
98         return false;
99     }
100     (void)fseek(pFile, 0, SEEK_SET);
101     int32_t totolLength = static_cast<int32_t>(fread(pduBuffer.get(), 1, MMS_PDU_MAX_SIZE, pFile));
102     TELEPHONY_LOGI("fread totolLength%{private}d", totolLength);
103 
104     long i = 0;
105     while (i < fileLen) {
106         mmsPdu += pduBuffer[i];
107         i++;
108     }
109     (void)fclose(pFile);
110     return true;
111 }
112 
StoreSendMmsPduToDataBase(NapiMmsPduHelper & helper)113 void StoreSendMmsPduToDataBase(NapiMmsPduHelper &helper) __attribute__((no_sanitize("cfi")))
114 {
115     std::shared_ptr<NAPIMmsPdu> mmsPduObj = std::make_shared<NAPIMmsPdu>();
116     if (mmsPduObj == nullptr) {
117         TELEPHONY_LOGE("mmsPduObj nullptr");
118         helper.NotifyAll();
119         return;
120     }
121     std::string mmsPdu;
122     if (!GetMmsPduFromFile(helper.GetPduFileName(), mmsPdu)) {
123         TELEPHONY_LOGE("get mmsPdu fail");
124         helper.NotifyAll();
125         return;
126     }
127     mmsPduObj->InsertMmsPdu(helper, mmsPdu);
128 }
129 
NativeSendMms(napi_env env,void * data)130 void NativeSendMms(napi_env env, void *data)
131 {
132     auto asyncContext = static_cast<MmsContext *>(data);
133     if (asyncContext == nullptr) {
134         TELEPHONY_LOGE("asyncContext nullptr");
135         return;
136     }
137     if (!TelephonyPermission::CheckCallerIsSystemApp()) {
138         TELEPHONY_LOGE("Non-system applications use system APIs!");
139         asyncContext->errorCode = TELEPHONY_ERR_ILLEGAL_USE_OF_SYSTEM_API;
140         return;
141     }
142     if (!STORE_MMS_PDU_TO_FILE) {
143         std::string pduFileName = NapiUtil::ToUtf8(asyncContext->data);
144         if (pduFileName.empty()) {
145             asyncContext->errorCode = TELEPHONY_ERR_ARGUMENT_INVALID;
146             asyncContext->resolved = false;
147             TELEPHONY_LOGE("pduFileName empty");
148             return;
149         }
150         if (g_datashareHelper == nullptr) {
151             asyncContext->errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
152             asyncContext->resolved = false;
153             TELEPHONY_LOGE("g_datashareHelper is nullptr");
154             return;
155         }
156         NapiMmsPduHelper helper;
157         helper.SetDataShareHelper(g_datashareHelper);
158         helper.SetPduFileName(pduFileName);
159         if (!helper.Run(StoreSendMmsPduToDataBase, helper)) {
160             TELEPHONY_LOGE("StoreMmsPdu fail");
161             asyncContext->errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
162             asyncContext->resolved = false;
163             return;
164         }
165         asyncContext->data = NapiUtil::ToUtf16(helper.GetDbUrl());
166     }
167     asyncContext->errorCode =
168         DelayedSingleton<SmsServiceManagerClient>::GetInstance()->SendMms(asyncContext->slotId, asyncContext->mmsc,
169             asyncContext->data, asyncContext->mmsConfig.userAgent, asyncContext->mmsConfig.userAgentProfile);
170     if (asyncContext->errorCode == TELEPHONY_ERR_SUCCESS) {
171         asyncContext->resolved = true;
172     } else {
173         asyncContext->resolved = false;
174     }
175     TELEPHONY_LOGI("NativeSendMms end resolved = %{public}d", asyncContext->resolved);
176 }
177 
SendMmsCallback(napi_env env,napi_status status,void * data)178 void SendMmsCallback(napi_env env, napi_status status, void *data)
179 {
180     auto context = static_cast<MmsContext *>(data);
181     if (g_datashareHelper != nullptr) {
182         g_datashareHelper->Release();
183     }
184     if (context == nullptr) {
185         TELEPHONY_LOGE("SendMmsCallback context nullptr");
186         return;
187     }
188     napi_value callbackValue = nullptr;
189     if (context->resolved) {
190         napi_get_undefined(env, &callbackValue);
191     } else {
192         JsError error = NapiUtil::ConverErrorMessageWithPermissionForJs(
193             context->errorCode, "sendMms", "ohos.permission.SEND_MESSAGES");
194         callbackValue = NapiUtil::CreateErrorMessage(env, error.errorMessage, error.errorCode);
195     }
196     NapiUtil::Handle1ValueCallback(env, context, callbackValue);
197 }
198 
MatchMmsParameters(napi_env env,napi_value parameters[],size_t parameterCount)199 bool MatchMmsParameters(napi_env env, napi_value parameters[], size_t parameterCount)
200 {
201     bool typeMatch = false;
202     switch (parameterCount) {
203         case TWO_PARAMETERS: {
204             typeMatch = NapiUtil::MatchParameters(env, parameters, { napi_object, napi_object });
205             break;
206         }
207         case THREE_PARAMETERS: {
208             typeMatch = NapiUtil::MatchParameters(env, parameters, { napi_object, napi_object, napi_function });
209             break;
210         }
211         default: {
212             break;
213         }
214     }
215     if (typeMatch) {
216         return NapiUtil::MatchObjectProperty(env, parameters[1],
217             {
218                 { "slotId", napi_number },
219                 { "mmsc", napi_string },
220                 { "data", napi_string },
221                 { "mmsConfig", napi_object },
222             });
223     }
224     return false;
225 }
226 
GetMmsValueLength(napi_env env,napi_value param)227 static bool GetMmsValueLength(napi_env env, napi_value param)
228 {
229     size_t len = 0;
230     napi_status status = napi_get_value_string_utf8(env, param, nullptr, 0, &len);
231     if (status != napi_ok) {
232         TELEPHONY_LOGE("Get length failed");
233         return false;
234     }
235     return (len > 0) && (len < BUFF_LENGTH);
236 }
237 
GetMmsNameProperty(napi_env env,napi_value param,MmsContext & context)238 static void GetMmsNameProperty(napi_env env, napi_value param, MmsContext &context)
239 {
240     napi_value slotIdValue = NapiUtil::GetNamedProperty(env, param, "slotId");
241     if (slotIdValue != nullptr) {
242         napi_get_value_int32(env, slotIdValue, &(context.slotId));
243     }
244     napi_value mmscValue = NapiUtil::GetNamedProperty(env, param, "mmsc");
245     if (mmscValue != nullptr && GetMmsValueLength(env, mmscValue)) {
246         char strChars[NORMAL_STRING_SIZE] = { 0 };
247         size_t strLength = 0;
248         napi_get_value_string_utf8(env, mmscValue, strChars, BUFF_LENGTH, &strLength);
249         std::string str8(strChars, strLength);
250         context.mmsc = NapiUtil::ToUtf16(str8);
251     }
252     napi_value dataValue = NapiUtil::GetNamedProperty(env, param, "data");
253     if (dataValue != nullptr && GetMmsValueLength(env, dataValue)) {
254         char strChars[NORMAL_STRING_SIZE] = { 0 };
255         size_t strLength = 0;
256         napi_get_value_string_utf8(env, dataValue, strChars, BUFF_LENGTH, &strLength);
257         std::string str8(strChars, strLength);
258         context.data = NapiUtil::ToUtf16(str8);
259     }
260     napi_value configValue = NapiUtil::GetNamedProperty(env, param, "mmsConfig");
261     if (configValue != nullptr) {
262         napi_value uaValue = NapiUtil::GetNamedProperty(env, configValue, "userAgent");
263         if (uaValue != nullptr && GetMmsValueLength(env, uaValue)) {
264             char strChars[NORMAL_STRING_SIZE] = { 0 };
265             size_t strLength = 0;
266             napi_get_value_string_utf8(env, uaValue, strChars, BUFF_LENGTH, &strLength);
267             std::string str8(strChars, strLength);
268             context.mmsConfig.userAgent = NapiUtil::ToUtf16(str8);
269         }
270         napi_value uaprofValue = NapiUtil::GetNamedProperty(env, configValue, "userAgentProfile");
271         if (uaprofValue != nullptr && GetMmsValueLength(env, uaprofValue)) {
272             char strChars[NORMAL_STRING_SIZE] = { 0 };
273             size_t strLength = 0;
274             napi_get_value_string_utf8(env, uaprofValue, strChars, BUFF_LENGTH, &strLength);
275             std::string str8(strChars, strLength);
276             context.mmsConfig.userAgentProfile = NapiUtil::ToUtf16(str8);
277         }
278     }
279 }
280 
SendMms(napi_env env,napi_callback_info info)281 napi_value NapiSendRecvMms::SendMms(napi_env env, napi_callback_info info)
282 {
283     size_t parameterCount = THREE_PARAMETERS;
284     napi_value parameters[THREE_PARAMETERS] = { 0 };
285     napi_value thisVar = nullptr;
286     void *data = nullptr;
287 
288     napi_get_cb_info(env, info, &parameterCount, parameters, &thisVar, &data);
289     if (!MatchMmsParameters(env, parameters, parameterCount)) {
290         TELEPHONY_LOGE("parameter matching failed.");
291         NapiUtil::ThrowParameterError(env);
292         return nullptr;
293     }
294     auto context = std::make_unique<MmsContext>().release();
295     if (context == nullptr) {
296         TELEPHONY_LOGE("MmsContext is nullptr.");
297         NapiUtil::ThrowParameterError(env);
298         return nullptr;
299     }
300     if (!STORE_MMS_PDU_TO_FILE) {
301         g_datashareHelper = GetDataShareHelper(env, info);
302     }
303     GetMmsNameProperty(env, parameters[1], *context);
304     if (parameterCount == THREE_PARAMETERS) {
305         napi_create_reference(env, parameters[PARAMETERS_INDEX_TWO], DEFAULT_REF_COUNT, &context->callbackRef);
306     }
307     napi_value result = NapiUtil::HandleAsyncWork(env, context, "SendMms", NativeSendMms, SendMmsCallback);
308     return result;
309 }
310 
WriteBufferToFile(const std::unique_ptr<char[]> & buff,uint32_t len,const std::string & strPathName)311 bool WriteBufferToFile(const std::unique_ptr<char[]> &buff, uint32_t len, const std::string &strPathName)
312 {
313     if (buff == nullptr) {
314         TELEPHONY_LOGE("buff nullptr");
315         return false;
316     }
317 
318     char realPath[PATH_MAX] = { 0 };
319     if (strPathName.empty() || realpath(strPathName.c_str(), realPath) == nullptr) {
320         TELEPHONY_LOGE("path or realPath is nullptr");
321         return false;
322     }
323 
324     FILE *pFile = fopen(realPath, "wb");
325     if (pFile == nullptr) {
326         TELEPHONY_LOGE("openFile Error");
327         return false;
328     }
329     uint32_t fileLen = fwrite(buff.get(), len, 1, pFile);
330     (void)fclose(pFile);
331     if (fileLen > 0) {
332         TELEPHONY_LOGI("write mms buffer to file success");
333         return true;
334     } else {
335         TELEPHONY_LOGI("write mms buffer to file error");
336         return false;
337     }
338 }
339 
StoreMmsPduToFile(const std::string & fileName,const std::string & mmsPdu)340 bool StoreMmsPduToFile(const std::string &fileName, const std::string &mmsPdu)
341 {
342     uint32_t len = static_cast<uint32_t>(mmsPdu.size());
343     if (len > MMS_PDU_MAX_SIZE || len == 0) {
344         TELEPHONY_LOGE("MMS pdu length invalid");
345         return false;
346     }
347 
348     std::unique_ptr<char[]> resultResponse = std::make_unique<char[]>(len);
349     if (memset_s(resultResponse.get(), len, 0x00, len) != EOK) {
350         TELEPHONY_LOGE("memset_s err");
351         return false;
352     }
353     if (memcpy_s(resultResponse.get(), len, &mmsPdu[0], len) != EOK) {
354         TELEPHONY_LOGE("memcpy_s error");
355         return false;
356     }
357 
358     TELEPHONY_LOGI("len:%{public}d", len);
359     if (!WriteBufferToFile(std::move(resultResponse), len, fileName)) {
360         TELEPHONY_LOGE("write to file error");
361         return false;
362     }
363     return true;
364 }
365 
GetMmsPduFromDataBase(NapiMmsPduHelper & helper)366 void GetMmsPduFromDataBase(NapiMmsPduHelper &helper) __attribute__((no_sanitize("cfi")))
367 {
368     NAPIMmsPdu mmsPduObj;
369     std::string mmsPdu = mmsPduObj.GetMmsPdu(helper);
370     if (mmsPdu.empty()) {
371         TELEPHONY_LOGE("from dataBase empty");
372         return;
373     }
374 
375     mmsPduObj.DeleteMmsPdu(helper);
376     if (!StoreMmsPduToFile(helper.GetStoreFileName(), mmsPdu)) {
377         TELEPHONY_LOGE("store mmsPdu fail");
378     }
379     helper.NotifyAll();
380 }
381 
DownloadExceptionCase(MmsContext & context,std::shared_ptr<OHOS::DataShare::DataShareHelper> g_datashareHelper)382 static bool DownloadExceptionCase(
383     MmsContext &context, std::shared_ptr<OHOS::DataShare::DataShareHelper> g_datashareHelper)
384 {
385     if (!TelephonyPermission::CheckCallerIsSystemApp()) {
386         TELEPHONY_LOGE("Non-system applications use system APIs!");
387         context.errorCode = TELEPHONY_ERR_ILLEGAL_USE_OF_SYSTEM_API;
388         context.resolved = false;
389         return false;
390     }
391     if (g_datashareHelper == nullptr) {
392         TELEPHONY_LOGE("g_datashareHelper is nullptr");
393         context.errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
394         context.resolved = false;
395         return false;
396     }
397     std::string fileName = NapiUtil::ToUtf8(context.data);
398     char realPath[PATH_MAX] = { 0 };
399     if (fileName.empty() || realpath(fileName.c_str(), realPath) == nullptr) {
400         TELEPHONY_LOGE("path or realPath is nullptr");
401         context.errorCode = TELEPHONY_ERR_ARGUMENT_INVALID;
402         context.resolved = false;
403         return false;
404     }
405     FILE *pFile = fopen(realPath, "wb");
406     if (pFile == nullptr) {
407         TELEPHONY_LOGE("openFile Error");
408         context.errorCode = TELEPHONY_ERR_ARGUMENT_INVALID;
409         context.resolved = false;
410         return false;
411     }
412     (void)fclose(pFile);
413     return true;
414 }
415 
UpdateReqCount()416 void UpdateReqCount()
417 {
418     std::unique_lock<std::mutex> lck(NapiSendRecvMms::countCtx_);
419     NapiSendRecvMms::reqCount_++;
420     TELEPHONY_LOGI("reqCount_:%{public}d", NapiSendRecvMms::reqCount_);
421 }
422 
DecreaseReqCount()423 void DecreaseReqCount()
424 {
425     NapiSendRecvMms::reqCount_--;
426     if (NapiSendRecvMms::reqCount_ > 0) {
427         NapiSendRecvMms::waitFlag = true;
428     } else {
429         NapiSendRecvMms::waitFlag = false;
430     }
431 }
432 
NativeDownloadMms(napi_env env,void * data)433 void NativeDownloadMms(napi_env env, void *data)
434 {
435     auto asyncContext = static_cast<MmsContext *>(data);
436     if (asyncContext == nullptr) {
437         TELEPHONY_LOGE("asyncContext nullptr");
438         return;
439     }
440     if (!DownloadExceptionCase(*asyncContext, g_datashareHelper)) {
441         TELEPHONY_LOGE("Exception case");
442         return;
443     }
444 
445     TELEPHONY_LOGI("native download mms");
446     UpdateReqCount();
447     std::unique_lock<std::mutex> lck(NapiSendRecvMms::downloadCtx_);
448     if (NapiSendRecvMms::waitFlag) {
449         TELEPHONY_LOGI("down multiple mms at once wait");
450         std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_PDN_TOGGLE_TIME));
451     }
452     std::u16string dbUrls;
453     asyncContext->errorCode =
454         DelayedSingleton<SmsServiceManagerClient>::GetInstance()->DownloadMms(asyncContext->slotId, asyncContext->mmsc,
455             dbUrls, asyncContext->mmsConfig.userAgent, asyncContext->mmsConfig.userAgentProfile);
456     TELEPHONY_LOGI("NativeDownloadMms dbUrls:%{public}s", NapiUtil::ToUtf8(dbUrls).c_str());
457     if (asyncContext->errorCode == TELEPHONY_ERR_SUCCESS) {
458         asyncContext->resolved = true;
459         if (!STORE_MMS_PDU_TO_FILE) {
460             NapiMmsPduHelper helper;
461             helper.SetDataShareHelper(g_datashareHelper);
462             helper.SetDbUrl(NapiUtil::ToUtf8(dbUrls));
463             helper.SetStoreFileName(NapiUtil::ToUtf8(asyncContext->data));
464             if (!helper.Run(GetMmsPduFromDataBase, helper)) {
465                 TELEPHONY_LOGE("StoreMmsPdu fail");
466                 asyncContext->errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
467                 asyncContext->resolved = false;
468                 return;
469             }
470         }
471     } else {
472         asyncContext->resolved = false;
473     }
474     DecreaseReqCount();
475     TELEPHONY_LOGI("NativeDownloadMms end resolved = %{public}d", asyncContext->resolved);
476 }
477 
DownloadMmsCallback(napi_env env,napi_status status,void * data)478 void DownloadMmsCallback(napi_env env, napi_status status, void *data)
479 {
480     auto context = static_cast<MmsContext *>(data);
481     if (g_datashareHelper != nullptr && !NapiSendRecvMms::waitFlag) {
482         g_datashareHelper->Release();
483     }
484     if (context == nullptr) {
485         TELEPHONY_LOGE("SendMmsCallback context nullptr");
486         return;
487     }
488     napi_value callbackValue = nullptr;
489     if (context->resolved) {
490         napi_get_undefined(env, &callbackValue);
491     } else {
492         JsError error = NapiUtil::ConverErrorMessageWithPermissionForJs(
493             context->errorCode, "downloadMms", "ohos.permission.RECEIVE_MMS");
494         callbackValue = NapiUtil::CreateErrorMessage(env, error.errorMessage, error.errorCode);
495     }
496     NapiUtil::Handle1ValueCallback(env, context, callbackValue);
497 }
498 
DownloadMms(napi_env env,napi_callback_info info)499 napi_value NapiSendRecvMms::DownloadMms(napi_env env, napi_callback_info info)
500 {
501     size_t parameterCount = THREE_PARAMETERS;
502     napi_value parameters[THREE_PARAMETERS] = { 0 };
503     napi_value thisVar = nullptr;
504     void *data = nullptr;
505 
506     napi_get_cb_info(env, info, &parameterCount, parameters, &thisVar, &data);
507     if (!MatchMmsParameters(env, parameters, parameterCount)) {
508         TELEPHONY_LOGE("DownloadMms parameter matching failed.");
509         NapiUtil::ThrowParameterError(env);
510         return nullptr;
511     }
512     auto context = std::make_unique<MmsContext>().release();
513     if (context == nullptr) {
514         TELEPHONY_LOGE("DownloadMms MmsContext is nullptr.");
515         NapiUtil::ThrowParameterError(env);
516         return nullptr;
517     }
518     if (!STORE_MMS_PDU_TO_FILE) {
519         g_datashareHelper = GetDataShareHelper(env, info);
520     }
521     GetMmsNameProperty(env, parameters[1], *context);
522     if (parameterCount == THREE_PARAMETERS) {
523         napi_create_reference(env, parameters[PARAMETERS_INDEX_TWO], DEFAULT_REF_COUNT, &context->callbackRef);
524     }
525     napi_value result = NapiUtil::HandleAsyncWork(env, context, "DownloadMms", NativeDownloadMms, DownloadMmsCallback);
526     return result;
527 }
528 } // namespace Telephony
529 } // namespace OHOS
530