1 /*
2 * Copyright (c) 2021-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 "distributed_sched_continuation.h"
17 #include "dtbschedmgr_log.h"
18 #include "parcel_helper.h"
19
20 using namespace OHOS::AppExecFwk;
21
22 namespace OHOS {
23 namespace DistributedSchedule {
24 namespace {
25 constexpr int64_t CONTINUATION_DELAY_TIME = 20000;
26 const std::string TAG = "DSchedContinuation";
27 const std::u16string NAPI_MISSION_CENTER_INTERFACE_TOKEN = u"ohos.DistributedSchedule.IMissionCallback";
28 constexpr int32_t NOTIFY_MISSION_CENTER_RESULT = 4;
29 const std::u16string DSCHED_EVENT_TOKEN = u"ohos.distributedSchedule.dschedeventlistener";
30 constexpr int32_t DSCHED_EVENT_CALLBACK = 0;
31 }
32
Init(const FuncContinuationCallback & contCallback)33 void DSchedContinuation::Init(const FuncContinuationCallback& contCallback)
34 {
35 auto runner = EventRunner::Create("dsched_continuation");
36 continuationHandler_ = std::make_shared<ContinuationHandler>(runner, shared_from_this(), contCallback);
37 diedListener_ = new DistributedEventDiedListener();
38 }
39
PushAbilityToken(int32_t sessionId,const sptr<IRemoteObject> & abilityToken)40 bool DSchedContinuation::PushAbilityToken(int32_t sessionId, const sptr<IRemoteObject>& abilityToken)
41 {
42 if (abilityToken == nullptr) {
43 HILOGE("PushAbilityToken abilityToken null!");
44 return false;
45 }
46
47 if (sessionId <= 0) {
48 HILOGE("PushAbilityToken sessionId invalid!");
49 return false;
50 }
51
52 if (continuationHandler_ == nullptr) {
53 HILOGE("PushAbilityToken not initialized!");
54 return false;
55 }
56
57 std::lock_guard<std::mutex> autoLock(continuationLock_);
58 bool ret = true;
59 ret = continuationHandler_->SendEvent(sessionId, 0, CONTINUATION_DELAY_TIME);
60 if (!ret) {
61 HILOGE("PushAbilityToken SendEvent failed!");
62 return false;
63 }
64
65 auto iterSession = continuationMap_.find(sessionId);
66 if (iterSession != continuationMap_.end()) {
67 HILOGE("PushAbilityToken sessionId:%{public}d exist!", sessionId);
68 return false;
69 }
70 (void)continuationMap_.emplace(sessionId, abilityToken);
71 return true;
72 }
73
PopAbilityToken(int32_t sessionId)74 sptr<IRemoteObject> DSchedContinuation::PopAbilityToken(int32_t sessionId)
75 {
76 if (sessionId <= 0) {
77 HILOGE("PopAbilityToken sessionId invalid");
78 return nullptr;
79 }
80
81 std::lock_guard<std::mutex> autoLock(continuationLock_);
82 auto iter = continuationMap_.find(sessionId);
83 if (iter == continuationMap_.end()) {
84 HILOGW("PopAbilityToken not found sessionId:%{public}d", sessionId);
85 return nullptr;
86 }
87 sptr<IRemoteObject> abilityToken = iter->second;
88 (void)continuationMap_.erase(iter);
89 if (continuationHandler_ != nullptr) {
90 continuationHandler_->RemoveEvent(sessionId);
91 }
92 return abilityToken;
93 }
94
GenerateSessionId()95 int32_t DSchedContinuation::GenerateSessionId()
96 {
97 std::lock_guard<std::mutex> autoLock(continuationLock_);
98 int32_t currValue = currSessionId_;
99 if (++currSessionId_ <= 0) {
100 currSessionId_ = 1;
101 }
102 return currValue;
103 }
104
SetTimeOut(int32_t missionId,int32_t timeout)105 void DSchedContinuation::SetTimeOut(int32_t missionId, int32_t timeout)
106 {
107 if (continuationHandler_ == nullptr) {
108 HILOGE("continuationHandler not initialized!");
109 return;
110 }
111 continuationHandler_->SendEvent(missionId, 0, timeout);
112 }
113
RemoveTimeOut(int32_t missionId)114 void DSchedContinuation::RemoveTimeOut(int32_t missionId)
115 {
116 if (continuationHandler_ == nullptr) {
117 HILOGE("continuationHandler not initialized!");
118 return;
119 }
120 continuationHandler_->RemoveEvent(missionId);
121 }
122
IsFreeInstall(int32_t missionId)123 bool DSchedContinuation::IsFreeInstall(int32_t missionId)
124 {
125 std::lock_guard<std::mutex> autoLock(continuationLock_);
126 auto iter = freeInstall_.find(missionId);
127 if (iter != freeInstall_.end()) {
128 HILOGD("continue free install, missionId:%{public}d exist!", missionId);
129 return iter->second;
130 }
131 return false;
132 }
133
IsInContinuationProgress(int32_t missionId)134 bool DSchedContinuation::IsInContinuationProgress(int32_t missionId)
135 {
136 std::lock_guard<std::mutex> autoLock(continuationLock_);
137 auto iterSession = callbackMap_.find(missionId);
138 if (iterSession != callbackMap_.end()) {
139 HILOGD("Continuation in progress, missionId:%{public}d exist!", missionId);
140 return true;
141 }
142 return false;
143 }
144
GetTargetDevice(int32_t missionId)145 std::string DSchedContinuation::GetTargetDevice(int32_t missionId)
146 {
147 std::lock_guard<std::mutex> autoLock(continuationLock_);
148 auto iter = continuationDevices_.find(missionId);
149 if (iter != continuationDevices_.end()) {
150 HILOGD("missionId:%{public}d exist!", missionId);
151 return iter->second;
152 }
153 return "";
154 }
155
PushCallback(const sptr<IRemoteObject> & callback)156 bool DSchedContinuation::PushCallback(const sptr<IRemoteObject>& callback)
157 {
158 if (continuationHandler_ == nullptr) {
159 HILOGE("not initialized!");
160 return false;
161 }
162 HILOGI("DSchedContinuation PushCallback start!");
163 if (callback == nullptr) {
164 HILOGE("callback null!");
165 return false;
166 }
167 std::lock_guard<std::mutex> autoLock(continuationLock_);
168 std::vector<sptr<IRemoteObject>> vecCallback = continuationCallbackArr_;
169 for (auto ele = continuationCallbackArr_.begin(); ele != continuationCallbackArr_.end(); ++ele) {
170 if ((*ele) == callback) {
171 HILOGW("callback already exists!");
172 return false;
173 }
174 }
175 continuationCallbackArr_.push_back(callback);
176 callback->AddDeathRecipient(diedListener_);
177
178 int dSchedEventresult = NotifyDSchedEventForOneCB(callback, ERR_OK);
179 if (dSchedEventresult != ERR_OK) {
180 HILOGE("Push continuation success, notify dms event result: %{public}d.", dSchedEventresult);
181 }
182 return true;
183 }
184
PushCallback(int32_t missionId,const sptr<IRemoteObject> & callback,std::string deviceId,bool isFreeInstall)185 bool DSchedContinuation::PushCallback(int32_t missionId, const sptr<IRemoteObject>& callback,
186 std::string deviceId, bool isFreeInstall)
187 {
188 HILOGI("DSchedContinuation PushCallback start!");
189 if (callback == nullptr) {
190 HILOGE("callback null!");
191 return false;
192 }
193
194 if (continuationHandler_ == nullptr) {
195 HILOGE("not initialized!");
196 return false;
197 }
198
199 std::lock_guard<std::mutex> autoLock(continuationLock_);
200 auto iterSession = callbackMap_.find(missionId);
201 if (iterSession != callbackMap_.end()) {
202 HILOGE("missionId:%{public}d exist!", missionId);
203 return false;
204 }
205 (void)callbackMap_.emplace(missionId, callback);
206 (void)continuationDevices_.emplace(missionId, deviceId);
207 if (isFreeInstall) {
208 freeInstall_[missionId] = isFreeInstall;
209 }
210 return true;
211 }
212
GetCallback()213 std::vector<sptr<IRemoteObject>> DSchedContinuation::GetCallback()
214 {
215 std::lock_guard<std::mutex> autoLock(continuationLock_);
216 return continuationCallbackArr_;
217 }
218
CleanupCallback(const sptr<IRemoteObject> & callback)219 bool DSchedContinuation::CleanupCallback(const sptr<IRemoteObject>& callback)
220 {
221 std::lock_guard<std::mutex> autoLock(continuationLock_);
222 if (continuationCallbackArr_.empty()) {
223 HILOGE("No need for cleaning!");
224 return false;
225 }
226 for (auto ele = continuationCallbackArr_.begin(); ele != continuationCallbackArr_.end(); ++ele) {
227 if ((*ele) == callback) {
228 continuationCallbackArr_.erase(ele);
229 HILOGI("callback is exists, cleared successfully.");
230 return true;
231 }
232 }
233 HILOGI("callback is not exists!");
234 return false;
235 }
236
PopCallback(int32_t missionId)237 sptr<IRemoteObject> DSchedContinuation::PopCallback(int32_t missionId)
238 {
239 std::lock_guard<std::mutex> autoLock(continuationLock_);
240 auto iter = callbackMap_.find(missionId);
241 if (iter == callbackMap_.end()) {
242 HILOGW("PopCallback not found missionId:%{public}d", missionId);
243 return nullptr;
244 }
245 sptr<IRemoteObject> callback = iter->second;
246
247 auto iteration = continuationDevices_.find(missionId);
248 if (iteration != continuationDevices_.end()) {
249 HILOGD("%{public}d need pop from continuationDevices_", missionId);
250 (void)continuationDevices_.erase(iteration);
251 }
252
253 auto it = freeInstall_.find(missionId);
254 if (it != freeInstall_.end()) {
255 HILOGD("%{public}d need pop from freeInstall_", missionId);
256 (void)freeInstall_.erase(it);
257 }
258 (void)cleanMission_.erase(missionId);
259 (void)callbackMap_.erase(iter);
260 return callback;
261 }
262
NotifyDSchedEventForOneCB(const sptr<IRemoteObject> & cb,int32_t resultCode)263 int32_t DSchedContinuation::NotifyDSchedEventForOneCB(const sptr<IRemoteObject> &cb, int32_t resultCode)
264 {
265 if (cb == nullptr) {
266 HILOGE("NotifyDSchedEventForOneCB input callback is null.");
267 return INVALID_PARAMETERS_ERR;
268 }
269
270 MessageParcel data;
271 if (!data.WriteInterfaceToken(DSCHED_EVENT_TOKEN)) {
272 HILOGE("NotifyDSchedEventForOneCB write token failed");
273 return SEND_REQUEST_DEF_FAIL;
274 }
275 PARCEL_WRITE_HELPER_RET(data, Int32, resultCode, SEND_REQUEST_DEF_FAIL);
276 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.srcNetworkId_, SEND_REQUEST_DEF_FAIL);
277 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.dstNetworkId_, SEND_REQUEST_DEF_FAIL);
278 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.srcBundleName_, SEND_REQUEST_DEF_FAIL);
279 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.srcModuleName_, SEND_REQUEST_DEF_FAIL);
280 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.srcAbilityName_, SEND_REQUEST_DEF_FAIL);
281 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.destBundleName_, SEND_REQUEST_DEF_FAIL);
282 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.destModuleName_, SEND_REQUEST_DEF_FAIL);
283 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.destAbilityName_, SEND_REQUEST_DEF_FAIL);
284 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.developerId_, SEND_REQUEST_DEF_FAIL);
285 PARCEL_WRITE_HELPER_RET(data, Int32, continueEvent_.dSchedEventType_, SEND_REQUEST_DEF_FAIL);
286 PARCEL_WRITE_HELPER_RET(data, Int32, continueEvent_.state_, SEND_REQUEST_DEF_FAIL);
287
288 MessageParcel reply;
289 MessageOption option;
290 int32_t ret = cb->SendRequest(DSCHED_EVENT_CALLBACK, data, reply, option);
291 HILOGI("NotifyDSchedEventForOneCB transact end, ret: %{public}d.", ret);
292 return ret;
293 }
294
NotifyDSchedEventResult(int32_t resultCode)295 int32_t DSchedContinuation::NotifyDSchedEventResult(int32_t resultCode)
296 {
297 HILOGI("NotifyDSchedEventResult GetCallback IDSchedEventListener");
298 std::vector<sptr<IRemoteObject>> vecCallback = GetCallback();
299 if (vecCallback.empty()) {
300 HILOGD("No listening has been registered, no need to report events");
301 return INVALID_PARAMETERS_ERR;
302 }
303 bool isAllSuc = true;
304 for (auto callback = vecCallback.begin(); callback != vecCallback.end(); ++callback) {
305 int32_t ret = NotifyDSchedEventForOneCB(*callback, resultCode);
306 if (ret != ERR_OK) {
307 HILOGE("NotifyDSchedEventResult transact fail, ret: %{public}d", ret);
308 isAllSuc = isAllSuc && false;
309 }
310 }
311 if (!isAllSuc) {
312 HILOGE("NotifyDSchedEventListenerResult transact fail, isAllSuc: %{public}d", isAllSuc);
313 return SEND_REQUEST_DEF_FAIL;
314 }
315 HILOGI("NotifyDSchedEventResult transact ok.");
316 return ERR_OK;
317 }
318
NotifyMissionCenterResult(int32_t missionId,int32_t resultCode)319 int32_t DSchedContinuation::NotifyMissionCenterResult(int32_t missionId, int32_t resultCode)
320 {
321 sptr<IRemoteObject> callback = PopCallback(missionId);
322 RemoveTimeOut(missionId);
323 if (callback == nullptr) {
324 HILOGE("NotifyMissionCenterResult callback is null");
325 return INVALID_PARAMETERS_ERR;
326 }
327
328 MessageParcel data;
329 if (!data.WriteInterfaceToken(NAPI_MISSION_CENTER_INTERFACE_TOKEN)) {
330 HILOGE("NotifyMissionCenterResult write token failed");
331 return INVALID_PARAMETERS_ERR;
332 }
333 PARCEL_WRITE_HELPER_RET(data, Int32, resultCode, INVALID_PARAMETERS_ERR);
334 MessageParcel reply;
335 MessageOption option;
336 int32_t error = callback->SendRequest(NOTIFY_MISSION_CENTER_RESULT, data, reply, option);
337 HILOGI("NotifyMissionCenterResult transact result: %{public}d", error);
338 return error;
339 }
340
ProcessEvent(const InnerEvent::Pointer & event)341 void DSchedContinuation::ContinuationHandler::ProcessEvent(const InnerEvent::Pointer& event)
342 {
343 if (event == nullptr) {
344 HILOGE("ProcessEvent event nullptr!");
345 return;
346 }
347
348 auto eventId = event->GetInnerEventId();
349 int32_t sessionId = static_cast<int32_t>(eventId);
350 if (sessionId <= 0) {
351 HILOGW("ProcessEvent sessionId invalid!");
352 return;
353 }
354
355 if (contCallback_ != nullptr) {
356 contCallback_(sessionId);
357 }
358 }
359
SetCleanMissionFlag(int32_t missionId,bool isCleanMission)360 void DSchedContinuation::SetCleanMissionFlag(int32_t missionId, bool isCleanMission)
361 {
362 std::lock_guard<std::mutex> autoLock(continuationLock_);
363 cleanMission_.emplace(missionId, isCleanMission);
364 }
365
IsCleanMission(int32_t missionId)366 bool DSchedContinuation::IsCleanMission(int32_t missionId)
367 {
368 std::lock_guard<std::mutex> autoLock(continuationLock_);
369 auto iter = cleanMission_.find(missionId);
370 if (iter != cleanMission_.end()) {
371 HILOGD("Application need not exit after continue, missionId:%{public}d exist!", missionId);
372 return iter->second;
373 }
374 return true;
375 }
376 } // namespace DistributedSchedule
377 } // namespace OHOS
378