1 /*
2 * Copyright (c) 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 #define LOG_TAG "CustomUtdStore"
16 #include "custom_utd_store.h"
17 #include <fstream>
18 #include <sstream>
19 #include <sys/stat.h>
20 #include "logger.h"
21 #include "preset_type_descriptors.h"
22 #include "unistd.h"
23 #include "utd_cfgs_checker.h"
24 #include "utd_graph.h"
25 #ifdef WITH_SELINUX
26 #include <policycoreutils.h>
27 #endif
28 namespace OHOS {
29 namespace UDMF {
30 constexpr const char* UTD_CFG_FILE = "utd-adt.json";
31 constexpr const char* CUSTOM_UTD_HAP_DIR = "/data/utd/utd-adt.json";
32 constexpr const char* CUSTOM_UTD_SA_DIR = "/data/service/el1/";
33 constexpr const char* OLD_CUSTOM_UTD_SA_SUB_DIR = "/distributeddata/utd/";
34 constexpr const char* CUSTOM_UTD_SA_SUB_DIR = "/utdtypes/utd/";
35
CustomUtdStore()36 CustomUtdStore::CustomUtdStore()
37 {
38 }
39
~CustomUtdStore()40 CustomUtdStore::~CustomUtdStore()
41 {
42 }
43
GetInstance()44 CustomUtdStore &CustomUtdStore::GetInstance()
45 {
46 static CustomUtdStore utdCustomPersistence;
47 return utdCustomPersistence;
48 }
49
GetCustomUtd(bool isHap,int32_t userId)50 std::vector<TypeDescriptorCfg> CustomUtdStore::GetCustomUtd(bool isHap, int32_t userId)
51 {
52 std::string path = GetCustomUtdPath(isHap, userId);
53 LOG_DEBUG(UDMF_CLIENT, "get utdcustom from cfg");
54
55 std::vector<TypeDescriptorCfg> customUtd;
56 std::ifstream fin(path);
57 if (!fin.is_open()) {
58 LOG_ERROR(UDMF_CLIENT, "Failed to open custom utd file, errno=%{public}d", errno);
59 return customUtd;
60 }
61
62 std::ostringstream buffer;
63 buffer << fin.rdbuf();
64 if (fin.fail() && !fin.eof()) {
65 LOG_ERROR(UDMF_CLIENT, "Error reading file, errno=%{public}d", errno);
66 return customUtd;
67 }
68
69 std::string jsonStr = buffer.str();
70 if (!utdJsonParser_.ParseStoredCustomUtdJson(jsonStr, customUtd)) {
71 LOG_ERROR(UDMF_CLIENT, "Failed to parse custom utd json");
72 customUtd.clear();
73 }
74 LOG_DEBUG(UDMF_CLIENT, "CustomUtd total:%{public}zu.", customUtd.size());
75 return customUtd;
76 }
77
GetCustomUtdPath(bool isHap,int32_t userId)78 std::string CustomUtdStore::GetCustomUtdPath(bool isHap, int32_t userId)
79 {
80 if (isHap) {
81 return CUSTOM_UTD_HAP_DIR;
82 }
83 std::string userIdStr = std::to_string(userId);
84 std::string path = std::string(CUSTOM_UTD_SA_DIR).append(userIdStr).append(CUSTOM_UTD_SA_SUB_DIR);
85 std::string oldPath = std::string(CUSTOM_UTD_SA_DIR).append(userIdStr).append(OLD_CUSTOM_UTD_SA_SUB_DIR);
86 path = (access(path.c_str(), F_OK) != 0 && access(oldPath.c_str(), F_OK) == 0) ? oldPath : path;
87 path.append(UTD_CFG_FILE);
88 return path;
89 }
90
SaveTypeCfgs(const std::vector<TypeDescriptorCfg> & customUtdTypes,int32_t user)91 int32_t CustomUtdStore::SaveTypeCfgs(const std::vector<TypeDescriptorCfg> &customUtdTypes, int32_t user)
92 {
93 LOG_DEBUG(UDMF_CLIENT, "customUtdTypes total:%{public}zu.", customUtdTypes.size());
94 std::string jsonData;
95 if (!utdJsonParser_.ConvertUtdCfgsToJson(customUtdTypes, jsonData)) {
96 LOG_ERROR(UDMF_CLIENT, "ConvertUtdCfgsToJson failed");
97 return E_JSON_CONVERT_FAILED;
98 }
99 std::string cfgFileDir = CUSTOM_UTD_SA_DIR + std::to_string(user) + CUSTOM_UTD_SA_SUB_DIR;
100 if (!CreateDirectory(cfgFileDir)) {
101 LOG_ERROR(UDMF_CLIENT, "CreateDirectory failed");
102 return E_FS_ERROR;
103 }
104 return SaveCfgFile(jsonData, cfgFileDir + UTD_CFG_FILE);
105 }
106
SaveCfgFile(const std::string & jsonData,const std::string & cfgFilePath)107 int32_t CustomUtdStore::SaveCfgFile(const std::string &jsonData, const std::string &cfgFilePath)
108 {
109 std::ofstream ofs;
110 ofs.open(cfgFilePath, 0x02);
111 if (!ofs.is_open()) {
112 LOG_ERROR(UDMF_CLIENT, "open cfg failed");
113 return E_FS_ERROR;
114 }
115 ofs << jsonData << std::endl;
116 if (!ofs.good()) {
117 LOG_ERROR(UDMF_CLIENT, "write cfg failed");
118 return E_FS_ERROR;
119 }
120 ofs.close();
121 LOG_DEBUG(UDMF_CLIENT, "set cfg end.");
122 return E_OK;
123 }
124
CreateDirectory(const std::string & path) const125 bool CustomUtdStore::CreateDirectory(const std::string &path) const
126 {
127 if (access(path.c_str(), F_OK) == 0) {
128 return true;
129 }
130
131 std::string::size_type index = 0;
132 do {
133 std::string subPath;
134 index = path.find('/', index + 1);
135 if (index == std::string::npos) {
136 subPath = path;
137 } else {
138 subPath = path.substr(0, index);
139 }
140
141 if (access(subPath.c_str(), F_OK) != 0) {
142 if (mkdir(subPath.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0) {
143 LOG_WARN(UDMF_CLIENT, "CreateDirectory, fail.");
144 return false;
145 }
146 }
147 } while (index != std::string::npos);
148
149 if (access(path.c_str(), F_OK) == 0) {
150 #ifdef WITH_SELINUX
151 Restorecon(path.c_str());
152 #endif
153 return true;
154 }
155 LOG_ERROR(UDMF_CLIENT, "CreateDirectory fail.");
156 return false;
157 }
158
InstallCustomUtds(const std::string & bundleName,const std::string & jsonStr,int32_t user,std::vector<TypeDescriptorCfg> & customTyepCfgs)159 bool CustomUtdStore::InstallCustomUtds(const std::string &bundleName, const std::string &jsonStr,
160 int32_t user, std::vector<TypeDescriptorCfg> &customTyepCfgs)
161 {
162 CustomUtdCfgs typeCfgs;
163 if (!utdJsonParser_.ParseUserCustomUtdJson(jsonStr, typeCfgs.first, typeCfgs.second)) {
164 LOG_ERROR(UDMF_CLIENT, "Parse json failed. bundleName:%{public}s", bundleName.c_str());
165 return false;
166 }
167 std::vector<TypeDescriptorCfg> presetTypes = PresetTypeDescriptors::GetInstance().GetPresetTypes();
168
169 if (!UtdCfgsChecker::GetInstance().CheckTypeDescriptors(
170 typeCfgs, presetTypes, customTyepCfgs, bundleName)) {
171 LOG_ERROR(UDMF_CLIENT, "check type descriptors failed, bundleName:%{public}s", bundleName.c_str());
172 return false;
173 }
174
175 ProcessUtdForSave(typeCfgs, customTyepCfgs, bundleName);
176 if (CustomUtdStore::GetInstance().SaveTypeCfgs(customTyepCfgs, user) != E_OK) {
177 LOG_ERROR(UDMF_CLIENT, "Save failed, bundleName: %{public}s", bundleName.c_str());
178 return false;
179 }
180 return true;
181 }
182
UninstallCustomUtds(const std::string & bundleName,int32_t user,std::vector<TypeDescriptorCfg> & customTyepCfgs)183 bool CustomUtdStore::UninstallCustomUtds(const std::string &bundleName, int32_t user,
184 std::vector<TypeDescriptorCfg> &customTyepCfgs)
185 {
186 for (auto iter = customTyepCfgs.begin(); iter != customTyepCfgs.end();) {
187 auto it = find(iter->installerBundles.begin(), iter->installerBundles.end(), bundleName);
188 if (it != iter->installerBundles.end()) {
189 iter->installerBundles.erase(it);
190 }
191 if (iter->installerBundles.empty()) {
192 iter = customTyepCfgs.erase(iter);
193 } else {
194 iter++;
195 }
196 }
197 std::vector<TypeDescriptorCfg> presetTypes = PresetTypeDescriptors::GetInstance().GetPresetTypes();
198 if (!UtdCfgsChecker::GetInstance().CheckBelongingToTypes(customTyepCfgs, presetTypes)) {
199 LOG_ERROR(UDMF_CLIENT, "belongingToTypes check failed. bundleName:%{public}s", bundleName.c_str());
200 return false;
201 }
202 if (CustomUtdStore::GetInstance().SaveTypeCfgs(customTyepCfgs, user) != E_OK) {
203 LOG_ERROR(UDMF_CLIENT, "Save type cfgs failed, bundleName: %{public}s", bundleName.c_str());
204 return false;
205 }
206 return true;
207 }
208
ProcessUtdForSave(const CustomUtdCfgs & utdTypes,std::vector<TypeDescriptorCfg> & customTyepCfgs,const std::string & bundleName)209 void CustomUtdStore::ProcessUtdForSave(const CustomUtdCfgs &utdTypes, std::vector<TypeDescriptorCfg> &customTyepCfgs,
210 const std::string &bundleName)
211 {
212 for (TypeDescriptorCfg declarationType : utdTypes.first) {
213 for (auto iter = customTyepCfgs.begin(); iter != customTyepCfgs.end();) {
214 if (iter->typeId == declarationType.typeId) {
215 declarationType.installerBundles = iter->installerBundles;
216 iter = customTyepCfgs.erase(iter);
217 } else {
218 iter++;
219 }
220 }
221 declarationType.installerBundles.emplace(bundleName);
222 declarationType.ownerBundle = bundleName;
223 customTyepCfgs.push_back(declarationType);
224 }
225 for (TypeDescriptorCfg referenceType : utdTypes.second) {
226 bool found = false;
227 for (auto &typeCfg : customTyepCfgs) {
228 if (typeCfg.typeId == referenceType.typeId) {
229 typeCfg.installerBundles.emplace(bundleName);
230 found = true;
231 break;
232 }
233 }
234 if (!found) {
235 referenceType.installerBundles.emplace(bundleName);
236 customTyepCfgs.push_back(referenceType);
237 }
238 }
239 }
240
GetCustomUtdInfo(bool isHap,int32_t userId)241 UtdFileInfo CustomUtdStore::GetCustomUtdInfo(bool isHap, int32_t userId)
242 {
243 UtdFileInfo info = {0};
244 std::string path = GetCustomUtdPath(isHap, userId);
245 struct stat fileStat;
246 if (stat(path.c_str(), &fileStat) != 0) {
247 LOG_WARN(UDMF_CLIENT, "custom utd file not exist");
248 return info;
249 }
250
251 info.lastTime = fileStat.st_mtime;
252 info.size = static_cast<uint64_t>(fileStat.st_size);
253 return info;
254 }
255 } // namespace UDMF
256 } // namespace OHOS