• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "module_usage_data_storage.h"
17 
18 #include <cinttypes>
19 #include <unistd.h>
20 #include "datetime_ex.h"
21 #include "string_ex.h"
22 
23 #include "bundle_util.h"
24 #include "json_util.h"
25 #include "kvstore_death_recipient_callback.h"
26 #include "nlohmann/json.hpp"
27 
28 using namespace OHOS::DistributedKv;
29 
30 namespace OHOS {
31 namespace AppExecFwk {
32 namespace {
33 const int32_t MAX_TIMES = 6000;             // tem min
34 const int32_t SLEEP_INTERVAL = 100 * 1000;  // 100ms
35 const std::string POUND_KEY_SEPARATOR = "#";
36 const std::string SCHEMA_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\","
37                                   "\"SCHEMA_MODE\":\"COMPATIBLE\","
38                                   "\"SCHEMA_SKIPSIZE\":0,"
39                                   "\"SCHEMA_DEFINE\":{"
40                                   "\"launchedCount\":\"INTEGER, NOT NULL\","
41                                   "\"lastLaunchTime\":\"LONG, NOT NULL\","
42                                   "\"isRemoved\":\"BOOL, NOT NULL\""
43                                   "},"
44                                   "\"SCHEMA_INDEXES\":[\"$.lastLaunchTime\"]}";
45 }  // namespace
46 
ModuleUsageRecordStorage()47 ModuleUsageRecordStorage::ModuleUsageRecordStorage()
48 {
49     APP_LOGI("usage instance is created");
50     TryTwice([this] { return GetKvStore(); });
51 }
52 
~ModuleUsageRecordStorage()53 ModuleUsageRecordStorage::~ModuleUsageRecordStorage()
54 {
55     APP_LOGI("usage instance is destroyed");
56     dataManager_.CloseKvStore(appId_, kvStorePtr_);
57 }
58 
RegisterKvStoreDeathListener()59 void ModuleUsageRecordStorage::RegisterKvStoreDeathListener()
60 {}
61 
ParseKey(const std::string & key,ModuleUsageRecord & record) const62 bool ModuleUsageRecordStorage::ParseKey(const std::string &key, ModuleUsageRecord &record) const
63 {
64     std::vector<std::string> splitKeys;
65     SplitStr(key, POUND_KEY_SEPARATOR, splitKeys);
66     if (splitKeys.size() != DATABASE_KEY_INDEX_MAX_LENGTH) {
67         APP_LOGE("error key, parsed failed!");
68         return false;
69     }
70 
71     record.bundleName = (splitKeys[DATABASE_KEY_INDEX_BUNDLE_NAME]);
72     record.name = (splitKeys[DATABASE_KEY_INDEX_MODULE_NAME]);
73     APP_LOGD(
74         "parseKey::bundleName = %{public}s, moduleName = %{public}s", record.bundleName.c_str(), record.name.c_str());
75     return true;
76 }
77 
AbilityRecordToKey(const std::string & userId,const std::string & deviceId,const std::string & bundleName,const std::string & moduleName,std::string & key) const78 void ModuleUsageRecordStorage::AbilityRecordToKey(const std::string &userId, const std::string &deviceId,
79     const std::string &bundleName, const std::string &moduleName, std::string &key) const
80 {
81     // deviceId_bundleName_moduleName
82     key.append(userId);
83     key.append(POUND_KEY_SEPARATOR);
84     key.append(deviceId);
85     key.append(POUND_KEY_SEPARATOR);
86     key.append(bundleName);
87     key.append(POUND_KEY_SEPARATOR);
88     key.append(moduleName);
89     APP_LOGD("userId = %{public}s, bundleName = %{public}s, moduleName = %{public}s",
90         userId.c_str(),
91         bundleName.c_str(),
92         moduleName.c_str());
93 }
94 
UpdateUsageRecord(const std::string & jsonString,ModuleUsageRecord & data)95 void ModuleUsageRecordStorage::UpdateUsageRecord(const std::string &jsonString, ModuleUsageRecord &data)
96 {
97     nlohmann::json jsonObject = nlohmann::json::parse(jsonString);
98     if (jsonObject.is_discarded()) {
99         APP_LOGE("failed to parse existing usage record: %{private}s.", jsonString.c_str());
100         return;
101     }
102 
103     const auto &jsonObjectEnd = jsonObject.end();
104     int32_t parseResult = ERR_OK;
105     uint32_t launchedCount;
106     GetValueIfFindKey<uint32_t>(jsonObject,
107         jsonObjectEnd,
108         UsageRecordKey::LAUNCHED_COUNT,
109         launchedCount,
110         JsonType::NUMBER,
111         true,
112         parseResult,
113         ArrayType::NOT_ARRAY);
114     if (parseResult != ERR_OK) {
115         APP_LOGE("parsing failed: %{public}d.", parseResult);
116         return;
117     }
118     data.launchedCount = launchedCount + 1;
119     APP_LOGD("launchedCount = %{public}u", data.launchedCount);
120     return;
121 }
122 
AddOrUpdateRecord(ModuleUsageRecord & data,const std::string & deviceId,int32_t userId)123 bool ModuleUsageRecordStorage::AddOrUpdateRecord(ModuleUsageRecord &data, const std::string &deviceId, int32_t userId)
124 {
125     APP_LOGI("add usage record data %{public}s", data.bundleName.c_str());
126     {
127         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
128         if (!CheckKvStore()) {
129             APP_LOGE("kvStore is nullptr");
130             return false;
131         }
132     }
133     Status status;
134     bool isExist = false;
135     {
136         std::string keyOfData;
137         AbilityRecordToKey(std::to_string(userId), deviceId, data.bundleName, data.name, keyOfData);
138         Key key(keyOfData);
139         Value oldValue;
140         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
141         status = kvStorePtr_->Get(key, oldValue);
142         if (status == Status::SUCCESS) {
143             APP_LOGD("get old value %{public}s", oldValue.ToString().c_str());
144             // already isExist, update
145             UpdateUsageRecord(oldValue.ToString(), data);
146             isExist = true;
147         }
148         if (status == Status::KEY_NOT_FOUND || isExist) {
149             Value value(data.ToString());
150             APP_LOGD("add to DB::value %{public}s", value.ToString().c_str());
151             status = kvStorePtr_->Put(key, value);
152             APP_LOGW("add result = %{public}d", status);
153             if (status == Status::IPC_ERROR) {
154                 status = kvStorePtr_->Put(key, value);
155                 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
156             }
157         }
158     }
159 
160     if (status != Status::SUCCESS) {
161         APP_LOGE("put value to kvStore error: %{public}d", status);
162         return false;
163     }
164 
165     APP_LOGD("update success");
166     return true;
167 }
168 
DeleteRecordByKeys(const std::string & bundleName,std::vector<DistributedKv::Key> & keys)169 bool ModuleUsageRecordStorage::DeleteRecordByKeys(const std::string &bundleName, std::vector<DistributedKv::Key> &keys)
170 {
171     if (keys.size() == 0) {
172         APP_LOGE("delete error: empty key");
173         return false;
174     }
175     Status status;
176     {
177         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
178         status = kvStorePtr_->DeleteBatch(keys);
179         if (status == Status::IPC_ERROR) {
180             status = kvStorePtr_->DeleteBatch(keys);
181             APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
182         }
183     }
184 
185     if (status != Status::SUCCESS) {
186         APP_LOGE("delete keys error: %{public}d", status);
187         return false;
188     }
189     APP_LOGD("delete success");
190     return true;
191 }
192 
DeleteUsageRecord(const InnerBundleInfo & data,int32_t userId)193 bool ModuleUsageRecordStorage::DeleteUsageRecord(const InnerBundleInfo &data, int32_t userId)
194 {
195     APP_LOGD("delete usage data");
196     {
197         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
198         if (!CheckKvStore()) {
199             APP_LOGE("kvStore is nullptr");
200             return false;
201         }
202     }
203 
204     std::vector<Key> keys;
205     InnerBundleInfoToKeys(data, userId, keys);
206     APP_LOGD("delete key %{public}zu", keys.size());
207     return DeleteRecordByKeys(data.GetBundleName(), keys);
208 }
209 
MarkUsageRecordRemoved(const InnerBundleInfo & data,int32_t userId)210 bool ModuleUsageRecordStorage::MarkUsageRecordRemoved(const InnerBundleInfo &data, int32_t userId)
211 {
212     {
213         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
214         if (!CheckKvStore()) {
215             APP_LOGE("kvStore is nullptr");
216             return false;
217         }
218     }
219     ModuleUsageRecord record;
220     Value value;
221     std::string jsonString;
222     std::vector<Key> keys;
223     InnerBundleInfoToKeys(data, userId, keys);
224     {
225         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
226         for (const Key &key : keys) {
227             Status status = kvStorePtr_->Get(key, value);
228             if (status != Status::SUCCESS) {
229                 APP_LOGD("database query by key error, result = %{public}d", status);
230                 return false;
231             }
232             if (!record.FromJsonString(value.ToString())) {
233                 APP_LOGW("database parse entry failed");
234                 return false;
235             }
236             if (!record.removed) {
237                 record.removed = true;
238                 jsonString = record.ToString();
239                 APP_LOGD("new value %{public}s", jsonString.c_str());
240                 value = jsonString;
241                 status = kvStorePtr_->Put(key, value);
242                 APP_LOGI("value update result: %{public}d", status);
243             }
244         }
245     }
246     return true;
247 }
248 
InnerBundleInfoToKeys(const InnerBundleInfo & data,int32_t userId,std::vector<DistributedKv::Key> & keys) const249 void ModuleUsageRecordStorage::InnerBundleInfoToKeys(
250     const InnerBundleInfo &data, int32_t userId, std::vector<DistributedKv::Key> &keys) const
251 {
252     std::vector<std::string> mouduleNames;
253     data.GetModuleNames(mouduleNames);
254     const std::string &bundleName = data.GetBundleName();
255     for (const auto &moduleName : mouduleNames) {
256         FillDataStorageKeys(std::to_string(userId), bundleName, moduleName, keys);
257     }
258 }
259 
FillDataStorageKeys(const std::string & userId,const std::string & bundleName,const std::string & moduleName,std::vector<DistributedKv::Key> & keys) const260 void ModuleUsageRecordStorage::FillDataStorageKeys(const std::string &userId, const std::string &bundleName,
261     const std::string &moduleName, std::vector<DistributedKv::Key> &keys) const
262 {
263     std::string keyOfData;
264     AbilityRecordToKey(userId, Constants::CURRENT_DEVICE_ID, bundleName, moduleName, keyOfData);
265     Key key(keyOfData);
266     keys.push_back(key);
267 }
268 
SaveEntries(const std::vector<Entry> & allEntries,std::vector<ModuleUsageRecord> & records) const269 void ModuleUsageRecordStorage::SaveEntries(
270     const std::vector<Entry> &allEntries, std::vector<ModuleUsageRecord> &records) const
271 {
272     APP_LOGD("SaveEntries %{public}zu", allEntries.size());
273     for (const auto &item : allEntries) {
274         APP_LOGD("SaveEntries %{public}s", item.value.ToString().c_str());
275         ModuleUsageRecord record;
276         if (!record.FromJsonString(item.value.ToString())) {
277             APP_LOGE("error entry: %{private}s", item.value.ToString().c_str());
278             continue;
279         }
280 
281         if (!ParseKey(item.key.ToString(), record)) {
282             APP_LOGE("error key");
283             continue;
284         }
285         records.emplace_back(record);
286     }
287 }
288 
QueryRecordByNum(int32_t maxNum,std::vector<ModuleUsageRecord> & records,int32_t userId)289 bool ModuleUsageRecordStorage::QueryRecordByNum(int32_t maxNum, std::vector<ModuleUsageRecord> &records, int32_t userId)
290 {
291     APP_LOGI("query record by num %{public}d userId %{public}d", maxNum, userId);
292     DataQuery query;
293     query.KeyPrefix(std::to_string(userId) + POUND_KEY_SEPARATOR + Constants::CURRENT_DEVICE_ID + POUND_KEY_SEPARATOR);
294     query.OrderByDesc(UsageRecordKey::SCHEMA_LAST_LAUNCH_TIME);
295     query.Limit(maxNum, 0);
296     std::vector<Entry> allEntries;
297     bool queryResult = QueryRecordByCondition(query, allEntries);
298     if (!queryResult || static_cast<int>(allEntries.size()) > maxNum) {
299         APP_LOGE("query record error");
300         return queryResult;
301     }
302     APP_LOGD("query record success");
303     SaveEntries(allEntries, records);
304     return true;
305 }
306 
QueryRecordByCondition(DataQuery & query,std::vector<Entry> & records)307 bool ModuleUsageRecordStorage::QueryRecordByCondition(DataQuery &query, std::vector<Entry> &records)
308 {
309     Status status;
310     {
311         std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
312         if (!CheckKvStore()) {
313             APP_LOGE("kvStore is nullptr");
314             return false;
315         }
316     }
317 
318     status = kvStorePtr_->GetEntriesWithQuery(query, records);
319     APP_LOGI("query record by condition %{public}d", status);
320     if (status == Status::IPC_ERROR) {
321         status = kvStorePtr_->GetEntriesWithQuery(query, records);
322         APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
323     }
324 
325     if (status != Status::SUCCESS) {
326         APP_LOGE("query key error: %{public}d", status);
327         return false;
328     }
329     return true;
330 }
331 
GetKvStore()332 Status ModuleUsageRecordStorage::GetKvStore()
333 {
334     Options options = {
335         .createIfMissing = true,
336         .encrypt = false,
337         .autoSync = false,
338         .kvStoreType = KvStoreType::SINGLE_VERSION
339     };
340 
341     options.schema = SCHEMA_DEFINE;
342     Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
343     if (status != Status::SUCCESS) {
344         APP_LOGE("usage get kvStore error: %{public}d", status);
345     } else {
346         APP_LOGI("usage get kvStore success");
347     }
348     return status;
349 }
350 
TryTwice(const std::function<Status ()> & func) const351 void ModuleUsageRecordStorage::TryTwice(const std::function<Status()> &func) const
352 {
353     Status status = func();
354     if (status == Status::IPC_ERROR) {
355         status = func();
356         APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
357     }
358 }
359 
CheckKvStore()360 bool ModuleUsageRecordStorage::CheckKvStore()
361 {
362     if (kvStorePtr_ != nullptr) {
363         return true;
364     }
365     int32_t tryTimes = MAX_TIMES;
366     while (tryTimes > 0) {
367         Status status = GetKvStore();
368         if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
369             return true;
370         }
371         APP_LOGD("usage CheckKvStore, Times: %{public}d", tryTimes);
372         usleep(SLEEP_INTERVAL);
373         tryTimes--;
374     }
375     return kvStorePtr_ != nullptr;
376 }
377 
ResetKvStore()378 bool ModuleUsageRecordStorage::ResetKvStore()
379 {
380     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
381     kvStorePtr_ = nullptr;
382     Status status = GetKvStore();
383     if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
384         return true;
385     }
386     APP_LOGW("usage reset failed");
387     return false;
388 }
389 }  // namespace AppExecFwk
390 }  // namespace OHOS
391