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 65 static int ActivityClose(struct hw_device_t *) { 66 ALOGI("close_activity"); 67 delete gActivityContext; 68 gActivityContext = NULL; 69 return 0; 70 } 71 72 static void RegisterActivityCallbackWrapper( 73 const struct activity_recognition_device *, 74 const activity_recognition_callback_procs_t *callback) { 75 gActivityContext->registerActivityCallback(callback); 76 } 77 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 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 94 static int FlushWrapper(const struct activity_recognition_device *) { 95 return gActivityContext->flush(); 96 } 97 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 127 ActivityContext::~ActivityContext() { 128 mHubConnection->setActivityCallback(NULL); 129 } 130 131 /* 132 * Obtain the activity handle for a given activity sensor index. 133 */ 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 */ 142 static int GetActivityTypeFromSensorIndex(int sensorIndex) { 143 int normalizedSensorIndex = sensorIndex - COMMS_SENSOR_ACTIVITY_FIRST; 144 return (normalizedSensorIndex % 2) + 1; 145 } 146 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 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 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 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 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 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 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 */ 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 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 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 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 389 bool ActivityContext::getHubAlive() { 390 return mHubConnection->initCheck() == OK 391 && mHubConnection->getAliveCheck() == OK; 392 } 393 394 //////////////////////////////////////////////////////////////////////////////// 395 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 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