mirror of
https://github.com/openharmony/multimedia_av_session.git
synced 2026-08-24 18:26:13 -04:00
209986ed33
Signed-off-by: LiYimeng <liyimeng2@huawei.com>
508 lines
19 KiB
C++
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
|