1 /*
2 * Copyright (C) 2015 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 <cstdlib>
18 #include <inttypes.h>
19
20 #define LOG_TAG "ActivityRecognitionHAL"
21 #include <utils/Log.h>
22
23 #include <media/stagefright/foundation/ADebug.h>
24
25 #include "activity.h"
26
27 using namespace android;
28
29 static const int kVersionMajor = 1;
30 static const int kVersionMinor = 0;
31
32 // The maximum delta between events at which point their timestamps are to be
33 // considered equal.
34 static const int64_t kEventTimestampThresholdNanos = 100000000; // 100ms.
35 static const int64_t kMaxEventAgeNanos = 10000000000; // 10000ms.
36 static const useconds_t kFlushDelayMicros = 10000; // 10ms.
37
38 static const char *const kActivityList[] = {
39 ACTIVITY_TYPE_IN_VEHICLE,
40 ACTIVITY_TYPE_ON_BICYCLE,
41 ACTIVITY_TYPE_WALKING,
42 ACTIVITY_TYPE_RUNNING,
43 ACTIVITY_TYPE_STILL,
44 ACTIVITY_TYPE_TILTING
45 };
46
47 static const int kActivitySensorMap[ARRAY_SIZE(kActivityList)][2] = {
48 { COMMS_SENSOR_ACTIVITY_IN_VEHICLE_START,
49 COMMS_SENSOR_ACTIVITY_IN_VEHICLE_STOP, },
50 { COMMS_SENSOR_ACTIVITY_ON_BICYCLE_START,
51 COMMS_SENSOR_ACTIVITY_ON_BICYCLE_STOP, },
52 { COMMS_SENSOR_ACTIVITY_WALKING_START,
53 COMMS_SENSOR_ACTIVITY_WALKING_STOP, },
54 { COMMS_SENSOR_ACTIVITY_RUNNING_START,
55 COMMS_SENSOR_ACTIVITY_RUNNING_STOP, },
56 { COMMS_SENSOR_ACTIVITY_STILL_START,
57 COMMS_SENSOR_ACTIVITY_STILL_STOP, },
58 { COMMS_SENSOR_ACTIVITY_TILTING,
59 COMMS_SENSOR_ACTIVITY_TILTING, },
60 };
61
62 // The global ActivityContext singleton.
63 static ActivityContext *gActivityContext = NULL;
64
ActivityClose(struct hw_device_t *)65 static int ActivityClose(struct hw_device_t *) {
66 ALOGI("close_activity");
67 delete gActivityContext;
68 gActivityContext = NULL;
69 return 0;
70 }
71
RegisterActivityCallbackWrapper(const struct activity_recognition_device *,const activity_recognition_callback_procs_t * callback)72 static void RegisterActivityCallbackWrapper(
73 const struct activity_recognition_device *,
74 const activity_recognition_callback_procs_t *callback) {
75 gActivityContext->registerActivityCallback(callback);
76 }
77
EnableActivityEventWrapper(const struct activity_recognition_device *,uint32_t activity_handle,uint32_t event_type,int64_t max_batch_report_latency_ns)78 static int EnableActivityEventWrapper(
79 const struct activity_recognition_device *,
80 uint32_t activity_handle,
81 uint32_t event_type,
82 int64_t max_batch_report_latency_ns) {
83 return gActivityContext->enableActivityEvent(activity_handle, event_type,
84 max_batch_report_latency_ns);
85 }
86
DisableActivityEventWrapper(const struct activity_recognition_device *,uint32_t activity_handle,uint32_t event_type)87 static int DisableActivityEventWrapper(
88 const struct activity_recognition_device *,
89 uint32_t activity_handle,
90 uint32_t event_type) {
91 return gActivityContext->disableActivityEvent(activity_handle, event_type);
92 }
93
FlushWrapper(const struct activity_recognition_device *)94 static int FlushWrapper(const struct activity_recognition_device *) {
95 return gActivityContext->flush();
96 }
97
ActivityContext(const struct hw_module_t * module)98 ActivityContext::ActivityContext(const struct hw_module_t *module)
99 : mHubConnection(HubConnection::getInstance()),
100 mCallback(NULL),
101 mNewestPublishedEventIndexIsKnown(false),
102 mNewestPublishedEventIndex(0),
103 mNewestPublishedTimestamp(0),
104 mOutstandingFlushEvents(0) {
105 memset(&device, 0, sizeof(device));
106
107 device.common.tag = HARDWARE_DEVICE_TAG;
108 device.common.version = ACTIVITY_RECOGNITION_API_VERSION_0_1;
109 device.common.module = const_cast<hw_module_t *>(module);
110 device.common.close = ActivityClose;
111 device.register_activity_callback = RegisterActivityCallbackWrapper;
112 device.enable_activity_event = EnableActivityEventWrapper;
113 device.disable_activity_event = DisableActivityEventWrapper;
114 device.flush = FlushWrapper;
115
116 if (getHubAlive()) {
117 mHubConnection->setActivityCallback(this);
118
119 // Reset the system to a known good state by disabling all transitions.
120 for (int i = COMMS_SENSOR_ACTIVITY_FIRST;
121 i <= COMMS_SENSOR_ACTIVITY_LAST; i++) {
122 mHubConnection->queueActivate(i, false /* enable */);
123 }
124 }
125 }
126
~ActivityContext()127 ActivityContext::~ActivityContext() {
128 mHubConnection->setActivityCallback(NULL);
129 }
130
131 /*
132 * Obtain the activity handle for a given activity sensor index.
133 */
GetActivityHandleFromSensorIndex(int sensorIndex)134 static int GetActivityHandleFromSensorIndex(int sensorIndex) {
135 int normalizedSensorIndex = sensorIndex - COMMS_SENSOR_ACTIVITY_FIRST;
136 return normalizedSensorIndex / 2;
137 }
138
139 /*
140 * Obtain the activity type for a given activity sensor index.
141 */
GetActivityTypeFromSensorIndex(int sensorIndex)142 static int GetActivityTypeFromSensorIndex(int sensorIndex) {
143 int normalizedSensorIndex = sensorIndex - COMMS_SENSOR_ACTIVITY_FIRST;
144 return (normalizedSensorIndex % 2) + 1;
145 }
146
PublishUnpublishedEvents()147 void ActivityContext::PublishUnpublishedEvents() {
148 if (mUnpublishedEvents.empty()) {
149 return;
150 }
151
152 while (mUnpublishedEvents.size() > 0) {
153 bool eventWasPublished = false;
154
155 for (size_t i = 0; i < mUnpublishedEvents.size(); i++) {
156 const ActivityEvent *event = &mUnpublishedEvents[i];
157 if (event->eventIndex == (uint8_t)(mNewestPublishedEventIndex + 1)) {
158 PublishEvent(*event);
159 eventWasPublished = true;
160 mUnpublishedEvents.removeAt(i);
161 break;
162 }
163 }
164
165 if (!eventWasPublished) {
166 ALOGD("Waiting on unpublished events");
167 break;
168 }
169 }
170 }
171
PublishEvent(const ActivityEvent & event)172 void ActivityContext::PublishEvent(const ActivityEvent& event) {
173 activity_event_t halEvent;
174 memset(&halEvent, 0, sizeof(halEvent));
175
176 int64_t timestampDelta = event.whenNs - mNewestPublishedTimestamp;
177 if (std::abs(timestampDelta) > kEventTimestampThresholdNanos) {
178 mNewestPublishedTimestamp = event.whenNs;
179 }
180
181 halEvent.activity = GetActivityHandleFromSensorIndex(event.sensorIndex);
182 halEvent.timestamp = mNewestPublishedTimestamp;
183
184 if (event.sensorIndex == COMMS_SENSOR_ACTIVITY_TILTING) {
185 ALOGD("Publishing tilt event (enter/exit)");
186
187 // Publish two events (enter/exit) for TILTING events.
188 halEvent.event_type = ACTIVITY_EVENT_ENTER;
189 (*mCallback->activity_callback)(mCallback, &halEvent, 1);
190
191 halEvent.event_type = ACTIVITY_EVENT_EXIT;
192 } else {
193 ALOGD("Publishing event - activity_handle: %d, event_type: %d"
194 ", timestamp: %" PRIu64,
195 halEvent.activity, halEvent.event_type, halEvent.timestamp);
196
197 // Just a single event is required for all other activity types.
198 halEvent.event_type = GetActivityTypeFromSensorIndex(event.sensorIndex);
199 }
200
201 (*mCallback->activity_callback)(mCallback, &halEvent, 1);
202 mNewestPublishedEventIndex = event.eventIndex;
203 mNewestPublishedEventIndexIsKnown = true;
204 }
205
DiscardExpiredUnpublishedEvents(uint64_t whenNs)206 void ActivityContext::DiscardExpiredUnpublishedEvents(uint64_t whenNs) {
207 // Determine the current oldest buffered event.
208 uint64_t oldestEventTimestamp = UINT64_MAX;
209 for (size_t i = 0; i < mUnpublishedEvents.size(); i++) {
210 const ActivityEvent *event = &mUnpublishedEvents[i];
211 if (event->whenNs < oldestEventTimestamp) {
212 oldestEventTimestamp = event->whenNs;
213 }
214 }
215
216 // If the age of the oldest buffered event is too large an AR sample
217 // has been lost. When this happens all AR transitions are set to
218 // ACTIVITY_EVENT_EXIT and the event ordering logic is reset.
219 if (oldestEventTimestamp != UINT64_MAX
220 && (whenNs - oldestEventTimestamp) > kMaxEventAgeNanos) {
221 ALOGD("Lost event detected, discarding buffered events");
222
223 // Publish stop events for all activity types except for TILTING.
224 for (uint32_t activity = 0;
225 activity < (ARRAY_SIZE(kActivityList) - 1); activity++) {
226 activity_event_t halEvent;
227 memset(&halEvent, 0, sizeof(halEvent));
228
229 halEvent.activity = activity;
230 halEvent.timestamp = oldestEventTimestamp;
231 halEvent.event_type = ACTIVITY_EVENT_EXIT;
232 (*mCallback->activity_callback)(mCallback, &halEvent, 1);
233 }
234
235 // Reset the event reordering logic.
236 OnSensorHubReset();
237 }
238 }
239
OnActivityEvent(int sensorIndex,uint8_t eventIndex,uint64_t whenNs)240 void ActivityContext::OnActivityEvent(int sensorIndex, uint8_t eventIndex,
241 uint64_t whenNs) {
242 ALOGD("OnActivityEvent sensorIndex = %d, eventIndex = %" PRIu8
243 ", whenNs = %" PRIu64, sensorIndex, eventIndex, whenNs);
244
245 Mutex::Autolock autoLock(mCallbackLock);
246 if (!mCallback) {
247 return;
248 }
249
250 DiscardExpiredUnpublishedEvents(whenNs);
251
252 ActivityEvent event = {
253 .eventIndex = eventIndex,
254 .sensorIndex = sensorIndex,
255 .whenNs = whenNs,
256 };
257
258 if (!mNewestPublishedEventIndexIsKnown
259 || eventIndex == (uint8_t)(mNewestPublishedEventIndex + 1)) {
260 PublishEvent(event);
261 PublishUnpublishedEvents();
262 } else {
263 ALOGD("OnActivityEvent out of order, pushing back");
264 mUnpublishedEvents.push(event);
265 }
266 }
267
OnFlush()268 void ActivityContext::OnFlush() {
269 // Once the number of outstanding flush events has reached zero, publish an
270 // event via the AR HAL.
271 Mutex::Autolock autoLock(mCallbackLock);
272 if (!mCallback) {
273 return;
274 }
275
276 // For each flush event from the sensor hub, decrement the counter of
277 // outstanding flushes.
278 mOutstandingFlushEvents--;
279 if (mOutstandingFlushEvents > 0) {
280 ALOGV("OnFlush with %d outstanding flush events", mOutstandingFlushEvents);
281 return;
282 } else if (mOutstandingFlushEvents < 0) {
283 // This can happen on app start.
284 ALOGD("more flush events received than requested");
285 mOutstandingFlushEvents = 0;
286 }
287
288 activity_event_t ev = {
289 .event_type = ACTIVITY_EVENT_FLUSH_COMPLETE,
290 .activity = 0,
291 .timestamp = 0ll,
292 };
293
294 (*mCallback->activity_callback)(mCallback, &ev, 1);
295 ALOGD("OnFlush published");
296 }
297
OnSensorHubReset()298 void ActivityContext::OnSensorHubReset() {
299 // Reset the unpublished event queue and clear the last known published
300 // event index.
301 mUnpublishedEvents.clear();
302 mNewestPublishedEventIndexIsKnown = false;
303 mOutstandingFlushEvents = 0;
304 mNewestPublishedTimestamp = 0;
305 }
306
registerActivityCallback(const activity_recognition_callback_procs_t * callback)307 void ActivityContext::registerActivityCallback(
308 const activity_recognition_callback_procs_t *callback) {
309 ALOGI("registerActivityCallback");
310
311 Mutex::Autolock autoLock(mCallbackLock);
312 mCallback = callback;
313 }
314
315 /*
316 * Returns a sensor index for a given activity handle and transition type.
317 */
GetActivitySensorForHandleAndType(uint32_t activity_handle,uint32_t event_type)318 int GetActivitySensorForHandleAndType(uint32_t activity_handle,
319 uint32_t event_type) {
320 // Ensure that the requested activity index is valid.
321 if (activity_handle >= ARRAY_SIZE(kActivityList)) {
322 return 0;
323 }
324
325 // Ensure that the event type is either an ENTER or EXIT.
326 if (event_type < ACTIVITY_EVENT_ENTER || event_type > ACTIVITY_EVENT_EXIT) {
327 return 0;
328 }
329
330 return kActivitySensorMap[activity_handle][event_type - 1];
331 }
332
enableActivityEvent(uint32_t activity_handle,uint32_t event_type,int64_t max_report_latency_ns)333 int ActivityContext::enableActivityEvent(uint32_t activity_handle,
334 uint32_t event_type, int64_t max_report_latency_ns) {
335 ALOGI("enableActivityEvent - activity_handle: %" PRIu32
336 ", event_type: %" PRIu32 ", latency: %" PRId64,
337 activity_handle, event_type, max_report_latency_ns);
338
339 int sensor_index = GetActivitySensorForHandleAndType(activity_handle,
340 event_type);
341 if (sensor_index <= 0) {
342 ALOGE("Enabling invalid activity_handle: %" PRIu32
343 ", event_type: %" PRIu32, activity_handle, event_type);
344 return 1;
345 }
346
347 mHubConnection->queueBatch(sensor_index, 1000000, max_report_latency_ns);
348 mHubConnection->queueActivate(sensor_index, true /* enable */);
349 return 0;
350 }
351
disableActivityEvent(uint32_t activity_handle,uint32_t event_type)352 int ActivityContext::disableActivityEvent(uint32_t activity_handle,
353 uint32_t event_type) {
354 ALOGI("disableActivityEvent");
355
356 // Obtain the sensor index for the requested activity and transition types.
357 int sensor_index = kActivitySensorMap[activity_handle][event_type - 1];
358 if (sensor_index > 0) {
359 mHubConnection->queueActivate(sensor_index, false /* enable */);
360 } else {
361 ALOGE("Disabling invalid activity_handle: %" PRIu32
362 ", event_type: %" PRIu32, activity_handle, event_type);
363 }
364
365 return 0;
366 }
367
flush()368 int ActivityContext::flush() {
369 {
370 // Aquire a lock for the mOutstandingFlushEvents shared state. OnFlush
371 // modifies this value as flush results are returned. Nested scope is
372 // used here to control the lifecycle of the lock as OnFlush may be
373 // invoked before this method returns.
374 Mutex::Autolock autoLock(mCallbackLock);
375 mOutstandingFlushEvents +=
376 (COMMS_SENSOR_ACTIVITY_LAST - COMMS_SENSOR_ACTIVITY_FIRST) + 1;
377 }
378
379 // Flush all activity sensors.
380 for (int i = COMMS_SENSOR_ACTIVITY_FIRST;
381 i <= COMMS_SENSOR_ACTIVITY_LAST; i++) {
382 mHubConnection->queueFlush(i);
383 usleep(kFlushDelayMicros);
384 }
385
386 return 0;
387 }
388
getHubAlive()389 bool ActivityContext::getHubAlive() {
390 return mHubConnection->initCheck() == OK
391 && mHubConnection->getAliveCheck() == OK;
392 }
393
394 ////////////////////////////////////////////////////////////////////////////////
395
open_activity(const struct hw_module_t * module,const char *,struct hw_device_t ** dev)396 static int open_activity(
397 const struct hw_module_t *module,
398 const char *,
399 struct hw_device_t **dev) {
400 ALOGI("open_activity");
401
402 gActivityContext = new ActivityContext(module);
403 *dev = &gActivityContext->device.common;
404 return 0;
405 }
406
407 static struct hw_module_methods_t activity_module_methods = {
408 .open = open_activity
409 };
410
get_activity_list(struct activity_recognition_module *,char const * const ** activity_list)411 static int get_activity_list(struct activity_recognition_module *,
412 char const* const **activity_list) {
413 ALOGI("get_activity_list");
414
415 if (gActivityContext != NULL && gActivityContext->getHubAlive()) {
416 *activity_list = kActivityList;
417 return sizeof(kActivityList) / sizeof(kActivityList[0]);
418 } else {
419 *activity_list = {};
420 return 0;
421 }
422 }
423
424 struct activity_recognition_module HAL_MODULE_INFO_SYM = {
425 .common = {
426 .tag = HARDWARE_MODULE_TAG,
427 .version_major = kVersionMajor,
428 .version_minor = kVersionMinor,
429 .id = ACTIVITY_RECOGNITION_HARDWARE_MODULE_ID,
430 .name = "Google Activity Recognition module",
431 .author = "Google",
432 .methods = &activity_module_methods,
433 .dso = NULL,
434 .reserved = {0},
435 },
436 .get_supported_activities_list = get_activity_list,
437 };
438