1 /*
2 * Copyright (c) 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 "egl_system_layers_manager.h"
17
18 #include <climits>
19 #include <cstdlib>
20 #include <dlfcn.h>
21 #include <fstream>
22 #include <string>
23 #include <unistd.h>
24 #include <vector>
25
26 #include "directory_ex.h"
27 #include "json/json.h"
28 #include "config_policy_utils.h"
29 #include "wrapper_log.h"
30
31 namespace OHOS {
32
33 namespace {
34
35 const std::string JSON_CONFIG_PATH = "etc/graphics_game/config/graphics_game.json";
36
37 const std::string DEFAULT_JSON_CONFIG = R"__(
38 {
39 "enableAppMode" : true,
40 "appMode" : {
41 "enableDefaultAppMode" : true,
42 "default" : ["iGraphicsCore.z"],
43 }
44 }
45 )__";
46
47 } // end of anonymous namespace
48
GetProcessName(pid_t pid,char * pname,int len)49 bool EglSystemLayersManager::GetProcessName(pid_t pid, char *pname, int len)
50 {
51 std::string const fileName = std::string{"/proc/"} + std::to_string(pid) + std::string("/cmdline");
52 char realFileName[PATH_MAX] = { '\0' };
53
54 if (realpath(fileName.c_str(), realFileName) == nullptr) {
55 WLOGE("realpath failed");
56 return false;
57 }
58
59 FILE *f = fopen(realFileName, "r");
60 if (f == nullptr) {
61 WLOGE("fopen %{private}s cmdline file failed", realFileName);
62 *pname = 0;
63 return false;
64 }
65
66 if (fgets(pname, len, f) == nullptr) {
67 WLOGE("fgets of cmdline failed");
68 *pname = 0;
69 if (fclose(f)) {
70 WLOGE("failed to close %{private}s file", realFileName);
71 }
72 return false;
73 }
74
75 if (*pname == 0) {
76 WLOGE("process name is empty");
77 if (fclose(f)) {
78 WLOGE("failed to close %{private}s file", realFileName);
79 }
80 return false;
81 }
82
83 if (fclose(f)) {
84 WLOGE("failed to close %{private}s file", realFileName);
85 }
86 return true;
87 }
88
GetDefaultJsonConfig(Json::Value & configData)89 bool EglSystemLayersManager::GetDefaultJsonConfig(Json::Value &configData)
90 {
91 WLOGD("Read default json config");
92
93 Json::CharReaderBuilder builder;
94 Json::CharReader *charReader = builder.newCharReader();
95 if (!charReader) {
96 WLOGE("Failed to create new Json::CharReader");
97 return false;
98 }
99
100 const std::unique_ptr<Json::CharReader> reader(charReader);
101 JSONCPP_STRING errs;
102 bool ret = reader->parse(DEFAULT_JSON_CONFIG.c_str(),
103 DEFAULT_JSON_CONFIG.c_str() + static_cast<int>(DEFAULT_JSON_CONFIG.length()), &configData, &errs);
104 if (!ret) {
105 WLOGE("default json config parse error: %{private}s", errs.c_str());
106 return false;
107 } else {
108 WLOGD("default json config parse success");
109 }
110
111 return true;
112 }
113
GetJsonConfig(Json::Value & configData)114 bool EglSystemLayersManager::GetJsonConfig(Json::Value &configData)
115 {
116 char pathBuf[MAX_PATH_LEN] = {'\0'};
117 char *path = GetOneCfgFile(JSON_CONFIG_PATH.c_str(), pathBuf, MAX_PATH_LEN);
118 if (!path) {
119 WLOGE("Failed to find system config path");
120 return GetDefaultJsonConfig(configData);
121 }
122
123 std::string realPath;
124 if (!PathToRealPath(std::string(path), realPath)) {
125 WLOGE("Failed to check system config path");
126 return GetDefaultJsonConfig(configData);
127 }
128
129 std::ifstream configFile(realPath, std::ifstream::in);
130 if (!configFile.good()) {
131 WLOGE("Failed to open system json config file");
132 return GetDefaultJsonConfig(configData);
133 }
134
135 Json::CharReaderBuilder builder;
136 JSONCPP_STRING errs;
137 bool readSuccess = Json::parseFromStream(builder, configFile, &configData, &errs);
138 if (!readSuccess) {
139 WLOGE("Failed to parse system json config file, error: %{private}s", errs.c_str());
140 return GetDefaultJsonConfig(configData);
141 }
142
143 std::string hookLayerName("HOOK_LAYER");
144 if (!configData.isMember(hookLayerName)) {
145 WLOGE("Failed to find %{private}s section in system json config file", hookLayerName.c_str());
146 return GetDefaultJsonConfig(configData);
147 }
148
149 configData = configData[hookLayerName];
150 return true;
151 }
152
GetStringVectorFromJson(const Json::Value & jsonVector)153 std::vector<std::string> EglSystemLayersManager::GetStringVectorFromJson(const Json::Value &jsonVector)
154 {
155 std::vector<std::string> stringVector{};
156
157 for (const auto &i : jsonVector) {
158 if (i.isString()) {
159 stringVector.push_back(i.asString());
160 } else {
161 WLOGD("%{private}s is not a string", i.asString().c_str());
162 }
163 }
164
165 return stringVector;
166 }
167
GetSystemLayersFromConfig(Json::Value & appModeSection,const std::string & processName)168 std::vector<std::string> EglSystemLayersManager::GetSystemLayersFromConfig(Json::Value &appModeSection,
169 const std::string &processName)
170 {
171 if (!appModeSection.isMember(processName)) {
172 std::string enableDefaultAppModeName("enableDefaultAppMode");
173 if (!appModeSection.isMember(enableDefaultAppModeName)) {
174 WLOGE("Failed to find %{private}s section", enableDefaultAppModeName.c_str());
175 return std::vector<std::string>{};
176 }
177
178 if (!appModeSection[enableDefaultAppModeName].isBool()) {
179 WLOGE("Failed to get value of %{private}s section, not a boolean", enableDefaultAppModeName.c_str());
180 return std::vector<std::string>{};
181 }
182
183 if (!appModeSection[enableDefaultAppModeName].asBool()) {
184 return std::vector<std::string>{};
185 }
186
187 std::string defaultName("default");
188 if (!appModeSection.isMember(defaultName)) {
189 WLOGE("Failed to find default app mode");
190 return std::vector<std::string>{};
191 }
192
193 const Json::Value defaultArray = appModeSection[defaultName];
194 if (!defaultArray.isArray()) {
195 WLOGE("%{private}s value is not array", defaultName.c_str());
196 return std::vector<std::string>{};
197 }
198
199 return GetStringVectorFromJson(defaultArray);
200 }
201
202 const Json::Value layersArray = appModeSection[processName];
203 if (!layersArray.isArray()) {
204 WLOGE("%{private}s value is not array", processName.c_str());
205 return std::vector<std::string>{};
206 }
207
208 return GetStringVectorFromJson(layersArray);
209 }
210
GetSystemLayers()211 std::vector<std::string> EglSystemLayersManager::GetSystemLayers()
212 {
213 Json::Value configData{};
214 if (!GetJsonConfig(configData)) {
215 WLOGE("Failed to get json config");
216 return std::vector<std::string>{};
217 }
218
219 std::string enableAppModeName("enableAppMode");
220 if (!configData.isMember(enableAppModeName)) {
221 WLOGE("Failed to find %{private}s parameter in json config", enableAppModeName.c_str());
222 return std::vector<std::string>{};
223 }
224
225 if (!configData[enableAppModeName].isBool()) {
226 WLOGE("Failed to get %{private}s parameter form config, not a boolean", enableAppModeName.c_str());
227 return std::vector<std::string>{};
228 }
229
230 if (!configData[enableAppModeName].asBool()) {
231 return std::vector<std::string>{};
232 }
233
234 const std::string appModeSectionName("appMode");
235 if (!configData.isMember(appModeSectionName)) {
236 WLOGE("Failed to find %{private}s section in config", appModeSectionName.c_str());
237 return std::vector<std::string>{};
238 }
239
240 constexpr int pnameLen = 512;
241 char pname[pnameLen + 1] = {0};
242 bool res = GetProcessName(getpid(), pname, pnameLen);
243 if (!res) {
244 WLOGE("Failed to get process name");
245 return std::vector<std::string>{};
246 } else {
247 WLOGD("GetProcessName() = %{public}s", pname);
248 }
249
250 Json::Value appModeSection = configData[appModeSectionName];
251
252 return GetSystemLayersFromConfig(appModeSection, std::string(pname));
253 }
254
255 } //namespace OHOS
256