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
16 #include <cinttypes>
17 #include <sys/resource.h>
18 #include <sched.h>
19 #include <linux/sched.h>
20 #include "rtg_interface.h"
21 #include "ipc_skeleton.h"
22 #include "concurrent_task_log.h"
23 #include "concurrent_task_controller.h"
24 constexpr int TARGET_UID = 3039;
25 using namespace OHOS::RME;
26
27 namespace OHOS {
28 namespace ConcurrentTask {
GetInstance()29 TaskController& TaskController::GetInstance()
30 {
31 static TaskController instance;
32 return instance;
33 }
34
ReportData(uint32_t resType,int64_t value,const Json::Value & payload)35 void TaskController::ReportData(uint32_t resType, int64_t value, const Json::Value& payload)
36 {
37 pid_t uid = IPCSkeleton::GetInstance().GetCallingUid();
38 if (!CheckUid(uid)) {
39 CONCUR_LOGE("only system call can be allowed");
40 return;
41 }
42 Json::ValueType type = payload.type();
43 if (type != Json::objectValue) {
44 CONCUR_LOGE("error payload");
45 return;
46 }
47 if (payload.empty()) {
48 CONCUR_LOGE("payload is empty");
49 return;
50 }
51 std::string strRequstType = "";
52 try {
53 strRequstType = payload["type"].asString();
54 } catch (...) {
55 CONCUR_LOGE("Unexpected type format");
56 return;
57 }
58 if (strRequstType.length() == 0) {
59 CONCUR_LOGE("Get payload type err");
60 return;
61 }
62 int requstType = GetRequestType(strRequstType);
63 DealSystemRequest(requstType, payload);
64 PrintInfo();
65 }
66
QueryInterval(int queryItem,IntervalReply & queryRs)67 void TaskController::QueryInterval(int queryItem, IntervalReply& queryRs)
68 {
69 pid_t uid = IPCSkeleton::GetInstance().GetCallingUid();
70 if (uid == 0) {
71 CONCUR_LOGE("Uid is 0, error query");
72 return;
73 }
74 switch (queryItem) {
75 case QUERY_UI:
76 QueryUi(uid, queryRs);
77 break;
78 case QUERY_RENDER:
79 QueryRender(uid, queryRs);
80 break;
81 case QUERY_RENDER_SERVICE:
82 QueryRenderService(uid, queryRs);
83 break;
84 case QUERY_COMPOSER:
85 QueryHwc(uid, queryRs);
86 break;
87 default:
88 break;
89 }
90 }
91
QueryUi(int uid,IntervalReply & queryRs)92 void TaskController::QueryUi(int uid, IntervalReply& queryRs)
93 {
94 if (uid == SYSTEM_UID) {
95 return;
96 }
97 pid_t pid = IPCSkeleton::GetInstance().GetCallingPid();
98 auto iter = GetRecordOfUid(uid);
99 if (iter == foregroundApp_.end()) {
100 CONCUR_LOGD("Query ui with uid %{public}d failed: pid %{public}d", uid, pid);
101 return;
102 }
103 int grpId = iter->GetGrpId();
104 if (grpId <= 0) {
105 CONCUR_LOGI("%{public}d Query ui with none grpid", uid);
106 queryRs.rtgId = -1;
107 } else {
108 queryRs.rtgId = grpId;
109 }
110 }
111
QueryRender(int uid,IntervalReply & queryRs)112 void TaskController::QueryRender(int uid, IntervalReply& queryRs)
113 {
114 if (uid == SYSTEM_UID) {
115 return;
116 }
117 pid_t pid = IPCSkeleton::GetInstance().GetCallingPid();
118 auto iter = GetRecordOfUid(uid);
119 if (iter == foregroundApp_.end()) {
120 CONCUR_LOGD("Query render with uid %{public}d failed, pid %{public}d", uid, pid);
121 return;
122 }
123 int grpId = iter->GetGrpId();
124 if (grpId <= 0) {
125 CONCUR_LOGI("%{public}d Query render with none grpid", uid);
126 queryRs.rtgId = -1;
127 } else {
128 queryRs.rtgId = grpId;
129 }
130 }
131
QueryRenderService(int uid,IntervalReply & queryRs)132 void TaskController::QueryRenderService(int uid, IntervalReply& queryRs)
133 {
134 if (renderServiceGrpId_ > 0) {
135 CONCUR_LOGD("uid %{public}d query rs group %{public}d.", uid, renderServiceGrpId_);
136 queryRs.rtgId = renderServiceGrpId_;
137 return;
138 }
139 TryCreateRsGroup();
140 queryRs.rtgId = renderServiceGrpId_;
141 CONCUR_LOGE("uid %{public}d query rs group failed and create %{public}d.", uid, renderServiceGrpId_);
142 }
143
QueryHwc(int uid,IntervalReply & queryRs)144 void TaskController::QueryHwc(int uid, IntervalReply& queryRs)
145 {
146 if (uid == SYSTEM_UID) {
147 return;
148 }
149 pid_t pid = IPCSkeleton::GetInstance().GetCallingPid();
150 auto iter = GetRecordOfUid(uid);
151 if (iter == foregroundApp_.end()) {
152 CONCUR_LOGD("Query ipc thread with uid %{public}d failed, pid %{public}d", uid, pid);
153 return;
154 }
155 int grpId = iter->GetGrpId();
156 if (grpId <= 0) {
157 CONCUR_LOGI("%{public}d Query ipc thread with none grpid", uid);
158 queryRs.rtgId = -1;
159 } else {
160 queryRs.rtgId = grpId;
161 }
162 }
163
SetHwcAuth(bool status)164 void TaskController::SetHwcAuth(bool status)
165 {
166 int ret;
167 if (status) {
168 ret = AuthEnable(TARGET_UID, AF_RTG_ALL, static_cast<unsigned int>(AuthStatus::AUTH_STATUS_FOREGROUND));
169 } else {
170 ret = AuthDelete(TARGET_UID);
171 }
172
173 if (ret == 0) {
174 CONCUR_LOGI("set auth status(%{public}d) for %{public}d success", status, TARGET_UID);
175 } else {
176 CONCUR_LOGE("set auth status(%{public}d) for %{public}d fail with ret %{public}d ", status, TARGET_UID, ret);
177 }
178 }
179
Init()180 void TaskController::Init()
181 {
182 SetHwcAuth(true);
183 TypeMapInit();
184 qosManager_.Init();
185 TryCreateRsGroup();
186 }
187
Release()188 void TaskController::Release()
189 {
190 SetHwcAuth(false);
191 msgType_.clear();
192 if (renderServiceGrpId_ <= 0) {
193 return;
194 }
195 DestroyRtgGrp(renderServiceGrpId_);
196 renderServiceGrpId_ = -1;
197 }
198
TypeMapInit()199 void TaskController::TypeMapInit()
200 {
201 msgType_.clear();
202 msgType_.insert(pair<std::string, int>("foreground", MSG_FOREGROUND));
203 msgType_.insert(pair<std::string, int>("background", MSG_BACKGROUND));
204 msgType_.insert(pair<std::string, int>("appStart", MSG_APP_START));
205 msgType_.insert(pair<std::string, int>("appKilled", MSG_APP_KILLED));
206 }
207
TryCreateRsGroup()208 void TaskController::TryCreateRsGroup()
209 {
210 if (!rtgEnabled_) {
211 rtgEnabled_ = EnableRtg(true) < 0 ? false : true;
212 if (!rtgEnabled_) {
213 CONCUR_LOGE("Rtg enable failed");
214 return;
215 }
216 CONCUR_LOGI("Enable Rtg");
217 }
218 renderServiceGrpId_ = CreateNewRtgGrp(PRIO_RT, MAX_KEY_THREADS);
219 if (renderServiceGrpId_ <= 0) {
220 CONCUR_LOGI("CreateRsRtgGroup with RT failed, try change to normal type.");
221 renderServiceGrpId_ = CreateNewRtgGrp(PRIO_NORMAL, MAX_KEY_THREADS);
222 }
223 if (renderServiceGrpId_ <= 0) {
224 CONCUR_LOGI("CreateRsRtgGroup failed! rtGrp:%{public}d", renderServiceGrpId_);
225 }
226 }
227
GetRequestType(std::string strRequstType)228 int TaskController::GetRequestType(std::string strRequstType)
229 {
230 auto iter = msgType_.find(strRequstType);
231 if (iter == msgType_.end()) {
232 return MSG_TYPE_MAX;
233 }
234 return msgType_[strRequstType];
235 }
236
CheckUid(pid_t uid)237 bool TaskController::CheckUid(pid_t uid)
238 {
239 if ((uid != SYSTEM_UID) && (uid != 0)) {
240 return false;
241 }
242 return true;
243 }
244
DealSystemRequest(int requestType,const Json::Value & payload)245 void TaskController::DealSystemRequest(int requestType, const Json::Value& payload)
246 {
247 int appUid = 0;
248 try {
249 appUid = stoi(payload["uid"].asString());
250 } catch (...) {
251 CONCUR_LOGE("Unexpected uid format");
252 }
253 if (appUid < 0) {
254 CONCUR_LOGE("appUid error:%d", appUid);
255 return;
256 }
257 switch (requestType) {
258 case MSG_FOREGROUND:
259 NewForeground(appUid);
260 break;
261 case MSG_BACKGROUND:
262 NewBackground(appUid);
263 break;
264 case MSG_APP_START:
265 NewAppStart(appUid);
266 break;
267 case MSG_APP_KILLED:
268 AppKilled(appUid);
269 break;
270 default:
271 CONCUR_LOGE("Unknown system request");
272 break;
273 }
274 }
275
DealAppRequest(int requestType,const Json::Value & payload,pid_t uid)276 void TaskController::DealAppRequest(int requestType, const Json::Value& payload, pid_t uid)
277 {
278 if (uid <= SYSTEM_UID) {
279 CONCUR_LOGE("Unexpected uid in app req");
280 return;
281 }
282 int tid = 0;
283 try {
284 tid = stoi(payload["tid"].asString());
285 } catch (...) {
286 CONCUR_LOGE("Unexpected tid format");
287 return;
288 }
289 if ((requestType >= MSG_REG_RENDER) && (requestType <= MSG_REG_KEY_THERAD)) {
290 int prioType = PRIO_NORMAL;
291 auto record = GetRecordOfUid(uid);
292 if (record == foregroundApp_.end()) {
293 return;
294 }
295 if (requestType != MSG_REG_KEY_THERAD) {
296 prioType = PRIO_RT;
297 }
298 record->AddKeyThread(tid, prioType);
299 }
300 }
301
GetRecordOfUid(int uid)302 std::list<ForegroundAppRecord>::iterator TaskController::GetRecordOfUid(int uid)
303 {
304 for (auto iter = foregroundApp_.begin(); iter != foregroundApp_.end(); iter++) {
305 if (iter->GetUid() == uid) {
306 return iter;
307 }
308 }
309 return foregroundApp_.end();
310 }
311
NewForeground(int uid)312 void TaskController::NewForeground(int uid)
313 {
314 auto it = find(authApps_.begin(), authApps_.end(), uid);
315 if (it == authApps_.end()) {
316 CONCUR_LOGI("un-authed uid %{public}d", uid);
317 return;
318 }
319 unsigned int uidParam = static_cast<unsigned int>(uid);
320 unsigned int uaFlag = AF_RTG_ALL;
321 unsigned int status = static_cast<unsigned int>(AuthStatus::AUTH_STATUS_FOREGROUND);
322
323 int ret = AuthEnable(uidParam, uaFlag, status);
324 if (ret == 0) {
325 CONCUR_LOGI("auth_enable %{public}d success", uid);
326 } else {
327 CONCUR_LOGE("auth_enable %{public}d fail with ret %{public}d", uid, ret);
328 }
329 bool found = false;
330 for (auto iter = foregroundApp_.begin(); iter != foregroundApp_.end(); iter++) {
331 if (iter->GetUid() == uid) {
332 found = true;
333 CONCUR_LOGI("uid %{public}d is already in foreground.", uid);
334 iter->BeginScene();
335 }
336 }
337 CONCUR_LOGI("uid %{public}d change to foreground.", uid);
338 if (!found) {
339 ForegroundAppRecord *tempRecord = new ForegroundAppRecord(uid);
340 if (tempRecord->IsValid()) {
341 foregroundApp_.push_back(*tempRecord);
342 tempRecord->BeginScene();
343 } else {
344 delete tempRecord;
345 }
346 }
347 }
348
NewBackground(int uid)349 void TaskController::NewBackground(int uid)
350 {
351 auto it = find(authApps_.begin(), authApps_.end(), uid);
352 if (it == authApps_.end()) {
353 CONCUR_LOGI("un-authed uid %{public}d", uid);
354 return;
355 }
356 CONCUR_LOGI("uid %{public}d change to background.", uid);
357 unsigned int uidParam = static_cast<unsigned int>(uid);
358
359 int ret = AuthPause(uidParam);
360 if (ret == 0) {
361 CONCUR_LOGI("auth_pause %{public}d success", uid);
362 } else {
363 CONCUR_LOGI("auth_pause %{public}d fail with %{public}d", uid, ret);
364 }
365 for (auto iter = foregroundApp_.begin(); iter != foregroundApp_.end(); iter++) {
366 if (iter->GetUid() == uid) {
367 iter->EndScene();
368 return;
369 }
370 }
371 }
372
NewAppStart(int uid)373 void TaskController::NewAppStart(int uid)
374 {
375 CONCUR_LOGI("uid %{public}d start.", uid);
376 unsigned int uidParam = static_cast<unsigned int>(uid);
377 unsigned int uaFlag = AF_RTG_ALL;
378 unsigned int status = static_cast<unsigned int>(AuthStatus::AUTH_STATUS_BACKGROUND);
379
380 int ret = AuthEnable(uidParam, uaFlag, status);
381 if (ret == 0) {
382 CONCUR_LOGI("auth_enable %{public}d success", uid);
383 } else {
384 CONCUR_LOGE("auth_enable %{public}d fail with ret %{public}d", uid, ret);
385 }
386 authApps_.push_back(uid);
387 }
388
AppKilled(int uid)389 void TaskController::AppKilled(int uid)
390 {
391 CONCUR_LOGI("uid %{public}d killed.", uid);
392 unsigned int uidParam = static_cast<unsigned int>(uid);
393 int ret = AuthDelete(uidParam);
394 if (ret == 0) {
395 CONCUR_LOGI("auth_delete %{public}d success", uid);
396 } else {
397 CONCUR_LOGE("auth_delete %{public}d fail with %{public}d", uid, ret);
398 }
399 std::lock_guard<std::mutex> lock(appInfoLock_);
400 for (auto iter = foregroundApp_.begin(); iter != foregroundApp_.end(); iter++) {
401 if (iter->GetUid() == uid) {
402 foregroundApp_.erase(iter++);
403 break;
404 }
405 }
406 for (auto iter = authApps_.begin(); iter != authApps_.end(); iter++) {
407 if (*iter == uid) {
408 authApps_.erase(iter++);
409 break;
410 }
411 }
412 }
413
PrintInfo()414 void TaskController::PrintInfo()
415 {
416 for (auto iter = foregroundApp_.begin(); iter != foregroundApp_.end(); iter++) {
417 iter->PrintKeyThreads();
418 }
419 }
420
ForegroundAppRecord(int uid)421 ForegroundAppRecord::ForegroundAppRecord(int uid)
422 {
423 uid_ = uid;
424 grpId_ = CreateNewRtgGrp(PRIO_RT, MAX_KEY_THREADS);
425 if (grpId_ <= 0) {
426 CONCUR_LOGI("CreateNewRtgGroup with RT failed, try change to normal type.");
427 grpId_ = CreateNewRtgGrp(PRIO_NORMAL, MAX_KEY_THREADS);
428 }
429 if (grpId_ <= 0) {
430 CONCUR_LOGI("CreateNewRtgGroup failed! rtGrp:%{public}d, pid: %{public}d", grpId_, uid);
431 }
432 }
433
~ForegroundAppRecord()434 ForegroundAppRecord::~ForegroundAppRecord()
435 {
436 if (grpId_ > 0) {
437 DestroyRtgGrp(grpId_);
438 }
439 }
440
AddKeyThread(int tid,int prio)441 void ForegroundAppRecord::AddKeyThread(int tid, int prio)
442 {
443 int rtgPrio = (prio >= PRIO_NORMAL) ? PRIO_NORMAL : PRIO_RT;
444 if (keyThreads_.find(tid) != keyThreads_.end()) {
445 return;
446 }
447 if (grpId_ <= 0) {
448 CONCUR_LOGI("Add key thread fail: Grp id not been created success.");
449 return;
450 }
451 if (keyThreads_.size() >= MAX_KEY_THREADS) {
452 CONCUR_LOGI("Add key thread fail: Key threads num limit.");
453 return;
454 }
455 if (prio == RPIO_IN) {
456 setpriority(PRIO_PROCESS, tid, -13); // -13 represent spcial nice in qos
457 } else {
458 int ret = AddThreadToRtg(tid, grpId_, rtgPrio);
459 if (ret != 0) {
460 CONCUR_LOGI("Add key thread fail: Kernel err report.");
461 } else {
462 CONCUR_LOGI("Add key thread %{public}d", tid);
463 }
464 keyThreads_.insert(tid);
465 }
466 }
467
BeginScene()468 bool ForegroundAppRecord::BeginScene()
469 {
470 if (grpId_ <= 0) {
471 CONCUR_LOGI("Error begin scene in uid %{public}d", uid_);
472 return false;
473 }
474 OHOS::RME::BeginFrameFreq(grpId_, 0);
475 OHOS::RME::EndFrameFreq(grpId_);
476 return true;
477 }
478
EndScene()479 bool ForegroundAppRecord::EndScene()
480 {
481 if (grpId_ <= 0) {
482 CONCUR_LOGI("Error end scene in uid %{public}d", uid_);
483 return false;
484 }
485 OHOS::RME::EndScene(grpId_);
486 return true;
487 }
488
GetUid()489 int ForegroundAppRecord::GetUid()
490 {
491 return uid_;
492 }
493
GetGrpId()494 int ForegroundAppRecord::GetGrpId()
495 {
496 return grpId_;
497 }
498
IsValid()499 bool ForegroundAppRecord::IsValid()
500 {
501 if (uid_ > 0 && grpId_ > 0) {
502 return true;
503 }
504 return false;
505 }
506
PrintKeyThreads()507 void ForegroundAppRecord::PrintKeyThreads()
508 {
509 std::string strLog = "pid ";
510 strLog.append(std::to_string(uid_));
511 strLog.append(" has key threads: ");
512 for (auto iter = keyThreads_.begin(); iter != keyThreads_.end(); iter++) {
513 std::string temp = std::to_string(*iter);
514 strLog.append(temp);
515 strLog.append(", ");
516 }
517 CONCUR_LOGD("%{public}s", strLog.c_str());
518 }
519 } // namespace ConcurrentTask
520 } // namespace OHOS
521