/* * Copyright (c) 2021-2023 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 "app_spawn_client.h" #include "hitrace_meter.h" #include "hilog_wrapper.h" namespace OHOS { namespace AppExecFwk { namespace { const int32_t CONNECT_RETRY_DELAY = 200 * 1000; // 200ms const int32_t CONNECT_RETRY_MAX_TIMES = 2; const size_t SOCK_MAX_SEND_BUFFER = 5 * 1024; // 5KB } // namespace AppSpawnClient::AppSpawnClient(bool isNWebSpawn) { socket_ = std::make_shared(isNWebSpawn); state_ = SpawnConnectionState::STATE_NOT_CONNECT; } ErrCode AppSpawnClient::OpenConnection() { HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__); if (state_ == SpawnConnectionState::STATE_CONNECTED) { return ERR_OK; } if (!socket_) { HILOG_ERROR("failed to open connection without socket!"); return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; } int32_t retryCount = 1; ErrCode errCode = socket_->OpenAppSpawnConnection(); while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) { HILOG_WARN("failed to OpenConnection, retry times %{public}d ...", retryCount); usleep(CONNECT_RETRY_DELAY); errCode = socket_->OpenAppSpawnConnection(); retryCount++; } if (SUCCEEDED(errCode)) { state_ = SpawnConnectionState::STATE_CONNECTED; } else { HILOG_ERROR("failed to openConnection, errorCode is %{public}08x", errCode); state_ = SpawnConnectionState::STATE_CONNECT_FAILED; } return errCode; } ErrCode AppSpawnClient::PreStartNWebSpawnProcess() { HILOG_INFO("PreStartNWebSpawnProcess"); int32_t retryCount = 1; ErrCode errCode = PreStartNWebSpawnProcessImpl(); while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) { HILOG_ERROR("failed to Start NWebSpawn Process, retry times %{public}d ...", retryCount); usleep(CONNECT_RETRY_DELAY); errCode = PreStartNWebSpawnProcessImpl(); retryCount++; } return errCode; } ErrCode AppSpawnClient::PreStartNWebSpawnProcessImpl() { HILOG_INFO("PreStartNWebSpawnProcessImpl"); if (!socket_) { HILOG_ERROR("failed to Pre Start NWebSpawn Process without socket!"); return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; } // openconnection failed, return fail ErrCode result = OpenConnection(); if (FAILED(result)) { HILOG_ERROR("connect to nwebspawn failed!"); return result; } std::unique_ptr autoCloseConnection( this, [](AppSpawnClient *client) { client->CloseConnection(); }); return result; } ErrCode AppSpawnClient::StartProcess(const AppSpawnStartMsg &startMsg, pid_t &pid) { HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__); if (!socket_) { HILOG_ERROR("failed to startProcess without socket!"); return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; } int32_t retryCount = 1; ErrCode errCode = StartProcessImpl(startMsg, pid); while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) { HILOG_WARN("failed to StartProcess, retry times %{public}d ...", retryCount); usleep(CONNECT_RETRY_DELAY); errCode = StartProcessImpl(startMsg, pid); retryCount++; } return errCode; } ErrCode AppSpawnClient::StartProcessImpl(const AppSpawnStartMsg &startMsg, pid_t &pid) { HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__); ErrCode result = OpenConnection(); // open connection failed, return fail if (FAILED(result)) { HILOG_ERROR("connect to appSpawn failed!"); return result; } std::unique_ptr autoCloseConnection( this, [](AppSpawnClient *client) { client->CloseConnection(); }); AppSpawnMsgWrapper msgWrapper; if (!msgWrapper.AssembleMsg(startMsg)) { HILOG_ERROR("AssembleMsg failed!"); return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED; } AppSpawnPidMsg pidMsg; if (msgWrapper.IsValid()) { result = socket_->WriteMessage(msgWrapper.GetMsgBuf(), msgWrapper.GetMsgLength()); if (FAILED(result)) { HILOG_ERROR("WriteMessage failed!"); return result; } result = StartProcessForWriteMsg(msgWrapper); if (FAILED(result)) { HILOG_ERROR("StartProcessForWriteMsg failed!"); return result; } result = socket_->ReadMessage(reinterpret_cast(pidMsg.pidBuf), LEN_PID); if (FAILED(result)) { HILOG_ERROR("ReadMessage failed!"); return result; } } if (pidMsg.pid <= 0) { HILOG_ERROR("invalid pid!"); result = ERR_APPEXECFWK_INVALID_PID; } else { pid = pidMsg.pid; } return result; } ErrCode AppSpawnClient::StartProcessForWriteMsg(const AppSpawnMsgWrapper &msgWrapper) { ErrCode result = ERR_OK; result = WriteStrInfoMessage(msgWrapper.GetExtraInfoStr()); if (FAILED(result)) { HILOG_ERROR("Write extra info failed!"); return result; } return result; } ErrCode AppSpawnClient::WriteStrInfoMessage(const std::string &strInfo) { ErrCode result = ERR_OK; if (strInfo.empty()) { return result; } // split msg const char *buff = strInfo.c_str(); size_t leftLen = strInfo.size() + 1; HILOG_DEBUG("strInfo length is %zu", leftLen); while (leftLen >= SOCK_MAX_SEND_BUFFER) { result = socket_->WriteMessage(buff, SOCK_MAX_SEND_BUFFER); if (FAILED(result)) { return result; } buff += SOCK_MAX_SEND_BUFFER; leftLen -= SOCK_MAX_SEND_BUFFER; } HILOG_DEBUG("strInfo: leftLen = %zu", leftLen); if (leftLen > 0) { result = socket_->WriteMessage(buff, leftLen); } return result; } ErrCode AppSpawnClient::GetRenderProcessTerminationStatus(const AppSpawnStartMsg &startMsg, int &status) { if (!socket_) { HILOG_ERROR("socket_ is null!"); return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET; } ErrCode result = OpenConnection(); // open connection failed, return fail if (FAILED(result)) { HILOG_ERROR("connect to appSpawn failed!"); return result; } std::unique_ptr autoCloseConnection( this, [](AppSpawnClient *client) { client->CloseConnection(); }); AppSpawnMsgWrapper msgWrapper; if (!msgWrapper.AssembleMsg(startMsg)) { HILOG_ERROR("AssembleMsg failed!"); return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED; } if (msgWrapper.IsValid()) { result = socket_->WriteMessage(msgWrapper.GetMsgBuf(), msgWrapper.GetMsgLength()); if (FAILED(result)) { HILOG_ERROR("WriteMessage failed!"); return result; } result = socket_->ReadMessage(reinterpret_cast(&status), sizeof(int)); if (FAILED(result)) { HILOG_ERROR("ReadMessage failed!"); return result; } } return result; } SpawnConnectionState AppSpawnClient::QueryConnectionState() const { return state_; } void AppSpawnClient::CloseConnection() { if (socket_ && state_ == SpawnConnectionState::STATE_CONNECTED) { socket_->CloseAppSpawnConnection(); } state_ = SpawnConnectionState::STATE_NOT_CONNECT; } void AppSpawnClient::SetSocket(const std::shared_ptr socket) { socket_ = socket; } } // namespace AppExecFwk } // namespace OHOS