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