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