1 /*
2  * Copyright (c) 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 #include "ipc_skeleton.h"
16 #include "napi_param_utils.h"
17 #include "key_session_impl.h"
18 #include "media_key_system_impl.h"
19 #include "key_session_napi.h"
20 #include "drm_trace.h"
21 #include "drm_error_code.h"
22 #include "drm_api_operation.h"
23 
24 namespace OHOS {
25 namespace DrmStandard {
26 thread_local napi_ref MediaKeySessionNapi::sConstructor_ = nullptr;
27 thread_local sptr<MediaKeySessionImpl> MediaKeySessionNapi::sMediaKeySessionImpl_ = nullptr;
28 
MediaKeySessionNapi()29 MediaKeySessionNapi::MediaKeySessionNapi() : env_(nullptr), wrapper_(nullptr)
30 {
31     DRM_INFO_LOG("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
32 }
33 
~MediaKeySessionNapi()34 MediaKeySessionNapi::~MediaKeySessionNapi()
35 {
36     DRM_INFO_LOG("~MediaKeySessionNapi Init enter.");
37     DRM_DEBUG_LOG("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
38     if (wrapper_ != nullptr) {
39         napi_delete_reference(env_, wrapper_);
40     }
41     if (keySessionImpl_) {
42         keySessionImpl_ = nullptr;
43     }
44     if (keySessionCallbackNapi_) {
45         keySessionCallbackNapi_ = nullptr;
46     }
47 }
48 
Init(napi_env env,napi_value exports)49 napi_value MediaKeySessionNapi::Init(napi_env env, napi_value exports)
50 {
51     DRM_INFO_LOG("MediaKeySessionNapi Init enter.");
52     napi_status status;
53     napi_value ctorObj;
54 
55     napi_property_descriptor session_props[] = {
56         DECLARE_NAPI_FUNCTION("generateMediaKeyRequest", GenerateMediaKeyRequest),
57         DECLARE_NAPI_FUNCTION("processMediaKeyResponse", ProcessMediaKeyResponse),
58         DECLARE_NAPI_FUNCTION("generateOfflineReleaseRequest", GenerateOfflineReleaseRequest),
59         DECLARE_NAPI_FUNCTION("processOfflineReleaseResponse", ProcessOfflineReleaseResponse),
60         DECLARE_NAPI_FUNCTION("checkMediaKeyStatus", CheckMediaKeyStatus),
61         DECLARE_NAPI_FUNCTION("restoreOfflineMediaKeys", RestoreOfflineMediaKeys),
62         DECLARE_NAPI_FUNCTION("clearMediaKeys", ClearMediaKeys),
63         DECLARE_NAPI_FUNCTION("getContentProtectionLevel", GetContentProtectionLevel),
64         DECLARE_NAPI_FUNCTION("requireSecureDecoderModule", RequireSecureDecoderModule),
65         DECLARE_NAPI_FUNCTION("destroy", Destroy),
66         DECLARE_NAPI_FUNCTION("on", SetEventCallback),
67         DECLARE_NAPI_FUNCTION("off", UnsetEventCallback),
68     };
69     status = napi_define_class(env, KEY_SESSION_NAPI_CLASS_NAME, NAPI_AUTO_LENGTH, MediaKeySessionNapiConstructor,
70         nullptr, sizeof(session_props) / sizeof(session_props[PARAM0]), session_props, &ctorObj);
71     if (status == napi_ok) {
72         status = napi_create_reference(env, ctorObj, 1, &sConstructor_);
73         if (status == napi_ok) {
74             status = napi_set_named_property(env, exports, KEY_SESSION_NAPI_CLASS_NAME, ctorObj);
75             if (status == napi_ok) {
76                 DRM_DEBUG_LOG("MediaKeySessionNapi return exports");
77                 return exports;
78             }
79         }
80     }
81     DRM_INFO_LOG("MediaKeySessionNapi Init call Failed!");
82     return nullptr;
83 }
84 
MediaKeySessionNapiConstructor(napi_env env,napi_callback_info info)85 napi_value MediaKeySessionNapi::MediaKeySessionNapiConstructor(napi_env env, napi_callback_info info)
86 {
87     DrmTrace trace("MediaKeySessionNapi::MediaKeySessionNapiConstructor");
88     DRM_INFO_LOG("MediaKeySessionNapiConstructor enter.");
89 
90     napi_status status;
91     napi_value result = nullptr;
92     napi_value thisVar = nullptr;
93 
94     napi_get_undefined(env, &result);
95     DRM_NAPI_GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
96 
97     if (status == napi_ok && thisVar != nullptr) {
98         std::unique_ptr<MediaKeySessionNapi> obj = std::make_unique<MediaKeySessionNapi>();
99         if (obj != nullptr) {
100             obj->env_ = env;
101             if (sMediaKeySessionImpl_ == nullptr) {
102                 DRM_ERR_LOG("sMediaKeySessionImpl_ is null");
103                 return result;
104             }
105             obj->keySessionImpl_ = sMediaKeySessionImpl_;
106             obj->keySessionCallbackNapi_ = new MediaKeySessionCallbackNapi(env);
107             obj->keySessionImpl_->SetCallback(obj->keySessionCallbackNapi_);
108 
109             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
110                 MediaKeySessionNapi::MediaKeySessionNapiDestructor, nullptr, nullptr);
111             if (status == napi_ok) {
112                 ObjectRefMap<MediaKeySessionNapi>::Insert(obj.get());
113                 obj.release();
114                 const std::string propertyName = "MediaKeySessionNative";
115                 SetMediaKeySessionNativeProperty(env, thisVar, propertyName, sMediaKeySessionImpl_);
116                 return thisVar;
117             } else {
118                 ObjectRefMap<MediaKeySessionNapi>::Erase(obj.get());
119                 DRM_ERR_LOG("Failure wrapping js to native napi");
120             }
121         }
122     }
123     return result;
124 }
125 
MediaKeySessionNapiDestructor(napi_env env,void * nativeObject,void * finalize)126 void MediaKeySessionNapi::MediaKeySessionNapiDestructor(napi_env env, void *nativeObject, void *finalize)
127 {
128     DrmTrace trace("MediaKeySessionNapiDestructor");
129     DRM_INFO_LOG("MediaKeySessionNapiDestructor enter.");
130     MediaKeySessionNapi *keySessionNapiObj = reinterpret_cast<MediaKeySessionNapi *>(nativeObject);
131     ObjectRefMap<MediaKeySessionNapi>::DecreaseRef(keySessionNapiObj);
132 }
133 
SetMediaKeySessionNativeProperty(napi_env env,napi_value obj,const std::string & name,sptr<MediaKeySessionImpl> keySessionImpl)134 bool MediaKeySessionNapi::SetMediaKeySessionNativeProperty(napi_env env, napi_value obj, const std::string &name,
135     sptr<MediaKeySessionImpl> keySessionImpl)
136 {
137     DRM_INFO_LOG("SetMediaKeySessionNativeProperty enter.");
138     DRM_CHECK_AND_RETURN_RET_LOG(obj != nullptr, false, "obj is nullptr");
139 
140     napi_value keySessionImplNative = nullptr;
141     int64_t nativePointer = reinterpret_cast<int64_t>(keySessionImpl.GetRefPtr());
142     napi_status status = napi_create_int64(env, nativePointer, &keySessionImplNative);
143     DRM_CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "create int failed.");
144 
145     napi_value nameStr = nullptr;
146     status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &nameStr);
147     DRM_CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "create string failed.");
148 
149     status = napi_set_property(env, obj, nameStr, keySessionImplNative);
150     DRM_CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "set property failed.");
151 
152     return true;
153 }
154 
CreateMediaKeySession(napi_env env,sptr<MediaKeySessionImpl> keySessionImpl)155 napi_value MediaKeySessionNapi::CreateMediaKeySession(napi_env env, sptr<MediaKeySessionImpl> keySessionImpl)
156 {
157     DrmTrace trace("MediaKeySessionNapi::CreateMediaKeySession");
158     DRM_INFO_LOG("CreateMediaKeySession enter.");
159     napi_status status;
160     napi_value result = nullptr;
161     napi_value constructor;
162     status = napi_get_reference_value(env, sConstructor_, &constructor);
163     if (status == napi_ok) {
164         sMediaKeySessionImpl_ = keySessionImpl;
165         if (sMediaKeySessionImpl_ == nullptr) {
166             DRM_ERR_LOG("Failed to CreateMediaKeySession instance");
167             napi_get_undefined(env, &result);
168             return result;
169         }
170         status = napi_new_instance(env, constructor, 0, nullptr, &result);
171         sMediaKeySessionImpl_ = nullptr;
172         if (status == napi_ok && result != nullptr) {
173             DRM_INFO_LOG("success to CreateMediaKeySession napi instance");
174             return result;
175         } else {
176             DRM_ERR_LOG("Failed to CreateMediaKeySession napi instance");
177         }
178     }
179     DRM_DEBUG_LOG("Failed to create CreateMediaKeySession napi instance last");
180     napi_get_undefined(env, &result);
181     return result;
182 }
183 
Destroy(napi_env env,napi_callback_info info)184 napi_value MediaKeySessionNapi::Destroy(napi_env env, napi_callback_info info)
185 {
186     DrmTrace trace("MediaKeySessionNapi::Destroy");
187     DRM_INFO_LOG("Destroy enter.");
188     int32_t currentPid = IPCSkeleton::GetCallingPid();
189     DRM_DEBUG_LOG("MediaKeySessionNapi GetCallingPID: %{public}d", currentPid);
190 
191     napi_status status;
192     napi_value result = nullptr;
193     size_t argc = ARGS_ZERO;
194     napi_value argv[ARGS_ZERO];
195     napi_value thisVar = nullptr;
196     MediaKeySessionNapi *keySessionNapi = nullptr;
197 
198     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
199 
200     napi_get_undefined(env, &result);
201     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
202     if (status == napi_ok && keySessionNapi != nullptr && keySessionNapi->keySessionImpl_ != nullptr) {
203         int32_t ret = keySessionNapi->keySessionImpl_->Release();
204         if (ret != DRM_OK) {
205             DRM_ERR_LOG("keySessionImpl_ Release call Failed!");
206             NapiDrmError::ThrowError(env, "Release failed, service error.", DRM_SERVICE_FATAL_ERROR);
207             return result;
208         }
209     } else {
210         DRM_ERR_LOG("Release call Failed!");
211         NapiDrmError::ThrowError(env, "Release failed, unknown error.", DRM_UNKNOWN_ERROR);
212         return result;
213     }
214     return result;
215 }
216 
CheckMediaKeySessionStatus(MediaKeySessionNapi * napi,std::shared_ptr<MediaKeySessionAsyncContext> context)217 bool MediaKeySessionNapi::CheckMediaKeySessionStatus(MediaKeySessionNapi *napi,
218     std::shared_ptr<MediaKeySessionAsyncContext> context)
219 {
220     DRM_NAPI_CHECK_AND_RETURN_LOG(napi != nullptr, false, "napi object is nullptr.");
221     if (napi->keySessionImpl_ == nullptr) {
222         context->SignError(DRM_SERVICE_FATAL_ERROR);
223         return false;
224     }
225     return true;
226 }
227 
CheckContextStatus(std::shared_ptr<MediaKeySessionAsyncContext> context)228 bool MediaKeySessionNapi::CheckContextStatus(std::shared_ptr<MediaKeySessionAsyncContext> context)
229 {
230     DRM_NAPI_CHECK_AND_RETURN_LOG(context != nullptr, false, "context object is nullptr.");
231     if (context->native == nullptr) {
232         context->SignError(DRM_SERVICE_FATAL_ERROR);
233         return false;
234     }
235     return true;
236 }
237 
GenerateMediaKeyRequest(napi_env env,napi_callback_info info)238 napi_value MediaKeySessionNapi::GenerateMediaKeyRequest(napi_env env, napi_callback_info info)
239 {
240     DRM_INFO_LOG("GenerateMediaKeyRequest enter");
241     DrmTrace trace("MediaKeySessionNapi::GenerateMediaKeyRequest");
242     auto context = std::make_shared<MediaKeySessionAsyncContext>();
243     if (context == nullptr) {
244         DRM_ERR_LOG("GenerateMediaKeyRequest failed.");
245         NapiDrmError::ThrowError(env, "make context failed, unknown error.", DRM_UNKNOWN_ERROR);
246         return NapiParamUtils::GetUndefinedValue(env);
247     }
248 
249     auto inputParser = [env, context](size_t argc, napi_value *argv) {
250         NAPI_CHECK_ARGS_RETURN_VOID(context, argc == ARGS_THREE || argc == ARGS_FOUR, "invalid arguments",
251             DRM_INVALID_PARAM);
252         context->mediaKeyRequestInfo.mimeType = NapiParamUtils::GetStringArgument(env, argv[PARAM0]);
253         context->status = NapiParamUtils::GetValueUint8Array(env, context->mediaKeyRequestInfo.initData, argv[PARAM1]);
254         NAPI_CHECK_STATUS_RETURN_VOID(context, "generateMediaKeyRequest failed!", DRM_INVALID_PARAM);
255         int32_t mediaKeyType = 0;
256         context->status = NapiParamUtils::GetValueInt32(env, mediaKeyType, argv[PARAM2]);
257         NAPI_CHECK_STATUS_RETURN_VOID(context, "generateMediaKeyRequest failed!", DRM_INVALID_PARAM);
258         context->mediaKeyRequestInfo.mediaKeyType = (IMediaKeySessionService::MediaKeyType)mediaKeyType;
259         if (argc == ARGS_FOUR) {
260             context->status =
261             NapiParamUtils::GetValueOptionsData(env, context->mediaKeyRequestInfo.optionalData, argv[PARAM3]);
262             NAPI_CHECK_STATUS_RETURN_VOID(context, "generateMediaKeyRequest failed!", DRM_INVALID_PARAM);
263         }
264     };
265     context->GetCbInfo(env, info, inputParser);
266 
267     auto executor = [context]() {
268         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckContextStatus(context), "context object state is error.");
269         auto obj = reinterpret_cast<MediaKeySessionNapi *>(context->native);
270         ObjectRefMap objectGuard(obj);
271         auto *napiMediaKeySession = objectGuard.GetPtr();
272         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckMediaKeySessionStatus(napiMediaKeySession, context),
273             "MediaKeySession state is error.");
274         context->intValue = napiMediaKeySession->keySessionImpl_->GenerateMediaKeyRequest(context->mediaKeyRequestInfo,
275             context->mediaKeyRequest);
276         if (context->intValue != DRM_OK) {
277             context->SignError(DRM_SERVICE_FATAL_ERROR);
278         }
279     };
280 
281     auto complete = [env, context](napi_value &output) {
282         NapiParamUtils::SetMediaKeyRequest(env, context->mediaKeyRequest, output);
283     };
284     return NapiAsyncWork::Enqueue(env, context, "GenerateMediaKeyRequest", executor, complete);
285 }
286 
ProcessMediaKeyResponse(napi_env env,napi_callback_info info)287 napi_value MediaKeySessionNapi::ProcessMediaKeyResponse(napi_env env, napi_callback_info info)
288 {
289     DRM_INFO_LOG("ProcessMediaKeyResponse enter.");
290     int64_t beginTime = std::chrono::duration_cast<std::chrono::milliseconds>(
291         std::chrono::system_clock::now().time_since_epoch()).count();
292     DrmTrace trace("MediaKeySessionNapi::ProcessMediaKeyResponse");
293     auto context = std::make_shared<MediaKeySessionAsyncContext>();
294     if (context == nullptr) {
295         DRM_ERR_LOG("ProcessMediaKeyResponse failed.");
296         NapiDrmError::ThrowError(env, "make context failed, unknown error.", DRM_UNKNOWN_ERROR);
297         return NapiParamUtils::GetUndefinedValue(env);
298     }
299 
300     auto inputParser = [env, context](size_t argc, napi_value *argv) {
301         NAPI_CHECK_ARGS_RETURN_VOID(context, argc == ARGS_ONE, "invalid arguments", DRM_INVALID_PARAM);
302         context->status = NapiParamUtils::GetValueUint8Array(env, context->response, argv[PARAM0]);
303         NAPI_CHECK_STATUS_RETURN_VOID(context, "ProcessMediaKeyResponse failed!", DRM_INVALID_PARAM);
304     };
305     context->GetCbInfo(env, info, inputParser);
306 
307     auto executor = [context]() {
308         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckContextStatus(context), "context object state is error.");
309         auto obj = reinterpret_cast<MediaKeySessionNapi *>(context->native);
310         ObjectRefMap objectGuard(obj);
311         auto *napiMediaKeySession = objectGuard.GetPtr();
312         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckMediaKeySessionStatus(napiMediaKeySession, context),
313             "MediaKeySession state is error.");
314         context->intValue =
315             napiMediaKeySession->keySessionImpl_->ProcessMediaKeyResponse(context->licenseId, context->response);
316         if (context->intValue != DRM_OK) {
317             context->SignError(DRM_SERVICE_FATAL_ERROR);
318         }
319     };
320 
321     auto complete = [env, context](napi_value &output) {
322         NapiParamUtils::SetValueUint8Array(env, context->licenseId, output);
323     };
324     ConfigParser::WriteEndEvent(0, 0, std::string("processMediaKeyResponse"), beginTime);
325     return NapiAsyncWork::Enqueue(env, context, "ProcessMediaKeyResponse", executor, complete);
326 }
327 
GenerateOfflineReleaseRequest(napi_env env,napi_callback_info info)328 napi_value MediaKeySessionNapi::GenerateOfflineReleaseRequest(napi_env env, napi_callback_info info)
329 {
330     DRM_INFO_LOG("GenerateOfflineReleaseRequest enter");
331     auto context = std::make_shared<MediaKeySessionAsyncContext>();
332     if (context == nullptr) {
333         DRM_ERR_LOG("GenerateOfflineReleaseRequest failed.");
334         NapiDrmError::ThrowError(env, "make context failed, unknown error.", DRM_UNKNOWN_ERROR);
335         return NapiParamUtils::GetUndefinedValue(env);
336     }
337 
338     auto inputParser = [env, context](size_t argc, napi_value *argv) {
339         NAPI_CHECK_ARGS_RETURN_VOID(context, argc == ARGS_ONE, "invalid arguments", DRM_INVALID_PARAM);
340         context->status = NapiParamUtils::GetValueUint8Array(env, context->releaseLicenseId, argv[PARAM0]);
341         NAPI_CHECK_STATUS_RETURN_VOID(context, "GenerateOfflineReleaseRequest failed.", DRM_INVALID_PARAM);
342     };
343     context->GetCbInfo(env, info, inputParser);
344 
345     auto executor = [context]() {
346         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckContextStatus(context), "context object state is error.");
347         auto obj = reinterpret_cast<MediaKeySessionNapi *>(context->native);
348         ObjectRefMap objectGuard(obj);
349         auto *napiMediaKeySession = objectGuard.GetPtr();
350         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckMediaKeySessionStatus(napiMediaKeySession, context),
351             "MediaKeySession state is error.");
352         context->intValue = napiMediaKeySession->keySessionImpl_->GenerateOfflineReleaseRequest(
353             context->releaseLicenseId, context->releaseRequest);
354         if (context->intValue != DRM_OK) {
355             context->SignError(DRM_SERVICE_FATAL_ERROR);
356         }
357     };
358 
359     auto complete = [env, context](napi_value &output) {
360         NapiParamUtils::SetValueUint8Array(env, context->releaseRequest, output);
361     };
362     return NapiAsyncWork::Enqueue(env, context, "GenerateOfflineReleaseRequest", executor, complete);
363 }
364 
ProcessOfflineReleaseResponse(napi_env env,napi_callback_info info)365 napi_value MediaKeySessionNapi::ProcessOfflineReleaseResponse(napi_env env, napi_callback_info info)
366 {
367     DRM_INFO_LOG("ProcessOfflineReleaseResponse enter.");
368     auto context = std::make_shared<MediaKeySessionAsyncContext>();
369     if (context == nullptr) {
370         DRM_ERR_LOG("ProcessOfflineReleaseResponse failed.");
371         NapiDrmError::ThrowError(env, "make context failed, unknown error.", DRM_UNKNOWN_ERROR);
372         return NapiParamUtils::GetUndefinedValue(env);
373     }
374 
375     auto inputParser = [env, context](size_t argc, napi_value *argv) {
376         NAPI_CHECK_ARGS_RETURN_VOID(context, argc == ARGS_TWO, "invalid arguments", DRM_INVALID_PARAM);
377         context->status = NapiParamUtils::GetValueUint8Array(env, context->releaseResponseLicenseId, argv[PARAM0]);
378         NAPI_CHECK_STATUS_RETURN_VOID(context, "GetValueUint8Array failed.", DRM_INVALID_PARAM);
379         context->status = NapiParamUtils::GetValueUint8Array(env, context->releaseResponse, argv[PARAM1]);
380         NAPI_CHECK_STATUS_RETURN_VOID(context, "ProcessOfflineReleaseResponse failed.", DRM_INVALID_PARAM);
381     };
382     context->GetCbInfo(env, info, inputParser);
383 
384     auto executor = [context]() {
385         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckContextStatus(context), "context object state is error.");
386         auto obj = reinterpret_cast<MediaKeySessionNapi *>(context->native);
387         ObjectRefMap objectGuard(obj);
388         auto *napiMediaKeySession = objectGuard.GetPtr();
389         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckMediaKeySessionStatus(napiMediaKeySession, context),
390             "MediaKeySession state is error.");
391         context->intValue = napiMediaKeySession->keySessionImpl_->ProcessOfflineReleaseResponse(
392             context->releaseResponseLicenseId, context->releaseResponse);
393         if (context->intValue != DRM_OK) {
394             context->SignError(DRM_SERVICE_FATAL_ERROR);
395         }
396     };
397 
398     auto complete = [env, context](napi_value &output) { output = NapiParamUtils::GetUndefinedValue(env); };
399     return NapiAsyncWork::Enqueue(env, context, "ProcessOfflineReleaseResponse", executor, complete);
400 }
401 
vectorToJsArray(napi_env env,std::map<std::string,std::string> & licenseStatus)402 static napi_value vectorToJsArray(napi_env env, std::map<std::string, std::string> &licenseStatus)
403 {
404     DRM_INFO_LOG("vectorToJsArray enter.");
405     napi_value jsArray;
406     napi_value jsName;
407     napi_value jsValue;
408     napi_create_array_with_length(env, licenseStatus.size(), &jsArray);
409     size_t index = 0;
410     for (auto it = licenseStatus.begin(); it != licenseStatus.end(); ++it) {
411         napi_value jsObject;
412         napi_create_object(env, &jsObject);
413         std::string name = it->first;
414         std::string status = it->second;
415         napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &jsName);
416         napi_set_named_property(env, jsObject, "name", jsName);
417         napi_create_string_utf8(env, status.c_str(), NAPI_AUTO_LENGTH, &jsValue);
418         napi_set_named_property(env, jsObject, "value", jsValue);
419         napi_set_element(env, jsArray, index++, jsObject);
420     }
421     return jsArray;
422 }
423 
CheckMediaKeyStatus(napi_env env,napi_callback_info info)424 napi_value MediaKeySessionNapi::CheckMediaKeyStatus(napi_env env, napi_callback_info info)
425 {
426     DRM_INFO_LOG("CheckMediaKeyStatus enter");
427     napi_value result = nullptr;
428     size_t argc = ARGS_ZERO;
429     napi_value argv[ARGS_ZERO];
430     napi_value thisVar = nullptr;
431     napi_status status;
432     MediaKeySessionNapi *keySessionNapi = nullptr;
433     std::map<std::string, std::string> licenseStatus;
434 
435     napi_get_undefined(env, &result);
436     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
437     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
438     if (status == napi_ok && keySessionNapi != nullptr && keySessionNapi->keySessionImpl_ != nullptr) {
439         int32_t ret = keySessionNapi->keySessionImpl_->CheckMediaKeyStatus(licenseStatus);
440         if (ret != DRM_OK) {
441             DRM_ERR_LOG("CheckMediaKeyStatus failed!");
442             NapiDrmError::ThrowError(env, "CheckMediaKeyStatus failed.", DRM_SERVICE_FATAL_ERROR);
443             return result;
444         }
445     } else {
446         DRM_ERR_LOG("CheckMediaKeyStatus call Failed!");
447         NapiDrmError::ThrowError(env, "CheckMediaKeyStatus call failed.", DRM_UNKNOWN_ERROR);
448         return result;
449     }
450 
451     if (licenseStatus.size() == 0) {
452         DRM_ERR_LOG("Licence not exist.");
453         NapiDrmError::ThrowError(env, "CheckMediaKeyStatus call failed, service error.", DRM_SERVICE_FATAL_ERROR);
454         return result;
455     }
456     result = vectorToJsArray(env, licenseStatus);
457     return result;
458 }
459 
RestoreOfflineMediaKeys(napi_env env,napi_callback_info info)460 napi_value MediaKeySessionNapi::RestoreOfflineMediaKeys(napi_env env, napi_callback_info info)
461 {
462     DRM_INFO_LOG("RestoreOfflineMediaKeys enter.");
463     int64_t beginTime = std::chrono::duration_cast<std::chrono::milliseconds>(
464         std::chrono::system_clock::now().time_since_epoch()).count();
465     auto context = std::make_shared<MediaKeySessionAsyncContext>();
466     if (context == nullptr) {
467         DRM_ERR_LOG("RestoreOfflineMediaKeys failed.");
468         NapiDrmError::ThrowError(env, "make_shared failed, unknown error.", DRM_UNKNOWN_ERROR);
469         return NapiParamUtils::GetUndefinedValue(env);
470     }
471 
472     auto inputParser = [env, context](size_t argc, napi_value *argv) {
473         NAPI_CHECK_ARGS_RETURN_VOID(context, argc == ARGS_ONE, "invalid arguments", DRM_INVALID_PARAM);
474         context->status = NapiParamUtils::GetValueUint8Array(env, context->restoreLicenseId, argv[PARAM0]);
475         NAPI_CHECK_STATUS_RETURN_VOID(context, "RestoreOfflineMediaKeys failed.", DRM_INVALID_PARAM);
476     };
477     context->GetCbInfo(env, info, inputParser);
478 
479     auto executor = [context]() {
480         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckContextStatus(context), "context object state is error.");
481         auto obj = reinterpret_cast<MediaKeySessionNapi *>(context->native);
482         ObjectRefMap objectGuard(obj);
483         auto *napiMediaKeySession = objectGuard.GetPtr();
484         DRM_NAPI_CHECK_AND_RETURN_VOID_LOG(CheckMediaKeySessionStatus(napiMediaKeySession, context),
485             "MediaKeySession state is error.");
486         context->intValue = napiMediaKeySession->keySessionImpl_->RestoreOfflineMediaKeys(context->restoreLicenseId);
487         if (context->intValue != DRM_OK) {
488             context->SignError(DRM_SERVICE_FATAL_ERROR);
489         }
490     };
491 
492     auto complete = [env, context](napi_value &output) { output = NapiParamUtils::GetUndefinedValue(env); };
493     ConfigParser::WriteEndEvent(0, 0, std::string("restoreOfflineMediaKeys"), beginTime);
494     return NapiAsyncWork::Enqueue(env, context, "RestoreOfflineMediaKeys", executor, complete);
495 }
496 
ClearMediaKeys(napi_env env,napi_callback_info info)497 napi_value MediaKeySessionNapi::ClearMediaKeys(napi_env env, napi_callback_info info)
498 {
499     DRM_INFO_LOG("ClearMediaKeys enter.");
500     napi_value result = nullptr;
501     size_t argc = ARGS_ZERO;
502     napi_value argv[ARGS_ZERO];
503     napi_value thisVar = nullptr;
504     napi_status status;
505 
506     napi_get_undefined(env, &result);
507     int32_t currentPid = IPCSkeleton::GetCallingPid();
508     DRM_DEBUG_LOG("MediaKeySessionNapi GetCallingPID: %{public}d", currentPid);
509     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
510     MediaKeySessionNapi *keySessionNapi = nullptr;
511     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
512     if (status == napi_ok && keySessionNapi != nullptr && keySessionNapi->keySessionImpl_ != nullptr) {
513         int32_t ret = keySessionNapi->keySessionImpl_->ClearMediaKeys();
514         if (ret != DRM_OK) {
515             DRM_ERR_LOG("ClearMediaKeys call Failed!");
516             NapiDrmError::ThrowError(env, "ClearMediaKeys call failed, service error.",
517                 DRM_SERVICE_FATAL_ERROR);
518             return result;
519         }
520     } else {
521         DRM_ERR_LOG("napi_unwrap call Failed!");
522         NapiDrmError::ThrowError(env, "napi_unwrap call failed.", DRM_UNKNOWN_ERROR);
523         return result;
524     }
525     return result;
526 }
527 
RequireSecureDecoderModule(napi_env env,napi_callback_info info)528 napi_value MediaKeySessionNapi::RequireSecureDecoderModule(napi_env env, napi_callback_info info)
529 {
530     DRM_INFO_LOG("RequireSecureDecoderModule enter.");
531     napi_value result = nullptr;
532     size_t argc = ARGS_ONE;
533     napi_value argv[ARGS_ONE] = {0};
534     napi_value thisVar = nullptr;
535 
536     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
537     napi_get_undefined(env, &result);
538     if (argc != ARGS_ONE) {
539         DRM_ERR_LOG("invalid arguments.");
540         NapiDrmError::ThrowError(env, "Invalid params, only need one param.", DRM_INVALID_PARAM);
541         return result;
542     }
543     char mimeTypeBuf[PATH_MAX];
544     size_t length = 0;
545     if (napi_get_value_string_utf8(env, argv[PARAM0], mimeTypeBuf, PATH_MAX, &length) != napi_ok) {
546         DRM_ERR_LOG("Could not able to read mimetype!");
547         NapiDrmError::ThrowError(env, "Could not able to read mimetype.", DRM_UNKNOWN_ERROR);
548         return result;
549     }
550 
551     std::string mimeType = std::string(mimeTypeBuf);
552     bool statusValue = false;
553     MediaKeySessionNapi *keySessionNapi = nullptr;
554     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
555     if (keySessionNapi == nullptr || keySessionNapi->keySessionImpl_ == nullptr) {
556         DRM_ERR_LOG("napi_unwrapcall Failed!");
557         NapiDrmError::ThrowError(env, "napi_unwrapcall failed.", DRM_UNKNOWN_ERROR);
558         return result;
559     }
560     int32_t ret = keySessionNapi->keySessionImpl_->RequireSecureDecoderModule(mimeType, &statusValue);
561     if (ret != DRM_OK) {
562         DRM_ERR_LOG("keySessionImpl_ RequireSecureDecoderModule call Failed!");
563         NapiDrmError::ThrowError(env, "RequireSecureDecoderModule failed, service error.", DRM_SERVICE_FATAL_ERROR);
564         return result;
565     }
566     status = napi_get_boolean(env, statusValue, &result);
567     DRM_INFO_LOG("napi_get_boolean call success!,statusValue:%{public}d.", statusValue);
568     return result;
569 }
570 
GetContentProtectionLevel(napi_env env,napi_callback_info info)571 napi_value MediaKeySessionNapi::GetContentProtectionLevel(napi_env env, napi_callback_info info)
572 {
573     DRM_INFO_LOG("GetContentProtectionLevel enter.");
574     napi_value result = nullptr;
575     size_t argc = ARGS_ONE;
576     napi_value argv[ARGS_ONE] = {0};
577     napi_value thisVar = nullptr;
578     MediaKeySessionNapi *keySessionNapi = nullptr;
579 
580     napi_get_undefined(env, &result);
581     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
582     IMediaKeySessionService::ContentProtectionLevel level = (IMediaKeySessionService::ContentProtectionLevel)0;
583     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
584     if (status == napi_ok && keySessionNapi != nullptr && keySessionNapi->keySessionImpl_ != nullptr) {
585         int32_t ret = keySessionNapi->keySessionImpl_->GetContentProtectionLevel(&level);
586         if (ret != DRM_OK) {
587             DRM_ERR_LOG("GetContentProtectionLevel call Failed!");
588             NapiDrmError::ThrowError(env, "GetContentProtectionLevel failed, service error.", DRM_SERVICE_FATAL_ERROR);
589             return result;
590         }
591     } else {
592         DRM_ERR_LOG("napi_unwrap call Failed!");
593         NapiDrmError::ThrowError(env, "napi_unwrap failed.", DRM_UNKNOWN_ERROR);
594         return result;
595     }
596 
597     NAPI_CALL(env, napi_create_int32(env, (int32_t)level, &result));
598     return result;
599 }
600 
SetEventCallbackReference(const std::string eventType,std::shared_ptr<AutoRef> callbackPair)601 void MediaKeySessionNapi::SetEventCallbackReference(const std::string eventType, std::shared_ptr<AutoRef> callbackPair)
602 {
603     DRM_INFO_LOG("SetEventCallbackReference");
604     std::lock_guard<std::mutex> lock(mutex_);
605     if (keySessionCallbackNapi_ != nullptr) {
606         keySessionCallbackNapi_->SetCallbackReference(eventType, callbackPair);
607     } else {
608         DRM_ERR_LOG("SetEventCallbackReference failed.");
609     }
610 }
611 
ClearEventCallbackReference(const std::string eventType)612 void MediaKeySessionNapi::ClearEventCallbackReference(const std::string eventType)
613 {
614     DRM_INFO_LOG("ClearEventCallbackReference");
615     if (keySessionCallbackNapi_ != nullptr) {
616         keySessionCallbackNapi_->ClearCallbackReference(eventType);
617     } else {
618         DRM_ERR_LOG("ClearEventCallbackReference failed.");
619     }
620 }
621 
SetEventCallback(napi_env env,napi_callback_info info)622 napi_value MediaKeySessionNapi::SetEventCallback(napi_env env, napi_callback_info info)
623 {
624     DRM_INFO_LOG("SetEventCallback");
625     napi_value result = nullptr;
626     napi_get_undefined(env, &result);
627     size_t length = 0;
628     size_t argc = ARGS_TWO;
629     napi_value thisVar = nullptr;
630     napi_value argv[ARGS_TWO] = { nullptr };
631     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
632     NAPI_ASSERT(env, argc == ARGS_TWO, "only requires 2 parameters");
633     if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
634         DRM_ERR_LOG("Failed to retrieve arguments in SetEventCallback!");
635         NapiDrmError::ThrowError(env, "Mandatory parameters are left unspecified.", DRM_INVALID_PARAM);
636         return result;
637     }
638     napi_valuetype valueType = napi_undefined;
639     if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
640         napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
641         NapiDrmError::ThrowError(
642             env, "Incorrect parameter types, check if callback type is a string, and callback is a function.",
643             DRM_INVALID_PARAM);
644         return result;
645     }
646 
647     MediaKeySessionNapi *keySessionNapi = nullptr;
648     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
649     if (status == napi_ok && keySessionNapi != nullptr) {
650         char buffer[PATH_MAX];
651         napi_get_value_string_utf8(env, argv[PARAM0], buffer, PATH_MAX, &length);
652         std::string eventType = std::string(buffer);
653         napi_ref callbackRef;
654         napi_create_reference(env, argv[PARAM1], 1, &callbackRef);
655         DRM_DEBUG_LOG("SetEventCallback event is %{public}s", eventType.c_str());
656 
657         std::shared_ptr<AutoRef> callbackPair = std::make_shared<AutoRef>(env, callbackRef);
658         keySessionNapi->SetEventCallbackReference(eventType, callbackPair);
659     } else {
660         DRM_ERR_LOG("napi_unwrap failed!");
661         NapiDrmError::ThrowError(env, "napi_unwrap failed!", DRM_UNKNOWN_ERROR);
662     }
663     return result;
664 }
665 
UnsetEventCallback(napi_env env,napi_callback_info info)666 napi_value MediaKeySessionNapi::UnsetEventCallback(napi_env env, napi_callback_info info)
667 {
668     DRM_INFO_LOG("UnsetEventCallback");
669     napi_value result = nullptr;
670     napi_get_undefined(env, &result);
671     napi_value thisVar = nullptr;
672     napi_value argv[1] = { nullptr };
673     size_t argc = 1;
674     DRM_NAPI_GET_JS_ARGS(env, info, argc, argv, thisVar);
675     NAPI_ASSERT(env, argc == ARGS_ONE, "only requires 1 parameters");
676     if (thisVar == nullptr || argv[PARAM0] == nullptr) {
677         DRM_ERR_LOG("Failed to retrieve arguments in UnsetEventCallback!");
678         NapiDrmError::ThrowError(env, "Mandatory parameters are left unspecified.", DRM_INVALID_PARAM);
679         return result;
680     }
681     napi_valuetype valueType = napi_undefined;
682     if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
683         DRM_ERR_LOG("Failed to retrieve reasonable arguments in UnsetEventCallback!");
684         NapiDrmError::ThrowError(env, "the param is not a string", DRM_INVALID_PARAM);
685         return result;
686     }
687 
688     MediaKeySessionNapi *keySessionNapi = nullptr;
689     size_t length = 0;
690     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&keySessionNapi));
691     if (status == napi_ok && keySessionNapi != nullptr) {
692         char buffer[PATH_MAX];
693         napi_get_value_string_utf8(env, argv[PARAM0], buffer, PATH_MAX, &length);
694         std::string eventType = std::string(buffer);
695         keySessionNapi->ClearEventCallbackReference(eventType);
696         DRM_INFO_LOG("UnsetEventCallback out");
697     } else {
698         DRM_ERR_LOG("UnsetEventCallback failed!");
699         NapiDrmError::ThrowError(env, "UnsetEventCallback failed, unknown error.", DRM_UNKNOWN_ERROR);
700     }
701     return result;
702 }
703 } // DrmStandardr
704 } // OHOS