1 /*
2  * Copyright (c) 2023-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 "native_distributedhardwarefwk_js.h"
17 
18 #include "device_type.h"
19 #include "ipc_skeleton.h"
20 #include "js_native_api.h"
21 #include "tokenid_kit.h"
22 #include "cJSON.h"
23 #include "distributed_hardware_log.h"
24 #include "distributed_hardware_fwk_kit.h"
25 
26 using namespace OHOS::DistributedHardware;
27 
28 namespace {
29 #define GET_PARAMS(env, info, num)    \
30     size_t argc = num;                \
31     napi_value argv[num] = {nullptr}; \
32     napi_value thisVar = nullptr;     \
33     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr))
34 
35 const int32_t DH_NAPI_ARGS_ONE = 1;
36 const int32_t DH_NAPI_ARGS_TWO = 2;
37 
38 enum DHBussinessErrorCode {
39     // Permission verify failed.
40     ERR_NO_PERMISSION = 201,
41     // The caller is not a system application.
42     ERR_NOT_SYSTEM_APP = 202,
43     // Input parameter error.
44     ERR_INVALID_PARAMS = 401,
45     // The distributed hardware is not started.
46     ERR_CODE_DH_NOT_START = 24200101,
47     // The source device is not connected.
48     ERR_CODE_DEVICE_NOT_CONNECT = 24200102,
49 };
50 
51 const std::string ERR_MESSAGE_INVALID_PARAMS = "Input parameter error.";
52 const std::string ERR_MESSAGE_NO_PERMISSION = "Permission verify failed.";
53 const std::string ERR_MESSAGE_NOT_SYSTEM_APP = "The caller is not a system application.";
54 const std::string ERR_MESSAGE_DH_NOT_START = "The distributed hardware is not started.";
55 const std::string ERR_MESSAGE_DEVICE_NOT_CONNECT = "The source device is not connected.";
56 
CheckArgsType(napi_env env,bool assertion,const std::string & paramName,const std::string & type)57 bool CheckArgsType(napi_env env, bool assertion, const std::string &paramName, const std::string &type)
58 {
59     if (!(assertion)) {
60         std::string errMsg = ERR_MESSAGE_INVALID_PARAMS + "The type of " + paramName +
61                 " must be " + type;
62         napi_throw_error(env, std::to_string(ERR_INVALID_PARAMS).c_str(), errMsg.c_str());
63         return false;
64     }
65     return true;
66 }
67 
IsFunctionType(napi_env env,napi_value value)68 bool IsFunctionType(napi_env env, napi_value value)
69 {
70     napi_valuetype eventHandleType = napi_undefined;
71     napi_typeof(env, value, &eventHandleType);
72     return CheckArgsType(env, eventHandleType == napi_function, "callback", "function");
73 }
74 } // namespace
75 
JsObjectToString(const napi_env & env,const napi_value & object,const std::string & fieldStr,char * dest,const int32_t destLen)76 void DistributedHardwareManager::JsObjectToString(const napi_env &env, const napi_value &object,
77     const std::string &fieldStr, char *dest, const int32_t destLen)
78 {
79     bool hasProperty = false;
80     NAPI_CALL_RETURN_VOID(env, napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty));
81     if (hasProperty) {
82         napi_value field = nullptr;
83         napi_valuetype valueType = napi_undefined;
84 
85         napi_get_named_property(env, object, fieldStr.c_str(), &field);
86         NAPI_CALL_RETURN_VOID(env, napi_typeof(env, field, &valueType));
87         if (!CheckArgsType(env, valueType == napi_string, fieldStr.c_str(), "string")) {
88             return;
89         }
90         size_t result = 0;
91         NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, field, dest, destLen, &result));
92     } else {
93         DHLOGE("devicemanager napi js to str no property: %{public}s", fieldStr.c_str());
94     }
95 }
96 
JsObjectToInt(const napi_env & env,const napi_value & object,const std::string & fieldStr,int32_t & fieldRef)97 void DistributedHardwareManager::JsObjectToInt(const napi_env &env, const napi_value &object,
98     const std::string &fieldStr, int32_t &fieldRef)
99 {
100     bool hasProperty = false;
101     NAPI_CALL_RETURN_VOID(env, napi_has_named_property(env, object, fieldStr.c_str(), &hasProperty));
102     if (hasProperty) {
103         napi_value field = nullptr;
104         napi_valuetype valueType = napi_undefined;
105 
106         napi_get_named_property(env, object, fieldStr.c_str(), &field);
107         NAPI_CALL_RETURN_VOID(env, napi_typeof(env, field, &valueType));
108         if (!CheckArgsType(env, valueType == napi_number, fieldStr.c_str(), "number")) {
109             return;
110         }
111         napi_get_value_int32(env, field, &fieldRef);
112     } else {
113         DHLOGE("devicemanager napi js to int no property: %{public}s", fieldStr.c_str());
114     }
115 }
116 
IsSystemApp()117 bool DistributedHardwareManager::IsSystemApp()
118 {
119     uint64_t tokenId = OHOS::IPCSkeleton::GetSelfTokenID();
120     return OHOS::Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId);
121 }
122 
PauseDistributedHardware(napi_env env,napi_callback_info info)123 napi_value DistributedHardwareManager::PauseDistributedHardware(napi_env env, napi_callback_info info)
124 {
125     DHLOGI("PauseDistributedHardware in");
126     if (!IsSystemApp()) {
127         return nullptr;
128     }
129     napi_value result = nullptr;
130     size_t argc = 2;
131     napi_value argv[2] = {nullptr};
132     napi_value thisVar = nullptr;
133     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
134     NAPI_ASSERT(env, ((argc >= DH_NAPI_ARGS_ONE) && (argc <= DH_NAPI_ARGS_TWO)), "requires 1 or 2 parameter");
135 
136     napi_valuetype valueType = napi_undefined;
137     napi_typeof(env, argv[0], &valueType);
138     if (!CheckArgsType(env, valueType == napi_object, "description", "object")) {
139         return nullptr;
140     }
141     int32_t type = -1;
142     char networkId[96];
143     JsObjectToInt(env, argv[0], "type", type);
144     DHType dhType = DHType::UNKNOWN;
145     DHSubtype dhSubtype = static_cast<DHSubtype>(type);
146     if (dhSubtype == DHSubtype::AUDIO_MIC || dhSubtype == DHSubtype::AUDIO_SPEAKER) {
147         dhType = DHType::AUDIO;
148     } else if (dhSubtype == DHSubtype::CAMERA) {
149         dhType = DHType::CAMERA;
150     }
151     JsObjectToString(env, argv[0], "srcNetworkId", networkId, sizeof(networkId));
152     std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = std::make_shared<DistributedHardwareFwkKit>();
153     if (argc == DH_NAPI_ARGS_ONE) {    // promise
154         napi_deferred deferred;
155         napi_value promise = 0;
156         napi_create_promise(env, &deferred, &promise);
157         int32_t ret = dhFwkKit->PauseDistributedHardware(dhType, std::string(networkId));
158         if (ret != 0) {
159             DHLOGE("PauseDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
160         }
161         return promise;
162     } else if (argc == DH_NAPI_ARGS_TWO) {    // callback
163         if (!IsFunctionType(env, argv[1])) {
164             return nullptr;
165         }
166         int32_t ret = dhFwkKit->PauseDistributedHardware(dhType, std::string(networkId));
167         if (ret != 0) {
168             DHLOGE("PauseDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
169         }
170     }
171     napi_get_undefined(env, &result);
172     return result;
173 }
174 
ResumeDistributedHardware(napi_env env,napi_callback_info info)175 napi_value DistributedHardwareManager::ResumeDistributedHardware(napi_env env, napi_callback_info info)
176 {
177     DHLOGI("ResumeDistributedHardware in");
178     if (!IsSystemApp()) {
179         return nullptr;
180     }
181     napi_value result = nullptr;
182     size_t argc = 2;
183     napi_value argv[2] = {nullptr};
184     napi_value thisVar = nullptr;
185     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
186     NAPI_ASSERT(env, ((argc >= DH_NAPI_ARGS_ONE) && (argc <= DH_NAPI_ARGS_TWO)), "requires 1 or 2 parameter");
187 
188     napi_valuetype valueType = napi_undefined;
189     napi_typeof(env, argv[0], &valueType);
190     if (!CheckArgsType(env, valueType == napi_object, "description", "object")) {
191         return nullptr;
192     }
193     int32_t type = -1;
194     char networkId[96];
195     JsObjectToInt(env, argv[0], "type", type);
196     DHType dhType = DHType::UNKNOWN;
197     DHSubtype dhSubtype = static_cast<DHSubtype>(type);
198     if (dhSubtype == DHSubtype::AUDIO_MIC || dhSubtype == DHSubtype::AUDIO_SPEAKER) {
199         dhType = DHType::AUDIO;
200     } else if (dhSubtype == DHSubtype::CAMERA) {
201         dhType = DHType::CAMERA;
202     }
203     JsObjectToString(env, argv[0], "srcNetworkId", networkId, sizeof(networkId));
204     std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = std::make_shared<DistributedHardwareFwkKit>();
205     if (argc == DH_NAPI_ARGS_ONE) {    // promise
206         napi_deferred deferred;
207         napi_value promise = 0;
208         napi_create_promise(env, &deferred, &promise);
209         int32_t ret = dhFwkKit->ResumeDistributedHardware(dhType, std::string(networkId));
210         if (ret != 0) {
211             DHLOGE("ResumeDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
212         }
213         return promise;
214     } else if (argc == DH_NAPI_ARGS_TWO) {    // callback
215         if (!IsFunctionType(env, argv[1])) {
216             return nullptr;
217         }
218         int32_t ret = dhFwkKit->ResumeDistributedHardware(dhType, std::string(networkId));
219         if (ret != 0) {
220             DHLOGE("ResumeDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
221         }
222     }
223     napi_get_undefined(env, &result);
224     return result;
225 }
226 
StopDistributedHardware(napi_env env,napi_callback_info info)227 napi_value DistributedHardwareManager::StopDistributedHardware(napi_env env, napi_callback_info info)
228 {
229     DHLOGI("StopDistributedHardware in");
230     if (!IsSystemApp()) {
231         return nullptr;
232     }
233     napi_value result = nullptr;
234     size_t argc = 2;
235     napi_value argv[2] = {nullptr};
236     napi_value thisVar = nullptr;
237     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
238     NAPI_ASSERT(env, ((argc >= DH_NAPI_ARGS_ONE) && (argc <= DH_NAPI_ARGS_TWO)), "requires 1 or 2 parameter");
239 
240     napi_valuetype valueType = napi_undefined;
241     napi_typeof(env, argv[0], &valueType);
242     if (!CheckArgsType(env, valueType == napi_object, "description", "object")) {
243         return nullptr;
244     }
245     int32_t type = -1;
246     char networkId[96];
247     JsObjectToInt(env, argv[0], "type", type);
248     DHType dhType = DHType::UNKNOWN;
249     DHSubtype dhSubtype = static_cast<DHSubtype>(type);
250     if (dhSubtype == DHSubtype::AUDIO_MIC || dhSubtype == DHSubtype::AUDIO_SPEAKER) {
251         dhType = DHType::AUDIO;
252     } else if (dhSubtype == DHSubtype::CAMERA) {
253         dhType = DHType::CAMERA;
254     }
255     JsObjectToString(env, argv[0], "srcNetworkId", networkId, sizeof(networkId));
256     std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = std::make_shared<DistributedHardwareFwkKit>();
257     if (argc == DH_NAPI_ARGS_ONE) {    // promise
258         napi_deferred deferred;
259         napi_value promise = 0;
260         napi_create_promise(env, &deferred, &promise);
261         int32_t ret = dhFwkKit->StopDistributedHardware(dhType, std::string(networkId));
262         if (ret != 0) {
263             DHLOGE("StopDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
264         }
265         return promise;
266     } else if (argc == DH_NAPI_ARGS_TWO) {    // callback
267         if (!IsFunctionType(env, argv[1])) {
268             return nullptr;
269         }
270         int32_t ret = dhFwkKit->StopDistributedHardware(dhType, std::string(networkId));
271         if (ret != 0) {
272             DHLOGE("StopDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
273         }
274     }
275     napi_get_undefined(env, &result);
276     return result;
277 }
278 
Init(napi_env env,napi_value exports)279 napi_value DistributedHardwareManager::Init(napi_env env, napi_value exports)
280 {
281     napi_property_descriptor dhmProperties[] = {
282         DECLARE_NAPI_FUNCTION("pauseDistributedHardware", PauseDistributedHardware),
283         DECLARE_NAPI_FUNCTION("resumeDistributedHardware", ResumeDistributedHardware),
284         DECLARE_NAPI_FUNCTION("stopDistributedHardware", StopDistributedHardware),
285     };
286 
287     DHLOGI("DistributedHardwareManager::Init is called!");
288     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(dhmProperties) / sizeof(dhmProperties[0]),
289         dhmProperties));
290     DHLOGI("All functions are configured..");
291     return exports;
292 }
293 
294 /*
295  * Function registering all props and functions of ohos.distributedhardware
296  */
Export(napi_env env,napi_value exports)297 static napi_value Export(napi_env env, napi_value exports)
298 {
299     DHLOGI("Export is called!");
300     DistributedHardwareManager::Init(env, exports);
301     return exports;
302 }
303 
304 /*
305  * module define
306  */
307 static napi_module g_dhModule = {.nm_version = 1,
308                                  .nm_flags = 0,
309                                  .nm_filename = nullptr,
310                                  .nm_register_func = Export,
311                                  .nm_modname = "distributedHardware.hardwareManager",
312                                  .nm_priv = ((void *)0),
313                                  .reserved = {0}};
314 
315 /*
316  * module register
317  */
RegisterModule(void)318 extern "C" __attribute__((constructor)) void RegisterModule(void)
319 {
320     DHLOGI("RegisterModule is called!");
321     napi_module_register(&g_dhModule);
322 }