1 /*
2 * Copyright (C) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mtp_dfx_reporter.h"
17
18 #include <set>
19 #include <thread>
20 #include <map>
21
22 #include "hisysevent.h"
23 #include "media_log.h"
24 #include "medialibrary_errno.h"
25 #include "mtp_manager.h"
26 #include "mtp_constants.h"
27
28 namespace OHOS {
29 namespace Media {
30 using namespace std;
31 static constexpr char MEDIA_LIBRARY[] = "MEDIALIBRARY";
32 constexpr int32_t MTP_MODE = 1;
33 constexpr int32_t PTP_MODE = 2;
34 static std::mutex mutex;
35 static std::unordered_map<std::string, FileCountInfo> fileCountInfoMap;
36 static std::unordered_map<uint16_t, std::pair<int32_t, int32_t>> operationStats;
37 constexpr int32_t MAX_FILE_COUNT_INFO = 50;
38 const std::string GARBLE = "*";
39 constexpr uint32_t GARBLE_SMALL = 3;
40 constexpr uint32_t GARBLE_LARGE = 8;
41 constexpr uint32_t GARBLE_LAST_TWO = 2;
42 constexpr uint32_t GARBLE_LAST_ONE = 1;
43 static const char *UTF16_CERROR = "__CONVERSION_ERROR__";
44 static const char16_t *g_utf8Cerror = u"__CONVERSION_ERROR__";
45
46 static const std::vector<std::pair<uint16_t, std::string>> ObjMediaPropTypeMap = {
47 {MTP_OPERATION_GET_OBJECT_HANDLES_CODE, "MTP_GET_OBJECT_HANDLES_INFO"},
48 {MTP_OPERATION_GET_OBJECT_CODE, "MTP_GET_OBJECT_INFO"},
49 {MTP_OPERATION_GET_PARTIAL_OBJECT_CODE, "MTP_GET_PARTIAL_OBJECT_INFO"},
50 {MTP_OPERATION_DELETE_OBJECT_CODE, "MTP_DELETE_OBJECT_INFO"},
51 {MTP_OPERATION_SEND_OBJECT_CODE, "MTP_SEND_OBJECT_INFO"},
52 {MTP_OPERATION_SET_OBJECT_PROP_VALUE_CODE, "MTP_SET_OBJECT_PROP_VALUE_INFO"},
53 {MTP_OPERATION_MOVE_OBJECT_CODE, "MTP_MOVE_OBJECT_INFO"},
54 {MTP_OPERATION_COPY_OBJECT_CODE, "MTP_COPY_OBJECT_INFO"}
55 };
56
GetInstance()57 MtpDfxReporter &MtpDfxReporter::GetInstance()
58 {
59 static MtpDfxReporter instance;
60 return instance;
61 }
62
Init()63 void MtpDfxReporter::Init()
64 {
65 MEDIA_INFO_LOG("MtpDfxReporter::Init");
66 std::lock_guard<std::mutex> lock(mutex);
67 std::unordered_map<std::string, FileCountInfo>().swap(fileCountInfoMap);
68 std::unordered_map<uint16_t, std::pair<int32_t, int32_t>>().swap(operationStats);
69 for (const auto& key : ObjMediaPropTypeMap) {
70 operationStats[key.first] = {0, 0};
71 }
72 lastReadResult_ = 0;
73 }
74
DoFileCountInfoStatistics(const FileCountInfo & fileCountInfo)75 void MtpDfxReporter::DoFileCountInfoStatistics(const FileCountInfo &fileCountInfo)
76 {
77 std::lock_guard<std::mutex> lock(mutex);
78 auto it = fileCountInfoMap.find(fileCountInfo.albumName);
79 if (it == fileCountInfoMap.end()) {
80 fileCountInfoMap[fileCountInfo.albumName] = fileCountInfo;
81 return;
82 }
83 it->second.pictureCount = fileCountInfo.pictureCount;
84 it->second.videoCount = fileCountInfo.videoCount;
85 it->second.normalCount = fileCountInfo.normalCount;
86 it->second.livePhotoCount = fileCountInfo.livePhotoCount;
87 it->second.onlyInCloudPhotoCount = fileCountInfo.onlyInCloudPhotoCount;
88 it->second.burstCount = fileCountInfo.burstCount;
89 it->second.burstTotalCount = fileCountInfo.burstTotalCount;
90 }
91
IsKeyInObjMediaPropTypeMap(uint16_t key)92 static bool IsKeyInObjMediaPropTypeMap(uint16_t key)
93 {
94 auto it = std::find_if(ObjMediaPropTypeMap.begin(), ObjMediaPropTypeMap.end(),
95 [key](const std::pair<uint16_t, std::string>& item) {
96 return item.first == key;
97 });
98
99 return it != ObjMediaPropTypeMap.end();
100 }
101
DoOperationResultStatistics(uint16_t operation,uint16_t responseCode)102 void MtpDfxReporter::DoOperationResultStatistics(uint16_t operation, uint16_t responseCode)
103 {
104 if (IsKeyInObjMediaPropTypeMap(operation)) {
105 std::lock_guard<std::mutex> lock(mutex);
106 if (responseCode == MTP_OK_CODE) {
107 operationStats[operation].first++;
108 } else {
109 operationStats[operation].second++;
110 }
111 }
112 }
113
DoFileCountInfoDfxReporter(int32_t mtpMode,std::vector<std::string> & result)114 void MtpDfxReporter::DoFileCountInfoDfxReporter(int32_t mtpMode, std::vector<std::string> &result)
115 {
116 int ret = HiSysEventWrite(
117 MEDIA_LIBRARY,
118 "MEDIALIB_MTP_PTP_SYNC_RESULT",
119 HiviewDFX::HiSysEvent::EventType::STATISTIC,
120 "MTP_MODE", mtpMode,
121 "FILE_COUNT_INFO", result);
122 if (ret != 0) {
123 MEDIA_ERR_LOG("DoBatchFileCountInfoDfxReporter error:%{public}d", ret);
124 }
125 }
126
DoBatchFileCountInfoDfxReporter(int32_t mtpMode)127 void MtpDfxReporter::DoBatchFileCountInfoDfxReporter(int32_t mtpMode)
128 {
129 vector<std::string> result;
130 std::lock_guard<std::mutex> lock(mutex);
131 uint32_t count = 0;
132 for (const auto& [key, info] : fileCountInfoMap) {
133 string albumName = GetSafeAlbumNameWhenChinese(key);
134 string resultStr = std::move(albumName) + "," + to_string(info.pictureCount) + "," +
135 to_string(info.videoCount) + "," + to_string(info.normalCount) + "," +
136 to_string(info.livePhotoCount) + "," + to_string(info.onlyInCloudPhotoCount) + "," +
137 to_string(info.burstCount) + "," + to_string(info.burstTotalCount);
138 result.push_back(resultStr);
139 count++;
140 if (count >= MAX_FILE_COUNT_INFO) {
141 count = 0;
142 DoFileCountInfoDfxReporter(mtpMode, result);
143 result.clear();
144 }
145 }
146 MEDIA_INFO_LOG("MtpDfxReporter:DoBatchFileCountInfoDfxReporter result.size():%{public}zu", result.size());
147 if (result.size() > 0) {
148 DoFileCountInfoDfxReporter(mtpMode, result);
149 }
150 std::unordered_map<std::string, FileCountInfo>().swap(fileCountInfoMap);
151 }
152
DoOperationResultDfxReporter(int32_t mtpMode)153 void MtpDfxReporter::DoOperationResultDfxReporter(int32_t mtpMode)
154 {
155 std::vector<std::pair<std::string, std::vector<int32_t>>> stats;
156 {
157 std::lock_guard<std::mutex> lock(mutex);
158 for (const auto& mapping : ObjMediaPropTypeMap) {
159 uint16_t operationCode = mapping.first;
160 const std::string& keyName = mapping.second;
161 std::vector<int32_t> operationInfoCount = {
162 operationStats[operationCode].first,
163 operationStats[operationCode].second
164 };
165 stats.emplace_back(keyName, operationInfoCount);
166 }
167 }
168
169 int ret = HiSysEventWrite(
170 MEDIA_LIBRARY,
171 "MEDIALIB_MTP_OPERATION_RESULT",
172 HiviewDFX::HiSysEvent::EventType::STATISTIC,
173 "MTP_MODE", mtpMode,
174 stats[GET_OBJECT_HANDLES].first.c_str(), stats[GET_OBJECT_HANDLES].second,
175 stats[GET_OBJECT].first.c_str(), stats[GET_OBJECT].second,
176 stats[GET_PARTIAL_OBJECT].first.c_str(), stats[GET_PARTIAL_OBJECT].second,
177 stats[DELETE_OBJECT].first.c_str(), stats[DELETE_OBJECT].second,
178 stats[SEND_OBJECT].first.c_str(), stats[SEND_OBJECT].second,
179 stats[SET_OBJECT_PROP_VALUE].first.c_str(), stats[SET_OBJECT_PROP_VALUE].second,
180 stats[MOVE_OBJECT].first.c_str(), stats[MOVE_OBJECT].second,
181 stats[COPY_OBJECT].first.c_str(), stats[COPY_OBJECT].second
182 );
183 if (ret != 0) {
184 MEDIA_ERR_LOG("DoOperationResultDfxReporter error:%{public}d", ret);
185 }
186 {
187 std::lock_guard<std::mutex> lock(mutex);
188 std::unordered_map<uint16_t, std::pair<int32_t, int32_t>>().swap(operationStats);
189 }
190 }
191
NotifyDoDfXReporter(int32_t mtpMode)192 void MtpDfxReporter::NotifyDoDfXReporter(int32_t mtpMode)
193 {
194 MEDIA_INFO_LOG("MtpDfxReporter:NotifyDoDfXReporter mtpMode:%{public}d", mtpMode);
195 std::thread([&, mtpMode]() {
196 DoBatchFileCountInfoDfxReporter(mtpMode);
197 DoOperationResultDfxReporter(mtpMode);
198 }).detach();
199 }
200
DoSendResponseResultDfxReporter(uint16_t operationCode,int32_t operationResult,uint64_t duration,int32_t operationMode)201 void MtpDfxReporter::DoSendResponseResultDfxReporter(uint16_t operationCode, int32_t operationResult,
202 uint64_t duration, int32_t operationMode)
203 {
204 if (operationResult == 0) {
205 return;
206 }
207 if (operationMode == readmode && operationResult == E_USB_DISCONNECT) {
208 if (lastReadResult_ == E_USB_DISCONNECT) {
209 MEDIA_DEBUG_LOG("DoSendResponseResultDfxReporter is called, operationResult is E_USB_DISCONNECT");
210 return;
211 }
212 lastReadResult_ = operationResult;
213 }
214 MEDIA_INFO_LOG("MtpDfxReporter operationCode:0x%{public}x, operationResult:%{public}d", operationCode,
215 operationResult);
216 int32_t mtpMode;
217 if (MtpManager::GetInstance().IsMtpMode()) {
218 mtpMode = MTP_MODE;
219 } else {
220 mtpMode = PTP_MODE;
221 }
222 int ret = HiSysEventWrite(
223 MEDIA_LIBRARY,
224 "MEDIALIB_MTP_PTP_SEND_RESPONSE",
225 HiviewDFX::HiSysEvent::EventType::STATISTIC,
226 "MTP_MODE", mtpMode,
227 "OPERATION_CODE", operationCode,
228 "OPERATION_RESULT", operationResult,
229 "OPERATION_COST_TIME", duration,
230 "OPERATION_MODE", operationMode);
231 if (ret != 0) {
232 MEDIA_ERR_LOG("DoSendResponseResultDfxReporter error:%{public}d", ret);
233 }
234 }
235
Str8ToStr16(const std::string & inputStr)236 static std::u16string Str8ToStr16(const std::string &inputStr)
237 {
238 if (inputStr.empty()) {
239 return u"";
240 }
241 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert(UTF16_CERROR, g_utf8Cerror);
242 std::u16string result = convert.from_bytes(inputStr);
243 return result == g_utf8Cerror ? u"" : result;
244 }
245
Str16ToStr8(const std::u16string & inputStr)246 static std::string Str16ToStr8(const std::u16string &inputStr)
247 {
248 if (inputStr.empty()) {
249 return "";
250 }
251 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert(UTF16_CERROR, g_utf8Cerror);
252 std::string result = convert.to_bytes(inputStr);
253 return result == UTF16_CERROR ? "" : result;
254 }
255
GetSafeAlbumNameWhenChinese(const string & albumName)256 string MtpDfxReporter::GetSafeAlbumNameWhenChinese(const string &albumName)
257 {
258 MEDIA_INFO_LOG("MtpDfxReporter:GetSafeAlbumNameWhenChinese");
259 CHECK_AND_RETURN_RET_LOG(!albumName.empty(), "", "input albumName is empty");
260 std::u16string wideStr = Str8ToStr16(albumName);
261 uint32_t length = wideStr.size();
262 if (length <= 0) {
263 return GARBLE;
264 }
265 std::u16string safeAlbumName;
266 if (length <= GARBLE_SMALL) {
267 safeAlbumName = wideStr.substr(length - GARBLE_LAST_ONE);
268 } else if (length > GARBLE_LARGE) {
269 safeAlbumName = wideStr.substr(GARBLE_LARGE);
270 } else {
271 safeAlbumName = wideStr.substr(length - GARBLE_LAST_TWO);
272 }
273 return GARBLE + Str16ToStr8(safeAlbumName);
274 }
275 } // namespace Media
276 } // namespace OHOS
277