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
16 #include <unistd.h>
17 #include <cstdlib>
18 #include <map>
19 #include <limits>
20 #include "bundle_active_constant.h"
21 #include "bundle_active_log.h"
22 #include "bundle_active_package_stats.h"
23 #include "bundle_active_period_stats.h"
24 #include "bundle_active_usage_database.h"
25 #include "bundle_active_account_helper.h"
26 #include "bundle_active_bundle_mgr_helper.h"
27 #include "bundle_active_util.h"
28
29 namespace OHOS {
30 namespace DeviceUsageStats {
31 using namespace OHOS::NativeRdb;
32 using namespace std;
33 namespace {
34 const int64_t MIN_START_TIME = 0;
35 }
UpgradeDatabase(const int32_t oldVersion,const int32_t curVersion)36 void BundleActiveUsageDatabase::UpgradeDatabase(const int32_t oldVersion, const int32_t curVersion)
37 {
38 BUNDLE_ACTIVE_LOGI("upgradle database oldVersion: %{public}d, curVersion: %{public}d", oldVersion, curVersion);
39 if (oldVersion < curVersion && curVersion == BUNDLE_ACTIVE_CURRENT_VERSION) {
40 if (oldVersion == BUNDLE_ACTIVE_VERSION_V1) {
41 SupportAppTwin();
42 SupportFirstUseTime();
43 }
44 if (oldVersion == BUNDLE_ACTIVE_VERSION_V2) {
45 SupportFirstUseTime();
46 }
47 currentVersion_ = curVersion;
48 }
49 }
50
SupportAppTwin()51 void BundleActiveUsageDatabase::SupportAppTwin()
52 {
53 vector<vector<string>> allTableName = vector<vector<string>>(ALL_TABLE_ARRAY_NUMBER);
54 for (uint32_t i = 0; i <databaseFiles_.size(); i++) {
55 HandleAllTableName(i, allTableName);
56 }
57
58 map<string, int32_t> bundleNameUidMap;
59 vector<int32_t> activatedOsAccountIds;
60 BundleActiveAccountHelper::GetActiveUserId(activatedOsAccountIds);
61 for (uint32_t i = 0; i < allTableName.size(); i++) {
62 auto tableNames = allTableName.at(i);
63 shared_ptr<NativeRdb::RdbStore> rdbStore = GetBundleActiveRdbStore(i);
64 if (!rdbStore) {
65 BUNDLE_ACTIVE_LOGI("get RdbStore fail, databaseType: %{public}u", i);
66 continue;
67 }
68 for (string tableName: tableNames) {
69 if (DURATION_LOG_TABLE == tableName) {
70 continue;
71 }
72 AddRdbColumn(rdbStore, tableName, BUNDLE_ACTIVE_DB_UID, RDB_STORE_COLUMN_TYPE_INT);
73 for (auto userId: activatedOsAccountIds) {
74 UpdateOldDataUid(rdbStore, tableName, userId, bundleNameUidMap);
75 }
76 }
77 }
78 }
79
SupportFirstUseTime()80 void BundleActiveUsageDatabase::SupportFirstUseTime()
81 {
82 shared_ptr<NativeRdb::RdbStore> rdbStore = GetBundleActiveRdbStore(APP_GROUP_DATABASE_INDEX);
83 if (!rdbStore) {
84 BUNDLE_ACTIVE_LOGE("get RdbStore fail, databaseType: %{public}u", APP_GROUP_DATABASE_INDEX);
85 return;
86 }
87 vector<vector<string>> allTableName = vector<vector<string>>(ALL_TABLE_ARRAY_NUMBER);
88 {
89 lock_guard<ffrt::mutex> lock(databaseMutex_);
90 for (uint32_t i = 0; i < databaseFiles_.size(); i++) {
91 HandleTableInfo(i);
92 }
93 HandleAllTableName(APP_GROUP_DATABASE_INDEX, allTableName);
94 }
95 auto it = std::find(allTableName.at(APP_GROUP_DATABASE_INDEX).begin(),
96 allTableName.at(APP_GROUP_DATABASE_INDEX).end(), BUNDLE_HISTORY_LOG_TABLE);
97 if (it == allTableName.at(APP_GROUP_DATABASE_INDEX).end()) {
98 BUNDLE_ACTIVE_LOGE("not have bundle history table");
99 return;
100 }
101 vector<int32_t> activatedOsAccountIds;
102 BundleActiveAccountHelper::GetActiveUserId(activatedOsAccountIds);
103 {
104 lock_guard<ffrt::mutex> lock(databaseMutex_);
105 AddRdbColumn(rdbStore, BUNDLE_HISTORY_LOG_TABLE, BUNDLE_ACTIVE_DB_FIRST_USE_TIME, RDB_STORE_COLUMN_TYPE_INT);
106 }
107 for (auto userId: activatedOsAccountIds) {
108 UpdateFirstUseTime(rdbStore, BUNDLE_HISTORY_LOG_TABLE, userId);
109 }
110 }
111
AddRdbColumn(const shared_ptr<NativeRdb::RdbStore> store,const string & tableName,const string & columnName,const string & columnType)112 void BundleActiveUsageDatabase::AddRdbColumn(const shared_ptr<NativeRdb::RdbStore> store,
113 const string& tableName, const string& columnName, const string& columnType)
114 {
115 if (columnType != RDB_STORE_COLUMN_TYPE_INT) {
116 return;
117 }
118 string sqlStr = "";
119 sqlStr = "ALTER TABLE " + tableName + " ADD " + columnName + " " + columnType;
120 if (columnName == BUNDLE_ACTIVE_DB_UID) {
121 sqlStr += " NOT NULL DEFAULT -1";
122 }
123 if (columnName == BUNDLE_ACTIVE_DB_FIRST_USE_TIME) {
124 sqlStr += " NOT NULL DEFAULT " + std::to_string(MAX_END_TIME);
125 }
126 auto ret = store->ExecuteSql(sqlStr);
127 if (ret != E_OK) {
128 BUNDLE_ACTIVE_LOGE("add column failed columnName %{public}s", columnName.c_str());
129 }
130 }
131
UpdateOldDataUid(const shared_ptr<NativeRdb::RdbStore> store,const string & tableName,const int32_t userId,map<string,int32_t> & bundleNameUidMap)132 void BundleActiveUsageDatabase::UpdateOldDataUid(const shared_ptr<NativeRdb::RdbStore> store,
133 const string& tableName, const int32_t userId, map<string, int32_t>& bundleNameUidMap)
134 {
135 vector<string> queryCondition;
136 string querySql = "select * from " + tableName;
137 shared_ptr<NativeRdb::ResultSet> bundleActiveResult;
138 bundleActiveResult = store->QueryByStep(querySql);
139 int32_t tableRowNumber = 0;
140 bundleActiveResult->GetRowCount(tableRowNumber);
141 string bundleName;
142 int32_t uid;
143 int32_t changeRow = BUNDLE_ACTIVE_FAIL;
144 NativeRdb::ValuesBucket valuesBucket;
145 for (int32_t i = 0; i < tableRowNumber; i++) {
146 bundleActiveResult->GoToRow(i);
147 bundleActiveResult->GetString(BUNDLE_NAME_COLUMN_INDEX, bundleName);
148 AppExecFwk::ApplicationInfo appInfo;
149 string bundleNameUserIdKey = bundleName + to_string(userId);
150 auto it = bundleNameUidMap.find(bundleNameUserIdKey);
151 if (it == bundleNameUidMap.end()) {
152 BundleActiveBundleMgrHelper::GetInstance()->GetApplicationInfo(bundleName,
153 AppExecFwk::ApplicationFlag::GET_BASIC_APPLICATION_INFO, userId, appInfo);
154 uid = appInfo.uid;
155 bundleNameUidMap[bundleNameUserIdKey] = uid;
156 } else {
157 uid = it->second;
158 }
159 queryCondition.push_back(to_string(userId));
160 queryCondition.push_back(bundleName);
161 valuesBucket.PutInt(BUNDLE_ACTIVE_DB_UID, uid);
162 store->Update(changeRow, tableName, valuesBucket, "userId = ? and bundleName = ?", queryCondition);
163 queryCondition.clear();
164 valuesBucket.Clear();
165 changeRow = BUNDLE_ACTIVE_FAIL;
166 }
167 bundleActiveResult->Close();
168 }
169
UpdateFirstUseTime(const shared_ptr<NativeRdb::RdbStore> store,const string & tableName,const int32_t userId)170 void BundleActiveUsageDatabase::UpdateFirstUseTime(const shared_ptr<NativeRdb::RdbStore> store,
171 const string& tableName, const int32_t userId)
172 {
173 map<string, int64_t> allBundleFirstUseTime = GetAllBundleFirstUseTime(userId);
174 lock_guard<ffrt::mutex> lock(databaseMutex_);
175 vector<string> queryCondition;
176 string querySql = "select * from " + tableName;
177 shared_ptr<NativeRdb::ResultSet> bundleActiveResult;
178 bundleActiveResult = store->QueryByStep(querySql);
179 int32_t tableRowNumber = 0;
180 bundleActiveResult->GetRowCount(tableRowNumber);
181 int32_t uid;
182 string bundleName;
183 int32_t changeRow = BUNDLE_ACTIVE_FAIL;
184 int64_t firstUseTime = MAX_END_TIME;
185 NativeRdb::ValuesBucket valuesBucket;
186 for (int32_t i = 0; i < tableRowNumber; i++) {
187 bundleActiveResult->GoToRow(i);
188 bundleActiveResult->GetInt(BUNDLE_HISTORY_LOG_UID_COLUMN_INDEX, uid);
189 bundleActiveResult->GetString(BUNDLE_NAME_COLUMN_INDEX, bundleName);
190 string bundleUidKey = BundleActiveUtil::GetBundleUsageKey(bundleName, uid);
191 auto it = allBundleFirstUseTime.find(bundleUidKey);
192 if (it != allBundleFirstUseTime.end()) {
193 firstUseTime = it->second;
194 }
195 queryCondition.push_back(to_string(userId));
196 queryCondition.push_back(bundleName);
197 queryCondition.push_back(to_string(uid));
198 valuesBucket.PutLong(BUNDLE_ACTIVE_DB_FIRST_USE_TIME, firstUseTime);
199 store->Update(changeRow, tableName, valuesBucket, "userId = ? and bundleName = ? and uid = ?", queryCondition);
200 queryCondition.clear();
201 valuesBucket.Clear();
202 changeRow = BUNDLE_ACTIVE_FAIL;
203 }
204 bundleActiveResult->Close();
205 }
206
GetAllBundleFirstUseTime(const int32_t userId)207 map<string, int64_t> BundleActiveUsageDatabase::GetAllBundleFirstUseTime(const int32_t userId)
208 {
209 vector<BundleActiveEvent> events = QueryDatabaseEvents(MIN_START_TIME, MAX_END_TIME, userId, "");
210 map<string, int64_t> allBundleFirstUseTime;
211 for (auto event : events) {
212 string bundleUidKey = BundleActiveUtil::GetBundleUsageKey(event.bundleName_, event.uid_);
213 auto it = allBundleFirstUseTime.find(bundleUidKey);
214 if (it == allBundleFirstUseTime.end()) {
215 allBundleFirstUseTime[bundleUidKey] = event.timeStamp_;
216 continue;
217 }
218 allBundleFirstUseTime[bundleUidKey] = std::min(allBundleFirstUseTime[bundleUidKey], event.timeStamp_);
219 }
220
221 vector<BundleActivePackageStats> packageStatsVector = QueryDatabaseUsageStats(YEARLY_DATABASE_INDEX,
222 MIN_START_TIME, MAX_END_TIME, userId, "");
223 for (auto packageStats : packageStatsVector) {
224 string bundleUidKey = BundleActiveUtil::GetBundleUsageKey(packageStats.bundleName_, packageStats.uid_);
225 auto it = allBundleFirstUseTime.find(bundleUidKey);
226 if (it == allBundleFirstUseTime.end()) {
227 allBundleFirstUseTime[bundleUidKey] = packageStats.lastTimeUsed_;
228 continue;
229 }
230 allBundleFirstUseTime[bundleUidKey] = std::min(allBundleFirstUseTime[bundleUidKey], packageStats.lastTimeUsed_);
231 }
232 return allBundleFirstUseTime;
233 }
234 } // namespace DeviceUsageStats
235 } // namespace OHOS
236