• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025-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 "cj_support.h"
17 
18 #if defined(OHOS_STANDARD_PLATFORM)
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include "ark_native_engine.h"
28 #include "cj_envsetup.h"
29 #include "elf.h"
30 #include "utils/log.h"
31 
32 #ifdef NAPI_TARGET_ARM64
33 #define LIBS_NAME "arm64"
34 #elif defined(NAPI_TARGET_ARM32)
35 #define LIBS_NAME "arm"
36 #elif defined(NAPI_TARGET_AMD64)
37 #define LIBS_NAME "x86_64"
38 #else
39 #error current platform not supported
40 #endif
41 
42 #include <cerrno>
43 #include <cstdlib>
44 #include <cstring>
45 #include <elf.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 
LoadExtendedInfo(int fd,Elf64_Off shoff,Elf64_Half * shnum,Elf64_Half * shstrndx)49 static bool LoadExtendedInfo(int fd, Elf64_Off shoff, Elf64_Half* shnum, Elf64_Half* shstrndx)
50 {
51     Elf64_Shdr firstShdr;
52     if (pread(fd, &firstShdr, sizeof(Elf64_Shdr), shoff) != sizeof(Elf64_Shdr)) {
53         return false;
54     }
55 
56     // Handle extended section header count
57     if (*shnum == 0) {
58         *shnum = firstShdr.sh_size;
59     }
60 
61     // Handle extended string table index
62     if (*shstrndx == SHN_XINDEX) {
63         *shstrndx = firstShdr.sh_link;
64     }
65     return true;
66 }
67 
68 // Check if has ".cjmetadata" section
HasCJMetadata(int fd)69 static bool HasCJMetadata(int fd)
70 {
71     // Read ELF header
72     Elf64_Ehdr ehdr;
73     if (pread(fd, &ehdr, sizeof(ehdr), 0) != sizeof(ehdr)) {
74         return false;
75     }
76 
77     Elf64_Half shnum = ehdr.e_shnum;
78     Elf64_Half shstrndx = ehdr.e_shstrndx;
79     // Load extended info
80     if ((shnum == 0 || shstrndx == SHN_XINDEX) && !LoadExtendedInfo(fd, ehdr.e_shoff, &shnum, &shstrndx)) {
81         return false;
82     }
83 
84     // Load section header string table
85     char* shstrtab = nullptr;
86     Elf64_Word shstrtabSize = 0;
87 
88     if (shstrndx != SHN_UNDEF && shstrndx < shnum) {
89         Elf64_Shdr shstrtabHdr;
90         const Elf64_Off shdrOffset = ehdr.e_shoff + shstrndx * ehdr.e_shentsize;
91         if (pread(fd, &shstrtabHdr, sizeof(shstrtabHdr), shdrOffset) != sizeof(shstrtabHdr)) {
92             return false;
93         }
94 
95         shstrtabSize = shstrtabHdr.sh_size;
96         shstrtab = static_cast<char*>(malloc(shstrtabSize));
97         if (!shstrtab) {
98             return false;
99         }
100 
101         if (pread(fd, shstrtab, shstrtabSize, shstrtabHdr.sh_offset) != shstrtabSize) {
102             free(shstrtab);
103             return false;
104         }
105     }
106 
107     // Iterate through section headers
108     bool found = false;
109     for (Elf64_Half i = 0; i < shnum; ++i) {
110         const Elf64_Off shdrOffset = ehdr.e_shoff + i * ehdr.e_shentsize;
111         Elf64_Shdr shdr;
112         if (pread(fd, &shdr, sizeof(shdr), shdrOffset) != sizeof(shdr)) {
113             break;
114         }
115 
116         // Validate section name offset
117         if (shdr.sh_name < shstrtabSize) {
118             const char* name = shstrtab + shdr.sh_name;
119 
120             // Safe string comparison with boundary check
121             const size_t maxLen = shstrtabSize - shdr.sh_name;
122             if (strncmp(name, ".cjmetadata", maxLen) == 0) {
123                 found = true;
124                 break;
125             }
126         }
127     }
128 
129     free(shstrtab);
130     return found;
131 }
132 
IsCJModule(const char * moduleName)133 bool IsCJModule(const char* moduleName)
134 {
135     HILOG_DEBUG("Checking whether is cj module, module name: %{public}s", moduleName);
136     std::string absolutePath("/data/storage/el1/bundle/libs/" LIBS_NAME);
137     std::string libName = "lib" + std::string(moduleName) + ".so";
138 
139     absolutePath = absolutePath + "/" + libName;
140     struct stat st;
141     if (stat(absolutePath.c_str(), &st) == 1) {
142         return false;
143     }
144     const char* soPath = absolutePath.c_str();
145     int fd = open(soPath, O_RDONLY);
146     if (fd == -1) {
147         return false;
148     }
149 
150     // Check if its a valid elf file
151     unsigned char eIdent[EI_NIDENT];
152     if (read(fd, eIdent, EI_NIDENT) != EI_NIDENT || eIdent[EI_MAG0] != ELFMAG0 || eIdent[EI_MAG1] != ELFMAG1 ||
153         eIdent[EI_MAG2] != ELFMAG2 || eIdent[EI_MAG3] != ELFMAG3) {
154         HILOG_ERROR("Invalid ELF file %{public}s", soPath);
155         close(fd);
156         return false;
157     }
158     int is64bit = (eIdent[EI_CLASS] == ELFCLASS64);
159     if (!is64bit) {
160         close(fd);
161         return false;
162     }
163     // Check if has .cjmetadat section
164     int result = HasCJMetadata(fd);
165     close(fd);
166 
167     if (result == 1) {
168         HILOG_DEBUG("Found 'cjmetadata' section %{public}s", soPath);
169         return true;
170     } else {
171         HILOG_DEBUG("Not Found 'cjmetadata' section %{public}s", soPath);
172         return false;
173     }
174 }
175 
LoadArkCJModule(napi_env env,const char * moduleName,napi_value * result)176 static bool LoadArkCJModule(napi_env env, const char* moduleName, napi_value* result)
177 {
178     const char* targetName;
179 #ifdef OHOS_PLATFORM
180     targetName = "libark_interop.z.so";
181 #elif defined(WINDOWS_PLATFORM)
182     targetName = "libark_interop.dll";
183 #elif defined(LINUX_PLATFORM)
184     targetName = "libark_interop.so";
185 #endif
186     auto engine = reinterpret_cast<NativeEngine*>(env);
187     auto runtime = OHOS::CJEnv::LoadInstance();
188     if (runtime == nullptr) {
189         HILOG_ERROR("Get CJEnvMethods failed");
190         return false;
191     }
192     auto handle = runtime->loadLibrary(0, targetName);
193     if (!handle) {
194         HILOG_ERROR("open '%{public}s' failed", targetName);
195         return false;
196     }
197     std::string libName = "lib" + std::string(moduleName) + ".so";
198 
199     if (auto symbol = runtime->getSymbol(handle, "ARKTS_LoadModuleByNapiEnv")) {
200         auto loader = reinterpret_cast<napi_value (*)(napi_env, const char*)>(symbol);
201         *result = loader(env, libName.c_str());
202     } else if (auto symbol = runtime->getSymbol(handle, "ARKTS_LoadModule")) {
203         auto loader = reinterpret_cast<napi_value (*)(EcmaVM*, const char*)>(symbol);
204         auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
205         *result = loader(vm, libName.c_str());
206     } else {
207         return false;
208     }
209     return true;
210 }
211 
LoadCJModule(napi_env env,const char * nameBuf)212 napi_value LoadCJModule(napi_env env, const char* nameBuf)
213 {
214     napi_value result;
215     if (napi_get_undefined(env, &result) != napi_ok) {
216         return result;
217     }
218     auto runtime = OHOS::CJEnv::LoadInstance();
219     if (runtime == nullptr) {
220         HILOG_ERROR("Get CJEnvMethods failed");
221         return result;
222     }
223     runtime->initCJAppNS("/data/storage/el1/bundle/libs/" LIBS_NAME);
224     if (!runtime->startRuntime()) {
225         HILOG_ERROR("start cjruntime failed");
226         return result;
227     }
228     if (!runtime->startUIScheduler()) {
229         HILOG_ERROR("start cj ui context failed");
230         return result;
231     }
232 
233     LoadArkCJModule(env, nameBuf, &result);
234     return result;
235 }
236 #else
IsCJModule(const char * moduleName)237 bool IsCJModule(const char* moduleName)
238 {
239     return false;
240 }
241 
LoadCJModule(napi_env env,const char * nameBuf)242 napi_value LoadCJModule(napi_env env, const char* nameBuf)
243 {
244     return nullptr;
245 }
246 #endif