blob: 87247292a73b878a0d95e3f5eb73ce96c3cb0652 [file] [log] [blame]
Peng Xu9ff7d222016-02-11 13:02:05 -08001/*
2 * Copyright 2016, 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 "context_hub.h"
18
19#include <string.h>
20#include <stdint.h>
21#include <stdio.h>
22
23#include <jni.h>
24#include "JNIHelp.h"
25#include "core_jni_helpers.h"
26#include "stdint.h"
27#include "stdlib.h"
28
29
30namespace android {
31
32namespace {
33
34// TODO: We should share this array_length function widely around Android
35// code.
36/*
37 * Finds the length of a statically-sized array using template trickery that
38 * also prevents it from being applied to the wrong type.
39 */
40template <typename T, size_t N>
41constexpr size_t array_length(T (&)[N]) { return N; }
42
43struct jniInfo_s {
44 JavaVM *vm;
45 jclass contextHubInfoClass;
46 jclass contextHubServiceClass;
47 jclass memoryRegionsClass;
48
49 jobject jContextHubService;
50
51 jmethodID msgReceiptCallBack;
52
53 jmethodID contextHubInfoCtor;
54 jmethodID contextHubInfoSetId;
55 jmethodID contextHubInfoSetName;
56 jmethodID contextHubInfoSetVendor;
57 jmethodID contextHubInfoSetToolchain;
58 jmethodID contextHubInfoSetPlatformVersion;
59 jmethodID contextHubInfoSetStaticSwVersion;
60 jmethodID contextHubInfoSetToolchainVersion;
61 jmethodID contextHubInfoSetPeakMips;
62 jmethodID contextHubInfoSetStoppedPowerDrawMw;
63 jmethodID contextHubInfoSetSleepPowerDrawMw;
64 jmethodID contextHubInfoSetPeakPowerDrawMw;
65 jmethodID contextHubInfoSetSupportedSensors;
66 jmethodID contextHubInfoSetMemoryRegions;
67
68 jmethodID contextHubServiceMsgReceiptCallback;
69};
70
71struct context_hub_info_s {
72 int cookie;
73 int numHubs;
74 const struct context_hub_t *hubs;
75 struct context_hub_module_t *contextHubModule;
76};
77
78struct contextHubServiceDb_s {
79 int initialized;
80 context_hub_info_s hubInfo;
81 jniInfo_s jniInfo;
82};
83
84} // unnamed namespace
85
86static contextHubServiceDb_s db;
87
88int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
89 void *cookie);
90
91static void initContextHubService() {
92 int err = 0;
93 db.hubInfo.hubs = NULL;
94 db.hubInfo.numHubs = 0;
95 db.hubInfo.cookie = 0;
96 int i;
97
98 err = hw_get_module(CONTEXT_HUB_MODULE_ID,
99 (hw_module_t const**)(&db.hubInfo.contextHubModule));
100
101 if (err) {
102 ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
103 strerror(-err));
104 }
105
106 if (db.hubInfo.contextHubModule) {
107 ALOGD("Fetching hub info");
108 db.hubInfo.numHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
109 &db.hubInfo.hubs);
110
111 if (db.hubInfo.numHubs > 0) {
112 for (i = 0; i < db.hubInfo.numHubs; i++) {
113 // TODO : Event though one cookie is OK for now, lets change
114 // this to be one per hub
115 db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
116 context_hub_callback,
117 &db.hubInfo.cookie);
118 }
119 }
120 }
121}
122
123static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) {
124 JNIEnv *env;
125 if ((db.jniInfo.vm)->AttachCurrentThread(&env, NULL) != JNI_OK) {
126 return -1;
127 }
128
129 jbyteArray jmsg = env->NewByteArray(msgLen);
130 jintArray jheader = env->NewIntArray(headerLen);
131
132 env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
133 env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
134
135
136 return env->CallIntMethod(db.jniInfo.jContextHubService,
137 db.jniInfo.contextHubServiceMsgReceiptCallback,
138 jheader, jmsg);
139}
140
141int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg,
142 void *cookie) {
143 int msgHeader[4];
144
145 msgHeader[0] = msg->message_type;
146 msgHeader[1] = 0; // TODO : HAL does not have a version field
147 msgHeader[2] = hub_id;
148
149 onMessageReceipt(msgHeader, sizeof(msgHeader), (char *)msg->message, msg->message_len); // TODO : Populate this
150 return 0;
151}
152
153static int init_jni(JNIEnv *env, jobject instance) {
154
155 if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
156 return -1;
157 }
158
159 db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
160
161 db.jniInfo.contextHubInfoClass =
162 env->FindClass("android/hardware/location/ContextHubInfo");
163
164 db.jniInfo.contextHubServiceClass =
165 env->FindClass("android/hardware/location/ContextHubService");
166
167 db.jniInfo.memoryRegionsClass =
168 env->FindClass("android/hardware/location/MemoryRegion");
169
170 //TODO :: Add error checking
171 db.jniInfo.contextHubInfoCtor =
172 env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
173 db.jniInfo.contextHubInfoSetId =
174 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
175 db.jniInfo.contextHubInfoSetName =
176 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
177 "(Ljava/lang/String;)V");
178
179 db.jniInfo.contextHubInfoSetVendor =
180 env->GetMethodID(db.jniInfo.contextHubInfoClass,
181 "setVendor", "(Ljava/lang/String;)V");
182 db.jniInfo.contextHubInfoSetToolchain =
183 env->GetMethodID(db.jniInfo.contextHubInfoClass,
184 "setToolchain", "(Ljava/lang/String;)V");
185 db.jniInfo.contextHubInfoSetPlatformVersion =
186 env->GetMethodID(db.jniInfo.contextHubInfoClass,
187 "setPlatformVersion", "(I)V");
188 db.jniInfo.contextHubInfoSetStaticSwVersion =
189 env->GetMethodID(db.jniInfo.contextHubInfoClass,
190 "setStaticSwVersion", "(I)V");
191 db.jniInfo.contextHubInfoSetToolchainVersion =
192 env->GetMethodID(db.jniInfo.contextHubInfoClass,
193 "setToolchainVersion", "(I)V");
194 db.jniInfo.contextHubInfoSetPeakMips =
195 env->GetMethodID(db.jniInfo.contextHubInfoClass,
196 "setPeakMips", "(F)V");
197 db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
198 env->GetMethodID(db.jniInfo.contextHubInfoClass,
199 "setStoppedPowerDrawMw", "(F)V");
200 db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
201 env->GetMethodID(db.jniInfo.contextHubInfoClass,
202 "setSleepPowerDrawMw", "(F)V");
203 db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
204 env->GetMethodID(db.jniInfo.contextHubInfoClass,
205 "setPeakPowerDrawMw", "(F)V");
206 db.jniInfo.contextHubInfoSetSupportedSensors =
207 env->GetMethodID(db.jniInfo.contextHubInfoClass,
208 "setSupportedSensors", "([I)V");
209 db.jniInfo.contextHubInfoSetMemoryRegions =
210 env->GetMethodID(db.jniInfo.contextHubInfoClass,
211 "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
212
213
214 db.jniInfo.contextHubServiceMsgReceiptCallback =
215 env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
216 "([I[B)I");
217 db.jniInfo.contextHubInfoSetName =
218 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
219 "(Ljava/lang/String;)V");
220
221
222 return 0;
223}
224
225static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
226 jstring jstrBuf;
227 jintArray jintBuf;
228 jobjectArray jmemBuf;
229
230 int dummyConnectedSensors[] = {1, 2, 3, 4, 5};
231
232 jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
233 db.jniInfo.contextHubInfoCtor);
234 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
235
236 jstrBuf = env->NewStringUTF(hub->name);
237 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
238
239 jstrBuf = env->NewStringUTF(hub->vendor);
240 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
241
242 jstrBuf = env->NewStringUTF(hub->toolchain);
243 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
244
245 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
246 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
247 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
248 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw, hub->stopped_power_draw_mw);
249 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw, hub->sleep_power_draw_mw);
250 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw, hub->peak_power_draw_mw);
251
252 // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
253 // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, hub->connected_sensors);
254 jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
255 env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
256
257 // We are not getting the memory regions from the CH Hal - change this when it is available
258 jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, NULL);
259 // Note the zero size above. We do not need to set any elements
260 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
261
262 return jHub;
263}
264
265static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
266{
267 jobject hub;
268 jobjectArray retArray;
269
270 initContextHubService();
271
272 if (init_jni(env, instance) < 0) {
273 return NULL;
274 }
275
276 // Note : The service is clamping the number of hubs to 1
277 db.hubInfo.numHubs = 1;
278
279 initContextHubService();
280
281 retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, NULL);
282
283 for(int i = 0; i < db.hubInfo.numHubs; i++) {
284 hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
285 env->SetObjectArrayElement(retArray, i, hub);
286 }
287
288 return retArray;
289}
290
291static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
292 jbyteArray data_) {
293 hub_message_t msg;
294 hub_app_name_t dest;
295 uint8_t os_name[8];
296
297 memset(os_name, 0, sizeof(os_name));
298
299 jint *header = env->GetIntArrayElements(header_, 0);
300 //int numHeaderElements = env->GetArrayLength(header_);
301 jbyte *data = env->GetByteArrayElements(data_, 0);
302 int dataBufferLength = env->GetArrayLength(data_);
303
304 /* Assume an int - thats all we understand */
305 dest.app_name_len = array_length(os_name); // TODO : Check this
306 //dest.app_name = &header[1];
307 dest.app_name = os_name;
308
309 msg.app = &dest;
310
311 msg.message_type = header[3];
312 msg.message_len = dataBufferLength;
313 msg.message = data;
314
315 jint retVal = db.hubInfo.contextHubModule->send_message(header[0], &msg);
316
317 env->ReleaseIntArrayElements(header_, header, 0);
318 env->ReleaseByteArrayElements(data_, data, 0);
319
320 return retVal;
321}
322
323//--------------------------------------------------------------------------------------------------
324//
325static const JNINativeMethod gContextHubServiceMethods[] = {
326 {"nativeInitialize",
327 "()[Landroid/hardware/location/ContextHubInfo;",
328 (void*)nativeInitialize },
329 {"nativeSendMessage",
330 "([I[B)I",
331 (void*)nativeSendMessage }
332};
333
334}//namespace android
335
336using namespace android;
337
338int register_android_hardware_location_ContextHubService(JNIEnv *env)
339{
340 RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
341 gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
342
343 return 0;
344}