/* * Copyright (c) 2021 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 "connection_record.h" #include "hilog_wrapper.h" #include "ability_util.h" #include "ability_manager_errors.h" #include "ability_manager_service.h" namespace OHOS { namespace AAFwk { int64_t ConnectionRecord::connectRecordId = 0; ConnectionRecord::ConnectionRecord(const sptr &callerToken, const std::shared_ptr &targetService, const sptr &connCallback) : state_(ConnectionState::INIT), callerToken_(callerToken), targetService_(targetService), connCallback_(connCallback) { recordId_ = connectRecordId++; } ConnectionRecord::~ConnectionRecord() {} std::shared_ptr ConnectionRecord::CreateConnectionRecord(const sptr &callerToken, const std::shared_ptr &targetService, const sptr &connCallback) { auto connRecord = std::make_shared(callerToken, targetService, connCallback); CHECK_POINTER_AND_RETURN(connRecord, nullptr); connRecord->SetConnectState(ConnectionState::INIT); return connRecord; } void ConnectionRecord::SetConnectState(const ConnectionState &state) { state_ = state; } ConnectionState ConnectionRecord::GetConnectState() const { return state_; } sptr ConnectionRecord::GetToken() const { return callerToken_; } std::shared_ptr ConnectionRecord::GetAbilityRecord() const { return targetService_; } sptr ConnectionRecord::GetAbilityConnectCallback() const { return connCallback_; } void ConnectionRecord::ClearConnCallBack() { if (connCallback_) { connCallback_.clear(); } } int ConnectionRecord::DisconnectAbility() { if (state_ != ConnectionState::CONNECTED) { HILOG_INFO("The connection has not established."); return INVALID_CONNECTION_STATE; } /* set state to Disconnecting */ SetConnectState(ConnectionState::DISCONNECTING); CHECK_POINTER_AND_RETURN(targetService_, ERR_INVALID_VALUE); int connectNums = targetService_->GetConnectRecordList().size(); if (connectNums == 1) { /* post timeout task to eventhandler */ auto handler = DelayedSingleton::GetInstance()->GetEventHandler(); if (handler == nullptr) { HILOG_ERROR("fail to get AbilityEventHandler"); } else { std::string taskName("DisconnectTimeout_"); taskName += std::to_string(recordId_); auto disconnectTask = [connectionRecord = shared_from_this()]() { HILOG_ERROR("Disconnect ability timeout"); connectionRecord->DisconnectTimeout(); }; handler->PostTask(disconnectTask, taskName, AbilityManagerService::DISCONNECT_TIMEOUT); } /* schedule disconnect to target ability */ targetService_->DisconnectAbility(); } else { SetConnectState(ConnectionState::DISCONNECTED); } return ERR_OK; } void ConnectionRecord::CompleteConnect(int resultCode) { CHECK_POINTER(targetService_); if (resultCode == ERR_OK) { SetConnectState(ConnectionState::CONNECTED); targetService_->SetAbilityState(AbilityState::ACTIVE); } const AppExecFwk::AbilityInfo &abilityInfo = targetService_->GetAbilityInfo(); AppExecFwk::ElementName element(abilityInfo.deviceId, abilityInfo.bundleName, abilityInfo.name); auto remoteObject = targetService_->GetConnRemoteObject(); if (connCallback_) { connCallback_->OnAbilityConnectDone(element, remoteObject, resultCode); } HILOG_INFO("result: %{public}d. connectstate:%{public}d.", resultCode, state_); } void ConnectionRecord::CompleteDisconnect(int resultCode) { if (resultCode == ERR_OK) { SetConnectState(ConnectionState::DISCONNECTED); } CHECK_POINTER(targetService_); const AppExecFwk::AbilityInfo &abilityInfo = targetService_->GetAbilityInfo(); AppExecFwk::ElementName element(abilityInfo.deviceId, abilityInfo.bundleName, abilityInfo.name); if (connCallback_) { connCallback_->OnAbilityDisconnectDone(element, resultCode); } HILOG_INFO("result: %{public}d. connectstate:%{public}d.", resultCode, state_); } void ConnectionRecord::ScheduleDisconnectAbilityDone() { if (state_ != ConnectionState::DISCONNECTING) { HILOG_ERROR("fail to schedule disconnect ability done, current state is not disconnecting."); return; } auto handler = DelayedSingleton::GetInstance()->GetEventHandler(); if (handler == nullptr) { HILOG_ERROR("fail to get AbilityEventHandler"); } else { std::string taskName = std::string("DisconnectTimeout_") + std::to_string(recordId_); handler->RemoveTask(taskName); } CompleteDisconnect(ERR_OK); } void ConnectionRecord::ScheduleConnectAbilityDone() { if (state_ != ConnectionState::CONNECTING) { HILOG_ERROR("fail to schedule connect ability done, current state is not connecting."); return; } auto handler = DelayedSingleton::GetInstance()->GetEventHandler(); if (handler == nullptr) { HILOG_ERROR("fail to get AbilityEventHandler"); } else { std::string taskName = std::string("ConnectTimeout_") + std::to_string(recordId_); handler->RemoveTask(taskName); } CompleteConnect(ERR_OK); } void ConnectionRecord::DisconnectTimeout() { CHECK_POINTER(targetService_); /* force to disconnect */ /* so scheduler target service disconnect done */ DelayedSingleton::GetInstance()->ScheduleDisconnectAbilityDone(targetService_->GetToken()); } std::string ConnectionRecord::ConvertConnectionState(const ConnectionState &state) const { switch (state) { case ConnectionState::INIT: return "INIT"; case ConnectionState::CONNECTING: return "CONNECTING"; case ConnectionState::CONNECTED: return "CONNECTED"; case ConnectionState::DISCONNECTING: return "DISCONNECTING"; case ConnectionState::DISCONNECTED: return "DISCONNECTED"; default: return "INVALIDSTATE"; } } void ConnectionRecord::Dump(std::vector &info) const { info.emplace_back(" > " + GetAbilityRecord()->GetAbilityInfo().bundleName + "/" + GetAbilityRecord()->GetAbilityInfo().name + " connectionState #" + ConvertConnectionState(GetConnectState())); } } // namespace AAFwk } // namespace OHOS