• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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