• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &currentInfo = 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