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 
16 #include "driver_installer.h"
17 
18 #include "base_bundle_installer.h"
19 #include "installd_client.h"
20 
21 namespace OHOS {
22 namespace AppExecFwk {
23 namespace {
24 const std::vector<std::string> DRIVER_PROPERTIES {
25     "cupsFilter", "cupsBackend", "cupsPpd", "saneConfig", "saneBackend"
26 };
27 const std::string TEMP_PREFIX = "temp_";
28 } // namespace
29 
CopyAllDriverFile(const std::unordered_map<std::string,InnerBundleInfo> & newInfos,const InnerBundleInfo & oldInfo) const30 ErrCode DriverInstaller::CopyAllDriverFile(const std::unordered_map<std::string, InnerBundleInfo> &newInfos,
31     const InnerBundleInfo &oldInfo) const
32 {
33     ErrCode result = ERR_OK;
34     for (const auto &info : newInfos) {
35         bool isModuleExisted = oldInfo.FindModule(info.second.GetCurrentModulePackage());
36         result = CopyDriverSoFile(info.second, info.first, isModuleExisted);
37         CHECK_RESULT(result, "copy all driver files failed due to error %{public}d");
38     }
39 
40     RemoveAndReNameDriverFile(newInfos, oldInfo);
41     return result;
42 }
43 
CopyDriverSoFile(const InnerBundleInfo & info,const std::string & srcPath,bool isModuleExisted) const44 ErrCode DriverInstaller::CopyDriverSoFile(const InnerBundleInfo &info, const std::string &srcPath,
45     bool isModuleExisted) const
46 {
47     APP_LOGD("begin");
48     auto extensionAbilityInfos = info.GetInnerExtensionInfos();
49     // key is the orignial dir in hap of driver so file
50     // value is the destination dir of driver so file
51     std::unordered_multimap<std::string, std::string> dirMap;
52     // 1. filter driver so files
53     ErrCode result = ERR_OK;
54     std::string cpuAbi = "";
55     std::string nativeLibraryPath = "";
56     info.FetchNativeSoAttrs(info.GetCurrentModulePackage(), cpuAbi, nativeLibraryPath);
57     for (const auto &extAbilityInfo : extensionAbilityInfos) {
58         if (extAbilityInfo.second.type != ExtensionAbilityType::DRIVER) {
59             continue;
60         }
61 
62         auto &metadata = extAbilityInfo.second.metadata;
63         auto filterFunc = [this, &result, &info, &dirMap, &isModuleExisted](const Metadata &meta) {
64             result = FilterDriverSoFile(info, meta, dirMap, isModuleExisted);
65             return result != ERR_OK;
66         };
67         std::any_of(metadata.begin(), metadata.end(), filterFunc);
68         CHECK_RESULT(result, "driver so path is invalid, error is %{public}d");
69     }
70     if (dirMap.empty()) {
71         APP_LOGD("no driver so file needs to be cpoied");
72         return ERR_OK;
73     }
74     // 2. copy driver so file to destined dir
75     std::string realSoDir;
76     realSoDir.append(Constants::BUNDLE_CODE_DIR).append(ServiceConstants::PATH_SEPARATOR)
77         .append(info.GetBundleName()).append(ServiceConstants::PATH_SEPARATOR)
78         .append(nativeLibraryPath);
79     return InstalldClient::GetInstance()->ExtractDriverSoFiles(realSoDir, dirMap);
80 }
81 
FilterDriverSoFile(const InnerBundleInfo & info,const Metadata & meta,std::unordered_multimap<std::string,std::string> & dirMap,bool isModuleExisted) const82 ErrCode DriverInstaller::FilterDriverSoFile(const InnerBundleInfo &info, const Metadata &meta,
83     std::unordered_multimap<std::string, std::string> &dirMap, bool isModuleExisted) const
84 {
85     APP_LOGD("begin");
86     // find driver metadata name in driver properties
87     if (std::find(DRIVER_PROPERTIES.cbegin(), DRIVER_PROPERTIES.cend(), meta.name) ==
88         DRIVER_PROPERTIES.cend()) {
89         APP_LOGD("metadata name %{public}s is not existed in driver properties", meta.name.c_str());
90         return ERR_OK;
91     }
92 
93     // check dir and obtain name of the file which needs to be copied
94     std::string originalDir = meta.resource;
95     std::string destinedDir = meta.value;
96     if (originalDir.find(ServiceConstants::RELATIVE_PATH) != std::string::npos ||
97         destinedDir.find(ServiceConstants::RELATIVE_PATH) != std::string::npos) {
98         APP_LOGW("metadata value %{public}s, resource %{public}s cannot support path",
99             destinedDir.c_str(), originalDir.c_str());
100         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
101     }
102 
103     // create destined dir of driver files
104     std::vector<std::string> originalDirVec;
105     SplitStr(originalDir, ServiceConstants::PATH_SEPARATOR, originalDirVec, false, false);
106     if (originalDirVec.empty()) {
107         APP_LOGW("original dir is invalid");
108         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
109     }
110     auto fileName = originalDirVec.back();
111     APP_LOGD("fileName is %{public}s", fileName.c_str());
112     const auto &moduleName = info.GetModuleName(info.GetCurrentModulePackage());
113     destinedDir = CreateDriverSoDestinedDir(info.GetBundleName(), moduleName, fileName, destinedDir, isModuleExisted);
114     APP_LOGD("metadata destined dir is %{public}s", destinedDir.c_str());
115     dirMap.emplace(originalDir, destinedDir);
116     return ERR_OK;
117 }
118 
RemoveAndReNameDriverFile(const std::unordered_map<std::string,InnerBundleInfo> & newInfos,const InnerBundleInfo & oldInfo) const119 void DriverInstaller::RemoveAndReNameDriverFile(const std::unordered_map<std::string, InnerBundleInfo> &newInfos,
120     const InnerBundleInfo &oldInfo) const
121 {
122     for (const auto &info : newInfos) {
123         std::string packageName = info.second.GetCurrentModulePackage();
124         if (!oldInfo.FindModule(packageName)) {
125             continue;
126         }
127         RemoveDriverSoFile(oldInfo, info.second.GetModuleName(packageName), false);
128         RenameDriverFile(info.second);
129     }
130 }
131 
RemoveDriverSoFile(const InnerBundleInfo & info,const std::string & moduleName,bool isModuleExisted) const132 void DriverInstaller::RemoveDriverSoFile(const InnerBundleInfo &info, const std::string &moduleName,
133     bool isModuleExisted) const
134 {
135     APP_LOGD("begin");
136     auto extensionAbilityInfos = info.GetInnerExtensionInfos();
137     for (const auto &extAbilityInfo : extensionAbilityInfos) {
138         // find module name from the extAbilityInfo
139         std::string extModuleName = extAbilityInfo.second.moduleName;
140         APP_LOGD("extModuleName is %{public}s", extModuleName.c_str());
141         if ((!moduleName.empty() && moduleName.compare(extModuleName) != 0) ||
142             (extAbilityInfo.second.type != ExtensionAbilityType::DRIVER)) {
143             APP_LOGD("no driver extension(%{public}d) or moduleName(%{public}s) is not matched",
144                 static_cast<int32_t>(extAbilityInfo.second.type), moduleName.c_str());
145             continue;
146         }
147         const auto &metadata = extAbilityInfo.second.metadata;
148         for (const auto &meta : metadata) {
149             if (std::find(DRIVER_PROPERTIES.cbegin(), DRIVER_PROPERTIES.cend(), meta.name) ==
150                 DRIVER_PROPERTIES.cend()) {
151                 APP_LOGD("metadata name %{public}s is not existed in driver properties", meta.name.c_str());
152                 continue;
153             }
154             std::vector<std::string> originalDirVec;
155             SplitStr(meta.resource, ServiceConstants::PATH_SEPARATOR, originalDirVec, false, false);
156             if (originalDirVec.empty()) {
157                 APP_LOGW("invalid metadata resource %{public}s", meta.resource.c_str());
158                 return;
159             }
160             auto fileName = originalDirVec.back();
161             APP_LOGD("fileName is %{public}s", fileName.c_str());
162             std::string destinedDir = CreateDriverSoDestinedDir(info.GetBundleName(), extModuleName, fileName,
163                 meta.value, isModuleExisted);
164             APP_LOGD("Remove driver so file path is %{public}s", destinedDir.c_str());
165             if (!destinedDir.empty()) {
166                 std::string systemServiceDir = ServiceConstants::SYSTEM_SERVICE_DIR;
167                 InstalldClient::GetInstance()->RemoveDir(systemServiceDir + destinedDir);
168             }
169         }
170     }
171     APP_LOGD("end");
172 }
173 
CreateDriverSoDestinedDir(const std::string & bundleName,const std::string & moduleName,const std::string & fileName,const std::string & destinedDir,bool isModuleExisted) const174 std::string DriverInstaller::CreateDriverSoDestinedDir(const std::string &bundleName, const std::string &moduleName,
175     const std::string &fileName, const std::string &destinedDir, bool isModuleExisted) const
176 {
177     APP_LOGD("bundleName is %{public}s, moduleName is %{public}s, fileName is %{public}s, destinedDir is %{public}s",
178         bundleName.c_str(), moduleName.c_str(), fileName.c_str(), destinedDir.c_str());
179     if (bundleName.empty() || moduleName.empty() || fileName.empty() || destinedDir.empty()) {
180         APP_LOGW("parameters are invalid");
181         return "";
182     }
183     if (destinedDir.find("..") != std::string::npos) {
184         APP_LOGW("destinedDir %{public}s invalid", destinedDir.c_str());
185         return "";
186     }
187     std::string resStr = destinedDir;
188     if (resStr.back() != ServiceConstants::PATH_SEPARATOR[0]) {
189         resStr += ServiceConstants::PATH_SEPARATOR;
190     }
191     if (isModuleExisted) {
192         resStr.append(TEMP_PREFIX);
193     }
194     resStr.append(bundleName).append(Constants::FILE_UNDERLINE).append(moduleName)
195         .append(Constants::FILE_UNDERLINE).append(fileName);
196     return resStr;
197 }
198 
RenameDriverFile(const InnerBundleInfo & info) const199 void DriverInstaller::RenameDriverFile(const InnerBundleInfo &info) const
200 {
201     APP_LOGD("begin");
202     auto extensionAbilityInfos = info.GetInnerExtensionInfos();
203     for (const auto &extAbilityInfo : extensionAbilityInfos) {
204         if (extAbilityInfo.second.type != ExtensionAbilityType::DRIVER) {
205             continue;
206         }
207         std::string extModuleName = extAbilityInfo.second.moduleName;
208         APP_LOGD("extModuleName is %{public}s", extModuleName.c_str());
209         const auto &metadata = extAbilityInfo.second.metadata;
210         for (const auto &meta : metadata) {
211             if (std::find(DRIVER_PROPERTIES.cbegin(), DRIVER_PROPERTIES.cend(), meta.name) ==
212                 DRIVER_PROPERTIES.cend()) {
213                 APP_LOGD("metadata name %{public}s is not existed in driver properties", meta.name.c_str());
214                 continue;
215             }
216             std::vector<std::string> originalDirVec;
217             SplitStr(meta.resource, ServiceConstants::PATH_SEPARATOR, originalDirVec, false, false);
218             if (originalDirVec.empty()) {
219                 APP_LOGW("invalid metadata resource %{public}s", meta.resource.c_str());
220                 return;
221             }
222             auto fileName = originalDirVec.back();
223             APP_LOGD("fileName is %{public}s", fileName.c_str());
224             std::string tempDestinedDir = CreateDriverSoDestinedDir(info.GetBundleName(), extModuleName, fileName,
225                 meta.value, true);
226             APP_LOGD("driver so file temp path is %{public}s", tempDestinedDir.c_str());
227 
228             std::string realDestinedDir = CreateDriverSoDestinedDir(info.GetBundleName(), extModuleName, fileName,
229                 meta.value, false);
230             APP_LOGD("driver so file real path is %{public}s", realDestinedDir.c_str());
231 
232             std::string systemServiceDir = ServiceConstants::SYSTEM_SERVICE_DIR;
233             InstalldClient::GetInstance()->MoveFile(systemServiceDir + tempDestinedDir,
234                 systemServiceDir + realDestinedDir);
235         }
236     }
237     APP_LOGD("end");
238 }
239 }  // namespace AppExecFwk
240 }  // namespace OHOS