1 /**
2 * Copyright (c) 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 "file.h"
17 #include "include/object_header.h"
18 #include "include/thread_scopes.h"
19 #include "intrinsics.h"
20 #include "libpandabase/utils/logger.h"
21 #include "libpandabase/utils/utf.h"
22 #include "libziparchive/extractortool/extractor.h"
23 #include "runtime/handle_scope-inl.h"
24 #include "plugins/ets/runtime/ets_class_linker_extension.h"
25 #include "plugins/ets/runtime/ets_coroutine.h"
26 #include "plugins/ets/runtime/ets_exceptions.h"
27 #include "plugins/ets/runtime/ets_stubs-inl.h"
28 #include "plugins/ets/runtime/types/ets_abc_file.h"
29 #include "plugins/ets/runtime/types/ets_primitives.h"
30 #include "plugins/ets/runtime/types/ets_runtime_linker.h"
31 #include "plugins/ets/runtime/types/ets_string.h"
32 #include "runtime/mem/local_object_handle.h"
33
34 namespace ark::ets::intrinsics {
35
CreateAbcFile(EtsCoroutine * coro,ClassLinkerContext * ctx,std::unique_ptr<const panda_file::File> && pf)36 static EtsAbcFile *CreateAbcFile(EtsCoroutine *coro, ClassLinkerContext *ctx,
37 std::unique_ptr<const panda_file::File> &&pf)
38 {
39 auto *abcFile = EtsAbcFile::FromEtsObject(EtsObject::Create(coro, PlatformTypes(coro)->coreAbcFile));
40 abcFile->SetPandaFile(pf.get());
41
42 Runtime::GetCurrent()->GetClassLinker()->AddPandaFile(std::move(pf), ctx);
43 return abcFile;
44 }
45
EtsAbcFileLoadAbcFile(EtsRuntimeLinker * runtimeLinker,EtsString * filePath)46 EtsAbcFile *EtsAbcFileLoadAbcFile(EtsRuntimeLinker *runtimeLinker, EtsString *filePath)
47 {
48 ASSERT(filePath != nullptr);
49 ASSERT(runtimeLinker != nullptr);
50 auto *ctx = runtimeLinker->GetClassLinkerContext();
51 auto *coro = EtsCoroutine::GetCurrent();
52
53 const auto path = filePath->GetMutf8();
54 std::unique_ptr<const panda_file::File> pf {nullptr};
55 {
56 // Loading panda-file might be time-consuming, which would affect GC
57 // unless being executed in native scope
58 ScopedNativeCodeThread etsNativeScope(coro);
59 pf = panda_file::OpenPandaFileOrZip(path);
60 }
61
62 if (pf == nullptr) {
63 // get hap path
64 auto pathStr = std::string(path.begin(), path.end());
65 size_t pos = pathStr.rfind("/ets/");
66 if (pos == std::string::npos) {
67 ets::ThrowEtsException(coro, panda_file_items::class_descriptors::ABC_FILE_NOT_FOUND_ERROR,
68 PandaString("Open failed, file: ") + path);
69 return nullptr;
70 }
71 std::string hapPath = pathStr.substr(0, pos);
72 hapPath += ".hap";
73
74 std::shared_ptr<ark::extractor::Extractor> extractor = std::make_shared<ark::extractor::Extractor>(hapPath);
75 if (!extractor || !extractor->Init()) {
76 ets::ThrowEtsException(coro, panda_file_items::class_descriptors::ABC_FILE_NOT_FOUND_ERROR,
77 PandaString("Open failed, file: ") + path);
78 return nullptr;
79 }
80 auto safeData = extractor->GetSafeData(pathStr);
81 ASSERT(safeData != nullptr);
82 pf = panda_file::OpenPandaFileFromSecureMemory(safeData->GetDataPtr(), safeData->GetDataLen(), pathStr);
83 }
84
85 if (pf == nullptr) {
86 ets::ThrowEtsException(coro, panda_file_items::class_descriptors::ABC_FILE_NOT_FOUND_ERROR,
87 PandaString("Abc file not found: ") + path);
88 return nullptr;
89 }
90 return CreateAbcFile(coro, ctx, std::move(pf));
91 }
92
EtsAbcFileLoadFromMemory(EtsRuntimeLinker * runtimeLinker,ObjectHeader * rawFileArray)93 EtsAbcFile *EtsAbcFileLoadFromMemory(EtsRuntimeLinker *runtimeLinker, ObjectHeader *rawFileArray)
94 {
95 ASSERT(rawFileArray != nullptr);
96 ASSERT(runtimeLinker != nullptr);
97
98 auto *ctx = runtimeLinker->GetClassLinkerContext();
99 auto *coro = EtsCoroutine::GetCurrent();
100 [[maybe_unused]] EtsHandleScope hs(coro);
101 EtsHandle arrayHandle(coro, reinterpret_cast<EtsByteArray *>(rawFileArray));
102
103 std::unique_ptr<const panda_file::File> pf {nullptr};
104 {
105 // Loading panda-file might be time-consuming, which would affect GC
106 // unless being executed in native scope
107 ScopedNativeCodeThread etsNativeScope(coro);
108 pf = panda_file::OpenPandaFileFromMemory(arrayHandle->GetData<void>(), arrayHandle->GetLength());
109 }
110
111 if (pf == nullptr) {
112 ets::ThrowEtsException(coro, panda_file_items::class_descriptors::ERROR,
113 PandaString("Failed to load abc file from memory"));
114 return nullptr;
115 }
116 return CreateAbcFile(coro, ctx, std::move(pf));
117 }
118
EtsAbcFileLoadClass(EtsAbcFile * abcFile,EtsRuntimeLinker * runtimeLinker,EtsString * clsName,EtsBoolean init)119 EtsClass *EtsAbcFileLoadClass(EtsAbcFile *abcFile, EtsRuntimeLinker *runtimeLinker, EtsString *clsName, EtsBoolean init)
120 {
121 const auto name = clsName->GetMutf8();
122 PandaString descriptor;
123 const auto *classDescriptor = ClassHelper::GetDescriptor(utf::CStringAsMutf8(name.c_str()), &descriptor);
124
125 const auto *pf = abcFile->GetPandaFile();
126 const auto classId = pf->GetClassId(classDescriptor);
127 if (!classId.IsValid() || pf->IsExternal(classId)) {
128 return nullptr;
129 }
130
131 auto *coro = EtsCoroutine::GetCurrent();
132 auto *classLinker = Runtime::GetCurrent()->GetClassLinker();
133 auto *ctx = runtimeLinker->GetClassLinkerContext();
134 auto *linkerErrorHandler = PandaEtsVM::GetCurrent()->GetEtsClassLinkerExtension()->GetErrorHandler();
135 auto *klass = classLinker->LoadClass(*pf, classId, ctx, linkerErrorHandler, true);
136 if (UNLIKELY(klass == nullptr)) {
137 ASSERT(coro->HasPendingException());
138 return nullptr;
139 }
140
141 if (UNLIKELY(init != 0 && !klass->IsInitialized())) {
142 if (UNLIKELY(!classLinker->InitializeClass(coro, klass))) {
143 ASSERT(coro->HasPendingException());
144 return nullptr;
145 }
146 }
147 return EtsClass::FromRuntimeClass(klass);
148 }
149
EtsAbcFileGetFilename(EtsAbcFile * abcFile)150 EtsString *EtsAbcFileGetFilename(EtsAbcFile *abcFile)
151 {
152 auto filename = abcFile->GetPandaFile()->GetFilename();
153 return EtsString::CreateFromMUtf8(filename.c_str());
154 }
155
156 } // namespace ark::ets::intrinsics
157