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