1 /*
2 * Copyright (C) 2021 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
16 #include "media_scanner_client.h"
17
18 using namespace OHOS::AppExecFwk;
19 using namespace OHOS::AAFwk;
20 using namespace std;
21
22 namespace OHOS {
23 namespace Media {
CreateScannerHelper()24 std::shared_ptr<IMediaScannerClient> MediaScannerHelperFactory::CreateScannerHelper()
25 {
26 return OHOS::Media::MediaScannerClient::GetMediaScannerInstance();
27 }
28
29 std::mutex MediaScannerClient::mutex_;
30 std::shared_ptr<MediaScannerClient> MediaScannerClient::msInstance_ = nullptr;
31
GetMediaScannerInstance()32 std::shared_ptr<MediaScannerClient> MediaScannerClient::GetMediaScannerInstance()
33 {
34 if (msInstance_ == nullptr) {
35 std::lock_guard<std::mutex> lock(mutex_);
36 if (msInstance_ == nullptr) {
37 msInstance_ = std::make_shared<MediaScannerClient>();
38 }
39 }
40
41 CHECK_AND_RETURN_RET_LOG(msInstance_ != nullptr, nullptr, "Failed to create new media scanner client");
42
43 return msInstance_;
44 }
45
~MediaScannerClient()46 MediaScannerClient::~MediaScannerClient()
47 {
48 connectionState_ = ConnectionState::CONN_NONE;
49 abilityMgrProxy_ = nullptr;
50 connection_ = nullptr;
51 scanList_.clear();
52 }
53
54
ConnectAbility()55 int32_t MediaScannerClient::ConnectAbility()
56 {
57 std::lock_guard<std::mutex> lock(mutex_);
58 if (!IsScannerServiceConnected()) {
59 // Obtain ability manager service for connecting to ability
60 auto abilityMgr = DelayedSingleton<SysMrgClient>::GetInstance()->GetSystemAbility(ABILITY_MGR_SERVICE_ID);
61 CHECK_AND_RETURN_RET_LOG(abilityMgr != nullptr, CONN_ERROR, "Ability Mgr instance not available");
62
63 abilityMgrProxy_ = iface_cast<IAbilityManager>(abilityMgr);
64 CHECK_AND_RETURN_RET_LOG(abilityMgrProxy_ != nullptr, CONN_ERROR, "Ability Mgr proxy is null");
65
66 // Create callback stub object and pass to fwk connect request.
67 connection_ = new (std::nothrow) MediaScannerConnectCallbackStub();
68 CHECK_AND_RETURN_RET_LOG(connection_ != nullptr, CONN_ERROR, "connect cb object create failed");
69
70 Want want;
71 want.SetElementName(SCANNER_BUNDLE_NAME, SCANNER_ABILITY_NAME);
72
73 // Connect to the service ability. Dest ability name mentioned in want param
74 SetConnectionState(ConnectionState::CONN_IN_PROGRESS);
75 int32_t ret = abilityMgrProxy_->ConnectAbility(want, connection_, nullptr);
76 if (ret != 0) {
77 MEDIA_ERR_LOG("MediaScannerClient:: Connect ability failed %{public}d", ret);
78 SetConnectionState(ConnectionState::CONN_ERROR);
79 return CONN_ERROR;
80 }
81 }
82
83 return CONN_SUCCESS;
84 }
85
DisconnectAbility()86 void MediaScannerClient::DisconnectAbility()
87 {
88 CHECK_AND_RETURN_LOG(connection_ != nullptr && abilityMgrProxy_ != nullptr, "Connection unavailable");
89
90 int32_t ret = abilityMgrProxy_->DisconnectAbility(connection_);
91 if (ret != 0) {
92 MEDIA_ERR_LOG("MediaScannerClient:: Disconnect ability failed %{public}d", ret);
93 return;
94 }
95
96 connectionState_ = ConnectionState::CONN_NONE;
97 abilityMgrProxy_ = nullptr;
98 connection_ = nullptr;
99 scanList_.clear();
100 }
101
Release()102 void MediaScannerClient::Release()
103 {
104 // If already disconnected, return from here
105 std::lock_guard<std::mutex> lock(mutex_);
106 if (!IsScannerServiceConnected()) {
107 MEDIA_ERR_LOG("Scanner Service is not connected");
108 return;
109 }
110
111 CHECK_AND_RETURN_LOG(abilityProxy_ != nullptr, "Ability service proxy unavailable");
112
113 if (abilityProxy_->IsScannerRunning()) {
114 MEDIA_ERR_LOG("scanner is running. Cannot release ability now");
115 return;
116 }
117
118 // Scanner is not running. Release ability
119 DisconnectAbility();
120 }
121
ScanDir(string & scanDirPath,const shared_ptr<IMediaScannerAppCallback> & scanDircb)122 ScanState MediaScannerClient::ScanDir(string &scanDirPath, const shared_ptr<IMediaScannerAppCallback> &scanDircb)
123 {
124 return ScanInternal(scanDirPath, scanDircb, ScanType::SCAN_DIR);
125 }
126
ScanFile(string & scanFilePath,const shared_ptr<IMediaScannerAppCallback> & scanFileCb)127 ScanState MediaScannerClient::ScanFile(string &scanFilePath, const shared_ptr<IMediaScannerAppCallback> &scanFileCb)
128 {
129 return ScanInternal(scanFilePath, scanFileCb, ScanType::SCAN_FILE);
130 }
131
ScanInternal(string & path,const shared_ptr<IMediaScannerAppCallback> & appCb,ScanType scanType)132 ScanState MediaScannerClient::ScanInternal(string &path, const shared_ptr<IMediaScannerAppCallback> &appCb,
133 ScanType scanType)
134 {
135 auto connectResult = ConnectAbility();
136 CHECK_AND_RETURN_RET_LOG(connectResult == CONN_SUCCESS, SCAN_ERROR, "Service error %{public}d", connectResult);
137
138 auto callbackStub = new(std::nothrow) MediaScannerOperationCallbackStub();
139 CHECK_AND_RETURN_RET_LOG(callbackStub != nullptr, SCAN_MEM_ALLOC_FAIL, "ScannerOperCallback creation failed");
140
141 callbackStub->SetApplicationCallback(appCb);
142
143 auto callbackRemoteObj = callbackStub->AsObject();
144 CHECK_AND_RETURN_RET_LOG(callbackRemoteObj != nullptr, SCAN_MEM_ALLOC_FAIL, "callback remote obj is null");
145
146 // If service is not connected, add the request into queue. Queue will be processed OnAbilityConnected callback
147 if (GetConnectionState() == ConnectionState::CONN_IN_PROGRESS) {
148 ScanRequest scanRequest;
149 scanRequest.scanType = scanType;
150 scanRequest.path = path;
151 scanRequest.serviceCb = callbackRemoteObj;
152 scanRequest.appCallback = appCb;
153
154 // Add request to the queue with locked scope
155 if (UpdateScanRequestQueue(scanRequest)) {
156 return SCAN_SUCCESS;
157 }
158 }
159
160 CHECK_AND_RETURN_RET_LOG(abilityProxy_ != nullptr, SCAN_ERROR, "Ability service proxy unavailable for scanning");
161
162 if (scanType == ScanType::SCAN_FILE) {
163 int32_t ret = abilityProxy_->ScanFileService(path, callbackRemoteObj);
164 CHECK_AND_RETURN_RET_LOG(ret == 0, static_cast<ScanState>(ret), "Scan file failed [%{public}d]", ret);
165 } else if (scanType == ScanType::SCAN_DIR) {
166 int32_t ret = abilityProxy_->ScanDirService(path, callbackRemoteObj);
167 CHECK_AND_RETURN_RET_LOG(ret == 0, static_cast<ScanState>(ret), "Scan dir failed [%{public}d]", ret);
168 }
169
170 return SCAN_SUCCESS;
171 }
172
IsScannerServiceConnected()173 bool MediaScannerClient::IsScannerServiceConnected()
174 {
175 ConnectionState connState = GetConnectionState();
176 if (connState == ConnectionState::CONN_SUCCESS || connState == ConnectionState::CONN_IN_PROGRESS) {
177 return true;
178 }
179
180 return false;
181 }
182
SetConnectionState(ConnectionState connState)183 void MediaScannerClient::SetConnectionState(ConnectionState connState)
184 {
185 connectionState_ = connState;
186 }
187
GetConnectionState()188 ConnectionState MediaScannerClient::GetConnectionState()
189 {
190 return connectionState_;
191 }
192
EmptyScanRequestQueue(bool isConnected)193 void MediaScannerClient::EmptyScanRequestQueue(bool isConnected)
194 {
195 for (auto &scanRequest : scanList_) {
196 if (!isConnected) {
197 MEDIA_ERR_LOG("Remote object unavailable. Notify registered clients");
198 CHECK_AND_RETURN_LOG(scanRequest.appCallback != nullptr, "Invalid app callback object");
199 scanRequest.appCallback->OnScanFinished(SCAN_ERROR, "", scanRequest.path);
200 continue;
201 }
202
203 CHECK_AND_RETURN_LOG(abilityProxy_ != nullptr, "Ability service unavailable");
204 auto ret(0);
205 switch (scanRequest.scanType) {
206 case SCAN_FILE:
207 ret = abilityProxy_->ScanFileService(scanRequest.path, scanRequest.serviceCb);
208 if (ret != SCAN_SUCCESS) {
209 MEDIA_ERR_LOG("Scan file operation failed %{public}d", ret);
210 scanRequest.appCallback->OnScanFinished(ret, "", scanRequest.path);
211 }
212 break;
213 case SCAN_DIR:
214 ret = abilityProxy_->ScanDirService(scanRequest.path, scanRequest.serviceCb);
215 if (ret != SCAN_SUCCESS) {
216 MEDIA_ERR_LOG("Scan dir operation failed %{public}d", ret);
217 scanRequest.appCallback->OnScanFinished(ret, "", scanRequest.path);
218 }
219 break;
220 default:
221 break;
222 }
223 }
224
225 scanList_.clear();
226 }
227
UpdateScanRequestQueue(ScanRequest & scanRequest)228 bool MediaScannerClient::UpdateScanRequestQueue(ScanRequest &scanRequest)
229 {
230 std::lock_guard<std::mutex> lock(mutex_);
231 if (GetConnectionState() == ConnectionState::CONN_IN_PROGRESS) {
232 scanList_.emplace_back(scanRequest);
233 return true;
234 }
235
236 return false;
237 }
238
OnConnectAbility(const sptr<IRemoteObject> & remoteObject,int32_t result)239 void MediaScannerClient::OnConnectAbility(const sptr<IRemoteObject> &remoteObject, int32_t result)
240 {
241 sptr<IMediaScannerAbility> scannerAbilityProxy = iface_cast<IMediaScannerAbility>(remoteObject);
242
243 std::lock_guard<std::mutex> lock(mutex_);
244 if (result == 0 && scannerAbilityProxy != nullptr) {
245 SetConnectionState(ConnectionState::CONN_SUCCESS);
246 abilityProxy_ = scannerAbilityProxy;
247 MediaScannerClient::EmptyScanRequestQueue(true);
248 } else {
249 SetConnectionState(ConnectionState::CONN_ERROR);
250 abilityProxy_ = nullptr;
251 MediaScannerClient::EmptyScanRequestQueue(false);
252 }
253 }
254
OnDisconnectAbility()255 void MediaScannerClient::OnDisconnectAbility()
256 {
257 abilityProxy_ = nullptr;
258
259 std::lock_guard<std::mutex> lock(mutex_);
260 SetConnectionState(ConnectionState::CONN_NONE);
261
262 // Clear all pending requests. Since service is disconnected, we cannot process any requests
263 if (!scanList_.empty()) {
264 MediaScannerClient::EmptyScanRequestQueue(false);
265 }
266 }
267
268 // Connect callback impl
MediaScannerConnectCallbackStub()269 MediaScannerConnectCallbackStub::MediaScannerConnectCallbackStub()
270 {
271 scannerClientInstance_ = MediaScannerClient::GetMediaScannerInstance();
272 }
273
~MediaScannerConnectCallbackStub()274 MediaScannerConnectCallbackStub::~MediaScannerConnectCallbackStub()
275 {
276 scannerClientInstance_ = nullptr;
277 }
278
OnAbilityConnectDone(const OHOS::AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t result)279 void MediaScannerConnectCallbackStub::OnAbilityConnectDone(const OHOS::AppExecFwk::ElementName &element,
280 const sptr<IRemoteObject> &remoteObject, int32_t result)
281 {
282 CHECK_AND_RETURN_LOG(scannerClientInstance_ != nullptr, "Scanner instance is down in OnAbilityConnectDone");
283 scannerClientInstance_->OnConnectAbility(remoteObject, result);
284 }
285
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int32_t result)286 void MediaScannerConnectCallbackStub::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int32_t result)
287 {
288 CHECK_AND_RETURN_LOG(scannerClientInstance_ != nullptr, "Scanner instance is down in OnAbilityDisconnectDone");
289 scannerClientInstance_->OnDisconnectAbility();
290 }
291 } // namespace Media
292 } // namespace OHOS
293