• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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