1 /*
2  * Copyright (c) 2022 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 "work_conn_manager.h"
16 
17 #include <hisysevent.h>
18 #include <if_system_ability_manager.h>
19 #include <ipc_skeleton.h>
20 #include <iservice_registry.h>
21 #include <string_ex.h>
22 #include <system_ability_definition.h>
23 
24 #include "ability_manager_client.h"
25 #include "ability_manager_proxy.h"
26 #include "work_sched_hilog.h"
27 #include "work_sched_utils.h"
28 #include "errors.h"
29 
30 #ifdef DEVICE_STANDBY_ENABLE
31 #include "standby_service_client.h"
32 #endif // DEVICE_STANDBY_ENABLE
33 
34 using namespace std;
35 using namespace OHOS::AAFwk;
36 using namespace OHOS::HiviewDFX;
37 
38 namespace OHOS {
39 namespace WorkScheduler {
40 const std::string PARAM_APP_CLONE_INDEX_KEY = "ohos.extra.param.key.appCloneIndex";
41 
AddConnInfo(string & workId,sptr<WorkSchedulerConnection> & connection)42 void WorkConnManager::AddConnInfo(string &workId, sptr<WorkSchedulerConnection> &connection)
43 {
44     std::lock_guard<ffrt::mutex> lock(connMapMutex_);
45     connMap_.emplace(workId, connection);
46 }
47 
RemoveConnInfo(string & workId)48 void WorkConnManager::RemoveConnInfo(string &workId)
49 {
50     std::lock_guard<ffrt::mutex> lock(connMapMutex_);
51     connMap_.erase(workId);
52 }
53 
GetConnInfo(string & workId)54 sptr<WorkSchedulerConnection> WorkConnManager::GetConnInfo(string &workId)
55 {
56     std::lock_guard<ffrt::mutex> lock(connMapMutex_);
57     if (connMap_.count(workId) > 0) {
58         return connMap_.at(workId);
59     }
60     return nullptr;
61 }
62 
StartWork(shared_ptr<WorkStatus> workStatus)63 bool WorkConnManager::StartWork(shared_ptr<WorkStatus> workStatus)
64 {
65     if (GetConnInfo(workStatus->workId_)) {
66         WS_HILOGE("Work has started with id: %{public}s, bundleName: %{public}s, abilityName: %{public}s",
67             workStatus->workId_.c_str(), workStatus->bundleName_.c_str(), workStatus->abilityName_.c_str());
68         return false;
69     }
70 
71     if (!workStatus->workInfo_->GetExtension()) {
72         WS_HILOGE("Work %{public}s extension's type is not workScheduler, connect failed",
73             workStatus->bundleName_.c_str());
74         return false;
75     }
76 
77     WS_HILOGD("Start Work with id: %{public}s, bundleName: %{public}s, abilityName: %{public}s",
78         workStatus->workId_.c_str(), workStatus->bundleName_.c_str(), workStatus->abilityName_.c_str());
79     sptr<ISystemAbilityManager> systemAbilityManager =
80         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
81     if (systemAbilityManager == nullptr) {
82         WS_HILOGE("Failed to get system ability manager service.");
83         return false;
84     }
85     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(ABILITY_MGR_SERVICE_ID);
86     if (remoteObject == nullptr) {
87         WS_HILOGE("Failed to ability manager service.");
88         return false;
89     }
90     sptr<AAFwk::IAbilityManager> abilityMgr_ = iface_cast<AAFwk::IAbilityManager>(remoteObject);
91     if ((abilityMgr_ == nullptr) || (abilityMgr_->AsObject() == nullptr)) {
92         WS_HILOGE("Failed to get ability manager services object");
93         return false;
94     }
95 
96     WS_HILOGI("Begin to connect bundle:%{public}s, abilityName:%{public}s, userId:%{public}d",
97         workStatus->bundleName_.c_str(), workStatus->abilityName_.c_str(), workStatus->userId_);
98     sptr<WorkSchedulerConnection> connection(new (std::nothrow) WorkSchedulerConnection(workStatus->workInfo_));
99     if (connection == nullptr) {
100         WS_HILOGE("Failed to new connection.");
101         return false;
102     }
103 
104     Want want;
105     want.SetElementName(workStatus->bundleName_, workStatus->abilityName_);
106     want.SetParam(PARAM_APP_CLONE_INDEX_KEY, workStatus->workInfo_->GetAppIndex());
107     int32_t ret = abilityMgr_->ConnectAbility(want, connection, nullptr, workStatus->userId_);
108     if (ret != ERR_OK) {
109         WS_HILOGE("connect failed");
110         return false;
111     }
112     AddConnInfo(workStatus->workId_, connection);
113 
114     // Notify work add event to battery statistics
115     WriteStartWorkEvent(workStatus);
116 
117     return true;
118 }
119 
DisConnect(sptr<WorkSchedulerConnection> connect)120 bool WorkConnManager::DisConnect(sptr<WorkSchedulerConnection> connect)
121 {
122     sptr<ISystemAbilityManager> systemAbilityManager =
123         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
124     if (systemAbilityManager == nullptr) {
125         WS_HILOGE("Failed to get system ability manager service.");
126         return false;
127     }
128     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(ABILITY_MGR_SERVICE_ID);
129     if (remoteObject == nullptr) {
130         WS_HILOGE("Failed to ability manager service.");
131         return false;
132     }
133     sptr<AAFwk::IAbilityManager> abilityMgr_ = iface_cast<AAFwk::IAbilityManager>(remoteObject);
134     if ((abilityMgr_ == nullptr) || (abilityMgr_->AsObject() == nullptr)) {
135         WS_HILOGE("Failed to  get ability manager services object.");
136         return false;
137     }
138     int32_t ret = abilityMgr_->DisconnectAbility(connect);
139     if (ret != ERR_OK) {
140         WS_HILOGE("disconnect failed");
141         return false;
142     }
143     return true;
144 }
145 
StopWork(shared_ptr<WorkStatus> workStatus,bool isTimeOut)146 bool WorkConnManager::StopWork(shared_ptr<WorkStatus> workStatus, bool isTimeOut)
147 {
148     bool ret = false;
149     sptr<WorkSchedulerConnection> conn = GetConnInfo(workStatus->workId_);
150     if (!conn) {
151         WS_HILOGE("%{public}s %{public}d connection is null", workStatus->workId_.c_str(), isTimeOut);
152         return false;
153     }
154     if (!conn->IsConnected()) {
155         WS_HILOGE("%{public}s %{public}d is not connected, work will be stopped  by timeout",
156             workStatus->workId_.c_str(), isTimeOut);
157         return false;
158     }
159     conn->StopWork();
160     ret = DisConnect(conn);
161 
162     RemoveConnInfo(workStatus->workId_);
163 
164     // Notify work remove event to battery statistics only work has started
165     if (ret) {
166         int32_t pid = IPCSkeleton::GetCallingPid();
167         workStatus->duration_ += WorkSchedUtils::GetCurrentTimeMs() - workStatus->workStartTime_;
168         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::WORK_SCHEDULER, "WORK_STOP",
169             HiSysEvent::EventType::STATISTIC, "UID",
170             workStatus->uid_, "PID", pid, "NAME", workStatus->bundleName_, "WORKID", workStatus->workId_,
171             "REASON", isTimeOut, "DURATION", workStatus->duration_);
172 #ifdef DEVICE_STANDBY_ENABLE
173         WS_HILOGI("OnWorkStop uid: %{public}d, duration:%{public}" PRIu64 ", startTime:%{public}" PRIu64,
174             workStatus->uid_, workStatus->duration_, workStatus->workStartTime_);
175         DevStandbyMgr::StandbyServiceClient::GetInstance().ReportWorkSchedulerStatus(false,
176             workStatus->uid_, workStatus->bundleName_);
177 #endif // DEVICE_STANDBY_ENABLE
178     }
179     return ret;
180 }
181 
WriteStartWorkEvent(shared_ptr<WorkStatus> workStatus)182 void WorkConnManager::WriteStartWorkEvent(shared_ptr<WorkStatus> workStatus)
183 {
184     int32_t pid = IPCSkeleton::GetCallingPid();
185     string conditions = "";
186     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::NETWORK) > 0) {
187         conditions.append("NETWORK-");
188     }
189 
190     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::CHARGER) > 0) {
191         conditions.append("CHARGER-");
192     }
193 
194     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::BATTERY_STATUS) > 0) {
195         conditions.append("BATTERY_STATUS-");
196     }
197 
198     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::BATTERY_LEVEL) > 0) {
199         conditions.append("BATTERY_LEVEL-");
200     }
201 
202     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::STORAGE) > 0) {
203         conditions.append("STORAGE-");
204     }
205 
206     if (workStatus->workInfo_->GetConditionMap()->count(WorkCondition::Type::TIMER) > 0) {
207         conditions.append("TIMER-");
208     }
209     conditions.pop_back();
210 
211     string type = "Repeat";
212     if (!workStatus->workInfo_->IsRepeat()) {
213         type = "Not Repeat";
214     }
215 
216     HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::WORK_SCHEDULER, "WORK_START",
217         HiSysEvent::EventType::STATISTIC, "UID",
218         workStatus->uid_, "PID", pid, "NAME", workStatus->bundleName_, "WORKID", workStatus->workId_, "TRIGGER",
219         conditions, "TYPE", type, "INTERVAL", workStatus->workInfo_->GetTimeInterval(),
220         "DELAY_REASON", workStatus->delayReason_);
221 #ifdef DEVICE_STANDBY_ENABLE
222     WS_HILOGI("OnWorkStart uid: %{public}d", workStatus->uid_);
223     DevStandbyMgr::StandbyServiceClient::GetInstance().ReportWorkSchedulerStatus(true,
224         workStatus->uid_, workStatus->bundleName_);
225 #endif // DEVICE_STANDBY_ENABLE
226 }
227 } // namespace WorkScheduler
228 } // namespace OHOS
229