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 
17 #include "BaseSensorObject.h"
18 #include "ConnectionDetector.h"
19 #include "DummyDynamicAccelDaemon.h"
20 #include "DynamicSensorManager.h"
21 
22 #include <cutils/properties.h>
23 #include <utils/Log.h>
24 #include <utils/SystemClock.h>
25 #include <utils/misc.h>
26 
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <algorithm>            //std::max
30 
31 #define SYSPROP_PREFIX                  "vendor.dynamic_sensor.mock"
32 #define FILE_NAME_BASE                  "dummy_accel_file"
33 #define FILE_NAME_REGEX                 ("^" FILE_NAME_BASE "[0-9]$")
34 
35 namespace android {
36 namespace SensorHalExt {
37 
DummyDynamicAccelDaemon(DynamicSensorManager & manager)38 DummyDynamicAccelDaemon::DummyDynamicAccelDaemon(DynamicSensorManager& manager)
39         : BaseDynamicSensorDaemon(manager) {
40     char property[PROPERTY_VALUE_MAX+1];
41 
42     property_get(SYSPROP_PREFIX ".file", property, "");
43     if (strcmp(property, "") != 0) {
44         mFileDetector = new FileConnectionDetector(
45                 this, std::string(property), std::string(FILE_NAME_REGEX));
46         mFileDetector->Init();
47     }
48 
49     property_get(SYSPROP_PREFIX ".socket", property, "");
50     if (strcmp(property, "") != 0) {
51         mSocketDetector = new SocketConnectionDetector(this, atoi(property));
52         mSocketDetector->Init();
53     }
54 }
55 
createSensor(const std::string & deviceKey)56 BaseSensorVector DummyDynamicAccelDaemon::createSensor(const std::string &deviceKey) {
57     BaseSensorVector ret;
58     if (deviceKey.compare(0, 1, "/") == 0) {
59         // file detector result, deviceKey is file absolute path
60         const size_t len = ::strlen(FILE_NAME_BASE) + 1; // +1 for number
61         if (deviceKey.length() < len) {
62             ALOGE("illegal file device key %s", deviceKey.c_str());
63         } else {
64             size_t start = deviceKey.length() - len;
65             ret.emplace_back(new DummySensor(deviceKey.substr(start)));
66         }
67     } else if (deviceKey.compare(0, ::strlen("socket:"), "socket:") == 0) {
68         ret.emplace_back(new DummySensor(deviceKey));
69     } else {
70         // unknown deviceKey
71         ALOGE("unknown deviceKey: %s", deviceKey.c_str());
72     }
73     return ret;
74 }
75 
DummySensor(const std::string & name)76 DummyDynamicAccelDaemon::DummySensor::DummySensor(const std::string &name)
77         : Thread(false /*canCallJava*/), mRunState(false) {
78     mSensorName = "Dummy Accel - " + name;
79     // fake sensor information for dummy sensor
80     mSensor = (struct sensor_t) {
81         mSensorName.c_str(),
82         "DemoSense, Inc.",
83         1,                                         // version
84         -1,                                        // handle, dummy number here
85         SENSOR_TYPE_ACCELEROMETER,
86         9.8 * 8.0f,                                // maxRange
87         9.8 * 8.0f / 32768.0f,                     // resolution
88         0.5f,                                      // power
89         (int32_t)(1.0E6f / 50),                    // minDelay
90         0,                                         // fifoReservedEventCount
91         0,                                         // fifoMaxEventCount
92         SENSOR_STRING_TYPE_ACCELEROMETER,
93         "",                                        // requiredPermission
94         (long)(1.0E6f / 50),                       // maxDelay
95         SENSOR_FLAG_CONTINUOUS_MODE,
96         { NULL, NULL }
97     };
98     mRunLock.lock();
99     run("DummySensor");
100 }
101 
~DummySensor()102 DummyDynamicAccelDaemon::DummySensor::~DummySensor() {
103     requestExitAndWait();
104     // unlock mRunLock so thread can be unblocked
105     mRunLock.unlock();
106 }
107 
getSensor() const108 const sensor_t* DummyDynamicAccelDaemon::DummySensor::getSensor() const {
109     return &mSensor;
110 }
111 
getUuid(uint8_t * uuid) const112 void DummyDynamicAccelDaemon::DummySensor::getUuid(uint8_t* uuid) const {
113     // at maximum, there will be always one instance, so we can hardcode
114     size_t hash = std::hash<std::string>()(mSensorName);
115     memset(uuid, 'x', 16);
116     memcpy(uuid, &hash, sizeof(hash));
117 }
118 
enable(bool enable)119 int DummyDynamicAccelDaemon::DummySensor::enable(bool enable) {
120     std::lock_guard<std::mutex> lk(mLock);
121     if (mRunState != enable) {
122         if (enable) {
123             mRunLock.unlock();
124         } else {
125             mRunLock.lock();
126         }
127         mRunState = enable;
128     }
129     return 0;
130 }
131 
batch(int64_t,int64_t)132 int DummyDynamicAccelDaemon::DummySensor::batch(int64_t /*samplePeriod*/, int64_t /*batchPeriod*/) {
133     // Dummy sensor does not support changing rate and batching. But return successful anyway.
134     return 0;
135 }
136 
waitUntilNextSample()137 void DummyDynamicAccelDaemon::DummySensor::waitUntilNextSample() {
138     // block when disabled (mRunLock locked)
139     mRunLock.lock();
140     mRunLock.unlock();
141 
142     if (!Thread::exitPending()) {
143         // sleep 20 ms (50Hz)
144         usleep(20000);
145     }
146 }
147 
threadLoop()148 bool DummyDynamicAccelDaemon::DummySensor::threadLoop() {
149     // designated intialization will leave the unspecified fields zeroed
150     sensors_event_t event = {
151         .version = sizeof(event),
152         .sensor = -1,
153         .type = SENSOR_TYPE_ACCELEROMETER,
154     };
155 
156     int64_t startTimeNs = elapsedRealtimeNano();
157 
158     ALOGI("Dynamic Dummy Accel started for sensor %s", mSensorName.c_str());
159     while (!Thread::exitPending()) {
160         waitUntilNextSample();
161 
162         if (Thread::exitPending()) {
163             break;
164         }
165         int64_t nowTimeNs = elapsedRealtimeNano();
166         float t = (nowTimeNs - startTimeNs) / 1e9f;
167 
168         event.data[0] = 2 * ::sin(3 * M_PI * t);
169         event.data[1] = 3 * ::cos(3 * M_PI * t);
170         event.data[2] = 1.5 * ::sin(6 * M_PI * t);
171         event.timestamp = nowTimeNs;
172         generateEvent(event);
173     }
174 
175     ALOGI("Dynamic Dummy Accel thread ended for sensor %s", mSensorName.c_str());
176     return false;
177 }
178 
179 } // namespace SensorHalExt
180 } // namespace android
181 
182