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 "Thumbnail"
16
17 #include "ithumbnail_helper.h"
18
19 #include "ability_manager_client.h"
20 #include "hitrace_meter.h"
21 #include "medialibrary_errno.h"
22 #include "media_log.h"
23 #include "thumbnail_const.h"
24 #include "thumbnail_utils.h"
25
26 using namespace std;
27 using namespace OHOS::DistributedKv;
28 using namespace OHOS::NativeRdb;
29
30 namespace OHOS {
31 namespace Media {
QueryThumbnailInfo(ThumbRdbOpt & opts,ThumbnailData & outData,int & err)32 shared_ptr<AbsSharedResultSet> IThumbnailHelper::QueryThumbnailInfo(ThumbRdbOpt &opts,
33 ThumbnailData &outData, int &err)
34 {
35 if (opts.store == nullptr) {
36 MEDIA_ERR_LOG("rdbStore is not init");
37 return nullptr;
38 }
39 string filesTableName = MEDIALIBRARY_TABLE;
40 int errCode = E_ERR;
41 if (!opts.networkId.empty()) {
42 filesTableName = opts.store->ObtainDistributedTableName(opts.networkId, MEDIALIBRARY_TABLE, errCode);
43 }
44
45 MEDIA_DEBUG_LOG("Get filesTableName [ %{public}s ] id [ %{public}s ]", filesTableName.c_str(), opts.row.c_str());
46 opts.table = filesTableName;
47 shared_ptr<AbsSharedResultSet> rdbSet = ThumbnailUtils::QueryThumbnailInfo(opts, outData, err);
48 if (rdbSet == nullptr) {
49 MEDIA_ERR_LOG("QueryThumbnailInfo Faild [ %{public}d ]", err);
50 return nullptr;
51 }
52 return rdbSet;
53 }
54
CreateLcd(AsyncTaskData * data)55 void IThumbnailHelper::CreateLcd(AsyncTaskData* data)
56 {
57 GenerateAsyncTaskData* taskData = static_cast<GenerateAsyncTaskData*>(data);
58 DoCreateLcd(taskData->opts, taskData->thumbnailData, true);
59 }
60
CreateThumbnail(AsyncTaskData * data)61 void IThumbnailHelper::CreateThumbnail(AsyncTaskData* data)
62 {
63 GenerateAsyncTaskData* taskData = static_cast<GenerateAsyncTaskData*>(data);
64 DoCreateThumbnail(taskData->opts, taskData->thumbnailData, true);
65 }
66
AddAsyncTask(MediaLibraryExecute executor,ThumbRdbOpt & opts,ThumbnailData & data,bool isFront)67 void IThumbnailHelper::AddAsyncTask(MediaLibraryExecute executor, ThumbRdbOpt &opts, ThumbnailData &data, bool isFront)
68 {
69 shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
70 if (asyncWorker == nullptr) {
71 MEDIA_DEBUG_LOG("IThumbnailHelper::AddAsyncTask asyncWorker is null");
72 return;
73 }
74 GenerateAsyncTaskData* taskData = new (nothrow)GenerateAsyncTaskData();
75 if (taskData == nullptr) {
76 MEDIA_DEBUG_LOG("IThumbnailHelper::GenerateAsyncTaskData taskData is null");
77 return;
78 }
79 taskData->opts = opts;
80 taskData->thumbnailData = data;
81
82 shared_ptr<MediaLibraryAsyncTask> generateAsyncTask = make_shared<MediaLibraryAsyncTask>(executor, taskData);
83 asyncWorker->AddTask(generateAsyncTask, isFront);
84 }
85
ThumbnailWait(bool release)86 ThumbnailWait::ThumbnailWait(bool release) : needRelease_(release)
87 {}
88
~ThumbnailWait()89 ThumbnailWait::~ThumbnailWait()
90 {
91 if (needRelease_) {
92 Notify();
93 }
94 }
95
96 ThumbnailMap ThumbnailWait::thumbnailMap_;
97 std::shared_mutex ThumbnailWait::mutex_;
98
WaitFor(const shared_ptr<SyncStatus> & thumbnailWait,int waitMs,unique_lock<mutex> & lck)99 static bool WaitFor(const shared_ptr<SyncStatus>& thumbnailWait, int waitMs, unique_lock<mutex> &lck)
100 {
101 bool ret = thumbnailWait->cond_.wait_for(lck, chrono::milliseconds(waitMs),
102 [thumbnailWait]() { return thumbnailWait->isSyncComplete_; });
103 if (!ret) {
104 MEDIA_INFO_LOG("IThumbnailHelper::Wait wait for lock timeout");
105 }
106 return ret;
107 }
108
InsertAndWait(const string & id,bool isLcd)109 WaitStatus ThumbnailWait::InsertAndWait(const string &id, bool isLcd)
110 {
111 id_ = id;
112
113 if (isLcd) {
114 id_ += THUMBNAIL_LCD_END_SUFFIX;
115 }
116 unique_lock<shared_mutex> writeLck(mutex_);
117 auto iter = thumbnailMap_.find(id_);
118 if (iter != thumbnailMap_.end()) {
119 auto thumbnailWait = iter->second;
120 unique_lock<mutex> lck(thumbnailWait->mtx_);
121 writeLck.unlock();
122 bool ret = WaitFor(thumbnailWait, WAIT_FOR_MS, lck);
123 if (ret) {
124 return WaitStatus::WAIT_SUCCESS;
125 } else {
126 return WaitStatus::TIMEOUT;
127 }
128 } else {
129 shared_ptr<SyncStatus> thumbnailWait = make_shared<SyncStatus>();
130 thumbnailMap_.insert(ThumbnailMap::value_type(id_, thumbnailWait));
131 return WaitStatus::INSERT;
132 }
133 }
134
CheckAndWait(const string & id,bool isLcd)135 void ThumbnailWait::CheckAndWait(const string &id, bool isLcd)
136 {
137 id_ = id;
138
139 if (isLcd) {
140 id_ += THUMBNAIL_LCD_END_SUFFIX;
141 }
142 shared_lock<shared_mutex> readLck(mutex_);
143 auto iter = thumbnailMap_.find(id_);
144 if (iter != thumbnailMap_.end()) {
145 auto thumbnailWait = iter->second;
146 unique_lock<mutex> lck(thumbnailWait->mtx_);
147 readLck.unlock();
148 WaitFor(thumbnailWait, WAIT_FOR_MS, lck);
149 }
150 }
151
Notify()152 void ThumbnailWait::Notify()
153 {
154 unique_lock<shared_mutex> writeLck(mutex_);
155 auto iter = thumbnailMap_.find(id_);
156 if (iter != thumbnailMap_.end()) {
157 auto thumbnailWait = iter->second;
158 thumbnailMap_.erase(iter);
159 {
160 unique_lock<mutex> lck(thumbnailWait->mtx_);
161 writeLck.unlock();
162 thumbnailWait->isSyncComplete_ = true;
163 }
164 thumbnailWait->cond_.notify_all();
165 }
166 }
167
DoCreateLcd(ThumbRdbOpt & opts,ThumbnailData & data,bool force)168 bool IThumbnailHelper::DoCreateLcd(ThumbRdbOpt &opts, ThumbnailData &data, bool force)
169 {
170 ThumbnailWait thumbnailWait(true);
171 auto ret = thumbnailWait.InsertAndWait(data.id, true);
172 int err = 0;
173 if (ret == WaitStatus::WAIT_SUCCESS) {
174 ThumbnailUtils::QueryThumbnailInfo(opts, data, err);
175 return true;
176 }
177
178 if (!opts.networkId.empty()) {
179 return false;
180 }
181
182 if (data.dateModified == 0) {
183 ThumbnailUtils::QueryThumbnailInfo(opts, data, err);
184 }
185
186 if (!ThumbnailUtils::GenLcdKey(data)) {
187 MEDIA_ERR_LOG("GenLcdKey faild");
188 return false;
189 }
190
191 if (!ThumbnailUtils::IsImageExist(data.lcdKey, opts.networkId, opts.kvStore)) {
192 if (!ThumbnailUtils::LoadSourceImage(data)) {
193 MEDIA_ERR_LOG("LoadSourceImage faild");
194 return false;
195 }
196 if (!ThumbnailUtils::CreateLcdData(data, opts.size)) {
197 MEDIA_ERR_LOG("CreateLcdData faild");
198 return false;
199 }
200
201 if (ThumbnailUtils::SaveLcdData(data, opts.networkId, opts.kvStore) != Status::SUCCESS) {
202 MEDIA_ERR_LOG("SaveLcdData faild");
203 return false;
204 }
205 } else {
206 return true;
207 }
208
209 data.lcd.clear();
210 if ((data.dateModified == 0) || force) {
211 ThumbnailUtils::DeleteOriginImage(opts, data);
212 }
213 if (!ThumbnailUtils::UpdateThumbnailInfo(opts, data, err)) {
214 MEDIA_INFO_LOG("UpdateThumbnailInfo faild err : %{public}d", err);
215 return false;
216 }
217
218 return true;
219 }
220
DoCreateThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,bool force)221 bool IThumbnailHelper::DoCreateThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, bool force)
222 {
223 ThumbnailWait thumbnailWait(true);
224 auto ret = thumbnailWait.InsertAndWait(data.id, true);
225 int err = 0;
226 if (ret == WaitStatus::WAIT_SUCCESS) {
227 ThumbnailUtils::QueryThumbnailInfo(opts, data, err);
228 return true;
229 }
230 if (!opts.networkId.empty()) {
231 return false;
232 }
233
234 if (data.dateModified == 0) {
235 ThumbnailUtils::QueryThumbnailInfo(opts, data, err);
236 }
237
238 if (!ThumbnailUtils::GenThumbnailKey(data)) {
239 MEDIA_ERR_LOG("GenThumbnailKey faild");
240 return false;
241 }
242
243 if (!ThumbnailUtils::IsImageExist(data.thumbnailKey, opts.networkId, opts.kvStore)) {
244 if (!ThumbnailUtils::LoadSourceImage(data)) {
245 MEDIA_ERR_LOG("LoadSourceImage faild");
246 return false;
247 }
248 if (!ThumbnailUtils::CreateThumbnailData(data)) {
249 MEDIA_ERR_LOG("CreateThumbnailData faild");
250 return false;
251 }
252
253 if (ThumbnailUtils::SaveThumbnailData(data, opts.networkId, opts.kvStore) != Status::SUCCESS) {
254 MEDIA_ERR_LOG("SaveThumbnailData faild");
255 return false;
256 }
257 }
258
259 data.thumbnail.clear();
260 if ((data.dateModified == 0) || force) {
261 ThumbnailUtils::DeleteOriginImage(opts, data);
262 }
263 if (!ThumbnailUtils::UpdateThumbnailInfo(opts, data, err)) {
264 MEDIA_ERR_LOG("UpdateThumbnailInfo faild, %{public}d", err);
265 return false;
266 }
267
268 return true;
269 }
270
DoThumbnailSync(ThumbRdbOpt & opts,ThumbnailData & outData)271 bool IThumbnailHelper::DoThumbnailSync(ThumbRdbOpt &opts, ThumbnailData &outData)
272 {
273 ThumbnailConnection *conn = new (nothrow) ThumbnailConnection;
274 if (conn == nullptr) {
275 return false;
276 }
277 sptr<AAFwk::IAbilityConnection> callback(conn);
278 int ret = conn->GetRemoteDataShareHelper(opts, callback);
279 if (ret != E_OK) {
280 return false;
281 }
282
283 vector<string> devices = { opts.networkId };
284 opts.table = MEDIALIBRARY_TABLE;
285 if (ThumbnailUtils::SyncPullTable(opts, devices, true)) {
286 MEDIA_INFO_LOG("GetThumbnailPixelMap SyncPullTable FALSE");
287 return false;
288 }
289 shared_ptr<AbsSharedResultSet> resultSet = QueryThumbnailInfo(opts, outData, ret);
290 if ((resultSet == nullptr)) {
291 MEDIA_ERR_LOG("QueryThumbnailInfo Faild [ %{public}d ]", ret);
292 return false;
293 }
294 return true;
295 }
296
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)297 void ThumbnailConnection::OnAbilityConnectDone(
298 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
299 {
300 if (remoteObject == nullptr) {
301 MEDIA_ERR_LOG("OnAbilityConnectDone failed, remote is nullptr");
302 return;
303 }
304 {
305 unique_lock<mutex> lock(status_.mtx_);
306 dataShareProxy_ = iface_cast<DataShare::DataShareProxy>(remoteObject);
307 }
308 status_.cond_.notify_all();
309 }
310
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)311 void ThumbnailConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
312 {
313 MEDIA_DEBUG_LOG("called begin %{public}d", resultCode);
314 unique_lock<mutex> lock(status_.mtx_);
315 dataShareProxy_ = nullptr;
316 }
317
GetRemoteDataShareHelper(ThumbRdbOpt & opts,sptr<AAFwk::IAbilityConnection> & callback)318 int32_t ThumbnailConnection::GetRemoteDataShareHelper(ThumbRdbOpt &opts, sptr<AAFwk::IAbilityConnection> &callback)
319 {
320 if ((opts.context == nullptr)) {
321 MEDIA_ERR_LOG("context nullptr");
322 return E_ERR;
323 }
324
325 AAFwk::Want want;
326 want.SetElementName(BUNDLE_NAME, "DataShareExtAbility");
327 want.SetDeviceId(opts.networkId);
328 auto err = AAFwk::AbilityManagerClient::GetInstance()->ConnectAbility(want, callback, opts.context->GetToken());
329 if (err != E_OK) {
330 MEDIA_ERR_LOG("ConnectAbility failed %{public}d", err);
331 return err;
332 }
333 unique_lock<mutex> lock(status_.mtx_);
334 if (status_.cond_.wait_for(lock, chrono::seconds(WAIT_FOR_SECOND),
335 [this] { return dataShareProxy_ != nullptr; })) {
336 MEDIA_DEBUG_LOG("All Wait connect success.");
337 } else {
338 MEDIA_ERR_LOG("All Wait connect timeout.");
339 return E_THUMBNAIL_CONNECT_TIMEOUT;
340 }
341
342 Uri distriuteGenUri(opts.uri + "/" + DISTRIBUTE_THU_OPRN_CREATE);
343 DataShare::DataShareValuesBucket valuesBucket;
344 valuesBucket.Put(MEDIA_DATA_DB_URI, opts.uri);
345 auto ret = dataShareProxy_->Insert(distriuteGenUri, valuesBucket);
346 MEDIA_DEBUG_LOG("called end ret = %{public}d", ret);
347 return ret;
348 }
349 } // namespace Media
350 } // namespace OHOS
351