diff --git a/interfaces/inner_api/el5filekeymanager/El5FilekeyManagerInterface.idl b/interfaces/inner_api/el5filekeymanager/El5FilekeyManagerInterface.idl index 27070333bd0043488451c5b8ec981d389e1665cb..6467f1369256b7938caa46fc52d78d6ce1a5fb38 100644 --- a/interfaces/inner_api/el5filekeymanager/El5FilekeyManagerInterface.idl +++ b/interfaces/inner_api/el5filekeymanager/El5FilekeyManagerInterface.idl @@ -18,6 +18,7 @@ import data_lock_type; import El5FilekeyCallbackInterface; sequenceable OHOS.Security.AccessToken.UserAppKeyInfo; sequenceable OHOS.Security.AccessToken.AppKeyLoadInfo; +option_stub_hooks on; interface OHOS.Security.AccessToken.El5FilekeyManagerInterface{ void AcquireAccess([in] DataLockType type); diff --git a/services/el5filekeymanager/BUILD.gn b/services/el5filekeymanager/BUILD.gn index 92cafd73cb3f65584c08545280e624f2a8fe2576..c9cc9e9ca32bcbb1747c8ba8776435193e9956fb 100644 --- a/services/el5filekeymanager/BUILD.gn +++ b/services/el5filekeymanager/BUILD.gn @@ -55,6 +55,7 @@ if (is_standard_system && ability_base_enable == true) { sources = [ "src/el5_filekey_manager_service.cpp", "src/el5_filekey_manager_service_ability.cpp", + "src/el5_memory_manager.cpp", ] configs = [] diff --git a/services/el5filekeymanager/include/el5_filekey_manager_service.h b/services/el5filekeymanager/include/el5_filekey_manager_service.h index 2d660a1126410191d070c8a96b70f180e0e83406..0738b4684d0dfa378ff26bee22cbca9da02a063d 100644 --- a/services/el5filekeymanager/include/el5_filekey_manager_service.h +++ b/services/el5filekeymanager/include/el5_filekey_manager_service.h @@ -60,6 +60,8 @@ public: void PostDelayedUnloadTask(uint32_t delayedTime); void CancelDelayedUnloadTask(); int Dump(int fd, const std::vector& args) override; + int32_t CallbackEnter(uint32_t code) override; + int32_t CallbackExit(uint32_t code, int32_t result) override; private: ServiceRunningState serviceRunningState_ = ServiceRunningState::STATE_NOT_START; diff --git a/services/el5filekeymanager/include/el5_filekey_manager_service_ability.h b/services/el5filekeymanager/include/el5_filekey_manager_service_ability.h index 357d62e2bcf6190f69989b643ab352c25e8bd558..09ee599aa47a5d5d53de1686e82d9d128d162a1c 100644 --- a/services/el5filekeymanager/include/el5_filekey_manager_service_ability.h +++ b/services/el5filekeymanager/include/el5_filekey_manager_service_ability.h @@ -40,6 +40,7 @@ public: private: void OnStart(const SystemAbilityOnDemandReason &startReason) final; void OnStop() final; + int32_t OnIdle(const SystemAbilityOnDemandReason &idleReason) final; void OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId) override; DISALLOW_COPY_AND_MOVE(El5FilekeyManagerServiceAbility); diff --git a/services/el5filekeymanager/include/el5_memory_manager.h b/services/el5filekeymanager/include/el5_memory_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..1b4fd487fc9a1a380c1247dcebb38673325c645b --- /dev/null +++ b/services/el5filekeymanager/include/el5_memory_manager.h @@ -0,0 +1,48 @@ +/* + * 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 EL5_MEMORY_MANAGER_H +#define EL5_MEMORY_MANAGER_H + +#include +#include +#include + +namespace OHOS { +namespace Security { +namespace AccessToken { + +class El5MemoryManager { +public: + El5MemoryManager() {}; + virtual ~El5MemoryManager() {}; + + static El5MemoryManager& GetInstance(); + void AddFunctionRuningNum(); + void DecreaseFunctionRuningNum(); + bool IsAllowUnloadService(); + void SetIsDelayedToUnload(bool isUnload); + bool IsDelayedToUnload(); + +private: + bool isDelayedToUnload_ = false; + int32_t callFuncRunningNum_ = 0; + std::mutex callNumberMutex_; + std::mutex isDelayedMutex_; +}; +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif // EL5_MEMORY_MANAGER_H diff --git a/services/el5filekeymanager/sa_profile/8250.json b/services/el5filekeymanager/sa_profile/8250.json index f7341c6c3245644d882b373871f9abe2b66ed392..a92ad3bb6872ef94e599b6f974bbd3bbbc4b0c49 100644 --- a/services/el5filekeymanager/sa_profile/8250.json +++ b/services/el5filekeymanager/sa_profile/8250.json @@ -20,6 +20,12 @@ "name": "usual.event.USER_STOPPED" } ] + }, + "stop-on-demand": { + "param": [{ + "name": "resourceschedule.memmgr.low.memory.prepare", + "value": "true" + }] } } ] diff --git a/services/el5filekeymanager/src/el5_filekey_manager_service.cpp b/services/el5filekeymanager/src/el5_filekey_manager_service.cpp index 450855093a9779fe9036161f2e78f4490b0cb70f..ff1394399ecc32b6e4ac735ac735b7e0395dafbf 100644 --- a/services/el5filekeymanager/src/el5_filekey_manager_service.cpp +++ b/services/el5filekeymanager/src/el5_filekey_manager_service.cpp @@ -22,9 +22,10 @@ #include "common_event_support.h" #endif #include "el5_filekey_manager_error.h" +#include "el5_filekey_manager_log.h" +#include "el5_memory_manager.h" #include "ipc_skeleton.h" #include "iservice_registry.h" -#include "el5_filekey_manager_log.h" #ifdef THEME_SCREENLOCK_MGR_ENABLE #include "screenlock_manager.h" #endif @@ -105,6 +106,20 @@ void El5FilekeyManagerService::UnInit() } } +// CallbackEnter, if "option_stub_hooks on", is called per IPC call at entrance of OnRemoteRequest +int32_t El5FilekeyManagerService::CallbackEnter(uint32_t code) +{ + El5MemoryManager::GetInstance().AddFunctionRuningNum(); + return ERR_OK; +} + +// CallbackExit, if "option_stub_hooks on", is called per IPC call at exit of OnRemoteRequest +int32_t El5FilekeyManagerService::CallbackExit(uint32_t code, int32_t result) +{ + El5MemoryManager::GetInstance().DecreaseFunctionRuningNum(); + return ERR_OK; +} + void El5FilekeyManagerService::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId) { LOG_INFO("SaId %{public}d added", systemAbilityId); @@ -150,6 +165,8 @@ void El5FilekeyManagerService::PostDelayedUnloadTask(uint32_t delayedTime) LOG_ERROR("GetSystemAbilityManager is null."); return; } + + El5MemoryManager::GetInstance().SetIsDelayedToUnload(true); int32_t ret = systemAbilityManager->UnloadSystemAbility(EL5_FILEKEY_MANAGER_SERVICE_ID); if (ret != ERR_OK) { LOG_ERROR("Unload el5_filekey_manager failed."); diff --git a/services/el5filekeymanager/src/el5_filekey_manager_service_ability.cpp b/services/el5filekeymanager/src/el5_filekey_manager_service_ability.cpp index fcd3f65fa398a56ba7656f82a39f5cdaebbcf41f..bd2c05e0543d62a19aec724e545d2651d345bc06 100644 --- a/services/el5filekeymanager/src/el5_filekey_manager_service_ability.cpp +++ b/services/el5filekeymanager/src/el5_filekey_manager_service_ability.cpp @@ -16,6 +16,7 @@ #include "el5_filekey_manager_service_ability.h" #include "el5_filekey_manager_error.h" +#include "el5_memory_manager.h" #include "system_ability_definition.h" namespace OHOS { @@ -23,6 +24,8 @@ namespace Security { namespace AccessToken { namespace { REGISTER_SYSTEM_ABILITY_BY_ID(El5FilekeyManagerServiceAbility, EL5_FILEKEY_MANAGER_SERVICE_ID, false); +constexpr int32_t SA_READY_TO_UNLOAD = 0; +constexpr int32_t SA_REFUSE_TO_UNLOAD = -1; } El5FilekeyManagerServiceAbility::El5FilekeyManagerServiceAbility(int32_t systemAbilityId, bool runOnCreate) @@ -53,6 +56,7 @@ void El5FilekeyManagerServiceAbility::OnStart(const SystemAbilityOnDemandReason LOG_ERROR("Failed to init the El5FilekeyManagerService instance."); return; } + El5MemoryManager::GetInstance().SetIsDelayedToUnload(false); AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID); AddSystemAbilityListener(SCREENLOCK_SERVICE_ID); @@ -79,6 +83,18 @@ void El5FilekeyManagerServiceAbility::OnStart(const SystemAbilityOnDemandReason } } +int32_t El5FilekeyManagerServiceAbility::OnIdle(const SystemAbilityOnDemandReason &idleReason) +{ + if (El5MemoryManager::GetInstance().IsDelayedToUnload() || + El5MemoryManager::GetInstance().IsAllowUnloadService()) { + LOG_INFO("IldeReason name=%{public}s, value=%{public}s.", + idleReason.GetName().c_str(), idleReason.GetValue().c_str()); + return SA_READY_TO_UNLOAD; + } + + return SA_REFUSE_TO_UNLOAD; +} + void El5FilekeyManagerServiceAbility::OnStop() { LOG_INFO("OnStop called."); diff --git a/services/el5filekeymanager/src/el5_memory_manager.cpp b/services/el5filekeymanager/src/el5_memory_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66a2a3bd4792bc051f12e29ecc4210c4d488da75 --- /dev/null +++ b/services/el5filekeymanager/src/el5_memory_manager.cpp @@ -0,0 +1,79 @@ +/* + * 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 "el5_memory_manager.h" + +#include "el5_filekey_manager_error.h" +#include "el5_filekey_manager_log.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +namespace { +constexpr int32_t MAX_RUNNING_NUM = 256; +std::recursive_mutex g_instanceMutex; +} + +El5MemoryManager& El5MemoryManager::GetInstance() +{ + static El5MemoryManager* instance = nullptr; + if (instance == nullptr) { + std::lock_guard lock(g_instanceMutex); + if (instance == nullptr) { + El5MemoryManager* tmp = new (std::nothrow) El5MemoryManager(); + instance = std::move(tmp); + } + } + return *instance; +} + +void El5MemoryManager::AddFunctionRuningNum() +{ + std::lock_guard lock(callNumberMutex_); + callFuncRunningNum_++; + if (callFuncRunningNum_ > MAX_RUNNING_NUM) { + LOG_WARN("The num of working function (%{public}d) over %{public}d.", callFuncRunningNum_, MAX_RUNNING_NUM); + } +} + +void El5MemoryManager::DecreaseFunctionRuningNum() +{ + std::lock_guard lock(callNumberMutex_); + callFuncRunningNum_--; +} + +bool El5MemoryManager::IsAllowUnloadService() +{ + std::lock_guard lock(callNumberMutex_); + if (callFuncRunningNum_ == 0) { + return true; + } + LOG_WARN("Not allowed to unload service, callFuncRunningNum_ is %{public}d.", callFuncRunningNum_); + return false; +} + +void El5MemoryManager::SetIsDelayedToUnload(bool isUnload) +{ + std::lock_guard lock(isDelayedMutex_); + isDelayedToUnload_ = isUnload; +} + +bool El5MemoryManager::IsDelayedToUnload() +{ + std::lock_guard lock(isDelayedMutex_); + return isDelayedToUnload_; +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS diff --git a/services/el5filekeymanager/test/BUILD.gn b/services/el5filekeymanager/test/BUILD.gn index 3bc0d39c99993734ba21a0efd77dd39dcaa76081..19b448ad1cf633d29c611d8a4f8c33ebdc195ee7 100644 --- a/services/el5filekeymanager/test/BUILD.gn +++ b/services/el5filekeymanager/test/BUILD.gn @@ -36,6 +36,7 @@ if (is_standard_system && ability_base_enable == true) { sources = [ "../src/el5_filekey_manager_service.cpp", + "../src/el5_memory_manager.cpp", "common/src/el5_test_common.cpp", "mock/src/mock_ipc.cpp", "src/el5_filekey_manager_service_mock_unittest.cpp", @@ -101,6 +102,7 @@ if (is_standard_system && ability_base_enable == true) { sources = [ "../src/el5_filekey_manager_service.cpp", + "../src/el5_memory_manager.cpp", "src/el5_filekey_manager_service_unittest.cpp", ] @@ -164,6 +166,7 @@ if (is_standard_system && ability_base_enable == true) { sources = [ "../src/el5_filekey_manager_service.cpp", + "../src/el5_memory_manager.cpp", "src/el5_filekey_manager_stub_unittest.cpp", ] @@ -208,12 +211,78 @@ if (is_standard_system && ability_base_enable == true) { } } + ohos_unittest("el5_filekey_memory_manager_unittest") { + subsystem_name = "accesscontrol" + part_name = "access_token" + module_out_path = "access_token/el5_filekey_manager" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + branch_protector_ret = "pac_ret" + + include_dirs = [ + "../include", + "include", + "${access_token_path}/frameworks/inner_api/el5filekeymanager/include/", + ] + + sources = [ + "../src/el5_filekey_manager_service.cpp", + "../src/el5_filekey_manager_service_ability.cpp", + "../src/el5_memory_manager.cpp", + "src/el5_filekey_memory_manager_unittest.cpp", + ] + + configs = [ "${access_token_path}/config:coverage_flags" ] + + deps = [ + "${access_token_path}/interfaces/inner_api/el5filekeymanager:el5_filekey_manager_sdk", + "${access_token_path}/interfaces/inner_api/el5filekeymanager:el5_filekey_manager_stub", + "${access_token_path}/interfaces/innerkits/accesstoken:libaccesstoken_sdk", + "${access_token_path}/interfaces/innerkits/accesstoken:libtokenid_sdk", + "${access_token_path}/interfaces/innerkits/token_setproc:libtoken_setproc", + ] + + external_deps = [ + "ability_base:want", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + cflags_cc = [ + "-DHILOG_ENABLE", + "-DDEBUG_API_PERFORMANCE", + ] + + if (common_event_service_enable) { + cflags_cc += [ "-DCOMMON_EVENT_SERVICE_ENABLE" ] + external_deps += [ "common_event_service:cesfwk_innerkits" ] + sources += [ "../src/el5_filekey_manager_subscriber.cpp" ] + } + + if (eventhandler_enable == true) { + cflags_cc += [ "-DEVENTHANDLER_ENABLE" ] + external_deps += [ "eventhandler:libeventhandler" ] + } + + if (theme_screenlock_mgr_enable) { + cflags_cc += [ "-DTHEME_SCREENLOCK_MGR_ENABLE" ] + external_deps += [ "screenlock_mgr:screenlock_client" ] + } + } + group("unittest") { testonly = true deps = [ ":el5_filekey_manager_service_mock_unittest", ":el5_filekey_manager_service_unittest", ":el5_filekey_manager_stub_unittest", + ":el5_filekey_memory_manager_unittest", ] } } diff --git a/services/el5filekeymanager/test/include/el5_filekey_memory_manager_unittest.h b/services/el5filekeymanager/test/include/el5_filekey_memory_manager_unittest.h new file mode 100644 index 0000000000000000000000000000000000000000..d747f45cedb718eafb8e539f2837b4d87e02c892 --- /dev/null +++ b/services/el5filekeymanager/test/include/el5_filekey_memory_manager_unittest.h @@ -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. + */ + +#ifndef EL5_FILEKEY_MEMORY_MANAGER_UNITTEST_H +#define EL5_FILEKEY_MEMORY_MANAGER_UNITTEST_H + +#include +#include + +#define private public +#include "el5_filekey_manager_service_ability.h" +#include "el5_filekey_manager_service.h" +#undef private + +namespace OHOS { +namespace Security { +namespace AccessToken { +class El5FilekeyMemoryManagerTest : public testing::Test { +public: + static void SetUpTestCase() {}; + + static void TearDownTestCase() {}; + + void SetUp(); + + void TearDown() {}; + std::shared_ptr el5FilekeyManagerServiceAbility_; +}; +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif // EL5_FILEKEY_MEMORY_MANAGER_UNITTEST_H diff --git a/services/el5filekeymanager/test/src/el5_filekey_memory_manager_unittest.cpp b/services/el5filekeymanager/test/src/el5_filekey_memory_manager_unittest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23f08b72c7b0eba34a17007688a04e1075405ec4 --- /dev/null +++ b/services/el5filekeymanager/test/src/el5_filekey_memory_manager_unittest.cpp @@ -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. + */ + +#include "el5_filekey_memory_manager_unittest.h" + +#include "el5_memory_manager.h" +#include "system_ability_definition.h" + +using namespace testing::ext; +using namespace OHOS::Security::AccessToken; +namespace { +constexpr int32_t MAX_RUNNING_NUM = 256; +constexpr int64_t EXTRA_PARAM = 3; +constexpr int32_t SA_READY_TO_UNLOAD = 0; +constexpr int32_t SA_REFUSE_TO_UNLOAD = -1; +} // namespace + +void El5FilekeyMemoryManagerTest::SetUp() +{ + el5FilekeyManagerServiceAbility_ = + std::make_shared(EL5_FILEKEY_MANAGER_SERVICE_ID, false); +} + +/** + * @tc.name: MemoryManagerTest001 + * @tc.desc: test AddFunctionRuningNum and DecreaseFunctionRuningNum. + * @tc.type: FUNC + * @tc.require: issueICIZZE + */ +HWTEST_F(El5FilekeyMemoryManagerTest, MemoryManagerTest001, TestSize.Level1) +{ + El5MemoryManager::GetInstance().SetIsDelayedToUnload(false); + OHOS::SystemAbilityOnDemandReason reason(OHOS::OnDemandReasonId::PARAM, "test", "true", EXTRA_PARAM); + for (int32_t i = 0; i <= MAX_RUNNING_NUM + 1; i++) { + El5MemoryManager::GetInstance().AddFunctionRuningNum(); + } + EXPECT_EQ(SA_REFUSE_TO_UNLOAD, el5FilekeyManagerServiceAbility_->OnIdle(reason)); + for (int32_t i = 0; i <= MAX_RUNNING_NUM + 1; i++) { + El5MemoryManager::GetInstance().DecreaseFunctionRuningNum(); + } + EXPECT_EQ(SA_READY_TO_UNLOAD, el5FilekeyManagerServiceAbility_->OnIdle(reason)); +} + +/** + * @tc.name: MemoryManagerTest002 + * @tc.desc: test SetIsDelayedToUnload and IsDelayedToUnload. + * @tc.type: FUNC + * @tc.require: issueICIZZE + */ +HWTEST_F(El5FilekeyMemoryManagerTest, MemoryManagerTest002, TestSize.Level1) +{ + El5MemoryManager::GetInstance().SetIsDelayedToUnload(true); + OHOS::SystemAbilityOnDemandReason reason(OHOS::OnDemandReasonId::PARAM, "test", "true", EXTRA_PARAM); + EXPECT_EQ(SA_READY_TO_UNLOAD, el5FilekeyManagerServiceAbility_->OnIdle(reason)); + El5MemoryManager::GetInstance().SetIsDelayedToUnload(false); +}