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 "RdbAdaptor"
16 #include "rdb_delegate.h"
17
18 #include "crypto_manager.h"
19 #include "datashare_errno.h"
20 #include "datashare_radar_reporter.h"
21 #include "device_manager_adapter.h"
22 #include "extension_connect_adaptor.h"
23 #include "int_wrapper.h"
24 #include "metadata/meta_data_manager.h"
25 #include "metadata/store_meta_data.h"
26 #include "metadata/secret_key_meta_data.h"
27 #include "resultset_json_formatter.h"
28 #include "log_print.h"
29 #include "rdb_errno.h"
30 #include "rdb_utils.h"
31 #include "scheduler_manager.h"
32 #include "string_wrapper.h"
33 #include "utils/anonymous.h"
34 #include "want_params.h"
35
36 namespace OHOS::DataShare {
37 constexpr static int32_t MAX_RESULTSET_COUNT = 32;
38 constexpr static int64_t TIMEOUT_TIME = 500;
39 std::atomic<int32_t> RdbDelegate::resultSetCount = 0;
40 ConcurrentMap<uint32_t, int32_t> RdbDelegate::resultSetCallingPids;
41 enum REMIND_TIMER_ARGS : int32_t {
42 ARG_DB_PATH = 0,
43 ARG_VERSION,
44 ARG_URI,
45 ARG_SUBSCRIBER_ID,
46 ARG_BUNDLE_NAME,
47 ARG_USER_ID,
48 ARG_TIME,
49 ARGS_SIZE
50 };
RemindTimerFunc(const std::vector<std::string> &args)51 std::string RemindTimerFunc(const std::vector<std::string> &args)
52 {
53 size_t size = args.size();
54 if (size != ARGS_SIZE) {
55 ZLOGE("RemindTimerFunc args size error, %{public}zu", size);
56 return "";
57 }
58 std::string dbPath = args[ARG_DB_PATH];
59 int version = std::strtol(args[ARG_VERSION].c_str(), nullptr, 0);
60 Key key(args[ARG_URI], std::strtoll(args[ARG_SUBSCRIBER_ID].c_str(), nullptr, 0), args[ARG_BUNDLE_NAME]);
61 int64_t reminderTime = std::strtoll(args[ARG_TIME].c_str(), nullptr, 0);
62 int32_t userId = std::strtol(args[ARG_USER_ID].c_str(), nullptr, 0);
63 SchedulerManager::GetInstance().SetTimer(dbPath, userId, version, key, reminderTime);
64 return args[ARG_TIME];
65 }
66
GetConfig(const DistributedData::StoreMetaData &meta, bool registerFunction)67 std::pair<int, RdbStoreConfig> RdbDelegate::GetConfig(const DistributedData::StoreMetaData &meta,
68 bool registerFunction)
69 {
70 RdbStoreConfig config(meta.dataDir);
71 config.SetCreateNecessary(false);
72 config.SetHaMode(meta.haMode);
73 config.SetBundleName(meta.bundleName);
74 if (meta.isEncrypt) {
75 DistributedData::SecretKeyMetaData secretKeyMeta;
76 if (!DistributedData::MetaDataManager::GetInstance().LoadMeta(meta.GetSecretKey(), secretKeyMeta, true)) {
77 return std::make_pair(E_DB_NOT_EXIST, config);
78 }
79 std::vector<uint8_t> decryptKey;
80 if (!DistributedData::CryptoManager::GetInstance().Decrypt(secretKeyMeta.sKey, decryptKey)) {
81 return std::make_pair(E_ERROR, config);
82 };
83 config.SetEncryptKey(decryptKey);
84 std::fill(decryptKey.begin(), decryptKey.end(), 0);
85 }
86 if (registerFunction) {
87 config.SetScalarFunction("remindTimer", ARGS_SIZE, RemindTimerFunc);
88 }
89 return std::make_pair(E_OK, config);
90 }
91
RdbDelegate(const DistributedData::StoreMetaData &meta, int version, bool registerFunction, const std::string &extUriData, const std::string &backup)92 RdbDelegate::RdbDelegate(const DistributedData::StoreMetaData &meta, int version,
93 bool registerFunction, const std::string &extUriData, const std::string &backup)
94 {
95 tokenId_ = meta.tokenId;
96 bundleName_ = meta.bundleName;
97 storeName_ = meta.storeId;
98 extUri_ = extUriData;
99 haMode_ = meta.haMode;
100 backup_ = backup;
101
102 auto [err, config] = GetConfig(meta, registerFunction);
103 if (err != E_OK) {
104 ZLOGW("Get rdbConfig failed, errCode is %{public}d, dir is %{public}s", err,
105 DistributedData::Anonymous::Change(meta.dataDir).c_str());
106 return;
107 }
108 DefaultOpenCallback callback;
109 store_ = RdbHelper::GetRdbStore(config, version, callback, errCode_);
110 if (errCode_ != E_OK) {
111 ZLOGW("GetRdbStore failed, errCode is %{public}d, dir is %{public}s", errCode_,
112 DistributedData::Anonymous::Change(meta.dataDir).c_str());
113 RdbDelegate::TryAndSend(errCode_);
114 }
115 }
116
TryAndSend(int errCode)117 void RdbDelegate::TryAndSend(int errCode)
118 {
119 if (errCode != E_SQLITE_CORRUPT || (haMode_ == HAMode::SINGLE && (backup_ != DUAL_WRITE && backup_ != PERIODIC))) {
120 return;
121 }
122 ZLOGE("Database corruption. BundleName: %{public}s. StoreName: %{public}s. ExtUri: %{public}s",
123 bundleName_.c_str(), storeName_.c_str(), DistributedData::Anonymous::Change(extUri_).c_str());
124 AAFwk::WantParams params;
125 params.SetParam("BundleName", AAFwk::String::Box(bundleName_));
126 params.SetParam("StoreName", AAFwk::String::Box(storeName_));
127 params.SetParam("StoreStatus", AAFwk::Integer::Box(1));
128 ExtensionConnectAdaptor::TryAndWait(extUri_, bundleName_, params);
129 }
130
InsertEx(const std::string &tableName, const DataShareValuesBucket &valuesBucket)131 std::pair<int64_t, int64_t> RdbDelegate::InsertEx(const std::string &tableName,
132 const DataShareValuesBucket &valuesBucket)
133 {
134 if (store_ == nullptr) {
135 ZLOGE("store is null");
136 return std::make_pair(E_DB_ERROR, 0);
137 }
138 int64_t rowId = 0;
139 ValuesBucket bucket = RdbDataShareAdapter::RdbUtils::ToValuesBucket(valuesBucket);
140 int ret = store_->Insert(rowId, tableName, bucket);
141 if (ret != E_OK) {
142 ZLOGE("Insert failed %{public}s %{public}d", tableName.c_str(), ret);
143 RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::PROXY_CALL_RDB,
144 RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::INSERT_RDB_ERROR);
145 if (ret == E_SQLITE_ERROR) {
146 EraseStoreCache(tokenId_);
147 }
148 RdbDelegate::TryAndSend(ret);
149 return std::make_pair(E_DB_ERROR, rowId);
150 }
151 return std::make_pair(E_OK, rowId);
152 }
153
UpdateEx( const std::string &tableName, const DataSharePredicates &predicate, const DataShareValuesBucket &valuesBucket)154 std::pair<int64_t, int64_t> RdbDelegate::UpdateEx(
155 const std::string &tableName, const DataSharePredicates &predicate, const DataShareValuesBucket &valuesBucket)
156 {
157 if (store_ == nullptr) {
158 ZLOGE("store is null");
159 return std::make_pair(E_DB_ERROR, 0);
160 }
161 int changeCount = 0;
162 ValuesBucket bucket = RdbDataShareAdapter::RdbUtils::ToValuesBucket(valuesBucket);
163 RdbPredicates predicates = RdbDataShareAdapter::RdbUtils::ToPredicates(predicate, tableName);
164 int ret = store_->Update(changeCount, bucket, predicates);
165 if (ret != E_OK) {
166 ZLOGE("Update failed %{public}s %{public}d", tableName.c_str(), ret);
167 RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::PROXY_CALL_RDB,
168 RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::UPDATE_RDB_ERROR);
169 if (ret == E_SQLITE_ERROR) {
170 EraseStoreCache(tokenId_);
171 }
172 RdbDelegate::TryAndSend(ret);
173 return std::make_pair(E_DB_ERROR, changeCount);
174 }
175 return std::make_pair(E_OK, changeCount);
176 }
177
DeleteEx(const std::string &tableName, const DataSharePredicates &predicate)178 std::pair<int64_t, int64_t> RdbDelegate::DeleteEx(const std::string &tableName, const DataSharePredicates &predicate)
179 {
180 if (store_ == nullptr) {
181 ZLOGE("store is null");
182 return std::make_pair(E_DB_ERROR, 0);
183 }
184 int changeCount = 0;
185 RdbPredicates predicates = RdbDataShareAdapter::RdbUtils::ToPredicates(predicate, tableName);
186 int ret = store_->Delete(changeCount, predicates);
187 if (ret != E_OK) {
188 ZLOGE("Delete failed %{public}s %{public}d", tableName.c_str(), ret);
189 RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::PROXY_CALL_RDB,
190 RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::DELETE_RDB_ERROR);
191 if (ret == E_SQLITE_ERROR) {
192 EraseStoreCache(tokenId_);
193 }
194 RdbDelegate::TryAndSend(ret);
195 return std::make_pair(E_DB_ERROR, changeCount);
196 }
197 return std::make_pair(E_OK, changeCount);
198 }
199
Query(const std::string &tableName, const DataSharePredicates &predicates, const std::vector<std::string> &columns, const int32_t callingPid)200 std::pair<int, std::shared_ptr<DataShareResultSet>> RdbDelegate::Query(const std::string &tableName,
201 const DataSharePredicates &predicates, const std::vector<std::string> &columns,
202 const int32_t callingPid)
203 {
204 if (store_ == nullptr) {
205 ZLOGE("store is null");
206 return std::make_pair(errCode_, nullptr);
207 }
208 int count = resultSetCount.fetch_add(1);
209 ZLOGD("start query %{public}d", count);
210 if (count > MAX_RESULTSET_COUNT && IsLimit(count, callingPid)) {
211 resultSetCount--;
212 return std::make_pair(E_RESULTSET_BUSY, nullptr);
213 }
214 RdbPredicates rdbPredicates = RdbDataShareAdapter::RdbUtils::ToPredicates(predicates, tableName);
215 std::shared_ptr<NativeRdb::ResultSet> resultSet = store_->QueryByStep(rdbPredicates, columns);
216 if (resultSet == nullptr) {
217 RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::PROXY_CALL_RDB,
218 RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::QUERY_RDB_ERROR);
219 ZLOGE("Query failed %{public}s, pid: %{public}d", tableName.c_str(), callingPid);
220 resultSetCount--;
221 return std::make_pair(E_ERROR, nullptr);
222 }
223 int err = resultSet->GetRowCount(count);
224 RdbDelegate::TryAndSend(err);
225 if (err == E_SQLITE_ERROR) {
226 ZLOGE("query failed, err:%{public}d, pid:%{public}d", E_SQLITE_ERROR, callingPid);
227 EraseStoreCache(tokenId_);
228 }
229 resultSetCallingPids.Compute(callingPid, [](const uint32_t &, int32_t &value) {
230 ++value;
231 return true;
232 });
233 int64_t beginTime = std::chrono::duration_cast<std::chrono::milliseconds>(
234 std::chrono::system_clock::now().time_since_epoch()).count();
235 auto bridge = RdbDataShareAdapter::RdbUtils::ToResultSetBridge(resultSet);
236 std::shared_ptr<DataShareResultSet> result = { new DataShareResultSet(bridge), [callingPid, beginTime](auto p) {
237 ZLOGD("release resultset");
238 resultSetCount--;
239 int64_t endTime = std::chrono::duration_cast<std::chrono::milliseconds>(
240 std::chrono::system_clock::now().time_since_epoch()).count();
241 if (endTime - beginTime > TIMEOUT_TIME) {
242 ZLOGE("pid %{public}d query time is %{public}" PRId64 ", %{public}d resultSet is used.", callingPid,
243 (endTime - beginTime), resultSetCount.load());
244 }
245 resultSetCallingPids.ComputeIfPresent(callingPid, [](const uint32_t &, int32_t &value) {
246 --value;
247 return value > 0;
248 });
249 delete p;
250 }};
251 return std::make_pair(E_OK, result);
252 }
253
Query(const std::string &sql, const std::vector<std::string> &selectionArgs)254 std::string RdbDelegate::Query(const std::string &sql, const std::vector<std::string> &selectionArgs)
255 {
256 if (store_ == nullptr) {
257 ZLOGE("store is null");
258 return "";
259 }
260 auto resultSet = store_->QueryByStep(sql, selectionArgs);
261 if (resultSet == nullptr) {
262 ZLOGE("Query failed %{private}s", sql.c_str());
263 return "";
264 }
265 int rowCount;
266 if (resultSet->GetRowCount(rowCount) == E_SQLITE_ERROR) {
267 ZLOGE("query failed, err:%{public}d", E_SQLITE_ERROR);
268 EraseStoreCache(tokenId_);
269 }
270 ResultSetJsonFormatter formatter(std::move(resultSet));
271 return DistributedData::Serializable::Marshall(formatter);
272 }
273
QuerySql(const std::string &sql)274 std::shared_ptr<NativeRdb::ResultSet> RdbDelegate::QuerySql(const std::string &sql)
275 {
276 if (store_ == nullptr) {
277 ZLOGE("store is null");
278 return nullptr;
279 }
280 auto resultSet = store_->QuerySql(sql);
281 if (resultSet == nullptr) {
282 ZLOGE("Query failed %{private}s", sql.c_str());
283 return resultSet;
284 }
285 int rowCount;
286 if (resultSet->GetRowCount(rowCount) == E_SQLITE_ERROR) {
287 ZLOGE("query failed, err:%{public}d", E_SQLITE_ERROR);
288 EraseStoreCache(tokenId_);
289 }
290 return resultSet;
291 }
292
IsInvalid()293 bool RdbDelegate::IsInvalid()
294 {
295 return store_ == nullptr;
296 }
297
IsLimit(int count, const int32_t callingPid)298 bool RdbDelegate::IsLimit(int count, const int32_t callingPid)
299 {
300 bool isFull = true;
301 for (int32_t retryCount = 0; retryCount < RETRY; retryCount++) {
302 std::this_thread::sleep_for(WAIT_TIME);
303 if (resultSetCount.load() <= MAX_RESULTSET_COUNT) {
304 isFull = false;
305 break;
306 }
307 }
308 if (!isFull) {
309 return false;
310 }
311 std::string logStr;
312 resultSetCallingPids.ForEach([&logStr](const uint32_t &key, const int32_t &value) {
313 logStr += std::to_string(key) + ":" + std::to_string(value) + ";";
314 return false;
315 });
316 ZLOGE("resultSetCount is full, pid: %{public}d, owner is %{public}s", callingPid, logStr.c_str());
317 return true;
318 }
319 } // namespace OHOS::DataShare