mirror of
https://github.com/openharmony/ability_dmsfwk_lite.git
synced 2026-07-01 20:54:02 -04:00
3b86853e08
Signed-off-by: wangyang2022 <wangyang412@huawei.com> Change-Id: I0a8546086cc167899c2eb3771e31a41f36ce1063
295 lines
8.8 KiB
C
295 lines
8.8 KiB
C
/*
|
|
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "dmslite_parser.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include "dmsfwk_interface.h"
|
|
#include "dmslite_log.h"
|
|
#include "dmslite_msg_handler.h"
|
|
#include "dmslite_tlv_common.h"
|
|
#include "securec.h"
|
|
|
|
#define MIN_VALID_NODES 2
|
|
|
|
#define HIGH_BIT_MASK 0xFF
|
|
#define LOW_BIT_MASK 0x7F
|
|
#define TLV_LENGTH_SHIFT_BITS 7
|
|
|
|
#define BREAK_IF_FAILURE(errCode); \
|
|
if ((errCode) != DMS_TLV_SUCCESS) { \
|
|
break; \
|
|
} \
|
|
|
|
static inline bool IsNextTlvLength(uint8_t num)
|
|
{
|
|
/* 128-16383 : 0b1xxxxxxx 0b0xxxxxxx */
|
|
return (((num) & HIGH_BIT_MASK) >> TLV_LENGTH_SHIFT_BITS) == 0x00;
|
|
}
|
|
|
|
static inline void TlvByteToLength(uint8_t byte, uint16_t *len)
|
|
{
|
|
*len = ((*len) << TLV_LENGTH_SHIFT_BITS) | (byte & LOW_BIT_MASK);
|
|
}
|
|
|
|
static TlvErrorCode TlvBytesToLength(const uint8_t *bytesBuffer, uint16_t bufLength,
|
|
uint16_t *length, uint8_t *bytesNumber)
|
|
{
|
|
uint8_t bytesNum = 0;
|
|
uint16_t len = 0;
|
|
/* compute TLV's L, when value > 127, the L should be two bytes, else L is one byte long
|
|
0-127 : 0b0xxxxxxx
|
|
128-16383 : 0b1xxxxxxx 0b0xxxxxxx */
|
|
for (uint8_t i = 0; i < bufLength; i++) {
|
|
TlvByteToLength(bytesBuffer[i], &len);
|
|
bytesNum++;
|
|
if (IsNextTlvLength(bytesBuffer[i])) {
|
|
HILOGD("[bytesNum = %hhu, byte = %x]", bytesNum, bytesBuffer[i]);
|
|
break;
|
|
}
|
|
if (bytesNum >= TLV_MAX_LENGTH_BYTES) {
|
|
return DMS_TLV_ERR_LEN;
|
|
}
|
|
}
|
|
/* it is meaningless to have a node with length being zero */
|
|
if (len == 0) {
|
|
HILOGE("[Invalid zero-size length]");
|
|
return DMS_TLV_ERR_LEN;
|
|
}
|
|
|
|
*length = len;
|
|
*bytesNumber = bytesNum;
|
|
|
|
return DMS_TLV_SUCCESS;
|
|
}
|
|
|
|
static TlvErrorCode TlvFillNode(const uint8_t *byteBuffer, uint16_t bufLength,
|
|
TlvNode *node, uint16_t *actualHandledLen)
|
|
{
|
|
if (bufLength <= TLV_TYPE_LEN) {
|
|
HILOGE("[Bad bufLength %hu]", bufLength);
|
|
return DMS_TLV_ERR_LEN;
|
|
}
|
|
|
|
/* fill TLV's T(type) */
|
|
node->type = *byteBuffer;
|
|
uint16_t curTlvNodeLen = TLV_TYPE_LEN;
|
|
|
|
/* fill TLV's L(length) */
|
|
uint16_t length = 0;
|
|
uint8_t bytesNum = 0;
|
|
const uint8_t *lengthPartAddr = byteBuffer + curTlvNodeLen;
|
|
TlvErrorCode errCode = TlvBytesToLength(lengthPartAddr, bufLength - curTlvNodeLen,
|
|
&length, &bytesNum);
|
|
if (errCode != DMS_TLV_SUCCESS) {
|
|
return DMS_TLV_ERR_LEN;
|
|
}
|
|
node->length = length;
|
|
curTlvNodeLen += bytesNum;
|
|
|
|
/* fill TLV's V(value) */
|
|
node->value = byteBuffer + curTlvNodeLen;
|
|
curTlvNodeLen += length;
|
|
if (curTlvNodeLen > bufLength) {
|
|
return DMS_TLV_ERR_LEN;
|
|
} else {
|
|
*actualHandledLen = curTlvNodeLen;
|
|
}
|
|
|
|
return DMS_TLV_SUCCESS;
|
|
}
|
|
|
|
static void TlvFreeNodeList(TlvNode *node)
|
|
{
|
|
TlvNode *next = NULL;
|
|
while (node != NULL) {
|
|
next = node->next;
|
|
free(node);
|
|
node = next;
|
|
}
|
|
}
|
|
|
|
static inline TlvNode* MallocTlvNode()
|
|
{
|
|
TlvNode *node = (TlvNode *)malloc(sizeof(TlvNode));
|
|
if (node == NULL) {
|
|
HILOGE("[Out of memory]");
|
|
return NULL;
|
|
}
|
|
/* won't fail */
|
|
(void) memset_s(node, sizeof(TlvNode), 0x00, sizeof(TlvNode));
|
|
|
|
return node;
|
|
}
|
|
|
|
static inline TlvErrorCode CheckNodeSequence(const TlvNode *lastNode, const TlvNode *curNode)
|
|
{
|
|
if (lastNode == curNode) {
|
|
return DMS_TLV_SUCCESS;
|
|
}
|
|
if (lastNode->type >= curNode->type) {
|
|
HILOGE("[Bad node type sequence '%hhu' is expected but '%hhu' appears]",
|
|
lastNode->type, curNode->type);
|
|
return DMS_TLV_ERR_OUT_OF_ORDER;
|
|
}
|
|
|
|
return DMS_TLV_SUCCESS;
|
|
}
|
|
|
|
static inline TlvErrorCode MoveToNextTlvNode(TlvNode **curNode)
|
|
{
|
|
TlvNode *next = MallocTlvNode();
|
|
if (next == NULL) {
|
|
return DMS_TLV_ERR_NO_MEM;
|
|
}
|
|
|
|
(*curNode)->next = next;
|
|
*curNode = next;
|
|
return DMS_TLV_SUCCESS;
|
|
}
|
|
|
|
TlvErrorCode TlvBytesToNode(const uint8_t *byteBuffer, uint16_t bufLength, TlvNode **tlv)
|
|
{
|
|
if ((tlv == NULL) || (byteBuffer == NULL)) {
|
|
HILOGE("[Bad parameter]");
|
|
return DMS_TLV_ERR_PARAM;
|
|
}
|
|
/* bufLength is longer than TLV_TYPE_LEN + 1(means length should be at least 1 byte) */
|
|
if (bufLength <= (TLV_TYPE_LEN + 1)) {
|
|
HILOGE("[Bad Length %hu]", bufLength);
|
|
return DMS_TLV_ERR_LEN;
|
|
}
|
|
|
|
TlvNode *head = MallocTlvNode();
|
|
if (head == NULL) {
|
|
return DMS_TLV_ERR_NO_MEM;
|
|
}
|
|
TlvNode *curNode = head;
|
|
TlvNode *lastNode = curNode;
|
|
|
|
/* translate bytes to tlv node until the end of buffer */
|
|
uint16_t remainingLen = bufLength;
|
|
uint8_t handledNodeNum = 0;
|
|
const uint8_t *nodeStartAddr = byteBuffer;
|
|
TlvErrorCode errCode = DMS_TLV_SUCCESS;
|
|
while (true) {
|
|
uint16_t curTlvNodeLen = 0;
|
|
errCode = TlvFillNode(nodeStartAddr, remainingLen, curNode, &curTlvNodeLen);
|
|
BREAK_IF_FAILURE(errCode);
|
|
|
|
/* check whether there is need to continue processing the remaining nodes */
|
|
handledNodeNum++;
|
|
|
|
/* check node type sequence: the type of node must appear in strictly increasing order */
|
|
errCode = CheckNodeSequence(lastNode, curNode);
|
|
BREAK_IF_FAILURE(errCode);
|
|
|
|
remainingLen -= curTlvNodeLen;
|
|
if (remainingLen == 0) {
|
|
break;
|
|
}
|
|
|
|
HILOGD("[curNode length:%hu type:%hhu handledNodeNum:%hhu]", curNode->length,
|
|
curNode->type, handledNodeNum);
|
|
/* if all is ok, then move to the T part of the next tlv node */
|
|
nodeStartAddr += curTlvNodeLen;
|
|
lastNode = curNode;
|
|
errCode = MoveToNextTlvNode(&curNode);
|
|
BREAK_IF_FAILURE(errCode);
|
|
}
|
|
|
|
if (errCode == DMS_TLV_SUCCESS && handledNodeNum < MIN_VALID_NODES) {
|
|
HILOGE("[Parse done, but node num is invalid]");
|
|
errCode = DMS_TLV_ERR_BAD_NODE_NUM;
|
|
}
|
|
|
|
if (errCode != DMS_TLV_SUCCESS) {
|
|
TlvFreeNodeList(head);
|
|
head = NULL;
|
|
}
|
|
*tlv = head;
|
|
|
|
return errCode;
|
|
}
|
|
|
|
static int32_t Parse(const uint8_t *payload, uint16_t length, TlvNode **head)
|
|
{
|
|
if (length > MAX_DMS_MSG_LENGTH) {
|
|
HILOGE("[Bad parameters][length = %hu]", length);
|
|
return DMS_TLV_ERR_PARAM;
|
|
}
|
|
|
|
TlvNode *tlvHead = NULL;
|
|
TlvErrorCode errCode = TlvBytesToNode(payload, length, &tlvHead);
|
|
*head = tlvHead;
|
|
HILOGI("[errCode = %d]", errCode);
|
|
return errCode;
|
|
}
|
|
|
|
static bool CanCall()
|
|
{
|
|
#ifndef WEARABLE_PRODUCT
|
|
uid_t callerUid = getuid();
|
|
/* only foundation and xts (shell-enabled mode only) is reasonable to call ProcessCommuMsg directly */
|
|
if (callerUid != FOUNDATION_UID && callerUid != SHELL_UID) {
|
|
HILOGD("[Caller uid is not allowed, uid = %u]", callerUid);
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
int32_t ProcessCommuMsg(const CommuMessage *commuMessage, const IDmsFeatureCallback *dmsFeatureCallback)
|
|
{
|
|
if (!CanCall()) {
|
|
return DMS_EC_FAILURE;
|
|
}
|
|
|
|
if (commuMessage == NULL || commuMessage->payload == NULL || dmsFeatureCallback == NULL) {
|
|
return DMS_EC_FAILURE;
|
|
}
|
|
|
|
TlvNode *tlvHead = NULL;
|
|
int32_t errCode = Parse(commuMessage->payload, commuMessage->payloadLength, &tlvHead);
|
|
/* mainly for xts testsuit convenient, in non-test mode the onTlvParseDone should be set NULL */
|
|
if (dmsFeatureCallback->onTlvParseDone != NULL) {
|
|
dmsFeatureCallback->onTlvParseDone(errCode, tlvHead);
|
|
}
|
|
if (errCode != DMS_TLV_SUCCESS) {
|
|
return DMS_EC_PARSE_TLV_FAILURE;
|
|
}
|
|
|
|
uint16_t commandId = UnMarshallUint16(tlvHead, COMMAND_ID);
|
|
HILOGI("[ProcessCommuMsg commandId %hu]", commandId);
|
|
switch (commandId) {
|
|
case DMS_MSG_CMD_START_FA: {
|
|
errCode = StartAbilityFromRemoteHandler(tlvHead, dmsFeatureCallback->onStartAbilityDone);
|
|
break;
|
|
}
|
|
case DMS_MSG_CMD_REPLY: {
|
|
errCode = ReplyMsgHandler(tlvHead);
|
|
break;
|
|
}
|
|
default: {
|
|
HILOGW("[Unknown command id %hu]", commandId);
|
|
errCode = DMS_EC_UNKNOWN_COMMAND_ID;
|
|
break;
|
|
}
|
|
}
|
|
TlvFreeNodeList(tlvHead);
|
|
return errCode;
|
|
} |