• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #define LOG_TAG "RdbStoreManager"
16 #include "rdb_store_manager.h"
17 
18 #include <algorithm>
19 #include <cinttypes>
20 
21 #include "logger.h"
22 #include "rdb_errno.h"
23 #include "rdb_radar_reporter.h"
24 #include "rdb_store_impl.h"
25 #include "rdb_trace.h"
26 #include "sqlite_global_config.h"
27 #include "task_executor.h"
28 
29 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
30 #if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
31 #include "rdb_manager_impl.h"
32 #include "rdb_security_manager.h"
33 #endif
34 #include "security_policy.h"
35 #endif
36 #include "rdb_fault_hiview_reporter.h"
37 #include "sqlite_utils.h"
38 #include "string_utils.h"
39 
40 namespace OHOS {
41 namespace NativeRdb {
42 using namespace OHOS::Rdb;
43 using Reportor = RdbFaultHiViewReporter;
44 __attribute__((used))
45 const bool RdbStoreManager::regCollector_ = RdbFaultHiViewReporter::RegCollector(RdbStoreManager::Collector);
GetInstance()46 RdbStoreManager &RdbStoreManager::GetInstance()
47 {
48     static RdbStoreManager manager;
49     return manager;
50 }
51 
~RdbStoreManager()52 RdbStoreManager::~RdbStoreManager()
53 {
54     Clear();
55 }
56 
RdbStoreManager()57 RdbStoreManager::RdbStoreManager() : configCache_(BUCKET_MAX_SIZE), promiseInfoCache_(PROMISEINFO_CACHE_SIZE)
58 {
59 }
60 
GetStoreFromCache(const std::string & path,const RdbStoreConfig & config,int & errCode)61 std::shared_ptr<RdbStoreImpl> RdbStoreManager::GetStoreFromCache(const std::string &path,
62     const RdbStoreConfig &config, int &errCode)
63 {
64     std::lock_guard<std::mutex> lock(mutex_);
65     std::shared_ptr<RdbStoreImpl> rdbStore = nullptr;
66     auto it = storeCache_.find(path);
67     if (it == storeCache_.end()) {
68         rdbStore = std::make_shared<RdbStoreImpl>(config);
69         storeCache_[path] = rdbStore;
70         return rdbStore;
71     }
72 
73     rdbStore = it->second.lock();
74     if (rdbStore == nullptr) {
75         rdbStore = std::make_shared<RdbStoreImpl>(config);
76         storeCache_[path] = rdbStore;
77         return rdbStore;
78     }
79 
80     if (!(rdbStore->GetConfig() == config)) {
81         auto log = RdbStoreConfig::FormatCfg(rdbStore->GetConfig(), config);
82         LOG_WARN("Diff config! app[%{public}s:%{public}s] path[%{public}s] cfg[%{public}s]",
83             config.GetBundleName().c_str(), config.GetModuleName().c_str(), SqliteUtils::Anonymous(path).c_str(),
84             log.c_str());
85         Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_CONFIG_INVALID_CHANGE, config, log));
86         if (rdbStore->GetConfig().IsMemoryRdb() || config.IsMemoryRdb()) {
87             errCode = E_CONFIG_INVALID_CHANGE;
88             rdbStore = nullptr;
89             return rdbStore;
90         }
91         rdbStore = std::make_shared<RdbStoreImpl>(config);
92         storeCache_[path] = rdbStore;
93     }
94     return rdbStore;
95 }
96 
GetRdbStore(const RdbStoreConfig & config,int & errCode,int version,RdbOpenCallback & openCallback)97 std::shared_ptr<RdbStore> RdbStoreManager::GetRdbStore(
98     const RdbStoreConfig &config, int &errCode, int version, RdbOpenCallback &openCallback)
99 {
100     std::string path;
101     errCode = SqliteGlobalConfig::GetDbPath(config, path);
102     if (errCode != E_OK) {
103         return nullptr;
104     }
105     errCode = CheckConfig(config, path);
106     if (errCode != E_OK) {
107         return nullptr;
108     }
109     std::shared_ptr<RdbStoreImpl> rdbStore = nullptr;
110     RdbStoreConfig modifyConfig = config;
111     if (config.GetRoleType() == OWNER && IsConfigInvalidChanged(path, modifyConfig)) {
112         errCode = E_CONFIG_INVALID_CHANGE;
113         rdbStore = nullptr;
114         return rdbStore;
115     }
116     rdbStore = GetStoreFromCache(path, modifyConfig, errCode);
117     if (rdbStore == nullptr) {
118         return rdbStore;
119     }
120     errCode = rdbStore->Init(version, openCallback);
121     if (errCode != E_OK) {
122         if (modifyConfig.IsEncrypt() != config.IsEncrypt()) {
123             rdbStore = nullptr;
124             rdbStore = GetStoreFromCache(path, config, errCode);
125             if (rdbStore == nullptr) {
126                 return rdbStore;
127             }
128             errCode = rdbStore->Init(version, openCallback);
129         }
130         if (errCode != E_OK || rdbStore == nullptr) {
131             rdbStore = nullptr;
132             return rdbStore;
133         }
134     }
135 
136     if (!rdbStore->GetConfig().IsMemoryRdb()) {
137         configCache_.Set(path, GetSyncParam(rdbStore->GetConfig()));
138     }
139     return rdbStore;
140 }
141 
IsConfigInvalidChanged(const std::string & path,RdbStoreConfig & config)142 bool RdbStoreManager::IsConfigInvalidChanged(const std::string &path, RdbStoreConfig &config)
143 {
144     if (config.IsMemoryRdb()) {
145         return false;
146     }
147     if (config.GetBundleName().empty()) {
148         LOG_WARN("no bundleName");
149         return false;
150     }
151     Param lastParam = GetSyncParam(config);
152     if (!configCache_.Get(path, lastParam) && GetParamFromService(lastParam) != E_OK) {
153         LOG_WARN("Not found config cache, path: %{public}s", SqliteUtils::Anonymous(path).c_str());
154         return false;
155     };
156     configCache_.Set(path, lastParam);
157     // The lastParam is possible that the same named db parameters of different paths when GetParamFromService
158     if (lastParam.customDir_ != config.GetCustomDir() || lastParam.hapName_ != config.GetModuleName() ||
159         lastParam.area_ != config.GetArea()) {
160         LOG_WARN("Diff db with the same name! customDir:%{public}s -> %{public}s, hapName:%{public}s -> %{public}s,"
161             "area:%{public}d -> %{public}d.", lastParam.customDir_.c_str(), config.GetCustomDir().c_str(),
162             lastParam.hapName_.c_str(), config.GetModuleName().c_str(), lastParam.area_, config.GetArea());
163         return false;
164     }
165     if (config.GetSecurityLevel() != SecurityLevel::LAST &&
166         static_cast<int32_t>(config.GetSecurityLevel()) < lastParam.level_) {
167         LOG_WARN("Illegal change, storePath %{public}s, securityLevel: %{public}d -> %{public}d",
168             SqliteUtils::Anonymous(path).c_str(), lastParam.level_, static_cast<int32_t>(config.GetSecurityLevel()));
169     }
170 
171     if (lastParam.isEncrypt_ != config.IsEncrypt()) {
172         LOG_WARN("Reset encrypt, storePath %{public}s, input:%{public}d  original:%{public}d",
173             SqliteUtils::Anonymous(path).c_str(), config.IsEncrypt(), lastParam.isEncrypt_);
174         config.SetEncryptStatus(lastParam.isEncrypt_);
175         config.SetAllowRebuild(false);
176     }
177     return false;
178 }
179 
GetSyncParam(const RdbStoreConfig & config)180 DistributedRdb::RdbSyncerParam RdbStoreManager::GetSyncParam(const RdbStoreConfig &config)
181 {
182     DistributedRdb::RdbSyncerParam syncerParam;
183     syncerParam.bundleName_ = config.GetBundleName();
184     syncerParam.hapName_ = config.GetModuleName();
185     syncerParam.storeName_ = config.GetName();
186     syncerParam.customDir_ = config.GetCustomDir();
187     syncerParam.area_ = config.GetArea();
188     syncerParam.level_ = static_cast<int32_t>(config.GetSecurityLevel());
189     syncerParam.isEncrypt_ = config.IsEncrypt();
190     syncerParam.isAutoClean_ = config.GetAutoClean();
191     syncerParam.isSearchable_ = config.IsSearchable();
192     syncerParam.roleType_ = config.GetRoleType();
193     syncerParam.haMode_ = config.GetHaMode();
194     syncerParam.tokenIds_ = config.GetPromiseInfo().tokenIds_;
195     syncerParam.uids_ = config.GetPromiseInfo().uids_;
196     syncerParam.user_ = config.GetPromiseInfo().user_;
197     syncerParam.permissionNames_ = config.GetPromiseInfo().permissionNames_;
198     syncerParam.subUser_ = config.GetSubUser();
199     return syncerParam;
200 }
201 
GetParamFromService(DistributedRdb::RdbSyncerParam & param)202 int32_t RdbStoreManager::GetParamFromService(DistributedRdb::RdbSyncerParam &param)
203 {
204 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
205     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
206     if (err == E_NOT_SUPPORT) {
207         return E_ERROR;
208     }
209     if (err != E_OK || service == nullptr) {
210         LOG_ERROR("GetRdbService failed, err is %{public}d.", err);
211         return E_ERROR;
212     }
213     err = service->BeforeOpen(param);
214     return err != DistributedRdb::RDB_OK ? E_ERROR : E_OK;
215 #endif
216     return E_ERROR;
217 }
218 
IsPermitted(const DistributedRdb::RdbSyncerParam & param,const std::string & path)219 bool RdbStoreManager::IsPermitted(const DistributedRdb::RdbSyncerParam &param, const std::string &path)
220 {
221 #if !defined(CROSS_PLATFORM)
222     bool result = false;
223     // ToDo: Scenario for handling cache refresh
224     if (promiseInfoCache_.Get(path, result)) {
225         return true;
226     };
227     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
228     if (err == E_NOT_SUPPORT) {
229         return false;
230     }
231     if (err != E_OK || service == nullptr) {
232         LOG_ERROR("GetRdbService failed, bundleName:%{public}s, err:%{public}d.", param.bundleName_.c_str(), err);
233         return false;
234     }
235     err = service->VerifyPromiseInfo(param);
236     if (err == DistributedRdb::RDB_OK) {
237         promiseInfoCache_.Set(path, true);
238         return true;
239     }
240     LOG_ERROR("failed, bundleName:%{public}s, store:%{public}s, err:%{public}d.", param.bundleName_.c_str(),
241         SqliteUtils::Anonymous(param.storeName_).c_str(), err);
242 #endif
243     return false;
244 }
245 
Clear()246 void RdbStoreManager::Clear()
247 {
248     configCache_.ResetCapacity(0);
249     configCache_.ResetCapacity(BUCKET_MAX_SIZE);
250     promiseInfoCache_.ResetCapacity(0);
251     promiseInfoCache_.ResetCapacity(PROMISEINFO_CACHE_SIZE);
252     std::lock_guard<std::mutex> lock(mutex_);
253     auto iter = storeCache_.begin();
254     while (iter != storeCache_.end()) {
255         auto rdbStore = iter->second.lock();
256         if (rdbStore.use_count() > 1) {
257             LOG_WARN("store[%{public}s] in use by %{public}ld holders",
258                 SqliteUtils::Anonymous(rdbStore->GetPath()).c_str(), rdbStore.use_count());
259         }
260         iter = storeCache_.erase(iter);
261     }
262     storeCache_.clear();
263 }
264 
Init()265 void RdbStoreManager::Init()
266 {
267     TaskExecutor::GetInstance().Init();
268 }
269 
Destroy()270 bool RdbStoreManager::Destroy()
271 {
272     Clear();
273     return TaskExecutor::GetInstance().Stop();
274 }
275 
Remove(const std::string & path,bool shouldClose)276 bool RdbStoreManager::Remove(const std::string &path, bool shouldClose)
277 {
278     std::lock_guard<std::mutex> lock(mutex_);
279     configCache_.Delete(path);
280     auto it = storeCache_.find(path);
281     if (it != storeCache_.end()) {
282         auto rdbStore = it->second.lock();
283         LOG_INFO("store in use by %{public}ld holders", rdbStore.use_count());
284         if (rdbStore && shouldClose) {
285             rdbStore->Close();
286         }
287         storeCache_.erase(it); // clean invalid store ptr
288         return true;
289     }
290 
291     return false;
292 }
293 
Delete(const RdbStoreConfig & config,bool shouldClose)294 bool RdbStoreManager::Delete(const RdbStoreConfig &config, bool shouldClose)
295 {
296     auto path = config.GetPath();
297 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
298     auto tokens = StringUtils::Split(path, "/");
299     if (!tokens.empty()) {
300         DistributedRdb::RdbSyncerParam param;
301         param.bundleName_ = config.GetBundleName();
302         param.storeName_ = *tokens.rbegin();
303         param.subUser_ = config.GetSubUser();
304         param.area_ = config.GetArea();
305         param.hapName_ = config.GetModuleName();
306         param.customDir_ = config.GetCustomDir();
307         auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
308         if (err != E_OK || service == nullptr) {
309             LOG_DEBUG("GetRdbService failed, err is %{public}d.", err);
310             return Remove(path, shouldClose);
311         }
312         err = service->Delete(param);
313         if (err != E_OK) {
314             LOG_ERROR("service delete store, storeName:%{public}s, err = %{public}d",
315                 SqliteUtils::Anonymous(param.storeName_).c_str(), err);
316             return Remove(path, shouldClose);
317         }
318     }
319 #endif
320     return Remove(path, shouldClose);
321 }
322 
Collector(const RdbStoreConfig & config,DebugInfos & debugInfos,DfxInfo & dfxInfo)323 int32_t RdbStoreManager::Collector(const RdbStoreConfig &config, DebugInfos &debugInfos, DfxInfo &dfxInfo)
324 {
325 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
326     Param param = GetSyncParam(config);
327     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
328     if (err != E_OK || service == nullptr) {
329         LOG_DEBUG("GetRdbService failed, err is %{public}d.", err);
330         return E_ERROR;
331     }
332 
333     err = service->GetDebugInfo(param, debugInfos);
334     if (err != E_OK) {
335         LOG_ERROR("GetDebugInfo failed, storeName:%{public}s, err = %{public}d",
336             SqliteUtils::Anonymous(param.storeName_).c_str(), err);
337         return E_ERROR;
338     }
339 
340     err = service->GetDfxInfo(param, dfxInfo);
341     if (err != E_OK) {
342         LOG_ERROR("GetDfxInfo failed, storeName:%{public}s, err = %{public}d",
343             SqliteUtils::Anonymous(param.storeName_).c_str(), err);
344         return E_ERROR;
345     }
346 
347 #endif
348     return E_OK;
349 }
350 
CheckConfig(const RdbStoreConfig & config,const std::string & path)351 int32_t RdbStoreManager::CheckConfig(const RdbStoreConfig &config, const std::string &path)
352 {
353     if (config.GetRoleType() == VISITOR_WRITE && !IsPermitted(GetSyncParam(config), path)) {
354         return E_NOT_SUPPORT;
355     }
356     if (config.IsMemoryRdb()) {
357         if (config.IsEncrypt() || config.IsVector() || config.GetRoleType() != OWNER ||
358             config.GetHaMode() != HAMode::SINGLE || config.IsSearchable() || config.IsReadOnly() ||
359             !config.GetDataGroupId().empty() || !config.GetCustomDir().empty()) {
360             LOG_ERROR("not support!config:%{public}s", config.ToString().c_str());
361             return E_NOT_SUPPORT;
362         }
363     }
364     return E_OK;
365 }
366 
367 } // namespace NativeRdb
368 } // namespace OHOS
369