1 /*
2  * Copyright (c) 2021-2024 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_msg_wrapper.h"
17 
18 #include "securec.h"
19 
20 #include "hilog_tag_wrapper.h"
21 #include "nlohmann/json.hpp"
22 
23 namespace OHOS {
24 namespace AppExecFwk {
25 namespace {
26 constexpr const char* HSPLIST_BUNDLES = "bundles";
27 constexpr const char* HSPLIST_MODULES = "modules";
28 constexpr const char* HSPLIST_VERSIONS = "versions";
29 constexpr const char* HSPLIST_SOCKET_TYPE = "|HspList|";
30 constexpr const char* OVERLAY_SOCKET_TYPE = "|Overlay|";
31 constexpr const char* DATA_GROUP_SOCKET_TYPE = "|DataGroup|";
32 constexpr const char* APP_ENV_TYPE = "|AppEnv|";
33 constexpr const char* DATAGROUPINFOLIST_DATAGROUPID = "dataGroupId";
34 constexpr const char* DATAGROUPINFOLIST_GID = "gid";
35 constexpr const char* DATAGROUPINFOLIST_DIR = "dir";
36 constexpr const char* JSON_DATA_APP = "/data/app/el2/";
37 constexpr const char* JSON_GROUP = "/group/";
38 constexpr const char* VERSION_PREFIX = "v";
39 }
40 
~AppSpawnMsgWrapper()41 AppSpawnMsgWrapper::~AppSpawnMsgWrapper()
42 {
43     FreeMsg();
44 }
45 
DumpToJson(const HspList & hspList)46 static std::string DumpToJson(const HspList &hspList)
47 {
48     nlohmann::json hspListJson;
49     for (auto& hsp : hspList) {
50         hspListJson[HSPLIST_BUNDLES].emplace_back(hsp.bundleName);
51         hspListJson[HSPLIST_MODULES].emplace_back(hsp.moduleName);
52         hspListJson[HSPLIST_VERSIONS].emplace_back(VERSION_PREFIX + std::to_string(hsp.versionCode));
53     }
54     return hspListJson.dump();
55 }
56 
DumpToJson(const DataGroupInfoList & dataGroupInfoList)57 static std::string DumpToJson(const DataGroupInfoList &dataGroupInfoList)
58 {
59     nlohmann::json dataGroupInfoListJson;
60     for (auto& dataGroupInfo : dataGroupInfoList) {
61         dataGroupInfoListJson[DATAGROUPINFOLIST_DATAGROUPID].emplace_back(dataGroupInfo.dataGroupId);
62         dataGroupInfoListJson[DATAGROUPINFOLIST_GID].emplace_back(std::to_string(dataGroupInfo.gid));
63         std::string dir = JSON_DATA_APP + std::to_string(dataGroupInfo.userId)
64             + JSON_GROUP + dataGroupInfo.uuid;
65         dataGroupInfoListJson[DATAGROUPINFOLIST_DIR].emplace_back(dir);
66     }
67     return dataGroupInfoListJson.dump();
68 }
69 
DumpAppEnvToJson(const std::map<std::string,std::string> & appEnv)70 static std::string DumpAppEnvToJson(const std::map<std::string, std::string> &appEnv)
71 {
72     nlohmann::json appEnvJson;
73     for (const auto &[envName, envValue] : appEnv) {
74         appEnvJson[envName] = envValue;
75     }
76     return appEnvJson.dump();
77 }
78 
AssembleMsg(const AppSpawnStartMsg & startMsg)79 bool AppSpawnMsgWrapper::AssembleMsg(const AppSpawnStartMsg &startMsg)
80 {
81     if (!VerifyMsg(startMsg)) {
82         return false;
83     }
84     FreeMsg();
85     size_t msgSize = sizeof(AppSpawnMsg) + 1;
86     msg_ = static_cast<AppSpawnMsg *>(malloc(msgSize));
87     if (msg_ == nullptr) {
88         TAG_LOGE(AAFwkTag::APPMGR, "failed to malloc!");
89         return false;
90     }
91     if (memset_s(msg_, msgSize, 0, msgSize) != EOK) {
92         TAG_LOGE(AAFwkTag::APPMGR, "failed to memset!");
93         return false;
94     }
95     msg_->code = static_cast<AppSpawn::ClientSocket::AppOperateCode>(startMsg.code);
96     if (msg_->code == AppSpawn::ClientSocket::AppOperateCode::DEFAULT ||
97         msg_->code == AppSpawn::ClientSocket::AppOperateCode::SPAWN_NATIVE_PROCESS) {
98         msg_->uid = startMsg.uid;
99         msg_->gid = startMsg.gid;
100         msg_->gidCount = startMsg.gids.size() + startMsg.dataGroupInfoList.size();
101         msg_->bundleIndex = startMsg.bundleIndex;
102         msg_->setAllowInternet = startMsg.setAllowInternet;
103         msg_->allowInternet = startMsg.allowInternet;
104         msg_->mountPermissionFlags = startMsg.mountPermissionFlags;
105         if (strcpy_s(msg_->ownerId, sizeof(msg_->ownerId), startMsg.ownerId.c_str()) != EOK) {
106             TAG_LOGE(AAFwkTag::APPMGR, "failed to transform ownerId!");
107             return false;
108         }
109         for (uint32_t i = 0; i < startMsg.gids.size(); ++i) {
110             msg_->gidTable[i] = startMsg.gids[i];
111         }
112         for (uint32_t i = startMsg.gids.size(); i < msg_->gidCount; ++i) {
113             msg_->gidTable[i] = startMsg.dataGroupInfoList[i - startMsg.gids.size()].gid;
114         }
115         if (strcpy_s(msg_->processName, sizeof(msg_->processName), startMsg.procName.c_str()) != EOK) {
116             TAG_LOGE(AAFwkTag::APPMGR, "failed to transform procName!");
117             return false;
118         }
119         if (strcpy_s(msg_->soPath, sizeof(msg_->soPath), startMsg.soPath.c_str()) != EOK) {
120             TAG_LOGE(AAFwkTag::APPMGR, "failed to transform soPath!");
121             return false;
122         }
123         msg_->accessTokenId = startMsg.accessTokenId;
124         if (strcpy_s(msg_->apl, sizeof(msg_->apl), startMsg.apl.c_str()) != EOK) {
125             TAG_LOGE(AAFwkTag::APPMGR, "failed to transform apl!");
126             return false;
127         }
128         if (strcpy_s(msg_->bundleName, sizeof(msg_->bundleName), startMsg.bundleName.c_str()) != EOK) {
129             TAG_LOGE(AAFwkTag::APPMGR, "failed to transform bundleName!");
130             return false;
131         }
132 
133         if (strcpy_s(msg_->renderCmd, sizeof(msg_->renderCmd), startMsg.renderParam.c_str()) != EOK) {
134             TAG_LOGE(AAFwkTag::APPMGR, "failed to transform renderCmd!");
135             return false;
136         }
137         msg_->flags = startMsg.flags;
138         msg_->accessTokenIdEx = startMsg.accessTokenIdEx;
139         msg_->hapFlags = startMsg.hapFlags;
140 
141         BuildExtraInfo(startMsg);
142     } else if (msg_->code == AppSpawn::ClientSocket::AppOperateCode::GET_RENDER_TERMINATION_STATUS) {
143         msg_->pid = startMsg.pid;
144     } else {
145         TAG_LOGE(AAFwkTag::APPMGR, "invalid code");
146         return false;
147     }
148 
149     isValid_ = true;
150     DumpMsg();
151     return isValid_;
152 }
153 
BuildExtraInfo(const AppSpawnStartMsg & startMsg)154 void AppSpawnMsgWrapper::BuildExtraInfo(const AppSpawnStartMsg &startMsg)
155 {
156     if (!startMsg.hspList.empty()) {
157         extraInfoStr_ += HSPLIST_SOCKET_TYPE + DumpToJson(startMsg.hspList) +
158                                 HSPLIST_SOCKET_TYPE;
159     }
160 
161     if (!startMsg.dataGroupInfoList.empty()) {
162         extraInfoStr_ += DATA_GROUP_SOCKET_TYPE + DumpToJson(startMsg.dataGroupInfoList) +
163                                 DATA_GROUP_SOCKET_TYPE;
164     }
165 
166     if (!startMsg.overlayInfo.empty()) {
167         extraInfoStr_ += OVERLAY_SOCKET_TYPE + startMsg.overlayInfo +
168                                 OVERLAY_SOCKET_TYPE;
169     }
170 
171     if (!startMsg.appEnv.empty()) {
172         auto appEnvStr = DumpAppEnvToJson(startMsg.appEnv);
173         TAG_LOGD(AAFwkTag::APPMGR, "AppEnv: %{public}s", appEnvStr.c_str());
174         extraInfoStr_ += APP_ENV_TYPE + appEnvStr + APP_ENV_TYPE;
175     }
176 
177     if (!extraInfoStr_.empty()) {
178         msg_->extraInfo.totalLength = extraInfoStr_.size() + 1;
179     }
180 }
181 
VerifyMsg(const AppSpawnStartMsg & startMsg) const182 bool AppSpawnMsgWrapper::VerifyMsg(const AppSpawnStartMsg &startMsg) const
183 {
184     if (startMsg.code == AppSpawn::ClientSocket::AppOperateCode::DEFAULT ||
185         startMsg.code == AppSpawn::ClientSocket::AppOperateCode::SPAWN_NATIVE_PROCESS) {
186         if (startMsg.uid < 0) {
187             TAG_LOGE(AAFwkTag::APPMGR, "invalid uid! [%{public}d]", startMsg.uid);
188             return false;
189         }
190 
191         if (startMsg.gid < 0) {
192             TAG_LOGE(AAFwkTag::APPMGR, "invalid gid! [%{public}d]", startMsg.gid);
193             return false;
194         }
195 
196         if (startMsg.gids.size() > AppSpawn::ClientSocket::MAX_GIDS) {
197             TAG_LOGE(AAFwkTag::APPMGR, "too many app gids!");
198             return false;
199         }
200 
201         for (uint32_t i = 0; i < startMsg.gids.size(); ++i) {
202             if (startMsg.gids[i] < 0) {
203                 TAG_LOGE(AAFwkTag::APPMGR, "invalid gids array! [%{public}d]", startMsg.gids[i]);
204                 return false;
205             }
206         }
207 
208         if (startMsg.procName.empty() || startMsg.procName.size() >= AppSpawn::ClientSocket::LEN_PROC_NAME) {
209             TAG_LOGE(AAFwkTag::APPMGR, "invalid procName!");
210             return false;
211         }
212     } else if (startMsg.code == AppSpawn::ClientSocket::AppOperateCode::GET_RENDER_TERMINATION_STATUS) {
213         if (startMsg.pid < 0) {
214             TAG_LOGE(AAFwkTag::APPMGR, "invalid pid!");
215             return false;
216         }
217     } else {
218         TAG_LOGE(AAFwkTag::APPMGR, "invalid code!");
219         return false;
220     }
221 
222     return true;
223 }
224 
DumpMsg() const225 void AppSpawnMsgWrapper::DumpMsg() const
226 {
227     if (!isValid_) {
228         return;
229     }
230     std::string accessTokenIdExString = std::to_string(msg_->accessTokenIdEx);
231     TAG_LOGD(AAFwkTag::APPMGR, "uid: %{public}d, gid: %{public}d, procName: %{public}s, accessTokenIdEx :%{public}s",
232         msg_->uid, msg_->gid, msg_->processName, accessTokenIdExString.c_str());
233 }
234 
FreeMsg()235 void AppSpawnMsgWrapper::FreeMsg()
236 {
237     if (msg_ != nullptr) {
238         free(msg_);
239         msg_ = nullptr;
240         isValid_ = false;
241     }
242 }
243 }  // namespace AppExecFwk
244 }  // namespace OHOS
245