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