• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "HidRawSensor.h"
17 #include "HidSensorDef.h"
18 
19 #include <utils/Errors.h>
20 #include "HidLog.h"
21 
22 #include <HidUtils.h>
23 
24 #include <algorithm>
25 #include <cfloat>
26 #include <codecvt>
27 #include <iomanip>
28 #include <sstream>
29 
30 namespace android {
31 namespace SensorHalExt {
32 
33 namespace {
34 const std::string CUSTOM_TYPE_PREFIX("com.google.hardware.sensor.hid_dynamic.");
35 }
36 
HidRawSensor(SP (HidDevice)device,uint32_t usage,const std::vector<HidParser::ReportPacket> & packets)37 HidRawSensor::HidRawSensor(
38         SP(HidDevice) device, uint32_t usage, const std::vector<HidParser::ReportPacket> &packets)
39         : mReportingStateId(-1), mPowerStateId(-1), mReportIntervalId(-1), mInputReportId(-1),
40         mEnabled(false), mSamplingPeriod(1000LL*1000*1000), mBatchingPeriod(0),
41         mDevice(device), mValid(false) {
42     if (device == nullptr) {
43         return;
44     }
45     memset(&mSensor, 0, sizeof(mSensor));
46 
47     const HidDevice::HidDeviceInfo &info =  device->getDeviceInfo();
48     initFeatureValueFromHidDeviceInfo(&mFeatureInfo, info);
49 
50     if (!populateFeatureValueFromFeatureReport(&mFeatureInfo, packets)) {
51         LOG_E << "populate feature from feature report failed" << LOG_ENDL;
52         return;
53     }
54 
55     if (!findSensorControlUsage(packets)) {
56         LOG_E << "finding sensor control usage failed" << LOG_ENDL;
57         return;
58     }
59 
60     // build translation table
61     bool translationTableValid = false;
62     switch (usage) {
63         using namespace Hid::Sensor::SensorTypeUsage;
64         using namespace Hid::Sensor::ReportUsage;
65         case ACCELEROMETER_3D:
66             // Hid unit default g
67             // Android unit m/s^2
68             // 1g = 9.81 m/s^2
69             mFeatureInfo.typeString = SENSOR_STRING_TYPE_ACCELEROMETER;
70             mFeatureInfo.type = SENSOR_TYPE_ACCELEROMETER;
71             mFeatureInfo.isWakeUp = false;
72 
73             translationTableValid = processTriAxisUsage(packets,
74                                          ACCELERATION_X_AXIS,
75                                          ACCELERATION_Y_AXIS,
76                                          ACCELERATION_Z_AXIS, 9.81);
77             break;
78         case GYROMETER_3D:
79             // Hid unit default degree/s
80             // Android unit rad/s
81             // 1 degree/s = pi/180 rad/s
82             mFeatureInfo.typeString = SENSOR_STRING_TYPE_GYROSCOPE;
83             mFeatureInfo.type = SENSOR_TYPE_GYROSCOPE;
84             mFeatureInfo.isWakeUp = false;
85 
86             translationTableValid = processTriAxisUsage(packets,
87                                          ANGULAR_VELOCITY_X_AXIS,
88                                          ANGULAR_VELOCITY_Y_AXIS,
89                                          ANGULAR_VELOCITY_Z_AXIS, M_PI/180);
90             break;
91         case COMPASS_3D: {
92             // Hid unit default mGauss
93             // Android unit uT
94             // 1uT  = 0.1 nGauss
95             mFeatureInfo.typeString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
96             mFeatureInfo.type = SENSOR_TYPE_MAGNETIC_FIELD;
97 
98             if (!processTriAxisUsage(packets,
99                                      MAGNETIC_FLUX_X_AXIS,
100                                      MAGNETIC_FLUX_Y_AXIS,
101                                      MAGNETIC_FLUX_Z_AXIS, 0.1)) {
102                 break;
103             }
104             const HidParser::ReportItem *pReportAccuracy = find(packets,
105                                                                   MAGNETOMETER_ACCURACY,
106                                                                   HidParser::REPORT_TYPE_INPUT,
107                                                                   mInputReportId);
108 
109             if (pReportAccuracy == nullptr) {
110                 LOG_E << "Cannot find accuracy field in usage "
111                       << std::hex << usage << std::dec << LOG_ENDL;
112                 break;
113             }
114             if (!pReportAccuracy->isByteAligned()) {
115                 LOG_E << "Accuracy field must align to byte" << LOG_ENDL;
116                 break;
117             }
118             if (pReportAccuracy->minRaw != 0 || pReportAccuracy->maxRaw != 2) {
119                 LOG_E << "Accuracy field value range must be [0, 2]" << LOG_ENDL;
120                 break;
121             }
122             ReportTranslateRecord accuracyRecord = {
123                 .type = TYPE_ACCURACY,
124                 .maxValue = 2,
125                 .minValue = 0,
126                 .byteOffset = pReportAccuracy->bitOffset / 8,
127                 .byteSize = pReportAccuracy->bitSize / 8,
128                 .a = 1,
129                 .b = 1};
130             mTranslateTable.push_back(accuracyRecord);
131             translationTableValid = true;
132             break;
133         }
134         case DEVICE_ORIENTATION:
135             translationTableValid = processQuaternionUsage(packets);
136             break;
137         case CUSTOM: {
138             if (!mFeatureInfo.isAndroidCustom) {
139                 LOG_E << "Invalid android custom sensor" << LOG_ENDL;
140                 break;
141             }
142             const HidParser::ReportPacket *pPacket = nullptr;
143             const uint32_t usages[] = {
144                 CUSTOM_VALUE_1, CUSTOM_VALUE_2, CUSTOM_VALUE_3,
145                 CUSTOM_VALUE_4, CUSTOM_VALUE_5, CUSTOM_VALUE_6
146             };
147             for (const auto &packet : packets) {
148                 if (packet.type == HidParser::REPORT_TYPE_INPUT && std::any_of(
149                         packet.reports.begin(), packet.reports.end(),
150                         [&usages] (const HidParser::ReportItem &d) {
151                                return std::find(std::begin(usages), std::end(usages), d.usage)
152                                        != std::end(usages);
153                         })) {
154                     pPacket = &packet;
155                     break;
156                 }
157             }
158 
159             if (pPacket == nullptr) {
160                 LOG_E << "Cannot find CUSTOM_VALUE_X in custom sensor" << LOG_ENDL;
161                 break;
162             }
163 
164             double range = 0;
165             double resolution = 1;
166 
167             for (const auto &digest : pPacket->reports) {
168                 if (digest.minRaw >= digest.maxRaw) {
169                     LOG_E << "Custome usage " << digest.usage << ", min must < max" << LOG_ENDL;
170                     return;
171                 }
172 
173                 if (!digest.isByteAligned()
174                         || (digest.bitSize != 8 && digest.bitSize != 16 && digest.bitSize != 32)) {
175                     LOG_E << "Custome usage " << std::hex << digest.usage << std::hex
176                           << ", each input must be 8/16/32 bits and must align to byte boundary"
177                           << LOG_ENDL;
178                     return;
179                 }
180 
181                 ReportTranslateRecord record = {
182                     .type = TYPE_FLOAT,
183                     .maxValue = digest.maxRaw,
184                     .minValue = digest.minRaw,
185                     .byteOffset = digest.bitOffset / 8,
186                     .byteSize = digest.bitSize / 8,
187                     .a = digest.a,
188                     .b = digest.b,
189                 };
190                 // keep track of range and resolution
191                 range = std::max(std::max(std::abs((digest.maxRaw + digest.b) * digest.a),
192                                           std::abs((digest.minRaw + digest.b) * digest.a)),
193                                  range);
194                 resolution = std::min(digest.a, resolution);
195 
196                 for (size_t i = 0; i < digest.count; ++i) {
197                     if (mTranslateTable.size() == 16) {
198                         LOG_I << "Custom usage has more than 16 inputs, ignore the rest" << LOG_ENDL;
199                         break;
200                     }
201                     record.index = mTranslateTable.size();
202                     mTranslateTable.push_back(record);
203                     record.byteOffset += digest.bitSize / 8;
204                 }
205                 if (mTranslateTable.size() == 16) {
206                     break;
207                 }
208             }
209             mFeatureInfo.maxRange = range;
210             mFeatureInfo.resolution = resolution;
211             mInputReportId = pPacket->id;
212             translationTableValid = !mTranslateTable.empty();
213             break;
214         }
215         default:
216             LOG_I << "unsupported sensor usage " << usage << LOG_ENDL;
217     }
218 
219     bool sensorValid = validateFeatureValueAndBuildSensor();
220     mValid = translationTableValid && sensorValid;
221     LOG_V << "HidRawSensor init, translationTableValid: " << translationTableValid
222           << ", sensorValid: " << sensorValid << LOG_ENDL;
223 }
224 
processQuaternionUsage(const std::vector<HidParser::ReportPacket> & packets)225 bool HidRawSensor::processQuaternionUsage(const std::vector<HidParser::ReportPacket> &packets) {
226     const HidParser::ReportItem *pReportQuaternion
227             = find(packets,
228                    Hid::Sensor::ReportUsage::ORIENTATION_QUATERNION,
229                    HidParser::REPORT_TYPE_INPUT);
230 
231     if (pReportQuaternion == nullptr) {
232         return false;
233     }
234 
235     const HidParser::ReportItem &quat = *pReportQuaternion;
236     if ((quat.bitSize != 16 && quat.bitSize != 32) || !quat.isByteAligned()) {
237         LOG_E << "Quaternion usage input must be 16 or 32 bits and aligned at byte boundary" << LOG_ENDL;
238         return false;
239     }
240 
241     double min, max;
242     quat.decode(quat.mask(quat.minRaw), &min);
243     quat.decode(quat.mask(quat.maxRaw), &max);
244     if (quat.count != 4 || min > -1 || max < 1) {
245         LOG_E << "Quaternion usage need 4 inputs with range [-1, 1]" << LOG_ENDL;
246         return false;
247     }
248 
249     if (quat.minRaw > quat.maxRaw) {
250         LOG_E << "Quaternion usage min must <= max" << LOG_ENDL;
251         return false;
252     }
253 
254     ReportTranslateRecord record = {
255         .type = TYPE_FLOAT,
256         .maxValue = quat.maxRaw,
257         .minValue = quat.minRaw,
258         .byteOffset = quat.bitOffset / 8,
259         .byteSize = quat.bitSize / 8,
260         .b = quat.b,
261     };
262 
263     // Android X Y Z maps to HID X -Z Y
264     // Android order xyzw, HID order wxyz
265     // X
266     record.index = 0;
267     record.a = quat.a;
268     record.byteOffset = (quat.bitOffset + quat.bitSize) / 8;
269     mTranslateTable.push_back(record);
270     // Y
271     record.index = 1;
272     record.a = -quat.a;
273     record.byteOffset = (quat.bitOffset + 3 * quat.bitSize) / 8;
274     mTranslateTable.push_back(record);
275     // Z
276     record.index = 2;
277     record.a = quat.a;
278     record.byteOffset = (quat.bitOffset + 2 * quat.bitSize) / 8;
279     mTranslateTable.push_back(record);
280     // W
281     record.index = 3;
282     record.a = quat.a;
283     record.byteOffset = quat.bitOffset / 8;
284     mTranslateTable.push_back(record);
285 
286     mFeatureInfo.typeString = SENSOR_STRING_TYPE_ROTATION_VECTOR;
287     mFeatureInfo.type = SENSOR_TYPE_ROTATION_VECTOR;
288     mFeatureInfo.maxRange = 1;
289     mFeatureInfo.resolution = quat.a;
290     mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
291 
292     mInputReportId = quat.id;
293 
294     return true;
295 }
296 
processTriAxisUsage(const std::vector<HidParser::ReportPacket> & packets,uint32_t usageX,uint32_t usageY,uint32_t usageZ,double defaultScaling)297 bool HidRawSensor::processTriAxisUsage(const std::vector<HidParser::ReportPacket> &packets,
298         uint32_t usageX, uint32_t usageY, uint32_t usageZ, double defaultScaling) {
299     const HidParser::ReportItem *pReportX = find(packets, usageX, HidParser::REPORT_TYPE_INPUT);
300     const HidParser::ReportItem *pReportY = find(packets, usageY, HidParser::REPORT_TYPE_INPUT);
301     const HidParser::ReportItem *pReportZ = find(packets, usageZ, HidParser::REPORT_TYPE_INPUT);
302 
303     if (pReportX == nullptr || pReportY == nullptr|| pReportZ == nullptr) {
304         LOG_E << "Three axis sensor does not find all 3 axis" << LOG_ENDL;
305         return false;
306     }
307 
308     const HidParser::ReportItem &reportX = *pReportX;
309     const HidParser::ReportItem &reportY = *pReportY;
310     const HidParser::ReportItem &reportZ = *pReportZ;
311     if (reportX.id != reportY.id || reportY.id != reportZ.id) {
312         LOG_E << "All 3 axis should be in the same report" << LOG_ENDL;
313         return false;
314     }
315     if (reportX.minRaw >= reportX.maxRaw
316             || reportX.minRaw != reportY.minRaw
317             || reportX.maxRaw != reportY.maxRaw
318             || reportY.minRaw != reportZ.minRaw
319             || reportY.maxRaw != reportZ.maxRaw) {
320         LOG_E << "All 3 axis should have same min and max value and min must < max" << LOG_ENDL;
321         return false;
322     }
323     if (reportX.a != reportY.a || reportY.a != reportY.a) {
324         LOG_E << "All 3 axis should have same resolution" << LOG_ENDL;
325         return false;
326     }
327     if (reportX.count != 1 || reportY.count != 1 || reportZ.count != 1
328             || (reportX.bitSize != 16 && reportX.bitSize != 32)
329             || reportX.bitSize != reportY.bitSize || reportY.bitSize != reportZ.bitSize
330             || !reportX.isByteAligned()
331             || !reportY.isByteAligned()
332             || !reportZ.isByteAligned() ) {
333         LOG_E << "All 3 axis should have count == 1, same size == 16 or 32 "
334               "and align at byte boundary" << LOG_ENDL;
335         return false;
336     }
337 
338     if (reportX.unit != 0 || reportY.unit != 0 || reportZ.unit != 0) {
339         LOG_E << "Specified unit for usage is not supported" << LOG_ENDL;
340         return false;
341     }
342 
343     if (reportX.a != reportY.a || reportY.a != reportZ.a
344         || reportX.b != reportY.b || reportY.b != reportZ.b) {
345         LOG_W << "Scaling for 3 axis are different. It is recommended to keep them the same" << LOG_ENDL;
346     }
347 
348     // set features
349     mFeatureInfo.maxRange = std::max(
350         std::abs((reportX.maxRaw + reportX.b) * reportX.a),
351         std::abs((reportX.minRaw + reportX.b) * reportX.a));
352     mFeatureInfo.resolution = reportX.a * defaultScaling;
353     mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
354 
355     ReportTranslateRecord record = {
356         .type = TYPE_FLOAT,
357         .maxValue = reportX.maxRaw,
358         .minValue = reportX.minRaw,
359         .byteSize = reportX.bitSize / 8,
360     };
361 
362     // Reorder and swap axis
363     //
364     // HID class devices are encouraged, where possible, to use a right-handed
365     // coordinate system. If a user is facing a device, report values should increase as
366     // controls are moved from left to right (X), from far to near (Y) and from high to
367     // low (Z).
368     //
369 
370     // Android X axis = Hid X axis
371     record.index = 0;
372     record.a = reportX.a * defaultScaling;
373     record.b = reportX.b;
374     record.byteOffset = reportX.bitOffset / 8;
375     mTranslateTable.push_back(record);
376 
377     // Android Y axis = - Hid Z axis
378     record.index = 1;
379     record.a = -reportZ.a * defaultScaling;
380     record.b = reportZ.b;
381     record.byteOffset = reportZ.bitOffset / 8;
382     mTranslateTable.push_back(record);
383 
384     // Android Z axis = Hid Y axis
385     record.index = 2;
386     record.a = reportY.a * defaultScaling;
387     record.b = reportY.b;
388     record.byteOffset = reportY.bitOffset / 8;
389     mTranslateTable.push_back(record);
390 
391     mInputReportId = reportX.id;
392     return true;
393 }
394 
find(const std::vector<HidParser::ReportPacket> & packets,unsigned int usage,int type,int id)395 const HidParser::ReportItem *HidRawSensor::find(
396         const std::vector<HidParser::ReportPacket> &packets,
397         unsigned int usage, int type, int id) {
398     for (const auto &packet : packets) {
399         if (packet.type != type) {
400             continue;
401         }
402         auto i = std::find_if(
403                 packet.reports.begin(), packet.reports.end(),
404                 [usage, id](const HidParser::ReportItem &p) {
405                     return p.usage == usage
406                             && (id == -1 || p.id == static_cast<unsigned int>(id));
407                 });
408         if (i != packet.reports.end()) {
409             return &(*i);
410         }
411     }
412     return nullptr;
413 };
414 
initFeatureValueFromHidDeviceInfo(FeatureValue * featureValue,const HidDevice::HidDeviceInfo & info)415 void HidRawSensor::initFeatureValueFromHidDeviceInfo(
416         FeatureValue *featureValue, const HidDevice::HidDeviceInfo &info) {
417     featureValue->name = info.name;
418 
419     std::ostringstream ss;
420     ss << info.busType << " "
421        << std::hex << std::setfill('0') << std::setw(4) << info.vendorId
422        << ":" << std::setw(4) << info.productId;
423     featureValue->vendor = ss.str();
424 
425     featureValue->permission = "";
426     featureValue->typeString = "";
427     featureValue->type = -1; // invalid type
428     featureValue->version = 1;
429 
430     featureValue->maxRange = -1.f;
431     featureValue->resolution = FLT_MAX;
432     featureValue->power = 1.f; // default value, does not have a valid source yet
433 
434     featureValue->minDelay = 0;
435     featureValue->maxDelay = 0;
436 
437     featureValue->fifoSize = 0;
438     featureValue->fifoMaxSize = 0;
439 
440     featureValue->reportModeFlag = SENSOR_FLAG_SPECIAL_REPORTING_MODE;
441     featureValue->isWakeUp = false;
442     featureValue->useUniqueIdForUuid = false;
443     memset(featureValue->uuid, 0, sizeof(featureValue->uuid));
444     featureValue->isAndroidCustom = false;
445 }
446 
populateFeatureValueFromFeatureReport(FeatureValue * featureValue,const std::vector<HidParser::ReportPacket> & packets)447 bool HidRawSensor::populateFeatureValueFromFeatureReport(
448         FeatureValue *featureValue, const std::vector<HidParser::ReportPacket> &packets) {
449     SP(HidDevice) device = PROMOTE(mDevice);
450     if (device == nullptr) {
451         return false;
452     }
453 
454     std::vector<uint8_t> buffer;
455     for (const auto &packet : packets) {
456         if (packet.type != HidParser::REPORT_TYPE_FEATURE) {
457             continue;
458         }
459 
460         if (!device->getFeature(packet.id, &buffer)) {
461             continue;
462         }
463 
464         std::string str;
465         using namespace Hid::Sensor::PropertyUsage;
466         for (const auto & r : packet.reports) {
467             switch (r.usage) {
468                 case FRIENDLY_NAME:
469                     if (decodeString(r, buffer, &str) && !str.empty()) {
470                         featureValue->name = str;
471                     }
472                     break;
473                 case SENSOR_MANUFACTURER:
474                     if (decodeString(r, buffer, &str) && !str.empty()) {
475                         featureValue->vendor = str;
476                     }
477                     break;
478                 case PERSISTENT_UNIQUE_ID:
479                     if (decodeString(r, buffer, &str) && !str.empty()) {
480                         featureValue->uniqueId = str;
481                     }
482                     break;
483                 case SENSOR_DESCRIPTION:
484                     if (decodeString(r, buffer, &str)) {
485                         detectSensorFromDescription(str);
486                     }
487                     break;
488                 default:
489                     // do not care about others
490                     break;
491             }
492         }
493     }
494     return true;
495 }
496 
validateFeatureValueAndBuildSensor()497 bool HidRawSensor::validateFeatureValueAndBuildSensor() {
498     if (mFeatureInfo.name.empty() || mFeatureInfo.vendor.empty() || mFeatureInfo.typeString.empty()
499             || mFeatureInfo.type <= 0 || mFeatureInfo.maxRange <= 0
500             || mFeatureInfo.resolution <= 0) {
501         return false;
502     }
503 
504     switch (mFeatureInfo.reportModeFlag) {
505         case SENSOR_FLAG_CONTINUOUS_MODE:
506         case SENSOR_FLAG_ON_CHANGE_MODE:
507             if (mFeatureInfo.minDelay < 0) {
508                 return false;
509             }
510             if (mFeatureInfo.maxDelay != 0 && mFeatureInfo.maxDelay < mFeatureInfo.minDelay) {
511                 return false;
512             }
513             break;
514         case SENSOR_FLAG_ONE_SHOT_MODE:
515             if (mFeatureInfo.minDelay != -1 && mFeatureInfo.maxDelay != 0) {
516                 return false;
517             }
518             break;
519         case SENSOR_FLAG_SPECIAL_REPORTING_MODE:
520             if (mFeatureInfo.minDelay != -1 && mFeatureInfo.maxDelay != 0) {
521                 return false;
522             }
523             break;
524         default:
525             break;
526     }
527 
528     if (mFeatureInfo.fifoMaxSize < mFeatureInfo.fifoSize) {
529         return false;
530     }
531 
532     // initialize uuid field, use name, vendor and uniqueId
533     // initialize uuid field using one of the following methods:
534     //
535     // 1. use uniqueId
536     // 2. use name, vendor and uniqueId
537     if (mFeatureInfo.useUniqueIdForUuid) {
538         if (mFeatureInfo.uniqueId.size() == sizeof(mFeatureInfo.uuid)) {
539             memcpy(mFeatureInfo.uuid, mFeatureInfo.uniqueId.c_str(),
540                    sizeof(mFeatureInfo.uuid));
541         }
542     } else if (mFeatureInfo.name.size() >= 4
543                    && mFeatureInfo.vendor.size() >= 4
544                    && mFeatureInfo.typeString.size() >= 4
545                    && mFeatureInfo.uniqueId.size() >= 4) {
546         uint32_t tmp[4], h;
547         std::hash<std::string> stringHash;
548         h = stringHash(mFeatureInfo.uniqueId);
549         tmp[0] = stringHash(mFeatureInfo.name) ^ h;
550         tmp[1] = stringHash(mFeatureInfo.vendor) ^ h;
551         tmp[2] = stringHash(mFeatureInfo.typeString) ^ h;
552         tmp[3] = tmp[0] ^ tmp[1] ^ tmp[2];
553         memcpy(mFeatureInfo.uuid, tmp, sizeof(mFeatureInfo.uuid));
554     }
555 
556     mSensor = (sensor_t) {
557         mFeatureInfo.name.c_str(),                 // name
558         mFeatureInfo.vendor.c_str(),               // vendor
559         mFeatureInfo.version,                      // version
560         -1,                                        // handle, dummy number here
561         mFeatureInfo.type,
562         mFeatureInfo.maxRange,                     // maxRange
563         mFeatureInfo.resolution,                   // resolution
564         mFeatureInfo.power,                        // power
565         mFeatureInfo.minDelay,                     // minDelay
566         (uint32_t)mFeatureInfo.fifoSize,           // fifoReservedEventCount
567         (uint32_t)mFeatureInfo.fifoMaxSize,        // fifoMaxEventCount
568         mFeatureInfo.typeString.c_str(),           // type string
569         mFeatureInfo.permission.c_str(),           // requiredPermission
570         (long)mFeatureInfo.maxDelay,               // maxDelay
571         mFeatureInfo.reportModeFlag | (mFeatureInfo.isWakeUp ? 1 : 0),
572         { NULL, NULL }
573     };
574     return true;
575 }
576 
decodeString(const HidParser::ReportItem & report,const std::vector<uint8_t> & buffer,std::string * d)577 bool HidRawSensor::decodeString(
578         const HidParser::ReportItem &report, const std::vector<uint8_t> &buffer, std::string *d) {
579     if (!report.isByteAligned() ||
580         (report.bitSize != 8 && report.bitSize != 16) || report.count < 1) {
581         return false;
582     }
583 
584     size_t charSize = report.bitSize / 8;
585     size_t offset = report.bitOffset / 8;
586     if (offset + report.count * charSize > buffer.size()) {
587         return false;
588     }
589 
590     if (charSize == 1) {
591         *d = std::string(buffer.begin() + offset,
592                          buffer.begin() + offset + report.count);
593     } else {
594         std::vector<uint16_t> data(report.count);
595         auto i = data.begin();
596         auto j = buffer.begin() + offset;
597         for ( ; i != data.end(); ++i, j += sizeof(uint16_t)) {
598             // hid specified little endian
599             *i = *j + (*(j + 1) << 8);
600         }
601         std::wstring wstr(data.begin(), data.end());
602 
603         std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
604         *d = converter.to_bytes(wstr);
605     }
606 
607     return true;
608 }
609 
split(const std::string & text,char sep)610 std::vector<std::string> split(const std::string &text, char sep) {
611     std::vector<std::string> tokens;
612     size_t start = 0, end = 0;
613     while ((end = text.find(sep, start)) != std::string::npos) {
614         if (end != start) {
615             tokens.push_back(text.substr(start, end - start));
616         }
617         start = end + 1;
618     }
619     if (end != start) {
620         tokens.push_back(text.substr(start));
621     }
622     return tokens;
623 }
624 
detectSensorFromDescription(const std::string & description)625 void HidRawSensor::detectSensorFromDescription(const std::string &description) {
626     if (detectAndroidHeadTrackerSensor(description) ||
627         detectAndroidCustomSensor(description)) {
628         mFeatureInfo.isAndroidCustom = true;
629     }
630 }
631 
detectAndroidHeadTrackerSensor(const std::string & description)632 bool HidRawSensor::detectAndroidHeadTrackerSensor(
633         const std::string &description) {
634     if (description.find("#AndroidHeadTracker#1.") != 0) {
635         return false;
636     }
637 
638     mFeatureInfo.type = SENSOR_TYPE_HEAD_TRACKER;
639     mFeatureInfo.typeString = SENSOR_STRING_TYPE_HEAD_TRACKER;
640     mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
641     mFeatureInfo.permission = "";
642     mFeatureInfo.isWakeUp = false;
643 
644     // HID head tracker sensors must use the HID unique ID for the sensor UUID
645     // to permit association between the sensor and audio device (see
646     // specification for HEAD_TRACKER in SensorType).
647     mFeatureInfo.useUniqueIdForUuid = true;
648 
649     return true;
650 }
651 
detectAndroidCustomSensor(const std::string & description)652 bool HidRawSensor::detectAndroidCustomSensor(const std::string &description) {
653     size_t nullPosition = description.find('\0');
654     if (nullPosition == std::string::npos) {
655         return false;
656     }
657     const std::string prefix("#ANDROID#");
658     if (description.find(prefix, nullPosition + 1) != nullPosition + 1) {
659         return false;
660     }
661 
662     std::string str(description.c_str() + nullPosition + 1 + prefix.size());
663 
664     // Format for predefined sensor types:
665     // #ANDROID#nn,[C|X|T|S],[B|0],[W|N]
666     // Format for vendor type sensor
667     // #ANDROID#xxx.yyy.zzz,[C|X|T|S],[B|0],[W|N]
668     //
669     // C: continuous
670     // X: on-change
671     // T: one-shot
672     // S: special trigger
673     //
674     // B: body permission
675     // 0: no permission required
676     std::vector<std::string> segments;
677     size_t start = 0, end = 0;
678     while ((end = str.find(',', start)) != std::string::npos) {
679         if (end != start) {
680             segments.push_back(str.substr(start, end - start));
681         }
682         start = end + 1;
683     }
684     if (end != start) {
685         segments.push_back(str.substr(start));
686     }
687 
688     if (segments.size() < 4) {
689         LOG_E << "Not enough segments in android custom description" << LOG_ENDL;
690         return false;
691     }
692 
693     // type
694     bool typeParsed = false;
695     if (!segments[0].empty()) {
696         if (::isdigit(segments[0][0])) {
697             int type = ::atoi(segments[0].c_str());
698             // all supported types here
699             switch (type) {
700                 case SENSOR_TYPE_HEART_RATE:
701                     mFeatureInfo.type = SENSOR_TYPE_HEART_RATE;
702                     mFeatureInfo.typeString = SENSOR_STRING_TYPE_HEART_RATE;
703                     typeParsed = true;
704                     break;
705                 case SENSOR_TYPE_AMBIENT_TEMPERATURE:
706                     mFeatureInfo.type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
707                     mFeatureInfo.typeString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
708                     typeParsed = true;
709                     break;
710                 case SENSOR_TYPE_LIGHT:
711                     mFeatureInfo.type = SENSOR_TYPE_LIGHT;
712                     mFeatureInfo.typeString = SENSOR_STRING_TYPE_LIGHT;
713                     typeParsed = true;
714                     break;
715                 case SENSOR_TYPE_PRESSURE:
716                     mFeatureInfo.type = SENSOR_TYPE_PRESSURE;
717                     mFeatureInfo.typeString = SENSOR_STRING_TYPE_PRESSURE;
718                     typeParsed = true;
719                     break;
720                 default:
721                     LOG_W << "Android type " << type << " has not been supported yet" << LOG_ENDL;
722                     break;
723             }
724         } else {
725             // assume a xxx.yyy.zzz format
726             std::ostringstream s;
727             bool lastIsDot = true;
728             for (auto c : segments[0]) {
729                 if (::isalpha(c)) {
730                     s << static_cast<char>(c);
731                     lastIsDot = false;
732                 } else if (!lastIsDot && c == '.') {
733                     s << static_cast<char>(c);
734                     lastIsDot = true;
735                 } else {
736                     break;
737                 }
738             }
739             if (s.str() == segments[0]) {
740                 mFeatureInfo.type = SENSOR_TYPE_DEVICE_PRIVATE_BASE;
741                 mFeatureInfo.typeString = CUSTOM_TYPE_PREFIX + s.str();
742                 typeParsed = true;
743             }
744         }
745     }
746 
747     // reporting type
748     bool reportingModeParsed = false;
749     if (segments[1].size() == 1) {
750         switch (segments[1][0]) {
751             case 'C':
752                 mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
753                 reportingModeParsed = true;
754                 break;
755             case 'X':
756                 mFeatureInfo.reportModeFlag = SENSOR_FLAG_ON_CHANGE_MODE;
757                 reportingModeParsed = true;
758                 break;
759             case 'T':
760                 mFeatureInfo.reportModeFlag = SENSOR_FLAG_ONE_SHOT_MODE;
761                 reportingModeParsed = true;
762                 break;
763             case 'S':
764                 mFeatureInfo.reportModeFlag = SENSOR_FLAG_SPECIAL_REPORTING_MODE;
765                 reportingModeParsed = true;
766                 break;
767             default:
768                 LOG_E << "Undefined reporting mode designation " << segments[1] << LOG_ENDL;
769         }
770     }
771 
772     // permission parsed
773     bool permissionParsed = false;
774     if (segments[2].size() == 1) {
775         switch (segments[2][0]) {
776             case 'B':
777                 mFeatureInfo.permission = SENSOR_PERMISSION_BODY_SENSORS;
778                 permissionParsed = true;
779                 break;
780             case '0':
781                 mFeatureInfo.permission = "";
782                 permissionParsed = true;
783                 break;
784             default:
785                 LOG_E << "Undefined permission designation " << segments[2] << LOG_ENDL;
786         }
787     }
788 
789     // wake up
790     bool wakeUpParsed = false;
791     if (segments[3].size() == 1) {
792         switch (segments[3][0]) {
793             case 'W':
794                 mFeatureInfo.isWakeUp = true;
795                 wakeUpParsed = true;
796                 break;
797             case 'N':
798                 mFeatureInfo.isWakeUp = false;
799                 wakeUpParsed = true;
800                 break;
801             default:
802                 LOG_E << "Undefined wake up designation " << segments[3] << LOG_ENDL;
803         }
804     }
805 
806     int ret = typeParsed && reportingModeParsed && permissionParsed && wakeUpParsed;
807     if (!ret) {
808         LOG_D << "detectAndroidCustomSensor typeParsed: " << typeParsed
809               << " reportingModeParsed: "  << reportingModeParsed
810               << " permissionParsed: " << permissionParsed
811               << " wakeUpParsed: " << wakeUpParsed << LOG_ENDL;
812     }
813     return ret;
814 }
815 
findSensorControlUsage(const std::vector<HidParser::ReportPacket> & packets)816 bool HidRawSensor::findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets) {
817     using namespace Hid::Sensor::PowerStateUsage;
818     using namespace Hid::Sensor::PropertyUsage;
819     using namespace Hid::Sensor::ReportingStateUsage;
820 
821     //REPORTING_STATE
822     const HidParser::ReportItem *reportingState
823             = find(packets, REPORTING_STATE, HidParser::REPORT_TYPE_FEATURE);
824 
825     if (reportingState == nullptr) {
826         LOG_W << "Cannot find valid reporting state feature" << LOG_ENDL;
827     } else {
828         mReportingStateId = reportingState->id;
829         mReportingStateBitOffset = reportingState->bitOffset;
830         mReportingStateBitSize = reportingState->bitSize;
831 
832         mReportingStateDisableIndex = -1;
833         mReportingStateEnableIndex = -1;
834         for (unsigned i = 0; i < reportingState->usageVector.size(); ++i) {
835             if (reportingState->usageVector[i] == REPORTING_STATE_NO_EVENTS) {
836                 mReportingStateDisableIndex = i;
837             }
838             if (reportingState->usageVector[i] == REPORTING_STATE_ALL_EVENTS) {
839                 mReportingStateEnableIndex = i;
840             }
841         }
842         if (mReportingStateDisableIndex < 0) {
843             LOG_W << "Cannot find reporting state to disable sensor"
844                   << LOG_ENDL;
845             mReportingStateId = -1;
846         }
847         if (mReportingStateEnableIndex < 0) {
848             LOG_W << "Cannot find reporting state to enable sensor" << LOG_ENDL;
849             mReportingStateId = -1;
850         }
851     }
852 
853     //POWER_STATE
854     const HidParser::ReportItem *powerState
855             = find(packets, POWER_STATE, HidParser::REPORT_TYPE_FEATURE);
856     if (powerState == nullptr) {
857         LOG_W << "Cannot find valid power state feature" << LOG_ENDL;
858     } else {
859         mPowerStateId = powerState->id;
860         mPowerStateBitOffset = powerState->bitOffset;
861         mPowerStateBitSize = powerState->bitSize;
862 
863         mPowerStateOffIndex = -1;
864         mPowerStateOnIndex = -1;
865         for (unsigned i = 0; i < powerState->usageVector.size(); ++i) {
866             if (powerState->usageVector[i] == POWER_STATE_D4_POWER_OFF) {
867                 mPowerStateOffIndex = i;
868             }
869             if (powerState->usageVector[i] == POWER_STATE_D0_FULL_POWER) {
870                 mPowerStateOnIndex = i;
871             }
872         }
873         if (mPowerStateOffIndex < 0) {
874             LOG_W << "Cannot find power state to power off sensor"
875                   << LOG_ENDL;
876             mPowerStateId = -1;
877         }
878         if (mPowerStateOnIndex < 0) {
879             LOG_W << "Cannot find power state to power on sensor" << LOG_ENDL;
880             mPowerStateId = -1;
881         }
882     }
883 
884     //REPORT_INTERVAL
885     const HidParser::ReportItem *reportInterval
886             = find(packets, REPORT_INTERVAL, HidParser::REPORT_TYPE_FEATURE);
887     if (reportInterval == nullptr
888             || reportInterval->minRaw < 0) {
889         LOG_W << "Cannot find valid report interval feature" << LOG_ENDL;
890     } else {
891         mReportIntervalId = reportInterval->id;
892         mReportIntervalBitOffset = reportInterval->bitOffset;
893         mReportIntervalBitSize = reportInterval->bitSize;
894         mReportIntervalScale = reportInterval->a;
895         mReportIntervalOffset = reportInterval->b;
896 
897         mFeatureInfo.minDelay = 1000000.0
898                                 * (reportInterval->minRaw + reportInterval->b)
899                                 * reportInterval->a;
900         mFeatureInfo.minDelay = std::max(1000, mFeatureInfo.minDelay);
901         mFeatureInfo.maxDelay = 1000000.0
902                                 * (reportInterval->maxRaw + reportInterval->b)
903                                 * reportInterval->a;
904         mFeatureInfo.maxDelay = std::min(static_cast<int64_t>(1000000000),
905                                          mFeatureInfo.maxDelay);
906     }
907     return true;
908     return (mPowerStateId >= 0 || mReportingStateId >= 0) && mReportIntervalId >= 0;
909 }
910 
getSensor() const911 const sensor_t* HidRawSensor::getSensor() const {
912     return &mSensor;
913 }
914 
getUuid(uint8_t * uuid) const915 void HidRawSensor::getUuid(uint8_t* uuid) const {
916     memcpy(uuid, mFeatureInfo.uuid, sizeof(mFeatureInfo.uuid));
917 }
918 
enable(bool enable)919 int HidRawSensor::enable(bool enable) {
920     SP(HidDevice) device = PROMOTE(mDevice);
921 
922     if (device == nullptr) {
923         return NO_INIT;
924     }
925 
926     if (enable == mEnabled) {
927         return NO_ERROR;
928     }
929 
930     std::vector<uint8_t> buffer;
931     bool setPowerOk = true;
932     if (mPowerStateId >= 0) {
933         setPowerOk = false;
934         uint8_t id = static_cast<uint8_t>(mPowerStateId);
935         if (device->getFeature(id, &buffer)
936                 && (8 * buffer.size()) >=
937                    (mPowerStateBitOffset + mPowerStateBitSize)) {
938             uint8_t index = enable ? mPowerStateOnIndex : mPowerStateOffIndex;
939             HidUtil::copyBits(&index, &(buffer[0]), buffer.size(),
940                               0, mPowerStateBitOffset, mPowerStateBitSize);
941             setPowerOk = device->setFeature(id, buffer);
942         } else {
943             LOG_E << "enable: changing POWER STATE failed" << LOG_ENDL;
944         }
945     }
946 
947     bool setReportingOk = true;
948     if (mReportingStateId >= 0) {
949         setReportingOk = false;
950         uint8_t id = static_cast<uint8_t>(mReportingStateId);
951         if (device->getFeature(id, &buffer)
952                 && (8 * buffer.size()) >
953                    (mReportingStateBitOffset + mReportingStateBitSize)) {
954             uint8_t index = enable ? mReportingStateEnableIndex :
955                                      mReportingStateDisableIndex;
956             HidUtil::copyBits(&index, &(buffer[0]), buffer.size(),0,
957                               mReportingStateBitOffset, mReportingStateBitSize);
958             setReportingOk = device->setFeature(id, buffer);
959         } else {
960             LOG_E << "enable: changing REPORTING STATE failed" << LOG_ENDL;
961         }
962     }
963 
964     if (setPowerOk && setReportingOk) {
965         mEnabled = enable;
966         return NO_ERROR;
967     } else {
968         return INVALID_OPERATION;
969     }
970 }
971 
batch(int64_t samplingPeriod,int64_t batchingPeriod)972 int HidRawSensor::batch(int64_t samplingPeriod, int64_t batchingPeriod) {
973     SP(HidDevice) device = PROMOTE(mDevice);
974     if (device == nullptr) {
975         return NO_INIT;
976     }
977 
978     if (samplingPeriod < 0 || batchingPeriod < 0) {
979         return BAD_VALUE;
980     }
981 
982     bool needRefresh = mSamplingPeriod != samplingPeriod || mBatchingPeriod != batchingPeriod;
983     std::vector<uint8_t> buffer;
984 
985     bool ok = true;
986     if (needRefresh && mReportIntervalId >= 0) {
987         ok = false;
988         uint8_t id = static_cast<uint8_t>(mReportIntervalId);
989         if (device->getFeature(id, &buffer)
990                 && (8 * buffer.size()) >=
991                    (mReportIntervalBitOffset + mReportIntervalBitSize)) {
992             int64_t periodMs =
993                     (((static_cast<double>(samplingPeriod)) / 1000000000.0)
994                      / mReportIntervalScale) - mReportIntervalOffset;
995             int64_t maxPeriodMs =
996                 (1LL << std::min(mReportIntervalBitSize, 63U)) - 1;
997             periodMs = std::min(periodMs, maxPeriodMs);
998             HidUtil::copyBits(&periodMs, &(buffer[0]), buffer.size(),
999                               0, mReportIntervalBitOffset,
1000                               mReportIntervalBitSize);
1001             ok = device->setFeature(id, buffer);
1002         }
1003     }
1004 
1005     if (ok) {
1006         mSamplingPeriod = samplingPeriod;
1007         mBatchingPeriod = batchingPeriod;
1008         return NO_ERROR;
1009     } else {
1010         return INVALID_OPERATION;
1011     }
1012 }
1013 
handleInput(uint8_t id,const std::vector<uint8_t> & message)1014 void HidRawSensor::handleInput(uint8_t id, const std::vector<uint8_t> &message) {
1015     if (id != mInputReportId || mEnabled == false) {
1016         return;
1017     }
1018     sensors_event_t event = {
1019         .version = sizeof(event),
1020         .sensor = -1,
1021         .type = mSensor.type
1022     };
1023     bool valid = true;
1024 
1025     switch (mFeatureInfo.type) {
1026         case SENSOR_TYPE_HEAD_TRACKER:
1027             valid = getHeadTrackerEventData(message, &event);
1028             break;
1029         default:
1030             valid = getSensorEventData(message, &event);
1031             break;
1032     }
1033     if (!valid) {
1034         LOG_E << "Invalid data observed in decoding, discard" << LOG_ENDL;
1035         return;
1036     }
1037     event.timestamp = -1;
1038     generateEvent(event);
1039 }
1040 
getHeadTrackerEventData(const std::vector<uint8_t> & message,sensors_event_t * event)1041 bool HidRawSensor::getHeadTrackerEventData(const std::vector<uint8_t> &message,
1042                                            sensors_event_t *event) {
1043     head_tracker_event_t *head_tracker;
1044 
1045     head_tracker = &(event->head_tracker);
1046     if (!getReportFieldValue(message, &(mTranslateTable[0]),
1047                              &(head_tracker->rx))
1048             || !getReportFieldValue(message, &(mTranslateTable[1]),
1049                                     &(head_tracker->ry))
1050             || !getReportFieldValue(message, &(mTranslateTable[2]),
1051                                     &(head_tracker->rz))
1052             || !getReportFieldValue(message, &(mTranslateTable[3]),
1053                                     &(head_tracker->vx))
1054             || !getReportFieldValue(message, &(mTranslateTable[4]),
1055                                     &(head_tracker->vy))
1056             || !getReportFieldValue(message, &(mTranslateTable[5]),
1057                                     &(head_tracker->vz))
1058             || !getReportFieldValue(message, &(mTranslateTable[6]),
1059                                     &(head_tracker->discontinuity_count))) {
1060         return false;
1061     }
1062 
1063     return true;
1064 }
1065 
getSensorEventData(const std::vector<uint8_t> & message,sensors_event_t * event)1066 bool HidRawSensor::getSensorEventData(const std::vector<uint8_t> &message,
1067                                       sensors_event_t *event) {
1068     for (const auto &rec : mTranslateTable) {
1069         int64_t v = 0;
1070         if (rec.minValue < 0) {
1071             v = (message[rec.byteOffset + rec.byteSize - 1] & 0x80) ? -1 : 0;
1072         }
1073         for (int i = static_cast<int>(rec.byteSize) - 1; i >= 0; --i) {
1074             v = (v << 8) | message[rec.byteOffset + i]; // HID is little endian
1075         }
1076 
1077         switch (rec.type) {
1078             case TYPE_FLOAT:
1079                 if (v > rec.maxValue || v < rec.minValue) {
1080                     return false;
1081                 }
1082                 event->data[rec.index] = rec.a * (v + rec.b);
1083                 break;
1084             case TYPE_INT64:
1085                 if (v > rec.maxValue || v < rec.minValue) {
1086                     return false;
1087                 }
1088                 event->u64.data[rec.index] = v + rec.b;
1089                 break;
1090             case TYPE_ACCURACY:
1091                 event->magnetic.status = (v & 0xFF) + rec.b;
1092                 break;
1093         }
1094     }
1095 
1096     return true;
1097 }
1098 
dump() const1099 std::string HidRawSensor::dump() const {
1100     std::ostringstream ss;
1101     ss << "Feature Values " << LOG_ENDL
1102           << "  name: " << mFeatureInfo.name << LOG_ENDL
1103           << "  vendor: " << mFeatureInfo.vendor << LOG_ENDL
1104           << "  permission: " << mFeatureInfo.permission << LOG_ENDL
1105           << "  typeString: " << mFeatureInfo.typeString << LOG_ENDL
1106           << "  type: " << mFeatureInfo.type << LOG_ENDL
1107           << "  maxRange: " << mFeatureInfo.maxRange << LOG_ENDL
1108           << "  resolution: " << mFeatureInfo.resolution << LOG_ENDL
1109           << "  power: " << mFeatureInfo.power << LOG_ENDL
1110           << "  minDelay: " << mFeatureInfo.minDelay << LOG_ENDL
1111           << "  maxDelay: " << mFeatureInfo.maxDelay << LOG_ENDL
1112           << "  fifoSize: " << mFeatureInfo.fifoSize << LOG_ENDL
1113           << "  fifoMaxSize: " << mFeatureInfo.fifoMaxSize << LOG_ENDL
1114           << "  reportModeFlag: " << mFeatureInfo.reportModeFlag << LOG_ENDL
1115           << "  isWakeUp: " << (mFeatureInfo.isWakeUp ? "true" : "false") << LOG_ENDL;
1116 
1117     ss << "  uniqueId: " << std::hex << std::setfill('0');
1118     for (auto d : mFeatureInfo.uniqueId) {
1119           ss << std::setw(2) << static_cast<int>(d) << " ";
1120     }
1121     ss << std::dec << std::setfill(' ') << LOG_ENDL;
1122 
1123     ss << "  uuid: " << std::hex << std::setfill('0');
1124     for (auto d : mFeatureInfo.uuid) {
1125           ss << std::setw(2) << static_cast<int>(d) << " ";
1126     }
1127     ss << std::dec << std::setfill(' ') << LOG_ENDL;
1128 
1129     ss << "Input report id: " << mInputReportId << LOG_ENDL;
1130     for (const auto &t : mTranslateTable) {
1131         ss << "  type, index: " << t.type << ", " << t.index
1132               << "; min,max: " << t.minValue << ", " << t.maxValue
1133               << "; byte-offset,size: " << t.byteOffset << ", " << t.byteSize
1134               << "; scaling,bias: " << t.a << ", " << t.b << LOG_ENDL;
1135     }
1136 
1137     ss << "Control features: " << LOG_ENDL;
1138     ss << "  Power state ";
1139     if (mPowerStateId >= 0) {
1140         ss << "found, id: " << mPowerStateId
1141               << " bit offset: " << mPowerStateBitOffset
1142               << " bit size: " << mPowerStateBitSize
1143               << " power off index: " << mPowerStateOffIndex
1144               << " power on index: " << mPowerStateOnIndex
1145               << LOG_ENDL;
1146     } else {
1147         ss << "not found" << LOG_ENDL;
1148     }
1149 
1150     ss << "  Reporting state ";
1151     if (mReportingStateId >= 0) {
1152         ss << "found, id: " << mReportingStateId
1153               << " bit offset: " << mReportingStateBitOffset
1154               << " bit size: " << mReportingStateBitSize
1155               << " disable index: " << mReportingStateDisableIndex
1156               << " enable index: " << mReportingStateEnableIndex
1157               << LOG_ENDL;
1158     } else {
1159         ss << "not found" << LOG_ENDL;
1160     }
1161 
1162     ss << "  Report interval ";
1163     if (mReportIntervalId >= 0) {
1164         ss << "found, id: " << mReportIntervalId
1165               << " bit offset: " << mReportIntervalBitOffset
1166               << " bit size: " << mReportIntervalBitSize << LOG_ENDL;
1167     } else {
1168         ss << "not found" << LOG_ENDL;
1169     }
1170     return ss.str();
1171 }
1172 
1173 } // namespace SensorHalExt
1174 } // namespace android
1175