/* * 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 #include #include #include #include #include #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& 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(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(&strLen), sizeof(size_t)); ofile.write(castPair.first.c_str(), strLen); int32_t mode = castPair.second; ofile.write(reinterpret_cast(&mode), sizeof(int32_t)); ofile.close(); } static bool ReadPairFromFile(std::pair& 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(&strLen), sizeof(size_t)); SLOGD("BufferSize=%{public}zu", strLen); if (strLen > static_cast(MAX_FILE_SIZE) || strLen == 0) { SLOGE("error, dataSize larger than %{public}d or invalid", MAX_FILE_SIZE); ifile.close(); return false; } std::vector strBuffer(strLen); ifile.read(strBuffer.data(), strLen); castPair.first = std::string(strBuffer.data(), strLen); ifile.read(reinterpret_cast(&castPair.second), sizeof(int32_t)); ifile.close(); return true; } static void WriteImageToFile(const std::shared_ptr& 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 tempBuffer = innerPixelMap->GetInnerImgBuffer(); size_t imgBufferSize = tempBuffer.size(); SLOGI("write img to file with imgBufferSize=%{public}zu", imgBufferSize); if (imgBufferSize > static_cast(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& 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(MAX_FILE_SIZE) || imgBufferSize == 0) { SLOGE("error, dataSize larger than %{public}d or invalid", MAX_FILE_SIZE); ifile.close(); return; } std::vector 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 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& retainedSessionIds) { std::vector 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(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 char_positions; for (size_t i = 0; i < title.size(); ++i) { if ((static_cast(title[i]) & UTF8_CONTINUATION_BYTE_MASK) != UTF8_CONTINUATION_BYTE_VALUE) { char_positions.push_back(i); } } const int char_count = static_cast(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(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(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 char_positions; for (size_t i = 0; i < deviceName.size(); ++i) { unsigned char byte = static_cast(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(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