1 /*
2 * Copyright (c) 2025 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 "plugin_installer.h"
17
18 #include <fcntl.h>
19
20 #include "app_log_tag_wrapper.h"
21 #include "app_provision_info_manager.h"
22 #include "bundle_mgr_service.h"
23 #include "bundle_util.h"
24 #include "hitrace_meter.h"
25 #include "installd_client.h"
26 #include "ipc_skeleton.h"
27 #include "json_util.h"
28 #include "scope_guard.h"
29
30 namespace OHOS {
31 namespace AppExecFwk {
32 using namespace OHOS::Security;
33 namespace {
34 constexpr const char* COMPILE_SDK_TYPE_OPEN_HARMONY = "OpenHarmony";
35 constexpr const char* DEBUG_APP_IDENTIFIER = "DEBUG_LIB_ID";
36 constexpr const char* PLUGINS = "plugins";
37 constexpr const char* LIBS_TMP = "libs_tmp";
38 constexpr const char* PERMISSION_KEY = "ohos.permission.kernel.SUPPORT_PLUGIN";
39 constexpr const char* PLUGIN_ID = "pluginDistributionIDs";
40 constexpr const char* PLUGIN_ID_SEPARATOR = "|";
41 constexpr const char* REMOVE_TMP_SUFFIX = "_removed";
42 }
43
PluginInstaller()44 PluginInstaller::PluginInstaller()
45 : bundleInstallChecker_(std::make_unique<BundleInstallChecker>())
46 {
47 APP_LOGD("create PluginInstaller instance");
48 }
49
~PluginInstaller()50 PluginInstaller::~PluginInstaller()
51 {
52 APP_LOGD("destroy PluginInstaller instance");
53 BundleUtil::DeleteTempDirs(toDeleteTempHspPath_);
54 toDeleteTempHspPath_.clear();
55 }
56
InstallPlugin(const std::string & hostBundleName,const std::vector<std::string> & pluginFilePaths,const InstallPluginParam & installPluginParam)57 ErrCode PluginInstaller::InstallPlugin(const std::string &hostBundleName,
58 const std::vector<std::string> &pluginFilePaths, const InstallPluginParam &installPluginParam)
59 {
60 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
61 LOG_NOFUNC_I(BMS_TAG_INSTALLER, "begin to install plugin");
62
63 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
64 if (!dataMgr) {
65 APP_LOGE("Get dataMgr shared_ptr nullptr");
66 return ERR_APPEXECFWK_NULL_PTR;
67 }
68 // check userId
69 if (installPluginParam.userId < Constants::DEFAULT_USERID) {
70 APP_LOGE("userId(%{public}d) invalid", installPluginParam.userId);
71 return ERR_APPEXECFWK_USER_NOT_EXIST;
72 }
73 if (!dataMgr->HasUserId(installPluginParam.userId)) {
74 APP_LOGE("user %{public}d not exist", installPluginParam.userId);
75 return ERR_APPEXECFWK_USER_NOT_EXIST;
76 }
77 auto &mtx = dataMgr->GetBundleMutex(hostBundleName);
78 std::lock_guard lock {mtx};
79 // check host application exist in userId
80 InnerBundleInfo hostBundleInfo;
81 if (!dataMgr->FetchInnerBundleInfo(hostBundleName, hostBundleInfo)) {
82 APP_LOGE("hostBundleName:%{public}s get bundle info failed", hostBundleName.c_str());
83 return ERR_APPEXECFWK_HOST_APPLICATION_NOT_FOUND;
84 }
85 if (!hostBundleInfo.HasInnerBundleUserInfo(installPluginParam.userId)) {
86 APP_LOGE("HostBundleName: %{public}s not installed in user %{public}d",
87 hostBundleName.c_str(), installPluginParam.userId);
88 return ERR_APPEXECFWK_USER_NOT_EXIST;
89 }
90 // check host application permission
91 ErrCode result = ERR_OK;
92 result = CheckSupportPluginPermission(hostBundleInfo);
93 CHECK_RESULT(result, "check host application permission failed %{public}d");
94 userId_ = installPluginParam.userId;
95 // parse hsp file
96 result = ParseFiles(pluginFilePaths, installPluginParam);
97 CHECK_RESULT(result, "parse file failed %{public}d");
98 bundleNameWithTime_ = bundleName_ + "." + std::to_string(BundleUtil::GetCurrentTimeNs());
99 // check host application and plugin
100 result = CheckPluginId(hostBundleName);
101 CHECK_RESULT(result, "check pluginId failed %{public}d");
102
103 result = ProcessPluginInstall(hostBundleInfo);
104 CHECK_RESULT(result, "process plugin install failed %{public}d");
105
106 LOG_NOFUNC_I(BMS_TAG_INSTALLER, "install plugin finished");
107 return ERR_OK;
108 }
109
UninstallPlugin(const std::string & hostBundleName,const std::string & pluginBundleName,const InstallPluginParam & installPluginParam)110 ErrCode PluginInstaller::UninstallPlugin(const std::string &hostBundleName, const std::string &pluginBundleName,
111 const InstallPluginParam &installPluginParam)
112 {
113 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
114 LOG_NOFUNC_I(BMS_TAG_INSTALLER, "begin to uninstall plugin");
115
116 ErrCode result = ERR_OK;
117 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
118 if (!dataMgr) {
119 APP_LOGE("Get dataMgr shared_ptr nullptr");
120 return ERR_APPEXECFWK_NULL_PTR;
121 }
122 // check userId
123 if (installPluginParam.userId < Constants::DEFAULT_USERID) {
124 APP_LOGE("userId(%{public}d) invalid", installPluginParam.userId);
125 return ERR_APPEXECFWK_USER_NOT_EXIST;
126 }
127 if (!dataMgr->HasUserId(installPluginParam.userId)) {
128 APP_LOGE("user %{public}d not exist", installPluginParam.userId);
129 return ERR_APPEXECFWK_USER_NOT_EXIST;
130 }
131 auto &mtx = dataMgr->GetBundleMutex(hostBundleName);
132 std::lock_guard lock {mtx};
133 // check host application exist in userId
134 InnerBundleInfo hostBundleInfo;
135 if (!dataMgr->FetchInnerBundleInfo(hostBundleName, hostBundleInfo)) {
136 APP_LOGE("hostBundleName:%{public}s get bundle info failed", hostBundleName.c_str());
137 return ERR_APPEXECFWK_HOST_APPLICATION_NOT_FOUND;
138 }
139 if (!hostBundleInfo.HasInnerBundleUserInfo(installPluginParam.userId)) {
140 APP_LOGE("HostBundleName: %{public}s not installed in user %{public}d",
141 hostBundleName.c_str(), installPluginParam.userId);
142 return ERR_APPEXECFWK_USER_NOT_EXIST;
143 }
144 // check plugin exist in host application
145 isPluginExist_ = dataMgr->GetPluginBundleInfo(hostBundleName, pluginBundleName,
146 oldPluginInfo_, installPluginParam.userId);
147 if (!isPluginExist_) {
148 APP_LOGE("plugin: %{public}s not installed in host application:%{public}s user %{public}d",
149 pluginBundleName.c_str(), hostBundleName.c_str(), installPluginParam.userId);
150 return ERR_APPEXECFWK_PLUGIN_NOT_FOUND;
151 }
152 userId_ = installPluginParam.userId;
153 bundleName_ = pluginBundleName;
154 result = ProcessPluginUninstall(hostBundleInfo);
155 CHECK_RESULT(result, "process plugin install failed %{public}d");
156
157 LOG_NOFUNC_I(BMS_TAG_INSTALLER, "uninstall plugin finish");
158 return ERR_OK;
159 }
160
ParseFiles(const std::vector<std::string> & pluginFilePaths,const InstallPluginParam & installPluginParam)161 ErrCode PluginInstaller::ParseFiles(const std::vector<std::string> &pluginFilePaths,
162 const InstallPluginParam &installPluginParam)
163 {
164 APP_LOGD("parsing plugin bundle files, path : %{private}s",
165 GetJsonStrFromInfo(pluginFilePaths).c_str());
166 ErrCode result = ERR_OK;
167
168 // check file paths
169 std::vector<std::string> inBundlePaths;
170 result = BundleUtil::CheckFilePath(pluginFilePaths, inBundlePaths);
171 CHECK_RESULT(result, "hsp files check failed %{public}d");
172
173 // copy the haps to the dir which cannot be accessed from caller
174 result = CopyHspToSecurityDir(inBundlePaths, installPluginParam);
175 CHECK_RESULT(result, "copy file failed %{public}d");
176
177 // check number and type of the hsp and sig files
178 std::vector<std::string> bundlePaths;
179 result = ObtainHspFileAndSignatureFilePath(inBundlePaths, bundlePaths, signatureFileDir_);
180 CHECK_RESULT(result, "obtain hsp file path or signature file path failed due to %{public}d");
181
182 // check syscap
183 result = bundleInstallChecker_->CheckSysCap(bundlePaths);
184 bool isSysCapValid = (result == ERR_OK);
185 if (!isSysCapValid) {
186 APP_LOGI("hap syscap check failed %{public}d", result);
187 }
188 // verify signature info for all haps
189 std::vector<Security::Verify::HapVerifyResult> hapVerifyResults;
190 result = bundleInstallChecker_->CheckMultipleHapsSignInfo(bundlePaths, hapVerifyResults);
191 CHECK_RESULT(result, "hap files check signature info failed %{public}d");
192
193 // parse bundle infos
194 InstallCheckParam checkParam;
195 checkParam.needSendEvent = false;
196 result = bundleInstallChecker_->ParseHapFiles(bundlePaths, checkParam, hapVerifyResults, parsedBundles_);
197 if (result != ERR_OK) {
198 APP_LOGE("parse haps file failed %{public}d", result);
199 return ERR_APPEXECFWK_PLUGIN_PARSER_ERROR;
200 }
201 // check install permission
202 result = bundleInstallChecker_->CheckInstallPermission(checkParam, hapVerifyResults);
203 CHECK_RESULT(result, "check install permission failed %{public}d");
204
205 // check hsp install condition
206 result = bundleInstallChecker_->CheckHspInstallCondition(hapVerifyResults);
207 CHECK_RESULT(result, "check hsp install condition failed %{public}d");
208
209 // check device type
210 if (!isSysCapValid) {
211 result = bundleInstallChecker_->CheckDeviceType(parsedBundles_);
212 if (result != ERR_OK) {
213 APP_LOGE("check device type failed %{public}d", result);
214 return ERR_APPEXECFWK_INSTALL_SYSCAP_FAILED_AND_DEVICE_TYPE_ERROR;
215 }
216 }
217
218 // check label info
219 result = CheckPluginAppLabelInfo();
220 CHECK_RESULT(result, "check plugin label info failed %{public}d");
221
222 // delivery sign profile to code signature
223 result = DeliveryProfileToCodeSign(hapVerifyResults);
224 CHECK_RESULT(result, "delivery sign profile failed %{public}d");
225
226 // check native file
227 result = bundleInstallChecker_->CheckMultiNativeFile(parsedBundles_);
228 CHECK_RESULT(result, "native so is incompatible in all haps %{public}d");
229
230 // check enterprise bundle
231 /* At this place, hapVerifyResults cannot be empty and unnecessary to check it */
232 isEnterpriseBundle_ = bundleInstallChecker_->CheckEnterpriseBundle(hapVerifyResults[0]);
233 appIdentifier_ = (hapVerifyResults[0].GetProvisionInfo().type == Security::Verify::ProvisionType::DEBUG) ?
234 DEBUG_APP_IDENTIFIER : hapVerifyResults[0].GetProvisionInfo().bundleInfo.appIdentifier;
235 compileSdkType_ = parsedBundles_.empty() ? COMPILE_SDK_TYPE_OPEN_HARMONY :
236 (parsedBundles_.begin()->second).GetBaseApplicationInfo().compileSdkType;
237 if (!ParsePluginId(hapVerifyResults[0].GetProvisionInfo().appServiceCapabilities, pluginIds_)) {
238 APP_LOGE("parse plugin id failed");
239 return ERR_APPEXECFWK_PLUGIN_INSTALL_PARSE_PLUGINID_ERROR;
240 }
241 return result;
242 }
243
MkdirIfNotExist(const std::string & dir)244 ErrCode PluginInstaller::MkdirIfNotExist(const std::string &dir)
245 {
246 bool isDirExist = false;
247 ErrCode result = InstalldClient::GetInstance()->IsExistDir(dir, isDirExist);
248 CHECK_RESULT(result, "check if dir exist failed %{public}d");
249 if (!isDirExist) {
250 result = InstalldClient::GetInstance()->CreateBundleDir(dir);
251 CHECK_RESULT(result, "create dir failed %{public}d");
252 }
253 return result;
254 }
255
CopyHspToSecurityDir(std::vector<std::string> & bundlePaths,const InstallPluginParam & installPluginParam)256 ErrCode PluginInstaller::CopyHspToSecurityDir(std::vector<std::string> &bundlePaths,
257 const InstallPluginParam &installPluginParam)
258 {
259 for (size_t index = 0; index < bundlePaths.size(); ++index) {
260 auto destination = BundleUtil::CopyFileToSecurityDir(bundlePaths[index], DirType::STREAM_INSTALL_DIR,
261 toDeleteTempHspPath_, installPluginParam.IsRenameInstall());
262 if (destination.empty()) {
263 APP_LOGE("copy file %{public}s to security dir failed", bundlePaths[index].c_str());
264 return ERR_APPEXECFWK_INSTALL_COPY_HAP_FAILED;
265 }
266 bundlePaths[index] = destination;
267 }
268 return ERR_OK;
269 }
270
ObtainHspFileAndSignatureFilePath(const std::vector<std::string> & inBundlePaths,std::vector<std::string> & bundlePaths,std::string & signatureFilePath)271 ErrCode PluginInstaller::ObtainHspFileAndSignatureFilePath(const std::vector<std::string> &inBundlePaths,
272 std::vector<std::string> &bundlePaths, std::string &signatureFilePath)
273 {
274 if (inBundlePaths.empty()) {
275 APP_LOGE("number of files in single shared lib path is illegal");
276 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
277 }
278 if (inBundlePaths.size() == 1) {
279 if (!BundleUtil::EndWith(inBundlePaths[0], ServiceConstants::HSP_FILE_SUFFIX)) {
280 APP_LOGE("invalid file in plugin bundle dir");
281 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
282 }
283 bundlePaths.emplace_back(inBundlePaths[0]);
284 return ERR_OK;
285 }
286 int32_t numberOfHsp = 0;
287 int32_t numberOfSignatureFile = 0;
288 for (const auto &path : inBundlePaths) {
289 if ((path.find(ServiceConstants::HSP_FILE_SUFFIX) == std::string::npos) &&
290 (path.find(ServiceConstants::CODE_SIGNATURE_FILE_SUFFIX) == std::string::npos)) {
291 APP_LOGE("only hsp or sig file can be contained in shared bundle dir");
292 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
293 }
294 if (BundleUtil::EndWith(path, ServiceConstants::HSP_FILE_SUFFIX)) {
295 numberOfHsp++;
296 bundlePaths.emplace_back(path);
297 }
298 if (BundleUtil::EndWith(path, ServiceConstants::CODE_SIGNATURE_FILE_SUFFIX)) {
299 numberOfSignatureFile++;
300 signatureFilePath = path;
301 }
302 }
303 APP_LOGD("signatureFilePath is %{public}s", signatureFilePath.c_str());
304 return ERR_OK;
305 }
306
ProcessNativeLibrary(const std::string & bundlePath,const std::string & moduleDir,const std::string & moduleName,const std::string & pluginBundleDir,InnerBundleInfo & newInfo)307 ErrCode PluginInstaller::ProcessNativeLibrary(
308 const std::string &bundlePath,
309 const std::string &moduleDir,
310 const std::string &moduleName,
311 const std::string &pluginBundleDir,
312 InnerBundleInfo &newInfo)
313 {
314 std::string cpuAbi;
315 if (!newInfo.FetchNativeSoAttrs(moduleName, cpuAbi, nativeLibraryPath_)) {
316 return ERR_OK;
317 }
318 isCompressNativeLibs_ = newInfo.IsCompressNativeLibs(moduleName);
319 if (isCompressNativeLibs_) {
320 if (nativeLibraryPath_.empty()) {
321 APP_LOGW("nativeLibraryPath is empty");
322 return ERR_OK;
323 }
324 std::string soPath = pluginBundleDir + ServiceConstants::PATH_SEPARATOR + nativeLibraryPath_;
325 APP_LOGD("tempSoPath=%{public}s,cpuAbi=%{public}s, bundlePath=%{public}s",
326 soPath.c_str(), cpuAbi.c_str(), bundlePath.c_str());
327
328 auto result = InstalldClient::GetInstance()->ExtractModuleFiles(bundlePath, moduleDir, soPath, cpuAbi);
329 CHECK_RESULT(result, "extract module files failed %{public}d");
330 // verify hap or hsp code signature for compressed so files
331 result = VerifyCodeSignatureForNativeFiles(
332 bundlePath, cpuAbi, soPath, signatureFileDir_, newInfo.IsPreInstallApp());
333 CHECK_RESULT(result, "fail to VerifyCodeSignature, error is %{public}d");
334 cpuAbi_ = cpuAbi;
335 soPath_ = soPath;
336 } else {
337 std::vector<std::string> fileNames;
338 auto result = InstalldClient::GetInstance()->GetNativeLibraryFileNames(bundlePath, cpuAbi, fileNames);
339 CHECK_RESULT(result, "fail to GetNativeLibraryFileNames, error is %{public}d");
340 newInfo.SetNativeLibraryFileNames(moduleName, fileNames);
341 }
342 return ERR_OK;
343 }
344
VerifyCodeSignatureForNativeFiles(const std::string & bundlePath,const std::string & cpuAbi,const std::string & targetSoPath,const std::string & signatureFileDir,bool isPreInstalledBundle) const345 ErrCode PluginInstaller::VerifyCodeSignatureForNativeFiles(const std::string &bundlePath,
346 const std::string &cpuAbi, const std::string &targetSoPath, const std::string &signatureFileDir,
347 bool isPreInstalledBundle) const
348 {
349 if (!isPreInstalledBundle) {
350 APP_LOGD("not pre-install app, skip verify code signature for native files");
351 return ERR_OK;
352 }
353 APP_LOGD("begin to verify code signature for hsp native files");
354 bool isCompileSdkOpenHarmony = (compileSdkType_ == COMPILE_SDK_TYPE_OPEN_HARMONY);
355 CodeSignatureParam codeSignatureParam;
356 codeSignatureParam.modulePath = bundlePath;
357 codeSignatureParam.cpuAbi = cpuAbi;
358 codeSignatureParam.targetSoPath = targetSoPath;
359 codeSignatureParam.signatureFileDir = signatureFileDir;
360 codeSignatureParam.isEnterpriseBundle = isEnterpriseBundle_;
361 codeSignatureParam.appIdentifier = appIdentifier_;
362 codeSignatureParam.isCompileSdkOpenHarmony = isCompileSdkOpenHarmony;
363 codeSignatureParam.isPreInstalledBundle = isPreInstalledBundle;
364 codeSignatureParam.isCompressNativeLibrary = isCompressNativeLibs_;
365 if (InstalldClient::GetInstance()->VerifyCodeSignature(codeSignatureParam) != ERR_OK) {
366 return ERR_BUNDLEMANAGER_INSTALL_CODE_SIGNATURE_FAILED;
367 }
368 return ERR_OK;
369 }
370
VerifyCodeSignatureForHsp(const std::string & hspPath,const std::string & appIdentifier,bool isEnterpriseBundle,bool isCompileSdkOpenHarmony) const371 ErrCode PluginInstaller::VerifyCodeSignatureForHsp(const std::string &hspPath,
372 const std::string &appIdentifier, bool isEnterpriseBundle, bool isCompileSdkOpenHarmony) const
373 {
374 APP_LOGD("begin to verify code signature for hsp");
375 CodeSignatureParam codeSignatureParam;
376 codeSignatureParam.modulePath = hspPath;
377 codeSignatureParam.cpuAbi = cpuAbi_;
378 codeSignatureParam.targetSoPath = soPath_;
379 codeSignatureParam.appIdentifier = appIdentifier;
380 codeSignatureParam.signatureFileDir = signatureFileDir_;
381 codeSignatureParam.isEnterpriseBundle = isEnterpriseBundle;
382 codeSignatureParam.isCompileSdkOpenHarmony = isCompileSdkOpenHarmony;
383 codeSignatureParam.isPreInstalledBundle = false;
384 if (InstalldClient::GetInstance()->VerifyCodeSignatureForHap(codeSignatureParam) != ERR_OK) {
385 return ERR_BUNDLEMANAGER_INSTALL_CODE_SIGNATURE_FAILED;
386 }
387 return ERR_OK;
388 }
389
DeliveryProfileToCodeSign(std::vector<Security::Verify::HapVerifyResult> & hapVerifyResults) const390 ErrCode PluginInstaller::DeliveryProfileToCodeSign(
391 std::vector<Security::Verify::HapVerifyResult> &hapVerifyResults) const
392 {
393 if (hapVerifyResults.empty()) {
394 APP_LOGE("no sign info in the all haps");
395 return ERR_APPEXECFWK_INSTALL_FAILED_INCOMPATIBLE_SIGNATURE;
396 }
397
398 Security::Verify::ProvisionInfo provisionInfo = hapVerifyResults[0].GetProvisionInfo();
399 if (provisionInfo.distributionType == Security::Verify::AppDistType::ENTERPRISE ||
400 provisionInfo.distributionType == Security::Verify::AppDistType::ENTERPRISE_NORMAL ||
401 provisionInfo.distributionType == Security::Verify::AppDistType::ENTERPRISE_MDM ||
402 provisionInfo.type == Security::Verify::ProvisionType::DEBUG) {
403 if (provisionInfo.profileBlockLength == 0 || provisionInfo.profileBlock == nullptr) {
404 APP_LOGE("invalid sign profile");
405 return ERR_APPEXECFWK_INSTALL_FAILED_INCOMPATIBLE_SIGNATURE;
406 }
407 return InstalldClient::GetInstance()->DeliverySignProfile(provisionInfo.bundleInfo.bundleName,
408 provisionInfo.profileBlockLength, provisionInfo.profileBlock.get());
409 }
410 return ERR_OK;
411 }
412
CheckPluginId(const std::string & hostBundleName)413 ErrCode PluginInstaller::CheckPluginId(const std::string &hostBundleName)
414 {
415 if (pluginIds_.empty()) {
416 APP_LOGE("plugin id is empty");
417 return ERR_APPEXECFWK_PLUGIN_INSTALL_CHECK_PLUGINID_ERROR;
418 }
419 auto appProvisionInfoMgr = DelayedSingleton<AppProvisionInfoManager>::GetInstance();
420 if (!appProvisionInfoMgr) {
421 APP_LOGE("appProvisionInfoMgr is nullptr");
422 return ERR_APPEXECFWK_NULL_PTR;
423 }
424 AppProvisionInfo hostAppProvisionInfo;
425 if (!appProvisionInfoMgr->GetAppProvisionInfo(hostBundleName, hostAppProvisionInfo)) {
426 APP_LOGW("bundleName:%{public}s GetAppProvisionInfo failed", hostBundleName.c_str());
427 return ERR_BUNDLE_MANAGER_INTERNAL_ERROR;
428 }
429 std::vector<std::string> hostPluginIds;
430 if (!ParsePluginId(hostAppProvisionInfo.appServiceCapabilities, hostPluginIds)) {
431 APP_LOGE("parse host application plugin id failed");
432 return ERR_APPEXECFWK_PLUGIN_INSTALL_PARSE_PLUGINID_ERROR;
433 }
434 if (hostPluginIds.empty()) {
435 APP_LOGE("host application plugin id is empty");
436 return ERR_APPEXECFWK_PLUGIN_INSTALL_CHECK_PLUGINID_ERROR;
437 }
438 std::unordered_set<std::string> pluginIdSet(hostPluginIds.begin(), hostPluginIds.end());
439 for (const auto &item : pluginIds_) {
440 if (pluginIdSet.find(item) != pluginIdSet.end()) {
441 return ERR_OK;
442 }
443 }
444 APP_LOGD("check plugin id success");
445 return ERR_APPEXECFWK_PLUGIN_INSTALL_CHECK_PLUGINID_ERROR;
446 }
447
ParsePluginId(const std::string & appServiceCapabilities,std::vector<std::string> & pluginIds)448 bool PluginInstaller::ParsePluginId(const std::string &appServiceCapabilities,
449 std::vector<std::string> &pluginIds)
450 {
451 if (appServiceCapabilities.empty()) {
452 APP_LOGE("appServiceCapabilities is empty");
453 return false;
454 }
455 auto appServiceCapabilityMap = BundleUtil::ParseMapFromJson(appServiceCapabilities);
456 for (auto &item : appServiceCapabilityMap) {
457 if (item.first == PERMISSION_KEY) {
458 auto pluginIdMap = BundleUtil::ParseMapFromJson(item.second);
459 if (pluginIdMap.find(PLUGIN_ID) == pluginIdMap.end()) {
460 APP_LOGE("pluginDistributionIDs not found in appServiceCapability");
461 return false;
462 }
463 OHOS::SplitStr(pluginIdMap.at(PLUGIN_ID), PLUGIN_ID_SEPARATOR, pluginIds);
464 return true;
465 }
466 }
467 APP_LOGE("support plugin permission not found in appServiceCapability");
468 return false;
469 }
470
CheckSupportPluginPermission(const InnerBundleInfo & hostBundleInfo)471 ErrCode PluginInstaller::CheckSupportPluginPermission(const InnerBundleInfo &hostBundleInfo)
472 {
473 std::vector<RequestPermission> reqPermissions = hostBundleInfo.GetAllRequestPermissions();
474 auto it = std::find_if(reqPermissions.begin(), reqPermissions.end(), [](const RequestPermission &permission) {
475 return permission.name == ServiceConstants::PERMISSION_SUPPORT_PLUGIN;
476 });
477 if (it == reqPermissions.end()) {
478 APP_LOGE("bundleName:%{public}s check support permission failed", hostBundleInfo.GetBundleName().c_str());
479 return ERR_APPEXECFWK_SUPPORT_PLUGIN_PERMISSION_ERROR;
480 }
481 return ERR_OK;
482 }
483
CheckPluginAppLabelInfo()484 ErrCode PluginInstaller::CheckPluginAppLabelInfo()
485 {
486 if (parsedBundles_.empty()) {
487 APP_LOGE("parsedBundles is empty");
488 return ERR_OK;
489 }
490 bundleName_ = parsedBundles_.begin()->second.GetBundleName();
491
492 ErrCode ret = bundleInstallChecker_->CheckAppLabelInfo(parsedBundles_);
493 if (ret != ERR_OK) {
494 APP_LOGE("check plugin app label info failed");
495 return ERR_APPEXECFWK_PLUGIN_CHECK_APP_LABEL_ERROR;
496 }
497 return ERR_OK;
498 }
499
ProcessPluginInstall(const InnerBundleInfo & hostBundleInfo)500 ErrCode PluginInstaller::ProcessPluginInstall(const InnerBundleInfo &hostBundleInfo)
501 {
502 if (parsedBundles_.empty()) {
503 APP_LOGD("no bundle to install");
504 return ERR_OK;
505 }
506 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
507 if (!dataMgr) {
508 APP_LOGE("Get dataMgr shared_ptr nullptr");
509 return ERR_APPEXECFWK_NULL_PTR;
510 }
511 ErrCode result = ERR_OK;
512 std::string pluginDir;
513 result = CheckPluginDir(hostBundleInfo.GetBundleName(), pluginDir);
514 CHECK_RESULT(result, "plugin dir check failed %{public}d");
515 isPluginExist_ = dataMgr->GetPluginBundleInfo(hostBundleInfo.GetBundleName(), bundleName_, oldPluginInfo_);
516 if (isPluginExist_) {
517 if (!CheckAppIdentifier()) {
518 return ERR_APPEXECFWK_INSTALL_FAILED_INCONSISTENT_SIGNATURE;
519 }
520 if (!CheckVersionCodeForUpdate()) {
521 return ERR_APPEXECFWK_INSTALL_VERSION_DOWNGRADE;
522 }
523 }
524 ScopeGuard deleteDirGuard([&] { RemovePluginDir(hostBundleInfo);});
525 for (auto &item : parsedBundles_) {
526 result = ExtractPluginBundles(item.first, item.second, pluginDir);
527 CHECK_RESULT(result, "extract plugin bundles failed %{public}d");
528 }
529
530 ScopeGuard dataRollBackGuard([&] { PluginRollBack(hostBundleInfo);});
531 InnerBundleInfo pluginInfo;
532 MergePluginBundleInfo(pluginInfo);
533 result = SavePluginInfoToStorage(pluginInfo, hostBundleInfo);
534 CHECK_RESULT(result, "save plugin info to storage failed %{public}d");
535
536 RemoveEmptyDirs(pluginDir);
537 RemoveOldInstallDir();
538 deleteDirGuard.Dismiss();
539 dataRollBackGuard.Dismiss();
540 APP_LOGD("install plugin bundle successfully: %{public}s", bundleName_.c_str());
541 return result;
542 }
543
CheckPluginDir(const std::string & hostBundleName,std::string & pluginDir)544 ErrCode PluginInstaller::CheckPluginDir(const std::string &hostBundleName, std::string &pluginDir)
545 {
546 ErrCode result = ERR_OK;
547 std::string bundleDir = std::string(Constants::BUNDLE_CODE_DIR) + ServiceConstants::PATH_SEPARATOR + hostBundleName;
548 result = MkdirIfNotExist(bundleDir);
549 CHECK_RESULT(result, "check bundle dir failed %{public}d");
550
551 pluginDir = bundleDir + ServiceConstants::PATH_SEPARATOR + PLUGINS;
552 result = MkdirIfNotExist(pluginDir);
553 CHECK_RESULT(result, "check plugin dir failed %{public}d");
554
555 return result;
556 }
557
CheckAppIdentifier() const558 bool PluginInstaller::CheckAppIdentifier() const
559 {
560 auto &newInfo = parsedBundles_.begin()->second;
561 if (!newInfo.GetAppIdentifier().empty() &&
562 !oldPluginInfo_.appIdentifier.empty() &&
563 newInfo.GetAppIdentifier() == oldPluginInfo_.appIdentifier) {
564 return true;
565 }
566 if (oldPluginInfo_.appId == newInfo.GetAppId()) {
567 return true;
568 }
569 APP_LOGE("the appIdentifier or appId of the new bundle is not the same as old one");
570 return false;
571 }
572
CheckVersionCodeForUpdate() const573 bool PluginInstaller::CheckVersionCodeForUpdate() const
574 {
575 auto &newInfo = parsedBundles_.begin()->second;
576 if (newInfo.GetVersionCode() < oldPluginInfo_.versionCode) {
577 APP_LOGE("fail to update lower version plugin");
578 return false;
579 }
580 return true;
581 }
582
ExtractPluginBundles(const std::string & bundlePath,InnerBundleInfo & newInfo,const std::string & pluginDir)583 ErrCode PluginInstaller::ExtractPluginBundles(const std::string &bundlePath, InnerBundleInfo &newInfo,
584 const std::string &pluginDir)
585 {
586 ErrCode result = ERR_OK;
587 std::string pluginBundleDir = pluginDir + ServiceConstants::PATH_SEPARATOR + bundleNameWithTime_; // pass pluginDir
588 result = MkdirIfNotExist(pluginBundleDir);
589 CHECK_RESULT(result, "check plugin bundle dir failed %{public}d");
590 newInfo.SetAppCodePath(pluginBundleDir);
591
592 auto &moduleName = newInfo.GetInnerModuleInfos().begin()->second.moduleName;
593 std::string moduleDir = pluginBundleDir + ServiceConstants::PATH_SEPARATOR + moduleName;
594 result = MkdirIfNotExist(moduleDir);
595 CHECK_RESULT(result, "check module dir failed %{public}d");
596
597 result = ProcessNativeLibrary(bundlePath, moduleDir, moduleName, pluginBundleDir, newInfo);
598 CHECK_RESULT(result, "ProcessNativeLibrary failed %{public}d");
599
600 // save hsp and so files to installation dir
601 result = SaveHspToInstallDir(bundlePath, pluginBundleDir, moduleName, newInfo);
602 CHECK_RESULT(result, "save hsp file failed %{public}d");
603
604 newInfo.AddModuleSrcDir(moduleDir);
605 newInfo.AddModuleResPath(moduleDir);
606 return ERR_OK;
607 }
608
MergePluginBundleInfo(InnerBundleInfo & pluginBundleInfo)609 void PluginInstaller::MergePluginBundleInfo(InnerBundleInfo &pluginBundleInfo)
610 {
611 auto iter = parsedBundles_.begin();
612 pluginBundleInfo = iter->second;
613 InnerBundleUserInfo newInnerBundleUserInfo;
614 newInnerBundleUserInfo.bundleName = bundleName_;
615 newInnerBundleUserInfo.bundleUserInfo.userId = userId_;
616 pluginBundleInfo.AddInnerBundleUserInfo(newInnerBundleUserInfo);
617 iter++;
618
619 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
620 if (dataMgr == nullptr) {
621 APP_LOGE("Get dataMgr shared_ptr nullptr");
622 return;
623 }
624 for (; iter != parsedBundles_.end(); ++iter) {
625 InnerBundleInfo ¤tInfo = iter->second;
626 dataMgr->AddNewModuleInfo(currentInfo, pluginBundleInfo);
627 }
628 }
629
SavePluginInfoToStorage(const InnerBundleInfo & pluginInfo,const InnerBundleInfo & hostBundleInfo)630 ErrCode PluginInstaller::SavePluginInfoToStorage(const InnerBundleInfo &pluginInfo,
631 const InnerBundleInfo &hostBundleInfo)
632 {
633 ErrCode result = ERR_OK;
634 PluginBundleInfo pluginBundleInfo;
635 pluginInfo.GetPluginBundleInfo(bundleNameWithTime_, pluginBundleInfo);
636
637 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
638 if (dataMgr == nullptr) {
639 APP_LOGE("get dataMgr failed");
640 return ERR_APPEXECFWK_NULL_PTR;
641 }
642 if (isPluginExist_) {
643 hostBundleInfo.GetPluginInstalledUser(bundleName_, hasInstalledUsers_);
644 }
645 std::unordered_set<int32_t> userIds(hasInstalledUsers_);
646 userIds.insert(userId_);
647 for (const auto &userId : userIds) {
648 result = dataMgr->AddPluginInfo(hostBundleInfo, pluginBundleInfo, userId);
649 if (result != ERR_OK) {
650 APP_LOGE("save pluginInfo to storage failed %{public}d, userId:%{public}d",
651 result, userId);
652 return result;
653 }
654 }
655 APP_LOGI("save pluginInfo:%{public}s success", bundleName_.c_str());
656 return ERR_OK;
657 }
658
PluginRollBack(const InnerBundleInfo & hostBundleInfo)659 void PluginInstaller::PluginRollBack(const InnerBundleInfo &hostBundleInfo)
660 {
661 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
662 if (dataMgr == nullptr) {
663 APP_LOGE("get dataMgr failed");
664 return;
665 }
666 if (!isPluginExist_) {
667 //rollback database
668 ErrCode err = dataMgr->RemovePluginInfo(hostBundleInfo, bundleName_, userId_);
669 if (err != ERR_OK) {
670 APP_LOGW("plugin:%{public}s clean PluginInfo failed", bundleName_.c_str());
671 }
672 return;
673 }
674 // for update
675 for (const auto &userId : hasInstalledUsers_) {
676 ErrCode err = dataMgr->AddPluginInfo(hostBundleInfo, oldPluginInfo_, userId);
677 if (err != ERR_OK) {
678 APP_LOGW("save old pluginInfo failed %{public}d, userId:%{public}d",
679 err, userId);
680 }
681 }
682 // current user has not install plugin before update, need to remove
683 if (hasInstalledUsers_.find(userId_) == hasInstalledUsers_.end()) {
684 ErrCode err = dataMgr->RemovePluginInfo(hostBundleInfo, bundleName_, userId_);
685 if (err != ERR_OK) {
686 APP_LOGW("plugin:%{public}s clean PluginInfo failed", bundleName_.c_str());
687 }
688 }
689 }
690
RemovePluginDir(const InnerBundleInfo & hostBundleInfo)691 ErrCode PluginInstaller::RemovePluginDir(const InnerBundleInfo &hostBundleInfo)
692 {
693 std::string pluginDir = hostBundleInfo.GetAppCodePath() + ServiceConstants::PATH_SEPARATOR + PLUGINS;
694 std::string pluginBundleDir = pluginDir + ServiceConstants::PATH_SEPARATOR + bundleNameWithTime_;
695 ErrCode err = InstalldClient::GetInstance()->RemoveDir(pluginBundleDir);
696 if (err != ERR_OK) {
697 APP_LOGW("remove dir of %{public}s failed: %{public}s", bundleName_.c_str(), pluginBundleDir.c_str());
698 return err;
699 }
700 return ERR_OK;
701 }
702
RemovePluginInfo(const InnerBundleInfo & hostBundleInfo)703 ErrCode PluginInstaller::RemovePluginInfo(const InnerBundleInfo &hostBundleInfo)
704 {
705 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
706 if (dataMgr == nullptr) {
707 APP_LOGE("get dataMgr failed");
708 return ERR_APPEXECFWK_NULL_PTR;
709 }
710 ErrCode err = dataMgr->RemovePluginInfo(hostBundleInfo, bundleName_, userId_);
711 if (err != ERR_OK) {
712 APP_LOGW("plugin:%{public}s clean PluginInfo failed", bundleName_.c_str());
713 return err;
714 }
715 return ERR_OK;
716 }
717
SaveHspToInstallDir(const std::string & bundlePath,const std::string & pluginBundleDir,const std::string & moduleName,InnerBundleInfo & newInfo)718 ErrCode PluginInstaller::SaveHspToInstallDir(const std::string &bundlePath,
719 const std::string &pluginBundleDir,
720 const std::string &moduleName,
721 InnerBundleInfo &newInfo)
722 {
723 ErrCode result = ERR_OK;
724 std::string hspPath = pluginBundleDir + ServiceConstants::PATH_SEPARATOR + moduleName +
725 ServiceConstants::HSP_FILE_SUFFIX;
726 if (!signatureFileDir_.empty()) {
727 result = InstalldClient::GetInstance()->CopyFile(bundlePath, hspPath, signatureFileDir_);
728 CHECK_RESULT(result, "copy hsp to install dir failed %{public}d");
729 } else {
730 result = InstalldClient::GetInstance()->MoveHapToCodeDir(bundlePath, hspPath);
731 CHECK_RESULT(result, "move hsp to install dir failed %{public}d");
732 bool isCompileSdkOpenHarmony = (compileSdkType_ == COMPILE_SDK_TYPE_OPEN_HARMONY);
733 result = VerifyCodeSignatureForHsp(hspPath, appIdentifier_, isEnterpriseBundle_,
734 isCompileSdkOpenHarmony);
735 }
736 newInfo.SetModuleHapPath(hspPath);
737
738 FILE *hspFp = fopen(hspPath.c_str(), "r");
739 if (hspFp == nullptr) {
740 APP_LOGE("fopen %{public}s failed", hspPath.c_str());
741 } else {
742 int32_t hspFd = fileno(hspFp);
743 if (hspFd < 0) {
744 APP_LOGE("open %{public}s failed", hspPath.c_str());
745 } else if (fsync(hspFd) != 0) {
746 APP_LOGE("fsync %{public}s failed", hspPath.c_str());
747 }
748 fclose(hspFp);
749 }
750 CHECK_RESULT(result, "verify code signature failed %{public}d");
751 return ERR_OK;
752 }
753
RemoveEmptyDirs(const std::string & pluginDir) const754 void PluginInstaller::RemoveEmptyDirs(const std::string &pluginDir) const
755 {
756 for (auto &item : parsedBundles_) {
757 std::string moduleDir = pluginDir + ServiceConstants::PATH_SEPARATOR + bundleNameWithTime_
758 + ServiceConstants::PATH_SEPARATOR + item.second.GetCurModuleName();
759 bool isEmpty = false;
760 InstalldClient::GetInstance()->IsDirEmpty(moduleDir, isEmpty);
761 if (isEmpty) {
762 APP_LOGD("remove empty dir : %{public}s", moduleDir.c_str());
763 RemoveDir(moduleDir);
764 }
765 }
766 }
767
RemoveDir(const std::string & dir) const768 void PluginInstaller::RemoveDir(const std::string &dir) const
769 {
770 auto result = InstalldClient::GetInstance()->RemoveDir(dir);
771 if (result != ERR_OK) {
772 APP_LOGW("remove dir %{public}s failed, error is %{public}d", dir.c_str(), result);
773 }
774 }
775
ProcessPluginUninstall(const InnerBundleInfo & hostBundleInfo)776 ErrCode PluginInstaller::ProcessPluginUninstall(const InnerBundleInfo &hostBundleInfo)
777 {
778 ErrCode result = ERR_OK;
779 bool isMultiUser = hostBundleInfo.HasMultiUserPlugin(bundleName_);
780 ScopeGuard removeDataGuard([&] { UninstallRollBack(hostBundleInfo); });
781 result = RemovePluginInfo(hostBundleInfo);
782 if (result != ERR_OK) {
783 APP_LOGE("bundleName:%{public}s remove plugin:%{public}s info failed",
784 hostBundleInfo.GetBundleName().c_str(), bundleName_.c_str());
785 return ERR_APPEXECFWK_REMOVE_PLUGIN_INFO_ERROR;
786 }
787 removeDataGuard.Dismiss();
788 if (!isMultiUser) {
789 std::string pluginBundleDir = GetPluginBundleDir();
790 std::string deleteDir = pluginBundleDir + REMOVE_TMP_SUFFIX;
791 if (!BundleUtil::RenameFile(pluginBundleDir, deleteDir)) {
792 APP_LOGW("rename failed, %{public}s -> %{public}s", pluginBundleDir.c_str(), deleteDir.c_str());
793 result = InstalldClient::GetInstance()->RemoveDir(pluginBundleDir);
794 } else {
795 result = InstalldClient::GetInstance()->RemoveDir(deleteDir);
796 }
797 if (result != ERR_OK) {
798 APP_LOGW("bundleName:%{public}s remove plugin:%{public}s dir failed",
799 hostBundleInfo.GetBundleName().c_str(), bundleName_.c_str());
800 }
801 InstalldClient::GetInstance()->RemoveSignProfile(bundleName_);
802 }
803 return ERR_OK;
804 }
805
GetPluginBundleDir()806 std::string PluginInstaller::GetPluginBundleDir()
807 {
808 for (const auto &item : oldPluginInfo_.pluginModuleInfos) {
809 if (!item.hapPath.empty()) {
810 auto pos = item.hapPath.rfind(ServiceConstants::PATH_SEPARATOR);
811 if (pos != std::string::npos) {
812 return item.hapPath.substr(0, pos);
813 }
814 }
815 }
816 return "";
817 }
818
RemoveOldInstallDir()819 void PluginInstaller::RemoveOldInstallDir()
820 {
821 if (!isPluginExist_) {
822 return;
823 }
824 std::string path = GetPluginBundleDir();
825 RemoveDir(path);
826 APP_LOGI("remove old install dir:%{public}s", path.c_str());
827 }
828
UninstallRollBack(const InnerBundleInfo & hostBundleInfo)829 void PluginInstaller::UninstallRollBack(const InnerBundleInfo &hostBundleInfo)
830 {
831 auto dataMgr = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
832 if (dataMgr == nullptr) {
833 APP_LOGE("get dataMgr failed");
834 return;
835 }
836 ErrCode err = dataMgr->AddPluginInfo(hostBundleInfo, oldPluginInfo_, userId_);
837 if (err != ERR_OK) {
838 APP_LOGW("save old pluginInfo failed %{public}d, userId:%{public}d", err, userId_);
839 }
840 }
841 } // AppExecFwk
842 } // OHOS