1/*
2 * Copyright (c) 2024 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 <regex>
17#include <string>
18#include <unordered_set>
19#include <vector>
20
21#include "appevent_watcher_impl.h"
22#include "cj_ffi/cj_common_ffi.h"
23#include "ffi_remote_data.h"
24#include "hiappevent_ffi.h"
25#include "hiappevent_impl.h"
26#include "hiappevent_verify.h"
27#include "log.h"
28#include "error.h"
29using namespace OHOS::HiviewDFX;
30using namespace OHOS::CJSystemapi::HiAppEvent;
31
32namespace {
33constexpr int ERR_CODE_PARAM_FORMAT = -1;
34constexpr int ERR_CODE_PARAM_INVALID = -2;
35const int8_t INT32_VALUE = 0;
36const int8_t DOUBLE_VALUE = 1;
37const int8_t STRING_VALUE = 2;
38const int8_t BOOL_VALUE = 3;
39const int8_t INT32_ARRAY_VALUE = 4;
40const int8_t DOUBLE_ARRAY_VALUE = 5;
41const int8_t STRING_ARRAY_VALUE = 6;
42const int8_t BOOL_ARRAY_VALUE = 7;
43constexpr int BIT_MASK = 1;
44constexpr unsigned int BIT_ALL_TYPES = 0xff;
45
46int CheckCondition(TriggerCondition &cond, CTriggerCondition triggerCondition)
47{
48    int ret = ERR_PARAM;
49    cond.row = triggerCondition.row;
50    if (cond.row < 0) {
51        ret = ERR_INVALID_COND_ROW;
52        return ret;
53    }
54    cond.size = triggerCondition.size;
55    if (cond.size < 0) {
56        ret = ERR_INVALID_COND_SIZE;
57        return ret;
58    }
59    if (triggerCondition.timeOut * HiAppEvent::TIMEOUT_STEP < 0) {
60        ret = ERR_INVALID_COND_TIMEOUT;
61        return ret;
62    }
63    cond.timeout = triggerCondition.timeOut * HiAppEvent::TIMEOUT_STEP;
64    return ret;
65}
66
67void CharPtrToVector(char** charPtr, int size, std::vector<std::string> &result)
68{
69    for (int i = 0; i < size; i++) {
70        result.push_back(std::string(charPtr[i]));
71    }
72}
73
74std::unordered_set<std::string> genArrString2Set(const CArrString& str)
75{
76    std::vector<std::string> strVec;
77    CharPtrToVector(str.head, str.size, strVec);
78    std::unordered_set<std::string> res(strVec.begin(), strVec.end());
79    return res;
80}
81
82int ConvertConfigReportProp(const CAppEventReportConfig& config, EventConfig reportConf)
83{
84    if (config.domain != nullptr) {
85        reportConf.domain = config.domain;
86    }
87    if (config.name != nullptr) {
88        reportConf.name = config.name;
89    }
90    reportConf.isRealTime = config.isRealTime;
91    if (!IsValidEventConfig(reportConf)) {
92        return ERR_CODE_PARAM_INVALID;
93    }
94    return SUCCESS_CODE;
95}
96
97int ConvertReportConfig(const CProcessor& processor, ReportConfig& conf)
98{
99    if (processor.name != nullptr && IsValidProcessorName(std::string(processor.name))) {
100        conf.name = processor.name;
101    } else {
102        return ERR_CODE_PARAM_FORMAT;
103    }
104    conf.debugMode = processor.debugMode;
105    conf.routeInfo = processor.routeInfo;
106    conf.appId = processor.appId;
107    conf.triggerCond.onStartup = processor.onStartReport;
108    conf.triggerCond.onBackground = processor.onBackgroundReport;
109    if (!IsValidPeriodReport(processor.periodReport)) {
110        conf.triggerCond.timeout = 0;
111    } else {
112        conf.triggerCond.timeout = processor.periodReport;
113    }
114    if (!IsValidBatchReport(processor.batchReport)) {
115        conf.triggerCond.row = 0;
116    } else {
117        conf.triggerCond.row = processor.batchReport;
118    }
119    conf.userIdNames = genArrString2Set(processor.userIds);
120    conf.userPropertyNames = genArrString2Set(processor.userProperties);
121    std::vector<EventConfig> eventConfigs;
122    CAppEventReportConfig* configPtr = processor.eventConfigs.head;
123    for (int i = 0; i < processor.eventConfigs.size; i++) {
124        EventConfig reportConf;
125        int res =  ConvertConfigReportProp(configPtr[i], reportConf);
126        if (res != 0) {
127            return res;
128        }
129        eventConfigs.push_back(reportConf);
130    }
131    conf.eventConfigs = eventConfigs;
132    return SUCCESS_CODE;
133}
134
135void AddParams2EventPack(const CArrParameters& params, std::shared_ptr<AppEventPack> appEventPack_)
136{
137    for (int i = 0; i < params.size; i++) {
138        auto head = params.head + i;
139        switch (head->valueType) {
140            case INT32_VALUE: // int32_t
141                appEventPack_->AddParam(std::string(head->key), *(int32_t*)head->value);
142                break;
143            case DOUBLE_VALUE: // double
144                appEventPack_->AddParam(std::string(head->key), *(double*)head->value);
145                break;
146            case STRING_VALUE: // std::string
147                appEventPack_->AddParam(std::string(head->key), std::string((char*)head->value));
148                break;
149            case BOOL_VALUE: // bool
150                appEventPack_->AddParam(std::string(head->key), *(bool*)head->value);
151                break;
152            case INT32_ARRAY_VALUE: { // int32_array
153                int* intArr = (int*)head->value;
154                std::vector<int> intVec(intArr, intArr + head->size);
155                appEventPack_->AddParam(std::string(head->key), intVec);
156                break;
157            }
158            case DOUBLE_ARRAY_VALUE: { // double_array
159                double* doubleArr = (double*)head->value;
160                std::vector<double> doubleVec(doubleArr, doubleArr + head->size);
161                appEventPack_->AddParam(std::string(head->key), doubleVec);
162                break;
163            }
164            case STRING_ARRAY_VALUE: { // string_array
165                char** strPtr = (char**)head->value;
166                std::vector<std::string> strVec;
167                CharPtrToVector(strPtr, head->size, strVec);
168                appEventPack_->AddParam(std::string(head->key), strVec);
169                break;
170            }
171            case BOOL_ARRAY_VALUE: { // bool_array
172                bool* boolArr = (bool*)head->value;
173                std::vector<bool> boolVec(boolArr, boolArr + head->size);
174                appEventPack_->AddParam(std::string(head->key), boolVec);
175                break;
176            }
177            default:
178                break;
179        }
180    }
181}
182}
183
184extern "C" {
185int FfiOHOSHiAppEventConfigure(CConfigOption config)
186{
187    int code = HiAppEventImpl::Configure(config.disable, config.maxStorage);
188    if (code != SUCCESS_CODE) {
189        LOGE("FfiOHOSHiAppEventConfigure failed");
190        return code;
191    }
192    return SUCCESS_CODE;
193}
194
195int FfiOHOSHiAppEventWrite(CAppEventInfo info)
196{
197    auto appEventPack_ = std::make_shared<AppEventPack>(info.domain, info.name, info.event);
198    AddParams2EventPack(info.cArrParamters, appEventPack_);
199    int code = HiAppEventImpl::Write(appEventPack_);
200    if (code != SUCCESS_CODE) {
201        LOGE("HiAppEvent::FfiOHOSHiAppEventWrite failed");
202        return GetErrorCode(code);
203    }
204    return code;
205}
206
207RetDataBool FfiOHOSHiAppEventAddProcessor(CProcessor processor)
208{
209    RetDataBool ret = { .code = ErrorCode::ERROR_UNKNOWN, .data = false };
210    ReportConfig conf;
211    int res = ConvertReportConfig(processor, conf);
212    if (res == ERR_CODE_PARAM_FORMAT) {
213        LOGE("failed to add processor, params format error");
214        ret.code = ERR_PARAM;
215        ret.data = false;
216        return ret;
217    }
218    if (HiAppEventImpl::Load(conf.name) != 0) {
219        LOGE("failed to add processor=%{public}s, name no found", conf.name.c_str());
220        return {ERR_CODE_PARAM_FORMAT, true};
221    }
222    int64_t processorId = HiAppEventImpl::AddProcessor(conf);
223    if (processorId <= 0) {
224        LOGE("HiAppEvent::FfiOHOSHiAppEventAddProcessor failed");
225    }
226    ret.code = processorId;
227    ret.data = true;
228    return ret;
229}
230
231int FfiOHOSHiAppEventRemoveProcessor(int64_t id)
232{
233    int res = HiAppEventImpl::RemoveProcessor(id);
234    return res;
235}
236
237int FfiOHOSHiAppEventSetUserId(const char* name, const char* value)
238{
239    if (!IsValidUserIdName(std::string(name))) {
240        return ERR_PARAM;
241    }
242    if (!IsValidUserIdValue(std::string(value))) {
243        return ERR_PARAM;
244    }
245    int res = HiAppEventImpl::SetUserId(std::string(name), std::string(value));
246    if (res != 0) {
247        return ERR_PARAM;
248    }
249    return SUCCESS_CODE;
250}
251
252RetDataCString FfiOHOSHiAppEventGetUserId(const char* name)
253{
254    RetDataCString ret = { .code = ERR_PARAM, .data = nullptr };
255    if (!IsValidUserIdName(std::string(name))) {
256        ret.code = ERR_PARAM;
257        ret.data = nullptr;
258        return ret;
259    }
260    auto [status, userId] = HiAppEventImpl::GetUserId(std::string(name));
261    if (status != 0) {
262        LOGE("HiAppEvent::FfiOHOSHiAppEventGetUserId error");
263        ret.code = status;
264        ret.data = nullptr;
265        return ret;
266    }
267    ret.code = status;
268    ret.data = MallocCString(userId);
269    return ret;
270}
271
272int FfiOHOSHiAppEventSetUserProperty(const char* name, const char* value)
273{
274    if (!IsValidUserPropName(name)) {
275        return ERR_PARAM;
276    }
277    if (!IsValidUserPropValue(value)) {
278        return ERR_PARAM;
279    }
280    int res = HiAppEventImpl::SetUserProperty(std::string(name), std::string(value));
281    if (res != 0) {
282        return ERR_PARAM;
283    }
284    return res;
285}
286
287RetDataCString FfiOHOSHiAppEventgetUserProperty(const char* name)
288{
289    RetDataCString ret = { .code = ERR_PARAM, .data = nullptr };
290    if (!IsValidUserPropName(std::string(name))) {
291        ret.code = ERR_PARAM;
292        ret.data = nullptr;
293        return ret;
294    }
295    auto [status, propertyId] = HiAppEventImpl::GetUserProperty(std::string(name));
296    if (status != 0) {
297        LOGE("HiAppEvent::FfiOHOSHiAppEventgetUserProperty error");
298        ret.code = status;
299        ret.data = nullptr;
300        return ret;
301    }
302    ret.code = status;
303    ret.data = MallocCString(propertyId);
304    return ret;
305}
306
307void FfiOHOSHiAppEventclearData()
308{
309    HiAppEventImpl::ClearData();
310}
311
312int64_t FfiOHOSHiAppEventConstructor(char* cWatcherName)
313{
314    auto nativeHolder = OHOS::FFI::FFIData::Create<AppEventPackageHolderImpl>(cWatcherName, -1L);
315    if (nativeHolder == nullptr) {
316        return -1;
317    }
318    return nativeHolder->GetID();
319}
320
321int FfiOHOSHiAppEventSetSize(int64_t id, int size)
322{
323    auto nativeAppEventPackageHolder = OHOS::FFI::FFIData::GetData<AppEventPackageHolderImpl>(id);
324    if (nativeAppEventPackageHolder == nullptr) {
325        return -1;
326    }
327    int ret = SUCCESS_CODE;
328    if (size >= 0) {
329        nativeAppEventPackageHolder->SetSize(size);
330    } else {
331        ret = ERR_INVALID_SIZE;
332    }
333    return ret;
334}
335
336ReTakeNext FfiOHOSHiAppEventTakeNext(int64_t id)
337{
338    auto nativeAppEventPackageHolder = OHOS::FFI::FFIData::GetData<AppEventPackageHolderImpl>(id);
339    if (nativeAppEventPackageHolder == nullptr) {
340        return ReTakeNext{.status = -1, .event = RetAppEventPackage{0}};
341    }
342    auto [state, package] = nativeAppEventPackageHolder->TakeNext();
343    ReTakeNext ret;
344    ret.status = state;
345    ret.event = package;
346    return ret;
347}
348
349RetDataI64 FfiOHOSHiAppEventAddWatcher(CWatcher watcher)
350{
351    RetDataI64 ret = { .code = ERR_PARAM, .data = 0 };
352    // check isValid
353    std::string name = std::string(watcher.name);
354    if (!IsValidWatcherName(name)) {
355        ret.code = ERR_INVALID_WATCHER_NAME;
356        return ret;
357    }
358    TriggerCondition cond;
359    ret.code = CheckCondition(cond, watcher.triggerCondition);
360    if (ret.code != ERR_PARAM) {
361        return ret;
362    }
363    std::vector<AppEventFilter> filters;
364    std::unordered_set<std::string> names;
365    for (int i = 0; i < watcher.appEventFilters.size; i++) {
366        for (int j = 0; j < watcher.appEventFilters.head[i].names.size; j++) {
367            names.insert(std::string(watcher.appEventFilters.head[i].names.head[j]));
368        }
369        std::string domain = std::string(watcher.appEventFilters.head[i].domain);
370        if (!IsValidDomain(domain)) {
371            ret.code = ERR_INVALID_FILTER_DOMAIN;
372            return ret;
373        }
374        uint32_t types = 0;
375        for (int k = 0; k < watcher.appEventFilters.head[i].eventTypes.size; k++) {
376            types |= (BIT_MASK << watcher.appEventFilters.head[i].eventTypes.head[k]);
377        }
378        types = types > 0 ? types : BIT_ALL_TYPES;
379        filters.emplace_back(AppEventFilter(domain, names, types));
380    }
381
382    auto [status, holderId] = HiAppEventImpl::addWatcher(name, filters, cond,
383                                                         watcher.callbackOnTriggerRef, watcher.callbackOnReceiveRef);
384    if (status != 0) {
385        ret.code = status;
386        return ret;
387    }
388    if (holderId == -1) {
389        ret.data = -1;
390        return ret;
391    }
392    ret.code = status;
393    ret.data = holderId;
394    return ret;
395}
396
397int FfiOHOSHiAppEventRemoveWatcher(CWatcher watcher)
398{
399    std::string name = std::string(watcher.name);
400    if (!IsValidWatcherName(name)) {
401        return ERR_INVALID_WATCHER_NAME;
402    }
403    HiAppEventImpl::removeWatcher(name);
404    return SUCCESS_CODE;
405}
406}