1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "app_spawn_client.h"
17
18 #include "hitrace_meter.h"
19 #include "hilog_wrapper.h"
20
21 namespace OHOS {
22 namespace AppExecFwk {
23 namespace {
24 const int32_t CONNECT_RETRY_DELAY = 200 * 1000; // 200ms
25 const int32_t CONNECT_RETRY_MAX_TIMES = 2;
26 const size_t SOCK_MAX_SEND_BUFFER = 5 * 1024; // 5KB
27 } // namespace
28
AppSpawnClient(bool isNWebSpawn)29 AppSpawnClient::AppSpawnClient(bool isNWebSpawn)
30 {
31 socket_ = std::make_shared<AppSpawnSocket>(isNWebSpawn);
32 state_ = SpawnConnectionState::STATE_NOT_CONNECT;
33 }
34
OpenConnection()35 ErrCode AppSpawnClient::OpenConnection()
36 {
37 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
38 if (state_ == SpawnConnectionState::STATE_CONNECTED) {
39 return ERR_OK;
40 }
41
42 if (!socket_) {
43 HILOG_ERROR("failed to open connection without socket!");
44 return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET;
45 }
46
47 int32_t retryCount = 1;
48 ErrCode errCode = socket_->OpenAppSpawnConnection();
49 while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) {
50 HILOG_WARN("failed to OpenConnection, retry times %{public}d ...", retryCount);
51 usleep(CONNECT_RETRY_DELAY);
52 errCode = socket_->OpenAppSpawnConnection();
53 retryCount++;
54 }
55 if (SUCCEEDED(errCode)) {
56 state_ = SpawnConnectionState::STATE_CONNECTED;
57 } else {
58 HILOG_ERROR("failed to openConnection, errorCode is %{public}08x", errCode);
59 state_ = SpawnConnectionState::STATE_CONNECT_FAILED;
60 }
61 return errCode;
62 }
63
PreStartNWebSpawnProcess()64 ErrCode AppSpawnClient::PreStartNWebSpawnProcess()
65 {
66 HILOG_INFO("PreStartNWebSpawnProcess");
67 int32_t retryCount = 1;
68 ErrCode errCode = PreStartNWebSpawnProcessImpl();
69 while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) {
70 HILOG_ERROR("failed to Start NWebSpawn Process, retry times %{public}d ...", retryCount);
71 usleep(CONNECT_RETRY_DELAY);
72 errCode = PreStartNWebSpawnProcessImpl();
73 retryCount++;
74 }
75 return errCode;
76 }
77
PreStartNWebSpawnProcessImpl()78 ErrCode AppSpawnClient::PreStartNWebSpawnProcessImpl()
79 {
80 HILOG_INFO("PreStartNWebSpawnProcessImpl");
81 if (!socket_) {
82 HILOG_ERROR("failed to Pre Start NWebSpawn Process without socket!");
83 return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET;
84 }
85
86 // openconnection failed, return fail
87 ErrCode result = OpenConnection();
88 if (FAILED(result)) {
89 HILOG_ERROR("connect to nwebspawn failed!");
90 return result;
91 }
92
93 std::unique_ptr<AppSpawnClient, void (*)(AppSpawnClient *)> autoCloseConnection(
94 this, [](AppSpawnClient *client) { client->CloseConnection(); });
95
96 return result;
97 }
98
StartProcess(const AppSpawnStartMsg & startMsg,pid_t & pid)99 ErrCode AppSpawnClient::StartProcess(const AppSpawnStartMsg &startMsg, pid_t &pid)
100 {
101 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
102 if (!socket_) {
103 HILOG_ERROR("failed to startProcess without socket!");
104 return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET;
105 }
106 int32_t retryCount = 1;
107 ErrCode errCode = StartProcessImpl(startMsg, pid);
108 while (FAILED(errCode) && retryCount <= CONNECT_RETRY_MAX_TIMES) {
109 HILOG_WARN("failed to StartProcess, retry times %{public}d ...", retryCount);
110 usleep(CONNECT_RETRY_DELAY);
111 errCode = StartProcessImpl(startMsg, pid);
112 retryCount++;
113 }
114 return errCode;
115 }
116
StartProcessImpl(const AppSpawnStartMsg & startMsg,pid_t & pid)117 ErrCode AppSpawnClient::StartProcessImpl(const AppSpawnStartMsg &startMsg, pid_t &pid)
118 {
119 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
120 ErrCode result = OpenConnection();
121 // open connection failed, return fail
122 if (FAILED(result)) {
123 HILOG_ERROR("connect to appSpawn failed!");
124 return result;
125 }
126 std::unique_ptr<AppSpawnClient, void (*)(AppSpawnClient *)> autoCloseConnection(
127 this, [](AppSpawnClient *client) { client->CloseConnection(); });
128
129 AppSpawnMsgWrapper msgWrapper;
130 if (!msgWrapper.AssembleMsg(startMsg)) {
131 HILOG_ERROR("AssembleMsg failed!");
132 return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED;
133 }
134 AppSpawnPidMsg pidMsg;
135 if (msgWrapper.IsValid()) {
136 result = socket_->WriteMessage(msgWrapper.GetMsgBuf(), msgWrapper.GetMsgLength());
137 if (FAILED(result)) {
138 HILOG_ERROR("WriteMessage failed!");
139 return result;
140 }
141 result = StartProcessForWriteMsg(msgWrapper);
142 if (FAILED(result)) {
143 HILOG_ERROR("StartProcessForWriteMsg failed!");
144 return result;
145 }
146 result = socket_->ReadMessage(reinterpret_cast<void *>(pidMsg.pidBuf), LEN_PID);
147 if (FAILED(result)) {
148 HILOG_ERROR("ReadMessage failed!");
149 return result;
150 }
151 }
152 if (pidMsg.pid <= 0) {
153 HILOG_ERROR("invalid pid!");
154 result = ERR_APPEXECFWK_INVALID_PID;
155 } else {
156 pid = pidMsg.pid;
157 }
158 return result;
159 }
160
StartProcessForWriteMsg(const AppSpawnMsgWrapper & msgWrapper)161 ErrCode AppSpawnClient::StartProcessForWriteMsg(const AppSpawnMsgWrapper &msgWrapper)
162 {
163 ErrCode result = ERR_OK;
164 result = WriteStrInfoMessage(msgWrapper.GetExtraInfoStr());
165 if (FAILED(result)) {
166 HILOG_ERROR("Write extra info failed!");
167 return result;
168 }
169 return result;
170 }
171
WriteStrInfoMessage(const std::string & strInfo)172 ErrCode AppSpawnClient::WriteStrInfoMessage(const std::string &strInfo)
173 {
174 ErrCode result = ERR_OK;
175 if (strInfo.empty()) {
176 return result;
177 }
178
179 // split msg
180 const char *buff = strInfo.c_str();
181 size_t leftLen = strInfo.size() + 1;
182 HILOG_DEBUG("strInfo length is %zu", leftLen);
183 while (leftLen >= SOCK_MAX_SEND_BUFFER) {
184 result = socket_->WriteMessage(buff, SOCK_MAX_SEND_BUFFER);
185 if (FAILED(result)) {
186 return result;
187 }
188 buff += SOCK_MAX_SEND_BUFFER;
189 leftLen -= SOCK_MAX_SEND_BUFFER;
190 }
191
192 HILOG_DEBUG("strInfo: leftLen = %zu", leftLen);
193 if (leftLen > 0) {
194 result = socket_->WriteMessage(buff, leftLen);
195 }
196 return result;
197 }
198
GetRenderProcessTerminationStatus(const AppSpawnStartMsg & startMsg,int & status)199 ErrCode AppSpawnClient::GetRenderProcessTerminationStatus(const AppSpawnStartMsg &startMsg, int &status)
200 {
201 if (!socket_) {
202 HILOG_ERROR("socket_ is null!");
203 return ERR_APPEXECFWK_BAD_APPSPAWN_SOCKET;
204 }
205
206 ErrCode result = OpenConnection();
207 // open connection failed, return fail
208 if (FAILED(result)) {
209 HILOG_ERROR("connect to appSpawn failed!");
210 return result;
211 }
212 std::unique_ptr<AppSpawnClient, void (*)(AppSpawnClient *)> autoCloseConnection(
213 this, [](AppSpawnClient *client) { client->CloseConnection(); });
214
215 AppSpawnMsgWrapper msgWrapper;
216 if (!msgWrapper.AssembleMsg(startMsg)) {
217 HILOG_ERROR("AssembleMsg failed!");
218 return ERR_APPEXECFWK_ASSEMBLE_START_MSG_FAILED;
219 }
220 if (msgWrapper.IsValid()) {
221 result = socket_->WriteMessage(msgWrapper.GetMsgBuf(), msgWrapper.GetMsgLength());
222 if (FAILED(result)) {
223 HILOG_ERROR("WriteMessage failed!");
224 return result;
225 }
226 result = socket_->ReadMessage(reinterpret_cast<void *>(&status), sizeof(int));
227 if (FAILED(result)) {
228 HILOG_ERROR("ReadMessage failed!");
229 return result;
230 }
231 }
232 return result;
233 }
234
QueryConnectionState() const235 SpawnConnectionState AppSpawnClient::QueryConnectionState() const
236 {
237 return state_;
238 }
239
CloseConnection()240 void AppSpawnClient::CloseConnection()
241 {
242 if (socket_ && state_ == SpawnConnectionState::STATE_CONNECTED) {
243 socket_->CloseAppSpawnConnection();
244 }
245 state_ = SpawnConnectionState::STATE_NOT_CONNECT;
246 }
247
SetSocket(const std::shared_ptr<AppSpawnSocket> socket)248 void AppSpawnClient::SetSocket(const std::shared_ptr<AppSpawnSocket> socket)
249 {
250 socket_ = socket;
251 }
252 } // namespace AppExecFwk
253 } // namespace OHOS
254