1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved.
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 #include "sanitizer_telemetry.h"
16
17 #include <parameters.h>
18 #include "hilog/log.h"
19 #include "hisysevent.h"
20
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN 0xD002D12
23
24 #undef LOG_TAG
25 #define LOG_TAG "SanitizerTelemetry"
26
27 namespace {
28 constexpr const char* const TELEMETRY_KEY_ID = "telemetryId";
29 constexpr const char* const TELEMETRY_KEY_FAULT = "fault";
30 constexpr const char* const TELEMETRY_KEY_STATUS = "telemetryStatus";
31 constexpr const char* const TELEMETRY_KEY_BUNDLE_NAME = "bundleName";
32 constexpr const char* const TELEMETRY_ON = "on";
33 constexpr const char* const TELEMETRY_OFF = "off";
34 constexpr const char* const TELEMETRY_KEY_GWP_ENABLE = "gwpEnable";
35 constexpr const char* const TELEMETRY_KEY_GWP_SAMPLE_RATE = "gwpSampleRate";
36 constexpr const char* const TELEMETRY_KEY_GWP_MAX_SLOTS = "gwpMaxSlots";
37 constexpr const char* const TELEMETRY_KEY_MIN_SAMPLE_SIZE = "minSampleSize";
38 constexpr const char* const TELEMETRY_KEY_STACK_PARAM = "stackParam";
39 constexpr const char* const PARAM_GWP_ASAN_ENABLE = "gwp_asan.enable.app.";
40 constexpr const char* const PARAM_GWP_ASAN_SAMPLE = "gwp_asan.sample.app.";
41 constexpr const char* const PARAM_GWP_ASAN_MIN_SIZE = "gwp_asan.app.min_size.";
42 constexpr const char* const PARAM_GWP_ASAN_LIBRARY = "gwp_asan.app.library.";
43 constexpr const char* const PARAM_GWP_ASAN_APP_BEGIN_TIME = "gwp_asan.gray_begin.app.";
44 constexpr const char* const PARAM_GWP_ASAN_APP_DAYS = "gwp_asan.gray_days.app.";
45 constexpr const char* const PARAM_GWP_ASAN_APP_NUM = "gwp_asan.app_num";
46 constexpr uint32_t TELEMETRY_SANITIZER_TYPE = 0x800;
47 constexpr int DECIMAL_BASE = 10;
48 constexpr int MAX_APP_NUM = 20;
49 constexpr uint64_t DAY_TO_SEC = 24 * 60 * 60;
50 constexpr uint64_t DEFAULT_DURATION_DAY = 7;
51 }
52
53 namespace OHOS {
54 namespace HiviewDFX {
55
OnUnorderedEvent(const Event & msg)56 void SanitizerTelemetry::OnUnorderedEvent(const Event& msg)
57 {
58 if (msg.messageType_ != Event::TELEMETRY_EVENT) {
59 HILOG_INFO(LOG_CORE, "only accept TELEMETRY_EVENT, current type: %{public}d", msg.messageType_);
60 return;
61 }
62
63 std::string bundleName = msg.GetValue(TELEMETRY_KEY_BUNDLE_NAME);
64 uint64_t beginTime = GetThirdPartyBeginTime(bundleName);
65 if (beginTime > 0) {
66 uint64_t now = static_cast<uint64_t>(std::time(nullptr));
67 uint64_t durationDay = GetThirdPartyDurationDay(bundleName) * DAY_TO_SEC;
68 if (now < beginTime + durationDay) {
69 HILOG_INFO(LOG_CORE, "in third-party telemetry");
70 return;
71 }
72 HILOG_INFO(LOG_CORE, "third-party telemetry expired, clear for: %{public}s", bundleName.c_str());
73 ClearThirdPartyTelemetryParam(bundleName);
74 }
75
76 std::string telemetryStatus = msg.GetValue(TELEMETRY_KEY_STATUS);
77 if (telemetryStatus == TELEMETRY_OFF) {
78 ClearTelemetryParam(bundleName);
79 } else if (telemetryStatus == TELEMETRY_ON) {
80 HandleTelemetryStart(msg);
81 } else {
82 HILOG_WARN(LOG_CORE, "wrong telemetryStatus: %{public}s", telemetryStatus.c_str());
83 }
84 }
85
HandleTelemetryStart(const Event & msg)86 void SanitizerTelemetry::HandleTelemetryStart(const Event& msg)
87 {
88 GwpTelemetryEvent gwpTelemetryEvent;
89 auto valuePairs = msg.GetKeyValuePairs();
90 if (valuePairs.count(TELEMETRY_KEY_FAULT) == 0) {
91 HILOG_ERROR(LOG_CORE, "no fault");
92 return;
93 }
94 long long tmp;
95 if (!SafeStoll(valuePairs[TELEMETRY_KEY_FAULT], tmp)) {
96 HILOG_ERROR(LOG_CORE, "failed to SafeStoll faultStr: %{public}s", valuePairs[TELEMETRY_KEY_FAULT].c_str());
97 return;
98 }
99 gwpTelemetryEvent.fault = static_cast<uint64_t>(tmp);
100 if (!(gwpTelemetryEvent.fault & TELEMETRY_SANITIZER_TYPE)) {
101 HILOG_WARN(LOG_CORE, "not sanitizer telemetry type");
102 return;
103 }
104 if (valuePairs.count(TELEMETRY_KEY_ID) == 0 || valuePairs[TELEMETRY_KEY_ID].empty()) {
105 HILOG_ERROR(LOG_CORE, "invalid telemetryId");
106 return;
107 }
108 if (valuePairs.count(TELEMETRY_KEY_BUNDLE_NAME) == 0) {
109 HILOG_ERROR(LOG_CORE, "no bundleName");
110 return;
111 }
112 gwpTelemetryEvent.bundleName = valuePairs[TELEMETRY_KEY_BUNDLE_NAME];
113 if (IsOverTelemetryAppNum(gwpTelemetryEvent.bundleName)) {
114 return;
115 }
116
117 gwpTelemetryEvent.telemetryId = valuePairs[TELEMETRY_KEY_ID];
118 if (valuePairs.count(TELEMETRY_KEY_GWP_ENABLE) != 0) {
119 gwpTelemetryEvent.gwpEnable = valuePairs[TELEMETRY_KEY_GWP_ENABLE];
120 }
121 if (valuePairs.count(TELEMETRY_KEY_GWP_SAMPLE_RATE) != 0) {
122 gwpTelemetryEvent.gwpSampleRate = valuePairs[TELEMETRY_KEY_GWP_SAMPLE_RATE];
123 }
124 if (valuePairs.count(TELEMETRY_KEY_GWP_MAX_SLOTS) != 0) {
125 gwpTelemetryEvent.gwpMaxSlots = valuePairs[TELEMETRY_KEY_GWP_MAX_SLOTS];
126 }
127 if (valuePairs.count(TELEMETRY_KEY_MIN_SAMPLE_SIZE) != 0) {
128 gwpTelemetryEvent.minSampleSize = valuePairs[TELEMETRY_KEY_MIN_SAMPLE_SIZE];
129 }
130 if (valuePairs.count(TELEMETRY_KEY_STACK_PARAM) != 0) {
131 gwpTelemetryEvent.stackParam = valuePairs[TELEMETRY_KEY_STACK_PARAM];
132 }
133 SetTelemetryParam(gwpTelemetryEvent);
134 }
135
IsOverTelemetryAppNum(const std::string & bundleName)136 bool SanitizerTelemetry::IsOverTelemetryAppNum(const std::string& bundleName)
137 {
138 uint64_t currentAppNum = GetTelemetryAppNum();
139 std::string enable = OHOS::system::GetParameter(PARAM_GWP_ASAN_ENABLE + bundleName, "");
140 if (enable.empty() && currentAppNum >= MAX_APP_NUM) {
141 HILOG_ERROR(LOG_CORE, "the num of telemetry app exceeds max limit %{public}d", MAX_APP_NUM);
142 return true;
143 }
144 OHOS::system::SetParameter(PARAM_GWP_ASAN_APP_NUM, std::to_string(currentAppNum + 1));
145 return false;
146 }
147
GetThirdPartyDurationDay(const std::string & bundleName)148 uint64_t SanitizerTelemetry::GetThirdPartyDurationDay(const std::string& bundleName)
149 {
150 std::string durationTimeStr = OHOS::system::GetParameter(PARAM_GWP_ASAN_APP_DAYS + bundleName,
151 std::to_string(DEFAULT_DURATION_DAY));
152 long long tmp;
153 if (!SafeStoll(durationTimeStr, tmp)) {
154 HILOG_ERROR(LOG_CORE, "failed to SafeStoll durationTimeStr: %{public}s", durationTimeStr.c_str());
155 return 0;
156 }
157 return static_cast<uint64_t>(tmp);
158 }
159
GetThirdPartyBeginTime(const std::string & bundleName)160 uint64_t SanitizerTelemetry::GetThirdPartyBeginTime(const std::string& bundleName)
161 {
162 std::string beginTimeStr = OHOS::system::GetParameter(PARAM_GWP_ASAN_APP_BEGIN_TIME + bundleName, "0");
163 long long tmp;
164 if (!SafeStoll(beginTimeStr, tmp)) {
165 HILOG_ERROR(LOG_CORE, "failed to SafeStoll beginTimeStr: %{public}s", beginTimeStr.c_str());
166 return 0;
167 }
168 return static_cast<uint64_t>(tmp);
169 }
170
GetTelemetryAppNum()171 uint64_t SanitizerTelemetry::GetTelemetryAppNum()
172 {
173 std::string appNumStr = OHOS::system::GetParameter(PARAM_GWP_ASAN_APP_NUM, "0");
174 long long tmp;
175 if (!SafeStoll(appNumStr, tmp)) {
176 HILOG_ERROR(LOG_CORE, "failed to SafeStoll appNumStr: %{public}s", appNumStr.c_str());
177 return 0;
178 }
179 return static_cast<uint64_t>(tmp);
180 }
181
SetTelemetryParam(const GwpTelemetryEvent & gwpTelemetryEvent)182 void SanitizerTelemetry::SetTelemetryParam(const GwpTelemetryEvent& gwpTelemetryEvent)
183 {
184 std::string sample = "";
185 if (!gwpTelemetryEvent.gwpSampleRate.empty()) {
186 sample = gwpTelemetryEvent.gwpSampleRate;
187 }
188 if (!gwpTelemetryEvent.gwpMaxSlots.empty()) {
189 sample += ":" + gwpTelemetryEvent.gwpMaxSlots;
190 }
191 std::string bundleName = gwpTelemetryEvent.bundleName;
192 SetIfTelemetryExist(PARAM_GWP_ASAN_ENABLE + bundleName, gwpTelemetryEvent.gwpEnable);
193 SetIfTelemetryExist(PARAM_GWP_ASAN_SAMPLE + bundleName, sample);
194 SetIfTelemetryExist(PARAM_GWP_ASAN_MIN_SIZE + bundleName, gwpTelemetryEvent.minSampleSize);
195 SetIfTelemetryExist(PARAM_GWP_ASAN_LIBRARY + bundleName, gwpTelemetryEvent.stackParam);
196 }
197
ClearTelemetryParam(const std::string & bundleName)198 void SanitizerTelemetry::ClearTelemetryParam(const std::string& bundleName)
199 {
200 ClearIfParameterSet(PARAM_GWP_ASAN_ENABLE + bundleName);
201 ClearIfParameterSet(PARAM_GWP_ASAN_SAMPLE + bundleName);
202 ClearIfParameterSet(PARAM_GWP_ASAN_MIN_SIZE + bundleName);
203 ClearIfParameterSet(PARAM_GWP_ASAN_LIBRARY + bundleName);
204 }
205
ClearThirdPartyTelemetryParam(const std::string & bundleName)206 void SanitizerTelemetry::ClearThirdPartyTelemetryParam(const std::string& bundleName)
207 {
208 ClearTelemetryParam(bundleName);
209 ClearIfParameterSet(PARAM_GWP_ASAN_APP_BEGIN_TIME + bundleName);
210 ClearIfParameterSet(PARAM_GWP_ASAN_APP_DAYS + bundleName);
211 }
212
SetIfTelemetryExist(const std::string & key,const std::string & value)213 void SanitizerTelemetry::SetIfTelemetryExist(const std::string& key, const std::string& value)
214 {
215 if (!value.empty()) {
216 HILOG_INFO(LOG_CORE, "set parameter: %{public}s = %{public}s", key.c_str(), value.c_str());
217 OHOS::system::SetParameter(key, value);
218 }
219 }
220
ClearIfParameterSet(const std::string & key)221 void SanitizerTelemetry::ClearIfParameterSet(const std::string& key)
222 {
223 std::string value = OHOS::system::GetParameter(key, "");
224 if (!value.empty()) {
225 HILOG_INFO(LOG_CORE, "clear parameter: %{public}s", key.c_str());
226 OHOS::system::SetParameter(key, "");
227 }
228 }
229
SafeStoll(const std::string & str,long long & value)230 bool SanitizerTelemetry::SafeStoll(const std::string& str, long long& value)
231 {
232 value = 0;
233 size_t start = 0;
234 bool isNegative = false;
235
236 if (str.empty()) {
237 HILOG_ERROR(LOG_CORE, "str is empty.");
238 return false;
239 }
240
241 if (str[0] == '-') {
242 isNegative = true;
243 start = 1;
244 } else if (str[0] == '+') {
245 start = 1;
246 }
247
248 size_t index = start;
249 for (const char c :str.substr(start)) {
250 if (!isdigit(c)) {
251 HILOG_ERROR(LOG_CORE, "digit check failed. str: %{public}s, index: %{public}zu", str.c_str(), index);
252 return false;
253 }
254 if (value > (LLONG_MAX - (c - '0')) / DECIMAL_BASE) {
255 HILOG_ERROR(LOG_CORE, "out of range, str: %{public}s", str.c_str());
256 return false;
257 }
258 value = value * DECIMAL_BASE + (c - '0');
259 index++;
260 }
261
262 if (isNegative) {
263 value = -value;
264 }
265
266 HILOG_DEBUG(LOG_CORE, "success, str: %{public}s, result: %{public}lld", str.c_str(), value);
267 return true;
268 }
269 } // namespace HiviewDFX
270 } // namespace OHOS