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 #include "wallpaper_manager.h"
16
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21
22 #include <cerrno>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <fstream>
27 #include <iostream>
28 #include <mutex>
29 #include <sstream>
30
31 #include "dfx_types.h"
32 #include "file_deal.h"
33 #include "file_ex.h"
34 #include "hilog_wrapper.h"
35 #include "hitrace_meter.h"
36 #include "i_wallpaper_service.h"
37 #include "if_system_ability_manager.h"
38 #include "image_packer.h"
39 #include "image_source.h"
40 #include "image_type.h"
41 #include "iservice_registry.h"
42 #include "system_ability_definition.h"
43 #include "wallpaper_service_cb_stub.h"
44 #include "wallpaper_service_proxy.h"
45
46 namespace OHOS {
47 using namespace MiscServices;
48 namespace WallpaperMgrService {
49 constexpr int OPTION_QUALITY = 100;
WallpaperManager()50 WallpaperManager::WallpaperManager() {}
~WallpaperManager()51 WallpaperManager::~WallpaperManager()
52 {
53 std::map<int32_t, int32_t>::iterator iter = wallpaperFdMap_.begin();
54 while (iter != wallpaperFdMap_.end()) {
55 close(iter->second);
56 ++iter;
57 }
58 }
59
ResetService(const wptr<IRemoteObject> & remote)60 void WallpaperManager::ResetService(const wptr<IRemoteObject> &remote)
61 {
62 HILOG_INFO("Remote is dead, reset service instance");
63 std::lock_guard<std::mutex> lock(wpProxyLock_);
64 if (wpProxy_ != nullptr) {
65 sptr<IRemoteObject> object = wpProxy_->AsObject();
66 if ((object != nullptr) && (remote == object)) {
67 object->RemoveDeathRecipient(deathRecipient_);
68 wpProxy_ = nullptr;
69 }
70 }
71 }
72
GetService()73 sptr<IWallpaperService> WallpaperManager::GetService()
74 {
75 std::lock_guard<std::mutex> lock(wpProxyLock_);
76 if (wpProxy_ != nullptr) {
77 return wpProxy_;
78 }
79
80 sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
81 if (samgr == nullptr) {
82 HILOG_ERROR("Get samgr failed");
83 return nullptr;
84 }
85 sptr<IRemoteObject> object = samgr->GetSystemAbility(WALLPAPER_MANAGER_SERVICE_ID);
86 if (object == nullptr) {
87 HILOG_ERROR("Get wallpaper object from samgr failed");
88 return nullptr;
89 }
90
91 if (deathRecipient_ == nullptr) {
92 deathRecipient_ = new DeathRecipient();
93 }
94
95 if ((object->IsProxyObject()) && (!object->AddDeathRecipient(deathRecipient_))) {
96 HILOG_ERROR("Failed to add death recipient");
97 }
98
99 HILOG_INFO("get remote object ok");
100 wpProxy_ = iface_cast<WallpaperServiceProxy>(object);
101 if (wpProxy_ == nullptr) {
102 HILOG_ERROR("iface_cast failed");
103 }
104 return wpProxy_;
105 }
106
OnRemoteDied(const wptr<IRemoteObject> & remote)107 void WallpaperManager::DeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
108 {
109 DelayedRefSingleton<WallpaperManager>::GetInstance().ResetService(remote);
110 }
111
CallService(F func,Args &&...args)112 template<typename F, typename... Args> ErrCode WallpaperManager::CallService(F func, Args &&...args)
113 {
114 auto service = GetService();
115 if (service == nullptr) {
116 HILOG_ERROR("get service failed");
117 return ERR_DEAD_OBJECT;
118 }
119
120 ErrCode result = (service->*func)(std::forward<Args>(args)...);
121 if (SUCCEEDED(result)) {
122 return ERR_OK;
123 }
124
125 // Reset service instance if 'ERR_DEAD_OBJECT' happened.
126 if (result == ERR_DEAD_OBJECT) {
127 ResetService(service);
128 }
129
130 HILOG_ERROR("Callservice failed with: %{public}d", result);
131 return result;
132 }
133
GetColors(int32_t wallpaperType,const ApiInfo & apiInfo,std::vector<uint64_t> & colors)134 int32_t WallpaperManager::GetColors(int32_t wallpaperType, const ApiInfo &apiInfo, std::vector<uint64_t> &colors)
135 {
136 auto wpServerProxy = GetService();
137 if (wpServerProxy == nullptr) {
138 HILOG_ERROR("Get proxy failed");
139 return static_cast<int32_t>(E_DEAL_FAILED);
140 }
141 if (apiInfo.isSystemApi) {
142 return wpServerProxy->GetColorsV9(wallpaperType, colors);
143 }
144 return wpServerProxy->GetColors(wallpaperType, colors);
145 }
146
GetFile(int32_t wallpaperType,int32_t & wallpaperFd)147 int32_t WallpaperManager::GetFile(int32_t wallpaperType, int32_t &wallpaperFd)
148 {
149 auto wpServerProxy = GetService();
150 if (wpServerProxy == nullptr) {
151 HILOG_ERROR("Get proxy failed");
152 return -1;
153 }
154 std::lock_guard<std::mutex> lock(wpFdLock_);
155 std::map<int32_t, int32_t>::iterator iter = wallpaperFdMap_.find(wallpaperType);
156 if (iter != wallpaperFdMap_.end() && fcntl(iter->second, F_GETFL) != -1) {
157 close(iter->second);
158 wallpaperFdMap_.erase(iter);
159 }
160 int32_t wallpaperErrorCode = wpServerProxy->GetFile(wallpaperType, wallpaperFd);
161 if (wallpaperErrorCode == static_cast<int32_t>(E_OK) && wallpaperFd != -1) {
162 wallpaperFdMap_.insert(std::pair<int32_t, int32_t>(wallpaperType, wallpaperFd));
163 }
164 return wallpaperErrorCode;
165 }
166
SetWallpaper(std::string url,int32_t wallpaperType,const ApiInfo & apiInfo)167 int32_t WallpaperManager::SetWallpaper(std::string url, int32_t wallpaperType, const ApiInfo &apiInfo)
168 {
169 auto wpServerProxy = GetService();
170 if (wpServerProxy == nullptr) {
171 HILOG_ERROR("Get proxy failed");
172 return static_cast<int32_t>(E_DEAL_FAILED);
173 }
174 std::string fileRealPath;
175 if (!GetRealPath(url, fileRealPath)) {
176 HILOG_ERROR("get real path file failed, len = %{public}zu", url.size());
177 return static_cast<int32_t>(E_FILE_ERROR);
178 }
179 FILE *pixMap = std::fopen(fileRealPath.c_str(), "rb");
180 if (pixMap == nullptr) {
181 HILOG_ERROR("fopen faild, %{public}s, %{public}s", fileRealPath.c_str(), strerror(errno));
182 return static_cast<int32_t>(E_FILE_ERROR);
183 }
184 int32_t fend = fseek(pixMap, 0, SEEK_END);
185 int32_t length = ftell(pixMap);
186 int32_t fset = fseek(pixMap, 0, SEEK_SET);
187 if (length <= 0 || fend != 0 || fset != 0) {
188 HILOG_ERROR("ftell file failed or fseek file failed, errno %{public}d", errno);
189 fclose(pixMap);
190 return static_cast<int32_t>(E_FILE_ERROR);
191 }
192 fclose(pixMap);
193 int fd = open(fileRealPath.c_str(), O_RDONLY, 0660);
194 if (fd < 0) {
195 HILOG_ERROR("open file failed, errno %{public}d", errno);
196 ReporterFault(FaultType::SET_WALLPAPER_FAULT, FaultCode::RF_FD_INPUT_FAILED);
197 return static_cast<int32_t>(E_FILE_ERROR);
198 }
199 StartAsyncTrace(HITRACE_TAG_MISC, "SetWallpaper", static_cast<int32_t>(TraceTaskId::SET_WALLPAPER));
200 int32_t wallpaperErrorCode = 0;
201 if (apiInfo.isSystemApi) {
202 wallpaperErrorCode = wpServerProxy->SetWallpaperByFDV9(fd, wallpaperType, length);
203 } else {
204 wallpaperErrorCode = wpServerProxy->SetWallpaperByFD(fd, wallpaperType, length);
205 }
206 close(fd);
207 if (wallpaperErrorCode == static_cast<int32_t>(E_OK)) {
208 CloseWallpaperFd(wallpaperType);
209 }
210 FinishAsyncTrace(HITRACE_TAG_MISC, "SetWallpaper", static_cast<int32_t>(TraceTaskId::SET_WALLPAPER));
211 return wallpaperErrorCode;
212 }
213
SetWallpaper(std::shared_ptr<OHOS::Media::PixelMap> pixelMap,int32_t wallpaperType,const ApiInfo & apiInfo)214 int32_t WallpaperManager::SetWallpaper(std::shared_ptr<OHOS::Media::PixelMap> pixelMap, int32_t wallpaperType,
215 const ApiInfo &apiInfo)
216 {
217 auto wpServerProxy = GetService();
218 if (wpServerProxy == nullptr) {
219 HILOG_ERROR("Get proxy failed");
220 return static_cast<int32_t>(E_DEAL_FAILED);
221 }
222
223 std::stringbuf stringBuf;
224 std::ostream ostream(&stringBuf);
225 int mapSize = WritePixelMapToStream(ostream, pixelMap);
226 if (mapSize <= 0) {
227 HILOG_ERROR("WritePixelMapToStream faild");
228 return static_cast<int32_t>(E_WRITE_PARCEL_ERROR);
229 }
230 char *buffer = new (std::nothrow) char[mapSize]();
231 if (buffer == nullptr) {
232 return static_cast<int32_t>(E_NO_MEMORY);
233 }
234 stringBuf.sgetn(buffer, mapSize);
235
236 int fd[2];
237 pipe(fd);
238 fcntl(fd[1], F_SETPIPE_SZ, mapSize);
239 fcntl(fd[0], F_SETPIPE_SZ, mapSize);
240 int32_t writeSize = write(fd[1], buffer, mapSize);
241 if (writeSize != mapSize) {
242 HILOG_ERROR("Write file failed, errno %{public}d", errno);
243 ReporterFault(FaultType::SET_WALLPAPER_FAULT, FaultCode::RF_FD_INPUT_FAILED);
244 delete[] buffer;
245 return static_cast<int32_t>(E_WRITE_PARCEL_ERROR);
246 }
247 close(fd[1]);
248 int32_t wallpaperErrorCode = 0;
249 if (apiInfo.isSystemApi) {
250 wallpaperErrorCode = wpServerProxy->SetWallpaperByMapV9(fd[0], wallpaperType, mapSize);
251 } else {
252 wallpaperErrorCode = wpServerProxy->SetWallpaperByMap(fd[0], wallpaperType, mapSize);
253 }
254 close(fd[0]);
255 if (wallpaperErrorCode == static_cast<int32_t>(E_OK)) {
256 CloseWallpaperFd(wallpaperType);
257 }
258 delete[] buffer;
259 return wallpaperErrorCode;
260 }
261
WritePixelMapToStream(std::ostream & outputStream,std::shared_ptr<OHOS::Media::PixelMap> pixelMap)262 int64_t WallpaperManager::WritePixelMapToStream(std::ostream &outputStream,
263 std::shared_ptr<OHOS::Media::PixelMap> pixelMap)
264 {
265 OHOS::Media::ImagePacker imagePacker;
266 OHOS::Media::PackOption option;
267 option.format = "image/jpeg";
268 option.quality = OPTION_QUALITY;
269 option.numberHint = 1;
270 std::set<std::string> formats;
271 uint32_t ret = imagePacker.GetSupportedFormats(formats);
272 if (ret != 0) {
273 HILOG_ERROR("image packer get supported format failed, ret=%{public}u.", ret);
274 }
275
276 imagePacker.StartPacking(outputStream, option);
277 imagePacker.AddImage(*pixelMap);
278 int64_t packedSize = 0;
279 imagePacker.FinalizePacking(packedSize);
280 HILOG_INFO("FrameWork WritePixelMapToStream End! packedSize=%{public}lld.", static_cast<long long>(packedSize));
281 return packedSize;
282 }
283
GetPixelMap(int32_t wallpaperType,const ApiInfo & apiInfo,std::shared_ptr<OHOS::Media::PixelMap> & pixelMap)284 int32_t WallpaperManager::GetPixelMap(int32_t wallpaperType, const ApiInfo &apiInfo,
285 std::shared_ptr<OHOS::Media::PixelMap> &pixelMap)
286 {
287 HILOG_INFO("FrameWork GetPixelMap Start by FD");
288 auto wpServerProxy = GetService();
289 if (wpServerProxy == nullptr) {
290 HILOG_ERROR("Get proxy failed");
291 return static_cast<int32_t>(E_SA_DIED);
292 }
293 IWallpaperService::FdInfo fdInfo;
294 int32_t wallpaperErrorCode = 0;
295 if (apiInfo.isSystemApi) {
296 wallpaperErrorCode = wpServerProxy->GetPixelMapV9(wallpaperType, fdInfo);
297 } else {
298 wallpaperErrorCode = wpServerProxy->GetPixelMap(wallpaperType, fdInfo);
299 }
300 if (wallpaperErrorCode != static_cast<int32_t>(E_OK)) {
301 return wallpaperErrorCode;
302 }
303 uint32_t errorCode = 0;
304 OHOS::Media::SourceOptions opts;
305 opts.formatHint = "image/jpeg";
306 HILOG_INFO(" CreateImageSource by FD");
307 std::unique_ptr<OHOS::Media::ImageSource> imageSource =
308 OHOS::Media::ImageSource::CreateImageSource(fdInfo.fd, opts, errorCode);
309 if (errorCode != 0) {
310 HILOG_ERROR("ImageSource::CreateImageSource failed,errcode= %{public}d", errorCode);
311 return static_cast<int32_t>(E_IMAGE_ERRCODE);
312 }
313 OHOS::Media::DecodeOptions decodeOpts;
314 HILOG_INFO(" CreatePixelMap");
315 pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
316
317 if (errorCode != 0) {
318 HILOG_ERROR("ImageSource::CreatePixelMap failed,errcode= %{public}d", errorCode);
319 return static_cast<int32_t>(E_IMAGE_ERRCODE);
320 }
321 close(fdInfo.fd);
322 return wallpaperErrorCode;
323 }
324
GetWallpaperId(int wallpaperType)325 int WallpaperManager::GetWallpaperId(int wallpaperType)
326 {
327 auto wpServerProxy = GetService();
328 if (wpServerProxy == nullptr) {
329 HILOG_ERROR("Get proxy failed");
330 return -1;
331 }
332 return wpServerProxy->GetWallpaperId(wallpaperType);
333 }
334
GetWallpaperMinHeight(const ApiInfo & apiInfo,int32_t & minHeight)335 int32_t WallpaperManager::GetWallpaperMinHeight(const ApiInfo &apiInfo, int32_t &minHeight)
336 {
337 auto wpServerProxy = GetService();
338 if (wpServerProxy == nullptr) {
339 HILOG_ERROR("Get proxy failed");
340 return E_DEAL_FAILED;
341 }
342 if (apiInfo.isSystemApi) {
343 return wpServerProxy->GetWallpaperMinHeightV9(minHeight);
344 }
345 return wpServerProxy->GetWallpaperMinHeight(minHeight);
346 }
347
GetWallpaperMinWidth(const ApiInfo & apiInfo,int32_t & minWidth)348 int32_t WallpaperManager::GetWallpaperMinWidth(const ApiInfo &apiInfo, int32_t &minWidth)
349 {
350 auto wpServerProxy = GetService();
351 if (wpServerProxy == nullptr) {
352 HILOG_ERROR("Get proxy failed");
353 return E_DEAL_FAILED;
354 }
355 if (apiInfo.isSystemApi) {
356 return wpServerProxy->GetWallpaperMinWidthV9(minWidth);
357 }
358 return wpServerProxy->GetWallpaperMinWidth(minWidth);
359 }
360
IsChangePermitted()361 bool WallpaperManager::IsChangePermitted()
362 {
363 auto wpServerProxy = GetService();
364 if (wpServerProxy == nullptr) {
365 HILOG_ERROR("Get proxy failed");
366 return false;
367 }
368 return wpServerProxy->IsChangePermitted();
369 }
370
IsOperationAllowed()371 bool WallpaperManager::IsOperationAllowed()
372 {
373 auto wpServerProxy = GetService();
374 if (wpServerProxy == nullptr) {
375 HILOG_ERROR("Get proxy failed");
376 return false;
377 }
378 return wpServerProxy->IsOperationAllowed();
379 }
380
ResetWallpaper(std::int32_t wallpaperType,const ApiInfo & apiInfo)381 int32_t WallpaperManager::ResetWallpaper(std::int32_t wallpaperType, const ApiInfo &apiInfo)
382 {
383 auto wpServerProxy = GetService();
384 if (wpServerProxy == nullptr) {
385 HILOG_ERROR("Get proxy failed");
386 return static_cast<int32_t>(E_SA_DIED);
387 }
388 int32_t wallpaperErrorCode = 0;
389 if (apiInfo.isSystemApi) {
390 wallpaperErrorCode = wpServerProxy->ResetWallpaperV9(wallpaperType);
391 } else {
392 wallpaperErrorCode = wpServerProxy->ResetWallpaper(wallpaperType);
393 }
394 if (wallpaperErrorCode == static_cast<int32_t>(E_OK)) {
395 CloseWallpaperFd(wallpaperType);
396 }
397 return wallpaperErrorCode;
398 }
399
On(const std::string & type,std::shared_ptr<WallpaperColorChangeListener> listener)400 bool WallpaperManager::On(const std::string &type, std::shared_ptr<WallpaperColorChangeListener> listener)
401 {
402 HILOG_DEBUG("WallpaperManager::On in");
403 auto wpServerProxy = GetService();
404 if (wpServerProxy == nullptr) {
405 HILOG_ERROR("Get proxy failed");
406 return false;
407 }
408 if (listener == nullptr) {
409 HILOG_ERROR("listener is nullptr.");
410 return false;
411 }
412 std::lock_guard<std::mutex> lck(listenerMapMutex_);
413
414 sptr<WallpaperColorChangeListenerClient> ipcListener = new (std::nothrow)
415 WallpaperColorChangeListenerClient(listener);
416 if (ipcListener == nullptr) {
417 HILOG_ERROR("new WallpaperColorChangeListenerClient failed");
418 return false;
419 }
420 HILOG_DEBUG("WallpaperManager::On out");
421 return wpServerProxy->On(ipcListener);
422 }
423
Off(const std::string & type,std::shared_ptr<WallpaperColorChangeListener> listener)424 bool WallpaperManager::Off(const std::string &type, std::shared_ptr<WallpaperColorChangeListener> listener)
425 {
426 HILOG_DEBUG("WallpaperManager::Off in");
427 auto wpServerProxy = GetService();
428 if (wpServerProxy == nullptr) {
429 HILOG_ERROR("Get proxy failed");
430 return false;
431 }
432 std::lock_guard<std::mutex> lck(listenerMapMutex_);
433 bool status = false;
434 if (listener != nullptr) {
435 sptr<WallpaperColorChangeListenerClient> ipcListener = new (std::nothrow)
436 WallpaperColorChangeListenerClient(listener);
437 if (ipcListener == nullptr) {
438 HILOG_ERROR("new WallpaperColorChangeListenerClient failed");
439 return false;
440 }
441 status = wpServerProxy->Off(ipcListener);
442 } else {
443 status = wpServerProxy->Off(nullptr);
444 }
445 if (status == false) {
446 HILOG_ERROR("off failed");
447 return false;
448 }
449 HILOG_DEBUG("WallpaperManager::Off out");
450 return true;
451 }
452
GetCallback()453 JScallback WallpaperManager::GetCallback()
454 {
455 return callback;
456 }
457
SetCallback(bool (* cb)(int))458 void WallpaperManager::SetCallback(bool (*cb)(int))
459 {
460 callback = cb;
461 }
462
RegisterWallpaperCallback(bool (* callback)(int))463 bool WallpaperManager::RegisterWallpaperCallback(bool (*callback)(int))
464 {
465 HILOG_ERROR(" WallpaperManager::RegisterWallpaperCallback statrt");
466 SetCallback(callback);
467 auto wpServerProxy = GetService();
468 if (wpServerProxy == nullptr) {
469 HILOG_ERROR("Get proxy failed");
470 return false;
471 }
472
473 if (callback == nullptr) {
474 HILOG_ERROR("callback is NULL.");
475 return false;
476 }
477 HILOG_INFO(" WallpaperManager::RegisterWallpaperCallback");
478
479 bool status = wpServerProxy->RegisterWallpaperCallback(new WallpaperServiceCbStub());
480 if (status == false) {
481 HILOG_ERROR("off failed code=%d.", ERR_NONE);
482 return false;
483 }
484
485 return 0;
486 }
487
ReporterFault(FaultType faultType,FaultCode faultCode)488 void WallpaperManager::ReporterFault(FaultType faultType, FaultCode faultCode)
489 {
490 MiscServices::FaultMsg msg;
491 msg.faultType = faultType;
492 msg.errorCode = faultCode;
493 FaultReporter::ReportRuntimeFault(msg);
494 }
495
CloseWallpaperFd(int32_t wallpaperType)496 void WallpaperManager::CloseWallpaperFd(int32_t wallpaperType)
497 {
498 std::lock_guard<std::mutex> lock(wpFdLock_);
499 std::map<int32_t, int32_t>::iterator iter = wallpaperFdMap_.find(wallpaperType);
500 if (iter != wallpaperFdMap_.end() && fcntl(iter->second, F_GETFL) != -1) {
501 close(iter->second);
502 wallpaperFdMap_.erase(iter);
503 }
504 }
505
GetRealPath(const std::string & inOriPath,std::string & outRealPath)506 bool WallpaperManager::GetRealPath(const std::string &inOriPath, std::string &outRealPath)
507 {
508 char realPath[PATH_MAX + 1] = { 0x00 };
509 if (inOriPath.size() > PATH_MAX || realpath(inOriPath.c_str(), realPath) == nullptr) {
510 HILOG_ERROR("get real path fail");
511 return false;
512 }
513 outRealPath = std::string(realPath);
514 if (!OHOS::FileExists(outRealPath)) {
515 HILOG_ERROR("real path file is not exist! %{public}s", outRealPath.c_str());
516 return false;
517 }
518 return true;
519 }
520 } // namespace WallpaperMgrService
521 } // namespace OHOS