OpenHarmony分布式调度详解|启动FA(3)

往期知识点记录:

前言

前两篇博客介绍了分布式任务调度的Service、Feature注册和Session会话数据解析,解析数据得到命令id后做出对应的动作,其中一个命令id对应的是启动FA设备。

远程启动FA设备

代码分析

远程启动Ability
/**
 * 函数功能:远程启动Ability
 * 函数参数:
 *      tlvHead:tlv数据链表
 *      onStartAbilityDone:启动Ability的回调函数
 * 函数返回值:
 *      成功,返回0;否则返回非0
 */
int32_t StartAbilityFromRemoteHandler(const TlvNode *tlvHead, StartAbilityCallback onStartAbilityDone)
{
    // 从tlv链表中获取bundleName、abilityName、callerSignature
    const char *calleeBundleName = UnMarshallString(tlvHead, DMS_TLV_TYPE_CALLEE_BUNDLE_NAME);
    const char *calleeAbilityName = UnMarshallString(tlvHead, DMS_TLV_TYPE_CALLEE_ABILITY_NAME);
    const char *callerSignature = UnMarshallString(tlvHead, DMS_TLV_TYPE_CALLER_SIGNATURE);
    // 将bundleName、abilityName和sigture封装为一个PermissionCheckInfo对象,并进行权限检查
    PermissionCheckInfo permissionCheckInfo;
    permissionCheckInfo.calleeAbilityName = calleeAbilityName;
    permissionCheckInfo.calleeBundleName = calleeBundleName;
    permissionCheckInfo.callerSignature = callerSignature;
    int32_t errCode = CheckRemotePermission(&permissionCheckInfo);
    if (errCode != DMS_EC_SUCCESS) {
        HILOGE("[Remote permission check failed]");
        return errCode;
    }
    return StartAbilityFromRemote(calleeBundleName, calleeAbilityName, onStartAbilityDone);
}
检查远程是否有与本地FAs交互的权限
/**
 * 函数功能:检查远程是否有与本地FAs交互的权限
 * 函数参数:
 *      permissionCheckInfo:检查远程权限所需的解析信息
 * 返回值:
 *      成功返回0,否则返回非零值
 * 说明:
 * 1.判断所检查的信息是否为空
 * 2.初始化BundleInfo
 * 3.获取调用者的uid
 * 4.根据uid进行权限检查
 */
int32_t CheckRemotePermission(const PermissionCheckInfo *permissionCheckInfo)
{
    if (permissionCheckInfo == NULL) { // 检查参数的有效性
        return DMS_EC_FAILURE;
    }
    BundleInfo bundleInfo; // 初始化一个包信息结构体对象,并为其填充为0
    if (memset_s(&bundleInfo, sizeof(BundleInfo), 0x00, sizeof(BundleInfo)) != EOK) {
        HILOGE("[bundleInfo memset failed]");
        return DMS_EC_FAILURE;
    }
    int32_t errCode;
#ifndef APP_PLATFORM_WATCHGT
    uid_t callerUid = getuid(); // 获取当前用户id
    if (callerUid == FOUNDATION_UID) { // 如果为FOUNDATION用户,则是进程内模式,属于进程间调用,否则属于跨进程调用
        /* inner-process mode */
        struct BmsServerProxy *bmsInterface = NULL; // 从BmsServerProxy对象中获取包信息
        if (!GetBmsInterface(&bmsInterface)) {
            HILOGE("[GetBmsInterface query null]");
            return DMS_EC_GET_BMS_FAILURE;
        }
        errCode = bmsInterface->GetBundleInfo(permissionCheckInfo->calleeBundleName,
            GET_BUNDLE_WITHOUT_ABILITIES, &bundleInfo);
    } else if (callerUid == SHELL_UID) { // 进程间模式,属于跨进程调用
        /* inter-process mode (mainly called in xts testsuit process started by shell) */
        errCode = GetBundleInfo(permissionCheckInfo->calleeBundleName,
            GET_BUNDLE_WITHOUT_ABILITIES, &bundleInfo);
    } else {
        errCode = EC_FAILURE;
    }
#else
    errCode = GetBundleInfo(permissionCheckInfo->calleeBundleName,
        GET_BUNDLE_WITHOUT_ABILITIES, &bundleInfo);
#endif
    if (errCode != EC_SUCCESS) {
        HILOGE("[GetBundleInfo errCode = %d]", errCode);
        return DMS_EC_GET_BUNDLEINFO_FAILURE;
    }
    /* appId: bundleName + "_" + signature */
    // 签名格式为:bundleName + "_" + signature + 包名长度 + 1
    const char *calleeSignature = bundleInfo.appId + strlen(permissionCheckInfo->calleeBundleName)
        + DELIMITER_LENGTH;
    if ((permissionCheckInfo->callerSignature == NULL) || (calleeSignature == NULL)) { // 如果签名为空,返回失败错误码
        HILOGE("[Signature is null]");
        return DMS_EC_FAILURE;
    }
    if (strcmp(permissionCheckInfo->callerSignature, calleeSignature) != 0) { // 如果签名不一致,则权限检查不通过
        HILOGE("[Signature unmatched]");
        return DMS_EC_CHECK_PERMISSION_FAILURE;
    }
    return DMS_EC_SUCCESS;
}
远程启动ability
/** 
 * 函数功能:远程启动ability
 * 函数参数:
 *      bundleName:包名称
 *      abilityName:ability名称
 *      onStartAbilityDone:启动ability的回调函数
 * 函数返回值:
 *      成功返回0;否则返回非0
 */
