P2P 关机流程服务异常修复完整方案
P2P 关机流程服务异常修复完整方案
项目: OpenHarmony 6.1 Miracast投屏
日期: 2026-07-17
涉及修改: 3个文件, 5项修复
一、根因分析
故障现象: 关闭WiFi开关后重新打开,投屏搜索不到设备。
根本原因: 多层故障链导致P2P服务无法正常启动。
故障层1:Manager层中间状态卡死 + 回调条件过宽
| 层级 | 问题 | 表现 |
|---|---|---|
| 修复D | AutoStopP2pService遇到OPENING/CLOSING态直接返回,不调DisableP2p |
midState卡死在中间态,状态机实例未重置 |
| 修复E | AutoStartP2pService遇到CLOSING态直接返回FAIL |
无法从CLOSING恢复启动 |
| 修复G | DealP2pStateChanged中staState == CLOSED也触发AutoStopP2pService |
WiFi已关闭时冗余触发P2P关机,干扰状态恢复 |
故障层2:状态机层指令丢失
| 层级 | 问题 | 表现 |
|---|---|---|
| 修复A | CMD_P2P_DISABLE 在P2pGroupRemoveState被静默丢弃 |
关机流程中断,状态机卡死 |
故障层3:入口与兜底
| 层级 | 问题 | 表现 |
|---|---|---|
| 权限 | CastEngine WFD Sink跨进程EnableP2p被拒 | VerifySameProcessPermission仅允许同进程 |
二、根因详解
根因1(核心):在关机过程中,P2pGroupOperatingState::ProcessCmdDisable 使用 DelayMessage 暂存 CMD_P2P_DISABLE,但在 P2pGroupRemoveState 中 CMD_P2P_DISABLE 只启动了一个计时器,组移除完成后计时器被停止,CMD_P2P_DISABLE 被静默丢弃了,关机流程中断,P2P状态被卡死在CLOSING
P2P关机详细流程:
1、创建组成功后:p2p状态为 GroupFormedState
初始状态机链(从前到后依次为父状态、子状态): P2pDefaultState → P2pEnabledState → P2pGroupFormationState → GroupFormedState
调用DisableP2p
ErrCode WifiP2pService::DisableP2p()
{
WIFI_LOGI("DisableP2p");
p2pStateMachine.SendMessage(static_cast<int>(P2P_STATE_MACHINE_CMD::CMD_P2P_DISABLE));
return ErrCode::WIFI_OPT_SUCCESS;
}
在初始状态处理消息
bool GroupFormedState::ProcessCmdDisable(const InternalMessagePtr msg) const
{
p2pStateMachine.DelayMessage(msg);// 关键核心点!CMD_P2P_DISABLE
p2pStateMachine.SwitchState(&p2pStateMachine.p2pGroupOperatingState);
return EXECUTED;
}
2、切换到状态 p2pGroupOperatingState
消息CMD_P2P_DISABLE在这里处理
此时状态机链:P2pDefaultState → P2pEnabledState → P2pGroupOperatingState
此处先移除组,再处理消息CMD_P2P_DISABLE
bool P2pGroupOperatingState::ProcessCmdDisable(const InternalMessagePtr msg) const
{
/**
* Before disabling P2P, you need to remove the group.
*/
p2pStateMachine.DelayMessage(msg);
return ProcessCmdRemoveGroup(msg);
}
bool P2pGroupOperatingState::ProcessCmdRemoveGroup(const InternalMessagePtr msg) const
{
if (group.GetP2pGroupStatus() == P2pGroupStatus::GS_STARTED) {
WifiNetAgent::GetInstance().DelInterfaceAddress(group.GetInterface(),
group.IsGroupOwner() ? group.GetGoIpAddress() : group.GetGcIpAddress(), P2P_IP_ADDR_PREFIX_LEN);
if (WifiP2PHalInterface::GetInstance().GroupRemove(group.GetInterface())) { // 下发删除组的命令到wpa_supplicant
// .....
} else {
p2pStateMachine.SwitchState(&p2pStateMachine.p2pGroupRemoveState); //删除组命令下发成功之后切换到状态p2pGroupRemoveState
}
}
return EXECUTED;
}
3、当前状态:p2pGroupRemoveState,在上一个状态 p2pGroupOperatingState 还没有处理CMD_P2P_DISABLE消息,在此时继续处理
当前状态链:P2pDefaultState → P2pEnabledState → P2pGroupOperatingState → P2pGroupRemoveState
bool P2pGroupRemoveState::ExecuteStateMsg(InternalMessagePtr msg)
{
//根因:在此处可以发现,CMD_P2P_DISABLE消息被静默丢弃,没有被真正消费,这里只是起了一个定时器然后就没有后续处理了,后续的状态机也没有真正转换成功。所以需要在这里将流程重新续上
int msgName = msg->GetMessageName();
switch (static_cast<P2P_STATE_MACHINE_CMD>(msgName)) {
case P2P_STATE_MACHINE_CMD::CMD_P2P_DISABLE: {
p2pStateMachine.DelayMessage(msg); //关键修改,补全了后续的关机指令
p2pStateMachine.StartTimer(static_cast<int>(P2P_STATE_MACHINE_CMD::P2P_DISABLE_TIMEOUT),
GROUP_REMOVE_TIMEOUT);
return EXECUTED;
}
case P2P_STATE_MACHINE_CMD::CMD_REMOVE_GROUP: {
return EXECUTED;
}
default:
WIFI_LOGE("Failed:The P2P state machine does not process messages: [%{public}d]", msgName);
return NOT_EXECUTED;
}
}
删除组之后:底层会上报GROUP_REMOVED事件,转化为消息:P2P_STATE_MACHINE_CMD::P2P_EVENT_GROUP_REMOVED。
bool P2pGroupRemoveState::ExecuteStateMsg(InternalMessagePtr msg)
没有处理P2P_EVENT_GROUP_REMOVED,冒泡到父状态 P2pGroupOperatingState 来处理
同理前文补充了p2pStateMachine.DelayMessage(msg),该消息也会被 父状态 P2pGroupOperatingState 处理
4、切换到状态 P2pGroupOperatingState
bool P2pGroupOperatingState::ProcessGroupRemovedEvt(...)
{
// 清理 DHCP / IP / current group ...
p2pStateMachine.SwitchState(&p2pStateMachine.p2pIdleState); // 切换到IdleState
return EXECUTED;
}
5、切换到状态:P2pIdleState 预期想处理:CMD_P2P_DISABLE
当前状态链:P2pDefaultState → P2pEnabledState → P2pIdleState
P2pIdleState没有对消息CMD_P2P_DISABLE进行处理,所以流转到直接父状态P2pEnabledState处理!
6、切换到状态:P2pEnabledState
由 Enabled状态 去真正 StopP2p
bool P2pEnabledState::ProcessCmdDisable(InternalMessagePtr msg) const
{
p2pStateMachine.BroadcastP2pStatusChanged(P2pState::P2P_STATE_CLOSING); // 广播关闭中
p2pStateMachine.BroadcastP2pDiscoveryChanged(false); // 停止发现
WifiP2PHalInterface::GetInstance().StopP2p(); // 调用 HAL 停止 P2P
p2pStateMachine.SwitchState(&p2pStateMachine.p2pDisablingState); // 切换到禁用中状态
return EXECUTED;
}
//处理禁用过程中的结果事件
bool P2pDisablingState::ExecuteStateMsg(InternalMessagePtr msg)
{
switch (static_cast<P2P_STATE_MACHINE_CMD>(msg->GetMessageName())) {
// WPA 驱动完成禁用操作后发送事件 disaplep2p成功!
case P2P_STATE_MACHINE_CMD::WPA_CONNECTED_EVENT: {
p2pStateMachine.StopTimer(static_cast<int>(P2P_STATE_MACHINE_CMD::DISABLE_P2P_TIMED_OUT));
const int DISABLE_P2P_SUCCEED = 0;
if (msg->GetParam1() == DISABLE_P2P_SUCCEED) {
p2pStateMachine.p2pMonitor.MonitorEnds(p2pStateMachine.p2pIface);
p2pStateMachine.SwitchState(&p2pStateMachine.p2pDisabledState); //一切完成,切换到DisabledState
p2pStateMachine.BroadcastP2pStatusChanged(P2pState::P2P_STATE_IDLE); //广播已切换到IDLE_STATE
} else {
WIFI_LOGW("something wrong happened when try to disable p2p");
}
break;
}
// 超时!
case P2P_STATE_MACHINE_CMD::DISABLE_P2P_TIMED_OUT: {
WIFI_LOGE("P2P disable time out!");
p2pStateMachine.p2pMonitor.MonitorEnds(p2pStateMachine.p2pIface);
p2pStateMachine.SwitchState(&p2pStateMachine.p2pDisabledState);
p2pStateMachine.BroadcastP2pStatusChanged(P2pState::P2P_STATE_IDLE); //依旧切换状态
break;
}
default:
return NOT_EXECUTED;
}
return EXECUTED;
}
广播监听到P2P状态切换,调用回调
void WifiP2pManager::DealP2pStateChanged(P2pState state)
{
if (state == P2pState::P2P_STATE_IDLE) {
// close p2p service sync here to avoid p2p service not closed when p2p service opened Again
CloseP2pService();
p2pEnableCond.notify_all();
}
return;
}
void WifiP2pManager::CloseP2pService(void)
{
//至此,P2P状态彻底变更完成
WifiConfigCenter::GetInstance().SetP2pMidState(WifiOprMidState::CLOSED);
WifiConfigCenter::GetInstance().SetP2pState(static_cast<int>(P2pState::P2P_STATE_CLOSED));
}
根因2:由于根因1,P2P关机流程异常中断,P2P状态卡死在CLOSING状态,AutoStopP2pService遇到OPENING/CLOSING态直接返回,AutoStartP2pService遇到CLOSING态直接返回FAIL,框架层状态机卡死,无法恢复
根因3:DealP2pStateChanged中staState == CLOSED也触发AutoStopP2pService,在打开WIFI的时候如果P2P在STA前面启动,那P2P会被误杀
根因4:CastEngine WFD Sink跨进程EnableP2p被拒,VerifySameProcessPermission仅允许同进程
三、逐文件修改详情
3.1 修复A:p2p_group_remove_state.cpp — ExecuteStateMsg(InternalMessagePtr msg)
函数: ExecuteStateMsg()
根因:CMD_P2P_DISABLE消息传递到P2pGroupRemoveState状态机时被静默丢弃,没有被真正消费,这里只是起了一个定时器然后就没有后续处理了,后续的状态机也没有真正转换成功
问题: CMD_P2P_DISABLE消息在处理过程中被丢弃,导致底层没有真正执行关闭P2P的动作,框架状态机也没有正常变更,关闭失败
修改前:
bool P2pGroupRemoveState::ExecuteStateMsg(InternalMessagePtr msg)
{
int msgName = msg->GetMessageName();
switch (static_cast<P2P_STATE_MACHINE_CMD>(msgName)) {
case P2P_STATE_MACHINE_CMD::CMD_P2P_DISABLE: {
p2pStateMachine.StartTimer(static_cast<int>(P2P_STATE_MACHINE_CMD::P2P_DISABLE_TIMEOUT),
GROUP_REMOVE_TIMEOUT);
return EXECUTED;
}
}
}
修改后:
bool P2pGroupRemoveState::ExecuteStateMsg(InternalMessagePtr msg)
{
int msgName = msg->GetMessageName();
switch (static_cast<P2P_STATE_MACHINE_CMD>(msgName)) {
case P2P_STATE_MACHINE_CMD::CMD_P2P_DISABLE: {
p2pStateMachine.DelayMessage(msg); //关键修改,补全了后续的关机指令
p2pStateMachine.StartTimer(static_cast<int>(P2P_STATE_MACHINE_CMD::P2P_DISABLE_TIMEOUT),
GROUP_REMOVE_TIMEOUT);
return EXECUTED;
}
}
}
修改点: CMD_P2P_DISABLE消息被静默丢弃,没有被真正消费,这里只是起了一个定时器然后就没有后续处理了,后续的状态机也没有真正转换成功。所以需要在这里将流程重新续上
3.2 修复G:wifi_p2p_manager.cpp — DealP2pStateChanged
函数: DealP2pStateChanged() (L345-380)
根因:WIFI重启时P2P可能先于STA启动导致被误杀
问题: 原代码在 P2P_STATE_STARTED 回调中,当 staState == CLOSING || staState == CLOSED 时都触发 AutoStopP2pService()。但 WiFi 已经处于 CLOSED 状态时,再触发 P2P 关机可能干扰状态恢复流程,比如CLOSED 可能是 WiFi 还没开(比如 P2P 先启动的时序),此时不应该误杀 P2P。事实上在AutoStopStaService()中已经包含了P2P关机的动作,这里完全是冗余操作
修改前 (L362):
if (staState == WifiOprMidState::CLOSING || staState == WifiOprMidState::CLOSED) {
AutoStopP2pService();
}
修改后:
if (staState == WifiOprMidState::CLOSING) {
AutoStopP2pService();
}
修改点: 移除 || staState == WifiOprMidState::CLOSED 条件,仅在 WiFi 正在关闭(CLOSING)时触发 P2P 关机。WiFi 已完全关闭(CLOSED)时不再冗余触发。
3.3 权限修复:wifi_p2p_service_impl.cpp
文件: foundation/communication/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_p2p_sa/wifi_p2p_service_impl.cpp
根因:跨进程EnableP2p权限被拒
WFD Sink进程(PID=3442)通过IPC调用P2P SA(PID=3998)的EnableP2p,VerifySameProcessPermission检查PID不匹配 → PERMISSION_DENIED
函数: CheckCanEnableP2p() (L108-128)
修改前 (L108-113):
ErrCode WifiP2pServiceImpl::CheckCanEnableP2p(void)
{
if (WifiPermissionUtils::VerifySameProcessPermission() == PERMISSION_DENIED) {
WIFI_LOGE("EnableP2p:VerifySameProcessPermission PERMISSION_DENIED!");
return WIFI_OPT_PERMISSION_DENIED;
}
修改后:增加是否是系统进程的判定
ErrCode WifiP2pServiceImpl::CheckCanEnableP2p(void)
{
if (WifiPermissionUtils::VerifySameProcessPermission() == PERMISSION_DENIED) {
if (!WifiAuthCenter::IsSystemAccess()) {
WIFI_LOGE("EnableP2p: permission denied (not same process, not system access)");
return WIFI_OPT_PERMISSION_DENIED;
}
}
前置条件: wifi_auth_center.h已在L21通过#include引入,无需额外添加头文件。
四、副作用分析
4.1 修复G对回调流程的影响
| 场景 | 影响 | 结论 |
|---|---|---|
| WiFi正在关闭(CLOSING) + P2P刚启动 | 仍触发AutoStopP2pService | 无变化:与原逻辑一致 |
| WiFi已关闭(CLOSED) + P2P刚启动 | 不再触发AutoStopP2pService | 正面改进:避免冗余关机干扰恢复 |
| WiFi正常运行(RUNNING/OPENING) | 不触发(原逻辑也不触发) | 无影响 |
4.2 修复A对状态及变更的影响
| 场景 | 影响 | 结论 |
|---|---|---|
| 修复A:ExecuteStateMsg(InternalMessagePtr msg) 重发 CMD_P2P_DISABLE | P2P关机流程缺失的CMD_P2P_DISABLE指令被续上 | 正面修复:关机路径的正面修复,根源上解决问题 |
五、问题总结
该问题是一个以状态机流转过程中指令丢失为核心,叠加了不合理的权限限制和功能耦合扩大化的综合性问题,依次进行针对性修改之后问题解决
更多推荐
所有评论(0)