1 /*
2  * Copyright (c) 2022-2024 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 "2.0/include/dscreen_manager.h"
17 
18 #include <cinttypes>
19 #include <dlfcn.h>
20 #include <fstream>
21 #include <map>
22 
23 #include "if_system_ability_manager.h"
24 #include "iservice_registry.h"
25 #include "nlohmann/json.hpp"
26 
27 #include "dscreen_constants.h"
28 #include "dscreen_errcode.h"
29 #include "dscreen_fwkkit.h"
30 #include "dscreen_json_util.h"
31 #include "dscreen_log.h"
32 #include "dscreen_util.h"
33 #include "idscreen_sink.h"
34 #include "common/include/screen_manager_adapter.h"
35 
36 using json = nlohmann::json;
37 
38 namespace OHOS {
39 namespace DistributedHardware {
40 namespace V2_0 {
41 IMPLEMENT_SINGLE_INSTANCE(DScreenManager);
42 
43 using AVTransProviderClass = IAVEngineProvider *(*)(const std::string);
44 
45 const std::string SENDER_SO_NAME = "libdistributed_av_sender.z.so";
46 const std::string GET_PROVIDER_FUNC = "GetAVSenderEngineProvider";
47 
48 const std::map<DScreenState, std::string> stateMap = {
49     { DISABLED, "disabled" },
50     { ENABLED, "enabled" },
51     { DISABLING, "disabling" },
52     { ENABLING, "enabling" },
53     { CONNECTING, "connecting" },
54     { CONNECTED, "connected" },
55     { DISCONNECTING, "disconnecting" }
56 };
57 
DScreenManager()58 DScreenManager::DScreenManager()
59 {
60     DHLOGI("DScreenMgr construct.");
61 }
62 
~DScreenManager()63 DScreenManager::~DScreenManager()
64 {
65     DHLOGI("DScreenMgr deConstruct.");
66 }
67 
Initialize()68 int32_t DScreenManager::Initialize()
69 {
70     DHLOGI("DScreenManager::Init2.0");
71     int32_t ret = LoadAVSenderEngineProvider();
72     if (ret != DH_SUCCESS) {
73         DHLOGE("Load av transport sender engine provider failed.");
74     }
75     return ret;
76 }
77 
Release()78 int32_t DScreenManager::Release()
79 {
80     DHLOGI("DScreenManager::UnInit");
81     UnloadAVSenderEngineProvider();
82     ScreenMgrAdapter::GetInstance().UnregisterScreenGroupListener(dScreenGroupListener_);
83     {
84         std::lock_guard<std::mutex> lock(dScreenMapMtx_);
85         dScreens_.clear();
86     }
87     providerPtr_ = nullptr;
88     {
89         std::lock_guard<std::mutex> lock(dScreenCallbackMtx_);
90         dScreenCallback_ = nullptr;
91     }
92     DHLOGI("DScreenManager::UnInit success");
93     return DH_SUCCESS;
94 }
95 
OnChange(const std::vector<uint64_t> & screenIds,Rosen::ScreenGroupChangeEvent event)96 void DScreenGroupListener::OnChange(const std::vector<uint64_t> &screenIds, Rosen::ScreenGroupChangeEvent event)
97 {
98     DHLOGI("On Screen change, screenIds size: %{public}zu", screenIds.size());
99     for (uint64_t screenId : screenIds) {
100         std::shared_ptr<DScreen> changedScreen = DScreenManager::GetInstance().FindDScreenById(screenId);
101         if (changedScreen == nullptr) {
102             DHLOGD("screen change not about remote screen, screenId: %{public}" PRIu64, screenId);
103             continue;
104         }
105         DScreenManager::GetInstance().HandleScreenChange(changedScreen, event);
106     }
107 }
108 
HandleScreenChange(const std::shared_ptr<DScreen> & changedScreen,Rosen::ScreenGroupChangeEvent event)109 void DScreenManager::HandleScreenChange(const std::shared_ptr<DScreen> &changedScreen,
110     Rosen::ScreenGroupChangeEvent event)
111 {
112     if (changedScreen == nullptr) {
113         DHLOGE("DScreenManager::HandleScreenChange, dScreen is null.");
114         return;
115     }
116     DHLOGI("DScreenManager::HandleScreenChange, screenId: %{public}" PRIu64 " changeEvent: %{public}" PRIu32,
117         changedScreen->GetScreenId(), event);
118     if (event == Rosen::ScreenGroupChangeEvent::ADD_TO_GROUP) {
119         if (StartDScreenMirror(changedScreen) != DH_SUCCESS) {
120             DHLOGE("start dScreen mirror failed.");
121             return;
122         }
123         PublishMessage(DHTopic::TOPIC_START_DSCREEN, changedScreen);
124     } else if (event == Rosen::ScreenGroupChangeEvent::REMOVE_FROM_GROUP) {
125         if (StopDScreenMirror(changedScreen) != DH_SUCCESS) {
126             DHLOGE("stop dScreen mirror failed.");
127         }
128         PublishMessage(DHTopic::TOPIC_STOP_DSCREEN, changedScreen);
129     } else if (event == Rosen::ScreenGroupChangeEvent::CHANGE_GROUP) {
130         DHLOGE("CHANGE_GROUP not implement.");
131     } else {
132         DHLOGE("unknown change type.");
133     }
134 }
135 
StartDScreenMirror(const std::shared_ptr<DScreen> & dScreen)136 int32_t DScreenManager::StartDScreenMirror(const std::shared_ptr<DScreen> &dScreen)
137 {
138     if (dScreen == nullptr) {
139         DHLOGE("DScreenManager::StartDScreenMirror, dScreen is null.");
140         return ERR_DH_SCREEN_SA_VALUE_NOT_INIT;
141     }
142     uint64_t screenId = dScreen->GetScreenId();
143     DHLOGI("DScreenManager::StartDScreenMirror, screenId: %{public}" PRIu64, screenId);
144     if (dScreen->GetState() == CONNECTING) {
145         DHLOGD("screen is connecting, no need handle change");
146         return DH_SUCCESS;
147     }
148     int32_t ret = dScreen->InitSenderEngine(providerPtr_, dScreen->GetDevId());
149     if (ret != DH_SUCCESS) {
150         DHLOGE("init av transport sender engine failed.");
151         return ret;
152     }
153     dScreen->AddTask(std::make_shared<Task>(TaskType::TASK_CONNECT, ""));
154     DHLOGI("StartDScreenMirror success, screenId:%{public}" PRIu64 ", peerDeviceId:%{public}s", screenId,
155         GetAnonyString(dScreen->GetDevId()).c_str());
156     return DH_SUCCESS;
157 }
158 
StopDScreenMirror(const std::shared_ptr<DScreen> & dScreen)159 int32_t DScreenManager::StopDScreenMirror(const std::shared_ptr<DScreen> &dScreen)
160 {
161     if (dScreen == nullptr) {
162         DHLOGE("DScreenManager::StopDScreenMirror, dScreen is null.");
163         return ERR_DH_SCREEN_SA_VALUE_NOT_INIT;
164     }
165     DHLOGI("DScreenManager::StopDScreenMirror, screenId: %{public}" PRIu64, dScreen->GetScreenId());
166     if (dScreen->GetState() == DISCONNECTING) {
167         DHLOGD("screen is disconnecting, no need handle change");
168         return DH_SUCCESS;
169     }
170     dScreen->AddTask(std::make_shared<Task>(TaskType::TASK_DISCONNECT, ""));
171     return DH_SUCCESS;
172 }
173 
OnRegResult(const std::shared_ptr<DScreen> & dScreen,const std::string & reqId,const int32_t status,const std::string & data)174 void DScreenCallback::OnRegResult(const std::shared_ptr<DScreen> &dScreen,
175     const std::string &reqId, const int32_t status, const std::string &data)
176 {
177     if (dScreen == nullptr) {
178         DHLOGE("DScreenCallback::OnRegResult, dScreen id nullptr");
179         return;
180     }
181     DHLOGI("DScreenCallback::OnRegResult, devId: %{public}s, dhId: %{public}s, reqId: %{public}s",
182         GetAnonyString(dScreen->GetDevId()).c_str(), GetAnonyString(dScreen->GetDHId()).c_str(),
183         GetAnonyString(reqId).c_str());
184     DScreenManager::GetInstance().OnRegResult(dScreen, reqId, status, data);
185 }
186 
OnUnregResult(const std::shared_ptr<DScreen> & dScreen,const std::string & reqId,const int32_t status,const std::string & data)187 void DScreenCallback::OnUnregResult(const std::shared_ptr<DScreen> &dScreen,
188     const std::string &reqId, const int32_t status, const std::string &data)
189 {
190     if (dScreen == nullptr) {
191         DHLOGE("DScreenCallback::OnUnregResult, dScreen id nullptr");
192         return;
193     }
194     DHLOGI("DScreenCallback::OnUnregResult, devId: %{public}s, dhId: %{public}s, reqId: %{public}s",
195         GetAnonyString(dScreen->GetDevId()).c_str(), GetAnonyString(dScreen->GetDHId()).c_str(),
196         GetAnonyString(reqId).c_str());
197     DScreenManager::GetInstance().OnUnregResult(dScreen, reqId, status, data);
198 }
199 
OnRegResult(const std::shared_ptr<DScreen> & dScreen,const std::string & reqId,int32_t status,const std::string & data)200 void DScreenManager::OnRegResult(const std::shared_ptr<DScreen> &dScreen,
201     const std::string &reqId, int32_t status, const std::string &data)
202 {
203     DHLOGI("DScreenManager::OnRegResult, devId: %{public}s, dhId: %{public}s, reqId: %{public}s",
204         GetAnonyString(dScreen->GetDevId()).c_str(), GetAnonyString(dScreen->GetDHId()).c_str(),
205         GetAnonyString(reqId).c_str());
206     if (dScreenSourceCallbackProxy_ == nullptr) {
207         DHLOGE("dScreenSourceCallbackProxy is null");
208         return;
209     }
210     dScreenSourceCallbackProxy_->OnNotifyRegResult(dScreen->GetDevId(), dScreen->GetDHId(), reqId, status, data);
211 }
212 
OnUnregResult(const std::shared_ptr<DScreen> & dScreen,const std::string & reqId,int32_t status,const std::string & data)213 void DScreenManager::OnUnregResult(const std::shared_ptr<DScreen> &dScreen,
214     const std::string &reqId, int32_t status, const std::string &data)
215 {
216     DHLOGI("DScreenManager::OnUnregResult, devId: %{public}s, dhId: %{public}s, reqId: %{public}s",
217         GetAnonyString(dScreen->GetDevId()).c_str(), GetAnonyString(dScreen->GetDHId()).c_str(),
218         GetAnonyString(reqId).c_str());
219     if (dScreenSourceCallbackProxy_ == nullptr) {
220         DHLOGE("dScreenSourceCallbackProxy is null");
221         return;
222     }
223     dScreenSourceCallbackProxy_->OnNotifyUnregResult(dScreen->GetDevId(), dScreen->GetDHId(), reqId, status, data);
224 }
225 
EnableDistributedScreen(const std::string & devId,const std::string & dhId,const EnableParam & param,const std::string & reqId)226 int32_t DScreenManager::EnableDistributedScreen(const std::string &devId, const std::string &dhId,
227     const EnableParam &param, const std::string &reqId)
228 {
229     DHLOGI("EnableDistributedScreen2.0, devId: %{public}s, dhId:%{public}s", GetAnonyString(devId).c_str(),
230         GetAnonyString(dhId).c_str());
231     if (devId.empty() || dhId.empty() || param.sinkVersion.empty() || param.sinkAttrs.empty() || reqId.empty()) {
232         DHLOGE("EnableDistributedScreen2.0 CheckRegParams is inlvalid.");
233         return ERR_DH_SCREEN_SA_ENABLE_FAILED;
234     }
235     if (dScreenGroupListener_ == nullptr) {
236         dScreenGroupListener_ = new (std::nothrow) DScreenGroupListener();
237         int32_t ret = ScreenMgrAdapter::GetInstance().RegisterScreenGroupListener(dScreenGroupListener_);
238         if (ret != DH_SUCCESS) {
239             DHLOGE("DScreenManager2.0 EnableDistributedScreen failed, err: %{public}" PRId32, ret);
240             dScreenGroupListener_ = nullptr;
241             return ERR_DH_SCREEN_SA_ENABLE_FAILED;
242         }
243     }
244     std::string dScreenIdx = devId + SEPERATOR + dhId;
245     std::lock_guard<std::mutex> lock(dScreenMapMtx_);
246     std::shared_ptr<DScreen> dScreen = dScreens_[dScreenIdx];
247     if (dScreen == nullptr) {
248         std::lock_guard<std::mutex> lock(dScreenCallbackMtx_);
249         if (dScreenCallback_ == nullptr) {
250             dScreenCallback_ = std::make_shared<DScreenCallback>();
251         }
252         dScreen = std::make_shared<DScreen>(devId, dhId, dScreenCallback_);
253     }
254     int32_t dScreenState = dScreen->GetState();
255     if (dScreenState == ENABLED || dScreenState == ENABLING) {
256         DHLOGI("dScreen state Already is ENABLED or ENABLING.");
257         return DH_SUCCESS;
258     }
259     dScreens_[dScreenIdx] = dScreen;
260     int32_t ret = dScreen->AddTask(std::make_shared<Task>(TaskType::TASK_ENABLE, reqId, param.sinkAttrs));
261     if (ret != DH_SUCCESS) {
262         DHLOGE("EnableDistributedScreen, add task failed. devId: %{public}s, dhId:%{public}s",
263             GetAnonyString(devId).c_str(), GetAnonyString(dhId).c_str());
264     }
265     return ret;
266 }
267 
DisableDistributedScreen(const std::string & devId,const std::string & dhId,const std::string & reqId)268 int32_t DScreenManager::DisableDistributedScreen(const std::string &devId, const std::string &dhId,
269     const std::string &reqId)
270 {
271     DHLOGI("DisableDistributedScreen, devId: %{public}s, dhId:%{public}s", GetAnonyString(devId).c_str(),
272         GetAnonyString(dhId).c_str());
273     std::string dScreenIdx = devId + SEPERATOR + dhId;
274     std::lock_guard<std::mutex> lock(dScreenMapMtx_);
275     if (dScreens_.count(dScreenIdx) == 0) {
276         DHLOGE("dscreen has already disabled, devId: %{public}s, dhId: %{public}s", GetAnonyString(devId).c_str(),
277             GetAnonyString(dhId).c_str());
278         return DH_SUCCESS;
279     }
280     int32_t dScreenState = dScreens_[dScreenIdx]->GetState();
281     int32_t ret = DH_SUCCESS;
282     switch (dScreenState) {
283         case DISABLED:
284         case DISABLING:
285             DHLOGE("dScreen state is invalid.");
286             ret = ERR_DH_SCREEN_SA_DISABLE_FAILED;
287             break;
288         case ENABLED:
289         case ENABLING:
290             ret = dScreens_[dScreenIdx]->AddTask(std::make_shared<Task>(TaskType::TASK_DISABLE, reqId, ""));
291             break;
292         case CONNECTING:
293         case CONNECTED:
294         case DISCONNECTING:
295             ret = dScreens_[dScreenIdx]->AddTask(std::make_shared<Task>(TaskType::TASK_DISCONNECT, ""));
296             if (ret == DH_SUCCESS) {
297                 ret = dScreens_[dScreenIdx]->AddTask(std::make_shared<Task>(TaskType::TASK_DISABLE, reqId, ""));
298             }
299             break;
300         default:
301             ret = ERR_DH_SCREEN_SA_DISABLE_FAILED;
302             break;
303     }
304     return ret;
305 }
306 
RegisterDScreenCallback(const sptr<IDScreenSourceCallback> & callback)307 void DScreenManager::RegisterDScreenCallback(const sptr<IDScreenSourceCallback> &callback)
308 {
309     DHLOGI("RegisterDScreenCallback");
310     dScreenSourceCallbackProxy_ = callback;
311 }
312 
FindDScreenById(uint64_t screenId)313 std::shared_ptr<DScreen> DScreenManager::FindDScreenById(uint64_t screenId)
314 {
315     DHLOGD("FindDScreenById, screenId: %{public}" PRIu64, screenId);
316     std::lock_guard<std::mutex> lock(dScreenMapMtx_);
317     for (const auto &iter : dScreens_) {
318         std::shared_ptr<DScreen> dScreen = iter.second;
319         if (dScreen == nullptr) {
320             continue;
321         }
322         if (dScreen->GetScreenId() == screenId) {
323             return dScreen;
324         }
325     }
326     DHLOGD("DScreen not found, screenId: %{public}" PRIu64, screenId);
327     return nullptr;
328 }
329 
GetScreenDumpInfo(std::string & result)330 void DScreenManager::GetScreenDumpInfo(std::string &result)
331 {
332     DHLOGI("GetScreenDumpInfo.");
333     result.clear();
334     result.append("RemoteScreens OnLine:\n[\n");
335     std::lock_guard<std::mutex> lock(dScreenMapMtx_);
336     if (dScreens_.size() == 0) {
337         result.append("]");
338         DHLOGD("no virtual screen enabled in V2_0::DScreenManager.");
339         return;
340     }
341     for (const auto &iter : dScreens_) {
342         result.append("    {\n");
343         std::shared_ptr<DScreen> dScreen = iter.second;
344         if (dScreen == nullptr) {
345             continue;
346         }
347         uint64_t screenId = dScreen->GetScreenId();
348         std::string devId = dScreen->GetDevId();
349         std::shared_ptr<VideoParam> videoParam = dScreen->GetVideoParam();
350         if (videoParam == nullptr) {
351             continue;
352         }
353         uint32_t screenHeight = videoParam->GetScreenHeight();
354         uint32_t screenWidth = videoParam->GetScreenWidth();
355         DScreenState state = dScreen->GetState();
356         std::string screenState =
357             stateMap.find(state) == stateMap.end() ? "unknown state" : stateMap.find(state)->second;
358         std::string screenInfo = "        \"virtualScreenId\" : \"" + std::to_string(screenId) + "\",\n" +
359                                  "        \"localDevId\" : \"" + GetAnonyString(localDevId_) + "\",\n" +
360                                  "        \"remoteDevId\" : \"" + GetAnonyString(devId) + "\",\n" +
361                                  "        \"screenWidth\" : \"" + std::to_string(screenWidth) + "\",\n" +
362                                  "        \"screenHeight\" : \"" + std::to_string(screenHeight) + "\",\n" +
363                                  "        \"state\" : \"" + screenState + "\"\n";
364         result.append(screenInfo);
365     }
366     result.append("    }\n]");
367 }
368 
PublishMessage(const DHTopic topic,const std::shared_ptr<DScreen> & dScreen)369 void DScreenManager::PublishMessage(const DHTopic topic, const std::shared_ptr<DScreen> &dScreen)
370 {
371     DHLOGD("PublishMessage");
372     if (DScreenFwkKit::GetInstance().GetDHFwkKit() == nullptr) {
373         DHLOGE("GetDHFwkKit fail.");
374         return;
375     }
376     json messageJosn;
377     std::string message;
378     if (topic == DHTopic::TOPIC_START_DSCREEN) {
379         messageJosn[SOURCE_WIN_ID] = dScreen->GetScreenId();
380         messageJosn[SINK_DEV_ID] = dScreen->GetDevId();
381         std::shared_ptr<VideoParam> videoParam = dScreen->GetVideoParam();
382         if (videoParam == nullptr) {
383             DHLOGE("videoParam is nullptr");
384             return;
385         }
386         messageJosn[SOURCE_WIN_WIDTH] = videoParam->GetScreenWidth();
387         messageJosn[SOURCE_WIN_HEIGHT] = videoParam->GetScreenHeight();
388         message = messageJosn.dump();
389     } else if (topic == DHTopic::TOPIC_STOP_DSCREEN) {
390         messageJosn[SOURCE_WIN_ID] = dScreen->GetScreenId();
391         messageJosn[SINK_DEV_ID] = dScreen->GetDevId();
392         message = messageJosn.dump();
393     }
394     DScreenFwkKit::GetInstance().GetDHFwkKit()->PublishMessage(topic, message);
395 }
396 
LoadAVSenderEngineProvider()397 int32_t DScreenManager::LoadAVSenderEngineProvider()
398 {
399     DHLOGI("LoadAVSenderEngineProvider enter");
400     void *pHandler = dlopen(SENDER_SO_NAME.c_str(), RTLD_LAZY | RTLD_NODELETE);
401     if (pHandler == nullptr) {
402         DHLOGE("so: %{public}s load failed, failed reason : %{public}s", SENDER_SO_NAME.c_str(), dlerror());
403         return ERR_DH_AV_TRANS_NULL_VALUE;
404     }
405     AVTransProviderClass getEngineFactoryFunc = (AVTransProviderClass)dlsym(pHandler, GET_PROVIDER_FUNC.c_str());
406     if (getEngineFactoryFunc == nullptr) {
407         DHLOGE("av transport engine factory function handler is null, failed reason : %{public}s", dlerror());
408         dlclose(pHandler);
409         pHandler = nullptr;
410         return ERR_DH_AV_TRANS_NULL_VALUE;
411     }
412     providerPtr_ = getEngineFactoryFunc(OWNER_NAME_D_SCREEN);
413     return DH_SUCCESS;
414 }
415 
UnloadAVSenderEngineProvider()416 int32_t DScreenManager::UnloadAVSenderEngineProvider()
417 {
418     DHLOGI("UnloadAVSenderEngineProvider enter");
419     void *pHandler = dlopen(SENDER_SO_NAME.c_str(), RTLD_LAZY | RTLD_NODELETE);
420     if (pHandler != nullptr) {
421         dlclose(pHandler);
422         pHandler = nullptr;
423     }
424     return DH_SUCCESS;
425 }
426 } // namespace V2_0
427 } // namespace DistributedHardware
428 } // namespace OHOS
429