1 /*
2 * Copyright (C) 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 #define MLOG_TAG "RdbStore"
16
17 #include "medialibrary_rdbstore.h"
18
19 #include "media_log.h"
20 #include "medialibrary_device.h"
21 #include "medialibrary_errno.h"
22 #include "medialibrary_sync_table.h"
23 #include "sqlite_database_utils.h"
24 using namespace std;
25 using namespace OHOS::NativeRdb;
26
27 namespace OHOS {
28 namespace Media {
MediaLibraryRdbStore(const shared_ptr<OHOS::AbilityRuntime::Context> & context)29 MediaLibraryRdbStore::MediaLibraryRdbStore(const shared_ptr<OHOS::AbilityRuntime::Context> &context)
30 {
31 if (context == nullptr) {
32 MEDIA_ERR_LOG("Failed to get context");
33 return;
34 }
35 string databaseDir = context->GetDatabaseDir();
36 string name = MEDIA_DATA_ABILITY_DB_NAME;
37 int32_t errCode = 0;
38 std::string realPath = SqliteDatabaseUtils::GetDefaultDatabasePath(databaseDir, name, errCode);
39 config_.SetName(name);
40 config_.SetPath(realPath);
41 config_.SetBundleName(context->GetBundleName());
42 config_.SetArea(context->GetArea());
43 config_.SetSecurityLevel(SecurityLevel::S3);
44 MEDIA_INFO_LOG("rdb config: name: %{private}s realPath: %{private}s bundleName: %{private}s area: %{private}d",
45 name.c_str(), realPath.c_str(), context->GetBundleName().c_str(), context->GetArea());
46 Init();
47 }
48
Init()49 void MediaLibraryRdbStore::Init()
50 {
51 MEDIA_INFO_LOG("Init rdb store");
52 if (rdbStore_ != nullptr) {
53 return;
54 }
55
56 int32_t errCode = 0;
57 MediaLibraryDataCallBack rdbDataCallBack;
58 rdbStore_ = RdbHelper::GetRdbStore(config_, MEDIA_RDB_VERSION, rdbDataCallBack, errCode);
59 if (rdbStore_ == nullptr) {
60 MEDIA_ERR_LOG("GetRdbStore is failed ");
61 return;
62 }
63
64 if (rdbDataCallBack.HasDistributedTables()) {
65 int ret = rdbStore_->SetDistributedTables(
66 {MEDIALIBRARY_TABLE, SMARTALBUM_TABLE, SMARTALBUM_MAP_TABLE, CATEGORY_SMARTALBUM_MAP_TABLE});
67 MEDIA_DEBUG_LOG("ret = %{private}d", ret);
68 }
69
70 if (!SubscribeRdbStoreObserver()) {
71 MEDIA_ERR_LOG("subscribe rdb observer err");
72 return;
73 }
74
75 MEDIA_INFO_LOG("SUCCESS");
76 }
77
~MediaLibraryRdbStore()78 MediaLibraryRdbStore::~MediaLibraryRdbStore()
79 {}
80
Stop()81 void MediaLibraryRdbStore::Stop()
82 {
83 if (rdbStore_ == nullptr) {
84 return;
85 }
86
87 UnSubscribeRdbStoreObserver();
88 rdbStore_ = nullptr;
89 }
90
SubscribeRdbStoreObserver()91 bool MediaLibraryRdbStore::SubscribeRdbStoreObserver()
92 {
93 if (rdbStore_ == nullptr) {
94 MEDIA_ERR_LOG("SubscribeRdbStoreObserver rdbStore is null");
95 return false;
96 }
97 rdbStoreObs_ = make_shared<MediaLibraryRdbStoreObserver>(bundleName_);
98 if (rdbStoreObs_ == nullptr) {
99 return false;
100 }
101
102 DistributedRdb::SubscribeOption option;
103 option.mode = DistributedRdb::SubscribeMode::REMOTE;
104 int ret = rdbStore_->Subscribe(option, rdbStoreObs_.get());
105 MEDIA_DEBUG_LOG("Subscribe ret = %d", ret);
106
107 return ret == E_OK;
108 }
109
UnSubscribeRdbStoreObserver()110 bool MediaLibraryRdbStore::UnSubscribeRdbStoreObserver()
111 {
112 if (rdbStore_ == nullptr) {
113 MEDIA_ERR_LOG("UnSubscribeRdbStoreObserver rdbStore is null");
114 return false;
115 }
116
117 DistributedRdb::SubscribeOption option;
118 option.mode = DistributedRdb::SubscribeMode::REMOTE;
119 int ret = rdbStore_->UnSubscribe(option, rdbStoreObs_.get());
120 MEDIA_DEBUG_LOG("UnSubscribe ret = %d", ret);
121 if (ret == E_OK) {
122 rdbStoreObs_ = nullptr;
123 return true;
124 }
125
126 return false;
127 }
128
Insert(MediaLibraryCommand & cmd,int64_t & rowId)129 int32_t MediaLibraryRdbStore::Insert(MediaLibraryCommand &cmd, int64_t &rowId)
130 {
131 MEDIA_DEBUG_LOG("Insert");
132 if (rdbStore_ == nullptr) {
133 MEDIA_ERR_LOG("Pointer rdbStore_ is nullptr. Maybe it didn't init successfully.");
134 return E_HAS_DB_ERROR;
135 }
136
137 int32_t ret = rdbStore_->Insert(rowId, cmd.GetTableName(), cmd.GetValueBucket());
138 if (ret != NativeRdb::E_OK) {
139 MEDIA_ERR_LOG("rdbStore_->Insert failed, ret = %{public}d", ret);
140 return E_HAS_DB_ERROR;
141 }
142
143 std::vector<std::string> devices = std::vector<std::string>();
144 if (!SyncPushTable(bundleName_, cmd.GetTableName(), devices)) {
145 MEDIA_ERR_LOG("SyncPushTable Error");
146 }
147 MEDIA_DEBUG_LOG("rdbStore_->Insert end, rowId = %d, ret = %{public}d", (int)rowId, ret);
148 return ret;
149 }
150
Delete(MediaLibraryCommand & cmd,int32_t & rowId)151 int32_t MediaLibraryRdbStore::Delete(MediaLibraryCommand &cmd, int32_t &rowId)
152 {
153 MEDIA_DEBUG_LOG("Delete");
154 if (rdbStore_ == nullptr) {
155 MEDIA_ERR_LOG("Pointer rdbStore_ is nullptr. Maybe it didn't init successfully.");
156 return E_HAS_DB_ERROR;
157 }
158
159 int32_t ret = rdbStore_->Delete(rowId, cmd.GetTableName(), cmd.GetAbsRdbPredicates()->GetWhereClause(),
160 cmd.GetAbsRdbPredicates()->GetWhereArgs());
161 if (ret != NativeRdb::E_OK) {
162 MEDIA_ERR_LOG("rdbStore_->Delete failed, ret = %{public}d", ret);
163 return E_HAS_DB_ERROR;
164 }
165
166 std::vector<std::string> devices = std::vector<std::string>();
167 if (!SyncPushTable(bundleName_, cmd.GetTableName(), devices)) {
168 MEDIA_ERR_LOG("SyncPushTable Error");
169 }
170
171 return ret;
172 }
173
Update(MediaLibraryCommand & cmd,int32_t & rowId)174 int32_t MediaLibraryRdbStore::Update(MediaLibraryCommand &cmd, int32_t &rowId)
175 {
176 MEDIA_DEBUG_LOG("Update");
177 if (rdbStore_ == nullptr) {
178 MEDIA_ERR_LOG("rdbStore_ is nullptr");
179 return E_HAS_DB_ERROR;
180 }
181
182 int32_t ret = rdbStore_->Update(rowId, cmd.GetTableName(), cmd.GetValueBucket(),
183 cmd.GetAbsRdbPredicates()->GetWhereClause(), cmd.GetAbsRdbPredicates()->GetWhereArgs());
184 if (ret != NativeRdb::E_OK) {
185 MEDIA_ERR_LOG("rdbStore_->Update failed, ret = %{public}d", ret);
186 return E_HAS_DB_ERROR;
187 }
188
189 std::vector<std::string> devices = std::vector<std::string>();
190 if (!SyncPushTable(bundleName_, cmd.GetTableName(), devices)) {
191 MEDIA_ERR_LOG("SyncPushTable Error");
192 }
193
194 return ret;
195 }
196
Query(MediaLibraryCommand & cmd,const vector<string> & columns)197 std::shared_ptr<NativeRdb::AbsSharedResultSet> MediaLibraryRdbStore::Query(MediaLibraryCommand &cmd,
198 const vector<string> &columns)
199 {
200 if (rdbStore_ == nullptr) {
201 MEDIA_ERR_LOG("rdbStore_ is nullptr");
202 return nullptr;
203 }
204
205 auto predicates = cmd.GetAbsRdbPredicates();
206 return rdbStore_->Query(*predicates, columns);
207 }
208
ExecuteSql(const std::string & sql)209 int32_t MediaLibraryRdbStore::ExecuteSql(const std::string &sql)
210 {
211 MEDIA_DEBUG_LOG("ExecuteSql");
212
213 if (rdbStore_ == nullptr) {
214 MEDIA_ERR_LOG("Pointer rdbStore_ is nullptr. Maybe it didn't init successfully.");
215 return E_HAS_DB_ERROR;
216 }
217
218 int32_t ret = rdbStore_->ExecuteSql(sql);
219 if (ret != NativeRdb::E_OK) {
220 MEDIA_ERR_LOG("rdbStore_->ExecuteSql failed, ret = %{public}d", ret);
221 return E_HAS_DB_ERROR;
222 }
223 return ret;
224 }
225
QuerySql(const std::string & sql)226 std::shared_ptr<NativeRdb::AbsSharedResultSet> MediaLibraryRdbStore::QuerySql(const std::string &sql)
227 {
228 MEDIA_DEBUG_LOG("ExecuteSql");
229
230 if (rdbStore_ == nullptr) {
231 MEDIA_ERR_LOG("Pointer rdbStore_ is nullptr. Maybe it didn't init successfully.");
232 return nullptr;
233 }
234
235 auto ret = rdbStore_->QuerySql(sql);
236 if (ret != nullptr) {
237 int count;
238 ret->GetRowCount(count);
239 MEDIA_DEBUG_LOG("GetRowCount() = %{public}d", count);
240 }
241 return ret;
242 }
243
GetRaw() const244 std::shared_ptr<NativeRdb::RdbStore> MediaLibraryRdbStore::GetRaw() const
245 {
246 return rdbStore_;
247 }
248
ObtainTableName(MediaLibraryCommand & cmd)249 std::string MediaLibraryRdbStore::ObtainTableName(MediaLibraryCommand &cmd)
250 {
251 const std::string &networkId = cmd.GetOprnDevice();
252 int errCode = E_ERR;
253 if (!networkId.empty()) {
254 return rdbStore_->ObtainDistributedTableName(networkId, cmd.GetTableName(), errCode);
255 }
256
257 return cmd.GetTableName();
258 }
259
SyncPullAllTableByDeviceId(const std::string & bundleName,std::vector<std::string> & devices)260 bool MediaLibraryRdbStore::SyncPullAllTableByDeviceId(const std::string &bundleName, std::vector<std::string> &devices)
261 {
262 return MediaLibrarySyncTable::SyncPullAllTableByDeviceId(rdbStore_, bundleName, devices);
263 }
264
SyncPullTable(const std::string & bundleName,const std::string & tableName,const std::vector<std::string> & devices,bool isLast)265 bool MediaLibraryRdbStore::SyncPullTable(const std::string &bundleName, const std::string &tableName,
266 const std::vector<std::string> &devices, bool isLast)
267 {
268 std::vector<std::string> devList(devices);
269 return MediaLibrarySyncTable::SyncPullTable(rdbStore_, bundleName, tableName, devList, isLast);
270 }
271
SyncPushTable(const std::string & bundleName,const std::string & tableName,const std::vector<std::string> & devices,bool isLast)272 bool MediaLibraryRdbStore::SyncPushTable(const std::string &bundleName, const std::string &tableName,
273 const std::vector<std::string> &devices, bool isLast)
274 {
275 std::vector<std::string> devList(devices);
276 return MediaLibrarySyncTable::SyncPushTable(rdbStore_, bundleName, tableName, devList, isLast);
277 }
278
PrepareDir(RdbStore & store)279 int32_t MediaLibraryDataCallBack::PrepareDir(RdbStore &store)
280 {
281 DirValuesBucket cameraDir = {
282 CAMERA_DIRECTORY_TYPE_VALUES, CAMERA_DIR_VALUES, CAMERA_TYPE_VALUES, CAMERA_EXTENSION_VALUES
283 };
284 DirValuesBucket videoDir = {
285 VIDEO_DIRECTORY_TYPE_VALUES, VIDEO_DIR_VALUES, VIDEO_TYPE_VALUES, VIDEO_EXTENSION_VALUES
286 };
287 DirValuesBucket pictureDir = {
288 PIC_DIRECTORY_TYPE_VALUES, PIC_DIR_VALUES, PIC_TYPE_VALUES, PIC_EXTENSION_VALUES
289 };
290 DirValuesBucket audioDir = {
291 AUDIO_DIRECTORY_TYPE_VALUES, AUDIO_DIR_VALUES, AUDIO_TYPE_VALUES, AUDIO_EXTENSION_VALUES
292 };
293 DirValuesBucket documentDir = {
294 DOC_DIRECTORY_TYPE_VALUES, DOC_DIR_VALUES, DOC_TYPE_VALUES, DOC_EXTENSION_VALUES
295 };
296 DirValuesBucket downloadDir = {
297 DOWNLOAD_DIRECTORY_TYPE_VALUES, DOWNLOAD_DIR_VALUES, DOWNLOAD_TYPE_VALUES, DOWNLOAD_EXTENSION_VALUES
298 };
299
300 vector<DirValuesBucket> dirValuesBuckets = {
301 cameraDir, videoDir, pictureDir, audioDir, documentDir, downloadDir
302 };
303
304 for (auto dirValuesBucket : dirValuesBuckets) {
305 if (InsertDirValues(dirValuesBucket, store) != NativeRdb::E_OK) {
306 MEDIA_ERR_LOG("PrepareDir failed");
307 return NativeRdb::E_ERROR;
308 }
309 }
310 return NativeRdb::E_OK;
311 }
312
InsertDirValues(const DirValuesBucket & dirValuesBucket,RdbStore & store)313 int32_t MediaLibraryDataCallBack::InsertDirValues(const DirValuesBucket &dirValuesBucket, RdbStore &store)
314 {
315 ValuesBucket valuesBucket;
316 valuesBucket.PutInt(CATEGORY_MEDIATYPE_DIRECTORY_DB_DIRECTORY_TYPE, dirValuesBucket.directoryType);
317 valuesBucket.PutString(CATEGORY_MEDIATYPE_DIRECTORY_DB_DIRECTORY, dirValuesBucket.dirValues);
318 valuesBucket.PutString(CATEGORY_MEDIATYPE_DIRECTORY_DB_MEDIA_TYPE, dirValuesBucket.typeValues);
319 valuesBucket.PutString(CATEGORY_MEDIATYPE_DIRECTORY_DB_EXTENSION, dirValuesBucket.extensionValues);
320 int64_t outRowId = -1;
321 int32_t insertResult = store.Insert(outRowId, MEDIATYPE_DIRECTORY_TABLE, valuesBucket);
322 MEDIA_DEBUG_LOG("insert dir outRowId: %{public}ld insertResult: %{public}d", (long)outRowId, insertResult);
323 return insertResult;
324 }
325
PrepareSmartAlbum(RdbStore & store)326 int32_t MediaLibraryDataCallBack::PrepareSmartAlbum(RdbStore &store)
327 {
328 SmartAlbumValuesBucket trashAlbum = {
329 TRASH_ALBUM_ID_VALUES, TRASH_ALBUM_NAME_VALUES, TRASH_ALBUM_TYPE_VALUES
330 };
331
332 SmartAlbumValuesBucket favAlbum = {
333 FAVOURITE_ALBUM_ID_VALUES, FAVOURTIE_ALBUM_NAME_VALUES, FAVOURITE_ALBUM_TYPE_VALUES
334 };
335
336 vector<SmartAlbumValuesBucket> smartAlbumValuesBuckets = {
337 trashAlbum, favAlbum
338 };
339
340 for (auto smartAlbum : smartAlbumValuesBuckets) {
341 if (InsertSmartAlbumValues(smartAlbum, store) != NativeRdb::E_OK) {
342 MEDIA_ERR_LOG("Prepare smartAlbum failed");
343 return NativeRdb::E_ERROR;
344 }
345 }
346 return NativeRdb::E_OK;
347 }
348
InsertSmartAlbumValues(const SmartAlbumValuesBucket & smartAlbum,RdbStore & store)349 int32_t MediaLibraryDataCallBack::InsertSmartAlbumValues(const SmartAlbumValuesBucket &smartAlbum, RdbStore &store)
350 {
351 ValuesBucket valuesBucket;
352 valuesBucket.PutInt(SMARTALBUM_DB_ID, smartAlbum.albumId);
353 valuesBucket.PutString(SMARTALBUM_DB_NAME, smartAlbum.albumName);
354 valuesBucket.PutInt(SMARTALBUM_DB_ALBUM_TYPE, smartAlbum.albumType);
355 int64_t outRowId = -1;
356 int32_t insertResult = store.Insert(outRowId, SMARTALBUM_TABLE, valuesBucket);
357 return insertResult;
358 }
359
OnCreate(RdbStore & store)360 int32_t MediaLibraryDataCallBack::OnCreate(RdbStore &store)
361 {
362 vector<string> executeSqlStrs = {
363 CREATE_MEDIA_TABLE,
364 CREATE_SMARTALBUM_TABLE,
365 CREATE_SMARTALBUMMAP_TABLE,
366 CREATE_DEVICE_TABLE,
367 CREATE_CATEGORY_SMARTALBUMMAP_TABLE,
368 CREATE_IMAGE_VIEW,
369 CREATE_VIDEO_VIEW,
370 CREATE_AUDIO_VIEW,
371 CREATE_ABLUM_VIEW,
372 CREATE_SMARTABLUMASSETS_VIEW,
373 CREATE_ASSETMAP_VIEW,
374 CREATE_MEDIATYPE_DIRECTORY_TABLE,
375 CREATE_BUNDLE_PREMISSION_TABLE,
376 };
377
378 for (string sqlStr : executeSqlStrs) {
379 if (store.ExecuteSql(sqlStr) != NativeRdb::E_OK) {
380 return NativeRdb::E_ERROR;
381 }
382 }
383
384 if (PrepareDir(store) != NativeRdb::E_OK) {
385 return NativeRdb::E_ERROR;
386 }
387
388 if (PrepareSmartAlbum(store) != NativeRdb::E_OK) {
389 return NativeRdb::E_ERROR;
390 }
391
392 isDistributedTables = true;
393 return NativeRdb::E_OK;
394 }
395
OnUpgrade(RdbStore & store,int32_t oldVersion,int32_t newVersion)396 int32_t MediaLibraryDataCallBack::OnUpgrade(RdbStore &store, int32_t oldVersion, int32_t newVersion)
397 {
398 #ifdef RDB_UPGRADE_MOCK
399 const std::string ALTER_MOCK_COLUMN = "ALTER TABLE " + MEDIALIBRARY_TABLE +
400 " ADD COLUMN upgrade_test_column INT DEFAULT 0";
401 MEDIA_DEBUG_LOG("OnUpgrade |Rdb Verison %{private}d => %{private}d", oldVersion, newVersion);
402 int32_t result = NativeRdb::E_ERROR;
403 result = store.ExecuteSql(ALTER_MOCK_COLUMN);
404 if (result != NativeRdb::E_OK) {
405 MEDIA_ERR_LOG("Upgrade rdb error %{private}d", result);
406 }
407 #endif
408 return NativeRdb::E_OK;
409 }
410
HasDistributedTables()411 bool MediaLibraryDataCallBack::HasDistributedTables()
412 {
413 return isDistributedTables;
414 }
415
MediaLibraryRdbStoreObserver(const string & bundleName)416 MediaLibraryRdbStoreObserver::MediaLibraryRdbStoreObserver(const string &bundleName)
417 {
418 bundleName_ = bundleName;
419 isNotifyDeviceChange_ = false;
420
421 if (timer_ == nullptr) {
422 timer_ = make_unique<OHOS::Utils::Timer>(bundleName_);
423 timerId_ = timer_->Register(bind(&MediaLibraryRdbStoreObserver::NotifyDeviceChange, this),
424 NOTIFY_TIME_INTERVAL);
425 timer_->Setup();
426 }
427 }
428
~MediaLibraryRdbStoreObserver()429 MediaLibraryRdbStoreObserver::~MediaLibraryRdbStoreObserver()
430 {
431 if (timer_ != nullptr) {
432 timer_->Shutdown();
433 timer_->Unregister(timerId_);
434 timer_ = nullptr;
435 }
436 }
437
OnChange(const vector<string> & devices)438 void MediaLibraryRdbStoreObserver::OnChange(const vector<string> &devices)
439 {
440 MEDIA_INFO_LOG("MediaLibraryRdbStoreObserver OnChange call");
441 if (devices.empty() || bundleName_.empty()) {
442 return;
443 }
444 MediaLibraryDevice::GetInstance()->NotifyRemoteFileChange();
445 }
446
NotifyDeviceChange()447 void MediaLibraryRdbStoreObserver::NotifyDeviceChange()
448 {
449 if (isNotifyDeviceChange_) {
450 MediaLibraryDevice::GetInstance()->NotifyDeviceChange();
451 isNotifyDeviceChange_ = false;
452 }
453 }
454 } // namespace Media
455 } // namespace OHOS
456