From b56b4b4070aa7c674fa48b4ea0a2149ad97c47c7 Mon Sep 17 00:00:00 2001 From: zhangzezhong Date: Sun, 8 Jun 2025 18:02:29 +0800 Subject: [PATCH] add ani appmanager on AppStateObserver Signed-off-by: zhangzezhong --- frameworks/ets/ani/ani_common/BUILD.gn | 2 + .../ets/ani/ani_common/include/ani_task.h | 35 ++ .../ets/ani/ani_common/src/ani_task.cpp | 51 ++ frameworks/ets/ani/app_manager/BUILD.gn | 1 + .../include/ets_app_state_observer.h | 68 +++ .../include/sts_app_manager_utils.h | 10 +- .../src/ets_app_state_observer.cpp | 441 ++++++++++++++++++ .../ani/app_manager/src/sts_app_manager.cpp | 193 ++++++-- frameworks/ets/ets/BUILD.gn | 17 + .../application/ApplicationStateObserver.ets | 54 +++ 10 files changed, 823 insertions(+), 49 deletions(-) create mode 100644 frameworks/ets/ani/ani_common/include/ani_task.h create mode 100644 frameworks/ets/ani/ani_common/src/ani_task.cpp create mode 100644 frameworks/ets/ani/app_manager/include/ets_app_state_observer.h create mode 100644 frameworks/ets/ani/app_manager/src/ets_app_state_observer.cpp create mode 100644 frameworks/ets/ets/application/ApplicationStateObserver.ets diff --git a/frameworks/ets/ani/ani_common/BUILD.gn b/frameworks/ets/ani/ani_common/BUILD.gn index 2bf78ab797a..373794c805e 100644 --- a/frameworks/ets/ani/ani_common/BUILD.gn +++ b/frameworks/ets/ani/ani_common/BUILD.gn @@ -44,6 +44,7 @@ ohos_shared_library("ani_common") { "src/ani_common_start_options.cpp", "src/ani_common_util.cpp", "src/ani_common_want.cpp", + "src/ani_task.cpp", ] cflags = [] @@ -64,6 +65,7 @@ ohos_shared_library("ani_common") { "ability_base:base", "ability_base:want", "c_utils:utils", + "eventhandler:libeventhandler", "hilog:libhilog", "image_framework:image_ani", "json:nlohmann_json_static", diff --git a/frameworks/ets/ani/ani_common/include/ani_task.h b/frameworks/ets/ani/ani_common/include/ani_task.h new file mode 100644 index 00000000000..ad2d7249ca8 --- /dev/null +++ b/frameworks/ets/ani/ani_common/include/ani_task.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_ETS_TASK_H +#define OHOS_ABILITY_RUNTIME_ETS_TASK_H + +#include "ability_business_error.h" +#include "ani.h" +#include "event_handler.h" + +namespace OHOS { +namespace AbilityRuntime { + +class AniTask { +public: + static ani_status AniSendEvent(const std::function task); + +private: + static std::shared_ptr mainHandler_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_TASK_H diff --git a/frameworks/ets/ani/ani_common/src/ani_task.cpp b/frameworks/ets/ani/ani_common/src/ani_task.cpp new file mode 100644 index 00000000000..0af19994a8a --- /dev/null +++ b/frameworks/ets/ani/ani_common/src/ani_task.cpp @@ -0,0 +1,51 @@ +/* + * 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_task.h" + +#include +#include + +#include "hilog_tag_wrapper.h" + +namespace OHOS { +namespace AbilityRuntime { +std::shared_ptr AniTask::mainHandler_ = nullptr; + +ani_status AniTask::AniSendEvent(const std::function task) +{ + TAG_LOGD(AAFwkTag::JSNAPI, "AniSendEvent"); + if (task == nullptr) { + TAG_LOGD(AAFwkTag::JSNAPI, "null task"); + return ani_status::ANI_INVALID_ARGS; + } + + if (!mainHandler_) { + std::shared_ptr runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); + if (!runner) { + TAG_LOGD(AAFwkTag::JSNAPI, "null EventRunner"); + return ani_status::ANI_NOT_FOUND; + } + mainHandler_ = std::make_shared(runner); + } + if (mainHandler_ == nullptr) { + TAG_LOGD(AAFwkTag::JSNAPI, "null mainHandler"); + return ani_status::ANI_NOT_FOUND; + } + mainHandler_->PostTask(std::move(task)); + return ani_status::ANI_OK; +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/app_manager/BUILD.gn b/frameworks/ets/ani/app_manager/BUILD.gn index 0e46637799e..fdaa1cbfbb3 100644 --- a/frameworks/ets/ani/app_manager/BUILD.gn +++ b/frameworks/ets/ani/app_manager/BUILD.gn @@ -41,6 +41,7 @@ ohos_shared_library("ability_app_manager_ani_kit") { sources = [ "./src/sts_app_manager.cpp", "./src/sts_app_manager_utils.cpp", + "./src/ets_app_state_observer.cpp", ] cflags = [] diff --git a/frameworks/ets/ani/app_manager/include/ets_app_state_observer.h b/frameworks/ets/ani/app_manager/include/ets_app_state_observer.h new file mode 100644 index 00000000000..d6025b33c46 --- /dev/null +++ b/frameworks/ets/ani/app_manager/include/ets_app_state_observer.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef OHOS_ABILITY_RUNTIME_ETS_APP_STATE_OBSERVER_H +#define OHOS_ABILITY_RUNTIME_ETS_APP_STATE_OBSERVER_H + +#include "ani_common_util.h" +#include "application_state_observer_stub.h" +#include "event_handler.h" +#include "sts_runtime.h" + +namespace OHOS { +namespace AbilityRuntime { +using OHOS::AppExecFwk::ApplicationStateObserverStub; +using OHOS::AppExecFwk::AppStateData; +using OHOS::AppExecFwk::AbilityStateData; +using OHOS::AppExecFwk::ProcessData; +class EtsAppStateObserver : public ApplicationStateObserverStub { +public: + explicit EtsAppStateObserver(ani_vm *etsVm); + ~EtsAppStateObserver() override; + void OnForegroundApplicationChanged(const AppStateData &appStateData) override; + void OnAbilityStateChanged(const AbilityStateData &abilityStateData) override; + void OnExtensionStateChanged(const AbilityStateData &abilityStateData) override; + void OnProcessCreated(const ProcessData &processData) override; + void OnProcessStateChanged(const ProcessData &processData) override; + void OnProcessDied(const ProcessData &processData) override; + void HandleOnForegroundApplicationChanged(const AppStateData &appStateData); + void HandleOnAbilityStateChanged(const AbilityStateData &abilityStateData); + void HandleOnExtensionStateChanged(const AbilityStateData &abilityStateData); + void HandleOnProcessCreated(const ProcessData &processData); + void HandleOnProcessStateChanged(const ProcessData &processData); + void HandleOnProcessDied(const ProcessData &processData); + void CallEtsFunction(ani_env* env, ani_object EtsObserverObject, + const char *methodName, const char *signature, ...); + void AddEtsObserverObject(ani_env *env, const int32_t observerId, ani_object EtsObserverObject); + bool RemoveEtsObserverObject(const int32_t observerId); + bool FindObserverByObserverId(const int32_t observerId); + size_t GetEtsObserverMapSize(); + void SetValid(const bool valid); + void OnAppStarted(const AppStateData &appStateData) override; + void OnAppStopped(const AppStateData &appStateData) override; + void HandleOnAppStarted(const AppStateData &appStateData); + void HandleOnAppStopped(const AppStateData &appStateData); + ani_env *AttachCurrentThread(); + void DetachCurrentThread(); + +private: + ani_vm *etsVm_; + volatile bool valid_ = true; + bool isAttachThread_ = false; + std::map etsObserverObjectMap_; +}; +} // namespace AbilityRuntime +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_ETS_APP_STATE_OBSERVER_H \ No newline at end of file diff --git a/frameworks/ets/ani/app_manager/include/sts_app_manager_utils.h b/frameworks/ets/ani/app_manager/include/sts_app_manager_utils.h index a3af678cbdd..f0e25b166a5 100644 --- a/frameworks/ets/ani/app_manager/include/sts_app_manager_utils.h +++ b/frameworks/ets/ani/app_manager/include/sts_app_manager_utils.h @@ -15,13 +15,15 @@ #ifndef OHOS_ABILITY_RUNTIME_STS_APP_MANAGER_UTILS_H #define OHOS_ABILITY_RUNTIME_STS_APP_MANAGER_UTILS_H -#include "sts_runtime.h" #include -#include "running_process_info.h" + +#include "ability_state_data.h" #include "app_state_data.h" -#include "running_multi_info.h" -#include "process_data.h" #include "keep_alive_info.h" +#include "process_data.h" +#include "running_multi_info.h" +#include "running_process_info.h" +#include "sts_runtime.h" namespace OHOS { namespace AppManagerSts { diff --git a/frameworks/ets/ani/app_manager/src/ets_app_state_observer.cpp b/frameworks/ets/ani/app_manager/src/ets_app_state_observer.cpp new file mode 100644 index 00000000000..bf60df1a0d7 --- /dev/null +++ b/frameworks/ets/ani/app_manager/src/ets_app_state_observer.cpp @@ -0,0 +1,441 @@ +/* + * 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 "ets_app_state_observer.h" + +#include "ani_common_ability_state_data.h" +#include "ani_common_util.h" +#include "ani_common_want.h" +#include "ani_task.h" +#include "hilog_tag_wrapper.h" +#include "sts_app_manager_utils.h" + +namespace OHOS { +namespace AbilityRuntime { +namespace { +constexpr const char *SIGNATURE_APP_STATE_DATA = "Lapplication/AppStateData/AppStateData;:V"; +constexpr const char *SIGNATURE_ABILITY_STATE_DATA = "Lapplication/AbilityStateData/AbilityStateData;:V"; +constexpr const char *SIGNATURE_PROCESS_DATA = "Lapplication/ProcessData/ProcessData;:V"; +constexpr const char *CLASS_NAME_APPLIACTION_STATE_OBSERVER = + "Lapplication/ApplicationStateObserver/ApplicationStateObserverImpl;"; +} + +EtsAppStateObserver::EtsAppStateObserver(ani_vm *etsVm) : etsVm_(etsVm) {} + +EtsAppStateObserver::~EtsAppStateObserver() +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + for (auto it = etsObserverObjectMap_.begin(); it != etsObserverObjectMap_.end();) { + env->GlobalReference_Delete(it->second); + it++; + } + DetachCurrentThread(); +}; + +void EtsAppStateObserver::OnForegroundApplicationChanged(const AppStateData &appStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "OnForegroundApplicationChanged bundleName:%{public}s,uid:%{public}d, state:%{public}d", + appStateData.bundleName.c_str(), appStateData.uid, appStateData.state); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "invalid appmgr"); + return; + } + auto task = [appStateData, this]() { + HandleOnForegroundApplicationChanged(appStateData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnForegroundApplicationChanged(const AppStateData &appStateData) +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto appStateDataObj = AppManagerSts::WrapAppStateData(env, appStateData); + if (appStateDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null appStateDataObj"); + DetachCurrentThread(); + return; + } + CallEtsFunction(env, item.second, "onForegroundApplicationChanged", SIGNATURE_APP_STATE_DATA, appStateDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnAbilityStateChanged(const AbilityStateData &abilityStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "OnAbilityStateChanged"); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appMgr may has cancelled storage"); + return; + } + auto task = [abilityStateData, this] () { + HandleOnAbilityStateChanged(abilityStateData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnAbilityStateChanged(const AbilityStateData &abilityStateData) +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto abilityStateDataObj = OHOS::AppExecFwk::WrapAbilityStateData(env, abilityStateData); + if (abilityStateDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null abilityStateDataObj"); + DetachCurrentThread(); + } + CallEtsFunction(env, item.second, "onAbilityStateChanged", SIGNATURE_ABILITY_STATE_DATA, abilityStateDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnExtensionStateChanged(const AbilityStateData &abilityStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "called"); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appMgr may destroyed"); + return; + } + auto task = [abilityStateData, this]() { + HandleOnExtensionStateChanged(abilityStateData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnExtensionStateChanged(const AbilityStateData &abilityStateData) +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto abilityStateDataObj = OHOS::AppExecFwk::WrapAbilityStateData(env, abilityStateData); + if (abilityStateDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null abilityStateDataObj"); + DetachCurrentThread(); + } + CallEtsFunction(env, item.second, "onAbilityStateChanged", SIGNATURE_ABILITY_STATE_DATA, abilityStateDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnProcessCreated(const ProcessData &processData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "OnProcessCreated"); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appmgr may has cancelled storage"); + return; + } + auto task = [processData, this]() { + HandleOnProcessCreated(processData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnProcessCreated(const ProcessData &processData) +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto processDataObj = AppManagerSts::WrapProcessData(env, processData); + if (processDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null processDataObj"); + DetachCurrentThread(); + return; + } + CallEtsFunction(env, item.second, "onProcessCreated", SIGNATURE_PROCESS_DATA, processDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnProcessStateChanged(const ProcessData &processData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "called"); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appMgr may destroyed"); + return; + } + auto task = [processData, this]() { + HandleOnProcessStateChanged(processData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnProcessStateChanged(const ProcessData &processData) +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto processDataObj = AppManagerSts::WrapProcessData(env, processData); + if (processDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null processDataObj"); + DetachCurrentThread(); + return; + } + CallEtsFunction(env, item.second, "onProcessStateChanged", SIGNATURE_PROCESS_DATA, processDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnProcessDied(const ProcessData &processData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "called"); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appmgr may destroyed"); + return; + } + auto task = [processData, this]() { + HandleOnProcessDied(processData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnProcessDied(const ProcessData &processData) +{ + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto processDataObj = AppManagerSts::WrapProcessData(env, processData); + if (processDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null processDataObj"); + DetachCurrentThread(); + return; + } + CallEtsFunction(env, item.second, "onProcessDied", SIGNATURE_PROCESS_DATA, processDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnAppStarted(const AppStateData &appStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "bundleName:%{public}s, uid:%{public}d, state:%{public}d", + appStateData.bundleName.c_str(), appStateData.uid, appStateData.state); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appMgr may destroyed"); + return; + } + auto task = [appStateData, this]() { + HandleOnAppStarted(appStateData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnAppStarted(const AppStateData &appStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "bundleName:%{public}s, uid:%{public}d, state:%{public}d", + appStateData.bundleName.c_str(), appStateData.uid, appStateData.state); + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto appStateDataObj = AppManagerSts::WrapAppStateData(env, appStateData); + if (appStateDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null appStateDataObj"); + DetachCurrentThread(); + return; + } + CallEtsFunction(env, item.second, "onAppStarted", SIGNATURE_APP_STATE_DATA, appStateDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::OnAppStopped(const AppStateData &appStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "bundleName:%{public}s, uid:%{public}d, state:%{public}d", + appStateData.bundleName.c_str(), appStateData.uid, appStateData.state); + if (!valid_) { + TAG_LOGE(AAFwkTag::APPMGR, "appMgr may destroyed"); + return; + } + auto task = [appStateData, this]() { + HandleOnAppStopped(appStateData); + }; + if (AniTask::AniSendEvent(task) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to aniSendEvent"); + } +} + +void EtsAppStateObserver::HandleOnAppStopped(const AppStateData &appStateData) +{ + TAG_LOGD(AAFwkTag::APPMGR, "bundleName:%{public}s, uid:%{public}d, state:%{public}d", + appStateData.bundleName.c_str(), appStateData.uid, appStateData.state); + ani_env *env = AttachCurrentThread(); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "GetEnv failed"); + return; + } + auto tmpMap = etsObserverObjectMap_; + for (auto &item : tmpMap) { + auto appStateDataObj = AppManagerSts::WrapAppStateData(env, appStateData); + if (appStateDataObj == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null appStateDataObj"); + DetachCurrentThread(); + return; + } + CallEtsFunction(env, item.second, "onAppStopped", SIGNATURE_APP_STATE_DATA, appStateDataObj); + } + DetachCurrentThread(); +} + +void EtsAppStateObserver::CallEtsFunction( + ani_env *env, ani_object EtsObserverObject, const char *methodName, const char *signature, ...) +{ + TAG_LOGD(AAFwkTag::APPMGR, "call method:%{public}s", methodName); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null env"); + return; + } + ani_class cls = nullptr; + ani_method method = nullptr; + ani_status status = ANI_OK; + status = env->FindClass(CLASS_NAME_APPLIACTION_STATE_OBSERVER, &cls); + if (status != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to find ApplicationStateObserver, status: %{public}d", status); + return; + } + if (cls == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null cls"); + return; + } + if ((status = env->Class_FindMethod(cls, methodName, signature, &method)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to find method, status: %{public}d", status); + return; + } + if (method == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null method"); + return; + } + env->ResetError(); + va_list args; + va_start(args, signature); + if ((status = env->Object_CallMethod_Void_V(EtsObserverObject, method, args)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to call %{public}s method,status: %{public}d", methodName, status); + return; + } + va_end(args); + return; +} + +void EtsAppStateObserver::AddEtsObserverObject(ani_env *env, const int32_t observerId, ani_object EtsObserverObject) +{ + TAG_LOGD(AAFwkTag::APPMGR, "AddEtsObserverObject"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null env"); + return; + } + ani_ref global = nullptr; + ani_status status = ANI_ERROR; + if ((status = env->GlobalReference_Create(EtsObserverObject, &global)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "status: %{public}d", status); + return; + } + if (global == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null EtsObserverObject ref"); + return; + } + etsObserverObjectMap_.emplace(observerId, reinterpret_cast(global)); +} + +bool EtsAppStateObserver::RemoveEtsObserverObject(const int32_t observerId) +{ + TAG_LOGD(AAFwkTag::APPMGR, "RemoveEtsObserverObject"); + return (etsObserverObjectMap_.erase(observerId) == 1); +} + +bool EtsAppStateObserver::FindObserverByObserverId(const int32_t observerId) +{ + return etsObserverObjectMap_.find(observerId) != etsObserverObjectMap_.end(); +} + +size_t EtsAppStateObserver::GetEtsObserverMapSize() +{ + return etsObserverObjectMap_.size(); +} + +void EtsAppStateObserver::SetValid(const bool valid) +{ + valid_ = valid; +} + +ani_env *EtsAppStateObserver::AttachCurrentThread() +{ + ani_env *env = nullptr; + ani_status status = ANI_ERROR; + if ((status = etsVm_->GetEnv(ANI_VERSION_1, &env)) == ANI_OK) { + return env; + } + ani_option interopEnabled { "--interop=disable", nullptr }; + ani_options aniArgs { 1, &interopEnabled }; + if ((status = etsVm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "status: %{public}d", status); + return nullptr; + } + isAttachThread_ = true; + return env; +} + +void EtsAppStateObserver::DetachCurrentThread() +{ + if (isAttachThread_) { + etsVm_->DetachCurrentThread(); + isAttachThread_ = false; + } +} +} // namespace AbilityRuntime +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/ets/ani/app_manager/src/sts_app_manager.cpp b/frameworks/ets/ani/app_manager/src/sts_app_manager.cpp index 367468e2f88..3dfd98fa703 100644 --- a/frameworks/ets/ani/app_manager/src/sts_app_manager.cpp +++ b/frameworks/ets/ani/app_manager/src/sts_app_manager.cpp @@ -14,6 +14,7 @@ */ #include "sts_app_manager.h" +#include "ets_app_state_observer.h" #include "hilog_tag_wrapper.h" #include "ability_manager_client.h" #include "ability_manager_interface.h" @@ -37,17 +38,22 @@ namespace OHOS { namespace AppManagerSts { +constexpr const char* ON_OFF_TYPE = "applicationState"; + constexpr int32_t ERR_FAILURE = -1; -static const char* ON_SIGNATURE_FIRST - = "Lstd/core/String;Lapplication/ApplicationStateObserver/ApplicationStateObserver;Lescompat/Array;:D"; -static const char* ON_SIGNATURE_SECOND - = "Lstd/core/String;Lapplication/ApplicationStateObserver/ApplicationStateObserver;:D"; +static const char *APPLICATION_STATE_WITH_BUNDLELIST_ON_SIGNATURE = + "Lstd/core/String;Lapplication/ApplicationStateObserver/ApplicationStateObserver;Lescompat/Array;:D"; + +static const char *APPLICATION_STATE_ON_SIGNATURE = + "Lstd/core/String;Lapplication/ApplicationStateObserver/ApplicationStateObserver;:D"; +static const char *APPLICATION_STATE_OFF_SIGNATURE = "Lstd/core/String;DLutils/AbilityUtils/AsyncCallbackWrapper;:V"; -static const char* OFF_SIGNATURE_FIRST - = "Lstd/core/String;DLutils/AbilityUtils/AsyncCallbackWrapper;:V"; class StsAppManager final { +private: + static int32_t serialNumber_; + static sptr appStateObserver_; public: static OHOS::sptr GetAppManagerInstance() { @@ -329,50 +335,144 @@ public: GetRunningProcessInfoByBundleNameAndUserId(env, stsBundleName, static_cast(userId), callback); } -static ani_double OnOnApplicationStateInner(ani_env *env, ani_string type, - ani_object observer, ani_object stsBundleNameList) -{ - TAG_LOGD(AAFwkTag::APPMGR, "OnOnApplicationStateInner called"); - if (env == nullptr) { - TAG_LOGE(AAFwkTag::APPMGR, "env null ptr"); - return ANI_ERROR; - } - std::string strType; - if (!OHOS::AppExecFwk::GetStdString(env, type, strType)) { - TAG_LOGE(AAFwkTag::APPMGR, "env null ptr"); - AbilityRuntime::ThrowStsErrorByNativeErr(env, - static_cast(AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM)); - return ANI_ERROR; - } - auto appManager = GetAppManagerInstance(); - if (appManager == nullptr) { - TAG_LOGE(AAFwkTag::APPMGR, "null appManager"); - AbilityRuntime::ThrowStsErrorByNativeErr(env, - static_cast(AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER)); - return ANI_ERROR; - } - - std::vector bundleNameList; - if (stsBundleNameList != nullptr) { - UnWrapArrayString(env, stsBundleNameList, bundleNameList); + static int32_t GetObserverId() + { + int32_t observerId = serialNumber_; + if (serialNumber_ < INT32_MAX) { + serialNumber_++; + } else { + serialNumber_ = 0; + } + return observerId; + } + + static bool CheckOnOnApplicationStateInnerParam(ani_env *env, ani_string type, ani_object observer, + ani_object stsBundleNameList, std::vector &bundleNameList) + { + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "env null ptr"); + return false; + } + std::string strType; + if (!OHOS::AppExecFwk::GetStdString(env, type, strType) || strType != ON_OFF_TYPE) { + TAG_LOGE(AAFwkTag::APPMGR, "GetStdString failed"); + AbilityRuntime::ThrowStsInvalidParamError( + env, "Parse param type failed, must be a string, value must be applicationState."); + return false; + } + ani_boolean isUndefined = false; + ani_status status = ANI_OK; + if ((status = env->Reference_IsUndefined(stsBundleNameList, &isUndefined)) != ANI_OK) { + TAG_LOGE(AAFwkTag::APPMGR, "Failed to check undefined status : %{public}d", status); + AbilityRuntime::ThrowStsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return false; + } + if (!isUndefined && !UnWrapArrayString(env, stsBundleNameList, bundleNameList)) { + TAG_LOGE(AAFwkTag::APPMGR, "GetStdString failed"); + AbilityRuntime::ThrowStsError(env, AbilityRuntime::AbilityErrorCode::ERROR_CODE_INVALID_PARAM); + return false; + } + return true; } - return ANI_OK; -} - static ani_double OnOnApplicationStateFirst(ani_env *env, ani_string type, + static ani_double OnOnApplicationStateInner(ani_env *env, ani_string type, ani_object observer, + ani_object stsBundleNameList) + { + TAG_LOGD(AAFwkTag::APPMGR, "OnOnApplicationStateInner called"); + std::vector bundleNameList; + if (!CheckOnOnApplicationStateInnerParam(env, type, observer, stsBundleNameList, bundleNameList)) { + return ANI_ERROR; + } + auto appManager = GetAppManagerInstance(); + if (appManager == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null appManager"); + AbilityRuntime::ThrowStsError(env, + static_cast(AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER)); + return ANI_ERROR; + } + ani_vm *aniVM = nullptr; + if (env->GetVM(&aniVM) != ANI_OK) { + TAG_LOGE(AAFwkTag::UI_EXT, "get aniVM failed"); + AbilityRuntime::ThrowStsError(env, + static_cast(AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER)); + return ANI_ERROR; + } + if (appStateObserver_ == nullptr) { + appStateObserver_ = new (std::nothrow) AbilityRuntime::EtsAppStateObserver(aniVM); + } + int32_t ret = appManager->RegisterApplicationStateObserver(appStateObserver_, bundleNameList); + TAG_LOGD(AAFwkTag::APPMGR, "err:%{public}d", ret); + if (ret == ERR_OK) { + int32_t observerId = GetObserverId(); + appStateObserver_->AddEtsObserverObject(env, observerId, observer); + TAG_LOGD(AAFwkTag::APPMGR, "OnOnApplicationStateInner end"); + return observerId; + } else { + AbilityRuntime::ThrowStsErrorByNativeErr(env, static_cast(ret)); + return ANI_ERROR; + } + } + + static ani_double OnOnApplicationStateWithBundleList(ani_env *env, ani_string type, ani_object observer, ani_object stsBundleNameList) { return OnOnApplicationStateInner(env, type, observer, stsBundleNameList); } - static ani_double OnOnApplicationStateSecond(ani_env *env, ani_string type, ani_object observer) + static ani_double OnOnApplicationState(ani_env *env, ani_string type, ani_object observer) { - return OnOnApplicationStateInner(env, type, observer, nullptr); + ani_ref undefined = nullptr; + env->GetUndefined(&undefined); + return OnOnApplicationStateInner(env, type, observer, static_cast(undefined)); + } + + static void OnOff(ani_env *env, ani_string type, ani_double stsObserverId, ani_object callback) + { + TAG_LOGD(AAFwkTag::APPMGR, "OnOff called"); + if (env == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "env null ptr"); + return; + } + std::string strType; + if (!OHOS::AppExecFwk::GetStdString(env, type, strType) || strType != ON_OFF_TYPE) { + TAG_LOGE(AAFwkTag::APPMGR, "GetStdString failed"); + AbilityRuntime::ThrowStsInvalidParamError( + env, "Parse param type failed, must be a string, value must be applicationState."); + return; + } + TAG_LOGD(AAFwkTag::APPMGR, "observerId:%{public}f", stsObserverId); + int64_t observerId = static_cast(stsObserverId); + + sptr appMgr = GetAppManagerInstance(); + if (appMgr == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "appManager null ptr"); + AppExecFwk::AsyncCallback(env, callback, + OHOS::AbilityRuntime::CreateStsError(env, + static_cast(AbilityRuntime::AbilityErrorCode::ERROR_CODE_INNER)), + nullptr); + return; + } + if (appStateObserver_ == nullptr) { + TAG_LOGE(AAFwkTag::APPMGR, "null observer"); + AbilityRuntime::ThrowStsInvalidParamError(env, "observer is nullptr, please register first."); + return; + } + if (!appStateObserver_->FindObserverByObserverId(observerId)) { + TAG_LOGE(AAFwkTag::APPMGR, "not find observer:%{public}d", static_cast(observerId)); + AbilityRuntime::ThrowStsInvalidParamError(env, "not find observerId."); + return; + } + int32_t ret = appMgr->UnregisterApplicationStateObserver(appStateObserver_); + if (ret == 0 && appStateObserver_->RemoveEtsObserverObject(observerId)) { + TAG_LOGD(AAFwkTag::APPMGR, "OnOff success"); + } else { + TAG_LOGE(AAFwkTag::APPMGR, "OnOff err:%{public}d", ret); + } + AppExecFwk::AsyncCallback(env, callback, + OHOS::AbilityRuntime::CreateStsErrorByNativeErr(env, static_cast(ret)), nullptr); + TAG_LOGD(AAFwkTag::APPMGR, "OnOff end"); } -static void OnOff(ani_env *env, [[maybe_unused]]ani_class aniClss) -{ -} static void GetAppMemorySize(ani_env *env, ani_object callback) { TAG_LOGD(AAFwkTag::APPMGR, "GetAppMemorySize called"); @@ -900,6 +1000,9 @@ static void OnOff(ani_env *env, [[maybe_unused]]ani_class aniClss) } }; //StsAppManager +int32_t StsAppManager::serialNumber_ = 0; +sptr StsAppManager::appStateObserver_ = nullptr; + void StsAppManagerRegistryInit(ani_env *env) { TAG_LOGD(AAFwkTag::APPMGR, "StsAppManagerRegistryInit call"); @@ -926,11 +1029,11 @@ void StsAppManagerRegistryInit(ani_env *env) reinterpret_cast(StsAppManager::GetRunningProcessInfoByBundleName)}, ani_native_function {"nativeGetRunningProcessInfoByBundleNameAndUserId", nullptr, reinterpret_cast(StsAppManager::GetRunningProcessInfoByBundleNameAndUserId)}, - ani_native_function {"nativeOn", ON_SIGNATURE_FIRST, - reinterpret_cast(StsAppManager::OnOnApplicationStateFirst)}, - ani_native_function {"nativeOn", ON_SIGNATURE_SECOND, - reinterpret_cast(StsAppManager::OnOnApplicationStateSecond)}, - ani_native_function {"nativeOff", OFF_SIGNATURE_FIRST, + ani_native_function {"nativeOn", APPLICATION_STATE_WITH_BUNDLELIST_ON_SIGNATURE, + reinterpret_cast(StsAppManager::OnOnApplicationStateWithBundleList)}, + ani_native_function {"nativeOn", APPLICATION_STATE_ON_SIGNATURE, + reinterpret_cast(StsAppManager::OnOnApplicationState)}, + ani_native_function {"nativeOff", APPLICATION_STATE_OFF_SIGNATURE, reinterpret_cast(StsAppManager::OnOff)}, ani_native_function {"nativeGetAppMemorySize", nullptr, reinterpret_cast(StsAppManager::GetAppMemorySize)}, diff --git a/frameworks/ets/ets/BUILD.gn b/frameworks/ets/ets/BUILD.gn index 7d3c48df8f5..57a3a4ee0d3 100644 --- a/frameworks/ets/ets/BUILD.gn +++ b/frameworks/ets/ets/BUILD.gn @@ -1065,6 +1065,22 @@ ohos_prebuilt_etc("ability_runtime_connect_options_abc_etc") { deps = [ ":ability_runtime_connect_options_abc" ] } +generate_static_abc("application_state_observer_abc") { + base_url = "./" + files = [ "./application/ApplicationStateObserver.ets" ] + + is_boot_abc = "True" + device_dst_file = "/system/framework/application_state_observer_abc.abc" +} + +ohos_prebuilt_etc("application_state_observer_abc_etc") { + source = "$target_out_dir/application_state_observer_abc.abc" + module_install_dir = "framework" + subsystem_name = "ability" + part_name = "ability_runtime" + deps = [ ":application_state_observer_abc" ] +} + group("ets_packages") { deps = [ ":ability_ability_application_abc_etc", @@ -1125,6 +1141,7 @@ group("ets_packages") { ":ability_runtime_want_agent_abc_etc", ":ability_runtime_want_agent_info_abc_etc", ":ability_runtime_want_constant_abc_etc", + ":application_state_observer_abc_etc", ":service_extension_ability_abc_etc", ":ui_extension_ability_ani_etc", ":uri_permission_manager_abc_etc", diff --git a/frameworks/ets/ets/application/ApplicationStateObserver.ets b/frameworks/ets/ets/application/ApplicationStateObserver.ets new file mode 100644 index 00000000000..3b59dc77f22 --- /dev/null +++ b/frameworks/ets/ets/application/ApplicationStateObserver.ets @@ -0,0 +1,54 @@ +/* + * 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 AppStateData from 'application.AppStateData'; +import AbilityStateData from 'application.AbilityStateData'; +import processData from 'application.ProcessData'; + +interface ApplicationStateObserver { + + onForegroundApplicationChanged(appStateData: AppStateData): void; + + onAbilityStateChanged(abilityStateData: AbilityStateData): void; + + onProcessCreated(processData: ProcessData): void; + + onProcessDied(processData: ProcessData): void; + + onProcessStateChanged(processData: ProcessData): void; + + onAppStarted(appStateData: AppStateData): void; + + onAppStopped(appStateData: AppStateData): void; +} + +class ApplicationStateObserverImpl implements ApplicationStateObserver { + onForegroundApplicationChanged(appStateData: AppStateData): void {} + + onAbilityStateChanged(abilityStateData: AbilityStateData): void {} + + onProcessCreated(processData: ProcessData): void {} + + onProcessDied(processData: ProcessData): void {} + + onProcessStateChanged(processData: ProcessData): void {} + + onAppStarted(appStateData: AppStateData): void {} + + onAppStopped(appStateData: AppStateData): void {} +} + +export type ProcessData = processData; + +export default ApplicationStateObserver; \ No newline at end of file -- Gitee