OpenHarmony系统hap包单例属性校验 原创

软通动力HOS
发布于 2023-4-6 09:28
浏览
1收藏

OpenHarmony 3.1系统启动是只有少数系统服务启动起来,但是有大部分服务无法启动,究其原因是hap包配置文件中服务单例属性未设置,默认为非单例启动属性。
hap包中module.json如下:

{
"app": {
"apiReleaseType": "Canary1",
"bundleName": "com.ohos.launcher",
"debug": true,
"distributedNotificationEnabled": true,
"icon": "$media:app_icon",
"iconId": 16777217,
"keepAlive": true,
"label": "$string:app_name",
"labelId": 16777216,
"minAPIVersion": 9,
"singleton": true,
"targetAPIVersion": 9,
"vendor": "ohos",
"versionCode": 1000000,
"versionName": "1.0.0"
},
"module": {
"deliveryWithInstall": true,
"description": "$string:mainability_description",
"descriptionId": 16777250,
"deviceTypes": ["phone"],
"extensionAbilities": [{
"description": "$string:mainability_description",
"descriptionId": 16777250,
"icon": "$media:icon",
"iconId": 16777264,
"label": "$string:entry_MainAbility",
"labelId": 16777240,
"name": "com.ohos.launcher.MainAbility",
"skills": [{
"actions": ["action.system.home", "com.ohos.action.main"],
"entities": ["entity.system.home", "flag.home.intent.from.system"]
}],
"srcEntrance": "./ets/MainAbility/MainAbility.ts",
"type": "service",
"visible": false
}, {
"name": "com.ohos.launcher.PowerManagerAbility",
"srcEntrance": "./ets/PowerManagerAbility/PowerManagerAbility.ts",
"type": "service",
"visible": true
}],
"installationFree": false,
"mainElement": "com.ohos.launcher.MainAbility",
"name": "phone-launcher",
"pages": "$profile:main_pages",
"requestPermissions": [{
"name": "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED"
}, {
"name": "ohos.permission.INSTALL_BUNDLE"
}, {
"name": "ohos.permission.LISTEN_BUNDLE_CHANGE"
}, {
"name": "ohos.permission.MANAGE_MISSIONS"
}, {
"name": "ohos.permission.REQUIRE_FORM"
}, {
"name": "ohos.permission.INPUT_MONITORING"
}, {
"name": "ohos.permission.INSTALL_BUNDLE"
}, {
"name": "ohos.permission.REMOVE_CACHE_FILES"
}, {
"name": "ohos.permission.REBOOT"
}],
"srcEntrance": "./ets/Application/AbilityStage.ts",
"type": "entry",
"uiSyntax": "ets",
"virtualMachine": "ark"
}
}

其单例属性singleton必须设置为true才可以校验通过。
烧录系统镜像后首次启动时在指定目录/system/app目录下扫描所有hap包并安装到系统,安装逻辑详见foundation/appexecfwk/standard/services/bundlemgr/src/bundle_mgr_service_event_handler.cpp代码:

{
APP_LOGD("scan thread start ");
auto scanner = std::make_unique<BundleScanner>();
if (!scanner) {
APP_LOGE("make scanner failed");
return;
}
std::string scanDir = (appType == Constants::AppType::SYSTEM_APP) ? Constants::SYSTEM_APP_SCAN_PATH
: Constants::THIRD_SYSTEM_APP_SCAN_PATH;
APP_LOGD("scanDir: %{public}s and userId: %{public}d", scanDir.c_str(), userId);
std::list<std::string> bundleList = scanner->Scan(scanDir);
auto iter = std::find(bundleList.begin(), bundleList.end(), Constants::SYSTEM_RESOURCES_APP_PATH);
if (iter != bundleList.end()) {
bundleList.erase(iter);
bundleList.insert(bundleList.begin(), Constants::SYSTEM_RESOURCES_APP_PATH);
}
for (const auto &item : bundleList) {
SystemBundleInstaller installer(item);
APP_LOGD("scan item ------------------------------------>>>%{public}s", item.c_str());
if (!installer.InstallSystemBundle(appType, userId)) {
APP_LOGW("Install System app:%{public}s error", item.c_str());
}
}
PerfProfile::GetInstance().Dump();
}

