diff --git a/frameworks/ets/ani/BUILD.gn b/frameworks/ets/ani/BUILD.gn index ba011e24b869b764414aceceba6f31d6d85e5f28..20775304f2818bd921380d30f3c8dc7e898b5de9 100644 --- a/frameworks/ets/ani/BUILD.gn +++ b/frameworks/ets/ani/BUILD.gn @@ -30,5 +30,6 @@ group("ani_packages") { "${ability_runtime_path}/frameworks/ets/ani/wantagent:aniwantagent", "${ability_runtime_path}/frameworks/ets/ani/application:application_ani", "${ability_runtime_path}/frameworks/ets/ani/event_hub:event_hub_ani_kit", + "${ability_runtime_path}/frameworks/ets/ani/apprecovery:appRecovery_ani", ] } \ No newline at end of file diff --git a/frameworks/ets/ani/apprecovery/BUILD.gn b/frameworks/ets/ani/apprecovery/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..714169c8c61e61d763ac3267f5ad74fc7b6edec8 --- /dev/null +++ b/frameworks/ets/ani/apprecovery/BUILD.gn @@ -0,0 +1,53 @@ +# Copyright (c) 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. + +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +ohos_shared_library("appRecovery_ani") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + cfi_vcall_icall_only = true + debug = false + } + + include_dirs = [ "./include" ] + + sources = [ "./src/app_recovery_ani.cpp" ] + + deps = [ + "${ability_runtime_innerkits_path}/ability_manager:ability_manager", + "${ability_runtime_innerkits_path}/ability_manager:ability_start_options", + "${ability_runtime_innerkits_path}/app_manager:app_manager", + "${ability_runtime_innerkits_path}/runtime:runtime", + "${ability_runtime_native_path}/ability/native:uiabilitykit_native", + "${ability_runtime_native_path}/appkit:appkit_native", + "${ability_runtime_path}/frameworks/ets/ani/ani_common:ani_common", + ] + + external_deps = [ + "ability_base:base", + "ability_base:want", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "hilog:libhilog", + "ipc:ipc_single", + "runtime_core:ani", + ] + + subsystem_name = "ability" + part_name = "ability_runtime" + output_extension = "so" +} diff --git a/frameworks/ets/ani/apprecovery/src/app_recovery_ani.cpp b/frameworks/ets/ani/apprecovery/src/app_recovery_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc8713be3ae335a51aaba18001b2ca144e4b38fa --- /dev/null +++ b/frameworks/ets/ani/apprecovery/src/app_recovery_ani.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (c) 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 "ani.h" + +#include "app_recovery.h" +#include "hilog_tag_wrapper.h" +#include "js_runtime.h" +#include "js_runtime_utils.h" +#include "ani_common_want.h" +#include "want.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr int RESTART_FLAG_INDEX = 0; // 0:RestartFlag +constexpr int OCCASION_FLAG_INDEX = 1; // 1:SaveOccasionFlag +constexpr int MODE_FLAG_INDEX = 2; // 2:SaveModeFlag +} +using namespace OHOS::AppExecFwk; + +bool IsRefUndefined(ani_env *env, ani_ref ref) +{ + ani_boolean isUndefined = ANI_FALSE; + env->Reference_IsUndefined(ref, &isUndefined); + return isUndefined; +} + +bool IsNull(ani_env *env, ani_ref ref) +{ + ani_boolean isNull = ANI_FALSE; + env->Reference_IsNull(ref, &isNull); + return isNull; +} + +bool CheckParamsValid(const uint16_t params[]) +{ + uint16_t restartFlag = params[0]; + constexpr uint16_t restartMaxVal = 0x0003; + if ((restartFlag < 0 || restartFlag > restartMaxVal) && (restartFlag != RestartFlag::NO_RESTART)) { + TAG_LOGE(AAFwkTag::RECOVERY, "invalid restartFlag: %{public}d", restartFlag); + return false; + } + uint16_t saveFlag = params[1]; + constexpr uint16_t saveMaxVal = 0x0003; + if (saveFlag < SaveOccasionFlag::SAVE_WHEN_ERROR || saveFlag > saveMaxVal) { + TAG_LOGE(AAFwkTag::RECOVERY, "invalid saveOccasionFlag: %{public}d", saveFlag); + return false; + } + uint16_t saveModeFlag = params[2]; + if (saveModeFlag < SaveModeFlag::SAVE_WITH_FILE || saveModeFlag > SaveModeFlag::SAVE_WITH_SHARED_MEMORY) { + TAG_LOGE(AAFwkTag::RECOVERY, "invalid saveModeFlag: %{public}d", saveModeFlag); + return false; + } + return true; +} + +static bool ParseParamToEnum(ani_env *env, ani_enum_item flagObj, uint16_t &flag) +{ + if (IsRefUndefined(env, flagObj)) { + TAG_LOGE(AAFwkTag::RECOVERY, "IsRefUndefined is true"); + return false; + } + ani_int flagValue = 0; + if (ANI_OK != env->EnumItem_GetValue_Int(flagObj, &flagValue)) { + TAG_LOGE(AAFwkTag::RECOVERY, "enum convert to int failed."); + return false; + } + flag = static_cast(flagValue); + return true; +} + +static ani_object EnableAppRecovery(ani_env *env, ani_enum_item restart, ani_enum_item occasion, ani_enum_item modeFlag) +{ + ani_object resultsObj{}; + uint16_t flags[] = { + RestartFlag::ALWAYS_RESTART, + SaveOccasionFlag::SAVE_WHEN_ERROR, + SaveModeFlag::SAVE_WITH_FILE + }; + + if (!ParseParamToEnum(env, restart, flags[RESTART_FLAG_INDEX]) || + !ParseParamToEnum(env, occasion, flags[OCCASION_FLAG_INDEX]) || + !ParseParamToEnum(env, modeFlag, flags[MODE_FLAG_INDEX])) { + TAG_LOGE(AAFwkTag::RECOVERY, "parse params to int failed."); + return resultsObj; + } + if (!CheckParamsValid(flags)) { + return resultsObj; + } + + AppRecovery::GetInstance().EnableAppRecovery(flags[RESTART_FLAG_INDEX], + flags[OCCASION_FLAG_INDEX], + flags[MODE_FLAG_INDEX]); + return resultsObj; +} + +static ani_boolean SaveAppState(ani_env *env) +{ + ani_boolean boolValue = ANI_FALSE; + + uintptr_t ability = 0; + if (AppRecovery::GetInstance().ScheduleSaveAppState(StateReason::DEVELOPER_REQUEST, ability)) { + boolValue = ANI_TRUE; + } + return boolValue; +} + +static ani_boolean SaveAppStateWithParam(ani_env *env, ani_object context) +{ + ani_boolean boolValue = ANI_FALSE; + + uintptr_t ability = 0; + if (!IsNull(env, context) && !IsRefUndefined(env, context)) { + ani_long contextLong{}; + if (ANI_OK != env->Object_GetFieldByName_Long(context, "nativeContext", &contextLong)) { + TAG_LOGE(AAFwkTag::RECOVERY, "get nativeContext failed."); + return boolValue; + } + ability = static_cast(contextLong); + } + if (AppRecovery::GetInstance().ScheduleSaveAppState(StateReason::DEVELOPER_REQUEST, ability)) { + boolValue = ANI_TRUE; + } + return boolValue; +} + +static ani_object RestartApp(ani_env *env) +{ + ani_object resultsObj{}; + AppRecovery::GetInstance().ScheduleRecoverApp(StateReason::DEVELOPER_REQUEST); + return resultsObj; +} + +static ani_object SetRestartWant(ani_env *env, ani_object wantObj) +{ + ani_object resultsObj{}; + if (IsRefUndefined(env, wantObj)) { + TAG_LOGE(AAFwkTag::RECOVERY, "get want param failed."); + return resultsObj; + } + std::shared_ptr want = std::make_shared(); + if (!AppExecFwk::UnwrapWant(env, wantObj, *want)) { + TAG_LOGE(AAFwkTag::RECOVERY, "unwrap want failed."); + return resultsObj; + } + AppRecovery::GetInstance().SetRestartWant(want); + return resultsObj; +} + +static void EtsAppRecoveryInit(ani_env *env) +{ + TAG_LOGD(AAFwkTag::RECOVERY, "EtsAppRecoveryInit Called."); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::RECOVERY, "null env"); + return; + } + ani_status status = ANI_ERROR; + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::RECOVERY, "ResetError failed"); + } + + ani_namespace ns; + status = env->FindNamespace("L@ohos/app/ability/appRecovery/appRecovery;", &ns); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::RECOVERY, "FindNamespace appRecovery failed status: %{public}d", status); + return; + } + + std::array kitFunctions = { + ani_native_function {"enableAppRecovery", nullptr, reinterpret_cast(EnableAppRecovery)}, + ani_native_function {"restartApp", nullptr, reinterpret_cast(RestartApp)}, + ani_native_function {"saveAppState", ":Z", reinterpret_cast(SaveAppState)}, + ani_native_function {"saveAppState", "Lapplication/UIAbilityContext/UIAbilityContext;:Z", + reinterpret_cast(SaveAppStateWithParam)}, + ani_native_function {"setRestartWant", nullptr, reinterpret_cast(SetRestartWant)}, + }; + + status = env->Namespace_BindNativeFunctions(ns, kitFunctions.data(), kitFunctions.size()); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::RECOVERY, "Namespace_BindNativeFunctions failed status: %{public}d", status); + } + + if (env->ResetError() != ANI_OK) { + TAG_LOGE(AAFwkTag::RECOVERY, "ResetError failed"); + } + TAG_LOGD(AAFwkTag::RECOVERY, "EtsAppRecoveryInit end"); +} +} // namespace AbilityRuntime +} // namespace OHOS + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + TAG_LOGD(AAFwkTag::RECOVERY, "ANI_Constructor start."); + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + if (vm == nullptr) { + TAG_LOGE(AAFwkTag::RECOVERY, "null vm"); + return ANI_ERROR; + } + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::RECOVERY, "GetEnv failed status: %{public}d", status); + return ANI_NOT_FOUND; + } + + OHOS::AbilityRuntime::EtsAppRecoveryInit(env); + *result = ANI_VERSION_1; + TAG_LOGD(AAFwkTag::RECOVERY, "ANI_Constructor finish"); + return ANI_OK; +} diff --git a/frameworks/ets/ets/@ohos.app.ability.appRecovery.ets b/frameworks/ets/ets/@ohos.app.ability.appRecovery.ets new file mode 100644 index 0000000000000000000000000000000000000000..62884ddc9b5c969ab2f6bfba07ab5e23fbaaf27f --- /dev/null +++ b/frameworks/ets/ets/@ohos.app.ability.appRecovery.ets @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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. + */ + +import UIAbilityContext from 'application.UIAbilityContext'; +import Want from '@ohos.app.ability.Want'; + +export default namespace appRecovery { + loadLibrary("appRecovery_ani"); + export enum RestartFlag { + ALWAYS_RESTART = 0, + RESTART_WHEN_JS_CRASH = 0x0001, + RESTART_WHEN_APP_FREEZE = 0x0002, + NO_RESTART = 0xFFFF + } + + export enum SaveOccasionFlag { + SAVE_WHEN_ERROR = 0x0001, + SAVE_WHEN_BACKGROUND = 0x0002 + } + + export enum SaveModeFlag { + SAVE_WITH_FILE = 0x0001, + SAVE_WITH_SHARED_MEMORY = 0x0002 + } + + export native function enableAppRecovery(restart?: RestartFlag, saveOccasion?: SaveOccasionFlag, + saveMode?: SaveModeFlag): void; + export native function restartApp(): void; + export native function setRestartWant(want: Want): void; + export native function saveAppState(): boolean; + export native function saveAppState(context?: UIAbilityContext): boolean; +} diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 7d3c48df8f5cbe4f28e0d467be81187604b50536..61f411238c5108907aa16cd9d8df4a16e7ded790 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -1065,6 +1065,21 @@ ohos_prebuilt_etc("ability_runtime_connect_options_abc_etc") { deps = [ ":ability_runtime_connect_options_abc" ] } +generate_static_abc("appRecovery_abc") { + base_url = "./" + files = [ "./@ohos.app.ability.appRecovery.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/appRecovery_abc.abc" +} + +ohos_prebuilt_etc("appRecovery_abc_etc") { + source = "$target_out_dir/appRecovery_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":appRecovery_abc" ] +} + group("ets_packages") { deps = [ ":ability_ability_application_abc_etc", @@ -1130,5 +1145,6 @@ group("ets_packages") { ":uri_permission_manager_abc_etc", ":ability_runtime_OpenLink_Options_abc_etc", ":ability_runtime_AbilityRunningInfo_abc_etc", + ":appRecovery_abc_etc", ] }