1 /*
2 * Copyright (c) 2023-2025 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 "ipc_skeleton.h"
19 #include "js_native_api.h"
20 #include "tokenid_kit.h"
21
22 #include "device_type.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 ¶mName, 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
CreateBusinessErr(napi_env env,int32_t errCode)123 napi_value DistributedHardwareManager::CreateBusinessErr(napi_env env, int32_t errCode)
124 {
125 napi_value error = nullptr;
126 switch (static_cast<DHBussinessErrorCode>(errCode)) {
127 case ERR_NOT_SYSTEM_APP:
128 napi_throw_error(env, std::to_string(errCode).c_str(), ERR_MESSAGE_NOT_SYSTEM_APP.c_str());
129 break;
130 case ERR_NO_PERMISSION:
131 napi_throw_error(env, std::to_string(errCode).c_str(), ERR_MESSAGE_NO_PERMISSION.c_str());
132 break;
133 case ERR_INVALID_PARAMS:
134 napi_throw_error(env, std::to_string(errCode).c_str(), ERR_MESSAGE_INVALID_PARAMS.c_str());
135 break;
136 default:
137 break;
138 }
139 return error;
140 }
141
PauseDistributedHardware(napi_env env,napi_callback_info info)142 napi_value DistributedHardwareManager::PauseDistributedHardware(napi_env env, napi_callback_info info)
143 {
144 DHLOGI("PauseDistributedHardware in");
145 if (!IsSystemApp()) {
146 CreateBusinessErr(env, ERR_NOT_SYSTEM_APP);
147 return nullptr;
148 }
149 napi_value result = nullptr;
150 size_t argc = 2;
151 napi_value argv[2] = {nullptr};
152 napi_value thisVar = nullptr;
153 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
154 NAPI_ASSERT(env, ((argc >= DH_NAPI_ARGS_ONE) && (argc <= DH_NAPI_ARGS_TWO)), "requires 1 or 2 parameter");
155
156 napi_valuetype valueType = napi_undefined;
157 napi_typeof(env, argv[0], &valueType);
158 if (!CheckArgsType(env, valueType == napi_object, "description", "object")) {
159 return nullptr;
160 }
161 int32_t type = -1;
162 char networkId[96];
163 JsObjectToInt(env, argv[0], "type", type);
164 DHType dhType = DHType::UNKNOWN;
165 DHSubtype dhSubtype = static_cast<DHSubtype>(type);
166 if (dhSubtype == DHSubtype::AUDIO_MIC || dhSubtype == DHSubtype::AUDIO_SPEAKER) {
167 dhType = DHType::AUDIO;
168 } else if (dhSubtype == DHSubtype::CAMERA) {
169 dhType = DHType::CAMERA;
170 }
171 JsObjectToString(env, argv[0], "srcNetworkId", networkId, sizeof(networkId));
172 std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = std::make_shared<DistributedHardwareFwkKit>();
173 if (argc == DH_NAPI_ARGS_ONE) { // promise
174 napi_deferred deferred;
175 napi_value promise = 0;
176 napi_create_promise(env, &deferred, &promise);
177 int32_t ret = dhFwkKit->PauseDistributedHardware(dhType, std::string(networkId));
178 if (ret != 0) {
179 DHLOGE("PauseDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
180 }
181 return promise;
182 } else if (argc == DH_NAPI_ARGS_TWO) { // callback
183 if (!IsFunctionType(env, argv[1])) {
184 return nullptr;
185 }
186 int32_t ret = dhFwkKit->PauseDistributedHardware(dhType, std::string(networkId));
187 if (ret != 0) {
188 DHLOGE("PauseDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
189 }
190 }
191 napi_get_undefined(env, &result);
192 return result;
193 }
194
ResumeDistributedHardware(napi_env env,napi_callback_info info)195 napi_value DistributedHardwareManager::ResumeDistributedHardware(napi_env env, napi_callback_info info)
196 {
197 DHLOGI("ResumeDistributedHardware in");
198 if (!IsSystemApp()) {
199 CreateBusinessErr(env, ERR_NOT_SYSTEM_APP);
200 return nullptr;
201 }
202 napi_value result = nullptr;
203 size_t argc = 2;
204 napi_value argv[2] = {nullptr};
205 napi_value thisVar = nullptr;
206 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
207 NAPI_ASSERT(env, ((argc >= DH_NAPI_ARGS_ONE) && (argc <= DH_NAPI_ARGS_TWO)), "requires 1 or 2 parameter");
208
209 napi_valuetype valueType = napi_undefined;
210 napi_typeof(env, argv[0], &valueType);
211 if (!CheckArgsType(env, valueType == napi_object, "description", "object")) {
212 return nullptr;
213 }
214 int32_t type = -1;
215 char networkId[96];
216 JsObjectToInt(env, argv[0], "type", type);
217 DHType dhType = DHType::UNKNOWN;
218 DHSubtype dhSubtype = static_cast<DHSubtype>(type);
219 if (dhSubtype == DHSubtype::AUDIO_MIC || dhSubtype == DHSubtype::AUDIO_SPEAKER) {
220 dhType = DHType::AUDIO;
221 } else if (dhSubtype == DHSubtype::CAMERA) {
222 dhType = DHType::CAMERA;
223 }
224 JsObjectToString(env, argv[0], "srcNetworkId", networkId, sizeof(networkId));
225 std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = std::make_shared<DistributedHardwareFwkKit>();
226 if (argc == DH_NAPI_ARGS_ONE) { // promise
227 napi_deferred deferred;
228 napi_value promise = 0;
229 napi_create_promise(env, &deferred, &promise);
230 int32_t ret = dhFwkKit->ResumeDistributedHardware(dhType, std::string(networkId));
231 if (ret != 0) {
232 DHLOGE("ResumeDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
233 }
234 return promise;
235 } else if (argc == DH_NAPI_ARGS_TWO) { // callback
236 if (!IsFunctionType(env, argv[1])) {
237 return nullptr;
238 }
239 int32_t ret = dhFwkKit->ResumeDistributedHardware(dhType, std::string(networkId));
240 if (ret != 0) {
241 DHLOGE("ResumeDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
242 }
243 }
244 napi_get_undefined(env, &result);
245 return result;
246 }
247
StopDistributedHardware(napi_env env,napi_callback_info info)248 napi_value DistributedHardwareManager::StopDistributedHardware(napi_env env, napi_callback_info info)
249 {
250 DHLOGI("StopDistributedHardware in");
251 if (!IsSystemApp()) {
252 CreateBusinessErr(env, ERR_NOT_SYSTEM_APP);
253 return nullptr;
254 }
255 napi_value result = nullptr;
256 size_t argc = 2;
257 napi_value argv[2] = {nullptr};
258 napi_value thisVar = nullptr;
259 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
260 NAPI_ASSERT(env, ((argc >= DH_NAPI_ARGS_ONE) && (argc <= DH_NAPI_ARGS_TWO)), "requires 1 or 2 parameter");
261
262 napi_valuetype valueType = napi_undefined;
263 napi_typeof(env, argv[0], &valueType);
264 if (!CheckArgsType(env, valueType == napi_object, "description", "object")) {
265 return nullptr;
266 }
267 int32_t type = -1;
268 char networkId[96];
269 JsObjectToInt(env, argv[0], "type", type);
270 DHType dhType = DHType::UNKNOWN;
271 DHSubtype dhSubtype = static_cast<DHSubtype>(type);
272 if (dhSubtype == DHSubtype::AUDIO_MIC || dhSubtype == DHSubtype::AUDIO_SPEAKER) {
273 dhType = DHType::AUDIO;
274 } else if (dhSubtype == DHSubtype::CAMERA) {
275 dhType = DHType::CAMERA;
276 }
277 JsObjectToString(env, argv[0], "srcNetworkId", networkId, sizeof(networkId));
278 std::shared_ptr<DistributedHardwareFwkKit> dhFwkKit = std::make_shared<DistributedHardwareFwkKit>();
279 if (argc == DH_NAPI_ARGS_ONE) { // promise
280 napi_deferred deferred;
281 napi_value promise = 0;
282 napi_create_promise(env, &deferred, &promise);
283 int32_t ret = dhFwkKit->StopDistributedHardware(dhType, std::string(networkId));
284 if (ret != 0) {
285 DHLOGE("StopDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
286 }
287 return promise;
288 } else if (argc == DH_NAPI_ARGS_TWO) { // callback
289 if (!IsFunctionType(env, argv[1])) {
290 return nullptr;
291 }
292 int32_t ret = dhFwkKit->StopDistributedHardware(dhType, std::string(networkId));
293 if (ret != 0) {
294 DHLOGE("StopDistributedHardware for DHType: %{public}u filed", (uint32_t)dhType);
295 }
296 }
297 napi_get_undefined(env, &result);
298 return result;
299 }
300
Init(napi_env env,napi_value exports)301 napi_value DistributedHardwareManager::Init(napi_env env, napi_value exports)
302 {
303 napi_property_descriptor dhmProperties[] = {
304 DECLARE_NAPI_FUNCTION("pauseDistributedHardware", PauseDistributedHardware),
305 DECLARE_NAPI_FUNCTION("resumeDistributedHardware", ResumeDistributedHardware),
306 DECLARE_NAPI_FUNCTION("stopDistributedHardware", StopDistributedHardware),
307 };
308
309 DHLOGI("DistributedHardwareManager::Init is called!");
310 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(dhmProperties) / sizeof(dhmProperties[0]),
311 dhmProperties));
312 DHLOGI("All functions are configured..");
313 return exports;
314 }
315
InitDistributedHardwareType(napi_env env,napi_value exports)316 void DistributedHardwareManager::InitDistributedHardwareType(napi_env env, napi_value exports)
317 {
318 char propertyName[] = "DistributedHardwareType";
319 napi_value all = nullptr;
320 napi_value camera = nullptr;
321 napi_value screen = nullptr;
322 napi_value modemMic = nullptr;
323 napi_value modemSpk = nullptr;
324 napi_value mic = nullptr;
325 napi_value speaker = nullptr;
326 napi_create_int32(env, ALL, &all);
327 napi_create_int32(env, CAMERA, &camera);
328 napi_create_int32(env, SCREEN, &screen);
329 napi_create_int32(env, MODEM_MIC, &modemMic);
330 napi_create_int32(env, MODEM_SPEAKER, &modemSpk);
331 napi_create_int32(env, MIC, &mic);
332 napi_create_int32(env, SPEAKER, &speaker);
333 napi_property_descriptor desc[] = {
334 DECLARE_NAPI_STATIC_PROPERTY("ALL", all),
335 DECLARE_NAPI_STATIC_PROPERTY("CAMERA", camera),
336 DECLARE_NAPI_STATIC_PROPERTY("SCREEN", screen),
337 DECLARE_NAPI_STATIC_PROPERTY("MODEM_MIC", modemMic),
338 DECLARE_NAPI_STATIC_PROPERTY("MODEM_SPEAKER", modemSpk),
339 DECLARE_NAPI_STATIC_PROPERTY("MIC", mic),
340 DECLARE_NAPI_STATIC_PROPERTY("SPEAKER", speaker)
341 };
342 napi_value obj = nullptr;
343 napi_create_object(env, &obj);
344 napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc);
345 napi_set_named_property(env, exports, propertyName, obj);
346 }
347
348 /*
349 * Function registering all props and functions of ohos.distributedhardware
350 */
Export(napi_env env,napi_value exports)351 static napi_value Export(napi_env env, napi_value exports)
352 {
353 DHLOGI("Export is called!");
354 DistributedHardwareManager::Init(env, exports);
355 DistributedHardwareManager::InitDistributedHardwareType(env, exports);
356 return exports;
357 }
358
359 /*
360 * module define
361 */
362 static napi_module g_dhModule = {.nm_version = 1,
363 .nm_flags = 0,
364 .nm_filename = nullptr,
365 .nm_register_func = Export,
366 .nm_modname = "distributedHardware.hardwareManager",
367 .nm_priv = ((void *)0),
368 .reserved = {0}};
369
370 /*
371 * module register
372 */
RegisterModule(void)373 extern "C" __attribute__((constructor)) void RegisterModule(void)
374 {
375 DHLOGI("RegisterModule is called!");
376 napi_module_register(&g_dhModule);
377 }