调用至foundation/appexecfwk/standard/services/bundlemgr/src/base_bundle_installer.cpp

const std::vector<std::string> &bundlePaths, const InstallParam &installParam, const Constants::AppType appType)
{
BYTRACE_NAME(BYTRACE_TAG_APP, __PRETTY_FUNCTION__);
APP_LOGD("begin to process bundle install --------------------------->>>");
PerfProfile::GetInstance().SetBundleInstallStartTime(GetTickCount());
int32_t uid = Constants::INVALID_UID;
ErrCode result = ProcessBundleInstall(bundlePaths, installParam, appType, uid);
if (installParam.needSendEvent && dataMgr_ && !bundleName_.empty()) {
dataMgr_->NotifyBundleStatus(bundleName_,
Constants::EMPTY_STRING,
mainAbility_,
result,
isAppExist_ ? NotifyType::UPDATE : NotifyType::INSTALL,
uid);
}
PerfProfile::GetInstance().SetBundleInstallEndTime(GetTickCount());
APP_LOGD("finish to process bundle install");
return result;
}
ErrCode BaseBundleInstaller::ProcessBundleInstall(const std::vector<std::string> &inBundlePaths,
const InstallParam &installParam, const Constants::AppType appType, int32_t &uid)
{
APP_LOGD("ProcessBundleInstall bundlePath install");
if (!dataMgr_) {
dataMgr_ = DelayedSingleton<BundleMgrService>::GetInstance()->GetDataMgr();
if (!dataMgr_) {
APP_LOGE("Get dataMgr shared_ptr nullptr");
return ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR;
}
}
userId_ = GetUserId(installParam);
if (userId_ == Constants::INVALID_USERID) {
return ERR_APPEXECFWK_INSTALL_PARAM_ERROR;
}
if (!dataMgr_->HasUserId(userId_)) {
APP_LOGE("The user %{public}d does not exist when install.", userId_);
return ERR_APPEXECFWK_USER_NOT_EXIST;
}
std::vector<std::string> bundlePaths;
// check hap paths
ErrCode result = BundleUtil::CheckFilePath(inBundlePaths, bundlePaths);
CHECK_RESULT_WITHOUT_ROLLBACK(result, "hap file check failed %{public}d");
UpdateInstallerState(InstallerState::INSTALL_BUNDLE_CHECKED);                  // ---- 5%
// check syscap
result = CheckSysCap(bundlePaths);
CHECK_RESULT_WITHOUT_ROLLBACK(result, "hap syscap check failed %{public}d");
UpdateInstallerState(InstallerState::INSTALL_SYSCAP_CHECKED);                  // ---- 10%
// verify signature info for all haps
std::vector<Security::Verify::HapVerifyResult> hapVerifyResults;
result = CheckMultipleHapsSignInfo(bundlePaths, installParam, hapVerifyResults);
CHECK_RESULT_WITHOUT_ROLLBACK(result, "hap files check signature info failed %{public}d");
UpdateInstallerState(InstallerState::INSTALL_SIGNATURE_CHECKED);               // ---- 15%
result = ModifyInstallDirByHapType(installParam, appType);
CHECK_RESULT_WITHOUT_ROLLBACK(result, "modify bundle install dir failed %{public}d");
// parse the bundle infos for all haps
// key is bundlePath , value is innerBundleInfo
std::unordered_map<std::string, InnerBundleInfo> newInfos;
result = ParseHapFiles(bundlePaths, installParam, appType, hapVerifyResults, newInfos);
CHECK_RESULT_WITHOUT_ROLLBACK(result, "parse haps file failed %{public}d");
UpdateInstallerState(InstallerState::INSTALL_PARSED);                          // ---- 20%
// check versioncode and bundleName
result = CheckAppLabelInfo(newInfos);
CHECK_RESULT_WITHOUT_ROLLBACK(result, "verisoncode or bundleName is different in all haps %{public}d");
UpdateInstallerState(InstallerState::INSTALL_VERSION_AND_BUNDLENAME_CHECKED);  // ---- 30%
// this state should always be set when return
ScopeGuard stateGuard([&] { dataMgr_->UpdateBundleInstallState(bundleName_, InstallState::INSTALL_SUCCESS); });
// this state should always be set when return
ScopeGuard enableGuard([&] { dataMgr_->EnableBundle(bundleName_); });
InnerBundleInfo oldInfo;
result = InnerProcessBundleInstall(newInfos, oldInfo, installParam, uid);
CHECK_RESULT_WITH_ROLLBACK(result, "internal processing failed with result %{public}d", newInfos, oldInfo);
UpdateInstallerState(InstallerState::INSTALL_INFO_SAVED);                      // ---- 80%
// rename for all temp dirs
for (const auto &info : newInfos) {
if (info.second.IsOnlyCreateBundleUser()) {
continue;
}
if ((result = RenameModuleDir(info.second)) != ERR_OK) {
break;
}
}
UpdateInstallerState(InstallerState::INSTALL_RENAMED);                         // ---- 90%
CHECK_RESULT_WITH_ROLLBACK(result, "rename temp dirs failed with result %{public}d", newInfos, oldInfo);
if (!uninstallModuleVec_.empty()) {
UninstallLowerVersionFeature(uninstallModuleVec_);
}
UpdateInstallerState(InstallerState::INSTALL_SUCCESS);                         // ---- 100%
APP_LOGD("finish ProcessBundleInstall bundlePath install");
return result;
}
ErrCode BaseBundleInstaller::InnerProcessBundleInstall(std::unordered_map<std::string, InnerBundleInfo> &newInfos,
InnerBundleInfo &oldInfo, const InstallParam &installParam, int32_t &uid)
{
BYTRACE_NAME(BYTRACE_TAG_APP, __PRETTY_FUNCTION__);
bundleName_ = newInfos.begin()->second.GetBundleName();
APP_LOGI("InnerProcessBundleInstall with bundleName %{public}s, userId is %{public}d", bundleName_.c_str(),
userId_);
if (installParam.needSavePreInstallInfo) {
PreInstallBundleInfo preInstallBundleInfo;
dataMgr_->GetPreInstallBundleInfo(bundleName_, preInstallBundleInfo);
preInstallBundleInfo.SetAppType(newInfos.begin()->second.GetAppType());
preInstallBundleInfo.SetVersionCode(newInfos.begin()->second.GetVersionCode());
for (const auto &item : newInfos) {
preInstallBundleInfo.AddBundlePath(item.first);
}
dataMgr_->SavePreInstallBundleInfo(bundleName_, preInstallBundleInfo);
}
// singleton app can only be installed in U0 and U0 can only install singleton app.
bool isSingleton = newInfos.begin()->second.IsSingleUser();
if ((isSingleton && (userId_ != Constants::DEFAULT_USERID)) ||
(!isSingleton && (userId_ == Constants::DEFAULT_USERID))) {
APP_LOGI("singleton(%{public}d) app(%{public}s) and user(%{public}d) are not matched.",
isSingleton, bundleName_.c_str(), userId_);
return ERR_APPEXECFWK_INSTALL_ZERO_USER_WITH_NO_SINGLETON;
}
// try to get the bundle info to decide use install or update. Always keep other exceptions below this line.
if (!GetInnerBundleInfo(oldInfo, isAppExist_)) {
return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR;
}
if (isAppExist_) {
for (const auto &item : newInfos) {
if (oldInfo.GetIsNewVersion() != item.second.GetIsNewVersion()) {
return ERR_APPEXECFWK_INSTALL_STATE_ERROR;
}
}
}
ErrCode result = ERR_OK;
if (isAppExist_) {
// to guarantee that the hap version can be compatible.
result = CheckVersionCompatibility(oldInfo);
if (result != ERR_OK) {
APP_LOGE("The app has been installed and update lower version bundle.");
return result;
}
hasInstalledInUser_ = oldInfo.HasInnerBundleUserInfo(userId_);
if (!hasInstalledInUser_) {
APP_LOGD("new userInfo with bundleName %{public}s and userId %{public}d",
bundleName_.c_str(), userId_);
InnerBundleUserInfo newInnerBundleUserInfo;
newInnerBundleUserInfo.bundleUserInfo.userId = userId_;
newInnerBundleUserInfo.bundleName = bundleName_;
oldInfo.AddInnerBundleUserInfo(newInnerBundleUserInfo);
uint32_t tokenId = CreateAccessTokenId(oldInfo);
oldInfo.SetAccessTokenId(tokenId, userId_);
result = GrantRequestPermissions(oldInfo, tokenId);
if (result != ERR_OK) {
return result;
}
result = CreateBundleUserData(oldInfo, false);
if (result != ERR_OK) {
return result;
}
}
for (auto &info : newInfos) {
std::string packageName = info.second.GetCurrentModulePackage();
if (oldInfo.FindModule(packageName)) {
installedModules_[packageName] = true;
}
}
}
auto it = newInfos.begin();
if (!isAppExist_) {
APP_LOGI("app is not exist");
InnerBundleInfo &newInfo = it->second;
if (newInfo.IsSingleUser() && (userId_ != Constants::DEFAULT_USERID)) {
APP_LOGE("singleton app(%{public}s) must be installed in user 0.", bundleName_.c_str());
return ERR_APPEXECFWK_INSTALL_ZERO_USER_WITH_NO_SINGLETON;
}
modulePath_ = it->first;
InnerBundleUserInfo newInnerBundleUserInfo;
newInnerBundleUserInfo.bundleUserInfo.userId = userId_;
newInnerBundleUserInfo.bundleName = bundleName_;
newInfo.AddInnerBundleUserInfo(newInnerBundleUserInfo);
result = ProcessBundleInstallStatus(newInfo, uid);
if (result != ERR_OK) {
return result;
}
it++;
hasInstalledInUser_ = true;
}
InnerBundleInfo bundleInfo;
bool isBundleExist = false;
if (!GetInnerBundleInfo(bundleInfo, isBundleExist) || !isBundleExist) {
return ERR_APPEXECFWK_INSTALL_BUNDLE_MGR_SERVICE_ERROR;
}
InnerBundleUserInfo innerBundleUserInfo;
if (!bundleInfo.GetInnerBundleUserInfo(userId_, innerBundleUserInfo)) {
APP_LOGE("oldInfo do not have user");
return ERR_APPEXECFWK_USER_NOT_EXIST;
}
// update haps
for (; it != newInfos.end(); ++it) {
modulePath_ = it->first;
InnerBundleInfo &newInfo = it->second;
newInfo.AddInnerBundleUserInfo(innerBundleUserInfo);
bool isReplace = (installParam.installFlag == InstallFlag::REPLACE_EXISTING);
// app exist, but module may not
if ((result = ProcessBundleUpdateStatus(
bundleInfo, newInfo, isReplace, installParam.noSkipsKill)) != ERR_OK) {
break;
}
}
uid = bundleInfo.GetUid(userId_);
mainAbility_ = bundleInfo.GetMainAbility();
return result;
}

