1 /**
2 * Copyright (c) 2021-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 "plugins/ets/runtime/ets_native_library_provider.h"
17
18 #include "ets_native_library.h"
19 #include "include/mem/panda_containers.h"
20 #include "include/mem/panda_string.h"
21 #include "plugins/ets/runtime/napi/ets_napi_invoke_interface.h"
22
23 namespace ark::ets {
24
25 namespace {
26
LoadFromPath(const PandaVector<PandaString> & pathes,const PandaString & name)27 Expected<EtsNativeLibrary, os::Error> LoadFromPath(const PandaVector<PandaString> &pathes, const PandaString &name)
28 {
29 if (name.find('/') == std::string::npos) {
30 for (const auto &path : pathes) {
31 if (path.empty()) {
32 continue;
33 }
34 PandaStringStream s;
35 s << path << '/' << name;
36 if (auto loadRes = EtsNativeLibrary::Load(s.str())) {
37 return loadRes;
38 }
39 }
40 }
41 return EtsNativeLibrary::Load(name);
42 }
43
44 } // namespace
45
LoadLibrary(EtsEnv * env,const PandaString & name)46 std::optional<std::string> NativeLibraryProvider::LoadLibrary(EtsEnv *env, const PandaString &name)
47 {
48 {
49 os::memory::ReadLockHolder lock(lock_);
50
51 auto it =
52 std::find_if(libraries_.begin(), libraries_.end(), [&name](auto &lib) { return lib.GetName() == name; });
53 if (it != libraries_.end()) {
54 return {};
55 }
56 }
57
58 auto loadRes = LoadFromPath(GetLibraryPath(), name);
59 if (!loadRes) {
60 return loadRes.Error().ToString();
61 }
62
63 const EtsNativeLibrary *lib = nullptr;
64 {
65 os::memory::WriteLockHolder lock(lock_);
66
67 auto [it, inserted] = libraries_.emplace(std::move(loadRes.Value()));
68 if (!inserted) {
69 return {};
70 }
71
72 lib = &*it;
73 }
74 ASSERT(lib != nullptr);
75
76 if (auto onLoadSymbol = lib->FindSymbol("EtsNapiOnLoad")) {
77 using EtsNapiOnLoadHandle = ets_int (*)(EtsEnv *);
78 auto onLoadHandle = reinterpret_cast<EtsNapiOnLoadHandle>(onLoadSymbol.Value());
79 ets_int etsNapiVersion = onLoadHandle(env);
80 if (!napi::CheckVersionEtsNapi(etsNapiVersion)) {
81 return {"Unsupported Ets napi version " + std::to_string(etsNapiVersion)};
82 }
83 }
84
85 return {};
86 }
87
ResolveSymbol(const PandaString & name) const88 void *NativeLibraryProvider::ResolveSymbol(const PandaString &name) const
89 {
90 os::memory::ReadLockHolder lock(lock_);
91
92 for (auto &lib : libraries_) {
93 if (auto ptr = lib.FindSymbol(name)) {
94 return ptr.Value();
95 }
96 }
97
98 return nullptr;
99 }
100
GetLibraryPath() const101 PandaVector<PandaString> NativeLibraryProvider::GetLibraryPath() const
102 {
103 os::memory::ReadLockHolder lock(lock_);
104 return libraryPath_;
105 }
106
SetLibraryPath(const PandaVector<PandaString> & pathes)107 void NativeLibraryProvider::SetLibraryPath(const PandaVector<PandaString> &pathes)
108 {
109 os::memory::WriteLockHolder lock(lock_);
110 libraryPath_ = pathes;
111 }
112
AddLibraryPath(const PandaString & path)113 void NativeLibraryProvider::AddLibraryPath(const PandaString &path)
114 {
115 os::memory::WriteLockHolder lock(lock_);
116 libraryPath_.emplace_back(path);
117 }
118
119 } // namespace ark::ets
120