1 /*
2  * Copyright (c) 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 "res_type.h"
17 #include "ressched_utils.h"
18 #include "app_startup_scene_rec.h"
19 #include "cgroup_sched_log.h"
20 namespace OHOS {
21 namespace ResourceSchedule {
22 static const int32_t CONTINUOUS_START_TIME_OUT = 15 * 1000 * 1000;
23 static const int32_t MAX_NO_REPEAT_APP_COUNT = 4;
24 static const int32_t MAX_CONTINUOUS_START_NUM = 5;
25 static const int32_t APP_START_UP = 0;
26 static const std::string RUNNER_NAME = "AppStartupSceneRecQueue";
AppStartupSceneRec()27 AppStartupSceneRec::AppStartupSceneRec()
28 {
29 }
~AppStartupSceneRec()30 AppStartupSceneRec::~AppStartupSceneRec()
31 {
32 }
Init()33 void AppStartupSceneRec::Init()
34 {
35     ffrtQueue_ = std::make_shared<ffrt::queue>(RUNNER_NAME.c_str(),
36         ffrt::queue_attr().qos(ffrt::qos_user_initiated));
37 }
Deinit()38 void AppStartupSceneRec::Deinit()
39 {
40     if (exitContinuousStartupTask != nullptr) {
41         ffrtQueue_->cancel(exitContinuousStartupTask);
42         exitContinuousStartupTask = nullptr;
43     }
44     ffrtQueue_.reset();
45     startPkgs_.clear();
46     startUidSet_.clear();
47     startIgnorePkgs_.clear();
48 }
GetInstance()49 AppStartupSceneRec& AppStartupSceneRec::GetInstance()
50 {
51     static AppStartupSceneRec instance;
52     return instance;
53 }
54 
IsAppStartUp(int32_t abilityState)55 bool AppStartupSceneRec::IsAppStartUp(int32_t abilityState)
56 {
57     return abilityState == APP_START_UP;
58 }
59 
RecordIsContinuousStartup(const int32_t abilityState,const std::string uid,const std::string bundleName)60 void AppStartupSceneRec::RecordIsContinuousStartup(const int32_t abilityState, const std::string uid,
61     const std::string bundleName)
62 {
63     if (!IsAppStartUp(abilityState)) {
64         CGS_LOGE("abilityState is not app startUp");
65         return;
66     }
67     if (startIgnorePkgs_.find(bundleName) != startIgnorePkgs_.end()) {
68         CGS_LOGE("recordIsContinuousStartup bundleName: %{public}s is IgnorePkg", bundleName.c_str());
69         return;
70     }
71     if (exitContinuousStartupTask != nullptr) {
72         ffrtQueue_->cancel(exitContinuousStartupTask);
73         exitContinuousStartupTask = nullptr;
74     }
75     auto tarEndTimePoint = std::chrono::steady_clock::now();
76     auto tarDuration = std::chrono::duration_cast<std::chrono::microseconds>(tarEndTimePoint.time_since_epoch());
77     int64_t curTime = tarDuration.count();
78     CGS_LOGI("recordIsContinuousStartup uid: %{public}s bundleName: %{public}s",
79         uid.c_str(), bundleName.c_str());
80     if (curTime - lastAppStartTime_ >= CONTINUOUS_START_TIME_OUT) {
81         CleanRecordSceneData();
82     }
83     UpdateAppStartupNum(uid, curTime, bundleName);
84     if (IsContinuousStartup() && !isReportContinuousStartup_.load()) {
85         nlohmann::json payload;
86         ResSchedUtils::GetInstance().ReportDataInProcess(
87             ResType::RES_TYPE_CONTINUOUS_STARTUP, ResType::ContinuousStartupStatus::START_CONTINUOUS_STARTUP, payload);
88         isReportContinuousStartup_ = true;
89     }
90     exitContinuousStartupTask = ffrtQueue_->submit_h([this] {
91         CleanRecordSceneData();
92     }, ffrt::task_attr().delay(CONTINUOUS_START_TIME_OUT));
93 }
CleanRecordSceneData()94 void AppStartupSceneRec::CleanRecordSceneData()
95 {
96     CGS_LOGI("CleanRecordSceneData");
97     std::unique_lock<ffrt::mutex> lock(mutex_);
98     appStartCount_ = 0;
99     startPkgs_.clear();
100     startUidSet_.clear();
101     exitContinuousStartupTask = nullptr;
102     if (isReportContinuousStartup_.load()) {
103         nlohmann::json payload;
104         ResSchedUtils::GetInstance().ReportDataInProcess(
105             ResType::RES_TYPE_CONTINUOUS_STARTUP, ResType::ContinuousStartupStatus::STOP_CONTINUOUS_STARTUP, payload);
106         isReportContinuousStartup_ = false;
107     }
108 }
UpdateAppStartupNum(const std::string uid,const int64_t curTime,const std::string bundleName)109 void AppStartupSceneRec::UpdateAppStartupNum(const std::string uid, const int64_t curTime,
110     const std::string bundleName)
111 {
112     std::unique_lock<ffrt::mutex> lock(mutex_);
113     lastAppStartTime_ = curTime;
114     appStartCount_++;
115     if (isReportContinuousStartup_.load()) {
116         CGS_LOGI("UpdateAppStartupNum appStartCount_:%{public}d", appStartCount_);
117         return;
118     }
119     startPkgs_.emplace_back(bundleName);
120     startUidSet_.insert(uid);
121 }
IsContinuousStartup()122 bool AppStartupSceneRec::IsContinuousStartup()
123 {
124     std::unique_lock<ffrt::mutex> lock(mutex_);
125     if (startPkgs_.size() >= MAX_CONTINUOUS_START_NUM && startUidSet_.size() >= MAX_NO_REPEAT_APP_COUNT) {
126         return true;
127     }
128     return false;
129 }
130 }
131 }