mirror of
https://github.com/openharmony/ability_ability_runtime.git
synced 2026-08-25 12:23:20 -04:00
4bed5b61c2
语境信息表内存优化part1 Created-by: wanghaha1204 Commit-by: wanghaha1204 Merged-by: openharmony_ci Description: **IssueNo**: https://gitcode.com/openharmony/arkcompiler_ets_runtime/issues/13409 **Description**: **稳定性自检:** | 自检项 | 自检结果 | | ------------------------------------------------------------ | -------- | | 涉及跨进程调用的相关操作需要抛至主线程或加锁防止并发 | | | 成员变量进行赋值或创建需要排查并发 | | | 谨慎在lambda表达式中使用引用捕获 | | | 谨慎在未经拷贝的情况下使用外部传入的string、C字符串 | | | map\vector\list\set等stl模板类使用时需要排查并发 | | | 谨慎考虑加锁范围 | | | 在IPC通信中谨慎使用同步通信方式 | | | 禁止传递this指针至其他模块或线程(特别是eventhandler任务) | | | 禁止将外部传入的裸指针在内部直接构造智能指针 | | | 禁止多个独立创建的智能指针管理同一地址 | | | 禁止在析构函数中抛异步任务 | | | 禁止js对象在非js线程(例如在IPC线程)创建、使用或销毁 | | | 禁止在对外接口中未经判空直接使用外部传入的指针 | | | 禁止接口返回局部变量引用 | | | 禁止在信号函数中加锁 | | | 禁止在关键流程(SA启动、应用启动等主流程)执行耗时的操作 | | | 禁止将同一个cpp编译在不同的so中 | | **安全编码自检:** | 自检项 | 自检结果 | | -------------------------------------------------------------- | -------- | | 裸指针避免通过隐式转换构造为sptr | | | json对象在取值之前必须先判断类型,避免类型不匹配 | | | 序列化时必须对传入的数组大小进行校验,避免出现超大数组 | | | 避免使用未明确位宽的整型,选择使用int8_t、uint8_t等类型 | | | 外部传入的路径要做规范化校验,对路径中的.、..、../等特殊字符严格校验 | | | 指针变量、表示资源描述符的变量、bool变量必须赋初值 | | | readParcelable获取的对象使用前需要判空 | | | 分配和释放内存的函数需要成对出现 | | | 申请内存后异常退出前需要及时进行内存释放 | | | 内存申请前必须对内存大小进行合法性校验 | | | 内存分配后必须判断是否成功 | | | 禁止使用realloc、alloca函数 | | | 禁止打印文件路径、口令等敏感信息,如有需要,使用private修饰 | | | 禁止打印内存地址 | | | 整数之间运算时必须严格检查,确保不会出现溢出、反转、除0 | | | 禁止对有符号整数进行位操作符运算 | | | 禁止对指针进行逻辑或位运算 | | | 循环次数如果收外部数据控制,需要检验其合法性 | | | 禁止使用内存操作类危险函数,需要使用安全函数 | | | 谨慎使用不可重入函数 | | | 必须检查安全函数的返回值,并进行正确处理 | | | 禁止仅通过TokenType类型判断绕过权限校验 | | **TDD Result**: **XTS Result**: ### 是否已执行L0用例 - [x] 已验证 - [ ] 不涉及。如不涉及,请写明理由 ### AI检视评分(使用本地代码检视skills扫描): # 代码检视报告 — PR19862-语境信息表内存优化part1(Round 2 / 最新提交) > 统一报告由 codecheck 工作台生成,**用于门禁管控**。本轮使用最新版 `orchestrator`,执行 `security-scanner + logic-scanner` 并完成 Refute 对抗性验证。 --- ## 报告元数据 > **门禁脚本只读取本 YAML 块**。字段名与取值域遵循 `codecheck_report_TEMPLATE.md` 固定合约。 ```yaml codecheck_report: schema_version: "1.0" scope: "PR19862-语境信息表内存优化part1" round: 2 commit_id: "1da08b2c847b3a700e6306ffb81319608cc3486a" change_id: "N/A" commit_subject: "语境信息表内存优化part1" date: "2026-08-07" dimensions_required: ["security-scanner", "logic-scanner"] dimensions_executed: ["security-scanner", "logic-scanner"] waived_dimensions: [] findings_total: 0 findings_by_severity: {P0: 0, P1: 0, P2: 0, P3: 0} score: 100 risk_level: "low" gate_decision: "approve" gate_blockers: [] must_fix: [] followups: [] ``` **取值域(唯一合法值)**:`risk_level ∈ {low, medium, high, unknown}`;`gate_decision ∈ {approve, conditional, block, insufficient}`。 --- ## 1. 基本信息 | 项目 | 值 | |------|-----| | 检视范围 | PR19862-语境信息表内存优化part1 | | commit-id | `1da08b2c847b3a700e6306ffb81319608cc3486a` | | Change-Id | `N/A`(提交消息未包含 Change-Id,以完整 commit-id 匹配门禁) | | commit message | `语境信息表内存优化part1` | | 检视日期 | `2026-08-07` | | 检视轮次 | Round 2 | | 检视维度 | `security-scanner + logic-scanner` | ### 提交内容核对(目标为提交时必填) | 校验项 | 结果 | |--------|------| | 提交范围 | 2 文件(+2/−0):`runtime.h` 新增默认关闭标志,`js_runtime.cpp` 向 Ark RuntimeOption 透传 | | 主要变更内容 | 为卡片渲染 VM 标记 `isFormRender`,使 Ark pkg-context 按卡片 VM 使用 per-VM 存储 | | 提交完整性 | ⚠️ 存在 `Signed-off-by`;无 Change-Id;完整 SHA 与 PR 当前 HEAD 一致,配套 form_fwk 与 arkcompiler 提交已核对 | ### Scanner 选择记录 | 探测项 | 结果 | |--------|------| | IPC/反序列化信号 | 未新增 | | DB/文件/持久化信号 | 未新增 | | 对外 Kit/NAPI/ANI/C API | 未涉及;修改的是 `interfaces/inner_api` 内部结构 | | 选定组合 | 通用提交必检:`security-scanner + logic-scanner` | --- ## 2. 总体评价 ### 2.1 上库质量评估结论 | 指标 | 结论 | |------|------| | **整体评分** | **100/100**(计算过程见附录 A,扣分明细见 2.3) | | **风险等级** | 🟢 低风险 | | **上库决策** | ✅ **可以上库** | **决策依据**: - 依据 1:必检维度 `security-scanner` 与 `logic-scanner` 均已执行,无缺失或豁免。 - 依据 2:变更仅新增一个有默认值的布尔字段及一次初始化期透传;无内存、资源、并发、IPC、输入或权限攻击面。 - 依据 3:配套 `ability_form_fwk` 调用方同时设置 `isUnique=true` 与 `isFormRender=true`,真实写入路径完整。 - 依据 4:`arkcompiler_ets_runtime` 的 `RuntimeOption` 与 `JSRuntimeOptions` 均将 `isFormThread_` 默认初始化为 `false`;非卡片路径行为保持等价。 - 依据 5:Refute 推翻旧报告的 3 个疑点;最终 P0/P1/P2/P3 均为 0,评分 100。 **阻塞项(Gate Blocker)**: - 无。 **上库条件(condition = 放行时必须满足,为空表示无条件)**: - 无。 ### 2.2 各维度通过率 | 维度 | 通过率 | 等级 | 评价 | |------|--------|------|------| | security-scanner | 11/11 | 🟢 | Core Scan 全项完成,G01–G15 未命中,0 个正式发现 | | logic-scanner | 7/7 | 🟢 | 控制流、数据流、状态、边界、错误、并发与业务契约均通过,0 个正式发现 | ### 2.3 评分扣分明细 | 严重等级 | 权重 | 数量 | 扣分 | |---------|------|------|------| | P0 致命 | −30 | 0 | −0 | | P1 严重 | −12 | 0 | −0 | | P2 一般 | −5 | 0 | −0 | | P3 提示 | −2 | 0 | −0 | | **合计** | | **0** | **−0** → 评分 **100** | > 公式:`评分 = max(0, 100 − (30×P0 + 12×P1 + 5×P2 + 2×P3))`;本轮为 `100 − 0 = 100`。 --- ## 3. 问题统计 > 严重等级已统一归一化为 P0/P1/P2/P3。 | 维度 | 总数 | P0 致命 | P1 严重 | P2 一般 | P3 提示 | |------|------|---------|---------|---------|---------| | security-scanner | 0 | 0 | 0 | 0 | 0 | | logic-scanner | 0 | 0 | 0 | 0 | 0 | | **总计** | **0** | **0** | **0** | **0** | **0** | --- ## 4. 高优先级发现(P0/P1,跨维度去重后) **无。** 本轮无 P0/P1 项。 --- ## 5. 分维度明细 ### 5.1 Security & Bug(经 security-scanner) - 模块风险画像:进程内 VM 初始化参数透传;未新增外部输入、资源所有权、副作用或异步行为。 - 11 项 Core Scan:空指针、越界、UAF、整数、并发、资源、反序列化、敏感日志、框架合规、类安全、IPC 鉴权均为未命中或不适用。 - G01–G15 同类横扫:未命中历史缺陷模式;无须进一步全库同类展开。 - 旧候选“新字段没有真实写入点”已由 `ability_form_fwk/services/form_render_service/src/form_render_record.cpp:543` 的生产赋值路径推翻。 **正式发现:无。** ### 5.2 Logic(经 logic-scanner) - 数据流完整:`FormRenderRecord` 写入 → `Runtime::Options` → `JsRuntime::CreateJsEnv` → Ark `RuntimeOption` → `JSRuntimeOptions` → `EcmaVM::IsFormThread`。 - `isUnique` 与 `isFormRender` 职责不同:前者控制卡片模块加载/Timer/Preload,后者控制 Ark pkg-context 的 per-VM/shared-store 分流;卡片入口同时设置二者。 - 默认行为等价:Ark 两层 `isFormThread_` 默认值均为 `false`,非卡片进程不受影响。 - 无新增控制流、状态转换、失败路径、算术边界或并发写入。 **正式发现:无。** --- ## 6. 待跟进(P2/P3 + Suspicious) **无。** 本轮无 P2/P3/Suspicious 项进入最终报告。 --- ## 7. 附录 ### 7.1 变更文件清单(或检视对象文件清单) | 文件 | 状态 | |------|------| | `frameworks/native/runtime/js_runtime.cpp` | ✏️ 修改(+1) | | `interfaces/inner_api/runtime/include/runtime.h` | ✏️ 修改(+1) | ### 7.2 检视轨迹(多轮重检时记录) | 轮次 | 范围 | 评分 | 风险等级 | 上库决策 | 结论 | |------|------|------|---------|---------|------| | Round 1 | PR #19862 两文件 | N/A | N/A | 门禁未识别 | 使用旧版无 YAML 格式;提出 3 个未完成跨仓库验证的候选项 | | Round 2 | PR #19862 两文件 + 配套 form_fwk/arkcompiler 调用链 | 100 | low | approve | 最新模板;3 个旧候选经 Refute 全部推翻,0 个正式发现 | ### 7.3 各 skill 原始产出 | skill | 产出文件 | 发现数 | |-------|---------|--------| | security-scanner | `security_scanner_pr19862_round2_20260807.md` | 0 | | logic-scanner | `logic_scanner_pr19862_round2_20260807.md` | 0 | | Refuter | `refute_log_pr19862_round2_20260807.md` | 3 个旧候选推翻,0 个进入报告 | ### 7.4 已排除发现 | ID | 旧候选 | 排除证据 | |----|--------|----------| | LOG-X01 | `isUnique` 与 `isFormRender` 可能分叉 | form_fwk 生产调用点同时设置二者;下游实现表明二者职责不同 | | SEC-X01 | `isFormRender` 无 `true` 写入点 | `form_render_record.cpp:543` 存在真实写入并进入 `JsFormRuntime::Init` | | LOG-X02 | 显式 `false` 可能改变旧行为 | Ark `RuntimeOption` 与 `JSRuntimeOptions` 默认值均为 `false` | --- ## 附录 A:评分与门禁规则(权威定义,勿改) ### A.1 严重等级统一归一化 | 统一等级 | 含义 | 各 skill 别名 | 门禁含义 | |---------|------|--------------|---------| | **P0 致命** | 崩溃/UAF/OOM/死锁/权限绕过/数据损坏/敏感数据泄漏等必现或易触发 | `critical` / `致命` / Confirmed P0 | **阻断上库** | | **P1 严重** | 影响正确性/安全边界,低概率触发或需组合条件 | `high` / `严重` / Confirmed P1、Likely P0 | 需修复或人工裁决 | | **P2 一般** | 逻辑缺陷/资源小泄漏/健壮性问题 | `medium` / `一般` / Likely P1、P2 | 建议修复,登记跟进 | | **P3 提示** | 风格/潜在风险/观察项,当前不可达 | `low` / `提示` / Suspicious | 不阻塞,登记跟进 | 归一化映射以**问题实际影响**为准,不以 skill 内部措辞为准;同一问题被多 skill 标注不同等级时,取最高等级。 ### A.2 评分公式与决策矩阵(确定性,可复现) ```text 评分 = max(0, 100 − (30×P0 + 12×P1 + 5×P2 + 2×P3)) ``` 决策矩阵(自上而下判定,命中即止): | 序 | 条件 | risk_level | gate_decision | |----|------|-----------|---------------| | 0 | 必检维度(dimensions_required)未执行且未豁免 | `unknown` | `insufficient` | | 1 | 存在 ≥1 项 P0 | `high` | `block` | | 2 | 存在 ≥1 项 P1(无 P0) | `medium` | `conditional` | | 3 | 评分 ≥ 90 | `low` | `approve` | | 4 | 评分 ≥ 70 | `medium` | `conditional` | | 5 | 评分 < 70 | `high` | `block` | **决策语义**: - `approve`:可以上库,P2/P3 项登记进 followups 跟踪。 - `conditional`:可上库但附条件——必须处理所有 `must_fix`(P1 项)或在门禁复核人书面裁决后放行;P2/P3 登记跟进。 - `block`:禁止上库,必须修复 `gate_blockers`(P0 项)后进入下一轮重检。 - `insufficient`:无法评估——必检维度缺失,补齐扫描后重出报告;`waived_dimensions` 中记录的用户豁免项除外。 ### A.3 必检维度 | 目标特征 | 必检维度(缺失即 insufficient) | |---------|-------------------------------| | 通用路径/提交 | `security-scanner` + `logic-scanner`(security-scanner 内含 bug+security 双视角,覆盖崩溃/挂死/OOM/UAF/死锁/权限绕过/敏感数据泄漏等高影响缺陷与安全审查) | | `services/` 下、IPC/DB/文件/配置密集区 | `security-scanner` + `logic-scanner` + `input-scanner` | | `interfaces/kits/`、NAPI/ANI/C 绑定、指定 Kit | `api-scanner` + 实现侧 `security-scanner` + `logic-scanner` | ### A.4 格式一致性要求(门禁校验项) 1. 章节编号与顺序固定(1 基本信息 → 2 总体评价 → 3 问题统计 → 4 高优先级发现 → 5 分维度明细 → 6 待跟进 → 7 附录 → 附录 A)。 2. YAML 报告元数据块字段名、取值域 See merge request: openharmony/ability_ability_runtime!19862
1985 lines
72 KiB
C++
Executable File
1985 lines
72 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2021-2025 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "js_runtime.h"
|
|
|
|
#include <cerrno>
|
|
#include <climits>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <mutex>
|
|
#include <regex>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <atomic>
|
|
#include <sys/epoll.h>
|
|
#include <unistd.h>
|
|
|
|
#include "accesstoken_kit.h"
|
|
#include "config_policy_utils.h"
|
|
#include "constants.h"
|
|
#include "connect_server_manager.h"
|
|
#include "ecmascript/napi/include/jsnapi.h"
|
|
#include "ecmascript/napi/include/dfx_jsnapi.h"
|
|
#include "extract_resource_manager.h"
|
|
#include "file_mapper.h"
|
|
#include "file_path_utils.h"
|
|
#include "hdc_register.h"
|
|
#include "hilog_tag_wrapper.h"
|
|
#include "hitrace_meter.h"
|
|
#include "ipc_skeleton.h"
|
|
#include "iservice_registry.h"
|
|
#include "js_environment.h"
|
|
#include "js_module_reader.h"
|
|
#include "js_module_searcher.h"
|
|
#include "js_quickfix_callback.h"
|
|
#include "js_runtime_common.h"
|
|
#include "js_runtime_utils.h"
|
|
#include "js_utils.h"
|
|
#include "js_worker.h"
|
|
#include "module_checker_delegate.h"
|
|
#include "napi/native_api.h"
|
|
#include "native_engine/impl/ark/ark_native_engine.h"
|
|
#include "native_engine/native_create_env.h"
|
|
#include "native_engine/native_engine.h"
|
|
#include "js_runtime_lite.h"
|
|
#include "ohos_js_env_logger.h"
|
|
#include "ohos_js_environment_impl.h"
|
|
#include "parameters.h"
|
|
#include "extractor.h"
|
|
#include "replace_intl_module.h"
|
|
#include "system_ability_definition.h"
|
|
#include "dfx_jsnapi.h"
|
|
#include "worker_info.h"
|
|
#include "ffrt.h"
|
|
|
|
#ifdef SUPPORT_SCREEN
|
|
#include "hot_reloader.h"
|
|
#include "ace_forward_compatibility.h"
|
|
#include "declarative_module_preloader.h"
|
|
#endif //SUPPORT_SCREEN
|
|
|
|
#include "syscap_ts.h"
|
|
|
|
using namespace OHOS::AbilityBase;
|
|
using Extractor = OHOS::AbilityBase::Extractor;
|
|
|
|
namespace OHOS {
|
|
namespace AbilityRuntime {
|
|
namespace {
|
|
constexpr size_t PARAM_TWO = 2;
|
|
constexpr uint8_t SYSCAP_MAX_SIZE = 100;
|
|
constexpr int64_t DEFAULT_GC_POOL_SIZE = 0x10000000; // 256MB
|
|
constexpr int32_t DEFAULT_INTER_VAL = 500;
|
|
constexpr int32_t API8 = 8;
|
|
const std::string SANDBOX_ARK_CACHE_PATH = "/data/storage/ark-cache/";
|
|
const std::string SANDBOX_ARK_PROIFILE_PATH = "/data/storage/ark-profile";
|
|
|
|
constexpr char MERGE_ABC_PATH[] = "/ets/modules.abc";
|
|
constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
|
|
constexpr const char* PERMISSION_RUN_ANY_CODE = "ohos.permission.RUN_ANY_CODE";
|
|
constexpr const char* PERMISSION_LOAD_INDEPENDENT_LIBRARY = "ohos.permission.kernel.LOAD_INDEPENDENT_LIBRARY";
|
|
constexpr const char* PERMISSION_LOAD_CERTSIGN_LIBRARY = "ohos.permission.kernel.LOAD_CERTSIGN_LIBRARY_FOR_WEB";
|
|
|
|
const std::string CONFIG_PATH = "/etc/system_kits_config.json";
|
|
const std::string SYSTEM_KITS_CONFIG_PATH = "/system/etc/system_kits_config.json";
|
|
|
|
const std::string SYSTEM_KITS = "systemkits";
|
|
const std::string NAMESPACE = "namespace";
|
|
const std::string TARGET_OHM = "targetohm";
|
|
const std::string SINCE_VERSION = "sinceVersion";
|
|
const std::string DEFAULT_PLUGIN = "plugin_default_namespace";
|
|
|
|
constexpr char DEVELOPER_MODE_STATE[] = "const.security.developermode.state";
|
|
const std::string MERGE_SOURCE_MAP_PATH = "ets/sourceMaps.map";
|
|
static auto PermissionCheckFunc = []() {
|
|
Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
|
|
|
|
int result = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken, PERMISSION_RUN_ANY_CODE);
|
|
if (result == Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
int32_t PrintVmLog(int32_t, int32_t, const char*, const char*, const char* message)
|
|
{
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "ArkLog: %{public}s", message);
|
|
return 0;
|
|
}
|
|
} // namespace
|
|
|
|
std::atomic<bool> JsRuntime::hasInstance(false);
|
|
JsRuntime::JsRuntime()
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
}
|
|
|
|
JsRuntime::~JsRuntime()
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
Deinitialize();
|
|
StopDebugMode();
|
|
}
|
|
|
|
bool JsRuntime::Init(const Options& options)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
JsRuntimeLite::InitJsRuntimeLite(options);
|
|
return Initialize(options);
|
|
}
|
|
|
|
std::unique_ptr<JsRuntime> JsRuntime::Create(const Options& options)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
std::unique_ptr<JsRuntime> instance;
|
|
JsRuntimeLite::InitJsRuntimeLite(options);
|
|
if (!options.preload && options.isStageModel) {
|
|
auto preloadedInstance = Runtime::GetPreloaded(Language::JS);
|
|
#ifdef SUPPORT_SCREEN
|
|
// reload ace if compatible mode changes
|
|
if (Ace::AceForwardCompatibility::PipelineChanged() && preloadedInstance) {
|
|
preloadedInstance.reset();
|
|
}
|
|
#endif
|
|
if (preloadedInstance && preloadedInstance->GetLanguage() == Runtime::Language::JS) {
|
|
instance.reset(static_cast<JsRuntime*>(preloadedInstance.release()));
|
|
} else {
|
|
instance = std::make_unique<JsRuntime>();
|
|
}
|
|
} else {
|
|
instance = std::make_unique<JsRuntime>();
|
|
}
|
|
|
|
if (!instance->Initialize(options)) {
|
|
return std::unique_ptr<JsRuntime>();
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
void JsRuntime::StartDebugMode(const DebugOption dOption)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "localDebug %{public}d", dOption.isDebugFromLocal);
|
|
if (!ShouldSkipDebugMode(dOption)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "not start debug");
|
|
return;
|
|
}
|
|
CHECK_POINTER(jsEnv_);
|
|
if (jsEnv_->GetDebugMode()) {
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "debugMode");
|
|
return;
|
|
}
|
|
// Set instance id to tid after the first instance.
|
|
if (JsRuntime::hasInstance.exchange(true, std::memory_order_relaxed)) {
|
|
instanceId_ = static_cast<uint32_t>(getproctid());
|
|
}
|
|
|
|
bool isStartWithDebug = dOption.isStartWithDebug;
|
|
bool isDebugApp = dOption.isDebugApp;
|
|
std::string appProvisionType = dOption.appProvisionType;
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Ark VM is starting debug mode [%{public}s]", isStartWithDebug ? "break" : "normal");
|
|
JsRuntimeCommon::GetInstance().StartDebuggerModule(isDebugApp, dOption.isStartWithNative);
|
|
const std::string bundleName = bundleName_;
|
|
uint32_t instanceId = instanceId_;
|
|
auto weak = jsEnv_;
|
|
std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : "";
|
|
HdcRegister::DebugRegisterMode debugMode = HdcRegister::DebugRegisterMode::HDC_DEBUG_REG;
|
|
if (debugOption_.isDebugFromLocal && debugOption_.isDeveloperMode) {
|
|
debugMode = HdcRegister::DebugRegisterMode::BOTH_REG;
|
|
} else if (debugOption_.isDebugFromLocal) {
|
|
debugMode = HdcRegister::DebugRegisterMode::LOCAL_DEBUG_REG;
|
|
}
|
|
HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp, debugMode,
|
|
[bundleName, isStartWithDebug, instanceId, weak, isDebugApp, appProvisionType]
|
|
(int socketFd, std::string option) {
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME,
|
|
"HdcRegister msg, fd %{public}d, option %{public}s, isStartWithDebug %{public}d, isDebugApp %{public}d",
|
|
socketFd, option.c_str(), isStartWithDebug, isDebugApp);
|
|
if (weak == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null weak");
|
|
return;
|
|
}
|
|
// system is unlocked when const.boot.oemmode is rd
|
|
std::string oemmode = OHOS::system::GetParameter("const.boot.oemmode", "");
|
|
bool unlocked = "rd" == oemmode;
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "unlocked= %{public}d, oemmode= %{public}s", unlocked, oemmode.c_str());
|
|
// Don't start any server if (system is locked) and app is release version
|
|
// Starting ConnectServer in release app on debuggable system is only for debug mode, not for profiling mode.
|
|
if ((!unlocked) && appProvisionType == AppExecFwk::Constants::APP_PROVISION_TYPE_RELEASE) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "not support release app");
|
|
return;
|
|
}
|
|
if (option.find(DEBUGGER) == std::string::npos) {
|
|
// if has old connect server, stop it
|
|
ConnectServerManager::Get().StopConnectServer(false);
|
|
ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp);
|
|
ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false);
|
|
} else {
|
|
// if has old debugger server, stop it
|
|
weak->StopDebugger(option);
|
|
weak->StartDebugger(option, socketFd, isDebugApp);
|
|
}
|
|
});
|
|
if (isDebugApp && appProvisionType != AppExecFwk::Constants::APP_PROVISION_TYPE_RELEASE) {
|
|
ConnectServerManager::Get().StartConnectServer(bundleName_, -1, true);
|
|
}
|
|
|
|
DebuggerConnectionHandler(isDebugApp, isStartWithDebug);
|
|
}
|
|
|
|
bool JsRuntime::ShouldSkipDebugMode(const DebugOption dOption)
|
|
{
|
|
if (!dOption.isDebugFromLocal && !dOption.isDeveloperMode) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "developer Mode false");
|
|
return false;
|
|
}
|
|
if (!(dOption.arkTSMode == AbilityRuntime::CODE_LANGUAGE_ARKTS_1_0)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "developer register in sts");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void JsRuntime::DebuggerConnectionHandler(bool isDebugApp, bool isStartWithDebug)
|
|
{
|
|
ConnectServerManager::Get().StoreInstanceMessage(getproctid(), instanceId_);
|
|
EcmaVM* vm = GetEcmaVm();
|
|
CHECK_POINTER(jsEnv_);
|
|
auto dTask = jsEnv_->GetDebuggerPostTask();
|
|
panda::JSNApi::DebugOption option = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? isStartWithDebug : false};
|
|
ConnectServerManager::Get().StoreDebuggerInfo(getproctid(), reinterpret_cast<void*>(vm), option, dTask, isDebugApp);
|
|
jsEnv_->NotifyDebugMode(getproctid(), ARK_DEBUGGER_LIB_PATH, instanceId_, isDebugApp, isStartWithDebug);
|
|
}
|
|
|
|
void JsRuntime::StopDebugMode()
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
if (jsEnv_->GetDebugMode()) {
|
|
ConnectServerManager::Get().RemoveInstance(instanceId_);
|
|
StopDebugger();
|
|
}
|
|
}
|
|
|
|
void JsRuntime::InitConsoleModule()
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->InitConsoleModule();
|
|
}
|
|
|
|
bool JsRuntime::StartDebugger(bool needBreakPoint, uint32_t instanceId)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
return true;
|
|
}
|
|
|
|
void JsRuntime::StopDebugger()
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->StopDebugger();
|
|
}
|
|
|
|
int32_t JsRuntime::JsperfProfilerCommandParse(const std::string &command, int32_t defaultValue)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "profiler command parse %{public}s", command.c_str());
|
|
auto findPos = command.find("jsperf");
|
|
if (findPos == std::string::npos) {
|
|
// jsperf command not found, so not to do, return zero.
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "jsperf command not found");
|
|
return 0;
|
|
}
|
|
|
|
// match jsperf command
|
|
auto jsPerfStr = command.substr(findPos, command.length() - findPos);
|
|
const std::regex regexJsperf(R"(^jsperf($|\s+($|\d*\s*($|nativeperf.*))))");
|
|
std::match_results<std::string::const_iterator> matchResults;
|
|
if (!std::regex_match(jsPerfStr, matchResults, regexJsperf)) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "the order not match");
|
|
return defaultValue;
|
|
}
|
|
|
|
// get match resuflt
|
|
std::string jsperfResuflt;
|
|
constexpr size_t matchResultIndex = 1;
|
|
if (matchResults.size() < PARAM_TWO) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "no results need to be matched");
|
|
return defaultValue;
|
|
}
|
|
|
|
jsperfResuflt = matchResults[matchResultIndex].str();
|
|
// match number result
|
|
const std::regex regexJsperfNum(R"(^\s*(\d+).*)");
|
|
std::match_results<std::string::const_iterator> jsperfMatchResults;
|
|
if (!std::regex_match(jsperfResuflt, jsperfMatchResults, regexJsperfNum)) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "the jsperf results not match");
|
|
return defaultValue;
|
|
}
|
|
|
|
// get match result
|
|
std::string interval;
|
|
constexpr size_t matchNumResultIndex = 1;
|
|
if (jsperfMatchResults.size() < PARAM_TWO) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "jsperfMatchResults not match");
|
|
return defaultValue;
|
|
}
|
|
|
|
interval = jsperfMatchResults[matchNumResultIndex].str();
|
|
if (interval.empty()) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "empty interval");
|
|
return defaultValue;
|
|
}
|
|
|
|
return std::stoi(interval);
|
|
}
|
|
|
|
void JsRuntime::StartProfiler(const DebugOption dOption)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "localDebug %{public}d", dOption.isDebugFromLocal);
|
|
if (!dOption.isDebugFromLocal && !dOption.isDeveloperMode) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "developer Mode false");
|
|
return;
|
|
}
|
|
CHECK_POINTER(jsEnv_);
|
|
if (JsRuntime::hasInstance.exchange(true, std::memory_order_relaxed)) {
|
|
instanceId_ = static_cast<uint32_t>(getproctid());
|
|
}
|
|
|
|
bool isStartWithDebug = dOption.isStartWithDebug;
|
|
bool isDebugApp = dOption.isDebugApp;
|
|
std::string appProvisionType = dOption.appProvisionType;
|
|
JsRuntimeCommon::GetInstance().StartDebuggerModule(isDebugApp, dOption.isStartWithNative);
|
|
const std::string bundleName = bundleName_;
|
|
auto weak = jsEnv_;
|
|
uint32_t instanceId = instanceId_;
|
|
std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : "";
|
|
HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp,
|
|
HdcRegister::DebugRegisterMode::HDC_DEBUG_REG,
|
|
[bundleName, isStartWithDebug, instanceId, weak, isDebugApp, appProvisionType](int socketFd, std::string option) {
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "HdcRegister msg, fd= %{public}d, option= %{public}s", socketFd, option.c_str());
|
|
if (weak == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null weak");
|
|
return;
|
|
}
|
|
if (appProvisionType == AppExecFwk::Constants::APP_PROVISION_TYPE_RELEASE) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "not support release app");
|
|
return;
|
|
}
|
|
if (option.find(DEBUGGER) == std::string::npos) {
|
|
// if has old connect server, stop it
|
|
ConnectServerManager::Get().StopConnectServer(false);
|
|
ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp);
|
|
ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false);
|
|
} else {
|
|
// if has old debugger server, stop it
|
|
weak->StopDebugger(option);
|
|
weak->StartDebugger(option, socketFd, isDebugApp);
|
|
}
|
|
});
|
|
|
|
DebuggerConnectionManager(isDebugApp, isStartWithDebug, dOption);
|
|
}
|
|
|
|
void JsRuntime::DebuggerConnectionManager(bool isDebugApp, bool isStartWithDebug, const DebugOption dOption)
|
|
{
|
|
if (isDebugApp && dOption.appProvisionType != AppExecFwk::Constants::APP_PROVISION_TYPE_RELEASE) {
|
|
ConnectServerManager::Get().StartConnectServer(bundleName_, 0, true);
|
|
}
|
|
ConnectServerManager::Get().StoreInstanceMessage(getproctid(), instanceId_);
|
|
JsEnv::JsEnvironment::PROFILERTYPE profiler = JsEnv::JsEnvironment::PROFILERTYPE::PROFILERTYPE_HEAP;
|
|
int32_t interval = 0;
|
|
const std::string profilerCommand("profile");
|
|
if (dOption.perfCmd.find(profilerCommand) != std::string::npos) {
|
|
profiler = JsEnv::JsEnvironment::PROFILERTYPE::PROFILERTYPE_CPU;
|
|
interval = JsperfProfilerCommandParse(dOption.perfCmd, DEFAULT_INTER_VAL);
|
|
}
|
|
EcmaVM* vm = GetEcmaVm();
|
|
CHECK_POINTER(jsEnv_);
|
|
auto dTask = jsEnv_->GetDebuggerPostTask();
|
|
panda::JSNApi::DebugOption option = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? isStartWithDebug : false};
|
|
ConnectServerManager::Get().StoreDebuggerInfo(getproctid(), reinterpret_cast<void*>(vm), option, dTask, isDebugApp);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "profiler:%{public}d interval:%{public}d", profiler, interval);
|
|
jsEnv_->StartProfiler(ARK_DEBUGGER_LIB_PATH, instanceId_, profiler, interval, getproctid(), isDebugApp);
|
|
}
|
|
|
|
bool JsRuntime::GetFileBuffer(const std::string& filePath, std::string& fileFullName, std::vector<uint8_t>& buffer,
|
|
bool isABC)
|
|
{
|
|
Extractor extractor(filePath);
|
|
if (!extractor.Init()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Extractor of %{private}s init failed", filePath.c_str());
|
|
return false;
|
|
}
|
|
|
|
std::vector<std::string> fileNames;
|
|
if (isABC) {
|
|
extractor.GetSpecifiedTypeFiles(fileNames, ".abc");
|
|
} else {
|
|
extractor.GetSpecifiedTypeFiles(fileNames, ".map");
|
|
}
|
|
if (fileNames.empty()) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "no .abc in hap/hqf %{private}s", filePath.c_str());
|
|
return true;
|
|
}
|
|
|
|
std::string fileName = fileNames.front();
|
|
fileFullName = filePath + "/" + fileName;
|
|
std::unique_ptr<uint8_t[]> data;
|
|
size_t dataLen = 0;
|
|
if (!extractor.ExtractToBufByName(fileName, data, dataLen)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Extract %{public}s failed", fileFullName.c_str());
|
|
return false;
|
|
}
|
|
|
|
buffer.assign(data.get(), data.get() + dataLen);
|
|
return true;
|
|
}
|
|
|
|
std::shared_ptr<AbilityBase::FileMapper> JsRuntime::GetSafeData(const std::string& path, std::string& fileFullName)
|
|
{
|
|
bool newCreate = false;
|
|
auto extractor = ExtractorUtil::GetExtractor(path, newCreate, true);
|
|
if (extractor == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null extractor path: %{private}s", path.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
std::vector<std::string> fileNames;
|
|
extractor->GetSpecifiedTypeFiles(fileNames, ".abc");
|
|
if (fileNames.empty()) {
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "no abc file in hap or hqf: %{private}s", path.c_str());
|
|
return nullptr;
|
|
}
|
|
std::string fileName = fileNames.front();
|
|
fileFullName = path + "/" + fileName;
|
|
|
|
auto safeData = extractor->GetSafeData(fileName);
|
|
if (safeData == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null safeData path: %{private}s", path.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
return safeData;
|
|
}
|
|
|
|
bool JsRuntime::LoadRepairPatch(const std::string& hqfFile, const std::string& hapPath)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, false);
|
|
|
|
HqfInitSourceMap(hqfFile);
|
|
|
|
std::string patchFile;
|
|
auto hqfSafeData = GetSafeData(hqfFile, patchFile);
|
|
if (hqfSafeData == nullptr) {
|
|
if (patchFile.empty()) {
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "No need to load patch cause no ets. path: %{private}s", hqfFile.c_str());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string baseFile;
|
|
auto hapSafeData = GetSafeData(hapPath, baseFile);
|
|
if (hapSafeData == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
std::string resolvedHapPath;
|
|
auto position = hapPath.find(".hap");
|
|
if (position != std::string::npos) {
|
|
resolvedHapPath = hapPath.substr(0, position) + MERGE_ABC_PATH;
|
|
}
|
|
|
|
auto hspPosition = hapPath.find(".hsp");
|
|
if (hspPosition != std::string::npos) {
|
|
resolvedHapPath = hapPath.substr(0, hspPosition) + MERGE_ABC_PATH;
|
|
}
|
|
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "LoadPatch, patchFile: %{private}s, baseFile: %{private}s",
|
|
patchFile.c_str(), resolvedHapPath.c_str());
|
|
auto ret = panda::JSNApi::LoadPatch(vm, patchFile, hqfSafeData->GetDataPtr(), hqfSafeData->GetDataLen(),
|
|
resolvedHapPath, hapSafeData->GetDataPtr(), hapSafeData->GetDataLen());
|
|
if (ret != panda::JSNApi::PatchErrorCode::SUCCESS) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "LoadPatch failed:%{public}d", static_cast<int32_t>(ret));
|
|
return false;
|
|
}
|
|
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Load patch %{private}s succeed", patchFile.c_str());
|
|
return true;
|
|
}
|
|
|
|
bool JsRuntime::UnLoadRepairPatch(const std::string& hqfFile)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, false);
|
|
|
|
Extractor extractor(hqfFile);
|
|
if (!extractor.Init()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Extractor of %{private}s init failed", hqfFile.c_str());
|
|
return false;
|
|
}
|
|
|
|
std::vector<std::string> fileNames;
|
|
extractor.GetSpecifiedTypeFiles(fileNames, ".abc");
|
|
if (fileNames.empty()) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "no .abc in hqf %{private}s", hqfFile.c_str());
|
|
return true;
|
|
}
|
|
|
|
for (const auto &fileName : fileNames) {
|
|
std::string patchFile = hqfFile + "/" + fileName;
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "UnloadPatch, patchFile: %{private}s", patchFile.c_str());
|
|
auto ret = panda::JSNApi::UnloadPatch(vm, patchFile);
|
|
if (ret != panda::JSNApi::PatchErrorCode::SUCCESS) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "UnLoadPatch failed with %{public}d", static_cast<int32_t>(ret));
|
|
}
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "UnLoad patch %{private}s succeed", patchFile.c_str());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool JsRuntime::NotifyHotReloadPage()
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
#ifdef SUPPORT_SCREEN
|
|
Ace::HotReloader::HotReload();
|
|
#endif // SUPPORT_SCREEN
|
|
return true;
|
|
}
|
|
|
|
bool JsRuntime::LoadScript(const std::string& path, std::vector<uint8_t>* buffer, bool isBundle)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "path: %{private}s", path.c_str());
|
|
CHECK_POINTER_AND_RETURN(jsEnv_, false);
|
|
return jsEnv_->LoadScript(path, buffer, isBundle);
|
|
}
|
|
|
|
bool JsRuntime::LoadScript(const std::string& path, uint8_t* buffer, size_t len, bool isBundle,
|
|
const std::string& srcEntrance)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "path: %{private}s", path.c_str());
|
|
CHECK_POINTER_AND_RETURN(jsEnv_, false);
|
|
if (isOhmUrl_ && !moduleName_.empty()) {
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, false);
|
|
std::string srcFilename = "";
|
|
srcFilename = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
|
|
return panda::JSNApi::ExecuteSecureWithOhmUrl(vm, buffer, len, srcFilename, srcEntrance);
|
|
}
|
|
return jsEnv_->LoadScript(path, buffer, len, isBundle);
|
|
}
|
|
|
|
std::unique_ptr<NativeReference> JsRuntime::LoadSystemModuleByEngine(
|
|
napi_env env, const std::string& moduleName, const napi_value* argv, size_t argc)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "ModuleName %{public}s", moduleName.c_str());
|
|
if (env == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null env");
|
|
return nullptr;
|
|
}
|
|
HandleScope handleScope(env);
|
|
napi_value globalObj = nullptr;
|
|
napi_get_global(env, &globalObj);
|
|
napi_value propertyValue = nullptr;
|
|
napi_get_named_property(env, globalObj, "requireNapi", &propertyValue);
|
|
|
|
std::unique_ptr<NativeReference> methodRequireNapiRef_;
|
|
napi_ref tmpRef = nullptr;
|
|
napi_create_reference(env, propertyValue, 1, &tmpRef);
|
|
methodRequireNapiRef_.reset(reinterpret_cast<NativeReference*>(tmpRef));
|
|
if (!methodRequireNapiRef_) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null methodRequireNapiRef_");
|
|
return nullptr;
|
|
}
|
|
|
|
napi_value className = nullptr;
|
|
napi_create_string_utf8(env, moduleName.c_str(), moduleName.length(), &className);
|
|
auto refValue = methodRequireNapiRef_->GetNapiValue();
|
|
napi_value args[1] = { className };
|
|
napi_value classValue = nullptr;
|
|
napi_call_function(env, globalObj, refValue, 1, args, &classValue);
|
|
napi_value instanceValue = nullptr;
|
|
napi_new_instance(env, classValue, argc, argv, &instanceValue);
|
|
if (instanceValue == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null instanceValue");
|
|
return nullptr;
|
|
}
|
|
|
|
napi_ref resultRef = nullptr;
|
|
napi_create_reference(env, instanceValue, 1, &resultRef);
|
|
return std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(resultRef));
|
|
}
|
|
|
|
void JsRuntime::FinishPreload()
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
panda::JSNApi::PreFork(vm);
|
|
}
|
|
|
|
void JsRuntime::PostPreload(const Options& options)
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
auto env = GetNapiEnv();
|
|
CHECK_POINTER(env);
|
|
panda::RuntimeOption postOption;
|
|
postOption.SetBundleName(options.bundleName);
|
|
postOption.SetArkTSMode(options.arkTSMode);
|
|
if (!options.arkNativeFilePath.empty()) {
|
|
std::string sandBoxAnFilePath = SANDBOX_ARK_CACHE_PATH + options.arkNativeFilePath;
|
|
postOption.SetAnDir(sandBoxAnFilePath);
|
|
}
|
|
if (options.isMultiThread) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Multi-Thread Mode: %{public}d", options.isMultiThread);
|
|
panda::JSNApi::SetMultiThreadCheck();
|
|
}
|
|
if (options.isErrorInfoEnhance) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Start Error-Info-Enhance Mode: %{public}d.", options.isErrorInfoEnhance);
|
|
panda::JSNApi::SetErrorInfoEnhance();
|
|
}
|
|
bool profileEnabled = OHOS::system::GetBoolParameter("ark.profile", false);
|
|
postOption.SetEnableProfile(profileEnabled);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "ASMM JIT Verify PostFork, jitEnabled: %{public}d", options.jitEnabled);
|
|
postOption.SetEnableJIT(options.jitEnabled);
|
|
postOption.SetAOTCompileStatusMap(options.aotCompileStatusMap);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "SmartGC: set options enableWarmStartupSmartGC to RuntimeOption");
|
|
postOption.SetEnableWarmStartupSmartGC(options.enableWarmStartupSmartGC);
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, "panda::JSNApi::PostFork");
|
|
panda::JSNApi::PostFork(vm, postOption);
|
|
}
|
|
reinterpret_cast<NativeEngine*>(env)->ReinitUVLoop();
|
|
uv_loop_s* loop = nullptr;
|
|
napi_get_uv_event_loop(env, &loop);
|
|
panda::JSNApi::SetLoop(vm, loop);
|
|
DFXJSNApi::RegisterAsyncDetectCallBack(vm);
|
|
}
|
|
|
|
void JsRuntime::LoadAotFile(const Options& options)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
if (options.hapPath.empty()) {
|
|
return;
|
|
}
|
|
|
|
bool newCreate = false;
|
|
std::string loadPath = ExtractorUtil::GetLoadFilePath(options.hapPath);
|
|
std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(loadPath, newCreate, true);
|
|
if (extractor != nullptr && newCreate) {
|
|
panda::JSNApi::LoadAotFile(vm, options.moduleName);
|
|
}
|
|
}
|
|
|
|
bool JsRuntime::Initialize(const Options& options)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
#ifdef SUPPORT_SCREEN
|
|
if (Ace::AceForwardCompatibility::PipelineChanged()) {
|
|
preloaded_ = false;
|
|
}
|
|
#endif
|
|
if (!preloaded_) {
|
|
if (!CreateJsEnv(options)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Create jsEnv failed");
|
|
return false;
|
|
}
|
|
}
|
|
apiTargetVersion_ = options.apiTargetVersion;
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Initialize: %{public}d", apiTargetVersion_);
|
|
bool isModular = false;
|
|
if (IsUseAbilityRuntime(options)) {
|
|
auto env = GetNapiEnv();
|
|
auto nativeEngine = reinterpret_cast<NativeEngine*>(env);
|
|
CHECK_POINTER_AND_RETURN(nativeEngine, false);
|
|
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, false);
|
|
|
|
panda::JSNApi::SetLargeHeap(options.allowArkTsLargeHeap);
|
|
if (preloaded_) {
|
|
PostPreload(options);
|
|
}
|
|
HandleScope handleScope(*this);
|
|
napi_value globalObj = nullptr;
|
|
napi_get_global(env, &globalObj);
|
|
CHECK_POINTER_AND_RETURN(globalObj, false);
|
|
if (!preloaded_) {
|
|
InitSyscapModule(env);
|
|
|
|
// Simple hook function 'isSystemplugin'
|
|
const char* moduleName = "JsRuntime";
|
|
BindNativeFunction(env, globalObj, "isSystemplugin", moduleName,
|
|
[](napi_env env, napi_callback_info cbinfo) -> napi_value {
|
|
return CreateJsUndefined(env);
|
|
});
|
|
|
|
napi_value propertyValue = nullptr;
|
|
napi_get_named_property(env, globalObj, "requireNapi", &propertyValue);
|
|
napi_ref tmpRef = nullptr;
|
|
napi_create_reference(env, propertyValue, 1, &tmpRef);
|
|
methodRequireNapiRef_.reset(reinterpret_cast<NativeReference*>(tmpRef));
|
|
if (!methodRequireNapiRef_) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null methodRequireNapiRef_");
|
|
return false;
|
|
}
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "PreloadAce start");
|
|
PreloadAce(options);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "PreloadAce end");
|
|
nativeEngine->RegisterPermissionCheck(PermissionCheckFunc);
|
|
}
|
|
|
|
if (!options.preload) {
|
|
isBundle_ = options.isBundle;
|
|
bundleName_ = options.bundleName;
|
|
codePath_ = options.codePath;
|
|
panda::JSNApi::SetSearchHapPathTracker(
|
|
vm, [options](const std::string moduleName, std::string& hapPath) -> bool {
|
|
if (options.hapModulePath.find(moduleName) == options.hapModulePath.end()) {
|
|
return false;
|
|
}
|
|
hapPath = options.hapModulePath.find(moduleName)->second;
|
|
return true;
|
|
});
|
|
ReInitJsEnvImpl(options);
|
|
LoadAotFile(options);
|
|
panda::JSNApi::SetBundle(vm, options.isBundle);
|
|
panda::JSNApi::SetBundleName(vm, options.bundleName);
|
|
panda::JSNApi::SetIsMainProcess(options.isMainProcess);
|
|
panda::JSNApi::SetHostResolveBufferTracker(
|
|
vm, JsModuleReader(options.bundleName, options.hapPath, options.isUnique));
|
|
isModular = !panda::JSNApi::IsBundle(vm);
|
|
std::vector<panda::HmsMap> systemKitsMap = GetSystemKitsMap(apiTargetVersion_);
|
|
panda::JSNApi::SetHmsModuleList(vm, systemKitsMap);
|
|
std::unordered_map<std::string, std::pair<std::unique_ptr<uint8_t[]>, size_t>> pkgInfoMap;
|
|
pkgContextInfoJsonStringMap_ = options.pkgContextInfoJsonStringMap;
|
|
packageNameList_ = options.packageNameList;
|
|
JsRuntimeLite::GetInstance().GetPkgContextInfoListMap(
|
|
options.pkgContextInfoJsonStringMap, pkgInfoMap);
|
|
panda::JSNApi::SetPkgContextInfoList(vm, pkgInfoMap);
|
|
panda::JSNApi::SetPkgNameList(vm, options.packageNameList);
|
|
panda::JSNApi::ModuleDeserialize(vm, options.versionCode);
|
|
}
|
|
}
|
|
|
|
if (!preloaded_) {
|
|
InitConsoleModule();
|
|
}
|
|
|
|
if (!options.preload) {
|
|
InitSourceMap(options.bundleName);
|
|
|
|
if (options.isUnique) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Not supported TimerModule when form render");
|
|
} else {
|
|
InitTimerModule();
|
|
}
|
|
|
|
OHOS::Global::I18n::ReplaceIntlModule(GetNapiEnv());
|
|
InitWorkerModule(options);
|
|
SetModuleLoadChecker(options.moduleCheckerDelegate);
|
|
SetRequestAotCallback();
|
|
|
|
if (!InitLoop(options.isStageModel)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Init loop failed");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
preloaded_ = options.preload;
|
|
return true;
|
|
}
|
|
|
|
bool JsRuntime::CreateJsEnv(const Options& options)
|
|
{
|
|
panda::RuntimeOption pandaOption;
|
|
int arkProperties = OHOS::system::GetIntParameter<int>("persist.ark.properties", -1);
|
|
std::string bundleName = OHOS::system::GetParameter("persist.ark.arkbundlename", "");
|
|
std::string memConfigProperty = OHOS::system::GetParameter("persist.ark.mem_config_property", "");
|
|
size_t gcThreadNum = OHOS::system::GetUintParameter<size_t>("persist.ark.gcthreads", 7);
|
|
size_t longPauseTime = OHOS::system::GetUintParameter<size_t>("persist.ark.longpausetime", 40);
|
|
pandaOption.SetLargeHeap(options.allowArkTsLargeHeap);
|
|
pandaOption.SetArkProperties(arkProperties);
|
|
pandaOption.SetArkBundleName(bundleName);
|
|
pandaOption.SetMemConfigProperty(memConfigProperty);
|
|
pandaOption.SetGcThreadNum(gcThreadNum);
|
|
pandaOption.SetLongPauseTime(longPauseTime);
|
|
pandaOption.SetIsFormThread(options.isFormRender);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "ark properties=%{public}d bundlename=%{public}s",
|
|
arkProperties, bundleName.c_str());
|
|
pandaOption.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
|
|
pandaOption.SetGcPoolSize(DEFAULT_GC_POOL_SIZE);
|
|
pandaOption.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::FOLLOW);
|
|
pandaOption.SetLogBufPrint(PrintVmLog);
|
|
|
|
bool asmInterpreterEnabled = OHOS::system::GetBoolParameter("persist.ark.asminterpreter", true);
|
|
std::string asmOpcodeDisableRange = OHOS::system::GetParameter("persist.ark.asmopcodedisablerange", "");
|
|
pandaOption.SetEnableAsmInterpreter(asmInterpreterEnabled);
|
|
pandaOption.SetAsmOpcodeDisableRange(asmOpcodeDisableRange);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "ASMM JIT Verify CreateJsEnv, jitEnabled: %{public}d", options.jitEnabled);
|
|
pandaOption.SetEnableJIT(options.jitEnabled);
|
|
|
|
if (options.isMultiThread) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Start Multi Thread Mode: %{public}d", options.isMultiThread);
|
|
panda::JSNApi::SetMultiThreadCheck();
|
|
}
|
|
|
|
if (options.isErrorInfoEnhance) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Start Error Info Enhance Mode: %{public}d.", options.isErrorInfoEnhance);
|
|
panda::JSNApi::SetErrorInfoEnhance();
|
|
}
|
|
|
|
if (IsUseAbilityRuntime(options)) {
|
|
// aot related
|
|
bool aotEnabled = OHOS::system::GetBoolParameter("persist.ark.aot", true);
|
|
pandaOption.SetEnableAOT(aotEnabled);
|
|
pandaOption.SetProfileDir(SANDBOX_ARK_PROIFILE_PATH);
|
|
}
|
|
|
|
OHOSJsEnvLogger::RegisterJsEnvLogger();
|
|
jsEnv_ = std::make_shared<JsEnv::JsEnvironment>(std::make_unique<OHOSJsEnvironmentImpl>(options.eventRunner));
|
|
if (jsEnv_ == nullptr || !jsEnv_->Initialize(pandaOption, static_cast<void*>(this))) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Init jsEnv failed");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void JsRuntime::PreloadAce(const Options& options)
|
|
{
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
#ifdef SUPPORT_SCREEN
|
|
if (options.loadAce) {
|
|
// ArkTsCard start
|
|
if (options.isUnique) {
|
|
OHOS::Ace::DeclarativeModulePreloader::PreloadCard(
|
|
*nativeEngine, options.bundleName, options.pkgContextInfoJsonStringMap);
|
|
} else {
|
|
OHOS::Ace::DeclarativeModulePreloader::Preload(*nativeEngine);
|
|
}
|
|
// ArkTsCard end
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void JsRuntime::ReloadFormComponent()
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
// ArkTsCard update condition, need to reload new component
|
|
#ifdef SUPPORT_SCREEN
|
|
OHOS::Ace::DeclarativeModulePreloader::ReloadCard(*nativeEngine, bundleName_, pkgContextInfoJsonStringMap_);
|
|
#endif
|
|
}
|
|
|
|
bool JsRuntime::InitLoop(bool isStage)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER_AND_RETURN(jsEnv_, false);
|
|
return jsEnv_->InitLoop(isStage);
|
|
}
|
|
|
|
void JsRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths, const bool& isSystemApp)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Set library path");
|
|
|
|
if (appLibPaths.size() == 0) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "no lib path to set");
|
|
return;
|
|
}
|
|
|
|
auto moduleManager = NativeModuleManager::GetInstance();
|
|
if (moduleManager == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null moduleManager");
|
|
return;
|
|
}
|
|
|
|
for (const auto &appLibPath : appLibPaths) {
|
|
moduleManager->SetAppLibPath(appLibPath.first, appLibPath.second, isSystemApp);
|
|
}
|
|
}
|
|
|
|
void JsRuntime::SetOrUpdateLibPath(const AppLibPathMap& appLibPaths, const bool& isSystemApp)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "SetOrUpdate library path");
|
|
|
|
if (appLibPaths.size() == 0) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "no lib path to set");
|
|
return;
|
|
}
|
|
|
|
auto moduleManager = NativeModuleManager::GetInstance();
|
|
if (moduleManager == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null moduleManager");
|
|
return;
|
|
}
|
|
|
|
for (const auto &appLibPath : appLibPaths) {
|
|
std::string pluginNamespace;
|
|
if (moduleManager->GetLdNamespaceName(appLibPath.first, pluginNamespace)) {
|
|
moduleManager->UpdateNamespaceLibPath(appLibPath.first, appLibPath.second);
|
|
} else {
|
|
moduleManager->SetAppLibPath(appLibPath.first, appLibPath.second, isSystemApp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void JsRuntime::InheritPluginNamespace(const std::vector<std::string> &moduleNames)
|
|
{
|
|
auto moduleManager = NativeModuleManager::GetInstance();
|
|
if (moduleManager == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null moduleManager");
|
|
return;
|
|
}
|
|
std::string currentNamespace;
|
|
if (!moduleManager->GetLdNamespaceName("default", currentNamespace)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "get current namespace failed");
|
|
return;
|
|
}
|
|
|
|
for (const auto& item : moduleNames) {
|
|
if (item.empty()) {
|
|
continue;
|
|
}
|
|
std::string pluginNamespace;
|
|
if (!moduleManager->GetLdNamespaceName(item, pluginNamespace)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "get %{public}s pluginNamespace failed", item.c_str());
|
|
continue;
|
|
}
|
|
moduleManager->InheritNamespaceEachOther(currentNamespace, pluginNamespace);
|
|
}
|
|
}
|
|
|
|
void JsRuntime::CreatePluginDefaultNamespace(const std::string &lddictionaries)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
Security::AccessToken::AccessTokenID selfToken = IPCSkeleton::GetSelfTokenID();
|
|
int result = Security::AccessToken::AccessTokenKit::VerifyAccessToken(selfToken,
|
|
PERMISSION_LOAD_INDEPENDENT_LIBRARY);
|
|
int resultWeb = Security::AccessToken::AccessTokenKit::VerifyAccessToken(selfToken,
|
|
PERMISSION_LOAD_CERTSIGN_LIBRARY);
|
|
if (result != Security::AccessToken::PermissionState::PERMISSION_GRANTED &&
|
|
resultWeb != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "verify access token failed: %{public}d", result);
|
|
return;
|
|
}
|
|
auto moduleManager = NativeModuleManager::GetInstance();
|
|
if (moduleManager == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null moduleManager");
|
|
return;
|
|
}
|
|
std::string currentNamespace;
|
|
if (!moduleManager->GetLdNamespaceName("default", currentNamespace)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "get current namespace failed");
|
|
return;
|
|
}
|
|
std::vector<std::string> appLibPaths;
|
|
moduleManager->SetAppLibPath(DEFAULT_PLUGIN, appLibPaths, false);
|
|
std::string pluginDefaultNamespace;
|
|
moduleManager->GetLdNamespaceName(DEFAULT_PLUGIN, pluginDefaultNamespace);
|
|
moduleManager->SetLdPermittedPathsForNamespace(pluginDefaultNamespace, lddictionaries);
|
|
moduleManager->InheritNamespaceEachOther(currentNamespace, pluginDefaultNamespace);
|
|
}
|
|
|
|
void JsRuntime::InitSourceMap(const std::string bundleName)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
|
|
auto init = [bundleName]() {
|
|
DFXJSNApi::SourceMapSetInitStatus(false);
|
|
std::vector<std::string> hapList;
|
|
JsModuleReader::GetHapPathList(bundleName, hapList);
|
|
for (auto &hapInfo : hapList) {
|
|
if (!hapInfo.empty()) {
|
|
std::string sourceMapData;
|
|
JsRuntime::ReadSourceMapData(hapInfo, MERGE_SOURCE_MAP_PATH, sourceMapData);
|
|
DFXJSNApi::SourceMapSplitSourceMap(sourceMapData);
|
|
}
|
|
}
|
|
DFXJSNApi::SourceMapSetInitStatus(true);
|
|
};
|
|
|
|
ffrt::submit(init, {}, {}, ffrt::task_attr().qos(ffrt::qos_user_initiated));
|
|
}
|
|
|
|
void JsRuntime::HqfInitSourceMap(const std::string hqfFilePath)
|
|
{
|
|
std::string patchSoureMapFile;
|
|
std::vector<uint8_t> soureMapBuffer;
|
|
if (!GetFileBuffer(hqfFilePath, patchSoureMapFile, soureMapBuffer, false)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "get patchSoureMap file buffer failed");
|
|
return;
|
|
}
|
|
std::string str(soureMapBuffer.begin(), soureMapBuffer.end());
|
|
CHECK_POINTER(jsEnv_);
|
|
DFXJSNApi::SourceMapSplitSourceMap(str);
|
|
}
|
|
|
|
void JsRuntime::Deinitialize()
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
for (auto it = modules_.begin(); it != modules_.end(); it = modules_.erase(it)) {
|
|
delete it->second;
|
|
it->second = nullptr;
|
|
}
|
|
|
|
methodRequireNapiRef_.reset();
|
|
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->DeInitLoop();
|
|
}
|
|
|
|
napi_value JsRuntime::LoadJsBundle(const std::string& path, const std::string& hapPath, bool useCommonChunk)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
auto env = GetNapiEnv();
|
|
CHECK_POINTER_AND_RETURN(env, nullptr);
|
|
HandleEscape handleEscape(env);
|
|
napi_value globalObj = nullptr;
|
|
napi_get_global(env, &globalObj);
|
|
napi_value exports = nullptr;
|
|
napi_create_object(env, &exports);
|
|
napi_set_named_property(env, globalObj, "exports", exports);
|
|
|
|
if (!RunScript(path, hapPath, useCommonChunk)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "run script: %{private}s failed", path.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
napi_value exportsObj = nullptr;
|
|
napi_get_named_property(env, globalObj, "exports", &exportsObj);
|
|
if (exportsObj == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null exportObj");
|
|
return nullptr;
|
|
}
|
|
|
|
napi_value exportObj = nullptr;
|
|
napi_get_named_property(env, exportsObj, "default", &exportObj);
|
|
if (exportObj == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null exportObj");
|
|
return nullptr;
|
|
}
|
|
|
|
return handleEscape.Escape(exportObj);
|
|
}
|
|
|
|
napi_value JsRuntime::LoadJsModule(const std::string& path, const std::string& hapPath, const std::string& srcEntrance)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
if (!RunScript(path, hapPath, false, srcEntrance)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "run script: %{private}s failed", path.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, nullptr);
|
|
panda::Local<panda::ObjectRef> exportObj;
|
|
if (isOhmUrl_) {
|
|
exportObj = panda::JSNApi::GetExportObjectFromOhmUrl(vm, srcEntrance, "default");
|
|
} else {
|
|
exportObj = panda::JSNApi::GetExportObject(vm, path, "default");
|
|
}
|
|
|
|
if (exportObj->IsNull()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Get export object failed");
|
|
return nullptr;
|
|
}
|
|
|
|
auto env = GetNapiEnv();
|
|
CHECK_POINTER_AND_RETURN(env, nullptr);
|
|
return ArkNativeEngine::ArkValueToNapiValue(env, exportObj);
|
|
}
|
|
|
|
std::unique_ptr<NativeReference> JsRuntime::LoadModule(const std::string& moduleName, const std::string& modulePath,
|
|
const std::string& hapPath, bool esmodule, bool useCommonChunk, const std::string& srcEntrance)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Load module(%{public}s, %{private}s, %{private}s, %{public}s)",
|
|
moduleName.c_str(), modulePath.c_str(), hapPath.c_str(), esmodule ? "true" : "false");
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, std::unique_ptr<NativeReference>());
|
|
// use for debugger, js engine need to know load module to handle debug event
|
|
panda::JSNApi::NotifyLoadModule(vm);
|
|
auto env = GetNapiEnv();
|
|
CHECK_POINTER_AND_RETURN(env, std::unique_ptr<NativeReference>());
|
|
isOhmUrl_ = panda::JSNApi::IsOhmUrl(srcEntrance);
|
|
|
|
HandleScope handleScope(*this);
|
|
|
|
std::string path = moduleName;
|
|
auto pos = path.find("::");
|
|
if (pos != std::string::npos) {
|
|
path.erase(pos, path.size() - pos);
|
|
moduleName_ = path;
|
|
}
|
|
|
|
napi_value classValue = nullptr;
|
|
|
|
auto it = modules_.find(modulePath);
|
|
if (it != modules_.end()) {
|
|
classValue = it->second->GetNapiValue();
|
|
} else {
|
|
std::string fileName;
|
|
if (!hapPath.empty()) {
|
|
fileName.append(codePath_).append(Constants::FILE_SEPARATOR).append(modulePath);
|
|
std::regex pattern(std::string(Constants::FILE_DOT) + std::string(Constants::FILE_SEPARATOR));
|
|
fileName = std::regex_replace(fileName, pattern, "");
|
|
} else {
|
|
if (!MakeFilePath(codePath_, modulePath, fileName)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "make module file path: %{private}s failed", modulePath.c_str());
|
|
return std::unique_ptr<NativeReference>();
|
|
}
|
|
}
|
|
classValue = esmodule ? LoadJsModule(fileName, hapPath, srcEntrance)
|
|
: LoadJsBundle(fileName, hapPath, useCommonChunk);
|
|
if (classValue == nullptr) {
|
|
return std::unique_ptr<NativeReference>();
|
|
}
|
|
|
|
napi_ref tmpRef = nullptr;
|
|
napi_status status = napi_create_reference(env, classValue, 1, &tmpRef);
|
|
if (status != napi_ok || tmpRef == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "create reference failed");
|
|
return std::unique_ptr<NativeReference>();
|
|
}
|
|
modules_.emplace(modulePath, reinterpret_cast<NativeReference*>(tmpRef));
|
|
}
|
|
|
|
napi_value instanceValue = nullptr;
|
|
napi_new_instance(env, classValue, 0, nullptr, &instanceValue);
|
|
if (instanceValue == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null instanceValue");
|
|
return std::unique_ptr<NativeReference>();
|
|
}
|
|
|
|
napi_ref resultRef = nullptr;
|
|
napi_create_reference(env, instanceValue, 1, &resultRef);
|
|
return std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(resultRef));
|
|
}
|
|
|
|
std::unique_ptr<NativeReference> JsRuntime::LoadSystemModule(
|
|
const std::string& moduleName, const napi_value* argv, size_t argc)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "SystemModule %{public}s", moduleName.c_str());
|
|
napi_env env = GetNapiEnv();
|
|
CHECK_POINTER_AND_RETURN(env, std::unique_ptr<NativeReference>());
|
|
|
|
HandleScope handleScope(*this);
|
|
|
|
if (methodRequireNapiRef_ == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null methodRequireNapiRef_");
|
|
return std::unique_ptr<NativeReference>();
|
|
}
|
|
|
|
napi_value className = nullptr;
|
|
napi_create_string_utf8(env, moduleName.c_str(), moduleName.length(), &className);
|
|
napi_value globalObj = nullptr;
|
|
napi_get_global(env, &globalObj);
|
|
napi_value refValue = methodRequireNapiRef_->GetNapiValue();
|
|
napi_value args[1] = { className };
|
|
napi_value classValue = nullptr;
|
|
napi_call_function(env, globalObj, refValue, 1, args, &classValue);
|
|
napi_value instanceValue = nullptr;
|
|
napi_new_instance(env, classValue, argc, argv, &instanceValue);
|
|
if (instanceValue == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null instanceValue");
|
|
return std::unique_ptr<NativeReference>();
|
|
}
|
|
|
|
napi_ref resultRef = nullptr;
|
|
napi_create_reference(env, instanceValue, 1, &resultRef);
|
|
return std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(resultRef));
|
|
}
|
|
|
|
napi_value JsRuntime::GetExportObjectFromOhmUrl(const std::string &srcEntrance, const std::string &key)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "Get %{private}s export %{private}s", srcEntrance.c_str(), key.c_str());
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, nullptr);
|
|
auto ohmUrl = panda::JSNApi::IsOhmUrl(srcEntrance);
|
|
if (!ohmUrl) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "srcEntrance %{private}s not ohmurl", srcEntrance.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
panda::Local<panda::ObjectRef> exportObj = panda::JSNApi::GetExportObjectFromOhmUrl(vm, srcEntrance, key);
|
|
if (exportObj->IsNull()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "Get %{private}s export %{private}s failed", srcEntrance.c_str(), key.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
auto env = GetNapiEnv();
|
|
CHECK_POINTER_AND_RETURN(env, nullptr);
|
|
return ArkNativeEngine::ArkValueToNapiValue(env, exportObj);
|
|
}
|
|
|
|
std::unique_ptr<AbilityBase::FileMapper> JsRuntime::ExecuteSecureWithOhmUrl(const std::string &moduleName,
|
|
const std::string &hapPath, const std::string &srcEntrance)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "moduleName %{public}s, hapPath %{private}s, execute %{private}s",
|
|
moduleName.c_str(), hapPath.c_str(), srcEntrance.c_str());
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, nullptr);
|
|
auto ohmUrl = panda::JSNApi::IsOhmUrl(srcEntrance);
|
|
if (!ohmUrl) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "srcEntrance %{private}s not ohmurl", srcEntrance.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
bool newCreate = false;
|
|
std::string loadPath = ExtractorUtil::GetLoadFilePath(hapPath);
|
|
auto extractor = ExtractorUtil::GetExtractor(loadPath, newCreate, true);
|
|
if (extractor == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "get hapPath %{private}s extractor failed", hapPath.c_str());
|
|
return nullptr;
|
|
}
|
|
extractor->SetAutoCloseFd(true);
|
|
|
|
std::string srcFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_PATH;
|
|
auto safeData = extractor->GetSafeData(srcFileName);
|
|
if (safeData == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null safeData srcFileName %{private}s", srcFileName.c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
auto start = std::chrono::high_resolution_clock::now();
|
|
auto ret = panda::JSNApi::ExecuteSecureWithOhmUrl(vm, safeData->GetDataPtr(), safeData->GetDataLen(), srcFileName,
|
|
srcEntrance);
|
|
auto end = std::chrono::high_resolution_clock::now();
|
|
auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "srcEntrance %{public}s timing %{public}lld", srcEntrance.c_str(), duration_ms);
|
|
if (!ret) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "ExecuteSecureWithOhmUrl failed");
|
|
return nullptr;
|
|
}
|
|
return safeData;
|
|
}
|
|
std::shared_ptr<AbilityBase::FileMapper> JsRuntime::GetOrCreateSafeData(std::shared_ptr<Extractor> extractor,
|
|
const std::string &modulePath)
|
|
{
|
|
//modulePath = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH
|
|
auto it = safeDataMap_.find(modulePath);
|
|
if (it != safeDataMap_.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
std::shared_ptr<AbilityBase::FileMapper> safeData = extractor->GetSafeData(modulePath);
|
|
if (!safeData) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null safeData");
|
|
return nullptr ;
|
|
}
|
|
//because extractor->GetSafeData will reload abc file,so need cache.
|
|
safeDataMap_.emplace(modulePath, safeData);
|
|
return safeData;
|
|
}
|
|
bool JsRuntime::RunScript(const std::string& srcPath, const std::string& hapPath, bool useCommonChunk,
|
|
const std::string& srcEntrance)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm, false);
|
|
HandleScope handleScope(*this);
|
|
std::string commonsPath = std::string(Constants::LOCAL_CODE_PATH) + "/" + moduleName_ + "/ets/commons.abc";
|
|
std::string vendorsPath = std::string(Constants::LOCAL_CODE_PATH) + "/" + moduleName_ + "/ets/vendors.abc";
|
|
if (hapPath.empty()) {
|
|
if (useCommonChunk) {
|
|
(void)LoadScript(commonsPath);
|
|
(void)LoadScript(vendorsPath);
|
|
}
|
|
return LoadScript(srcPath);
|
|
}
|
|
|
|
bool newCreate = false;
|
|
std::string loadPath = ExtractorUtil::GetLoadFilePath(hapPath);
|
|
std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(loadPath, newCreate, true);
|
|
if (!extractor) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "hapPath[%{private}s]", hapPath.c_str());
|
|
return false;
|
|
}
|
|
if (newCreate) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "newCreate");
|
|
panda::JSNApi::LoadAotFile(vm, moduleName_);
|
|
auto resourceManager = AbilityBase::ExtractResourceManager::GetExtractResourceManager().GetGlobalObject();
|
|
if (resourceManager) {
|
|
resourceManager->AddResource(loadPath.c_str());
|
|
}
|
|
}
|
|
|
|
auto func = [&](std::string modulePath, const std::string abcPath) {
|
|
bool useSafeMempry = apiTargetVersion_ == 0 || apiTargetVersion_ > API8;
|
|
if (!extractor->IsHapCompress(modulePath) && useSafeMempry) {
|
|
auto safeData = isBundle_ ? extractor->GetSafeData(modulePath) : GetOrCreateSafeData(extractor, modulePath);
|
|
if (!safeData) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null safeData");
|
|
return false;
|
|
}
|
|
return LoadScript(abcPath, safeData->GetDataPtr(), safeData->GetDataLen(), isBundle_, srcEntrance);
|
|
} else {
|
|
std::unique_ptr<uint8_t[]> data;
|
|
size_t dataLen = 0;
|
|
if (!extractor->ExtractToBufByName(modulePath, data, dataLen)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "get abc file failed");
|
|
return false;
|
|
}
|
|
std::vector<uint8_t> buffer;
|
|
buffer.assign(data.get(), data.get() + dataLen);
|
|
|
|
return LoadScript(abcPath, &buffer, isBundle_);
|
|
}
|
|
};
|
|
|
|
if (useCommonChunk) {
|
|
(void)func(commonsPath, commonsPath);
|
|
(void)func(vendorsPath, vendorsPath);
|
|
}
|
|
|
|
std::string path = srcPath;
|
|
if (!isBundle_) {
|
|
if (moduleName_.empty()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "moduleName empty");
|
|
return false;
|
|
}
|
|
path = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
|
|
panda::JSNApi::SetAssetPath(vm, path);
|
|
panda::JSNApi::SetModuleName(vm, moduleName_);
|
|
}
|
|
return func(path, srcPath);
|
|
}
|
|
|
|
bool JsRuntime::RunSandboxScript(const std::string& path, const std::string& hapPath)
|
|
{
|
|
std::string fileName;
|
|
if (!hapPath.empty()) {
|
|
fileName.append(codePath_).append(Constants::FILE_SEPARATOR).append(path);
|
|
std::regex pattern(std::string(Constants::FILE_DOT) + std::string(Constants::FILE_SEPARATOR));
|
|
fileName = std::regex_replace(fileName, pattern, "");
|
|
} else {
|
|
if (!MakeFilePath(codePath_, path, fileName)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "make module file path: %{private}s failed", path.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!RunScript(fileName, hapPath)) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "run script: %{public}s failed", fileName.c_str());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void JsRuntime::PostTask(const std::function<void()>& task, const std::string& name, int64_t delayTime)
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->PostTask(task, name, delayTime);
|
|
}
|
|
|
|
void JsRuntime::PostSyncTask(const std::function<void()>& task, const std::string& name)
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->PostSyncTask(task, name);
|
|
}
|
|
|
|
void JsRuntime::RemoveTask(const std::string& name)
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->RemoveTask(name);
|
|
}
|
|
|
|
void JsRuntime::DumpCpuProfile()
|
|
{
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
nativeEngine->DumpCpuProfile();
|
|
}
|
|
|
|
void JsRuntime::DumpHeapSnapshot(bool isPrivate)
|
|
{
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
nativeEngine->DumpHeapSnapshot(true, DumpFormat::JSON, isPrivate, false);
|
|
}
|
|
|
|
void JsRuntime::DumpHeapSnapshot(uint32_t tid, bool isFullGC, bool isBinary)
|
|
{
|
|
OHOS::AbilityRuntime::Runtime::JsHeapDumpParam param;
|
|
param.isFullGC = isFullGC;
|
|
param.isBinary = isBinary;
|
|
DumpHeapSnapshot(tid, param);
|
|
}
|
|
|
|
void JsRuntime::DumpHeapSnapshot(uint32_t tid, const OHOS::AbilityRuntime::Runtime::JsHeapDumpParam ¶m)
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
panda::ecmascript::DumpSnapShotOption dumpOption;
|
|
if (param.isBinary) {
|
|
dumpOption.dumpFormat = panda::ecmascript::DumpFormat::BINARY;
|
|
} else {
|
|
dumpOption.dumpFormat = panda::ecmascript::DumpFormat::JSON;
|
|
}
|
|
dumpOption.isVmMode = true;
|
|
dumpOption.isPrivate = false;
|
|
dumpOption.captureNumericValue = true;
|
|
dumpOption.isFullGC = param.isFullGC;
|
|
dumpOption.isSync = false;
|
|
dumpOption.isClearNodeIdCache = param.isClearNodeIdCache;
|
|
dumpOption.isProcDump = param.isProcDump;
|
|
if (param.languageEnv == CODE_LANGUAGE_ARKTS_1_0) {
|
|
dumpOption.languageEnv = panda::ecmascript::LanguageEnv::DYNAMIC;
|
|
} else if (param.languageEnv == CODE_LANGUAGE_ARKTS_1_2) {
|
|
dumpOption.languageEnv = panda::ecmascript::LanguageEnv::STATIC;
|
|
} else if (param.languageEnv == CODE_LANGUAGE_ARKTS_HYBRID) {
|
|
dumpOption.languageEnv = panda::ecmascript::LanguageEnv::HYBRID;
|
|
} else {
|
|
dumpOption.languageEnv = panda::ecmascript::LanguageEnv::DYNAMIC;
|
|
}
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "DumpHeapSnapshot languageEnv: %{public}u",
|
|
static_cast<uint8_t>(dumpOption.languageEnv));
|
|
DFXJSNApi::DumpHeapSnapshot(vm, dumpOption, tid);
|
|
}
|
|
|
|
void JsRuntime::DumpJsHandleMap()
|
|
{
|
|
TAG_LOGI(AAFwkTag::JSRUNTIME, "DumpJsHandleMap");
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
DFXJSNApi::GetHandleNodeIdMap(vm);
|
|
DFXJSNApi::DestroyHeapProfiler(vm);
|
|
}
|
|
|
|
size_t JsRuntime::GetHeapTotalSize()
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
if (!vm) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null vm");
|
|
return 0;
|
|
}
|
|
return DFXJSNApi::GetHeapTotalSize(vm);
|
|
}
|
|
|
|
size_t JsRuntime::GetHeapObjectSize()
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
if (!vm) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null vm");
|
|
return 0;
|
|
}
|
|
return DFXJSNApi::GetHeapObjectSize(vm);
|
|
}
|
|
|
|
size_t JsRuntime::GetSharedHeapSize()
|
|
{
|
|
return DFXJSNApi::GetSharedHeapSize();
|
|
}
|
|
|
|
panda::GCStatistic JsRuntime::GetGCStatistic()
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
if (!vm) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null vm");
|
|
panda::GCStatistic gCStatistic;
|
|
return gCStatistic;
|
|
}
|
|
return DFXJSNApi::GetGCStatistic(vm);
|
|
}
|
|
|
|
void JsRuntime::ForceFullGC(uint32_t tid)
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
DFXJSNApi::TriggerGC(vm, tid);
|
|
}
|
|
|
|
void JsRuntime::DestroyHeapProfiler()
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->DestroyHeapProfiler();
|
|
}
|
|
|
|
void JsRuntime::ForceFullGC()
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
panda::JSNApi::TriggerGC(vm, panda::ecmascript::GCReason::TRIGGER_BY_ABILITY,
|
|
panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
|
|
}
|
|
|
|
void JsRuntime::AllowCrossThreadExecution()
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
panda::JSNApi::AllowCrossThreadExecution(vm);
|
|
}
|
|
|
|
void JsRuntime::GetHeapPrepare()
|
|
{
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->GetHeapPrepare();
|
|
}
|
|
|
|
void JsRuntime::NotifyApplicationState(bool isBackground)
|
|
{
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
nativeEngine->NotifyApplicationState(isBackground);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "isBackground %{public}d", isBackground);
|
|
}
|
|
|
|
bool JsRuntime::SuspendVM(uint32_t tid)
|
|
{
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER_AND_RETURN(nativeEngine, false);
|
|
return nativeEngine->SuspendVMById(tid);
|
|
}
|
|
|
|
void JsRuntime::ResumeVM(uint32_t tid)
|
|
{
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
nativeEngine->ResumeVMById(tid);
|
|
}
|
|
|
|
void JsRuntime::PreloadSystemModule(const std::string& moduleName)
|
|
{
|
|
HandleScope handleScope(*this);
|
|
auto env = GetNapiEnv();
|
|
CHECK_POINTER(env);
|
|
if (methodRequireNapiRef_ == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null methodRequireNapiRef_");
|
|
return;
|
|
}
|
|
napi_value className = nullptr;
|
|
napi_create_string_utf8(env, moduleName.c_str(), moduleName.length(), &className);
|
|
napi_value globalObj = nullptr;
|
|
napi_get_global(env, &globalObj);
|
|
napi_value refValue = methodRequireNapiRef_->GetNapiValue();
|
|
napi_value args[1] = { className };
|
|
napi_call_function(env, globalObj, refValue, 1, args, nullptr);
|
|
}
|
|
|
|
void JsRuntime::PreloadMainAbility(const std::string& moduleName, const std::string& srcPath,
|
|
const std::string& hapPath, bool isEsMode, const std::string& srcEntrance)
|
|
{
|
|
HandleScope handleScope(*this);
|
|
std::string key(moduleName);
|
|
key.append("::");
|
|
key.append(srcPath);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "PreloadMainAbility srcPath: %{public}s", srcPath.c_str());
|
|
preloadList_[key] = LoadModule(moduleName, srcPath, hapPath, isEsMode, false, srcEntrance);
|
|
}
|
|
|
|
void JsRuntime::PreloadModule(const std::string& moduleName, const std::string& srcPath,
|
|
const std::string& hapPath, bool isEsMode, bool useCommonTrunk)
|
|
{
|
|
std::string key(moduleName);
|
|
key.append("::");
|
|
key.append(srcPath);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "PreloadModule srcPath: %{public}s", srcPath.c_str());
|
|
preloadList_[key] = LoadModule(moduleName, srcPath, hapPath, isEsMode, useCommonTrunk);
|
|
}
|
|
|
|
bool JsRuntime::PopPreloadObj(const std::string& key, std::unique_ptr<NativeReference>& obj)
|
|
{
|
|
if (preloadList_.find(key) == preloadList_.end()) {
|
|
return false;
|
|
}
|
|
if (preloadList_[key] != nullptr) {
|
|
obj = std::move(preloadList_[key]);
|
|
preloadList_.erase(key);
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "PopPreloadObj key: %{public}s", key.c_str());
|
|
return true;
|
|
}
|
|
preloadList_.erase(key);
|
|
return false;
|
|
}
|
|
|
|
NativeEngine& JsRuntime::GetNativeEngine() const
|
|
{
|
|
return *GetNativeEnginePointer();
|
|
}
|
|
|
|
napi_env JsRuntime::GetNapiEnv() const
|
|
{
|
|
return reinterpret_cast<napi_env>(GetNativeEnginePointer());
|
|
}
|
|
|
|
NativeEngine* JsRuntime::GetNativeEnginePointer() const
|
|
{
|
|
CHECK_POINTER_AND_RETURN(jsEnv_, nullptr);
|
|
return jsEnv_->GetNativeEngine();
|
|
}
|
|
|
|
panda::ecmascript::EcmaVM* JsRuntime::GetEcmaVm() const
|
|
{
|
|
CHECK_POINTER_AND_RETURN(jsEnv_, nullptr);
|
|
return jsEnv_->GetVM();
|
|
}
|
|
|
|
bool JsRuntime::IsUseAbilityRuntime(const Options& options) const
|
|
{
|
|
return (options.isStageModel) || (options.isTestFramework);
|
|
}
|
|
|
|
void JsRuntime::UpdateModuleNameAndAssetPath(const std::string& moduleName)
|
|
{
|
|
if (isBundle_) {
|
|
return;
|
|
}
|
|
|
|
auto vm = GetEcmaVm();
|
|
if (!vm || moduleName.empty()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null vm or moduleName");
|
|
return;
|
|
}
|
|
|
|
moduleName_ = moduleName;
|
|
std::string path = BUNDLE_INSTALL_PATH + moduleName_ + MERGE_ABC_PATH;
|
|
panda::JSNApi::SetAssetPath(vm, path);
|
|
panda::JSNApi::SetModuleName(vm, moduleName_);
|
|
}
|
|
|
|
void JsRuntime::RegisterUncaughtExceptionHandler(const JsEnv::UncaughtExceptionInfo& uncaughtExceptionInfo,
|
|
bool isStatic)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->RegisterUncaughtExceptionHandler(uncaughtExceptionInfo, isStatic);
|
|
}
|
|
|
|
void JsRuntime::RegisterUncatchableExceptionHandler(const JsEnv::UncatchableTask& uncatchableTask, bool isStatic)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->RegisterUncatchableExceptionHandler(uncatchableTask, isStatic);
|
|
}
|
|
|
|
void JsRuntime::RegisterQuickFixQueryFunc(const std::map<std::string, std::string>& moduleAndPath)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER(vm);
|
|
for (auto it = moduleAndPath.begin(); it != moduleAndPath.end(); it++) {
|
|
std::string hqfFile(AbilityBase::GetLoadPath(it->second));
|
|
HqfInitSourceMap(hqfFile);
|
|
}
|
|
panda::JSNApi::RegisterQuickFixQueryFunc(vm, JsQuickfixCallback(moduleAndPath));
|
|
}
|
|
|
|
bool JsRuntime::ReadSourceMapData(const std::string& hapPath, const std::string& sourceMapPath, std::string& content)
|
|
{
|
|
// Source map relative path, FA: "/assets/js", Stage: "/ets"
|
|
if (hapPath.empty()) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "empty hapPath");
|
|
return false;
|
|
}
|
|
bool newCreate = false;
|
|
std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(
|
|
ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
|
|
if (extractor == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "hap's path: %{public}s, get extractor failed", hapPath.c_str());
|
|
return false;
|
|
}
|
|
std::unique_ptr<uint8_t[]> dataPtr = nullptr;
|
|
size_t len = 0;
|
|
if (!extractor->ExtractToBufByName(sourceMapPath, dataPtr, len)) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "can't find source map, and switch to stage model");
|
|
std::string tempPath = std::regex_replace(sourceMapPath, std::regex("ets"), "assets/js");
|
|
if (!extractor->ExtractToBufByName(tempPath, dataPtr, len)) {
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "get mergeSourceMapData fileBuffer failed, map path: %{private}s",
|
|
tempPath.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
content.assign(dataPtr.get(), dataPtr.get() + len);
|
|
return true;
|
|
}
|
|
|
|
void JsRuntime::FreeNativeReference(std::unique_ptr<NativeReference> reference)
|
|
{
|
|
FreeNativeReference(std::move(reference), nullptr);
|
|
}
|
|
|
|
void JsRuntime::FreeNativeReference(std::shared_ptr<NativeReference>&& reference)
|
|
{
|
|
FreeNativeReference(nullptr, std::move(reference));
|
|
}
|
|
|
|
struct JsNativeReferenceDeleterObject {
|
|
std::unique_ptr<NativeReference> uniqueNativeRef_ = nullptr;
|
|
std::shared_ptr<NativeReference> sharedNativeRef_ = nullptr;
|
|
};
|
|
|
|
void JsRuntime::FreeNativeReference(std::unique_ptr<NativeReference> uniqueNativeRef,
|
|
std::shared_ptr<NativeReference>&& sharedNativeRef)
|
|
{
|
|
if (uniqueNativeRef == nullptr && sharedNativeRef == nullptr) {
|
|
TAG_LOGW(AAFwkTag::JSRUNTIME, "invalid nativeRef");
|
|
return;
|
|
}
|
|
|
|
auto nativeEngine = GetNativeEnginePointer();
|
|
CHECK_POINTER(nativeEngine);
|
|
auto uvLoop = nativeEngine->GetUVLoop();
|
|
CHECK_POINTER(uvLoop);
|
|
|
|
auto work = new (std::nothrow) uv_work_t;
|
|
if (work == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null work");
|
|
return;
|
|
}
|
|
|
|
auto cb = new (std::nothrow) JsNativeReferenceDeleterObject();
|
|
if (cb == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null cb");
|
|
delete work;
|
|
work = nullptr;
|
|
return;
|
|
}
|
|
|
|
if (uniqueNativeRef != nullptr) {
|
|
cb->uniqueNativeRef_ = std::move(uniqueNativeRef);
|
|
}
|
|
if (sharedNativeRef != nullptr) {
|
|
cb->sharedNativeRef_ = std::move(sharedNativeRef);
|
|
}
|
|
work->data = reinterpret_cast<void*>(cb);
|
|
int ret = uv_queue_work(uvLoop, work, [](uv_work_t *work) {},
|
|
[](uv_work_t *work, int status) {
|
|
if (work != nullptr) {
|
|
if (work->data != nullptr) {
|
|
delete reinterpret_cast<JsNativeReferenceDeleterObject*>(work->data);
|
|
work->data = nullptr;
|
|
}
|
|
delete work;
|
|
work = nullptr;
|
|
}
|
|
});
|
|
if (ret != 0) {
|
|
delete reinterpret_cast<JsNativeReferenceDeleterObject*>(work->data);
|
|
work->data = nullptr;
|
|
delete work;
|
|
work = nullptr;
|
|
}
|
|
}
|
|
|
|
void JsRuntime::InitTimerModule()
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->InitTimerModule();
|
|
}
|
|
|
|
void JsRuntime::InitWorkerModule(const Options& options)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
std::shared_ptr<JsEnv::WorkerInfo> workerInfo = std::make_shared<JsEnv::WorkerInfo>();
|
|
workerInfo->codePath = panda::panda_file::StringPacProtect(options.codePath);
|
|
workerInfo->isDebugVersion = options.isDebugVersion;
|
|
workerInfo->isBundle = options.isBundle;
|
|
workerInfo->packagePathStr = options.packagePathStr;
|
|
workerInfo->assetBasePathStr = options.assetBasePathStr;
|
|
workerInfo->hapPath = panda::panda_file::StringPacProtect(options.hapPath);
|
|
workerInfo->isStageModel = panda::panda_file::BoolPacProtect(options.isStageModel);
|
|
workerInfo->moduleName = options.moduleName;
|
|
workerInfo->apiTargetVersion = panda::panda_file::DataProtect(static_cast<uintptr_t>(options.apiTargetVersion));
|
|
if (options.isJsFramework) {
|
|
SetJsFramework();
|
|
}
|
|
jsEnv_->InitWorkerModule(workerInfo);
|
|
}
|
|
|
|
void JsRuntime::SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> moduleCheckerDelegate) const
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->SetModuleLoadChecker(moduleCheckerDelegate);
|
|
}
|
|
|
|
void JsRuntime::ReInitJsEnvImpl(const Options& options)
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->ReInitJsEnvImpl(std::make_unique<OHOSJsEnvironmentImpl>(options.eventRunner));
|
|
}
|
|
|
|
void JsRuntime::SetRequestAotCallback()
|
|
{
|
|
HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
|
|
CHECK_POINTER(jsEnv_);
|
|
auto callback = [](const std::string& bundleName, const std::string& moduleName, int32_t triggerMode) -> int32_t {
|
|
auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
|
|
if (systemAbilityMgr == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null SaMgr");
|
|
return ERR_INVALID_VALUE;
|
|
}
|
|
|
|
auto remoteObj = systemAbilityMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
|
|
if (remoteObj == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null remoteObject");
|
|
return ERR_INVALID_VALUE;
|
|
}
|
|
|
|
auto bundleMgr = iface_cast<AppExecFwk::IBundleMgr>(remoteObj);
|
|
if (bundleMgr == nullptr) {
|
|
TAG_LOGE(AAFwkTag::JSRUNTIME, "null bms");
|
|
return ERR_INVALID_VALUE;
|
|
}
|
|
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME,
|
|
"Reset compile status, bundleName: %{public}s, moduleName: %{public}s, triggerMode: %{public}d",
|
|
bundleName.c_str(), moduleName.c_str(), triggerMode);
|
|
return bundleMgr->ResetAOTCompileStatus(bundleName, moduleName, triggerMode);
|
|
};
|
|
|
|
jsEnv_->SetRequestAotCallback(callback);
|
|
}
|
|
|
|
void JsRuntime::SetDeviceDisconnectCallback(const std::function<bool()> &cb)
|
|
{
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
|
|
CHECK_POINTER(jsEnv_);
|
|
jsEnv_->SetDeviceDisconnectCallback(cb);
|
|
}
|
|
|
|
void JsRuntime::SetStopPreloadSoCallback(const std::function<void()> &callback)
|
|
{
|
|
auto vm = GetEcmaVm();
|
|
panda::JSNApi::SetStopPreLoadSoCallback(vm, callback);
|
|
}
|
|
|
|
std::string JsRuntime::GetSystemKitPath()
|
|
{
|
|
char buf[MAX_PATH_LEN] = { 0 };
|
|
char *configPath = GetOneCfgFile(CONFIG_PATH.c_str(), buf, MAX_PATH_LEN);
|
|
if (configPath == nullptr || configPath[0] == '\0' || strlen(configPath) > MAX_PATH_LEN) {
|
|
return SYSTEM_KITS_CONFIG_PATH;
|
|
}
|
|
return configPath;
|
|
}
|
|
|
|
std::vector<panda::HmsMap> JsRuntime::GetSystemKitsMap(uint32_t version)
|
|
{
|
|
std::vector<panda::HmsMap> systemKitsMap;
|
|
nlohmann::json jsonBuf;
|
|
std::string configPath = GetSystemKitPath();
|
|
if (configPath == "" || access(configPath.c_str(), F_OK) != 0) {
|
|
return systemKitsMap;
|
|
}
|
|
|
|
std::fstream in;
|
|
char errBuf[256];
|
|
errBuf[0] = '\0';
|
|
in.open(configPath, std::ios_base::in);
|
|
if (!in.is_open()) {
|
|
strerror_r(errno, errBuf, sizeof(errBuf));
|
|
return systemKitsMap;
|
|
}
|
|
|
|
in.seekg(0, std::ios::end);
|
|
int64_t size = in.tellg();
|
|
if (size <= 0) {
|
|
in.close();
|
|
return systemKitsMap;
|
|
}
|
|
|
|
in.seekg(0, std::ios::beg);
|
|
jsonBuf = nlohmann::json::parse(in, nullptr, false);
|
|
in.close();
|
|
if (jsonBuf.is_discarded()) {
|
|
return systemKitsMap;
|
|
}
|
|
|
|
if (!jsonBuf.contains(SYSTEM_KITS)) {
|
|
return systemKitsMap;
|
|
}
|
|
for (auto &item : jsonBuf.at(SYSTEM_KITS).items()) {
|
|
nlohmann::json& jsonObject = item.value();
|
|
if (!jsonObject.contains(NAMESPACE) || !jsonObject.at(NAMESPACE).is_string() ||
|
|
!jsonObject.contains(TARGET_OHM) || !jsonObject.at(TARGET_OHM).is_string() ||
|
|
!jsonObject.contains(SINCE_VERSION) || !jsonObject.at(SINCE_VERSION).is_number()) {
|
|
continue;
|
|
}
|
|
uint32_t sinceVersion = jsonObject.at(SINCE_VERSION).get<uint32_t>();
|
|
panda::HmsMap hmsMap = {
|
|
.originalPath = jsonObject.at(NAMESPACE).get<std::string>(),
|
|
.targetPath = jsonObject.at(TARGET_OHM).get<std::string>(),
|
|
.sinceVersion = sinceVersion
|
|
};
|
|
systemKitsMap.emplace_back(hmsMap);
|
|
}
|
|
TAG_LOGD(AAFwkTag::JSRUNTIME, "The size of the map is %{public}zu", systemKitsMap.size());
|
|
return systemKitsMap;
|
|
}
|
|
|
|
void JsRuntime::SetPkgContextInfoJson(std::string moduleName, std::string hapPath, std::string packageName)
|
|
{
|
|
auto iterator = pkgContextInfoJsonStringMap_.find(moduleName);
|
|
if (iterator == pkgContextInfoJsonStringMap_.end()) {
|
|
pkgContextInfoJsonStringMap_[moduleName] = hapPath;
|
|
packageNameList_[moduleName] = packageName;
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm,);
|
|
std::unordered_map<std::string, std::pair<std::unique_ptr<uint8_t[]>, size_t>> pkgInfoMap;
|
|
JsRuntimeLite::GetInstance().GetPkgContextInfoListMap(
|
|
pkgContextInfoJsonStringMap_, pkgInfoMap);
|
|
panda::JSNApi::SetPkgContextInfoList(vm, pkgInfoMap);
|
|
panda::JSNApi::SetPkgNameList(vm, packageNameList_);
|
|
}
|
|
}
|
|
|
|
void JsRuntime::UpdatePkgContextInfoJson(const std::string& moduleName, const std::string& hapPath,
|
|
const std::string& packageName)
|
|
{
|
|
std::map<std::string, std::string> pkgContextInfoJsonStringMap;
|
|
pkgContextInfoJsonStringMap[moduleName] = hapPath;
|
|
std::map<std::string, std::string> packageNameList;
|
|
packageNameList[moduleName] = packageName;
|
|
auto vm = GetEcmaVm();
|
|
CHECK_POINTER_AND_RETURN(vm,);
|
|
std::unordered_map<std::string, std::pair<std::unique_ptr<uint8_t[]>, size_t>> pkgInfoMap;
|
|
JsRuntimeLite::GetInstance().GetPkgContextInfoListMap(pkgContextInfoJsonStringMap, pkgInfoMap);
|
|
panda::JSNApi::UpdatePkgContextInfoList(vm, pkgInfoMap);
|
|
panda::JSNApi::UpdatePkgNameList(vm, packageNameList);
|
|
}
|
|
|
|
void JsRuntime::SetDebugOption(const DebugOption debugOption)
|
|
{
|
|
debugOption_ = debugOption;
|
|
}
|
|
|
|
void JsRuntime::StartLocalDebugMode(bool isDebugFromLocal)
|
|
{
|
|
debugOption_.isDebugFromLocal = isDebugFromLocal;
|
|
StartDebugMode(debugOption_);
|
|
}
|
|
} // namespace AbilityRuntime
|
|
} // namespace OHOS
|