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