1 /*
2  * Copyright (c) 2022-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 #include "bundle_active_core.h"
16 #include "app_group_callback_info.h"
17 #include "bundle_active_user_history.h"
18 #include "bundle_active_log.h"
19 #include "bundle_active_util.h"
20 
21 namespace OHOS {
22 namespace DeviceUsageStats {
23 using namespace DeviceUsageStatsGroupConst;
24 using namespace std;
25 
BundleActivePackageHistory()26 BundleActivePackageHistory::BundleActivePackageHistory()
27 {
28     bundleName_ = "";
29     lastBootFromUsedTimeStamp_ = 0;
30     lastScreenUsedTimeStamp_ = 0;
31     lastGroupCalculatedTimeStamp_ = 0;
32     currentGroup_ = DeviceUsageStatsGroupConst::ACTIVE_GROUP_NEVER;
33     reasonInGroup_ = DeviceUsageStatsGroupConst::GROUP_CONTROL_REASON_DEFAULT;
34     bundleAliveTimeoutTimeStamp_ = 0;
35     bundleDailyTimeoutTimeStamp_ = 0;
36     uid_ = 0;
37     lastCalculatedGroup_ = ACTIVE_GROUP_NEVER;
38     isChanged_ = false;
39 };
40 
WriteDeviceDuration()41 void BundleActiveUserHistory::WriteDeviceDuration()
42 {
43     database_.PutDurationData(bootBasedDuration_, ScreenOnDuration_);
44 }
45 
WriteBundleUsage(const int32_t userId)46 void BundleActiveUserHistory::WriteBundleUsage(const int32_t userId)
47 {
48     BUNDLE_ACTIVE_LOGI("WriteBundleUsage called");
49     auto userHistory = GetUserHistory(userId, false);
50     if (userHistory == nullptr) {
51         BUNDLE_ACTIVE_LOGI("WriteBundleUsage called, no existed user history, return");
52         return;
53     }
54     database_.PutBundleHistoryData(userId, userHistory);
55 }
56 
OnBundleUninstalled(const int32_t userId,const std::string bundleName,const int32_t uid,const int32_t appIndex)57 void BundleActiveUserHistory::OnBundleUninstalled(const int32_t userId, const std::string bundleName,
58     const int32_t uid, const int32_t appIndex)
59 {
60     database_.OnPackageUninstalled(userId, bundleName, uid, appIndex);
61 }
62 
BundleActiveUserHistory(const int64_t bootBasedTimeStamp,const std::shared_ptr<BundleActiveCore> & bundleActiveCore)63 BundleActiveUserHistory::BundleActiveUserHistory(const int64_t bootBasedTimeStamp,
64     const std::shared_ptr<BundleActiveCore>& bundleActiveCore)
65 {
66     bootBasedTimeStamp_ = bootBasedTimeStamp;
67     screenOnTimeStamp_ = bootBasedTimeStamp;
68     database_.InitUsageGroupDatabase(APP_GROUP_DATABASE_INDEX, false);
69     auto bootAndScreenOnDuraton = database_.GetDurationData();
70     bootBasedDuration_ = bootAndScreenOnDuraton.first;
71     ScreenOnDuration_ = bootAndScreenOnDuraton.second;
72     isScreenOn_ = false;
73     if (bundleActiveCore) {
74         bundleActiveCore_ = bundleActiveCore;
75     }
76 }
77 
GetLevelIndex(const string & bundleName,const int32_t userId,const int64_t bootBasedTimeStamp,const std::vector<int64_t> screenTimeLevel,const std::vector<int64_t> bootFromTimeLevel,const int32_t uid)78 int32_t BundleActiveUserHistory::GetLevelIndex(const string& bundleName, const int32_t userId,
79     const int64_t bootBasedTimeStamp, const std::vector<int64_t> screenTimeLevel,
80     const std::vector<int64_t> bootFromTimeLevel, const int32_t uid)
81 {
82     auto oneUserHistory = GetUserHistory(userId, false);
83     if (oneUserHistory == nullptr) {
84         return -1;
85     }
86     auto oneBundleHistory = GetUsageHistoryInUserHistory(oneUserHistory, bundleName, bootBasedTimeStamp, false, uid);
87     if (oneBundleHistory == nullptr) {
88         return -1;
89     }
90     int64_t screenDiff = GetScreenOnTimeStamp(bootBasedTimeStamp) - oneBundleHistory->lastScreenUsedTimeStamp_;
91     int64_t bootFromDiff = GetBootBasedTimeStamp(bootBasedTimeStamp) - oneBundleHistory->lastBootFromUsedTimeStamp_;
92     BUNDLE_ACTIVE_LOGI("screendiff is %{public}lld, bootfromdiff is %{public}lld, bundle name is %{public}s,"
93         "userid is %{public}d",
94         (long long)screenDiff, (long long)bootFromDiff, bundleName.c_str(), userId);
95     for (int32_t i = 3; i >= 0; i--) {
96         if (screenDiff >= screenTimeLevel[i] && bootFromDiff >= bootFromTimeLevel[i]) {
97             return i;
98         }
99     }
100     return -1;
101 }
102 
GetBootBasedTimeStamp(int64_t bootBasedTimeStamp)103 int64_t BundleActiveUserHistory::GetBootBasedTimeStamp(int64_t bootBasedTimeStamp)
104 {
105     return bootBasedTimeStamp - bootBasedTimeStamp_ + bootBasedDuration_;
106 }
107 
GetScreenOnTimeStamp(int64_t bootBasedTimeStamp)108 int64_t BundleActiveUserHistory::GetScreenOnTimeStamp(int64_t bootBasedTimeStamp)
109 {
110     int64_t result = ScreenOnDuration_;
111     if (isScreenOn_) {
112         result += bootBasedTimeStamp - screenOnTimeStamp_;
113     }
114     return result;
115 }
116 
GetUserHistory(const int32_t userId,const bool create)117 shared_ptr<map<string, shared_ptr<BundleActivePackageHistory>>> BundleActiveUserHistory::GetUserHistory(
118     const int32_t userId, const bool create)
119 {
120     auto it = userHistory_.find(userId);
121     if ((it == userHistory_.end()) && create) {
122         shared_ptr<map<string, shared_ptr<BundleActivePackageHistory>>> usageHistoryInserted =
123             database_.GetBundleHistoryData(userId);
124         if (!usageHistoryInserted) {
125             BUNDLE_ACTIVE_LOGI("GetUserHistory READ FROM DATABASE FAILD");
126             usageHistoryInserted =
127                 make_shared<map<string, shared_ptr<BundleActivePackageHistory>>>();
128         }
129         BUNDLE_ACTIVE_LOGI("GetUserHistory usageHistoryInserted not null");
130         userHistory_[userId] = usageHistoryInserted;
131     }
132 
133     if (it == userHistory_.end() && !create) {
134         return nullptr;
135     }
136     return userHistory_[userId];
137 }
138 
GetUsageHistoryInUserHistory(shared_ptr<map<string,shared_ptr<BundleActivePackageHistory>>> oneUserHistory,string bundleName,int64_t bootBasedTimeStamp,const bool create,const int32_t uid)139 shared_ptr<BundleActivePackageHistory> BundleActiveUserHistory::GetUsageHistoryInUserHistory(
140     shared_ptr<map<string, shared_ptr<BundleActivePackageHistory>>> oneUserHistory,
141     string bundleName, int64_t bootBasedTimeStamp, const bool create, const int32_t uid)
142 {
143     if (!oneUserHistory) {
144         return nullptr;
145     }
146     std::string userHistoryKey = BundleActiveUtil::GetBundleUsageKey(bundleName, uid);
147     auto it = oneUserHistory->find(userHistoryKey);
148     if ((it == oneUserHistory->end()) && create) {
149         shared_ptr<BundleActivePackageHistory> usageHistoryInserted =
150             make_shared<BundleActivePackageHistory>();
151         usageHistoryInserted->bundleName_ = bundleName;
152         usageHistoryInserted->lastBootFromUsedTimeStamp_ = GetBootBasedTimeStamp(bootBasedTimeStamp);
153         usageHistoryInserted->lastScreenUsedTimeStamp_ = GetScreenOnTimeStamp(bootBasedTimeStamp);
154         usageHistoryInserted->currentGroup_ = ACTIVE_GROUP_NEVER;
155         usageHistoryInserted->reasonInGroup_ = GROUP_CONTROL_REASON_DEFAULT;
156         usageHistoryInserted->bundleAliveTimeoutTimeStamp_ = 0;
157         usageHistoryInserted->bundleDailyTimeoutTimeStamp_ = 0;
158         usageHistoryInserted->uid_ = uid;
159         (*oneUserHistory)[userHistoryKey] = usageHistoryInserted;
160     }
161     return (*oneUserHistory)[userHistoryKey];
162 }
163 
GetUsageHistoryForBundle(const string & bundleName,const int32_t userId,const int64_t bootBasedTimeStamp,const bool create,const int32_t uid)164 shared_ptr<BundleActivePackageHistory> BundleActiveUserHistory::GetUsageHistoryForBundle(
165     const string& bundleName, const int32_t userId, const int64_t bootBasedTimeStamp, const bool create,
166     const int32_t uid)
167 {
168     auto oneUserHistory = GetUserHistory(userId, create);
169     if (!oneUserHistory) {
170         return nullptr;
171     }
172     auto oneBundleHistory = GetUsageHistoryInUserHistory(oneUserHistory, bundleName, bootBasedTimeStamp, create, uid);
173     if (!oneBundleHistory) {
174         return nullptr;
175     }
176     return oneBundleHistory;
177 }
178 
ReportUsage(shared_ptr<BundleActivePackageHistory> oneBundleUsageHistory,const string & bundleName,const int32_t newGroup,const uint32_t groupReason,const int64_t bootBasedTimeStamp,const int64_t timeUntilNextCheck,const int32_t userId,const int32_t uid)179 void BundleActiveUserHistory::ReportUsage(shared_ptr<BundleActivePackageHistory> oneBundleUsageHistory,
180     const string& bundleName, const int32_t newGroup, const uint32_t groupReason, const int64_t bootBasedTimeStamp,
181     const int64_t timeUntilNextCheck, const int32_t userId, const int32_t uid)
182 {
183     if ((oneBundleUsageHistory->reasonInGroup_ & GROUP_CONTROL_REASON_MASK) == GROUP_CONTROL_REASON_FORCED) {
184         return;
185     }
186     if (timeUntilNextCheck > bootBasedTimeStamp) {
187         int64_t nextCheckTimeStamp = bootBasedDuration_ + (timeUntilNextCheck - bootBasedTimeStamp_);
188         if (newGroup == ACTIVE_GROUP_ALIVE) {
189             oneBundleUsageHistory->bundleAliveTimeoutTimeStamp_ = max(nextCheckTimeStamp,
190                 oneBundleUsageHistory->bundleAliveTimeoutTimeStamp_);
191         } else if (newGroup == ACTIVE_GROUP_DAILY) {
192             oneBundleUsageHistory->bundleDailyTimeoutTimeStamp_ = max(nextCheckTimeStamp,
193                 oneBundleUsageHistory->bundleDailyTimeoutTimeStamp_);
194         } else {
195             return;
196         }
197     }
198     if (bootBasedTimeStamp > 0) {
199         oneBundleUsageHistory->lastBootFromUsedTimeStamp_ = bootBasedDuration_ +
200             (bootBasedTimeStamp - bootBasedTimeStamp_);
201         oneBundleUsageHistory->lastScreenUsedTimeStamp_ = GetScreenOnTimeStamp(bootBasedTimeStamp);
202     }
203     int32_t oldGroup = oneBundleUsageHistory->currentGroup_;
204     if (oneBundleUsageHistory->currentGroup_ > newGroup) {
205         oneBundleUsageHistory->currentGroup_ = newGroup;
206     }
207     oneBundleUsageHistory->reasonInGroup_ = GROUP_CONTROL_REASON_USAGE | groupReason;
208     oneBundleUsageHistory->isChanged_ = true;
209     BUNDLE_ACTIVE_LOGD("RegisterAppGroupCallBack will ReportUsage");
210     bool isGroupChanged = (oldGroup == oneBundleUsageHistory->currentGroup_) ? false : true;
211     if (isGroupChanged) {
212         AppGroupCallbackInfo callbackInfo(
213             userId, oldGroup, newGroup, oneBundleUsageHistory->reasonInGroup_, bundleName);
214         BUNDLE_ACTIVE_LOGI("RegisterAppGroupCallBack AppGroupCallbackInfo build success");
215         if (!bundleActiveCore_.expired()) {
216             BUNDLE_ACTIVE_LOGD("RegisterAppGroupCallBack will callback!");
217             bundleActiveCore_.lock()->OnAppGroupChanged(callbackInfo);
218         }
219     }
220 }
221 
SetAppGroup(const string & bundleName,const int32_t userId,const int32_t uid,const int64_t bootBasedTimeStamp,int32_t newGroup,uint32_t groupReason,const bool isFlush)222 int32_t BundleActiveUserHistory::SetAppGroup(const string& bundleName, const int32_t userId, const int32_t uid,
223     const int64_t bootBasedTimeStamp, int32_t newGroup, uint32_t groupReason, const bool isFlush)
224 {
225     std::lock_guard<ffrt::mutex> lock(setGroupMutex_);
226     BUNDLE_ACTIVE_LOGI("set %{public}s to group %{public}d, reason is %{public}d, userId is %{public}d",
227         bundleName.c_str(), newGroup, groupReason, userId);
228     shared_ptr<map<string, shared_ptr<BundleActivePackageHistory>>> userBundleHistory = GetUserHistory(userId, false);
229     if (!userBundleHistory) {
230         return ERR_GET_BUNDLE_USED_HISTORY_FAILED;
231     }
232     shared_ptr<BundleActivePackageHistory> oneBundleHistory = GetUsageHistoryInUserHistory(userBundleHistory,
233         bundleName, bootBasedTimeStamp, false, uid);
234     if (!oneBundleHistory) {
235         return ERR_GET_BUNDLE_USED_HISTORY_FAILED;
236     }
237     if (oneBundleHistory->currentGroup_ == newGroup && oneBundleHistory->reasonInGroup_ == groupReason) {
238         BUNDLE_ACTIVE_LOGI("%{public}s group and reason is same as before, not update", bundleName.c_str());
239         return ERR_REPEAT_SET_APP_GROUP;
240     }
241     int32_t oldGroup = oneBundleHistory->currentGroup_;
242     oneBundleHistory->currentGroup_ = newGroup;
243     oneBundleHistory->reasonInGroup_ = groupReason;
244     oneBundleHistory->isChanged_ = true;
245     BUNDLE_ACTIVE_LOGI("SetAppGroup set success");
246     if (isFlush) {
247         WriteBundleUsage(userId);
248     }
249 
250     bool isGroupChanged = (oldGroup == newGroup) ? true : false;
251     if (!isGroupChanged) {
252         AppGroupCallbackInfo callbackInfo(
253             userId, oldGroup, newGroup, oneBundleHistory->reasonInGroup_, bundleName);
254         if (!bundleActiveCore_.expired()) {
255             bundleActiveCore_.lock()->OnAppGroupChanged(callbackInfo);
256         }
257     }
258     return ERR_OK;
259 }
260 
UpdateBootBasedAndScreenTime(const bool & isScreenOn,const int64_t bootBasedTimeStamp,const bool & isShutdown)261 void BundleActiveUserHistory::UpdateBootBasedAndScreenTime(const bool& isScreenOn, const int64_t bootBasedTimeStamp,
262     const bool& isShutdown)
263 {
264     if (isScreenOn_ == isScreenOn && isShutdown == false) {
265         return;
266     }
267     isScreenOn_ = isScreenOn;
268     if (isScreenOn_) {
269         screenOnTimeStamp_ = bootBasedTimeStamp;
270     } else {
271         ScreenOnDuration_ += bootBasedTimeStamp - screenOnTimeStamp_;
272         bootBasedDuration_ += bootBasedTimeStamp - bootBasedTimeStamp_;
273         bootBasedTimeStamp_ = bootBasedTimeStamp;
274     }
275     database_.PutDurationData(bootBasedDuration_, ScreenOnDuration_);
276 }
277 
PrintData(int32_t userId)278 void BundleActiveUserHistory::PrintData(int32_t userId)
279 {
280     auto oneUserHistory = GetUserHistory(userId, false);
281     BUNDLE_ACTIVE_LOGI("PrintData screen is %{public}d", isScreenOn_);
282     if (oneUserHistory == nullptr) {
283         return;
284     }
285     for (auto oneBundleUsage : (*oneUserHistory)) {
286         BUNDLE_ACTIVE_LOGI("bundle name is %{public}s, lastBootFromUsedTimeStamp_ is %{public}lld, "
287             "lastScreenUsedTimeStamp_ is %{public}lld, currentGroup_ is %{public}d, reasonInGroup_ is %{public}d, "
288             "daily time out %{public}lld, alive time out %{public}lld", oneBundleUsage.first.c_str(),
289             (long long)oneBundleUsage.second->lastBootFromUsedTimeStamp_,
290             (long long)oneBundleUsage.second->lastScreenUsedTimeStamp_,
291             oneBundleUsage.second->currentGroup_, oneBundleUsage.second->reasonInGroup_,
292             (long long)oneBundleUsage.second->bundleDailyTimeoutTimeStamp_,
293             (long long)oneBundleUsage.second->bundleAliveTimeoutTimeStamp_);
294     }
295 }
296 }  // namespace DeviceUsageStats
297 }  // namespace OHOS
298 
299