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 #define MLOG_TAG "DfxDeprecatedPermUsage"
17
18 #include "dfx_deprecated_perm_usage.h"
19
20 #include <charconv>
21
22 #include "hisysevent.h"
23 #include "ipc_skeleton.h"
24 #include "media_log.h"
25 #include "medialibrary_bundle_manager.h"
26 #include "medialibrary_errno.h"
27 #include "preferences_helper.h"
28
29 namespace OHOS {
30 namespace Media {
31 const std::string DFX_DEPRECATED_PERM_USAGE_XML = "/data/storage/el2/base/preferences/dfx_deprecated_perm_usage.xml";
32 constexpr char MEDIA_LIBRARY[] = "MEDIALIBRARY";
33 const std::string OPERATION_OBJECT = "OPERATION_OBJECT";
34 const std::string OPERATION_TYPE = "OPERATION_TYPE";
35 const std::string BUNDLE_NAME_LIST = "BUNDLE_NAME_LIST";
36 const size_t BATCH_SIZE = 300;
37
38 std::mutex DfxDeprecatedPermUsage::mutex_;
39
Record(const uint32_t object,const uint32_t type)40 int32_t DfxDeprecatedPermUsage::Record(const uint32_t object, const uint32_t type)
41 {
42 std::unique_lock<std::mutex> lock(mutex_, std::defer_lock);
43 CHECK_AND_RETURN_RET_WARN_LOG(lock.try_lock(), E_OK, "Record or statistics has started, skipping this operation");
44
45 std::string bundleName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
46 CHECK_AND_EXECUTE(!bundleName.empty(), bundleName = std::to_string(IPCSkeleton::GetCallingUid()));
47
48 int32_t errCode = NativePreferences::E_OK;
49 std::shared_ptr<NativePreferences::Preferences> prefs =
50 NativePreferences::PreferencesHelper::GetPreferences(DFX_DEPRECATED_PERM_USAGE_XML, errCode);
51 CHECK_AND_RETURN_RET_LOG(prefs, E_ERR, "get preferences error: %{public}d", errCode);
52
53 std::string key = std::to_string(object) + "," + std::to_string(type);
54 std::vector<std::string> bundleNames = prefs->Get(key, std::vector<std::string>{});
55 if (std::find(bundleNames.begin(), bundleNames.end(), bundleName) == bundleNames.end()) {
56 bundleNames.push_back(bundleName);
57 prefs->Put(key, bundleNames);
58 prefs->FlushSync();
59 }
60 return E_OK;
61 }
62
StrToUint32(const std::string & str,uint32_t & value)63 static bool StrToUint32(const std::string &str, uint32_t &value)
64 {
65 auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
66 return ec == std::errc{} && ptr == str.data() + str.size();
67 }
68
Statistics()69 int32_t DfxDeprecatedPermUsage::Statistics()
70 {
71 std::unique_lock<std::mutex> lock(mutex_, std::defer_lock);
72 CHECK_AND_RETURN_RET_WARN_LOG(lock.try_lock(), E_OK, "Record or statistics has started, skipping this operation");
73
74 int32_t errCode = NativePreferences::E_OK;
75 std::shared_ptr<NativePreferences::Preferences> prefs =
76 NativePreferences::PreferencesHelper::GetPreferences(DFX_DEPRECATED_PERM_USAGE_XML, errCode);
77 CHECK_AND_RETURN_RET_LOG(prefs, E_ERR, "get preferences error: %{public}d", errCode);
78
79 std::unordered_map<std::string, NativePreferences::PreferencesValue> allDatas = prefs->GetAllDatas();
80 CHECK_AND_RETURN_RET_INFO_LOG(!allDatas.empty(), E_OK, "has no data to statistics");
81
82 MEDIA_INFO_LOG("Statistics start, allDatas size: %{public}zu", allDatas.size());
83 int32_t reportResult = 0;
84 for (const auto &[key, val] : allDatas) {
85 size_t commaPos = key.find(",");
86 CHECK_AND_CONTINUE_ERR_LOG(commaPos != std::string::npos, "invalid key format: %{public}s", key.c_str());
87 std::string objectStr = key.substr(0, commaPos);
88 std::string typeStr = key.substr(commaPos + 1);
89 uint32_t object = 0;
90 uint32_t type = 0;
91 CHECK_AND_CONTINUE_ERR_LOG(StrToUint32(objectStr, object) && StrToUint32(typeStr, type),
92 "object or type is invalid, key format: %{public}s",
93 key.c_str());
94 std::vector<std::string> bundleNames = val;
95 CHECK_AND_CONTINUE_ERR_LOG(!bundleNames.empty(), "bundleNames is empty");
96 int32_t batchResult = ReportBatch(object, type, bundleNames);
97 if (batchResult != 0) {
98 MEDIA_ERR_LOG("ReportBatch failed, error: %{public}d", batchResult);
99 reportResult = batchResult;
100 }
101 }
102 if (reportResult == 0) {
103 prefs->Clear();
104 prefs->FlushSync();
105 }
106 return E_OK;
107 }
108
ReportBatch(const uint32_t object,const uint32_t type,const std::vector<std::string> & bundleNames)109 int32_t DfxDeprecatedPermUsage::ReportBatch(
110 const uint32_t object, const uint32_t type, const std::vector<std::string> &bundleNames)
111 {
112 int32_t batchResult = 0;
113 for (size_t start = 0; start < bundleNames.size(); start += BATCH_SIZE) {
114 std::ostringstream oss;
115 size_t end = std::min(start + BATCH_SIZE, bundleNames.size());
116 oss << bundleNames[start];
117 for (size_t i = start + 1; i < end; ++i) {
118 oss << "," << bundleNames[i];
119 }
120 int32_t ret = Report(object, type, oss.str());
121 if (ret != 0) {
122 MEDIA_ERR_LOG("Report failed, error: %{public}d", ret);
123 batchResult = ret;
124 }
125 }
126 return batchResult;
127 }
128
Report(const uint32_t object,const uint32_t type,const std::string & bundleNameList)129 int32_t DfxDeprecatedPermUsage::Report(const uint32_t object, const uint32_t type, const std::string &bundleNameList)
130 {
131 int32_t ret = HiSysEventWrite(
132 MEDIA_LIBRARY,
133 "MEDIALIB_DEPRECATED_PERM_USAGE",
134 HiviewDFX::HiSysEvent::EventType::STATISTIC,
135 OPERATION_OBJECT, object,
136 OPERATION_TYPE, type,
137 BUNDLE_NAME_LIST, bundleNameList);
138
139 CHECK_AND_RETURN_RET_LOG(ret == 0, ret, "Deprecated perm usage statistics report error: %{public}d", ret);
140 MEDIA_INFO_LOG("Deprecated perm usage statistics report success");
141 return ret;
142 }
143 } // namespace Media
144 } // namespace OHOS