diff --git a/ets_environment/frameworks/ets_environment/BUILD.gn b/ets_environment/frameworks/ets_environment/BUILD.gn index 32cc779fb52836d7c206faa339cb8411df87faf7..1c67d800122633704574c09186d75869cc286013 100644 --- a/ets_environment/frameworks/ets_environment/BUILD.gn +++ b/ets_environment/frameworks/ets_environment/BUILD.gn @@ -46,6 +46,10 @@ ohos_shared_library("ets_environment") { defines = [] + deps = [ + "${ability_runtime_innerkits_path}/connect_server_manager:connect_server_manager", + ] + external_deps = [ "c_utils:utils", "eventhandler:libeventhandler", diff --git a/ets_environment/frameworks/ets_environment/src/ets_environment.cpp b/ets_environment/frameworks/ets_environment/src/ets_environment.cpp index 120420f132fda03aa3cb481fce210a1859cb04ff..ee3ed919acd6833ef612b93802d65553d9b8e29e 100644 --- a/ets_environment/frameworks/ets_environment/src/ets_environment.cpp +++ b/ets_environment/frameworks/ets_environment/src/ets_environment.cpp @@ -15,6 +15,7 @@ #include "ets_environment.h" +#include #include #include #include @@ -27,12 +28,14 @@ #include "static_core/plugins/ets/runtime/ets_namespace_manager.h" #include "ets_ani_expo.h" +#include "static_core/runtime/tooling/inspector/debugger_arkapi.h" #ifdef LIKELY #undef LIKELY #endif #ifdef UNLIKELY #undef UNLIKELY #endif +#include "connect_server_manager.h" #include "dynamic_loader.h" #include "elf_factory.h" #include "event_handler.h" @@ -51,9 +54,11 @@ const char ETS_ANI_GET_CREATEDVMS[] = "ANI_GetCreatedVMs"; const char ETS_LIB_PATH[] = "libets_interop_js_napi.z.so"; const char BOOT_PATH[] = "/system/framework/bootpath.json"; const char BACKTRACE[] = "=====================Backtrace========================"; +static const std::string DEBUGGER = "@Debugger"; using CreateVMETSRuntimeType = ani_status (*)(const ani_options *options, uint32_t version, ani_vm **result); using ANIGetCreatedVMsType = ani_status (*)(ani_vm **vms_buffer, ani_size vms_buffer_length, ani_size *result); +using DebuggerPostTask = std::function &&)>; const char ETS_SDK_NSNAME[] = "ets_sdk"; const char ETS_SYS_NSNAME[] = "ets_system"; @@ -215,7 +220,7 @@ void ETSEnvironment::InitETSSysNS(const std::string &path) dlns_inherit(&ns, &ndk, "allow_all_shared_libs"); } -bool ETSEnvironment::Initialize() +bool ETSEnvironment::Initialize(const std::shared_ptr eventRunner, bool isStartWithDebug) { TAG_LOGD(AAFwkTag::ETSRUNTIME, "Initialize called"); if (!LoadRuntimeApis()) { @@ -228,6 +233,8 @@ bool ETSEnvironment::Initialize() return false; } + InitEventHandler(eventRunner); + std::vector options; // Create boot-panda-files options std::string bootString = "--ext:--boot-panda-files=" + bootfiles; @@ -235,6 +242,16 @@ bool ETSEnvironment::Initialize() options.push_back(ani_option { "--ext:--compiler-enable-jit=false", nullptr }); options.push_back(ani_option { "--ext:--log-level=info", nullptr }); options.push_back(ani_option { "--ext:taskpool-support-interop=true", nullptr }); + std::string interpreerMode = "--ext:--interpreter-type=cpp"; + std::string debugEnalbeMode = "--ext:--debugger-enable=true"; + std::string debugLibraryPathMode = "--ext:--debugger-library-path=/system/lib64/libarkinspector.so"; + std::string breadonstartMode = "--ext:--debugger-break-on-start"; + if (isStartWithDebug) { + options.push_back(ani_option { interpreerMode.data(), nullptr }); + options.push_back(ani_option { debugEnalbeMode.data(), nullptr }); + options.push_back(ani_option { debugLibraryPathMode.data(), nullptr }); + options.push_back(ani_option { breadonstartMode.data(), nullptr }); + } ani_options optionsPtr = { options.size(), options.data() }; ani_status status = ANI_ERROR; if ((status = lazyApis_.ANI_CreateVM(&optionsPtr, ANI_VERSION_1, &vmEntry_.aniVm_)) != ANI_OK) { @@ -545,8 +562,8 @@ ETSEnvFuncs *ETSEnvironment::RegisterFuncs() .InitETSSysNS = [](const std::string &path) { ETSEnvironment::InitETSSysNS(path); }, - .Initialize = []() { - return ETSEnvironment::GetInstance()->Initialize(); + .Initialize = [](const std::shared_ptr eventRunner, bool isStartWithDebug) { + return ETSEnvironment::GetInstance()->Initialize(eventRunner, isStartWithDebug); }, .RegisterUncaughtExceptionHandler = [](const ETSUncaughtExceptionInfo &exceptionInfo) { ETSEnvironment::GetInstance()->RegisterUncaughtExceptionHandler(exceptionInfo); @@ -580,10 +597,119 @@ ETSEnvFuncs *ETSEnvironment::RegisterFuncs() .SetExtensionApiCheckCallback = []( std::function &cb) { ark::ets::EtsNamespaceManager::SetExtensionApiCheckCallback(cb); + }, + .RemoveInstance = [](uint32_t instanceId) { + return ETSEnvironment::GetInstance()->RemoveInstance(instanceId); + }, + .StopDebugMode = [](void *jsVm) { + return ETSEnvironment::GetInstance()->StopDebugMode(jsVm); + }, + .StartDebuggerForSocketPair = [](std::string &option, int32_t socketFd) { + return ETSEnvironment::GetInstance()->StartDebuggerForSocketPair(option, socketFd); + }, + .NotifyDebugMode = [](uint32_t tid, uint32_t instanceId, bool isStartWithDebug, void *jsVm) { + return ETSEnvironment::GetInstance()->NotifyDebugMode(tid, instanceId, isStartWithDebug, jsVm); + }, + .BroadcastAndConnect = [](const std::string& bundleName, int socketFd) { + return ETSEnvironment::GetInstance()->BroadcastAndConnect(bundleName, socketFd); } }; return &funcs; } + +void ETSEnvironment::NotifyDebugMode(uint32_t tid, uint32_t instanceId, bool isStartWithDebug, void *jsVm) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Start"); + AbilityRuntime::ConnectServerManager::Get().StoreInstanceMessage(getproctid(), instanceId, "Debugger"); + auto task = GetDebuggerPostTask(); + ark::ArkDebugNativeAPI::NotifyDebugMode(tid, instanceId, isStartWithDebug, jsVm, task); +} + +void ETSEnvironment::RemoveInstance(uint32_t instanceId) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Start"); + AbilityRuntime::ConnectServerManager::Get().RemoveInstance(instanceId); +} + +void ETSEnvironment::StopDebugMode(void *jsVm) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Start"); + if (debugMode_) { + ark::ArkDebugNativeAPI::StopDebugger(jsVm); + } +} + +void ETSEnvironment::StartDebuggerForSocketPair(std::string &option, int32_t socketFd) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Start"); + int32_t identifierId = ParseHdcRegisterOption(option); + if (identifierId == -1) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "Abnormal parsing of tid results"); + return; + } + debugMode_ = ark::ArkDebugNativeAPI::StartDebuggerForSocketPair(ParseHdcRegisterOption(option), socketFd); +} + +DebuggerPostTask ETSEnvironment::GetDebuggerPostTask() +{ + auto debuggerPostTask = [weak = weak_from_this()](std::function&& task) { + auto etsEnv = weak.lock(); + if (etsEnv == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "StsEnv is invalid"); + return; + } + etsEnv->PostTask(task, "ETSEnvironment:GetDebuggerPostTask", 0); + }; + return debuggerPostTask; +} + +int32_t ETSEnvironment::ParseHdcRegisterOption(std::string& option) +{ + int32_t pid = -1; + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Start"); + std::size_t pos = option.find_first_of(":"); + if (pos == std::string::npos) { + return pid; + } + std::string idStr = option.substr(pos + 1); + pos = idStr.find(DEBUGGER); + if (pos == std::string::npos) { + return pid; + } + idStr = idStr.substr(0, pos); + pos = idStr.find("@"); + if (pos != std::string::npos) { + idStr = idStr.substr(pos + 1); + } + auto res = std::from_chars(idStr.c_str(), idStr.c_str() + idStr.size(), pid); + if (res.ec != std::errc()) { + TAG_LOGE(AAFwkTag::AA_TOOL, "pid from_chars (%{public}s) failed", idStr.c_str()); + } + return pid; +} + +void ETSEnvironment::InitEventHandler(const std::shared_ptr &eventRunner) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "InitEventHandler called"); + if (eventRunner != nullptr) { + eventHandler_ = std::make_shared(eventRunner); + } +} + +void ETSEnvironment::PostTask(const std::function &task, const std::string &name, int64_t delayTime) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "PostTask called"); + if (eventHandler_ != nullptr) { + eventHandler_->PostTask(task, name, delayTime); + } +} + +void ETSEnvironment::BroadcastAndConnect(const std::string& bundleName, int socketFd) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "BroadcastAndConnect called"); + AbilityRuntime::ConnectServerManager::Get().SendInstanceMessageAll(nullptr); + AbilityRuntime::ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false); +} } // namespace EtsEnv } // namespace OHOS diff --git a/ets_environment/interfaces/inner_api/ets_environment.h b/ets_environment/interfaces/inner_api/ets_environment.h index d8652e9011f1b567c3c1028fb4f753bf16e57f3d..06780e1571e5989e2067407604e5dc310661f65d 100644 --- a/ets_environment/interfaces/inner_api/ets_environment.h +++ b/ets_environment/interfaces/inner_api/ets_environment.h @@ -41,6 +41,8 @@ struct ETSRuntimeAPI { ani_status (*ANI_CreateVM)(const ani_options *options, uint32_t version, ani_vm **result); }; +using DebuggerPostTask = std::function&&)>; + class ETSEnvironment final : public std::enable_shared_from_this { public: ETSEnvironment() {}; @@ -50,7 +52,7 @@ public: static void InitETSSysNS(const std::string &path); static ETSEnvFuncs *RegisterFuncs(); - bool Initialize(); + bool Initialize(const std::shared_ptr eventRunner, bool isDebug); void RegisterUncaughtExceptionHandler(const ETSUncaughtExceptionInfo &handle); ani_env *GetAniEnv(); bool HandleUncaughtError(); @@ -61,6 +63,15 @@ public: bool PostFork(void *napiEnv, const std::string &aotPath); bool PreloadSystemClass(const char *className); + void RemoveInstance(uint32_t instanceId); + void StopDebugMode(void *jsVm); + void StartDebuggerForSocketPair(std::string &option, int32_t socketFd); + void NotifyDebugMode(uint32_t tid, uint32_t instanceId, bool isStartWithDebug, void *jsVm); + void PostTask(const std::function &task, const std::string &name, int64_t delayTime); + void BroadcastAndConnect(const std::string& bundleName, int socketFd); + + DebuggerPostTask GetDebuggerPostTask(); + struct VMEntry { ani_vm *aniVm_; ani_env *aniEnv_; @@ -80,9 +91,13 @@ private: EtsEnv::ETSErrorObject GetETSErrorObject(); std::string GetErrorProperty(ani_error aniError, const char *property); bool LoadAbcLinker(ani_env *env, const std::string &modulePath, ani_class &abcCls, ani_object &abcObj); + void InitEventHandler(const std::shared_ptr &eventRunner); + int32_t ParseHdcRegisterOption(std::string& option); static ETSRuntimeAPI lazyApis_; VMEntry vmEntry_; ETSUncaughtExceptionInfo uncaughtExceptionInfo_; + std::shared_ptr eventHandler_; + bool debugMode_ = false; }; } // namespace EtsEnv } // namespace OHOS diff --git a/ets_environment/interfaces/inner_api/ets_interface.h b/ets_environment/interfaces/inner_api/ets_interface.h index 59845e267956ad94e2149b2ebaefa6fa66acfd47..124563013b299e06c2e9bf88f13df33c438c852c 100644 --- a/ets_environment/interfaces/inner_api/ets_interface.h +++ b/ets_environment/interfaces/inner_api/ets_interface.h @@ -23,12 +23,18 @@ #include "ets_native_reference.h" #include "napi/native_api.h" +namespace OHOS { +namespace AppExecFwk { + class EventRunner; +} +} + extern "C" { struct ETSEnvFuncs { void (*InitETSSDKNS)(const std::string &path) = nullptr; void (*InitETSSysNS)(const std::string &path) = nullptr; - bool (*Initialize)() = nullptr; + bool (*Initialize)(const std::shared_ptr eventRunner, bool isDebug) = nullptr; void (*RegisterUncaughtExceptionHandler)( const OHOS::EtsEnv::ETSUncaughtExceptionInfo &uncaughtExceptionInfo) = nullptr; ani_env *(*GetAniEnv)() = nullptr; @@ -43,6 +49,12 @@ struct ETSEnvFuncs { void (*PreloadSystemClass)(const char *className) = nullptr; void (*SetExtensionApiCheckCallback)( std::function &cb) = nullptr; + void (*RemoveInstance)(uint32_t instanceId) = nullptr; + void (*StopDebugMode)(void *jsVm) = nullptr; + void (*StartDebuggerForSocketPair)(std::string &option, int32_t socketFd) = nullptr; + void (*NotifyDebugMode)(uint32_t tid, uint32_t instanceId, bool isStartWithDebug, + void *jsVm) = nullptr; + void (*BroadcastAndConnect)(const std::string& bundleName, int socketFd) = nullptr; }; } #endif // OHOS_ABILITY_RUNTIME_ETS_INTERFACE_H diff --git a/ets_environment/test/unittest/ets_environment_test/BUILD.gn b/ets_environment/test/unittest/ets_environment_test/BUILD.gn index 470009ccaa22072b432f557ee6ce7da4f944ae88..5adacb33093ce8771571d1d929081ce0cc7cebd1 100644 --- a/ets_environment/test/unittest/ets_environment_test/BUILD.gn +++ b/ets_environment/test/unittest/ets_environment_test/BUILD.gn @@ -32,7 +32,9 @@ template("ets_environment_test_template") { configs = [] - deps = [] + deps = [ + "${ability_runtime_innerkits_path}/connect_server_manager:connect_server_manager", + ] external_deps = [ "ability_runtime:runtime", diff --git a/ets_environment/test/unittest/ets_environment_test/ets_environment_test.cpp b/ets_environment/test/unittest/ets_environment_test/ets_environment_test.cpp index 855a6072b4facb1bea4ddaa0ceb978b24f856919..146d2d4001339b06433aeb34731a74a4905ec32d 100644 --- a/ets_environment/test/unittest/ets_environment_test/ets_environment_test.cpp +++ b/ets_environment/test/unittest/ets_environment_test/ets_environment_test.cpp @@ -251,7 +251,7 @@ HWTEST_F(EtsEnvironmentTest, Initialize_0100, TestSize.Level0) { auto etsEnv = std::make_shared(); ASSERT_NE(etsEnv, nullptr); - bool result = etsEnv->Initialize(); + bool result = etsEnv->Initialize(nullptr, false); EXPECT_FALSE(result); } @@ -353,5 +353,44 @@ HWTEST_F(EtsEnvironmentTest, PreloadSystemClass_0100, TestSize.Level0) auto result = etsEnv->PreloadSystemClass(className.c_str()); EXPECT_FALSE(result); } + +/** + * @tc.name: GetDebuggerPostTask_0100 + * @tc.desc: Sts environment GetDebuggerPostTask. + * @tc.type: FUNC + */ +HWTEST_F(EtsEnvironmentTest, GetDebuggerPostTask_0100, TestSize.Level0) +{ + auto etsEnv = std::make_shared(); + ASSERT_NE(etsEnv, nullptr); + auto task = etsEnv->GetDebuggerPostTask(); + ASSERT_NE(task, nullptr); +} + +/** + * @tc.name: ParseHdcRegisterOption_0100 + * @tc.desc: Js environment ParseHdcRegisterOption. + * @tc.type: FUNC + */ +HWTEST_F(EtsEnvironmentTest, ParseHdcRegisterOption_0100, TestSize.Level2) +{ + auto etsEnv = std::make_shared(); + ASSERT_NE(etsEnv, nullptr); + std::string option1 = ""; + int result1 = etsEnv->ParseHdcRegisterOption(option1); + ASSERT_EQ(result1, -1); + std::string option2 = "@"; + int result2 = etsEnv->ParseHdcRegisterOption(option2); + ASSERT_EQ(result2, -1); + std::string option3 = ":"; + int result3 = etsEnv->ParseHdcRegisterOption(option3); + ASSERT_EQ(result3, -1); + std::string option4 = "ark:123@Debugger"; + int result4 = etsEnv->ParseHdcRegisterOption(option4); + ASSERT_EQ(result4, 123); + std::string option5 = "ark:123@456@Debugger"; + int result5 = etsEnv->ParseHdcRegisterOption(option5); + ASSERT_EQ(result5, 456); +} } // namespace StsEnv } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/appkit/app/main_thread.cpp b/frameworks/native/appkit/app/main_thread.cpp index 939413f8036037c0985d3ed2e57c65947686bd88..ef55b3fa940f6247adf14835275f2462aec4828d 100644 --- a/frameworks/native/appkit/app/main_thread.cpp +++ b/frameworks/native/appkit/app/main_thread.cpp @@ -1678,6 +1678,7 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con options.uid = bundleInfo.applicationInfo.uid; options.apiTargetVersion = appInfo.apiTargetVersion; options.pkgContextInfoJsonStringMap = pkgContextInfoJsonStringMap; + options.isStartWithDebug = appLaunchData.GetDebugApp(); options.allowArkTsLargeHeap = appInfo.allowArkTsLargeHeap; options.versionCode = appInfo.versionCode; #ifdef CJ_FRONTEND @@ -1759,6 +1760,7 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con ResHelper::ReportLoadAbcCompletedInfoToRss(uid, currentPid, bundleName); }); AbilityRuntime::Runtime::DebugOption debugOption; + debugOption.arkTSMode = appInfo.arkTSMode; debugOption.isStartWithDebug = appLaunchData.GetDebugApp(); debugOption.processName = processName; debugOption.isDebugApp = appInfo.debug; @@ -1767,6 +1769,7 @@ void MainThread::HandleLaunchApplication(const AppLaunchData &appLaunchData, con debugOption.isDebugFromLocal = appLaunchData.GetDebugFromLocal(); debugOption.perfCmd = perfCmd; debugOption.isDeveloperMode = isDeveloperMode_; + debugOption.bundleName = appInfo.bundleName; runtime->SetDebugOption(debugOption); if (perfCmd.find(PERFCMD_PROFILE) != std::string::npos || perfCmd.find(PERFCMD_DUMPHEAP) != std::string::npos) { diff --git a/frameworks/native/runtime/cj_runtime.cpp b/frameworks/native/runtime/cj_runtime.cpp index 5dae7bf282576d25cfe92569967e2608af9db938..0d98ceb19278f08132f6ae9328277de8843a4c64 100644 --- a/frameworks/native/runtime/cj_runtime.cpp +++ b/frameworks/native/runtime/cj_runtime.cpp @@ -31,11 +31,6 @@ using namespace OHOS::AbilityRuntime; - -namespace { -const std::string DEBUGGER = "@Debugger"; -} // namespace - #define LIB_NAME "libcj_environment.z.so" #define GET_ENV_INS_NAME "OHOS_GetCJEnvInstance" diff --git a/frameworks/native/runtime/ets_runtime.cpp b/frameworks/native/runtime/ets_runtime.cpp index 1e3997c4e9daed6b942f7bf5976f3ea0ad433b35..bd546e081bbcfbfed060cf4c7ab8d231c6a77820 100644 --- a/frameworks/native/runtime/ets_runtime.cpp +++ b/frameworks/native/runtime/ets_runtime.cpp @@ -23,12 +23,16 @@ #include #include +#include "bundle_constants.h" #include "constants.h" #include "ets_interface.h" #include "file_path_utils.h" #include "hilog_tag_wrapper.h" +#include "hdc_register.h" #include "hybrid_js_module_reader.h" #include "nocopyable.h" +#include "parameters.h" +#include "static_core/plugins/ets/runtime/ets_namespace_manager.h" #ifdef SUPPORT_SCREEN #include "ace_forward_compatibility.h" @@ -308,6 +312,7 @@ ETSRuntime::~ETSRuntime() { TAG_LOGD(AAFwkTag::ETSRUNTIME, "~ETSRuntime called"); Deinitialize(); + StopDebugMode(); } void ETSRuntime::Deinitialize() @@ -324,7 +329,7 @@ bool ETSRuntime::CreateEtsEnv(const Options &options) return false; } - if (!g_etsEnvFuncs->Initialize()) { + if (!g_etsEnvFuncs->Initialize(options.eventRunner, options.isStartWithDebug)) { TAG_LOGE(AAFwkTag::ETSRUNTIME, "Initialize failed"); return false; } @@ -489,5 +494,110 @@ bool ETSRuntime::PreloadSystemClass(const char *className) g_etsEnvFuncs->PreloadSystemClass(className); return true; } + +void ETSRuntime::StartDebugMode(const DebugOption dOption) +{ + TAG_LOGD(AAFwkTag::ETSRUNTIME, "localDebug %{public}d", dOption.isDebugFromLocal); + if (!dOption.isDebugFromLocal && !dOption.isDeveloperMode) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "developer Mode false"); + return; + } + // Set instance id to tid after the first instance. + instanceId_ = static_cast(getproctid()); + + bool isStartWithDebug = dOption.isStartWithDebug; + bool isDebugApp = dOption.isDebugApp; + std::string appProvisionType = dOption.appProvisionType; + TAG_LOGD(AAFwkTag::ETSRUNTIME, "Ark VM is starting debug mode [%{public}s]", isStartWithDebug ? "break" : "normal"); + const std::string bundleName = dOption.bundleName; + uint32_t instanceId = instanceId_; + std::string inputProcessName = bundleName != dOption.processName ? dOption.processName : ""; + HdcRegister::DebugRegisterMode debugMode = HdcRegister::DebugRegisterMode::HDC_DEBUG_REG; + HdcRegister::Get().StartHdcRegister(bundleName, inputProcessName, isDebugApp, debugMode, + [bundleName, isStartWithDebug, instanceId, isDebugApp, appProvisionType] + (int socketFd, std::string option) { + TAG_LOGI(AAFwkTag::ETSRUNTIME, "HdcRegister msg, fd= %{public}d, option= %{public}s", socketFd, option.c_str()); + // system is debuggable when const.secure is false and const.debuggable is true + bool isSystemDebuggable = system::GetBoolParameter("const.secure", true) == false && + system::GetBoolParameter("const.debuggable", false) == true; + // Don't start any server if (system not in debuggable mode) and app is release version + // Starting ConnectServer in release app on debuggable system is only for debug mode, not for profiling mode. + if ((!isSystemDebuggable) && appProvisionType == AppExecFwk::Constants::APP_PROVISION_TYPE_RELEASE) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "not support release app"); + return; + } + if (option.find(DEBUGGER) == std::string::npos) { + // if has old connect server, stop it + if (g_etsEnvFuncs == nullptr || g_etsEnvFuncs->BroadcastAndConnect == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs or BroadcastAndConnect"); + return; + } + g_etsEnvFuncs->BroadcastAndConnect(bundleName, socketFd); + } else { + if (appProvisionType == AppExecFwk::Constants::APP_PROVISION_TYPE_RELEASE) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "not support release app"); + return; + } + if (g_etsEnvFuncs == nullptr || g_etsEnvFuncs->StartDebuggerForSocketPair == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs or StartDebuggerForSocketPair"); + return; + } + g_etsEnvFuncs->StartDebuggerForSocketPair(option, socketFd); + } + }); + DebuggerConnectionHandler(isDebugApp, isStartWithDebug); +} + +void ETSRuntime::DebuggerConnectionHandler(bool isDebugApp, bool isStartWithDebug) +{ + auto dTask = nullptr; + if (jsRuntime_ == nullptr) { + TAG_LOGD(AAFwkTag::ETSRUNTIME, "jsRuntime_ is nullptr"); + return; + } + if (g_etsEnvFuncs == nullptr || g_etsEnvFuncs->NotifyDebugMode == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs or NotifyDebugMode"); + return; + } + if (jsRuntime_ == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null js runtime"); + return; + } + auto &jsRuntimePoint = (static_cast(*jsRuntime_)); + auto vm = jsRuntimePoint.GetEcmaVm(); + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null js vm"); + return; + } + g_etsEnvFuncs->NotifyDebugMode(getproctid(), instanceId_, isStartWithDebug, vm); +} + +void ETSRuntime::StopDebugMode() +{ + if (g_etsEnvFuncs == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null g_etsEnvFuncs"); + return; + } + if (g_etsEnvFuncs->RemoveInstance == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null RemoveInstance"); + return; + } + g_etsEnvFuncs->RemoveInstance(instanceId_); + if (g_etsEnvFuncs->StopDebugMode == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null StopDebugMode"); + return; + } + if (jsRuntime_ == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null js runtime"); + return; + } + auto &jsRuntimePoint = (static_cast(*jsRuntime_)); + auto vm = jsRuntimePoint.GetEcmaVm(); + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::ETSRUNTIME, "null js vm"); + return; + } + g_etsEnvFuncs->StopDebugMode(vm); +} } // namespace AbilityRuntime } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/runtime/js_runtime.cpp b/frameworks/native/runtime/js_runtime.cpp index 5084526ede9fbf5bd709ad4b80e2a2bbcee24dd7..f69dd652eb31b91f9f534cd47abc36aec41de8d0 100644 --- a/frameworks/native/runtime/js_runtime.cpp +++ b/frameworks/native/runtime/js_runtime.cpp @@ -85,7 +85,6 @@ 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"; -const std::string DEBUGGER = "@Debugger"; constexpr char MERGE_ABC_PATH[] = "/ets/modules.abc"; constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/"; @@ -164,8 +163,8 @@ void JsRuntime::StartDebugMode(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"); + if (!ShouldSkipDebugMode(dOption)) { + TAG_LOGE(AAFwkTag::JSRUNTIME, "not start debug"); return; } CHECK_POINTER(jsEnv_); @@ -213,10 +212,16 @@ void JsRuntime::StartDebugMode(const DebugOption dOption) TAG_LOGE(AAFwkTag::JSRUNTIME, "not support release app"); return; } + auto callback = [weak, isDebugApp, isStartWithDebug](int32_t tid, const DebuggerPostTask& task) { + panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? isStartWithDebug : false}; + if (weak != nullptr) { + panda::JSNApi::StoreDebugInfo(tid, weak->GetVM(), debugOption, task, isDebugApp); + } + }; 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().SendInstanceMessageAll(callback); ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false); } else { // if has old debugger server, stop it @@ -231,6 +236,19 @@ void JsRuntime::StartDebugMode(const DebugOption dOption) 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_); diff --git a/frameworks/native/runtime/ohos_js_environment_impl.cpp b/frameworks/native/runtime/ohos_js_environment_impl.cpp index 6f77792c827d0a27dbb3adb6887609c4a1f2e805..b6dd34dbb8ca0505236c285f233aa762f9601d10 100644 --- a/frameworks/native/runtime/ohos_js_environment_impl.cpp +++ b/frameworks/native/runtime/ohos_js_environment_impl.cpp @@ -97,9 +97,11 @@ OHOSJsEnvironmentImpl::~OHOSJsEnvironmentImpl() void OHOSJsEnvironmentImpl::PostTask(const std::function& task, const std::string& name, int64_t delayTime) { TAG_LOGD(AAFwkTag::JSRUNTIME, "called"); - if (eventHandler_ != nullptr) { - eventHandler_->PostTask(task, name, delayTime); + if (eventHandler_ == nullptr) { + TAG_LOGE(AAFwkTag::JSRUNTIME, "null eventHandler_"); + return; } + eventHandler_->PostTask(task, name, delayTime); } void OHOSJsEnvironmentImpl::PostSyncTask(const std::function& task, const std::string& name) diff --git a/interfaces/inner_api/connect_server_manager/BUILD.gn b/interfaces/inner_api/connect_server_manager/BUILD.gn index c2c684462c3aa841d1cc7b8b242102147ddd9f05..3f285a6fd25b1ad26c81bf7144635517eb4127d8 100644 --- a/interfaces/inner_api/connect_server_manager/BUILD.gn +++ b/interfaces/inner_api/connect_server_manager/BUILD.gn @@ -53,6 +53,7 @@ ohos_shared_library("connect_server_manager") { external_deps = [ "ets_runtime:libark_jsruntime", "hilog:libhilog", + "runtime_core:libarkruntime", ] configs = [ diff --git a/interfaces/inner_api/connect_server_manager/include/connect_server_manager.h b/interfaces/inner_api/connect_server_manager/include/connect_server_manager.h index 8f1f12a09360d5ca5c2291939279a859155436c8..bdcb2d2d58558a18ee769fcd882a7a8a5060db70 100644 --- a/interfaces/inner_api/connect_server_manager/include/connect_server_manager.h +++ b/interfaces/inner_api/connect_server_manager/include/connect_server_manager.h @@ -52,6 +52,7 @@ public: void SetConnectedCallback(); bool SendInstanceMessage(int32_t tid, int32_t instanceId, const std::string& instanceName); void SendDebuggerInfo(bool needBreakPoint, bool isDebugApp); + void SendInstanceMessageAll(std::function callback); void LoadConnectServerDebuggerSo(); bool SetRecordCallback(const std::function &startRecordFunc, const std::function &stopRecordFunc); diff --git a/interfaces/inner_api/connect_server_manager/src/connect_server_manager.cpp b/interfaces/inner_api/connect_server_manager/src/connect_server_manager.cpp index 73a75f3f6a61e73725f46fa5f69a11725f9d8dad..f9b313200f1e79aa33ba0643b1c7cb4de6ffc3c8 100644 --- a/interfaces/inner_api/connect_server_manager/src/connect_server_manager.cpp +++ b/interfaces/inner_api/connect_server_manager/src/connect_server_manager.cpp @@ -467,4 +467,24 @@ void ConnectServerManager::AddInstanceCallback(const int32_t instanceId) } } } + +void ConnectServerManager::SendInstanceMessageAll(std::function callback) +{ + ConnectServerManager::Get().SetConnectedCallback(); + std::lock_guard lock(mutex_); + for (const auto& instance : instanceMap_) { + auto instanceId = instance.first; + auto instanceName = instance.second.first; + auto tid = instance.second.second; + std::lock_guard lock(g_debuggerMutex); + ConnectServerManager::Get().SendInstanceMessage(tid, instanceId, instanceName); + const auto &debuggerPostTask = g_debuggerInfo[tid].second; + if (!debuggerPostTask) { + continue; + } + if (callback != nullptr) { + callback(tid, debuggerPostTask); + } + } +} } // namespace OHOS::AbilityRuntime \ No newline at end of file diff --git a/interfaces/inner_api/runtime/include/ets_runtime.h b/interfaces/inner_api/runtime/include/ets_runtime.h index d95e652469e6389948a7f9fe94ab3cad0c410572..82c7f67a7261a8de2456a9b6af70ce4adad0c47c 100644 --- a/interfaces/inner_api/runtime/include/ets_runtime.h +++ b/interfaces/inner_api/runtime/include/ets_runtime.h @@ -54,7 +54,7 @@ public: return Language::ETS; } - void StartDebugMode(const DebugOption debugOption) override {} + void StartDebugMode(const DebugOption debugOption) override; void DumpHeapSnapshot(bool isPrivate) override {} void NotifyApplicationState(bool isBackground) override {} bool SuspendVM(uint32_t tid) override { return false; } @@ -93,6 +93,9 @@ public: std::unique_ptr MoveJsRuntime(); static std::unique_ptr PreFork(const Options &options, std::unique_ptr &jsRuntime); bool PreloadSystemClass(const char *className) override; + void DebuggerConnectionHandler(bool isDebugApp, bool isStartWithDebug); + void StopDebugMode(); + uint32_t instanceId_ = 0; private: bool Initialize(const Options &options, std::unique_ptr &jsRuntime); @@ -107,6 +110,7 @@ private: std::string codePath_; std::string moduleName_; std::unique_ptr jsRuntime_ = nullptr; + bool debugMode_ = false; }; } // namespace AbilityRuntime } // namespace OHOS diff --git a/interfaces/inner_api/runtime/include/js_runtime.h b/interfaces/inner_api/runtime/include/js_runtime.h index 4cdf127a7396d0de6becf9e2ecd1ce2aa259aec0..57b5e9e2a2f976578c221d7f4dce603bfcdf525b 100644 --- a/interfaces/inner_api/runtime/include/js_runtime.h +++ b/interfaces/inner_api/runtime/include/js_runtime.h @@ -52,6 +52,14 @@ using UncatchableTask = std::function>; +#ifdef APP_USE_ARM +constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_inspector.z.so"; +#elif defined(APP_USE_X86_64) +constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_inspector.z.so"; +#else +constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_inspector.z.so"; +#endif + namespace AbilityRuntime { class TimerTask; @@ -106,6 +114,7 @@ public: const std::string& hapPath, bool isEsMode, bool useCommonTrunk) override; bool PopPreloadObj(const std::string& key, std::unique_ptr& obj); void StartDebugMode(const DebugOption debugOption) override; + bool ShouldSkipDebugMode(const DebugOption debugOption); void SetDebugOption(const DebugOption debugOption) override; void StartLocalDebugMode(bool isDebugFromLocal) override; void DebuggerConnectionHandler(bool isDebugApp, bool isStartWithDebug); diff --git a/interfaces/inner_api/runtime/include/runtime.h b/interfaces/inner_api/runtime/include/runtime.h index 30cf7b3a5912cec7f2a5409b2f2cb08d214805f9..d39a14c84ab92490a1ce17180be28f8248363c58 100644 --- a/interfaces/inner_api/runtime/include/runtime.h +++ b/interfaces/inner_api/runtime/include/runtime.h @@ -31,6 +31,7 @@ namespace { const std::string CODE_LANGUAGE_ARKTS_1_0 = "dynamic"; const std::string CODE_LANGUAGE_ARKTS_1_2 = "static"; const std::string CODE_LANGUAGE_ARKTS_HYBRID = "hybrid"; +const std::string DEBUGGER = "@Debugger"; } // namespace class Runtime { @@ -74,6 +75,7 @@ public: std::map pkgContextInfoJsonStringMap; std::map packageNameList; std::map aotCompileStatusMap; + bool isStartWithDebug = false; uint32_t versionCode = 0; bool enableWarmStartupSmartGC = false; }; @@ -88,6 +90,7 @@ public: bool isStartWithNative = false; bool isDebugFromLocal = false; bool isDeveloperMode; + std::string arkTSMode = CODE_LANGUAGE_ARKTS_1_2; }; static std::unique_ptr Create(Options &options); diff --git a/test/unittest/runtime_test/BUILD.gn b/test/unittest/runtime_test/BUILD.gn index e4f1504fa7338cfba09c11d13948606e57cbec80..709cca198469e7e10a8adf232458cb9c80a764e0 100644 --- a/test/unittest/runtime_test/BUILD.gn +++ b/test/unittest/runtime_test/BUILD.gn @@ -284,7 +284,9 @@ ohos_unittest("ets_runtime_test") { ] configs = [ "${ability_runtime_services_path}/abilitymgr:abilityms_config" ] - deps = [] + deps = [ + "${ability_runtime_innerkits_path}/connect_server_manager:connect_server_manager", + ] external_deps = [ "ability_runtime:runtime", diff --git a/test/unittest/runtime_test/ets_runtime_test.cpp b/test/unittest/runtime_test/ets_runtime_test.cpp index 6723ed99970288d4f8a4fb1863282ee387f45b00..a58660781fee289a4944cdd09c01898b6e8662f5 100644 --- a/test/unittest/runtime_test/ets_runtime_test.cpp +++ b/test/unittest/runtime_test/ets_runtime_test.cpp @@ -338,5 +338,32 @@ HWTEST_F(EtsRuntimeTest, SetExtensionApiCheckCallback_100, TestSize.Level1) etsRuntime->SetExtensionApiCheckCallback(callback); EXPECT_EQ(etsRuntime->GetJsRuntime(), nullptr); } + +/** + * @tc.name: Create_100 + * @tc.desc: EtsRuntime test for Create Initialize failed. + * @tc.type: FUNC + */ +HWTEST_F(EtsRuntimeTest, StartDebug_100, TestSize.Level1) +{ + options_.lang = Runtime::Language::JS; + options_.preload = true; + options_.isStageModel = false; + std::unique_ptr jsRuntime = JsRuntime::Create(options_); + auto etsRuntime = ETSRuntime::Create(options_, jsRuntime); + EXPECT_EQ(etsRuntime, nullptr); + AbilityRuntime::Runtime::DebugOption debugOption; + debugOption.isDeveloperMode = false; + debugOption.isDebugFromLocal = false; + debugOption.bundleName = "test"; + debugOption.isDebugApp = false; + debugOption.isStartWithDebug = false; + etsRuntime->StartDebugMode(debugOption); + uint32_t instanceId = etsRuntime->instanceId_; + EXPECT_EQ(instanceId, 0); + debugOption.isDeveloperMode = true; + etsRuntime->StartDebugMode(debugOption); + EXPECT_NE(instanceId, 0); +} } // namespace AbilityRuntime } // namespace OHOS \ No newline at end of file