int32_t StartAbilityFromRemote(const char *bundleName, const char *abilityName,
    StartAbilityCallback onStartAbilityDone)
{
    if (bundleName == NULL || abilityName == NULL) { // 检查参数的有效性
        HILOGE("[Invalid parameters]");
        return DMS_EC_FAILURE;
    }
    if (g_serviceIdentity.token == INVALID_IPC_TOKEN) { // 判断全局服务id的token是否有效
        /* register a callback for notification when ams starts ability successfully */
        // 当ams启动ability成功时,注册一个回调
        IpcCbMode mode = ONCE; // 采用及时模式
        if (RegisterIpcCallback(AmsResultCallback, mode, IPC_WAIT_FOREVER,
            &g_serviceIdentity, NULL) != EC_SUCCESS) {
            HILOGE("[RegisterIpcCallback failed]");
            return DMS_EC_REGISTE_IPC_CALLBACK_FAILURE;
        }
    }
    if (g_onStartAbilityDone == NULL) { // 如果g_onStartAbilityDone为NULL,则将其赋值为onStartAbilityDone回调
        g_onStartAbilityDone = onStartAbilityDone;
    }
    return StartAbilityFromRemoteInner(bundleName, abilityName);
}

/**
 * 函数功能:ams结果回调函数
 * 函数参数:
 *      context:Ipc上下文
 *      ipcMsg:Ipc消息
 *      io:IpcIo信息
 *      arg:参数。该函数中没有用到,在调用此函数的地方也把该参数设为NULL
 * 函数返回值:
 *      成功,返回0;否则返回-10
 */
static int32_t AmsResultCallback(const IpcContext* context, void *ipcMsg, IpcIo *io, void *arg)
{
    /* Notice: must free ipcMsg, for we don't need ipcMsg here, just free it at first */
    FreeBuffer(context, ipcMsg); // 释放ipcMsg所占空间
    HILOGD("[AmsResultCallback called]");
    if (g_onStartAbilityDone == NULL) { // 如果为空,返回无效参数错误码
        return LITEIPC_EINVAL;
    }
    ElementName elementName; // 创建一个ElementName结构体对象,并将其填充为0,包含设备名、包名、ability名
    if (memset_s(&elementName, sizeof(ElementName), 0x00, sizeof(ElementName)) != EOK) {
        HILOGE("[elementName memset failed]");
        return LITEIPC_EINVAL;
    }
    /* the element is not used so far, and deserialize element first before we can get the errcode from io */
    if (!DeserializeElement(&elementName, io)) { // 对elementName进行反序列化
        return LITEIPC_EINVAL;
    }
    ClearElement(&elementName);
    int8_t errCode = DMS_EC_START_ABILITY_ASYNC_FAILURE; // errCode默认设为启动失败错误码
    if (IpcIoPopInt32(io) == EC_SUCCESS) { // FA成功启动并显示在屏幕上
        /* this means that FA starts and shows on screen successfully */
        errCode = DMS_EC_START_ABILITY_ASYNC_SUCCESS;
    }
    g_onStartAbilityDone(errCode);
    return LITEIPC_OK;
}
从远端内部启动ability
/**
 * 函数功能:从远端内部启动ability
 * 函数参数:
 *      bundleName:包名称
 *      abilityName:ability名称
 * 函数返回值:
 *      成功返回值1,否则返回其他错误码
 */
