增强 ScreenUnlockInterceptor 配置加载失败的鲁棒性

当 ams_extension_config.json 读取或解析失败时,configMap_ 为空,
导致所有 extension 在解锁前被拦截。增加 isConfigLoaded_ 标志位,
配置未加载成功时拦截器直接放行所有 extension。

变更内容:
- ExtensionConfig 新增 std::atomic<bool> isConfigLoaded_ 标志
- LoadExtensionConfig 解析完成后设置标志为 true
- ScreenUnlockInterceptor::CheckExtensionInterception 增加前置判断,
  配置未加载时直接返回 ERR_OK 放行
- 补充 4 个测试用例覆盖新增分支,修改 NoConfig 测试用例适配新逻辑

Signed-off-by: yewei0794 <weiyejxnf@163.com>
Co-Authored-By: Agent

🤖‍ AI[100%] 👌 AI Adopted[100%] 🧑 Human[0%]
Co-authored-by: claude (glm-5.1) <ai@local>

Change-Id: Iaed7559ddceb3914c69366aa38b58347b5478492
This commit is contained in:
yewei0794
2026-05-26 22:07:55 +08:00
parent 350e10728e
commit 5a25ffbe5e
5 changed files with 130 additions and 3 deletions
@@ -16,6 +16,7 @@
#ifndef OHOS_ABILITY_RUNTIME_EXTENSION_CONFIG_H
#define OHOS_ABILITY_RUNTIME_EXTENSION_CONFIG_H
#include <atomic>
#include <map>
#include <mutex>
#include <nlohmann/json.hpp>
@@ -96,6 +97,7 @@ public:
bool HasScreenUnlockAccessConfig(const std::string &extensionTypeName);
bool HasScreenUnlockAccessAllowList(const std::string &extensionTypeName);
bool HasScreenUnlockAccessBlockList(const std::string &extensionTypeName);
bool IsConfigLoaded() const;
private:
void LoadExtensionConfig(const nlohmann::json &object);
bool ReadFileInfoJson(const std::string &filePath, nlohmann::json &jsonBuf);
@@ -124,6 +126,7 @@ private:
std::unordered_map<std::string, ExtensionConfigItem> configMap_;
std::mutex configMapMutex_;
std::atomic<bool> isConfigLoaded_ = false;
};
} // OHOS
} // AAFwk
@@ -143,6 +143,7 @@ void ExtensionConfig::LoadExtensionConfig(const nlohmann::json &object)
LoadExtensionSAEnable(jsonObject, extensionTypeName);
LoadScreenUnlockAccess(jsonObject, extensionTypeName);
}
isConfigLoaded_.store(true);
}
void ExtensionConfig::LoadExtensionAutoDisconnectTime(const nlohmann::json &object,
@@ -667,6 +668,11 @@ bool ExtensionConfig::ReadFileInfoJson(const std::string &filePath, nlohmann::js
return true;
}
bool ExtensionConfig::IsConfigLoaded() const
{
return isConfigLoaded_.load();
}
bool ExtensionConfig::CheckExtensionUriValid(const std::string &uri)
{
const size_t memberNum = 4;
@@ -150,6 +150,10 @@ ErrCode ScreenUnlockInterceptor::CheckExtensionInterception(const std::string &e
const std::string &bundleName, bool isSystemApp)
{
auto extensionConfig = DelayedSingleton<ExtensionConfig>::GetInstance();
if (!extensionConfig->IsConfigLoaded()) {
TAG_LOGW(AAFwkTag::ABILITYMGR, "extension config not loaded, allow all extensions");
return ERR_OK;
}
if (!extensionConfig->HasScreenUnlockAccessConfig(extensionTypeName)) {
TAG_LOGD(AAFwkTag::ABILITYMGR, "no screen_unlock_access config for extension: %{public}s",
extensionTypeName.c_str());
@@ -64,10 +64,14 @@ void ScreenUnlockInterceptorCoverageTest::TearDownTestCase()
void ScreenUnlockInterceptorCoverageTest::SetUp()
{
extensionConfig_->configMap_.clear();
extensionConfig_->isConfigLoaded_.store(false);
}
void ScreenUnlockInterceptorCoverageTest::TearDown()
{}
{
extensionConfig_->configMap_.clear();
extensionConfig_->isConfigLoaded_.store(false);
}
void ScreenUnlockInterceptorCoverageTest::LoadTestConfig(const std::string &configStr)
{
@@ -63,10 +63,14 @@ void ScreenUnlockInterceptorTest::TearDownTestCase()
void ScreenUnlockInterceptorTest::SetUp()
{
extensionConfig_->configMap_.clear();
extensionConfig_->isConfigLoaded_.store(false);
}
void ScreenUnlockInterceptorTest::TearDown()
{}
{
extensionConfig_->configMap_.clear();
extensionConfig_->isConfigLoaded_.store(false);
}
void ScreenUnlockInterceptorTest::LoadTestConfig(const std::string &configStr)
{
@@ -202,12 +206,20 @@ HWTEST_F(ScreenUnlockInterceptorTest, DoProcess_ScreenUnlocked, TestSize.Level1)
/**
* @tc.name: CheckExtensionInterception_NoConfig_ShouldBlock
* @tc.desc: Test CheckExtensionInterception when no screen_unlock_access config exists
* @tc.desc: Test CheckExtensionInterception when config is loaded but no screen_unlock_access config for this type
* @tc.type: FUNC
*/
HWTEST_F(ScreenUnlockInterceptorTest, CheckExtensionInterception_NoConfig_ShouldBlock, TestSize.Level1)
{
GTEST_LOG_(INFO) << "CheckExtensionInterception_NoConfig_ShouldBlock start";
// Load a dummy config so isConfigLoaded_ is true, simulating successful file read
const std::string configStr = R"({
"ams_extension_config": [{
"extension_type_name": "other_type",
"screen_unlock_access": { "defaultInterception": false }
}]
})";
LoadTestConfig(configStr);
ScreenUnlockInterceptor screenUnlockInterceptor;
auto ret = screenUnlockInterceptor.CheckExtensionInterception("form", "com.test.bundle", true);
EXPECT_EQ(ret, ERR_BLOCK_START_FIRST_BOOT_SCREEN_UNLOCK);
@@ -580,5 +592,103 @@ HWTEST_F(ScreenUnlockInterceptorTest, CheckExtensionInterception_SystemApp_NoInt
EXPECT_EQ(ret, ERR_BLOCK_START_FIRST_BOOT_SCREEN_UNLOCK);
GTEST_LOG_(INFO) << "CheckExtensionInterception_SystemApp_NoInterceptionConfig end";
}
/**
* @tc.name: CheckExtensionInterception_ConfigNotLoaded_ShouldAllow
* @tc.desc: Test CheckExtensionInterception when config file failed to load, should allow all
* @tc.type: FUNC
*/
HWTEST_F(ScreenUnlockInterceptorTest, CheckExtensionInterception_ConfigNotLoaded_ShouldAllow, TestSize.Level1)
{
GTEST_LOG_(INFO) << "CheckExtensionInterception_ConfigNotLoaded_ShouldAllow start";
// isConfigLoaded_ is false by default (SetUp resets it), simulating config file read failure
EXPECT_FALSE(extensionConfig_->IsConfigLoaded());
ScreenUnlockInterceptor screenUnlockInterceptor;
// system app extension
auto ret = screenUnlockInterceptor.CheckExtensionInterception("form", "com.test.bundle", true);
EXPECT_EQ(ret, ERR_OK);
// third-party extension
ret = screenUnlockInterceptor.CheckExtensionInterception("service", "com.test.bundle", false);
EXPECT_EQ(ret, ERR_OK);
GTEST_LOG_(INFO) << "CheckExtensionInterception_ConfigNotLoaded_ShouldAllow end";
}
/**
* @tc.name: IsConfigLoaded_AfterLoadConfig_ShouldReturnTrue
* @tc.desc: Test IsConfigLoaded returns true after config loaded, false after reset
* @tc.type: FUNC
*/
HWTEST_F(ScreenUnlockInterceptorTest, IsConfigLoaded_AfterLoadConfig_ShouldReturnTrue, TestSize.Level1)
{
GTEST_LOG_(INFO) << "IsConfigLoaded_AfterLoadConfig_ShouldReturnTrue start";
EXPECT_FALSE(extensionConfig_->IsConfigLoaded());
const std::string configStr = R"({
"ams_extension_config": [{
"extension_type_name": "form",
"screen_unlock_access": { "defaultInterception": false }
}]
})";
LoadTestConfig(configStr);
EXPECT_TRUE(extensionConfig_->IsConfigLoaded());
GTEST_LOG_(INFO) << "IsConfigLoaded_AfterLoadConfig_ShouldReturnTrue end";
}
/**
* @tc.name: DoProcess_SystemAppExtension_ConfigNotLoaded_ShouldAllow
* @tc.desc: Test DoProcess full chain: system app extension with config not loaded should allow
* @tc.type: FUNC
*/
HWTEST_F(ScreenUnlockInterceptorTest, DoProcess_SystemAppExtension_ConfigNotLoaded_ShouldAllow, TestSize.Level1)
{
GTEST_LOG_(INFO) << "DoProcess_SystemAppExtension_ConfigNotLoaded_ShouldAllow start";
EXPECT_FALSE(extensionConfig_->IsConfigLoaded());
ScreenUnlockInterceptor screenUnlockInterceptor;
StartAbilityUtils::startAbilityInfo = std::make_shared<StartAbilityInfo>();
StartAbilityUtils::startAbilityInfo->abilityInfo.type = AbilityType::EXTENSION;
StartAbilityUtils::startAbilityInfo->abilityInfo.extensionTypeName = "form";
StartAbilityUtils::startAbilityInfo->abilityInfo.applicationInfo.isSystemApp = true;
StartAbilityUtils::startAbilityInfo->abilityInfo.applicationInfo.allowAppRunWhenDeviceFirstLocked = true;
StartAbilityUtils::startAbilityInfo->abilityInfo.applicationInfo.bundleName = "com.test.bundle";
Want want;
AbilityInterceptorParam param(want, 0, 100, true, nullptr, []() { return false; });
auto screenLockManager = OHOS::ScreenLock::ScreenLockManager::GetInstance();
EXPECT_NE(screenLockManager, nullptr);
screenLockManager->SetScreenLockedState(true);
auto ret = screenUnlockInterceptor.DoProcess(param);
EXPECT_EQ(ret, ERR_OK);
GTEST_LOG_(INFO) << "DoProcess_SystemAppExtension_ConfigNotLoaded_ShouldAllow end";
}
/**
* @tc.name: DoProcess_ThirdPartyExtension_ConfigNotLoaded_ShouldAllow
* @tc.desc: Test DoProcess full chain: third-party extension with config not loaded should allow
* @tc.type: FUNC
*/
HWTEST_F(ScreenUnlockInterceptorTest, DoProcess_ThirdPartyExtension_ConfigNotLoaded_ShouldAllow, TestSize.Level1)
{
GTEST_LOG_(INFO) << "DoProcess_ThirdPartyExtension_ConfigNotLoaded_ShouldAllow start";
EXPECT_FALSE(extensionConfig_->IsConfigLoaded());
ScreenUnlockInterceptor screenUnlockInterceptor;
StartAbilityUtils::startAbilityInfo = std::make_shared<StartAbilityInfo>();
StartAbilityUtils::startAbilityInfo->abilityInfo.type = AbilityType::EXTENSION;
StartAbilityUtils::startAbilityInfo->abilityInfo.extensionTypeName = "service";
StartAbilityUtils::startAbilityInfo->abilityInfo.applicationInfo.isSystemApp = false;
StartAbilityUtils::startAbilityInfo->abilityInfo.applicationInfo.allowAppRunWhenDeviceFirstLocked = false;
StartAbilityUtils::startAbilityInfo->abilityInfo.applicationInfo.bundleName = "com.test.thirdparty";
Want want;
AbilityInterceptorParam param(want, 0, 100, true, nullptr, []() { return false; });
auto screenLockManager = OHOS::ScreenLock::ScreenLockManager::GetInstance();
EXPECT_NE(screenLockManager, nullptr);
screenLockManager->SetScreenLockedState(true);
auto ret = screenUnlockInterceptor.DoProcess(param);
EXPECT_EQ(ret, ERR_OK);
GTEST_LOG_(INFO) << "DoProcess_ThirdPartyExtension_ConfigNotLoaded_ShouldAllow end";
}
} // namespace AAFwk
} // namespace OHOS