Files
multimedia_av_session/utils/include/avsession_utils.h
T
LiYimeng 209986ed33 IPC warning
Signed-off-by: LiYimeng <liyimeng2@huawei.com>
2026-07-29 10:59:03 +08:00

508 lines
19 KiB
C++

/*
* Copyright (c) 2022-2025 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.
*/
#ifndef OHOS_AVSESSION_UTILS_H
#define OHOS_AVSESSION_UTILS_H
#include <cstdio>
#include <fstream>
#include <string>
#include <vector>
#include <set>
#include <regex>
#ifndef CLIENT_LITE
#include "common_event_manager.h"
#endif
#include "avsession_log.h"
#include "avsession_pixel_map.h"
#include "directory_ex.h"
namespace OHOS::AVSession {
class AVSessionUtils {
public:
static constexpr const int32_t MAX_FILE_SIZE = 4 * 1024 * 1024;
static void WritePairToFile(const std::pair<std::string, int32_t>& castPair,
const std::string& fileDir, const std::string& fileName)
{
char realPath[PATH_MAX] = { 0x00 };
if (realpath(fileDir.c_str(), realPath) == nullptr &&
!OHOS::ForceCreateDirectory(fileDir)) {
SLOGE("WritePairToFile check and create path failed %{public}s", fileDir.c_str());
return;
}
std::string filePath = fileDir + fileName;
size_t strLen = castPair.first.size();
if (strLen > static_cast<size_t>(MAX_FILE_SIZE) || strLen == 0) {
SLOGE("error, dataSize larger than %{public}d or invalid", MAX_FILE_SIZE);
return;
}
std::ofstream ofile(filePath.c_str(), std::ios::binary | std::ios::out | std::ios::trunc);
if (!ofile.is_open()) {
SLOGE("open file error");
return;
}
ofile.write(reinterpret_cast<char*>(&strLen), sizeof(size_t));
ofile.write(castPair.first.c_str(), strLen);
int32_t mode = castPair.second;
ofile.write(reinterpret_cast<char*>(&mode), sizeof(int32_t));
ofile.close();
}
static bool ReadPairFromFile(std::pair<std::string, int32_t>& castPair,
const std::string& fileDir, const std::string& fileName)
{
std::string filePath = fileDir + fileName;
char realPath[PATH_MAX] = { 0x00 };
if (realpath(fileDir.c_str(), realPath) == nullptr) {
SLOGE("check path fail:%{public}s", fileDir.c_str());
return false;
}
std::ifstream ifile(filePath.c_str(), std::ios::binary | std::ios::in);
if (!ifile.is_open()) {
SLOGE("open file error");
return false;
}
size_t strLen;
ifile.read(reinterpret_cast<char*>(&strLen), sizeof(size_t));
SLOGD("BufferSize=%{public}zu", strLen);
if (strLen > static_cast<size_t>(MAX_FILE_SIZE) || strLen == 0) {
SLOGE("error, dataSize larger than %{public}d or invalid", MAX_FILE_SIZE);
ifile.close();
return false;
}
std::vector<char> strBuffer(strLen);
ifile.read(strBuffer.data(), strLen);
castPair.first = std::string(strBuffer.data(), strLen);
ifile.read(reinterpret_cast<char*>(&castPair.second), sizeof(int32_t));
ifile.close();
return true;
}
static void WriteImageToFile(const std::shared_ptr<AVSessionPixelMap>& innerPixelMap,
const std::string& fileDir, const std::string& fileName)
{
if (innerPixelMap == nullptr) {
SLOGE("innerPixelMap is nullptr");
return;
}
char realPath[PATH_MAX] = { 0x00 };
if (realpath(fileDir.c_str(), realPath) == nullptr &&
!OHOS::ForceCreateDirectory(fileDir)) {
SLOGE("WriteImageToFile check and create path failed %{public}s", fileDir.c_str());
return;
}
std::string filePath = fileDir + fileName;
std::vector<uint8_t> tempBuffer = innerPixelMap->GetInnerImgBuffer();
size_t imgBufferSize = tempBuffer.size();
SLOGI("write img to file with imgBufferSize=%{public}zu", imgBufferSize);
if (imgBufferSize > static_cast<size_t>(MAX_FILE_SIZE) || imgBufferSize == 0) {
SLOGE("error, dataSize larger than %{public}d or invalid", MAX_FILE_SIZE);
return;
}
std::ofstream ofile(filePath.c_str(), std::ios::binary | std::ios::out | std::ios::trunc);
if (!ofile.is_open()) {
SLOGE("open file error, filePath=%{public}s", filePath.c_str());
return;
}
ofile.write((char*)&imgBufferSize, sizeof(size_t));
SLOGI("write imgBuffer after write size %{public}zu", imgBufferSize);
ofile.write((char*)(&(tempBuffer[0])), imgBufferSize);
ofile.close();
}
static void ReadImageFromFile(std::shared_ptr<AVSessionPixelMap>& innerPixelMap,
const std::string& fileDir, const std::string& fileName)
{
if (innerPixelMap == nullptr) {
return;
}
char realPath[PATH_MAX] = { 0x00 };
if (realpath(fileDir.c_str(), realPath) == nullptr) {
SLOGE("check path fail:%{public}s", fileDir.c_str());
return;
}
std::string filePath = fileDir + fileName;
std::ifstream ifile(filePath.c_str(), std::ios::binary | std::ios::in);
if (!ifile.is_open()) {
SLOGE("open file err:Path=%{public}s", filePath.c_str());
return;
}
size_t imgBufferSize;
ifile.read((char*)&imgBufferSize, sizeof(size_t));
SLOGD("imgBufferSize=%{public}zu", imgBufferSize);
if (imgBufferSize > static_cast<size_t>(MAX_FILE_SIZE) || imgBufferSize == 0) {
SLOGE("error, dataSize larger than %{public}d or invalid", MAX_FILE_SIZE);
ifile.close();
return;
}
std::vector<std::uint8_t> imgBuffer(imgBufferSize);
ifile.read((char*)&imgBuffer[0], imgBufferSize);
SLOGD("imgBuffer prepare set");
innerPixelMap->SetInnerImgBuffer(imgBuffer);
SLOGD("imgBuffer SetInnerImgBuffer done");
ifile.close();
}
static void DeleteFile(const std::string& filePath)
{
if (OHOS::RemoveFile(filePath)) {
SLOGI("remove .image.dat file success filePath=%{public}s", filePath.c_str());
} else {
SLOGE("remove .image.dat file fail filePath=%{public}s", filePath.c_str());
}
}
static void DeleteCacheFiles(const std::string& path)
{
std::vector<std::string> fileList;
OHOS::GetDirFiles(path, fileList);
for (const auto& file : fileList) {
if (file.find(AVSessionUtils::GetFileSuffix()) != std::string::npos) {
DeleteFile(file);
}
}
}
static void DeleteCacheFilesExcluding(const std::string& path,
const std::set<std::string>& retainedSessionIds)
{
std::vector<std::string> fileList;
OHOS::GetDirFiles(path, fileList);
for (const auto& file : fileList) {
if (file.find(AVSessionUtils::GetFileSuffix()) == std::string::npos) {
continue;
}
size_t slashPos = file.find_last_of('/');
std::string baseName = (slashPos != std::string::npos) ? file.substr(slashPos + 1) : file;
size_t suffixPos = baseName.rfind(AVSessionUtils::GetFileSuffix());
std::string stem = (suffixPos != std::string::npos && suffixPos > 0)
? baseName.substr(0, suffixPos) : baseName;
std::string sessionId = stem;
std::string castPrefix(CAST_PREFIX);
if (castPrefix.size() < stem.size() && stem.compare(0, castPrefix.size(), castPrefix) == 0) {
sessionId = stem.substr(castPrefix.size());
}
if (retainedSessionIds.find(sessionId) != retainedSessionIds.end()) {
SLOGI("skip alive session cache file %{public}s", AVSessionUtils::GetAnonySessionId(sessionId).c_str());
continue;
}
DeleteFile(file);
}
}
static std::string GetCachePathName()
{
return std::string(DATA_PATH_NAME) + PUBLIC_PATH_NAME + CACHE_PATH_NAME;
}
static std::string GetCachePathName(int32_t userId)
{
return std::string(DATA_PATH_NAME) + std::to_string(userId) + CACHE_PATH_NAME;
}
static std::string GetCachePathNameForCast(int32_t userId)
{
return std::string(DATA_PATH_NAME) + std::to_string(userId) + CACHE_PATH_NAME + CAST_PREFIX;
}
static std::string GetFixedPathName()
{
return std::string(DATA_PATH_NAME) + PUBLIC_PATH_NAME + FIXED_PATH_NAME;
}
static std::string GetFixedPathName(int32_t userId)
{
return std::string(DATA_PATH_NAME) + std::to_string(userId) + FIXED_PATH_NAME;
}
static std::string GetFixedPathNameForDevice(int32_t userId)
{
return std::string(DATA_PATH_NAME) + std::to_string(userId) + DEVICE_PATH_NAME;
}
static const char* GetFileSuffix()
{
return FILE_SUFFIX;
}
static const char* GetPairFileSuffix()
{
return PAIR_FILE_SUFFIX;
}
static const char* GetCastPrefix()
{
return CAST_PREFIX;
}
static std::string GetAnonySessionId(std::string sessionId)
{
constexpr size_t PRE_LEN = 3;
constexpr size_t MAX_LEN = 100;
std::string res;
std::string tmpStr("******");
size_t len = sessionId.length();
std::regex nameRegex("[\\w]*");
if (len < PRE_LEN || len > MAX_LEN) {
SLOGE("GetAnonySessionId err length %{public}d", static_cast<int>(len));
return "ERROR_LENGTH";
}
if (!std::regex_match(sessionId, nameRegex)) {
SLOGE("GetAnonySessionId err content");
return "ERROR_CONTENT";
}
res.append(sessionId, 0, PRE_LEN).append(tmpStr).append(sessionId, len - PRE_LEN, PRE_LEN);
return res;
}
static std::string GetAnonymousDeviceId(std::string deviceId)
{
if (deviceId.empty() || deviceId.length() < DEVICE_ID_MIN_LEN) {
return "unknown";
}
const uint32_t half = DEVICE_ID_MIN_LEN / 2;
return deviceId.substr(0, half) + "**" + deviceId.substr(deviceId.length() - half);
}
#ifndef CLIENT_LITE
static int32_t PublishCommonEvent(const std::string& action)
{
OHOS::AAFwk::Want want;
want.SetAction(action);
EventFwk::CommonEventData data;
data.SetWant(want);
EventFwk::CommonEventPublishInfo publishInfo;
int32_t ret = EventFwk::CommonEventManager::NewPublishCommonEvent(data, publishInfo);
SLOGI("PublishCommonEvent: %{public}s return %{public}d", action.c_str(), ret);
return ret;
}
static int32_t PublishCommonEventWithDeviceName(const std::string& action, const std::string& sinkDeviceName,
const std::string& sourceDeviceName)
{
OHOS::AAFwk::Want want;
want.SetAction(action);
want.SetParam("sinkDeviceName", sinkDeviceName);
want.SetParam("sourceDeviceName", sourceDeviceName);
EventFwk::CommonEventData data;
data.SetWant(want);
EventFwk::CommonEventPublishInfo publishInfo;
int32_t ret = EventFwk::CommonEventManager::NewPublishCommonEvent(data, publishInfo);
SLOGI("PublishCommonEventWithDeviceName: %{public}s return %{public}d", action.c_str(), ret);
return ret;
}
static void PublishCtrlCmdEvent(const std::string& cmd, int32_t uid, int32_t pid)
{
OHOS::AAFwk::Want want;
want.SetAction("usual.event.MEDIA_CTRL_EVENT");
want.SetParam("cmd", cmd);
want.SetParam("uid", uid);
want.SetParam("pid", pid);
EventFwk::CommonEventData data { want };
EventFwk::CommonEventPublishInfo publishInfo;
publishInfo.SetSubscriberUid({RSS_UID});
int32_t ret = EventFwk::CommonEventManager::NewPublishCommonEvent(data, publishInfo);
SLOGD("publish ret:%{public}d cmd:%{public}s uid:%{public}d pid:%{public}d", ret, cmd.c_str(), uid, pid);
}
#endif
static std::string GetAnonyTitle(const std::string& title, double ratio = 0.3)
{
if (title.empty()) return "";
const unsigned char UTF8_CONTINUATION_BYTE_MASK = 0xC0;
const unsigned char UTF8_CONTINUATION_BYTE_VALUE = 0x80;
const unsigned char UTF8_3BYTE_START_MIN = 0xE0;
const unsigned char UTF8_3BYTE_START_MAX = 0xEF;
std::vector<int> char_positions;
for (size_t i = 0; i < title.size(); ++i) {
if ((static_cast<unsigned char>(title[i]) & UTF8_CONTINUATION_BYTE_MASK) != UTF8_CONTINUATION_BYTE_VALUE) {
char_positions.push_back(i);
}
}
const int char_count = static_cast<int>(char_positions.size());
if (char_count == 0) return "***";
// 特殊处理短字符串
const int VERY_SHORT_TEXT_LENGTH = 3;
const int SHORT_TEXT_LENGTH = 2;
if (char_count <= VERY_SHORT_TEXT_LENGTH) {
std::string first_char = title.substr(char_positions[0], 3);
if (char_count == VERY_SHORT_TEXT_LENGTH) {
const unsigned char first_byte = static_cast<unsigned char>(title[0]);
if (first_byte >= UTF8_3BYTE_START_MIN && first_byte <= UTF8_3BYTE_START_MAX) {
return first_char + "***";
}
}
if (char_count == SHORT_TEXT_LENGTH) {
return first_char + "***";
}
return "*" + title + "*";
}
const int SHORT_TEXT_THRESHOLD = 7;
const int LONG_TEXT_FRONT_KEEP = 2;
const int LONG_TEXT_BACK_KEEP = 2;
const int MIN_KEEP_COUNT = 1;
int keep_front = 0;
int keep_back = 0;
if (char_count <= SHORT_TEXT_THRESHOLD) {
// 短文本:按比例计算掩码长度
const int mask_len = static_cast<int>(std::ceil(char_count * ratio));
const int DIVISOR_FOR_HALF_CALCULATION = 2; // 用于计算一半的除数
keep_front = (char_count - mask_len) / DIVISOR_FOR_HALF_CALCULATION;
keep_back = char_count - mask_len - keep_front;
// 确保前后至少保留1个字符
keep_front = std::max(keep_front, MIN_KEEP_COUNT);
keep_back = std::max(keep_back, MIN_KEEP_COUNT);
} else {
// 长文本:固定保留前后2个字符
keep_front = LONG_TEXT_FRONT_KEEP;
keep_back = LONG_TEXT_BACK_KEEP;
}
if (keep_front + keep_back >= char_count) return std::string(1, title[0]) + "***";
// 构建匿名化字符串
const int start_idx = char_positions[keep_front]; // 掩码开始位置
const int end_idx = char_positions[char_count - keep_back]; // 掩码结束位置
return title.substr(0, start_idx) + "***" + title.substr(end_idx);
}
static std::string GetAnonyDeviceName(const std::string& deviceName)
{
CHECK_AND_RETURN_RET_LOG(!deviceName.empty(), "", "GetAnonyDeviceName deviceName is empty");
constexpr unsigned char UTF8_CONTINUATION_BYTE_MASK = 0xC0;
constexpr unsigned char UTF8_CONTINUATION_BYTE_VALUE = 0x80;
constexpr size_t CHAR_COUNT_MIN_THRESHOLD = 3;
constexpr size_t CHAR_COUNT_LEVEL_1 = 6;
constexpr size_t CHAR_COUNT_LEVEL_2 = 9;
constexpr size_t CHAR_COUNT_LEVEL_3 = 16;
constexpr size_t KEEP_COUNT_1 = 1;
constexpr size_t KEEP_COUNT_2 = 2;
constexpr size_t KEEP_COUNT_3 = 3;
constexpr size_t KEEP_COUNT_4 = 4;
std::vector<size_t> char_positions;
for (size_t i = 0; i < deviceName.size(); ++i) {
unsigned char byte = static_cast<unsigned char>(deviceName[i]);
if ((byte & UTF8_CONTINUATION_BYTE_MASK) != UTF8_CONTINUATION_BYTE_VALUE) {
char_positions.push_back(i);
}
}
const size_t char_count = char_positions.size();
if (char_count == 0) {
return "****";
}
size_t first_char_len = (char_count >= 2) ?
(char_positions[1] - char_positions[0]) : (deviceName.size() - char_positions[0]);
std::string first_char = deviceName.substr(char_positions[0], first_char_len);
if (char_count < CHAR_COUNT_MIN_THRESHOLD) {
return first_char + "****";
}
size_t keep_front = KEEP_COUNT_2;
size_t keep_back = KEEP_COUNT_1;
if (char_count >= CHAR_COUNT_LEVEL_1) {
keep_front = KEEP_COUNT_2;
keep_back = KEEP_COUNT_2;
}
if (char_count >= CHAR_COUNT_LEVEL_2) {
keep_front = KEEP_COUNT_3;
keep_back = KEEP_COUNT_2;
}
if (char_count >= CHAR_COUNT_LEVEL_3) {
keep_front = KEEP_COUNT_4;
keep_back = KEEP_COUNT_3;
}
std::string front_part = deviceName.substr(0, char_positions[keep_front]);
std::string back_part = deviceName.substr(char_positions[char_count - keep_back]);
return front_part + "****" + back_part;
}
static std::string GetAnonyNetworkId(const std::string& networkId)
{
if (networkId.empty()) {
return "";
}
const size_t total_length = networkId.length();
int PREFIX_LENGTH = 4;
int SUFFIX_LENGTH = 4;
CHECK_AND_RETURN_RET(total_length >= static_cast<size_t>(PREFIX_LENGTH + SUFFIX_LENGTH),
std::string(total_length, '*'));
std::string result;
result.reserve(total_length);
result += networkId.substr(0, PREFIX_LENGTH);
result.append(total_length - PREFIX_LENGTH - SUFFIX_LENGTH, '*');
result += networkId.substr(total_length - SUFFIX_LENGTH);
return result;
}
static bool IsValidFileName(const std::string& fileName)
{
if (fileName.empty()) {
return false;
}
if (fileName.find('/') != std::string::npos) {
return false;
}
if (fileName.find('\\') != std::string::npos) {
return false;
}
if (fileName.find("..") != std::string::npos) {
return false;
}
return true;
}
private:
static constexpr const int32_t RSS_UID = 1096;
static constexpr const char* DATA_PATH_NAME = "/data/service/el2/";
static constexpr const char* CACHE_PATH_NAME = "/av_session/cache/";
static constexpr const char* FIXED_PATH_NAME = "/av_session/";
static constexpr const char* DEVICE_PATH_NAME = "/av_session/deviceInfo/";
static constexpr const char* PUBLIC_PATH_NAME = "public";
static constexpr const char* FILE_SUFFIX = ".image.dat";
static constexpr const char* PAIR_FILE_SUFFIX = ".dat";
static constexpr const char* CAST_PREFIX = "cast_";
static constexpr const int32_t DEVICE_ID_MIN_LEN = 10;
};
} // namespace OHOS::AVSession
#endif // OHOS_AVSESSION_UTILS_H