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