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