1 /*
2  * Copyright (c) 2022-2023 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 "1.0/include/screenregionmgr.h"
17 
18 #include "display_manager.h"
19 #include "if_system_ability_manager.h"
20 #include "iservice_registry.h"
21 #include "nlohmann/json.hpp"
22 
23 #include "dscreen_errcode.h"
24 #include "dscreen_constants.h"
25 #include "dscreen_fwkkit.h"
26 #include "dscreen_json_util.h"
27 #include "dscreen_log.h"
28 #include "dscreen_maprelation.h"
29 #include "dscreen_util.h"
30 #include "screen_client.h"
31 #include "idscreen_source.h"
32 #include "screen_client_common.h"
33 
34 using json = nlohmann::json;
35 
36 namespace OHOS {
37 namespace DistributedHardware {
38 namespace V1_0 {
39 IMPLEMENT_SINGLE_INSTANCE(ScreenRegionManager);
ScreenRegionManager()40 ScreenRegionManager::ScreenRegionManager()
41 {
42     DHLOGI("ScreenRegionManager");
43 }
44 
~ScreenRegionManager()45 ScreenRegionManager::~ScreenRegionManager()
46 {
47     DHLOGI("~ScreenRegionManager");
48 }
49 
ReleaseAllRegions()50 int32_t ScreenRegionManager::ReleaseAllRegions()
51 {
52     DHLOGI("ScreenRegionManager::ReleaseAllRegion");
53     std::lock_guard<std::mutex> lock(screenRegionsMtx_);
54     for (const auto &item : screenRegions_) {
55         std::shared_ptr<ScreenRegion> screenRegion = item.second;
56         if (screenRegion == nullptr) {
57             continue;
58         }
59         int32_t ret = screenRegion->Stop();
60         if (ret != DH_SUCCESS) {
61             DHLOGE("Release region failed, remoteDevId: %{public}s, err: %{public}" PRId32,
62                 GetAnonyString(screenRegion->GetRemoteDevId()).c_str(), ret);
63         }
64     }
65     screenRegions_.clear();
66     return DH_SUCCESS;
67 }
68 
HandleDScreenNotify(const std::string & remoteDevId,int32_t eventCode,const std::string & eventContent)69 void ScreenRegionManager::HandleDScreenNotify(const std::string &remoteDevId, int32_t eventCode,
70     const std::string &eventContent)
71 {
72     DHLOGI("HandleDScreenNotify, remoteDevId: %{public}s, eventCode: %{public}" PRId32,
73         GetAnonyString(remoteDevId).c_str(), eventCode);
74     if (eventCode == NOTIFY_SINK_SETUP) {
75         HandleNotifySetUp(remoteDevId, eventContent);
76         return;
77     }
78     DHLOGE("invalid event.");
79 }
80 
GetScreenDumpInfo(std::string & result)81 void ScreenRegionManager::GetScreenDumpInfo(std::string &result)
82 {
83     DHLOGI("GetScreenDumpInfo.");
84     result.clear();
85     result.append("screenRegion OnLine:\n[\n");
86     if (screenRegions_.size() == 0) {
87         result.append("]");
88         DHLOGD("no screenRegion");
89         return;
90     }
91 
92     for (const auto &iter : screenRegions_) {
93         result.append("    {\n");
94         std::shared_ptr<ScreenRegion> screenRegion = iter.second;
95         if (screenRegion == nullptr) {
96             continue;
97         }
98         uint64_t screenId = screenRegion->GetScreenId();
99         std::string remoteDevId = screenRegion->GetRemoteDevId();
100         std::shared_ptr<VideoParam> videoParam = screenRegion->GetVideoParam();
101         if (videoParam == nullptr) {
102             continue;
103         }
104         uint32_t screenHeight = videoParam->GetScreenHeight();
105         uint32_t screenWidth = videoParam->GetScreenWidth();
106         int32_t windowId = screenRegion->GetWindowId();
107         std::string screenInfo = "        \"clientWindowId\" : \"" + std::to_string(windowId) + "\",\n" +
108                                  "        \"remoteScreenId\" : \"" + std::to_string(screenId) + "\",\n" +
109                                  "        \"localDevId\" : \"" + GetAnonyString(localDevId_) + "\",\n" +
110                                  "        \"remoteDevId\" : \"" + GetAnonyString(remoteDevId) + "\",\n" +
111                                  "        \"screenWidth\" : \"" + std::to_string(screenWidth) + "\",\n" +
112                                  "        \"screenHeight\" : \"" + std::to_string(screenHeight) + "\"\n";
113         result.append(screenInfo);
114     }
115     result.append("    }\n]");
116 }
117 
CheckContentJson(json & eventContentJson)118 bool ScreenRegionManager::CheckContentJson(json &eventContentJson)
119 {
120     if (!IsUInt64(eventContentJson, KEY_SCREEN_ID)) {
121         return false;
122     }
123     if (!IsString(eventContentJson, KEY_DH_ID)) {
124         return false;
125     }
126     if (eventContentJson.contains(KEY_VERSION) && !IsString(eventContentJson, KEY_VERSION)) {
127         return false;
128     }
129     return true;
130 }
131 
HandleNotifySetUp(const std::string & remoteDevId,const std::string & eventContent)132 void ScreenRegionManager::HandleNotifySetUp(const std::string &remoteDevId, const std::string &eventContent)
133 {
134     DHLOGI("HandleNotifySetUp, remoteDevId: %{public}s", GetAnonyString(remoteDevId).c_str());
135     json eventContentJson = json::parse(eventContent, nullptr, false);
136     if (eventContentJson.is_discarded()||!CheckContentJson(eventContentJson) ||
137         !eventContentJson.contains(KEY_VIDEO_PARAM) || !eventContentJson.contains(KEY_MAPRELATION)) {
138         NotifyRemoteSourceSetUpResult(remoteDevId, "", ERR_DH_SCREEN_SA_SCREENREGION_SETUP_FAIL, "");
139         return;
140     }
141     std::string version = "1.0";
142     if (IsString(eventContentJson, KEY_VERSION)) {
143         version = eventContentJson[KEY_VERSION].get<std::string>();
144     }
145     uint64_t screenId = eventContentJson[KEY_SCREEN_ID].get<uint64_t>();
146     std::string dhId = eventContentJson[KEY_DH_ID].get<std::string>();
147 
148     std::shared_ptr<VideoParam> videoParam =
149         std::make_shared<VideoParam>(eventContentJson[KEY_VIDEO_PARAM].get<VideoParam>());
150     std::shared_ptr<DScreenMapRelation> mapRelation =
151         std::make_shared<DScreenMapRelation>(eventContentJson[KEY_MAPRELATION].get<DScreenMapRelation>());
152 
153     uint64_t displayId = Rosen::DisplayManager::GetInstance().GetDefaultDisplayId();
154     std::shared_ptr<ScreenRegion> screenRegion = std::make_shared<ScreenRegion>(remoteDevId, screenId, displayId);
155     screenRegion->SetVideoParam(videoParam);
156     screenRegion->SetMapRelation(mapRelation);
157 
158     int32_t ret = DH_SUCCESS;
159     {
160         std::lock_guard<std::mutex> lock(screenRegionsMtx_);
161         if (screenRegions_.count(remoteDevId) != 0) {
162             ret = screenRegions_[remoteDevId]->Stop();
163         }
164 
165         if (ret != DH_SUCCESS) {
166             DHLOGE("screenRegion stop failed, remoteDevId: %{public}s, err: %{public}" PRId32,
167                 GetAnonyString(screenRegions_[remoteDevId]->GetRemoteDevId()).c_str(), ret);
168             NotifyRemoteSourceSetUpResult(remoteDevId, dhId, ERR_DH_SCREEN_SA_SCREENREGION_SETUP_FAIL, "");
169             return;
170         }
171         screenRegions_[remoteDevId] = screenRegion;
172     }
173     ret = screenRegion->SetUp(version);
174     if (ret != DH_SUCCESS) {
175         NotifyRemoteSourceSetUpResult(remoteDevId, dhId, ERR_DH_SCREEN_SA_SCREENREGION_SETUP_FAIL, "");
176         return;
177     }
178 
179     ret = screenRegion->Start();
180     if (ret != DH_SUCCESS) {
181         NotifyRemoteSourceSetUpResult(remoteDevId, dhId, ERR_DH_SCREEN_SA_SCREENREGION_START_FAIL, "");
182         return;
183     }
184 
185     PublishMessage(DHTopic::TOPIC_SINK_PROJECT_WINDOW_INFO, screenId, remoteDevId, screenRegion->GetWindowId(),
186         screenRegion->GetWindowProperty());
187     NotifyRemoteSourceSetUpResult(remoteDevId, dhId, DH_SUCCESS, "");
188 }
189 
NotifyRemoteSourceSetUpResult(const std::string & remoteDevId,const std::string & dhId,int32_t errCode,const std::string & errContent)190 void ScreenRegionManager::NotifyRemoteSourceSetUpResult(const std::string &remoteDevId, const std::string &dhId,
191     int32_t errCode, const std::string &errContent)
192 {
193     DHLOGI("NotifyRemoteSourceSetUpResult, sourceDevId: %{public}s, dhId: %{public}s, errCode: %{public}" PRId32,
194         GetAnonyString(remoteDevId).c_str(), GetAnonyString(dhId).c_str(), errCode);
195     int32_t eventCode = NOTIFY_SOURCE_SETUP_RESULT;
196 
197     json eventContentJson;
198     eventContentJson[KEY_DH_ID] = dhId;
199     eventContentJson[KEY_ERR_CODE] = errCode;
200     eventContentJson[KEY_ERR_CONTENT] = errContent;
201 
202     std::string eventContent = eventContentJson.dump();
203 
204     NotifyRemoteScreenService(remoteDevId, dhId, eventCode, eventContent);
205 }
206 
NotifyRemoteScreenService(const std::string & remoteDevId,const std::string & dhId,int32_t eventCode,const std::string & eventContent)207 int32_t ScreenRegionManager::NotifyRemoteScreenService(const std::string &remoteDevId, const std::string &dhId,
208     int32_t eventCode, const std::string &eventContent)
209 {
210     DHLOGI("Notify remote source screen service, remote devId: %{public}s, eventCode: %{public}" PRId32,
211         GetAnonyString(remoteDevId).c_str(), eventCode);
212     sptr<IDScreenSource> remoteSourceSA = GetDScreenSourceSA(remoteDevId);
213     if (remoteSourceSA == nullptr) {
214         DHLOGE("get remote source sa failed.");
215         return ERR_DH_SCREEN_SA_GET_REMOTE_SOURCE_SERVICE_FAIL;
216     }
217     std::string localDevId;
218     int32_t ret = GetLocalDeviceNetworkId(localDevId);
219     if (ret != DH_SUCCESS) {
220         DHLOGE("notify remote screen service failed, cannot get local device id");
221         return ret;
222     }
223     localDevId_ = localDevId;
224     remoteSourceSA->DScreenNotify(localDevId, eventCode, eventContent);
225     return DH_SUCCESS;
226 }
227 
GetDScreenSourceSA(const std::string & devId)228 sptr<IDScreenSource> ScreenRegionManager::GetDScreenSourceSA(const std::string &devId)
229 {
230     DHLOGI("GetDScreenSourceSA, devId: %{public}s", GetAnonyString(devId).c_str());
231     sptr<ISystemAbilityManager> samgr =
232         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
233     if (samgr == nullptr) {
234         DHLOGE("Failed to get system ability mgr.");
235         return nullptr;
236     }
237     auto remoteObject = samgr->GetSystemAbility(DISTRIBUTED_HARDWARE_SCREEN_SOURCE_SA_ID, devId);
238     if (remoteObject == nullptr) {
239         DHLOGE("remoteObject is null");
240         return nullptr;
241     }
242 
243     sptr<IDScreenSource> remoteSourceSA = iface_cast<IDScreenSource>(remoteObject);
244     if (remoteSourceSA == nullptr) {
245         DHLOGE("Failed to get remote dscreen source sa");
246         return nullptr;
247     }
248     return remoteSourceSA;
249 }
250 
PublishMessage(const DHTopic topic,const uint64_t & screenId,const std::string & remoteDevId,const int32_t & windowId,std::shared_ptr<WindowProperty> windowProperty)251 void ScreenRegionManager::PublishMessage(const DHTopic topic, const uint64_t &screenId,
252     const std::string &remoteDevId, const int32_t &windowId, std::shared_ptr<WindowProperty> windowProperty)
253 {
254     DHLOGI("ScreenRegionManager PublishMessage");
255     if (DScreenFwkKit::GetInstance().GetDHFwkKit() == nullptr) {
256         DHLOGE("GetDHFwkKit fail.");
257         return;
258     }
259 
260     json messageJosn;
261     std::string message;
262     messageJosn[SOURCE_WIN_ID] = screenId;
263     messageJosn[SOURCE_DEV_ID] = remoteDevId;
264     messageJosn[SINK_SHOW_WIN_ID] = windowId;
265     messageJosn[SINK_PROJ_SHOW_WIDTH] = windowProperty->width;
266     messageJosn[SINK_PROJ_SHOW_HEIGHT] = windowProperty->height;
267     messageJosn[SINK_WIN_SHOW_X] = windowProperty->startX;
268     messageJosn[SINK_WIN_SHOW_Y] = windowProperty->startY;
269     message = messageJosn.dump();
270 
271     DScreenFwkKit::GetInstance().GetDHFwkKit()->PublishMessage(topic, message);
272 }
273 } // namespace V1_0
274 } // namespace DistributedHardware
275 } // namespace OHOS