InnerProcessBundleInstall函数中校验单例属性,如果是单例属性必须是默认用户或者不是单例属性非默认用户才能正常安装,否则安装异常返回ERR_APPEXECFWK_INSTALL_ZERO_USER_WITH_NO_SINGLETON错误码:

bool isSingleton = newInfos.begin()->second.IsSingleUser();
if ((isSingleton && (userId_ != Constants::DEFAULT_USERID)) ||
(!isSingleton && (userId_ == Constants::DEFAULT_USERID))) {
APP_LOGI("singleton(%{public}d) app(%{public}s) and user(%{public}d) are not matched.",
isSingleton, bundleName_.c_str(), userId_);
return ERR_APPEXECFWK_INSTALL_ZERO_USER_WITH_NO_SINGLETON;
}

见日志:

01-01 00:00:10.163   329  1789 I 01120/BundleMgrService: [base_bundle_installer.cpp(InnerProcessBundleInstall):190] singleton(0) app(com.ohos.launcher) and user(0) are not matched.
01-01 00:00:10.163   329  1789 E 01120/BundleMgrService: [base_bundle_installer.cpp(ProcessBundleInstall):372] internal processing failed with result 8519710

解决方法:
1.系统hap打包时singleton设置为true.
2.注释singleton校验为临时验证方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
3
收藏 1
回复
举报
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

尝试设置一下单例属性

回复
2023-4-6 10:24:00
亲亲子袊
亲亲子袊

具体在哪里如何设置呢?

回复
2023-7-21 15:33:36
NL_AIDC_XJS
NL_AIDC_XJS

系统hap打包时singleton设置为true.这个设置的文件在哪里

回复
2024-1-31 10:40:35
回复
    相关推荐