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