static int32_t StartAbilityFromRemoteInner(const char *bundleName, const char *abilityName)
{
    Want want; /* NOTICE: must call ClearWant if filling want sucessfully */
    if (FillWant(&want, bundleName, abilityName) != DMS_EC_SUCCESS) { // 构造Want对象,用于在不同ability之间传递信息
        return DMS_EC_FILL_WANT_FAILURE;
    }
    int32_t errCode;
    uid_t callerUid = getuid(); // 获取当前调用者的uid
    if (callerUid == FOUNDATION_UID) { // 如果为FOUNDATION用户,则是进程内调用
        /* inner-process mode */
        struct AmsInterface *amsInterface = NULL;
        if (!GetAmsInterface(&amsInterface)) { // 拿到ams的Feature接口,并调用启动FA
            HILOGE("[GetAmsInterface query null]");
            ClearWant(&want);
            return DMS_EC_GET_AMS_FAILURE;
        }
        errCode = amsInterface->StartAbility(&want);
    } else if (callerUid == SHELL_UID) { // 如果为SHELL用户,则是进程间调用
        /* inter-process mode (mainly called in xts testsuit process started by shell) */
        errCode = StartAbility(&want);
    } else {
        errCode = EC_FAILURE;
    }
    ClearWant(&want);
    if (errCode != EC_SUCCESS) { // 如果errCode不为0,调用StartAbility启动FA失败
        HILOGE("[Call ams StartAbility failed errCode = %d]", errCode);
        return DMS_EC_START_ABILITY_SYNC_FAILURE;
    }
    /* this just means we send to the ams a request of starting FA successfully */
    // 这仅仅意味着我们向ams发送了一个成功启动FA的请求
    return DMS_EC_START_ABILITY_SYNC_SUCCESS;
}

/**
 * 函数功能:填充Want信息,包括需要启动的FA的包名和ability名
 * 函数参数:
 *      want:要填充的want结构体对象
 *      bundleName:要启动的FA的包名
 *      abilityName:要启动的FA的ability名
 * 函数返回值:
 *      成功,返回0;否则返回非0
 */
static int32_t FillWant(Want *want, const char *bundleName, const char *abilityName)
{
    if (memset_s(want, sizeof(Want), 0x00, sizeof(Want)) != EOK) { // 将Want结构体填充为0
        HILOGE("[want memset failed]");
        return DMS_EC_FAILURE;
    }
    ElementName element; // 构造一个临时的ElementName结构体对象,并将其填充为0
    if (memset_s(&element, sizeof(ElementName), 0x00, sizeof(ElementName)) != EOK) { // 将ElementName填充为0
        HILOGE("[elementName memset failed]");
        return DMS_EC_FAILURE;
    }
    if (!(SetElementBundleName(&element, bundleName) // 将bundleName设置到element中
        && SetElementAbilityName(&element, abilityName) // 将abilityName设置到element中
        && SetWantElement(want, element) // 将element设置到want中
        && SetWantSvcIdentity(want, g_serviceIdentity))) { // 设置want的identity
        HILOGE("[Fill want failed]");
        ClearElement(&element);
        ClearWant(want);
        return DMS_EC_FAILURE;
    }
    ClearElement(&element);
    return DMS_EC_SUCCESS;
}

/**
 * 函数功能:获取ams的api接口
 * 函数参数:
 *      amsInterface:ams接口对象
 * 函数返回值:
 *      成功,返回true;否则返回false
 */
static bool GetAmsInterface(struct AmsInterface **amsInterface)
{
    // 通过SAMGR获取ams的FeatureApi接口得到iUnknown对象
    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(AMS_SERVICE, AMS_FEATURE);
    if (iUnknown == NULL) {
        HILOGE("[GetFeatureApi failed]");
        return false;
    }
    // 通过QueryInterface获取amsInterface接口
    int32_t errCode = iUnknown->QueryInterface(iUnknown, DEFAULT_VERSION, (void**) amsInterface);
    if (errCode != EC_SUCCESS) {
        HILOGE("[QueryInterface failed]");
        return false;
    }
    return true;
}

总结

本文分析了FA启动的函数调用关系。首先,在启动前对ability信息进行权限检查和签名校验,之后通过SAMGR获取ams的FeatureApi接口来启动FA。

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值