1/*
2 * Copyright (c) 2021-2022 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 "sensor_dump.h"
17
18#include <getopt.h>
19
20#include <cinttypes>
21#include <cstring>
22#include <ctime>
23#include <queue>
24
25#include "securec.h"
26#include "sensor_agent_type.h"
27#include "sensor_errors.h"
28
29#undef LOG_TAG
30#define LOG_TAG "SensorDump"
31
32namespace OHOS {
33namespace Sensors {
34using namespace OHOS::HiviewDFX;
35namespace {
36constexpr int32_t MAX_DUMP_PARAMETERS = 32;
37#ifdef BUILD_VARIANT_ENG
38constexpr uint32_t MAX_DUMP_DATA_SIZE = 10;
39#endif // BUILD_VARIANT_ENG
40constexpr uint32_t MS_NS = 1000000;
41
42enum {
43    SOLITARIES_DIMENSION = 1,
44    TWO_DIMENSION = 2,
45    COMMON_DIMENSION = 3,
46    VECTOR_DIMENSION = 4,
47    UNCALIBRATED_DIMENSION = 6,
48    SEVEN_DIMENSION = 7,
49    POSE_6DOF_DIMENSION = 15,
50    DEFAULT_DIMENSION = 16,
51};
52} // namespace
53
54std::unordered_map<int32_t, std::string> SensorDump::sensorMap_ = {
55    { SENSOR_TYPE_ID_ACCELEROMETER, "ACCELEROMETER" },
56    { SENSOR_TYPE_ID_ACCELEROMETER_UNCALIBRATED, "ACCELEROMETER UNCALIBRATED" },
57    { SENSOR_TYPE_ID_LINEAR_ACCELERATION, "LINEAR ACCELERATION" },
58    { SENSOR_TYPE_ID_GRAVITY, "GRAVITY" },
59    { SENSOR_TYPE_ID_GYROSCOPE, "GYROSCOPE" },
60    { SENSOR_TYPE_ID_CAPACITIVE, "CAPACITIVE"},
61    { SENSOR_TYPE_ID_TEMPERATURE, "TEMPERATURE"},
62    { SENSOR_TYPE_ID_GESTURE, "GESTURE"},
63    { SENSOR_TYPE_ID_GYROSCOPE_UNCALIBRATED, "GYROSCOPE UNCALIBRATED" },
64    { SENSOR_TYPE_ID_SIGNIFICANT_MOTION, "SIGNIFICANT MOTION" },
65    { SENSOR_TYPE_ID_PEDOMETER_DETECTION, "PEDOMETER DETECTION" },
66    { SENSOR_TYPE_ID_PEDOMETER, "PEDOMETER" },
67    { SENSOR_TYPE_ID_AMBIENT_TEMPERATURE, "AMBIENT TEMPERATURE" },
68    { SENSOR_TYPE_ID_MAGNETIC_FIELD, "MAGNETIC FIELD" },
69    { SENSOR_TYPE_ID_MAGNETIC_FIELD_UNCALIBRATED, "MAGNETIC FIELD UNCALIBRATED" },
70    { SENSOR_TYPE_ID_HUMIDITY, "HUMIDITY" },
71    { SENSOR_TYPE_ID_BAROMETER, "BAROMETER" },
72    { SENSOR_TYPE_ID_DEVICE_ORIENTATION, "DEVICE ORIENTATION" },
73    { SENSOR_TYPE_ID_ORIENTATION, "ORIENTATION" },
74    { SENSOR_TYPE_ID_ROTATION_VECTOR, "ROTATION VECTOR" },
75    { SENSOR_TYPE_ID_GAME_ROTATION_VECTOR, "GAME ROTATION VECTOR" },
76    { SENSOR_TYPE_ID_GEOMAGNETIC_ROTATION_VECTOR, "GEOMAGNETIC ROTATION VECTOR" },
77    { SENSOR_TYPE_ID_PROXIMITY, "PROXIMITY" },
78    { SENSOR_TYPE_ID_PROXIMITY1, "SECONDARY PROXIMITY" },
79    { SENSOR_TYPE_ID_AMBIENT_LIGHT, "AMBIENT LIGHT" },
80    { SENSOR_TYPE_ID_AMBIENT_LIGHT1, "SECONDARY AMBIENT LIGHT" },
81    { SENSOR_TYPE_ID_HALL, "HALL" },
82    { SENSOR_TYPE_ID_HALL_EXT, "EXTENDED HALL" },
83    { SENSOR_TYPE_ID_HEART_RATE, "HEART RATE" },
84    { SENSOR_TYPE_ID_WEAR_DETECTION, "WEAR DETECTION" },
85    { SENSOR_TYPE_ID_COLOR, "COLOR" },
86    { SENSOR_TYPE_ID_SAR, "SAR" },
87    { SENSOR_TYPE_ID_POSTURE, "POSTURE" },
88    { SENSOR_TYPE_ID_HEADPOSTURE, "HEAD POSTURE" },
89    { SENSOR_TYPE_ID_DROP_DETECTION, "DROP DETECTION" },
90    { SENSOR_TYPE_ID_RPC, "RPC" },
91};
92
93void SensorDump::RunSensorDump(int32_t fd, int32_t optionIndex, const std::vector<std::string> &args, char **argv)
94{
95    struct option dumpOptions[] = {
96        {"channel", no_argument, 0, 'c'},
97#ifdef BUILD_VARIANT_ENG
98        {"data", no_argument, 0, 'd'},
99#endif // BUILD_VARIANT_ENG
100        {"open", no_argument, 0, 'o'},
101        {"help", no_argument, 0, 'h'},
102        {"list", no_argument, 0, 'l'},
103        {NULL, 0, 0, 0}
104    };
105    optind = 1;
106    int32_t c;
107    while ((c = getopt_long(args.size(), argv, "cdohl", dumpOptions, &optionIndex)) != -1) {
108        switch (c) {
109            case 'c': {
110                DumpSensorChannel(fd, clientInfo_);
111                break;
112            }
113#ifdef BUILD_VARIANT_ENG
114            case 'd': {
115                DumpSensorData(fd, clientInfo_);
116                break;
117            }
118#endif // BUILD_VARIANT_ENG
119            case 'o': {
120                DumpOpeningSensor(fd, sensors_, clientInfo_);
121                break;
122            }
123            case 'h': {
124                DumpHelp(fd);
125                break;
126            }
127            case 'l': {
128                DumpSensorList(fd, sensors_);
129                break;
130            }
131            default: {
132                dprintf(fd, "Unrecognized option, More info with: \"hidumper -s 3601 -a -h\"\n");
133                break;
134            }
135        }
136    }
137}
138
139void SensorDump::ParseCommand(int32_t fd, const std::vector<std::string> &args, const std::vector<Sensor> &sensors,
140    ClientInfo &clientInfo)
141{
142    int32_t count = 0;
143    for (const auto &str : args) {
144        if (str.find("--") == 0) {
145            ++count;
146            continue;
147        }
148        if (str.find("-") == 0) {
149            count += static_cast<int32_t>(str.size()) - 1;
150            continue;
151        }
152    }
153    if (count > MAX_DUMP_PARAMETERS) {
154        SEN_HILOGE("Cmd param number not more than 32");
155        dprintf(fd, "Cmd param number not more than 32\n");
156        return;
157    }
158    int32_t optionIndex = 0;
159    char **argv = new (std::nothrow) char *[args.size()];
160    CHKPV(argv);
161    if (memset_s(argv, args.size() * sizeof(char *), 0, args.size() * sizeof(char *)) != EOK) {
162        SEN_HILOGE("memset_s failed");
163        delete[] argv;
164        return;
165    }
166    for (size_t i = 0; i < args.size(); ++i) {
167        argv[i] = new (std::nothrow) char[args[i].size() + 1];
168        if (argv[i] == nullptr) {
169            SEN_HILOGE("Alloc failure");
170            goto RELEASE_RES;
171        }
172        if (strcpy_s(argv[i], args[i].size() + 1, args[i].c_str()) != EOK) {
173            SEN_HILOGE("strcpy_s error");
174            goto RELEASE_RES;
175        }
176    }
177    sensors_ = sensors;
178    RunSensorDump(fd, optionIndex, args, argv);
179    RELEASE_RES:
180    for (size_t i = 0; i < args.size(); ++i) {
181        if (argv[i] != nullptr) {
182            delete[] argv[i];
183        }
184    }
185    delete[] argv;
186}
187
188void SensorDump::DumpHelp(int32_t fd)
189{
190    dprintf(fd, "Usage:\n");
191    dprintf(fd, "      -h, --help: dump help\n");
192    dprintf(fd, "      -l, --list: dump the sensor list\n");
193    dprintf(fd, "      -c, --channel: dump the sensor data channel info\n");
194    dprintf(fd, "      -o, --open: dump the opening sensors\n");
195#ifdef BUILD_VARIANT_ENG
196    dprintf(fd, "      -d, --data: dump the last 10 packages sensor data\n");
197#endif // BUILD_VARIANT_ENG
198}
199
200bool SensorDump::DumpSensorList(int32_t fd, const std::vector<Sensor> &sensors)
201{
202    DumpCurrentTime(fd);
203    dprintf(fd, "Total sensor:%d, Sensor list:\n", int32_t { sensors.size() });
204    for (const auto &sensor : sensors) {
205        auto sensorId = sensor.GetSensorId();
206        if (sensorMap_.find(sensorId) == sensorMap_.end()) {
207            continue;
208        }
209        dprintf(fd,
210                "sensorId:%8u | sensorType:%s | sensorName:%s | vendorName:%s | maxRange:%f"
211                "| fifoMaxEventCount:%d | minSamplePeriodNs:%" PRId64 " | maxSamplePeriodNs:%" PRId64 "\n",
212                sensorId, sensorMap_[sensorId].c_str(), sensor.GetSensorName().c_str(), sensor.GetVendorName().c_str(),
213                sensor.GetMaxRange(), sensor.GetFifoMaxEventCount(), sensor.GetMinSamplePeriodNs(),
214                sensor.GetMaxSamplePeriodNs());
215    }
216    return true;
217}
218
219bool SensorDump::DumpSensorChannel(int32_t fd, ClientInfo &clientInfo)
220{
221    DumpCurrentTime(fd);
222    dprintf(fd, "Sensor channel info:\n");
223    std::vector<SensorChannelInfo> channelInfo;
224    clientInfo.GetSensorChannelInfo(channelInfo);
225    for (const auto &channel : channelInfo) {
226        auto sensorId = channel.GetSensorId();
227        if (sensorMap_.find(sensorId) == sensorMap_.end()) {
228            continue;
229        }
230        dprintf(fd,
231                "uid:%d | packageName:%s | sensorId:%8u | sensorType:%s | samplingPeriodNs:%" PRId64 ""
232                "| fifoCount:%u\n",
233                channel.GetUid(), channel.GetPackageName().c_str(), sensorId, sensorMap_[sensorId].c_str(),
234                channel.GetSamplingPeriodNs(), channel.GetFifoCount());
235    }
236    return true;
237}
238
239bool SensorDump::DumpOpeningSensor(int32_t fd, const std::vector<Sensor> &sensors, ClientInfo &clientInfo)
240{
241    DumpCurrentTime(fd);
242    dprintf(fd, "Opening sensors:\n");
243    for (const auto &sensor : sensors) {
244        int32_t sensorId = sensor.GetSensorId();
245        if (sensorMap_.find(sensorId) == sensorMap_.end()) {
246            continue;
247        }
248        if (clientInfo.GetSensorState(sensorId)) {
249            dprintf(fd, "sensorId: %8u | sensorType: %s | channelSize: %lu\n",
250                sensorId, sensorMap_[sensorId].c_str(), clientInfo.GetSensorChannel(sensorId).size());
251        }
252    }
253    return true;
254}
255
256#ifdef BUILD_VARIANT_ENG
257bool SensorDump::DumpSensorData(int32_t fd, ClientInfo &clientInfo)
258{
259    dprintf(fd, "Last 10 packages sensor data:\n");
260    auto dataMap = clientInfo.GetDumpQueue();
261    int32_t j = 0;
262    for (auto &sensorData : dataMap) {
263        int32_t sensorId = sensorData.first;
264        if (sensorMap_.find(sensorId) == sensorMap_.end()) {
265            continue;
266        }
267        dprintf(fd, "sensorId: %8u | sensorType: %s:\n", sensorId, sensorMap_[sensorId].c_str());
268        for (uint32_t i = 0; i < MAX_DUMP_DATA_SIZE && (!sensorData.second.empty()); i++) {
269            auto data = sensorData.second.front();
270            sensorData.second.pop();
271            timespec time = { 0, 0 };
272            clock_gettime(CLOCK_REALTIME, &time);
273            struct tm *timeinfo = localtime(&(time.tv_sec));
274            CHKPF(timeinfo);
275            dprintf(fd, "      %2d (ts=%.9f, time=%02d:%02d:%02d.%03d) | data:%s", ++j, data.timestamp / 1e9,
276                    timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, int32_t { (time.tv_nsec / MS_NS) },
277                    GetDataBySensorId(sensorId, data).c_str());
278        }
279    }
280    return true;
281}
282#endif // BUILD_VARIANT_ENG
283
284void SensorDump::DumpCurrentTime(int32_t fd)
285{
286    timespec curTime = { 0, 0 };
287    clock_gettime(CLOCK_REALTIME, &curTime);
288    struct tm *timeinfo = localtime(&(curTime.tv_sec));
289    CHKPV(timeinfo);
290    dprintf(fd, "Current time: %02d:%02d:%02d.%03d\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec,
291            int32_t { (curTime.tv_nsec / MS_NS) });
292}
293
294int32_t SensorDump::GetDataDimension(int32_t sensorId)
295{
296    switch (sensorId) {
297        case SENSOR_TYPE_ID_BAROMETER:
298        case SENSOR_TYPE_ID_HALL:
299        case SENSOR_TYPE_ID_HALL_EXT:
300        case SENSOR_TYPE_ID_TEMPERATURE:
301        case SENSOR_TYPE_ID_PROXIMITY:
302        case SENSOR_TYPE_ID_PROXIMITY1:
303        case SENSOR_TYPE_ID_HUMIDITY:
304        case SENSOR_TYPE_ID_AMBIENT_TEMPERATURE:
305        case SENSOR_TYPE_ID_SIGNIFICANT_MOTION:
306        case SENSOR_TYPE_ID_PEDOMETER_DETECTION:
307        case SENSOR_TYPE_ID_PEDOMETER:
308        case SENSOR_TYPE_ID_HEART_RATE:
309        case SENSOR_TYPE_ID_WEAR_DETECTION:
310        case SENSOR_TYPE_ID_SAR:
311            return SOLITARIES_DIMENSION;
312        case SENSOR_TYPE_ID_COLOR:
313            return TWO_DIMENSION;
314        case SENSOR_TYPE_ID_ROTATION_VECTOR:
315        case SENSOR_TYPE_ID_HEADPOSTURE:
316            return VECTOR_DIMENSION;
317        case SENSOR_TYPE_ID_MAGNETIC_FIELD_UNCALIBRATED:
318        case SENSOR_TYPE_ID_GYROSCOPE_UNCALIBRATED:
319        case SENSOR_TYPE_ID_ACCELEROMETER_UNCALIBRATED:
320            return UNCALIBRATED_DIMENSION;
321        case SENSOR_TYPE_ID_POSTURE:
322            return SEVEN_DIMENSION;
323        default:
324            SEN_HILOGW("Unknown sensorId:%{public}d, size:%{public}d", sensorId, COMMON_DIMENSION);
325            return COMMON_DIMENSION;
326    }
327}
328
329std::string SensorDump::GetDataBySensorId(int32_t sensorId, SensorData &sensorData)
330{
331    SEN_HILOGD("sensorId:%{public}u", sensorId);
332    std::string str;
333    int32_t dataLen = GetDataDimension(sensorId);
334    if (sensorData.dataLen < sizeof(float)) {
335        SEN_HILOGE("SensorData dataLen less than float size");
336        return str;
337    }
338    auto data = reinterpret_cast<float *>(sensorData.data);
339    for (int32_t i = 0; i < dataLen; ++i) {
340        str.append(std::to_string(*data));
341        if (i != dataLen - 1) {
342            str.append(",");
343        }
344        ++data;
345    }
346    str.append("\n");
347    return str;
348}
349} // namespace Sensors
350} // namespace OHOS
351