Bundle Manager Service
负责安装、卸载应用程序,以及管理bundle信息。
鸿蒙系统的安装包模块包括:bundle_daemon、bundlems、bm、API。
bundle_daemon
是安装包模块的守护进程,由init进程在设备启动的时候拉起。
bundlems
是运行在foundation进程里面的系统服务,也就是安装包管理服务。
bm
是系统提供的命令行工具,用于安装、卸载应用程序,以及获取bundle信息。
API
封装IPC调用逻辑,供应用程序调用,操作安装程序、卸载程序和管理bundle信息。
code-1.0/foundation/appexecfwk/services/bundlemgr_lite/src/bundle_installer.cpp
bundle_daemon
code-1.0\foundation\appexecfwk\services\bundlemgr_lite\bundle_daemon\
bundle_daemon
源代码位于上面这个路径。
const char BDS_SERVICE[] = "bundle_daemon";
static BundleDaemonFeature g_defaultApi = {
SERVER_IPROXY_IMPL_BEGIN,
.Invoke = BundleDaemon::Invoke,
IPROXY_END,
};
static void Init()
{
SamgrLite *samgrLite = SAMGR_GetInstance();
if (samgrLite == nullptr) {
PRINTE("BundleDaemon", "get samgr is nullptr");
return;
}
// 注册服务bundle daemon
BOOL result = samgrLite->RegisterService(&BundleDaemon::GetInstance());
if (!result) {
PRINTE("BundleDaemon", "register bundle_daemon service fail");
return;
}
// 注册bundle_daemon服务的默认feature
result = samgrLite->RegisterDefaultFeatureApi(BDS_SERVICE, GET_IUNKNOWN(g_defaultApi));
PRINTE("BundleDaemon", "register default feature api %{public}s", result ? "success" : "fail");
}
SYSEX_SERVICE_INIT(Init);
使用鸿蒙系统的IPC(服务)框架,定义并注册一个服务和服务的feature。这里服务的名字是bundle_daemon
,服务的默认feature只有一个函数Invoke()
。
Invoke
static constexpr InvokeFunc invokeFuncs[BDS_CMD_END] {
BundleDaemon::ExtractHapInvoke, // 安装应用程序
BundleDaemon::RenameFileInvoke, // 文件重命名
BundleDaemon::CreatePermissionInvoke, // 创建文件夹/storage/app/etc/permissions/
BundleDaemon::CreateDataDirectoryInvoke, // 创建应用程序数据文件夹
BundleDaemon::StoreContentToFileInvoke, // 把数据保存到文件
BundleDaemon::RemoveFileInvoke, // 删除文件
BundleDaemon::RemoveInstallDirectoryInvoke, // 卸载应用程序
};
int32 BundleDaemon::Invoke(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply)
{
PRINTI("BundleDaemon", "bundle_daemon invoke start %{public}d", funcId);
if (origin == nullptr || req == nullptr) {
PRINTE("BundleDaemon", "invalid param");
return EC_INVALID;
}
// check permission
pid_t uid = GetCallingUid(origin);
if (uid != BMS_UID) {
PRINTE("BundleDaemon", "permission denied");
return EC_PERMISSION;
}
if (funcId == REGISTER_CALLBACK) {
return RegisterCallbackInvoke(req);
}
int32 ret = EC_COMMU;
// funcId有效性判断,调用对应的函数
if (funcId >= EXTRACT_HAP && funcId < BDS_CMD_END) {
ret = (BundleDaemon::invokeFuncs[funcId])(req);
}
// 返回执行结果给调用进程
return BundleDaemon::GetInstance().bundleMsClient_->SendReply(ret);
}
根据client传入的funcId,调用对应的函数。这里一共定义了7个函数。
安装应用程序
安装应用程序,会调用函数ExtractHapInvoke()。
code-1.0/foundation/appexecfwk/services/bundlemgr_lite/bundle_daemon/src/bundle_daemon.cpp
int32 BundleDaemon::ExtractHapInvoke(IpcIo *req)
{
size_t len = 0;
// 从传入的参数获得安装包路径
const char *hapPath = reinterpret_cast<char *>(IpcIoPopString(req, &len));
if (hapPath == nullptr || len == 0) {
return EC_INVALID;
}
// 从传入的参数获得安装路径
const char *codePath = reinterpret_cast<char *>(IpcIoPopString(req, &len));
if (codePath == nullptr || len == 0) {
return EC_INVALID;
}
// 执行安装过程
return BundleDaemon::GetInstance().handler_.ExtractHap(hapPath, codePath);
}
code-1.0/foundation/appexecfwk/services/bundlemgr_lite/bundle_daemon/src/bundle_daemon_handler.cpp
int32 BundleDaemonHandler::ExtractHap(const char *hapPath, const char *codePath)
{
// 获得安装包的真实路径
char realHapPath[PATH_MAX] = { '\0' };
if (hapPath == nullptr || realpath(hapPath, realHapPath) == nullptr) {
PRINTE("BundleDaemonHandler", "realPath fail!");
return EC_INVALID;
}
// 使用ExtractorUtil打开安装包
ExtractorUtil extractorUtil(realHapPath);
if (!extractorUtil.Init()) {
PRINTE("BundleDaemonHandler", "init fail!");
return EC_NOINIT;
}
// check and mkdir code path
if (!IsValideCodePath(codePath)) {
return EC_INVALID;
}
if (!BundleFileUtils::RemoveFile(codePath)) {
PRINTE("BundleDaemonHandler", "remove codePath fail!");
return EC_NODIR;
}
std::string codeDir = std::string(codePath);
if (codeDir.back() != PATH_SEPARATOR) {
codeDir += PATH_SEPARATOR;
}
if (!BundleFileUtils::MkRecursiveDir(codeDir.c_str(), true)) {
PRINTE("BundleDaemonHandler", "create codePath fail!");
return EC_NODIR;
}
// unzip one by one
const std::vector<std::string> &fileNames = extractorUtil.GetZipFileNames();
for (const auto &fileName : fileNames) {
if (fileName.find("..") != std::string::npos) {
PRINTE("BundleDaemonHandler", "zip file is invalid!");
return EC_NODIR;
}
if (fileName.back() == PATH_SEPARATOR) {
continue;
}
const std::string dir = BundleFileUtils::GetPathDir(fileName);
if (!dir.empty()) {
std::string fileDir = codeDir + dir;
if (!BundleFileUtils::MkRecursiveDir(fileDir.c_str(), false)) {
PRINTE("BundleDaemonHandler", "create other dir fail!");
return EC_NODIR;
}
}
std::string filePath = codeDir + fileName;
if (!extractorUtil.ExtractFileToPath(filePath, fileName)) {
PRINTE("BundleDaemonHandler", "ExtractFileToPath fail!");
return EC_NODIR;
}
}
return EC_SUCCESS;
}
其实,就是把应用程序安装包(安装包是一个zip文件)从原始路径解压到目标路径。
卸载应用程序
code-1.0/foundation/appexecfwk/services/bundlemgr_lite/bundle_daemon/src/bundle_daemon.cpp
int32 BundleDaemon::RemoveInstallDirectoryInvoke(IpcIo *req)
{
size_t len = 0;
// 应用程序包安装路径
const char *codePath = reinterpret_cast<char *>(IpcIoPopString(req, &len));
if (codePath == nullptr || len == 0) {
return EC_INVALID;
}
// 应用程序数据路径
const char *dataPath = reinterpret_cast<char *>(IpcIoPopString(req, &len));
if (dataPath == nullptr || len == 0) {
return EC_INVALID;
}
// 删除程序包路径和数据路径
return BundleDaemon::GetInstance().handler_.RemoveInstallDirectory(codePath, dataPath);
}
int32 BundleDaemonHandler::RemoveInstallDirectory(const char *codePath, const char *dataPath)
{
bool result = IsValideCodePath(codePath) && BundleFileUtils::RemoveFile(codePath);
result = IsValideDataPath(dataPath) && BundleFileUtils::RemoveFile(dataPath) && result;
return result ? EC_SUCCESS : EC_NODIR;
}
小节:应用程序的安装和卸载一共涉及到三个路径,分别是应用程序安装包路径、应用程序安装路径、应用程序数据路径。其中应用程序安装包路径是client指定的。应用程序安装路径是/storage/app/run/
或/sdcard/app/run/
。应用程序数据路径是/storage/app/data/
或/sdcard/app/data/
。
另外,还有几个路径如下:
- 系统应用路径 /system/internal/
- 预制的第三方应用路径 /system/external/
- 应用权限路径 /storage/app/etc/permissions/
bundle daemon启动过程
前情提要
code-1.0\foundation\appexecfwk\services\bundlemgr_lite\bundle_daemon\src\bundle_daemon.cpp
static void Init()
{
SamgrLite *samgrLite = SAMGR_GetInstance();
if (samgrLite == nullptr) {
PRINTE("BundleDaemon", "get samgr is nullptr");
return;
}
BOOL result = samgrLite->RegisterService(&BundleDaemon::GetInstance());
if (!result) {
PRINTE("BundleDaemon", "register bundle_daemon service fail");
return;
}
result = samgrLite->RegisterDefaultFeatureApi(BDS_SERVICE, GET_IUNKNOWN(g_defaultApi));
PRINTE("BundleDaemon", "register default feature api %{public}s", result ? "success" : "fail");
}
SYSEX_SERVICE_INIT(Init);
这里作为一个背景知识点进行介绍,不能理解的话,知道就可以了。
bundle_daemon.cpp
也被一起打包进可执行文件bundle_daemon
,运行bundle_daemon这个bin档的时候,这里的Init()函数会在main()函数之前被执行。
code-1.0\foundation\appexecfwk\services\bundlemgr_lite\bundle_daemon\src\main.cpp
extern "C" void __attribute__((weak)) HOS_SystemInit(void)
{
SAMGR_Bootstrap();
}
int main(int argc, char* argv[])
{
HOS_SystemInit();
while (true) {
pause();
}
return 0;
}
在执行bundle_daemon可执行文件时,会进入程序入口main()函数,函数体很简单,先调用SAMGR_Bootstrap()函数,然后进入无限循环。
SAMGR_Bootstrap()
函数是动态链接库libsamgr.so里面的,这里暂不展开,后面会专门分享这个库的实现。这个函数完成的工作是:创建线程,线程首先向sa manager service
注册endpoint,然后注册identity,最后进入无限循环处理clients发来的消息。
上面这些其实都是显式框架代码,如果想要自己构建一个SA,就可以参考bundle_daemon
的实现。SAMGR_Bootstrap()
是隐式的框架代码,庞大的框架代码都隐藏在这个函数身后。
API
code-1.0/foundation/appexecfwk/frameworks/bundle_lite/
代码位于上面的目录,模块名字是bundle
,编译生成动态链接库libbundle.so
,供应用程序调用。提供包操作的相关接口:
- Install() // 安装应用程序
- Uninstall() // 卸载应用程序
- GetBundleInfo() // 获取应用程序信息
Install
安装或更新一个应用程序。
bool Install(const char *hapPath, const InstallParam *installParam, InstallerCallback installerCallback)
{
// installParam是保留参数,目前没有使用,传入为nullptr
if ((hapPath == nullptr) || (installerCallback == nullptr)) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to nullptr parameters");
return false;
}
// 检查权限
if (CheckPermission(0, static_cast<const char *>(PERMISSION_INSTALL_BUNDLE)) != GRANTED) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to permission denied");
return false;
}
// 进行IPC,从sa manager service获取bms inner proxy
auto bmsInnerClient = GetBmsInnerClient();
if (bmsInnerClient == nullptr) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to nullptr bms client");
return false;
}
// 构建IPC request变量
IpcIo ipcIo;
char data[IPC_IO_DATA_MAX];
IpcIoInit(&ipcIo, data, IPC_IO_DATA_MAX, 1);
// 向request中放入hapPath
IpcIoPushString(&ipcIo, hapPath);
const SvcIdentity *svc = OHOS::BundleSelfCallback::GetInstance().RegisterBundleSelfCallback(installerCallback);
if (svc == nullptr) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Install svc is nullptr");
return false;
}
// 向request中放入SvcIndentity
IpcIoPushSvc(&ipcIo, svc);
if (!IpcIoAvailable(&ipcIo)) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Install ipc failed");
return false;
}
HILOG_DEBUG(HILOG_MODULE_APP, "BMS client invoke install");
uint8_t result = 0;
// 进行IPC,调用bms的Invoke()函数
int32_t ret = bmsInnerClient->Invoke(bmsInnerClient, INSTALL, &ipcIo, &result, Notify);
if (ret != OHOS_SUCCESS) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Install invoke failed: %{public}d", ret);
return false;
}
return result == OHOS_SUCCESS;
}
安装应用程序示例
#include "bundle_manager.h"
static void ReceiveCallback(const uint8_t resultCode, const void *resultMessage)
{
std::string strMessage = reinterpret_cast<const char *>(resultMessage);
if (!strMessage.empty()) {
printf("resultMessage is %s\n", strMessage.c_str());
}
sem_post(&g_sem);
}
Install(hapPath, null, ReceiveCallback);
Uninstall
卸载系统已经安装的第三方应用程序。
bool Uninstall(const char *bundleName, const InstallParam *installParam, InstallerCallback installerCallback)
{
// 同样,installParam参数目前保留未使用
// 包名长度不能超过128个字符
if ((bundleName == nullptr) || (installerCallback == nullptr) || (strlen(bundleName) >= MAX_BUNDLE_NAME)) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager uninstall failed due to nullptr or invalid parameters");
return false;
}
// 权限检查
if (CheckPermission(0, static_cast<const char *>(PERMISSION_INSTALL_BUNDLE)) != GRANTED) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager uninstall failed due to permission denied");
return false;
}
// 通过IPC,从sa manager service获取bms inner proxy
auto bmsInnerClient = GetBmsInnerClient();
if (bmsInnerClient == nullptr) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager uninstall failed due to nullptr bms client");
return false;
}
// 注册InstallerCallback
// 注册成功后,会返回SvcIndentity
const SvcIdentity *svc = OHOS::BundleSelfCallback::GetInstance().RegisterBundleSelfCallback(installerCallback);
if (svc == nullptr) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Uninstall svc is nullptr");
return false;
}
// 构建IPC request
IpcIo ipcIo;
char data[IPC_IO_DATA_MAX];
IpcIoInit(&ipcIo, data, IPC_IO_DATA_MAX, 1);
// 向IPC request中写入bundle name
IpcIoPushString(&ipcIo, bundleName);
// 向IPC request中写入SvcIndentity
IpcIoPushSvc(&ipcIo, svc);
if (!IpcIoAvailable(&ipcIo)) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Uninstall ipc failed");
return false;
}
HILOG_DEBUG(HILOG_MODULE_APP, "BMS client invoke uninstall");
uint8_t result = 0;
// 通过IPC,调用bms inner的Invoke()
int32_t ret = bmsInnerClient->Invoke(bmsInnerClient, UNINSTALL, &ipcIo, &result, Notify);
if (ret != OHOS_SUCCESS) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Uninstall invoke failed: %{public}d", ret);
return false;
}
return result == OHOS_SUCCESS;
}
获取应用程序信息
获取系统安装的应用程序的信息。
uint8_t GetBundleInfo(const char *bundleName, int32_t flags, BundleInfo *bundleInfo)
{
if ((bundleName == nullptr) || (bundleInfo == nullptr)) {
return ERR_APPEXECFWK_OBJECT_NULL;
}
if (flags < 0 || flags > 1 || (strlen(bundleName) >= MAX_BUNDLE_NAME)) {
return ERR_APPEXECFWK_QUERY_PARAMETER_ERROR;
}
if (CheckPermission(0, static_cast<const char *>(PERMISSION_GET_BUNDLE_INFO)) != GRANTED) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager get BundleInfo failed due to permission denied");
return ERR_APPEXECFWK_PERMISSION_DENIED;
}
// 通过IPC,向sa manager service获取bms proxy
auto bmsClient = GetBmsClient();
if (bmsClient == nullptr) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager get BundleInfo failed due to nullptr bms client");
return ERR_APPEXECFWK_OBJECT_NULL;
}
// 构建IPC request data
IpcIo ipcIo;
char data[IPC_IO_DATA_MAX];
IpcIoInit(&ipcIo, data, IPC_IO_DATA_MAX, 0);
// 向IPC request中写入bundle name
IpcIoPushString(&ipcIo, bundleName);
IpcIoPushInt32(&ipcIo, flags);
if (!IpcIoAvailable(&ipcIo)) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager GetBundleInfo ipc failed");
return ERR_APPEXECFWK_SERIALIZATION_FAILED;
}
ResultOfGetBundleInfo resultOfGetBundleInfo;
resultOfGetBundleInfo.bundleInfo = nullptr;
// 通过IPC,调用bms的Invoke()
int32_t ret = bmsClient->Invoke(bmsClient, GET_BUNDLE_INFO, &ipcIo, &resultOfGetBundleInfo, Notify);
if (ret != OHOS_SUCCESS) {
HILOG_ERROR(HILOG_MODULE_APP, "BundleManager GetBundleInfo invoke failed: %{public}d", ret);
return ERR_APPEXECFWK_INVOKE_ERROR;
}
// 将返回数据写入到bundleInfo
if (resultOfGetBundleInfo.resultCode == ERR_OK) {
OHOS::BundleInfoUtils::CopyBundleInfo(flags, bundleInfo, *(resultOfGetBundleInfo.bundleInfo));
ClearBundleInfo(resultOfGetBundleInfo.bundleInfo);
AdapterFree(resultOfGetBundleInfo.bundleInfo);
}
return resultOfGetBundleInfo.resultCode;
}
应用程序信息结构体
包括基本的:
- 是否常驻内存
- 是否是c/c++开发的应用
- uid、gid
- 是否是系统应用
- targetApi、compatibleApi
- 版本号、版本名称
- bundle name、label、iconPath
- 代码路径、数据路径
- ModuleInfo和数量
- AbilityInfo和数量
- appId、sharedLibPath
这些信息里面,有两个比较有特点:ModuleInfo和AbilityInfo。一个应用程序可以包含多个子模块和多个Ability。
typedef struct {
#ifdef OHOS_APPEXECFWK_BMS_BUNDLEMANAGER
/** Whether the application is kept alive */
bool isKeepAlive;
/**
* Whether the application is a local application. A local application refers to an application developed using
* C++ in the system. The value <b>true</b> indicates a local application, and <b>false</b> indicates a non-local
* application.
*/
bool isNativeApp;
/** UID allocated during application installation */
int32_t uid;
/** Application group ID allocated during application installation */
int32_t gid;
#endif
/**
* Whether the application is a system application. System applications cannot be uninstalled. The value
* <b>true</b> indicates a system application, and <b>false</b> indicates a non-system application.
*/
bool isSystemApp;
/** Pointer to the minimum API version required for running the application */
int32_t compatibleApi;
/** Pointer to the target API version for running the application */
int32_t targetApi;
/** Version code of the application, which is the internal version number */
int32_t versionCode;
/** Pointer to the version name visible to users */
char *versionName;
/** Pointer to the bundle name of the application */
char *bundleName;
/** Pointer to the application name visible to users */
char *label;
/** Pointer to the big icon of the application */
char *bigIconPath;
/**
* Pointer to the installation path of the application, which is in the <b>/app/run/<i>bundle name</i></b>
* format
*/
char *codePath;
/** Pointer to the path for storing data files of the application. The data path is <b>/app/data</b>. */
char *dataPath;
/** Pointer to the vendor name of the application */
char *vendor;
/**
* Pointer to the HAP package information about the application. The HAP information is encapsulated in
* {@link ModuleInfo} objects.
*/
ModuleInfo *moduleInfos;
/** Number of {@link ModuleInfo} objects included in the application */
int32_t numOfModule;
#ifdef OHOS_APPEXECFWK_BMS_BUNDLEMANAGER
/** Pointer to the shared library path */
char *sharedLibPath;
/**
* Application ID, which uniquely identifies an application. It is a combination of the bundle name and
* signature of the application.
*/
char *appId;
/**
* Pointer to the ability information about the application. The ability information is encapsulated in
* {@link AbilityInfo} objects.
*/
AbilityInfo *abilityInfos;
/** Number of {@link AbilityInfo} objects in the application */
int32_t numOfAbility;
#else
/**
* Pointer to the path for storing the small icon of the application. This field is available only to basic
* watches.
*/
char *smallIconPath;
/** Pointer to the ability information about the application. This field is available only to basic watches. */
AbilityInfo *abilityInfo;
#endif
} BundleInfo;
bm
code-1.0\foundation\appexecfwk\services\bundlemgr_lite\tools\
bm
模块的代码位于上面的路径。bm是系统提供的一个工具,用于从命令行操作bundle,它通过调用bundle API实现,即依赖动态链接库libbundle.so(模块bundle)。
安装应用程序
通过bm
安装应用程序,命令大概如下:
bm install -p xxx.hap
code-1.0/foundation/appexecfwk/services/bundlemgr_lite/tools/src/command_parser.cpp
#include "bundle_manager.h"
void CommandParser::RunAsInstallCommand(int32_t argc, char *argv[]) const
{
int32_t option;
// 路径最长是4096个字符
char realPath[PATH_MAX + 1] = { 0 };
uint32_t cbId = INITIAL_CBID;
SvcIdentity sid = SAMGR_GetRemoteIdentity(BMS_SERVICE, BMS_INNER_FEATURE);
while ((option = getopt_long_only(argc, argv, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr)) != -1) {
switch (option) {
case 'p':
// 调用Install()安装应用程序
Install(realPath, nullptr, ReceiveCallback);
sem_wait(&g_sem);
break;
}
}
}
安装应用程序,直接调用bundle_manager的Install()函数。
卸载应用程序
通过bm
卸载应用程序,命令大概如下:
bm uninstall -n "bundle_name"
code-1.0/foundation/appexecfwk/services/bundlemgr_lite/tools/src/command_parser.cpp
#include "bundle_manager.h"
void CommandParser::RunAsUninstallCommand(int32_t argc, char *argv[]) const
{
int32_t option;
uint32_t cbId = INITIAL_CBID;
SvcIdentity sid = SAMGR_GetRemoteIdentity(BMS_SERVICE, BMS_INNER_FEATURE);
while ((option = getopt_long_only(argc, argv, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr)) != -1) {
switch (option) {
case 'n':
// 调用Uninstall()卸载应用程序
Uninstall(optarg, nullptr, ReceiveCallback);
sem_wait(&g_sem);
break;
}
}
}
卸载应用程序,直接调用bundle_manager的Uninstall()函数。