已开启
补充execCmd接口的ccm管控 #20321
补充execCmd接口的ccm管控 #20321
已开启
SKY2001创建于 3 天前
9 个文件变更+172-1
@@ -26,6 +26,7 @@ enum class CliManagerErrorCode {
26 ERROR_PERMISSION_DENIED = 201,26 ERROR_PERMISSION_DENIED = 201,
27 ERROR_NOT_SYSTEM_APP = 202,27 ERROR_NOT_SYSTEM_APP = 202,
28 ERROR_INVALID_PARAM = 401,28 ERROR_INVALID_PARAM = 401,
29+ ERROR_NOT_SUPPORTED = 801,
29 30 
30 ERROR_TOOL_NOT_FOUND = 35600030,31 ERROR_TOOL_NOT_FOUND = 35600030,
31 ERROR_REACH_LIMIT = 35600031,32 ERROR_REACH_LIMIT = 35600031,
@@ -22,6 +22,8 @@
22namespace OHOS {22namespace OHOS {
23namespace CliTool {23namespace CliTool {
24namespace {24namespace {
25+constexpr const char* ERROR_MSG_NOT_SUPPORTED =
26+ "Capability not supported. Failed to call the API due to limited device capabilities.";
25static const std::map<CliManagerErrorCode, std::string> ERROR_MSG_MAP = {27static const std::map<CliManagerErrorCode, std::string> ERROR_MSG_MAP = {
26 {CliManagerErrorCode::ERROR_PERMISSION_DENIED, "Permission denied."},28 {CliManagerErrorCode::ERROR_PERMISSION_DENIED, "Permission denied."},
27 {CliManagerErrorCode::ERROR_NOT_SYSTEM_APP, "Not system application."},29 {CliManagerErrorCode::ERROR_NOT_SYSTEM_APP, "Not system application."},
@@ -34,6 +36,7 @@ static const std::map<CliManagerErrorCode, std::string> ERROR_MSG_MAP = {
34 {CliManagerErrorCode::ERROR_FUNCTION_NOT_EXIST, "The function does not exist."},36 {CliManagerErrorCode::ERROR_FUNCTION_NOT_EXIST, "The function does not exist."},
35 {CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_FAILED, "The function execute failed."},37 {CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_FAILED, "The function execute failed."},
36 {CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_TIMEOUT, "The function execute timeout."},38 {CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_TIMEOUT, "The function execute timeout."},
39+ {CliManagerErrorCode::ERROR_NOT_SUPPORTED, ERROR_MSG_NOT_SUPPORTED},
37};40};
38 41 
39static const std::map<int32_t, CliManagerErrorCode> NATIVE_TO_BUSINESS_ERROR_MAP = {42static const std::map<int32_t, CliManagerErrorCode> NATIVE_TO_BUSINESS_ERROR_MAP = {
@@ -49,6 +52,7 @@ static const std::map<int32_t, CliManagerErrorCode> NATIVE_TO_BUSINESS_ERROR_MAP
49 {ERR_FUNCTION_NOT_EXIST, CliManagerErrorCode::ERROR_FUNCTION_NOT_EXIST},52 {ERR_FUNCTION_NOT_EXIST, CliManagerErrorCode::ERROR_FUNCTION_NOT_EXIST},
50 {ERR_FUNCTION_EXECUTE_FAILED, CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_FAILED},53 {ERR_FUNCTION_EXECUTE_FAILED, CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_FAILED},
51 {ERR_FUNCTION_EXECUTE_TIMEOUT, CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_TIMEOUT},54 {ERR_FUNCTION_EXECUTE_TIMEOUT, CliManagerErrorCode::ERROR_FUNCTION_EXECUTE_TIMEOUT},
55+ {AAFwk::ERR_CAPABILITY_NOT_SUPPORT, CliManagerErrorCode::ERROR_NOT_SUPPORTED},
52};56};
53 57 
54static const std::map<int32_t, std::string> INNER_ERROR_MSG_MAP = {58static const std::map<int32_t, std::string> INNER_ERROR_MSG_MAP = {
@@ -1088,6 +1088,10 @@ int32_t CliToolManagerService::ExecCmd(const ExecCmdParam &param, const std::str
1088{1088{
1089 InterfaceCallCounter counter(interfaceCalledCount_);1089 InterfaceCallCounter counter(interfaceCalledCount_);
1090 TAG_LOGI(AAFwkTag::CLI_TOOL, "ExecCmd called: cmd=%{public}s", param.cmd.c_str());1090 TAG_LOGI(AAFwkTag::CLI_TOOL, "ExecCmd called: cmd=%{public}s", param.cmd.c_str());
1091+ if (!AAFwk::AppUtils::GetInstance().IsSupportExecCmd()) {
1092+ TAG_LOGE(AAFwkTag::CLI_TOOL, "Disabled ExecCmd");
1093+ return AAFwk::ERR_CAPABILITY_NOT_SUPPORT;
1094+ }
1091 if (auto ret = ValidateExecToolPermissions(); ret != ERR_OK) {1095 if (auto ret = ValidateExecToolPermissions(); ret != ERR_OK) {
1092 return ret;1096 return ret;
1093 }1097 }
@@ -14,6 +14,7 @@
14#include "cli_tool_mgr_client.h"14#include "cli_tool_mgr_client.h"
15#undef private15#undef private
16 16 
17+#include "ability_manager_errors.h"
17#include "cli_error_code.h"18#include "cli_error_code.h"
18#include "mock_cli_tool_mgr_client_flag.h"19#include "mock_cli_tool_mgr_client_flag.h"
19#include "mock_cli_tool_mgr_service.h"20#include "mock_cli_tool_mgr_service.h"
@@ -461,6 +462,31 @@ HWTEST_F(CliToolMGRClientTest, ExecCmd_0200, TestSize.Level1)
461 EXPECT_EQ(callbackCode, ERR_OK);462 EXPECT_EQ(callbackCode, ERR_OK);
462}463}
463 464 
465+/**
466+ * @tc.name: ExecCmd_0300
467+ * @tc.desc: Test ExecCmd success activates the provisional session subscription
468+ * @tc.type: FUNC
469+ */
470+HWTEST_F(CliToolMGRClientTest, ExecCmd_0300, TestSize.Level1)
471+{
472+ SetMockService();
473+ ExecCmdParam param;
474+ param.cmd = "echo activate_subscription";
475+ param.options.timeout = 30;
476+ auto sessionCallback = std::make_shared<MockSessionCallback>();
477+ 
478+ // Success path: the provisional subscription is activated, so a session event is delivered.
479+ CliToolMgrClientFlag::retExecCmd = ERR_OK;
480+ EXPECT_EQ(CliToolMGRClient::GetInstance().ExecCmd(param, nullptr, sessionCallback), ERR_OK);
481+ 
482+ CliToolEvent event;
483+ event.type = "stdout";
484+ EXPECT_EQ(CliSessionSubscriptionManager::GetInstance().HandleSessionEvent(
485+ "shell", CliToolMgrClientFlag::lastSubscriptionId, event), ERR_OK);
486+ EXPECT_EQ(sessionCallback->eventCount, 1);
487+ EXPECT_EQ(sessionCallback->lastEventType, "stdout");
488+}
489+ 
464/**490/**
465 * @tc.name: ExecCmd_0400491 * @tc.name: ExecCmd_0400
466 * @tc.desc: Test ExecCmd with null session callback still succeeds492 * @tc.desc: Test ExecCmd with null session callback still succeeds
@@ -533,6 +559,72 @@ HWTEST_F(CliToolMGRClientTest, ExecCmd_0600, TestSize.Level1)
533 // sessionInfo was not set, so receivedSession keeps default empty state559 // sessionInfo was not set, so receivedSession keeps default empty state
534 EXPECT_TRUE(receivedSession.sessionId.empty());560 EXPECT_TRUE(receivedSession.sessionId.empty());
535}561}
562+ 
563+/**
564+ * @tc.name: ExecCmd_0700
565+ * @tc.desc: Test ExecCmd propagates capability-not-supported verbatim and cleans up callback and subscription
566+ * @tc.type: FUNC
567+ */
568+HWTEST_F(CliToolMGRClientTest, ExecCmd_0700, TestSize.Level1)
569+{
570+ SetMockService();
571+ ExecCmdParam param;
572+ param.cmd = "echo capability_disabled";
573+ param.options.timeout = 30;
574+ int32_t callbackCode = -1;
575+ auto sessionCallback = std::make_shared<MockSessionCallback>();
576+ 
577+ // Simulate the service-side capability gate rejecting ExecCmd (device does not support exec cmd).
578+ CliToolMgrClientFlag::retExecCmd = AAFwk::ERR_CAPABILITY_NOT_SUPPORT;
579+ EXPECT_EQ(CliToolMGRClient::GetInstance().ExecCmd(param,
580+ [&callbackCode](int32_t code, const CliSessionInfo &) { callbackCode = code; },
581+ sessionCallback), AAFwk::ERR_CAPABILITY_NOT_SUPPORT);
582+ 
583+ // Error path: the reply callback is removed (stray reply dropped) and the subscription is removed.
584+ EXPECT_EQ(CliEventReplyManager::GetInstance().HandleEventReply(
585+ CliToolMgrClientFlag::lastEventId, CliEventReplyResult {}), -1);
586+ CliToolEvent event;
587+ event.type = "stdout";
588+ EXPECT_NE(CliSessionSubscriptionManager::GetInstance().HandleSessionEvent(
589+ "shell", CliToolMgrClientFlag::lastSubscriptionId, event), ERR_OK);
590+ EXPECT_EQ(callbackCode, -1);
591+ EXPECT_EQ(sessionCallback->eventCount, 0);
592+}
593+ 
594+/**
595+ * @tc.name: ExecCmd_0800
596+ * @tc.desc: Test ExecCmd success delivers a non-OK reply code and sessionInfo to the reply callback
597+ * @tc.type: FUNC
598+ */
599+HWTEST_F(CliToolMGRClientTest, ExecCmd_0800, TestSize.Level1)
600+{
601+ SetMockService();
602+ ExecCmdParam param;
603+ param.cmd = "echo reply_with_code";
604+ param.options.timeout = 30;
605+ int32_t receivedCode = -1;
606+ CliSessionInfo receivedSession;
607+ receivedSession.sessionId = "unset";
608+ 
609+ CliToolMgrClientFlag::retExecCmd = ERR_OK;
610+ EXPECT_EQ(CliToolMGRClient::GetInstance().ExecCmd(param,
611+ [&receivedCode, &receivedSession](int32_t code, const CliSessionInfo &session) {
612+ receivedCode = code;
613+ receivedSession = session;
614+ }, nullptr), ERR_OK);
615+ 
616+ // The service later reports a non-OK result with a populated session; both must reach the callback verbatim.
617+ CliSessionInfo session;
618+ session.sessionId = "shell_session";
619+ CliEventReplyResult result;
620+ result.code = ERR_NO_INIT;
621+ result.sessionInfo = session;
622+ EXPECT_EQ(CliEventReplyManager::GetInstance().HandleEventReply(
623+ CliToolMgrClientFlag::lastEventId, result), ERR_OK);
624+ EXPECT_EQ(receivedCode, ERR_NO_INIT);
625+ EXPECT_EQ(receivedSession.sessionId, "shell_session");
626+}
627+ 
536/**628/**
537 * @tc.name: FunctionInterfaces_0100629 * @tc.name: FunctionInterfaces_0100
538 * @tc.desc: Test function register/query/getAll success paths630 * @tc.desc: Test function register/query/getAll success paths
@@ -194,9 +194,10 @@ int32_t MockCliToolMgrService::ExecTool(const ExecToolParam &, const std::string
194}194}
195 195 
196int32_t MockCliToolMgrService::ExecCmd(const ExecCmdParam &, const std::string &eventId,196int32_t MockCliToolMgrService::ExecCmd(const ExecCmdParam &, const std::string &eventId,
197- const sptr<ICliToolManagerScheduler> &, const std::string &)197+ const sptr<ICliToolManagerScheduler> &, const std::string &subscriptionId)
198{198{
199 CliToolMgrClientFlag::lastEventId = eventId;199 CliToolMgrClientFlag::lastEventId = eventId;
200+ CliToolMgrClientFlag::lastSubscriptionId = subscriptionId;
200 return CliToolMgrClientFlag::retExecCmd;201 return CliToolMgrClientFlag::retExecCmd;
201}202}
202 203 
@@ -27,6 +27,7 @@ ohos_unittest("cli_tool_mgr_service_test") {
27 module_out_path = module_output_path27 module_out_path = module_output_path
28 28 
29 include_dirs = [29 include_dirs = [
30+ "${ability_runtime_innerkits_path}/ability_manager/include",
30 "${ability_runtime_innerkits_path}/app_manager/include/appmgr",31 "${ability_runtime_innerkits_path}/app_manager/include/appmgr",
31 "${ability_runtime_path}/interfaces/kits/native/appkit/ability_bundle_manager_helper",32 "${ability_runtime_path}/interfaces/kits/native/appkit/ability_bundle_manager_helper",
32 "${ability_runtime_path}/test/unittest/cli_tool_mgr/cli_tool_mgr_service_test",33 "${ability_runtime_path}/test/unittest/cli_tool_mgr/cli_tool_mgr_service_test",
@@ -36,6 +36,7 @@
36#undef private36#undef private
37#undef protected37#undef protected
38 38 
39+#include "ability_manager_errors.h"
39#include "cli_error_code.h"40#include "cli_error_code.h"
40#include "cli_tool_app_state_observer.h"41#include "cli_tool_app_state_observer.h"
41#include "ccm_util.h"42#include "ccm_util.h"
@@ -80,6 +81,11 @@ bool IsPermissionGateResult(int32_t result)
80{81{
81 return result == ERR_NOT_SYSTEM_APP || result == ERR_PERMISSION_DENIED;82 return result == ERR_NOT_SYSTEM_APP || result == ERR_PERMISSION_DENIED;
82}83}
84+ 
85+bool IsCapabilityGateResult(int32_t result)
86+{
87+ return result == AAFwk::ERR_CAPABILITY_NOT_SUPPORT;
88+}
83} // namespace {89} // namespace {
84 90 
85class TestScheduler : public CliToolManagerSchedulerStub {91class TestScheduler : public CliToolManagerSchedulerStub {
@@ -2398,6 +2404,52 @@ HWTEST_F(CliToolManagerServiceTest, ExecCmd_0700, TestSize.Level1)
2398 TAG_LOGI(AAFwkTag::TEST, "CliToolManagerService_ExecCmd_0700 end");2404 TAG_LOGI(AAFwkTag::TEST, "CliToolManagerService_ExecCmd_0700 end");
2399}2405}
2400 2406 
2407+/**
2408+ * @tc.name: CliToolManagerService_ExecCmd_0800
2409+ * @tc.desc: Test ExecCmd capability gate rejects before session setup and creates no session record
2410+ * @tc.type: FUNC
2411+ */
2412+HWTEST_F(CliToolManagerServiceTest, ExecCmd_0800, TestSize.Level1)
2413+{
2414+ TAG_LOGI(AAFwkTag::TEST, "CliToolManagerService_ExecCmd_0800 start");
2415+ 
2416+ ExecCmdParam param;
2417+ param.cmd = "echo capability_gate";
2418+ param.options.timeout = 30;
2419+ sptr<TestScheduler> scheduler = new TestScheduler();
2420+ int32_t result = service_->ExecCmd(param, "event_exec_cmd_cap_gate", scheduler, "subscription_cap_gate");
2421+ 
2422+ // When exec cmd is not supported on the device, ExecCmd is rejected at the capability gate
2423+ // (before permission/scheduler/session setup); otherwise an early-rejection code is returned.
2424+ EXPECT_TRUE(IsCapabilityGateResult(result) || IsPermissionGateResult(result) ||
2425+ result == ERR_NO_INIT || result == ERR_NOT_HAP || result == ERR_INVALID_PARAM);
2426+ // No session record is created on early rejection.
2427+ EXPECT_TRUE(service_->sessionRecords_.empty());
2428+ 
2429+ TAG_LOGI(AAFwkTag::TEST, "CliToolManagerService_ExecCmd_0800 end");
2430+}
2431+ 
2432+/**
2433+ * @tc.name: CliToolManagerService_ExecCmd_0900
2434+ * @tc.desc: Test ExecCmd capability gate takes precedence over scheduler setup with null scheduler
2435+ * @tc.type: FUNC
2436+ */
2437+HWTEST_F(CliToolManagerServiceTest, ExecCmd_0900, TestSize.Level1)
2438+{
2439+ TAG_LOGI(AAFwkTag::TEST, "CliToolManagerService_ExecCmd_0900 start");
2440+ 
2441+ ExecCmdParam param;
2442+ param.cmd = "echo null_scheduler_gate";
2443+ param.options.timeout = 30;
2444+ // A null scheduler would normally yield ERR_NO_INIT at SetScheduler; the capability gate rejects first.
2445+ int32_t result = service_->ExecCmd(param, "event_exec_cmd_null_sched_gate", nullptr, "subscription_ns_gate");
2446+ 
2447+ EXPECT_TRUE(IsCapabilityGateResult(result) || result == ERR_NO_INIT || IsPermissionGateResult(result));
2448+ EXPECT_TRUE(service_->sessionRecords_.empty());
2449+ 
2450+ TAG_LOGI(AAFwkTag::TEST, "CliToolManagerService_ExecCmd_0900 end");
2451+}
2452+ 
2401/**2453/**
2402 * @tc.name: CliToolManagerService_RegisterFunction_01002454 * @tc.name: CliToolManagerService_RegisterFunction_0100
2403 * @tc.desc: Test RegisterFunction with valid function2455 * @tc.desc: Test RegisterFunction with valid function
@@ -365,6 +365,8 @@ public:
365 365 
366 bool IsAutoStartupSupported();366 bool IsAutoStartupSupported();
367 367 
368+ bool IsSupportExecCmd();
369+ 
368 bool IsProductAppbootSettingEnabled();370 bool IsProductAppbootSettingEnabled();
369 371 
370 void LoadAppTransferList();372 void LoadAppTransferList();
@@ -479,6 +481,8 @@ private:
479 volatile DeviceConfiguration<bool> isSupportAllowDebugPermission_ = {false, false};481 volatile DeviceConfiguration<bool> isSupportAllowDebugPermission_ = {false, false};
480 volatile DeviceConfiguration<bool> isStartUIAbilityInCurrentProcess_ = {false, false};482 volatile DeviceConfiguration<bool> isStartUIAbilityInCurrentProcess_ = {false, false};
481 volatile DeviceConfiguration<bool> isSupportModularObjectExtension_ = {false, false};483 volatile DeviceConfiguration<bool> isSupportModularObjectExtension_ = {false, false};
484+ volatile DeviceConfiguration<bool> isSupportExecCmd_ = {false, false};
485+ std::mutex isSupportExecCmdMutex_;
482 volatile DeviceConfiguration<bool> isAutoStartupSupported_ = {false, false};486 volatile DeviceConfiguration<bool> isAutoStartupSupported_ = {false, false};
483 volatile DeviceConfiguration<bool> isProductAppbootSettingEnabled_ = {false, false};487 volatile DeviceConfiguration<bool> isProductAppbootSettingEnabled_ = {false, false};
484 volatile DeviceConfiguration<bool> isHybridSpawnUnified_ = {false, false};488 volatile DeviceConfiguration<bool> isHybridSpawnUnified_ = {false, false};
@@ -90,6 +90,7 @@ constexpr const char* IS_ENTERPRISE_DEVICE_TYPE = "const.edm.is_enterprise_devic
90constexpr const char* IS_EDM_ENABLE = "persist.edm.edm_enable";90constexpr const char* IS_EDM_ENABLE = "persist.edm.edm_enable";
91constexpr const char* IS_DEVELOPER_MODE = "security.developermode.state";91constexpr const char* IS_DEVELOPER_MODE = "security.developermode.state";
92constexpr const char* SUPPORT_AUTO_STARTUP = "const.abilityms.enable_auto_startup";92constexpr const char* SUPPORT_AUTO_STARTUP = "const.abilityms.enable_auto_startup";
93+constexpr const char* SUPPORT_EXEC_CMD = "const.abilityms.support_exec_cmd";
93constexpr const char* SUPPORT_DELAYED_PROCESS_EXIT = "const.abilityms.support_delayed_process_exit";94constexpr const char* SUPPORT_DELAYED_PROCESS_EXIT = "const.abilityms.support_delayed_process_exit";
94// Support prepare terminate95// Support prepare terminate
95constexpr int32_t PREPARE_TERMINATE_ENABLE_SIZE = 6;96constexpr int32_t PREPARE_TERMINATE_ENABLE_SIZE = 6;
@@ -905,6 +906,17 @@ bool AppUtils::IsAutoStartupSupported()
905 return isAutoStartupSupported_.value;906 return isAutoStartupSupported_.value;
906}907}
907 908 
909+bool AppUtils::IsSupportExecCmd()
A
Aafwk_helper3 天前

🤖 AI 代码检视意见(回复本评论可解决检视意见,点击被检视代码行左侧的小头像可收起检视意见)


🟡 在互斥锁内进行日志打印可能引发死锁

位置: L909-L918 | 严重程度: Medium

❓ 问题描述

IsSupportExecCmd 方法中,TAG_LOGD 被置于 std::lock_guard 保护的临界区内执行。HiLog 等日志系统内部通常会获取自身的锁来写入日志缓冲区。如果在持有业务锁(isSupportExecCmdMutex_)的状态下调用日志接口获取日志锁,而另一处代码以相反的顺序获取这两个锁,将导致锁顺序倒置并引发死锁。此外,在锁内执行耗时的I/O或日志操作会降低系统的并发性能。

💡 修复建议

修改建议:将日志打印移出临界区。先将需要记录的值保存到局部变量中,释放互斥锁后再执行日志打印。

909: bool AppUtils::IsSupportExecCmd() 910: { 911: bool value = false; 912: { 913: std::lock_guard lock(isSupportExecCmdMutex_); 914: if (!isSupportExecCmd_.isLoaded) { 915: isSupportExecCmd_.value = system::GetBoolParameter(SUPPORT_EXEC_CMD, false); 916: isSupportExecCmd_.isLoaded = true; 917: } 918: value = isSupportExecCmd_.value; 919: } 920: TAG_LOGD(AAFwkTag::DEFAULT, "SupportExecCmd: %{public}d", value); 921: return value; 922: }


likedislike
910+{
911+ std::lock_guard lock(isSupportExecCmdMutex_);
912+ if (!isSupportExecCmd_.isLoaded) {
913+ isSupportExecCmd_.value = system::GetBoolParameter(SUPPORT_EXEC_CMD, false);
914+ isSupportExecCmd_.isLoaded = true;
915+ }
916+ TAG_LOGD(AAFwkTag::DEFAULT, "SupportExecCmd: %{public}d", isSupportExecCmd_.value);
917+ return isSupportExecCmd_.value;
918+}
919+ 
908bool AppUtils::IsProductAppbootSettingEnabled()920bool AppUtils::IsProductAppbootSettingEnabled()
909{921{
910 if (!isProductAppbootSettingEnabled_.isLoaded) {922 if (!isProductAppbootSettingEnabled_.isLoaded) {