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 #define LOG_TAG "ActivityRecognitionHAL"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include "activity.h"
22
23 #include <media/stagefright/foundation/ADebug.h>
24
25 using namespace android;
26
27 static const int kVersionMajor = 1;
28 static const int kVersionMinor = 0;
29
30 static const int ACTIVITY_TYPE_TILTING_INDEX = 6;
31
32 static const char *const kActivityList[] = {
33 ACTIVITY_TYPE_IN_VEHICLE,
34 ACTIVITY_TYPE_ON_BICYCLE,
35 ACTIVITY_TYPE_WALKING,
36 ACTIVITY_TYPE_RUNNING,
37 ACTIVITY_TYPE_STILL,
38 "com.google.android.contexthub.ar.inconsistent",
39 ACTIVITY_TYPE_TILTING
40 };
41
ActivityContext(const struct hw_module_t * module)42 ActivityContext::ActivityContext(const struct hw_module_t *module)
43 : mHubConnection(HubConnection::getInstance()),
44 mHubAlive(true),
45 mCallback(NULL),
46 mPrevActivity(-1),
47 mInitExitDone(false) {
48 memset(&device, 0, sizeof(device));
49
50 device.common.tag = HARDWARE_DEVICE_TAG;
51 device.common.version = ACTIVITY_RECOGNITION_API_VERSION_0_1;
52 device.common.module = const_cast<hw_module_t *>(module);
53 device.common.close = CloseWrapper;
54 device.register_activity_callback = RegisterActivityCallbackWrapper;
55 device.enable_activity_event = EnableActivityEventWrapper;
56 device.disable_activity_event = DisableActivityEventWrapper;
57 device.flush = FlushWrapper;
58
59 if (mHubConnection->initCheck() != (status_t)OK) {
60 mHubAlive = false;
61 } else {
62 if (mHubConnection->getAliveCheck() != (status_t)OK) {
63 mHubAlive = false;
64 } else {
65 mHubConnection->setActivityCallback(
66 this, &ActivityContext::HubCallbackWrapper);
67
68 mHubConnection->queueActivate(COMMS_SENSOR_ACTIVITY, false /* enable */);
69 }
70 }
71 }
72
~ActivityContext()73 ActivityContext::~ActivityContext() {
74 mHubConnection->setActivityCallback(NULL, NULL);
75 }
76
close()77 int ActivityContext::close() {
78 ALOGI("close");
79
80 delete this;
81
82 return 0;
83 }
84
onActivityEvent(uint64_t when_us,bool is_flush,float x,float,float)85 void ActivityContext::onActivityEvent(
86 uint64_t when_us, bool is_flush, float x, float, float) {
87 Mutex::Autolock autoLock(mLock);
88
89 if (!mCallback) {
90 return;
91 }
92
93 if (is_flush) {
94 activity_event_t ev;
95 memset(&ev, 0, sizeof(ev));
96
97 ev.event_type = ACTIVITY_EVENT_FLUSH_COMPLETE;
98 ev.activity = 0;
99 ev.timestamp = 0ll;
100
101 (*mCallback->activity_callback)(mCallback, &ev, 1);
102 return;
103 }
104
105 int activityRaw = (int)x;
106
107 ALOGV("activityRaw = %d", activityRaw);
108
109 if (mPrevActivity >= 0 && mPrevActivity == activityRaw) {
110 // same old, same old...
111 return;
112 }
113
114 activity_event_t ev[8];
115 memset(&ev, 0, 8*sizeof(activity_event_t));
116 int num_events = 0;
117
118 // exit all other activities when first enabled.
119 if (!mInitExitDone) {
120 mInitExitDone = true;
121
122 int numActivities = sizeof(kActivityList) / sizeof(kActivityList[0]);
123 for (int i = 0; i < numActivities; ++i) {
124 if ((i == activityRaw) || !isEnabled(i, ACTIVITY_EVENT_EXIT)) {
125 continue;
126 }
127
128 activity_event_t *curr_ev = &ev[num_events];
129 curr_ev->event_type = ACTIVITY_EVENT_EXIT;
130 curr_ev->activity = i;
131 curr_ev->timestamp = when_us * 1000ll; // timestamp is in ns.
132 curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0;
133 num_events++;
134 }
135 }
136
137 // tilt activities do not change the current activity type, but have a
138 // simultaneous enter and exit event type
139 if (activityRaw == ACTIVITY_TYPE_TILTING_INDEX) {
140 if (isEnabled(activityRaw, ACTIVITY_EVENT_ENTER)) {
141 activity_event_t *curr_ev = &ev[num_events];
142 curr_ev->event_type = ACTIVITY_EVENT_ENTER;
143 curr_ev->activity = activityRaw;
144 curr_ev->timestamp = when_us * 1000ll; // timestamp is in ns.
145 curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0;
146 num_events++;
147 }
148
149 if (isEnabled(activityRaw, ACTIVITY_EVENT_EXIT)) {
150 activity_event_t *curr_ev = &ev[num_events];
151 curr_ev->event_type = ACTIVITY_EVENT_EXIT;
152 curr_ev->activity = activityRaw;
153 curr_ev->timestamp = when_us * 1000ll; // timestamp is in ns.
154 curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0;
155 num_events++;
156 }
157 } else {
158 if ((mPrevActivity >= 0) &&
159 (isEnabled(mPrevActivity, ACTIVITY_EVENT_EXIT))) {
160 activity_event_t *curr_ev = &ev[num_events];
161 curr_ev->event_type = ACTIVITY_EVENT_EXIT;
162 curr_ev->activity = mPrevActivity;
163 curr_ev->timestamp = when_us * 1000ll; // timestamp is in ns.
164 curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0;
165 num_events++;
166 }
167
168 if (isEnabled(activityRaw, ACTIVITY_EVENT_ENTER)) {
169 activity_event_t *curr_ev = &ev[num_events];
170 curr_ev->event_type = ACTIVITY_EVENT_ENTER;
171 curr_ev->activity = activityRaw;
172 curr_ev->timestamp = when_us * 1000ll; // timestamp is in ns.
173 curr_ev->reserved[0] = curr_ev->reserved[1] = curr_ev->reserved[2] = curr_ev->reserved[3] = 0;
174 num_events++;
175 }
176
177 mPrevActivity = activityRaw;
178 }
179
180 if (num_events > 0) {
181 (*mCallback->activity_callback)(mCallback, ev, num_events);
182 }
183 }
184
registerActivityCallback(const activity_recognition_callback_procs_t * callback)185 void ActivityContext::registerActivityCallback(
186 const activity_recognition_callback_procs_t *callback) {
187 ALOGI("registerActivityCallback");
188
189 Mutex::Autolock autoLock(mLock);
190 mCallback = callback;
191 }
192
enableActivityEvent(uint32_t activity_handle,uint32_t event_type,int64_t max_batch_report_latency_ns)193 int ActivityContext::enableActivityEvent(
194 uint32_t activity_handle,
195 uint32_t event_type,
196 int64_t max_batch_report_latency_ns) {
197 ALOGI("enableActivityEvent");
198
199 bool wasEnabled = !mMaxBatchReportLatencyNs.isEmpty();
200 int64_t prev_latency = calculateReportLatencyNs();
201
202 ALOGD_IF(DEBUG_ACTIVITY_RECOGNITION, "ACTVT type = %u, latency = %d sec", (unsigned) event_type,
203 (int)(max_batch_report_latency_ns/1000000000ull));
204
205 mMaxBatchReportLatencyNs.add(
206 ((uint64_t)activity_handle << 32) | event_type,
207 max_batch_report_latency_ns);
208
209 if (!wasEnabled) {
210 mPrevActivity = -1;
211 mInitExitDone = false;
212
213 mHubConnection->queueBatch(
214 COMMS_SENSOR_ACTIVITY, SENSOR_FLAG_ON_CHANGE_MODE, 1000000, max_batch_report_latency_ns);
215 mHubConnection->queueActivate(COMMS_SENSOR_ACTIVITY, true /* enable */);
216 } else if (max_batch_report_latency_ns != prev_latency) {
217 mHubConnection->queueBatch(
218 COMMS_SENSOR_ACTIVITY, SENSOR_FLAG_ON_CHANGE_MODE, 1000000, max_batch_report_latency_ns);
219 }
220
221 return 0;
222 }
223
calculateReportLatencyNs()224 int64_t ActivityContext::calculateReportLatencyNs() {
225 int64_t ret = INT64_MAX;
226
227 for (size_t i = 0 ; i < mMaxBatchReportLatencyNs.size(); ++i) {
228 if (mMaxBatchReportLatencyNs[i] <ret) {
229 ret = mMaxBatchReportLatencyNs[i];
230 }
231 }
232 return ret;
233 }
234
disableActivityEvent(uint32_t activity_handle,uint32_t event_type)235 int ActivityContext::disableActivityEvent(
236 uint32_t activity_handle, uint32_t event_type) {
237 ALOGI("disableActivityEvent");
238
239 bool wasEnabled = !mMaxBatchReportLatencyNs.isEmpty();
240
241 mMaxBatchReportLatencyNs.removeItem(
242 ((uint64_t)activity_handle << 32) | event_type);
243
244 bool isEnabled = !mMaxBatchReportLatencyNs.isEmpty();
245
246 if (wasEnabled && !isEnabled) {
247 mHubConnection->queueActivate(COMMS_SENSOR_ACTIVITY, false /* enable */);
248 }
249
250 return 0;
251 }
252
isEnabled(uint32_t activity_handle,uint32_t event_type) const253 bool ActivityContext::isEnabled(
254 uint32_t activity_handle, uint32_t event_type) const {
255 return mMaxBatchReportLatencyNs.indexOfKey(
256 ((uint64_t)activity_handle << 32) | event_type) >= 0;
257 }
258
flush()259 int ActivityContext::flush() {
260 mHubConnection->queueFlush(COMMS_SENSOR_ACTIVITY);
261 return 0;
262 }
263
264 // static
CloseWrapper(struct hw_device_t * dev)265 int ActivityContext::CloseWrapper(struct hw_device_t *dev) {
266 return reinterpret_cast<ActivityContext *>(dev)->close();
267 }
268
269 // static
RegisterActivityCallbackWrapper(const struct activity_recognition_device * dev,const activity_recognition_callback_procs_t * callback)270 void ActivityContext::RegisterActivityCallbackWrapper(
271 const struct activity_recognition_device *dev,
272 const activity_recognition_callback_procs_t *callback) {
273 const_cast<ActivityContext *>(
274 reinterpret_cast<const ActivityContext *>(dev))
275 ->registerActivityCallback(callback);
276 }
277
278 // static
EnableActivityEventWrapper(const struct activity_recognition_device * dev,uint32_t activity_handle,uint32_t event_type,int64_t max_batch_report_latency_ns)279 int ActivityContext::EnableActivityEventWrapper(
280 const struct activity_recognition_device *dev,
281 uint32_t activity_handle,
282 uint32_t event_type,
283 int64_t max_batch_report_latency_ns) {
284 return const_cast<ActivityContext *>(
285 reinterpret_cast<const ActivityContext *>(dev))
286 ->enableActivityEvent(
287 activity_handle, event_type, max_batch_report_latency_ns);
288 }
289
290 // static
DisableActivityEventWrapper(const struct activity_recognition_device * dev,uint32_t activity_handle,uint32_t event_type)291 int ActivityContext::DisableActivityEventWrapper(
292 const struct activity_recognition_device *dev,
293 uint32_t activity_handle,
294 uint32_t event_type) {
295 return const_cast<ActivityContext *>(
296 reinterpret_cast<const ActivityContext *>(dev))
297 ->disableActivityEvent(activity_handle, event_type);
298 }
299
300 // static
FlushWrapper(const struct activity_recognition_device * dev)301 int ActivityContext::FlushWrapper(
302 const struct activity_recognition_device *dev) {
303 return const_cast<ActivityContext *>(
304 reinterpret_cast<const ActivityContext *>(dev))->flush();
305 }
306
307 // static
HubCallbackWrapper(void * me,uint64_t time_ms,bool is_flush,float x,float y,float z)308 void ActivityContext::HubCallbackWrapper(
309 void *me, uint64_t time_ms, bool is_flush, float x, float y, float z) {
310 static_cast<ActivityContext *>(me)->onActivityEvent(time_ms, is_flush, x, y, z);
311 }
312
getHubAlive()313 bool ActivityContext::getHubAlive() {
314 return mHubAlive;
315 }
316
317 ////////////////////////////////////////////////////////////////////////////////
318
319 static bool gHubAlive = false;
320
open_activity(const struct hw_module_t * module,const char *,struct hw_device_t ** dev)321 static int open_activity(
322 const struct hw_module_t *module,
323 const char *,
324 struct hw_device_t **dev) {
325 ALOGI("open_activity");
326
327 ActivityContext *ctx = new ActivityContext(module);
328
329 gHubAlive = ctx->getHubAlive();
330 *dev = &ctx->device.common;
331
332 return 0;
333 }
334
335 static struct hw_module_methods_t activity_module_methods = {
336 .open = open_activity
337 };
338
get_activity_list(struct activity_recognition_module *,char const * const ** activity_list)339 static int get_activity_list(
340 struct activity_recognition_module *,
341 char const* const **activity_list) {
342 ALOGI("get_activity_list");
343
344 if (gHubAlive) {
345 *activity_list = kActivityList;
346 return sizeof(kActivityList) / sizeof(kActivityList[0]);
347 } else {
348 *activity_list = {};
349 return 0;
350 }
351 }
352
353 struct activity_recognition_module HAL_MODULE_INFO_SYM = {
354 .common = {
355 .tag = HARDWARE_MODULE_TAG,
356 .version_major = kVersionMajor,
357 .version_minor = kVersionMinor,
358 .id = ACTIVITY_RECOGNITION_HARDWARE_MODULE_ID,
359 .name = "Google Activity Recognition module",
360 .author = "Google",
361 .methods = &activity_module_methods,
362 .dso = NULL,
363 .reserved = {0},
364 },
365 .get_supported_activities_list = get_activity_list,
366 };
367
368