1 /*
2 * Copyright (c) 2021-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
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 std::string & type,const sptr<IRemoteObject> & callback)156 bool DSchedContinuation::PushCallback(const std::string& type, 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 = continuationCallbackMap_[type];
169 for (auto ele = vecCallback.begin(); ele != vecCallback.end(); ++ele) {
170 if ((*ele) == callback) {
171 HILOGE("type:%{public}s, callback already exists!", type.c_str());
172 return false;
173 }
174 }
175 vecCallback.push_back(callback);
176 continuationCallbackMap_[type] = vecCallback;
177 callback->AddDeathRecipient(diedListener_);
178 return true;
179 }
180
PushCallback(int32_t missionId,const sptr<IRemoteObject> & callback,std::string deviceId,bool isFreeInstall)181 bool DSchedContinuation::PushCallback(int32_t missionId, const sptr<IRemoteObject>& callback,
182 std::string deviceId, bool isFreeInstall)
183 {
184 HILOGI("DSchedContinuation PushCallback start!");
185 if (callback == nullptr) {
186 HILOGE("callback null!");
187 return false;
188 }
189
190 if (continuationHandler_ == nullptr) {
191 HILOGE("not initialized!");
192 return false;
193 }
194
195 std::lock_guard<std::mutex> autoLock(continuationLock_);
196 auto iterSession = callbackMap_.find(missionId);
197 if (iterSession != callbackMap_.end()) {
198 HILOGE("missionId:%{public}d exist!", missionId);
199 return false;
200 }
201 (void)callbackMap_.emplace(missionId, callback);
202 (void)continuationDevices_.emplace(missionId, deviceId);
203 if (isFreeInstall) {
204 freeInstall_[missionId] = isFreeInstall;
205 }
206 return true;
207 }
208
GetCallback(const std::string & type)209 std::vector<sptr<IRemoteObject>> DSchedContinuation::GetCallback(const std::string& type)
210 {
211 std::lock_guard<std::mutex> autoLock(continuationLock_);
212 return continuationCallbackMap_[type];
213 }
214
CleanupCallback(const std::string & type,const sptr<IRemoteObject> & callback)215 bool DSchedContinuation::CleanupCallback(const std::string& type, const sptr<IRemoteObject>& callback)
216 {
217 std::lock_guard<std::mutex> autoLock(continuationLock_);
218 std::vector<sptr<IRemoteObject>> vecCallback = continuationCallbackMap_[type];
219 if (vecCallback.empty()) {
220 HILOGE("PopCallback not found, type:%{public}s", type.c_str());
221 return false;
222 }
223 for (auto ele = vecCallback.begin(); ele != vecCallback.end(); ++ele) {
224 if ((*ele) == callback) {
225 vecCallback.erase(ele);
226 continuationCallbackMap_[type] = vecCallback;
227 HILOGI("type:%{public}s, callback is exists, cleared successfully.", type.c_str());
228 return true;
229 }
230 }
231 HILOGI("type:%{public}s, callback is not exists!", type.c_str());
232 return false;
233 }
234
PopCallback(int32_t missionId)235 sptr<IRemoteObject> DSchedContinuation::PopCallback(int32_t missionId)
236 {
237 std::lock_guard<std::mutex> autoLock(continuationLock_);
238 auto iter = callbackMap_.find(missionId);
239 if (iter == callbackMap_.end()) {
240 HILOGW("PopCallback not found missionId:%{public}d", missionId);
241 return nullptr;
242 }
243 sptr<IRemoteObject> callback = iter->second;
244
245 auto iteration = continuationDevices_.find(missionId);
246 if (iteration != continuationDevices_.end()) {
247 HILOGD("%{public}d need pop from continuationDevices_", missionId);
248 (void)continuationDevices_.erase(iteration);
249 }
250
251 auto it = freeInstall_.find(missionId);
252 if (it != freeInstall_.end()) {
253 HILOGD("%{public}d need pop from freeInstall_", missionId);
254 (void)freeInstall_.erase(it);
255 }
256 (void)cleanMission_.erase(missionId);
257 (void)callbackMap_.erase(iter);
258 return callback;
259 }
260
NotifyDSchedEventResult(const std::string & type,int32_t resultCode)261 int32_t DSchedContinuation::NotifyDSchedEventResult(const std::string& type, int32_t resultCode)
262 {
263 HILOGI("GetCallback IDSchedEventListener");
264 std::vector<sptr<IRemoteObject>> vecCallback = GetCallback(type);
265 if (vecCallback.empty()) {
266 HILOGD("No listening has been registered, no need to report events");
267 return INVALID_PARAMETERS_ERR;
268 }
269 int32_t error = -1;
270 for (auto callback = vecCallback.begin(); callback != vecCallback.end(); ++callback) {
271 MessageParcel data;
272 if (!data.WriteInterfaceToken(DSCHED_EVENT_TOKEN)) {
273 HILOGE("NotifyMissionCenterResult write token failed");
274 return INVALID_PARAMETERS_ERR;
275 }
276 PARCEL_WRITE_HELPER_RET(data, Int32, resultCode, false);
277 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.srcNetworkId, false);
278 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.dstNetworkId, false);
279 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.bundleName, false);
280 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.moduleName, false);
281 PARCEL_WRITE_HELPER_RET(data, String, continueEvent_.abilityName, false);
282 MessageParcel reply;
283 MessageOption option;
284 error = (*callback)->SendRequest(DSCHED_EVENT_CALLBACK, data, reply, option);
285 HILOGI("NotifyDSchedEventListenerResult transact result: %{public}d", error);
286 }
287 return error;
288 }
289
NotifyMissionCenterResult(int32_t missionId,int32_t resultCode)290 int32_t DSchedContinuation::NotifyMissionCenterResult(int32_t missionId, int32_t resultCode)
291 {
292 sptr<IRemoteObject> callback = PopCallback(missionId);
293 RemoveTimeOut(missionId);
294 if (callback == nullptr) {
295 HILOGE("NotifyMissionCenterResult callback is null");
296 return INVALID_PARAMETERS_ERR;
297 }
298
299 MessageParcel data;
300 if (!data.WriteInterfaceToken(NAPI_MISSION_CENTER_INTERFACE_TOKEN)) {
301 HILOGE("NotifyMissionCenterResult write token failed");
302 return INVALID_PARAMETERS_ERR;
303 }
304 PARCEL_WRITE_HELPER_RET(data, Int32, resultCode, INVALID_PARAMETERS_ERR);
305 MessageParcel reply;
306 MessageOption option;
307 int32_t error = callback->SendRequest(NOTIFY_MISSION_CENTER_RESULT, data, reply, option);
308 HILOGI("NotifyMissionCenterResult transact result: %{public}d", error);
309 return error;
310 }
311
ProcessEvent(const InnerEvent::Pointer & event)312 void DSchedContinuation::ContinuationHandler::ProcessEvent(const InnerEvent::Pointer& event)
313 {
314 if (event == nullptr) {
315 HILOGE("ProcessEvent event nullptr!");
316 return;
317 }
318
319 auto eventId = event->GetInnerEventId();
320 int32_t sessionId = static_cast<int32_t>(eventId);
321 if (sessionId <= 0) {
322 HILOGW("ProcessEvent sessionId invalid!");
323 return;
324 }
325
326 if (contCallback_ != nullptr) {
327 contCallback_(sessionId);
328 }
329 }
330
SetCleanMissionFlag(int32_t missionId,bool isCleanMission)331 void DSchedContinuation::SetCleanMissionFlag(int32_t missionId, bool isCleanMission)
332 {
333 std::lock_guard<std::mutex> autoLock(continuationLock_);
334 cleanMission_.emplace(missionId, isCleanMission);
335 }
336
IsCleanMission(int32_t missionId)337 bool DSchedContinuation::IsCleanMission(int32_t missionId)
338 {
339 std::lock_guard<std::mutex> autoLock(continuationLock_);
340 auto iter = cleanMission_.find(missionId);
341 if (iter != cleanMission_.end()) {
342 HILOGD("Application need not exit after continue, missionId:%{public}d exist!", missionId);
343 return iter->second;
344 }
345 return true;
346 }
347 } // namespace DistributedSchedule
348 } // namespace OHOS
349