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_store_impl.h"
24 #include "rdb_trace.h"
25 #include "sqlite_global_config.h"
26 #include "task_executor.h"
27 #include "rdb_radar_reporter.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 "sqlite_utils.h"
37 #include "string_utils.h"
38 #include "rdb_fault_hiview_reporter.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 RdbStoreConfig & config,const std::string & path)61 std::shared_ptr<RdbStoreImpl> RdbStoreManager::GetStoreFromCache(const RdbStoreConfig &config, 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     if (!(rdbStore->GetConfig() == config)) {
73         storeCache_.erase(it);
74         LOG_INFO("app[%{public}s:%{public}s] path[%{public}s]"
75                  " cfg[%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}s]"
76                  " %{public}s",
77             config.GetBundleName().c_str(), config.GetModuleName().c_str(), SqliteUtils::Anonymous(path).c_str(),
78             config.GetDBType(), config.GetHaMode(), config.IsEncrypt(), config.GetArea(), config.GetSecurityLevel(),
79             config.GetRoleType(), config.IsReadOnly(), config.GetCustomDir().c_str(),
80             Reportor::FormatBrief(Connection::Collect(config), SqliteUtils::Anonymous(config.GetName())).c_str());
81         return nullptr;
82     }
83     return rdbStore;
84 }
85 
GetRdbStore(const RdbStoreConfig & config,int & errCode,int version,RdbOpenCallback & openCallback)86 std::shared_ptr<RdbStore> RdbStoreManager::GetRdbStore(
87     const RdbStoreConfig &config, int &errCode, int version, RdbOpenCallback &openCallback)
88 {
89     RdbStoreConfig modifyConfig = config;
90     if (config.IsVector() && config.GetStorageMode() == StorageMode::MODE_MEMORY) {
91         LOG_ERROR("GetRdbStore type not support memory mode.");
92         return nullptr;
93     }
94     // TOD this lock should only work on storeCache_, add one more lock for connectionpool
95     std::lock_guard<std::mutex> lock(mutex_);
96     auto path = modifyConfig.GetRoleType() == VISITOR ? modifyConfig.GetVisitorDir() : modifyConfig.GetPath();
97     bundleName_ = modifyConfig.GetBundleName();
98     std::shared_ptr<RdbStoreImpl> rdbStore = GetStoreFromCache(modifyConfig, path);
99     if (rdbStore != nullptr) {
100         return rdbStore;
101     }
102     if (modifyConfig.GetRoleType() == OWNER && IsConfigInvalidChanged(path, modifyConfig)) {
103         errCode = E_CONFIG_INVALID_CHANGE;
104         return nullptr;
105     }
106     rdbStore = std::make_shared<RdbStoreImpl>(modifyConfig, errCode);
107     if (errCode != E_OK) {
108         LOG_ERROR("GetRdbStore fail path:%{public}s, rc=%{public}d", SqliteUtils::Anonymous(path).c_str(), errCode);
109         return nullptr;
110     }
111 
112     if (modifyConfig.GetRoleType() == OWNER && !modifyConfig.IsReadOnly()) {
113         errCode = SetSecurityLabel(modifyConfig);
114         if (errCode != E_OK) {
115             LOG_ERROR("fail, storeName:%{public}s security %{public}d errCode:%{public}d",
116                 SqliteUtils::Anonymous(modifyConfig.GetName()).c_str(), modifyConfig.GetSecurityLevel(), errCode);
117             return nullptr;
118         }
119         if (modifyConfig.IsVector()) {
120             storeCache_[path] = rdbStore;
121             return rdbStore;
122         }
123         (void)rdbStore->ExchangeSlaverToMaster();
124         errCode = ProcessOpenCallback(*rdbStore, modifyConfig, version, openCallback);
125         if (errCode != E_OK) {
126             LOG_ERROR("fail, storeName:%{public}s path:%{public}s ProcessOpenCallback errCode:%{public}d",
127                 SqliteUtils::Anonymous(modifyConfig.GetName()).c_str(),
128                 SqliteUtils::Anonymous(modifyConfig.GetPath()).c_str(), errCode);
129             return nullptr;
130         }
131     }
132 
133     storeCache_[path] = rdbStore;
134     return rdbStore;
135 }
136 
IsConfigInvalidChanged(const std::string & path,RdbStoreConfig & config)137 bool RdbStoreManager::IsConfigInvalidChanged(const std::string &path, RdbStoreConfig &config)
138 {
139     Param param = GetSyncParam(config);
140     Param tempParam;
141     if (config.GetBundleName().empty()) {
142         LOG_WARN("Config has no bundleName, path: %{public}s", SqliteUtils::Anonymous(path).c_str());
143         return false;
144     }
145     if (!configCache_.Get(path, tempParam)) {
146         LOG_WARN("Not found config cache, path: %{public}s", SqliteUtils::Anonymous(path).c_str());
147         tempParam = param;
148         if (GetParamFromService(tempParam) == E_OK) {
149             configCache_.Set(path, tempParam);
150         } else {
151             return false;
152         };
153     };
154     bool isLevelInvalidChange = (tempParam.level_ > param.level_);
155     bool isEncryptInvalidChange = (tempParam.isEncrypt_ != param.isEncrypt_);
156     bool isAreaInvalidChange = (tempParam.area_ != param.area_);
157     if (isLevelInvalidChange || isEncryptInvalidChange || isAreaInvalidChange) {
158         LOG_WARN("Store config invalid change, storePath %{public}s, securitylevel: %{public}d -> %{public}d, "
159                  "area: %{public}d -> %{public}d, isEncrypt: %{public}d -> %{public}d",
160             SqliteUtils::Anonymous(path).c_str(), tempParam.level_, param.level_, tempParam.area_, param.area_,
161             tempParam.isEncrypt_, param.isEncrypt_);
162         if (isEncryptInvalidChange) {
163             config.SetEncryptStatus(tempParam.isEncrypt_);
164         }
165     }
166     return false;
167 }
168 
GetSyncParam(const RdbStoreConfig & config)169 DistributedRdb::RdbSyncerParam RdbStoreManager::GetSyncParam(const RdbStoreConfig &config)
170 {
171     DistributedRdb::RdbSyncerParam syncerParam;
172     syncerParam.bundleName_ = config.GetBundleName();
173     syncerParam.hapName_ = config.GetModuleName();
174     syncerParam.storeName_ = config.GetName();
175     syncerParam.customDir_ = config.GetCustomDir();
176     syncerParam.area_ = config.GetArea();
177     syncerParam.level_ = static_cast<int32_t>(config.GetSecurityLevel());
178     syncerParam.isEncrypt_ = config.IsEncrypt();
179     syncerParam.isAutoClean_ = config.GetAutoClean();
180     syncerParam.isSearchable_ = config.IsSearchable();
181     syncerParam.roleType_ = config.GetRoleType();
182     syncerParam.haMode_ = config.GetHaMode();
183     return syncerParam;
184 }
185 
GetParamFromService(DistributedRdb::RdbSyncerParam & param)186 int32_t RdbStoreManager::GetParamFromService(DistributedRdb::RdbSyncerParam &param)
187 {
188 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
189     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
190     if (err == E_NOT_SUPPORT) {
191         return E_ERROR;
192     }
193     if (err != E_OK || service == nullptr) {
194         LOG_ERROR("GetRdbService failed, err is %{public}d.", err);
195         return E_ERROR;
196     }
197     err = service->BeforeOpen(param);
198     if (err != DistributedRdb::RDB_OK && err != DistributedRdb::RDB_NO_META) {
199         LOG_ERROR("BeforeOpen failed, err is %{public}d.", err);
200         return E_ERROR;
201     }
202     return E_OK;
203 #endif
204     return E_ERROR;
205 }
206 
Clear()207 void RdbStoreManager::Clear()
208 {
209     std::lock_guard<std::mutex> lock(mutex_);
210     auto iter = storeCache_.begin();
211     while (iter != storeCache_.end()) {
212         iter = storeCache_.erase(iter);
213     }
214     storeCache_.clear();
215 }
216 
Remove(const std::string & path)217 bool RdbStoreManager::Remove(const std::string &path)
218 {
219     std::lock_guard<std::mutex> lock(mutex_);
220     configCache_.Delete(path);
221     if (storeCache_.find(path) != storeCache_.end()) {
222         if (storeCache_[path].lock()) {
223             LOG_INFO("store in use by %{public}ld holders", storeCache_[path].lock().use_count());
224         }
225         storeCache_.erase(path); // clean invalid store ptr
226         return true;
227     }
228 
229     return false;
230 }
231 
ProcessOpenCallback(RdbStore & rdbStore,const RdbStoreConfig & config,int version,RdbOpenCallback & openCallback)232 int RdbStoreManager::ProcessOpenCallback(
233     RdbStore &rdbStore, const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback)
234 {
235     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
236     int errCode = E_OK;
237     if (version == -1) {
238         return errCode;
239     }
240 
241     int currentVersion;
242     errCode = rdbStore.GetVersion(currentVersion);
243     if (errCode != E_OK) {
244         return errCode;
245     }
246 
247     if (version == currentVersion) {
248         return openCallback.OnOpen(rdbStore);
249     }
250 
251     if (currentVersion == 0) {
252         errCode = openCallback.OnCreate(rdbStore);
253     } else if (version > currentVersion) {
254         errCode = openCallback.OnUpgrade(rdbStore, currentVersion, version);
255     } else {
256         errCode = openCallback.OnDowngrade(rdbStore, currentVersion, version);
257     }
258 
259     if (errCode == E_OK) {
260         errCode = rdbStore.SetVersion(version);
261     }
262 
263     if (errCode != E_OK) {
264         LOG_ERROR("RdbHelper ProcessOpenCallback set new version failed.");
265         return errCode;
266     }
267 
268     return openCallback.OnOpen(rdbStore);
269 }
270 
Delete(const std::string & path)271 bool RdbStoreManager::Delete(const std::string &path)
272 {
273 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
274     auto tokens = StringUtils::Split(path, "/");
275     if (!tokens.empty()) {
276         DistributedRdb::RdbSyncerParam param;
277         param.storeName_ = *tokens.rbegin();
278         param.bundleName_ = bundleName_;
279         auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
280         if (err != E_OK || service == nullptr) {
281             LOG_DEBUG("GetRdbService failed, err is %{public}d.", err);
282             return Remove(path);
283         }
284         err = service->Delete(param);
285         if (err != E_OK) {
286             LOG_ERROR("service delete store, storeName:%{public}s, err = %{public}d",
287                 SqliteUtils::Anonymous(param.storeName_).c_str(), err);
288             return Remove(path);
289         }
290     }
291 #endif
292     return Remove(path);
293 }
294 
SetSecurityLabel(const RdbStoreConfig & config)295 int RdbStoreManager::SetSecurityLabel(const RdbStoreConfig &config)
296 {
297 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
298     return SecurityPolicy::SetSecurityLabel(config);
299 #endif
300     return E_OK;
301 }
302 
Collector(const RdbStoreConfig & config)303 std::map<std::string, RdbStoreManager::Info> RdbStoreManager::Collector(const RdbStoreConfig &config)
304 {
305     std::map<std::string, Info> debugInfos;
306 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
307     Param param = GetSyncParam(config);
308     auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param);
309     if (err != E_OK || service == nullptr) {
310         LOG_DEBUG("GetRdbService failed, err is %{public}d.", err);
311         return std::map<std::string, Info>();
312     }
313     err = service->GetDebugInfo(param, debugInfos);
314     if (err != E_OK) {
315         LOG_ERROR("GetDebugInfo failed, storeName:%{public}s, err = %{public}d",
316             SqliteUtils::Anonymous(param.storeName_).c_str(), err);
317         return std::map<std::string, Info>();
318     }
319 #endif
320     return debugInfos;
321 }
322 } // namespace NativeRdb
323 } // namespace OHOS
324