1 /*
2 * Copyright (c) 2024 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
16 #include "js_continuation_state_manager.h"
17 #include "js_continuation_state_client.h"
18
19 #include "napi_error_code.h"
20 #include "dtbschedmgr_log.h"
21 #include "iservice_registry.h"
22 #include "system_ability_definition.h"
23
24 namespace OHOS {
25 namespace DistributedSchedule {
26 using namespace OHOS::AbilityRuntime;
27 using namespace OHOS::AppExecFwk;
28 namespace {
29 const std::string TAG = "JsContinuationStateManager";
30 const std::string BIZTYPE_PREPARE_CONTINUE = "prepareContinue";
31 const std::string CODE_KEY_NAME = "code";
32 const std::string ERR_DMS_WORK_ABNORMALLY_MSG = "the system ability work abnormally.";
33 const int32_t ARG_INDEX_4_CALLBACK_FUNC = 2;
34 const int32_t SUCCESS = 0;
35 const int32_t FAILED = 1;
36 constexpr int32_t ARG_COUNT_TWO = 2;
37 constexpr int32_t ARG_COUNT_THREE = 3;
38 const int32_t CALLBACK_PARAMS_NUM = 2;
39 }
40
41 std::map<std::string, sptr<DistributedSchedule::JsContinuationStateManagerStub>>
42 JsContinuationStateManager::callbackStubs_;
43
ContinueStateCallbackOn(napi_env env,napi_callback_info info)44 napi_value JsContinuationStateManager::ContinueStateCallbackOn(napi_env env, napi_callback_info info)
45 {
46 HILOGI("ContinueStateCallbackOn call");
47 napi_value ret = nullptr;
48 int32_t result = SUCCESS;
49 sptr<DistributedSchedule::JsContinuationStateManagerStub> stub = CreateStub(env, info, true);
50 if (stub == nullptr || BIZTYPE_PREPARE_CONTINUE != stub->callbackData_.bizType) {
51 HILOGE("ContinueStateCallbackOn Unsupported business type: %{public}s; need: %{public}s",
52 stub == nullptr ? "" : stub->callbackData_.bizType.c_str(), BIZTYPE_PREPARE_CONTINUE.c_str());
53 napi_throw_error(env, std::to_string(ERR_DMS_WORK_ABNORMALLY).c_str(), ERR_DMS_WORK_ABNORMALLY_MSG.c_str());
54 result = FAILED;
55 napi_get_value_int32(env, ret, &result);
56 return ret;
57 }
58
59 std::string key = std::to_string(stub->callbackData_.missionId) + stub->callbackData_.bundleName +
60 stub->callbackData_.moduleName + stub->callbackData_.abilityName;
61 auto cacheStubEntry = callbackStubs_.find(key);
62 if (cacheStubEntry == callbackStubs_.end() || cacheStubEntry->second == nullptr) {
63 callbackStubs_[key] = stub;
64 } else {
65 napi_ref oldCallbackRef = callbackStubs_[key]->callbackData_.callbackRef;
66 if (oldCallbackRef != nullptr) {
67 napi_delete_reference(env, oldCallbackRef);
68 }
69 callbackStubs_[key]->callbackData_.callbackRef = stub->callbackData_.callbackRef;
70 }
71
72 DistributedSchedule::ContinuationStateClient client;
73 result = client.RegisterContinueStateCallback(stub);
74 HILOGI("ContinueStateCallbackOn register callback result: %{public}d", result);
75
76 if (result != ERR_OK) {
77 napi_throw_error(env, std::to_string(ERR_DMS_WORK_ABNORMALLY).c_str(), ERR_DMS_WORK_ABNORMALLY_MSG.c_str());
78 }
79 napi_get_value_int32(env, ret, &result);
80 return ret;
81 }
82
ContinueStateCallbackOff(napi_env env,napi_callback_info info)83 napi_value JsContinuationStateManager::ContinueStateCallbackOff(napi_env env, napi_callback_info info)
84 {
85 HILOGI("ContinueStateCallbackOff call");
86 napi_value ret = nullptr;
87 int32_t result = SUCCESS;
88 sptr<DistributedSchedule::JsContinuationStateManagerStub> stub = CreateStub(env, info, false);
89 if (stub == nullptr || BIZTYPE_PREPARE_CONTINUE != stub->callbackData_.bizType) {
90 HILOGE("ContinueStateCallbackOff Unsupported business type: %{public}s; need: %{public}s",
91 stub == nullptr ? "" : stub->callbackData_.bizType.c_str(), BIZTYPE_PREPARE_CONTINUE.c_str());
92 napi_throw_error(env, std::to_string(ERR_DMS_WORK_ABNORMALLY).c_str(), ERR_DMS_WORK_ABNORMALLY_MSG.c_str());
93 result = FAILED;
94 napi_get_value_int32(env, ret, &result);
95 return ret;
96 }
97
98 DistributedSchedule::ContinuationStateClient client;
99 result = client.UnRegisterContinueStateCallback(stub);
100 HILOGI("ContinueStateCallbackOff unregister callback result: %{public}d", result);
101
102 std::string key = std::to_string(stub->callbackData_.missionId) + stub->callbackData_.bundleName +
103 stub->callbackData_.moduleName + stub->callbackData_.abilityName;
104 if (result == ERR_OK) {
105 callbackStubs_.erase(key);
106 }
107 if (stub->callbackData_.callbackRef != nullptr) {
108 int32_t state = result;
109 napi_value callback = nullptr;
110 napi_get_reference_value(env, stub->callbackData_.callbackRef, &callback);
111 napi_value undefined = nullptr;
112 napi_get_undefined(env, &undefined);
113 napi_value continueResultInfo;
114 napi_create_object(env, &continueResultInfo);
115 napi_value resultState;
116 napi_create_int32(env, state, &resultState);
117 napi_set_named_property(env, continueResultInfo, "resultState", resultState);
118 napi_value resultInfo;
119 napi_create_string_utf8(env, "", 0, &resultInfo);
120 napi_set_named_property(env, continueResultInfo, "resultInfo", resultInfo);
121 napi_value callbackResult[2] = {NULL, continueResultInfo};
122 napi_call_function(env, undefined, callback, CALLBACK_PARAMS_NUM, callbackResult, nullptr);
123 }
124
125 if (result != ERR_OK) {
126 napi_throw_error(env, std::to_string(ERR_DMS_WORK_ABNORMALLY).c_str(), ERR_DMS_WORK_ABNORMALLY_MSG.c_str());
127 }
128 napi_get_value_int32(env, ret, &result);
129 return ret;
130 }
131
CreateStub(napi_env env,napi_callback_info info,const bool isRegisterOn)132 sptr<DistributedSchedule::JsContinuationStateManagerStub> JsContinuationStateManager::CreateStub(
133 napi_env env, napi_callback_info info, const bool isRegisterOn)
134 {
135 // get and check all params
136 size_t argc = ARG_COUNT_THREE;
137 napi_value args[ARG_COUNT_THREE];
138 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
139 if ((argc != ARG_COUNT_THREE && isRegisterOn) || (argc < ARG_COUNT_TWO && !isRegisterOn)) {
140 HILOGE("Mandatory parameters are left unspecified");
141 napi_throw_error(env, std::to_string(PARAMETER_CHECK_FAILED).c_str(),
142 "Mandatory parameters are left unspecified.");
143 return nullptr;
144 }
145 // this.context is 2nd parameter
146 std::shared_ptr<AbilityRuntime::AbilityContext> abilityContext = nullptr;
147 GetAbilityContext(abilityContext, env, args[1]);
148 if (abilityContext == nullptr) {
149 HILOGE("get ability context failed");
150 napi_throw_error(env, std::to_string(PARAMETER_CHECK_FAILED).c_str(), "get ability context failed");
151 return nullptr;
152 }
153 std::shared_ptr<AppExecFwk::AbilityInfo> abilityInfo = abilityContext->GetAbilityInfo();
154 DistributedSchedule::JsContinuationStateManagerStub::StateCallbackData callbackData;
155 callbackData.env = env;
156 callbackData.bundleName = abilityContext->GetBundleName();
157 callbackData.moduleName = abilityInfo->moduleName;
158 callbackData.abilityName = abilityInfo->name;
159 size_t stringSize = 0;
160 std::string type;
161 napi_get_value_string_utf8(env, args[0], nullptr, 0, &stringSize);
162 napi_get_value_string_utf8(env, args[0], &type[0], stringSize + 1, &stringSize);
163 callbackData.bizType = type.c_str();
164 if (argc == ARG_COUNT_THREE) {
165 napi_valuetype valuetype;
166 napi_typeof(env, args[ARG_INDEX_4_CALLBACK_FUNC], &valuetype);
167 if (valuetype != napi_function) {
168 napi_throw_error(env, std::to_string(PARAMETER_CHECK_FAILED).c_str(),
169 "The third parameter must be an asynchronous function");
170 return nullptr;
171 }
172 napi_ref callbackRef = nullptr;
173 napi_create_reference(env, args[ARG_INDEX_4_CALLBACK_FUNC], 1, &callbackRef);
174 callbackData.callbackRef = callbackRef;
175 }
176 abilityContext->GetMissionId(callbackData.missionId);
177 sptr<DistributedSchedule::JsContinuationStateManagerStub> stub(
178 new DistributedSchedule::JsContinuationStateManagerStub());
179 stub->callbackData_ = callbackData;
180 return stub;
181 }
182
GetAbilityContext(std::shared_ptr<AbilityRuntime::AbilityContext> & abilityContext,napi_env env,napi_value context)183 void JsContinuationStateManager::GetAbilityContext(
184 std::shared_ptr<AbilityRuntime::AbilityContext> &abilityContext, napi_env env, napi_value context)
185 {
186 bool stageMode = false;
187 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, context, stageMode);
188 if (status != napi_ok || !stageMode) {
189 auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
190 if (!ability) {
191 HILOGE("get ability info failed");
192 return;
193 }
194 abilityContext = ability->GetAbilityContext();
195 if (!abilityContext) {
196 HILOGE("get ability context failed");
197 return;
198 }
199 } else {
200 auto modeContext = AbilityRuntime::GetStageModeContext(env, context);
201 if (!modeContext) {
202 HILOGE("get stageMode ability info failed");
203 return;
204 }
205 abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(modeContext);
206 if (!abilityContext) {
207 HILOGE("get stageMode ability context failed");
208 return;
209 }
210 }
211 }
212
MakeContinueStateCodeEnumObject(napi_env env)213 napi_value JsContinuationStateManager::MakeContinueStateCodeEnumObject(napi_env env)
214 {
215 napi_value object;
216 napi_create_object(env, &object);
217 MakeEnumItem(env, object, "SUCCESS", SUCCESS);
218 MakeEnumItem(env, object, "SYSTEM_ERROR", FAILED);
219 return object;
220 }
221
MakeEnumItem(const napi_env & env,napi_value object,const char * name,int32_t value)222 napi_status JsContinuationStateManager::MakeEnumItem(
223 const napi_env &env, napi_value object, const char* name, int32_t value)
224 {
225 napi_value itemName;
226 napi_value itemValue;
227 napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &itemName);
228 napi_create_int32(env, value, &itemValue);
229 napi_set_property(env, object, itemName, itemValue);
230 return napi_ok;
231 }
232
JsContinueManagerInit(napi_env env,napi_value exportObj)233 napi_value JsContinueManagerInit(napi_env env, napi_value exportObj)
234 {
235 napi_value continueStateCodeEnumObject = JsContinuationStateManager::MakeContinueStateCodeEnumObject(env);
236
237 static napi_property_descriptor desc[] = {
238 DECLARE_NAPI_FUNCTION("on", JsContinuationStateManager::ContinueStateCallbackOn),
239 DECLARE_NAPI_FUNCTION("off", JsContinuationStateManager::ContinueStateCallbackOff),
240 DECLARE_NAPI_PROPERTY("ContinueStateCode", continueStateCodeEnumObject),
241 };
242 napi_define_properties(env, exportObj, sizeof(desc) / sizeof(desc[0]), desc);
243 return exportObj;
244 }
245
246 static napi_module continueManagerModule = {
247 .nm_filename = "app/ability/libcontinuemanager_napi.so/continuemanager.js",
248 .nm_register_func = OHOS::DistributedSchedule::JsContinueManagerInit,
249 .nm_modname = "app.ability.continueManager",
250 };
251
ContinuationStateManagerModuleRegister()252 extern "C" __attribute__((constructor)) void ContinuationStateManagerModuleRegister()
253 {
254 napi_module_register(&continueManagerModule);
255 }
256 } // namespace DistributedSchedule
257 } // namespace OHOS