• 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)
58 {
59 }
60 
GetStoreFromCache(const std::string & path)61 std::shared_ptr<RdbStoreImpl> RdbStoreManager::GetStoreFromCache(const std::string &path)
62 {
63     auto it = storeCache_.find(path);
64     if (it == storeCache_.end()) {
65         return nullptr;
66     }
67     std::shared_ptr<RdbStoreImpl> rdbStore = it->second.lock();
68     if (rdbStore == nullptr) {
69         storeCache_.erase(it);
70         return nullptr;
71     }
72     return rdbStore;
73 }
74 
GetRdbStore(const RdbStoreConfig & config,int & errCode,int version,RdbOpenCallback & openCallback)75 std::shared_ptr<RdbStore> RdbStoreManager::GetRdbStore(
76     const RdbStoreConfig &config, int &errCode, int version, RdbOpenCallback &openCallback)
77 {
78     errCode = CheckConfig(config);
79     if (errCode != E_OK) {
80         return nullptr;
81     }
82     std::string path;
83     errCode = SqliteGlobalConfig::GetDbPath(config, path);
84     if (errCode != E_OK) {
85         return nullptr;
86     }
87     // TOD this lock should only work on storeCache_, add one more lock for connectionPool
88     std::lock_guard<std::mutex> lock(mutex_);
89     std::shared_ptr<RdbStoreImpl> rdbStore = GetStoreFromCache(path);
90     if (rdbStore != nullptr && rdbStore->GetConfig() == config) {
91         return rdbStore;
92     }
93     if (rdbStore != nullptr) {
94         LOG_WARN("Diff config! app[%{public}s:%{public}s] path[%{public}s] cfg[%{public}s]",
95             config.GetBundleName().c_str(), config.GetModuleName().c_str(), SqliteUtils::Anonymous(path).c_str(),
96             RdbStoreConfig::FormatCfg(rdbStore->GetConfig(), config).c_str());
97         if (rdbStore->GetConfig().IsMemoryRdb() || config.IsMemoryRdb()) {
98             errCode = E_CONFIG_INVALID_CHANGE;
99             return nullptr;
100         }
101         storeCache_.erase(path);
102         rdbStore = nullptr;
103     }
104     std::tie(errCode, rdbStore) = OpenStore(config, path);
105     if (errCode != E_OK || rdbStore == nullptr) {
106         LOG_ERROR("OpenStore failed. path:%{public}s, rc=%{public}d", SqliteUtils::Anonymous(path).c_str(), errCode);
107         return nullptr;
108     }
109     if (rdbStore->GetConfig().GetRoleType() == OWNER && !rdbStore->GetConfig().IsReadOnly()) {
110         errCode = SetSecurityLabel(rdbStore->GetConfig());
111         if (errCode != E_OK) {
112             return nullptr;
113         }
114         (void)rdbStore->ExchangeSlaverToMaster();
115         errCode = ProcessOpenCallback(*rdbStore, version, openCallback);
116         if (errCode != E_OK) {
117             LOG_ERROR("fail, path:%{public}s ProcessOpenCallback errCode:%{public}d",
118                 SqliteUtils::Anonymous(rdbStore->GetConfig().GetPath()).c_str(), errCode);
119             return nullptr;
120         }
121     }
122     if (!rdbStore->GetConfig().IsMemoryRdb()) {
123         configCache_.Set(path, GetSyncParam(rdbStore->GetConfig()));
124     }
125     storeCache_.insert_or_assign(std::move(path), rdbStore);
126     return rdbStore;
127 }
128 
IsConfigInvalidChanged(const std::string & path,RdbStoreConfig & config)129 bool RdbStoreManager::IsConfigInvalidChanged(const std::string &path, RdbStoreConfig &config)
130 {
131     if (config.IsMemoryRdb()) {
132         return false;
133     }
134     if (config.GetBundleName().empty()) {
135         LOG_WARN("Config has no bundleName, path: %{public}s", SqliteUtils::Anonymous(path).c_str());
136         return false;
137     }
138     Param lastParam = GetSyncParam(config);
139     if (!configCache_.Get(path, lastParam) && GetParamFromService(lastParam) != E_OK) {
140         LOG_WARN("Not found config cache, path: %{public}s", SqliteUtils::Anonymous(path).c_str());
141         return false;
142     };
143     // The lastParam is possible that the same named db parameters of different paths when GetParamFromService
144     if (lastParam.customDir_ != config.GetCustomDir() || lastParam.hapName_ != config.GetModuleName() ||
145         lastParam.area_ != config.GetArea()) {
146         LOG_WARN("Diff db with the same name! customDir:%{public}s -> %{public}s, hapName:%{public}s -> %{public}s,"
147             "area:%{public}d -> %{public}d.", lastParam.customDir_.c_str(), config.GetCustomDir().c_str(),
148             lastParam.hapName_.c_str(), config.GetModuleName().c_str(), lastParam.area_, config.GetArea());
149         return false;
150     }
151     if (config.GetSecurityLevel() != SecurityLevel::LAST &&
152         static_cast<int32_t>(config.GetSecurityLevel()) < lastParam.level_) {
153         LOG_WARN("Illegal change, storePath %{public}s, securityLevel: %{public}d -> %{public}d",
154             SqliteUtils::Anonymous(path).c_str(), lastParam.level_, static_cast<int32_t>(config.GetSecurityLevel()));
155     }
156 
157     if (lastParam.isEncrypt_ != config.IsEncrypt()) {
158         LOG_WARN("Reset encrypt, storePath %{public}s, input:%{public}d  original:%{public}d",
159             SqliteUtils::Anonymous(path).c_str(), config.IsEncrypt(), lastParam.isEncrypt_);
160         config.SetEncryptStatus(lastParam.isEncrypt_);
161     }
162     return false;
163 }
164 
GetSyncParam(const RdbStoreConfig & config)165 DistributedRdb::RdbSyncerParam RdbStoreManager::GetSyncParam(const RdbStoreConfig &config)
166 {
167     DistributedRdb::RdbSyncerParam syncerParam;
168     syncerParam.bundleName_ = config.GetBundleName();
169     syncerParam.hapName_ = config.GetModuleName();
170     syncerParam.storeName_ = config.GetName();
171     syncerParam.customDir_ = config.GetCustomDir();
172     syncerParam.area_ = config.GetArea();
173     syncerParam.level_ = static_cast<int32_t>(config.GetSecurityLevel());
174     syncerParam.isEncrypt_ = config.IsEncrypt();
175     syncerParam.isAutoClean_ = config.GetAutoClean();
176     syncerParam.isSearchable_ = config.IsSearchable();
177     syncerParam.roleType_ = config.GetRoleType();
178     syncerParam.haMode_ = config.GetHaMode();
179     syncerParam.tokenIds_ = config.GetPromiseInfo().tokenIds_;
180     syncerParam.uids_ = config.GetPromiseInfo().uids_;
181     syncerParam.user_ = config.GetPromiseInfo().user_;
182     syncerParam.permissionNames_ = config.GetPromiseInfo().permissionNames_;
183     syncerParam.subUser_ = config.GetSubUser();
184     return syncerParam;
185 }
186 
GetParamFromService(DistributedRdb::RdbSyncerParam & param)187 int32_t RdbStoreManager::GetParamFromService(DistributedRdb::RdbSyncerParam &param)
188 {
189 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
190     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
191     if (err == E_NOT_SUPPORT) {
192         return E_ERROR;
193     }
194     if (err != E_OK || service == nullptr) {
195         LOG_ERROR("GetRdbService failed, err is %{public}d.", err);
196         return E_ERROR;
197     }
198     err = service->BeforeOpen(param);
199     return err != DistributedRdb::RDB_OK ? E_ERROR : E_OK;
200 #endif
201     return E_ERROR;
202 }
203 
IsPermitted(const DistributedRdb::RdbSyncerParam & param)204 bool RdbStoreManager::IsPermitted(const DistributedRdb::RdbSyncerParam &param)
205 {
206 #if !defined(CROSS_PLATFORM)
207     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
208     if (err == E_NOT_SUPPORT) {
209         return false;
210     }
211     if (err != E_OK || service == nullptr) {
212         LOG_ERROR("GetRdbService failed, bundleName:%{public}s, err:%{public}d.", param.bundleName_.c_str(), err);
213         return false;
214     }
215     err = service->VerifyPromiseInfo(param);
216     if (err == DistributedRdb::RDB_OK) {
217         return true;
218     }
219     LOG_ERROR("failed, bundleName:%{public}s, store:%{public}s, err:%{public}d.", param.bundleName_.c_str(),
220         SqliteUtils::Anonymous(param.storeName_).c_str(), err);
221 #endif
222     return false;
223 }
224 
Clear()225 void RdbStoreManager::Clear()
226 {
227     std::lock_guard<std::mutex> lock(mutex_);
228     auto iter = storeCache_.begin();
229     while (iter != storeCache_.end()) {
230         iter = storeCache_.erase(iter);
231     }
232     storeCache_.clear();
233 }
234 
Remove(const std::string & path,bool shouldClose)235 bool RdbStoreManager::Remove(const std::string &path, bool shouldClose)
236 {
237     std::lock_guard<std::mutex> lock(mutex_);
238     configCache_.Delete(path);
239     auto it = storeCache_.find(path);
240     if (it != storeCache_.end()) {
241         auto rdbStore = it->second.lock();
242         LOG_INFO("store in use by %{public}ld holders", storeCache_[path].lock().use_count());
243         if (rdbStore && shouldClose) {
244             rdbStore->Close();
245         }
246         storeCache_.erase(it); // clean invalid store ptr
247         return true;
248     }
249 
250     return false;
251 }
252 
ProcessOpenCallback(RdbStore & rdbStore,int version,RdbOpenCallback & openCallback)253 int RdbStoreManager::ProcessOpenCallback(RdbStore &rdbStore, int version, RdbOpenCallback &openCallback)
254 {
255     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
256     int errCode = E_OK;
257     if (version == -1) {
258         return errCode;
259     }
260 
261     int currentVersion;
262     errCode = rdbStore.GetVersion(currentVersion);
263     if (errCode != E_OK) {
264         return errCode;
265     }
266 
267     if (version == currentVersion) {
268         return openCallback.OnOpen(rdbStore);
269     }
270 
271     if (currentVersion == 0) {
272         errCode = openCallback.OnCreate(rdbStore);
273     } else if (version > currentVersion) {
274         errCode = openCallback.OnUpgrade(rdbStore, currentVersion, version);
275     } else {
276         errCode = openCallback.OnDowngrade(rdbStore, currentVersion, version);
277     }
278 
279     if (errCode == E_OK) {
280         errCode = rdbStore.SetVersion(version);
281     }
282 
283     if (errCode != E_OK) {
284         LOG_ERROR("RdbHelper ProcessOpenCallback set new version failed.");
285         return errCode;
286     }
287 
288     return openCallback.OnOpen(rdbStore);
289 }
290 
Delete(const RdbStoreConfig & config,bool shouldClose)291 bool RdbStoreManager::Delete(const RdbStoreConfig &config, bool shouldClose)
292 {
293     auto path = config.GetPath();
294 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
295     auto tokens = StringUtils::Split(path, "/");
296     if (!tokens.empty()) {
297         DistributedRdb::RdbSyncerParam param;
298         param.bundleName_ = config.GetBundleName();
299         param.storeName_ = *tokens.rbegin();
300         param.subUser_ = config.GetSubUser();
301         auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
302         if (err != E_OK || service == nullptr) {
303             LOG_DEBUG("GetRdbService failed, err is %{public}d.", err);
304             return Remove(path, shouldClose);
305         }
306         err = service->Delete(param);
307         if (err != E_OK) {
308             LOG_ERROR("service delete store, storeName:%{public}s, err = %{public}d",
309                 SqliteUtils::Anonymous(param.storeName_).c_str(), err);
310             return Remove(path, shouldClose);
311         }
312     }
313 #endif
314     return Remove(path, shouldClose);
315 }
316 
SetSecurityLabel(const RdbStoreConfig & config)317 int RdbStoreManager::SetSecurityLabel(const RdbStoreConfig &config)
318 {
319     if (config.IsMemoryRdb()) {
320         return E_OK;
321     }
322 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
323     return SecurityPolicy::SetSecurityLabel(config);
324 #endif
325     return E_OK;
326 }
327 
Collector(const RdbStoreConfig & config,DebugInfos & debugInfos,DfxInfo & dfxInfo)328 int32_t RdbStoreManager::Collector(const RdbStoreConfig &config, DebugInfos &debugInfos, DfxInfo &dfxInfo)
329 {
330 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
331     Param param = GetSyncParam(config);
332     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
333     if (err != E_OK || service == nullptr) {
334         LOG_DEBUG("GetRdbService failed, err is %{public}d.", err);
335         return E_ERROR;
336     }
337 
338     err = service->GetDebugInfo(param, debugInfos);
339     if (err != E_OK) {
340         LOG_ERROR("GetDebugInfo failed, storeName:%{public}s, err = %{public}d",
341             SqliteUtils::Anonymous(param.storeName_).c_str(), err);
342         return E_ERROR;
343     }
344 
345     err = service->GetDfxInfo(param, dfxInfo);
346     if (err != E_OK) {
347         LOG_ERROR("GetDfxInfo failed, storeName:%{public}s, err = %{public}d",
348             SqliteUtils::Anonymous(param.storeName_).c_str(), err);
349         return E_ERROR;
350     }
351 
352 #endif
353     return E_OK;
354 }
355 
CheckConfig(const RdbStoreConfig & config)356 int32_t RdbStoreManager::CheckConfig(const RdbStoreConfig &config)
357 {
358     if (config.GetRoleType() == VISITOR_WRITE && !IsPermitted(GetSyncParam(config))) {
359         return E_NOT_SUPPORT;
360     }
361     if (config.IsMemoryRdb()) {
362         if (config.IsEncrypt() || config.IsVector() || config.GetRoleType() != OWNER ||
363             config.GetHaMode() != HAMode::SINGLE || config.IsSearchable() || config.IsReadOnly() ||
364             !config.GetDataGroupId().empty() || !config.GetCustomDir().empty()) {
365             LOG_ERROR("not support!config:%{public}s", config.ToString().c_str());
366             return E_NOT_SUPPORT;
367         }
368     }
369     return E_OK;
370 }
371 
OpenStore(const RdbStoreConfig & config,const std::string & path)372 std::pair<int32_t, std::shared_ptr<RdbStoreImpl>> RdbStoreManager::OpenStore(
373     const RdbStoreConfig &config, const std::string &path)
374 {
375     RdbStoreConfig modifyConfig = config;
376     if (modifyConfig.GetRoleType() == OWNER && IsConfigInvalidChanged(path, modifyConfig)) {
377         return { E_CONFIG_INVALID_CHANGE, nullptr };
378     }
379 
380     std::pair<int32_t, std::shared_ptr<RdbStoreImpl>> result = { E_ERROR, nullptr };
381     auto &[errCode, store] = result;
382     store = std::make_shared<RdbStoreImpl>(modifyConfig, errCode);
383     if (errCode != E_OK && modifyConfig.IsEncrypt() != config.IsEncrypt()) {
384         LOG_WARN("Failed to OpenStore using modifyConfig. path:%{public}s, rc=%{public}d",
385             SqliteUtils::Anonymous(path).c_str(), errCode);
386         store = std::make_shared<RdbStoreImpl>(config, errCode); // retry with input config
387     }
388     return result;
389 }
390 } // namespace NativeRdb
391 } // namespace OHOS
392