/* * 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 "ability_manager_errors.h" #include "ability_manager_service.h" #include "ability_util.h" #include "connection_state_manager.h" #include "hilog_wrapper.h" namespace OHOS { namespace AAFwk { int64_t ConnectionRecord::connectRecordId = 0; #ifdef SUPPORT_ASAN const int DISCONNECT_TIMEOUT_MULTIPLE = 75; #else const int DISCONNECT_TIMEOUT_MULTIPLE = 1; #endif 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_ERROR("The connection has not established, connectionState: %{public}d.", static_cast(state_)); return INVALID_CONNECTION_STATE; } /* set state to Disconnecting */ SetConnectState(ConnectionState::DISCONNECTING); CHECK_POINTER_AND_RETURN(targetService_, ERR_INVALID_VALUE); std::size_t connectNums = targetService_->GetConnectRecordList().size(); if (connectNums == 1) { /* post timeout task to taskhandler */ auto handler = DelayedSingleton::GetInstance()->GetTaskHandler(); if (handler == nullptr) { HILOG_ERROR("fail to get TaskHandler"); } else { std::string taskName("DisconnectTimeout_"); taskName += std::to_string(recordId_); auto disconnectTask = [connectionRecord = shared_from_this()]() { HILOG_ERROR("Disconnect ability timeout"); connectionRecord->DisconnectTimeout(); }; int disconnectTimeout = AmsConfigurationParameter::GetInstance().GetAppStartTimeoutTime() * DISCONNECT_TIMEOUT_MULTIPLE; handler->SubmitTask(disconnectTask, taskName, disconnectTimeout); } /* schedule disconnect to target ability */ targetService_->DisconnectAbility(); } else { HILOG_DEBUG("The current connection count is %{public}zu, no need to disconnect, just remove connection.", connectNums); targetService_->RemoveConnectRecordFromList(shared_from_this()); 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, abilityInfo.moduleName); auto remoteObject = targetService_->GetConnRemoteObject(); auto callback = connCallback_; auto handler = DelayedSingleton::GetInstance()->GetTaskHandler(); if (callback && handler) { handler->SubmitTask([callback, element, remoteObject, resultCode] { HILOG_DEBUG("OnAbilityConnectDone"); callback->OnAbilityConnectDone(element, remoteObject, resultCode); }); } DelayedSingleton::GetInstance()->AddConnection(shared_from_this()); HILOG_INFO("result: %{public}d. connectState:%{public}d.", resultCode, state_); } void ConnectionRecord::CompleteDisconnect(int resultCode, bool isDied) { 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, abilityInfo.moduleName); auto code = isDied ? (resultCode - 1) : resultCode; auto onDisconnectDoneTask = [connCallback = connCallback_, element, code]() { HILOG_DEBUG("OnAbilityDisconnectDone."); if (!connCallback) { HILOG_DEBUG("connCallback_ is nullptr."); return; } connCallback->OnAbilityDisconnectDone(element, code); }; auto handler = DelayedSingleton::GetInstance()->GetTaskHandler(); if (handler == nullptr) { HILOG_ERROR("handler is nullptr."); return; } handler->SubmitTask(onDisconnectDoneTask); DelayedSingleton::GetInstance()->RemoveConnection(shared_from_this(), isDied); HILOG_DEBUG("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()->GetTaskHandler(); if (handler == nullptr) { HILOG_ERROR("fail to get AbilityTaskHandler"); } else { std::string taskName = std::string("DisconnectTimeout_") + std::to_string(recordId_); handler->CancelTask(taskName); } CompleteDisconnect(ERR_OK, false); } 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()->GetTaskHandler(); if (handler == nullptr) { HILOG_ERROR("fail to get AbilityTaskHandler"); } else { std::string taskName = std::string("ConnectTimeout_") + std::to_string(recordId_); handler->CancelTask(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())); } void ConnectionRecord::AttachCallerInfo() { callerTokenId_ = IPCSkeleton::GetCallingTokenID(); // tokenId identifies the real caller auto targetRecord = Token::GetAbilityRecordByToken(callerToken_); if (targetRecord) { callerUid_ = targetRecord->GetUid(); callerPid_ = targetRecord->GetPid(); callerName_ = targetRecord->GetAbilityInfo().bundleName; return; } callerUid_ = static_cast(IPCSkeleton::GetCallingUid()); callerPid_ = static_cast(IPCSkeleton::GetCallingPid()); callerName_ = ConnectionStateManager::GetProcessNameByPid(callerPid_); } int32_t ConnectionRecord::GetCallerUid() const { return callerUid_; } int32_t ConnectionRecord::GetCallerPid() const { return callerPid_; } uint32_t ConnectionRecord::GetCallerTokenId() const { return callerTokenId_; } std::string ConnectionRecord::GetCallerName() const { return callerName_; } sptr ConnectionRecord::GetTargetToken() const { auto targetService = targetService_; if (!targetService) { return nullptr; } auto token = targetService->GetToken(); if (!token) { return nullptr; } return token->AsObject(); } sptr ConnectionRecord::GetConnection() const { auto callback = connCallback_; if (!callback) { return nullptr; } return callback->AsObject(); } } // namespace AAFwk } // namespace OHOS