1/*
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#define LOG_NDEBUG 0
20#define LOG_TAG "ContextHubService"
21
22#include <inttypes.h>
23#include <jni.h>
24#include <queue>
25#include <unordered_map>
26#include <string.h>
27#include <stdint.h>
28#include <stdio.h>
29#include <stdlib.h>
30
31#include <cutils/log.h>
32
33#include "JNIHelp.h"
34#include "core_jni_helpers.h"
35
36static constexpr int OS_APP_ID=-1;
37
38static constexpr int MIN_APP_ID=1;
39static constexpr int MAX_APP_ID=128;
40
41static constexpr size_t MSG_HEADER_SIZE=4;
42static constexpr int HEADER_FIELD_MSG_TYPE=0;
43//static constexpr int HEADER_FIELD_MSG_VERSION=1;
44static constexpr int HEADER_FIELD_HUB_HANDLE=2;
45static constexpr int HEADER_FIELD_APP_INSTANCE=3;
46
47namespace android {
48
49namespace {
50
51/*
52 * Finds the length of a statically-sized array using template trickery that
53 * also prevents it from being applied to the wrong type.
54 */
55template <typename T, size_t N>
56constexpr size_t array_length(T (&)[N]) { return N; }
57
58struct jniInfo_s {
59    JavaVM *vm;
60    jclass contextHubInfoClass;
61    jclass contextHubServiceClass;
62    jclass memoryRegionsClass;
63
64    jobject jContextHubService;
65
66    jmethodID msgReceiptCallBack;
67
68    jmethodID contextHubInfoCtor;
69    jmethodID contextHubInfoSetId;
70    jmethodID contextHubInfoSetName;
71    jmethodID contextHubInfoSetVendor;
72    jmethodID contextHubInfoSetToolchain;
73    jmethodID contextHubInfoSetPlatformVersion;
74    jmethodID contextHubInfoSetStaticSwVersion;
75    jmethodID contextHubInfoSetToolchainVersion;
76    jmethodID contextHubInfoSetPeakMips;
77    jmethodID contextHubInfoSetStoppedPowerDrawMw;
78    jmethodID contextHubInfoSetSleepPowerDrawMw;
79    jmethodID contextHubInfoSetPeakPowerDrawMw;
80    jmethodID contextHubInfoSetSupportedSensors;
81    jmethodID contextHubInfoSetMemoryRegions;
82    jmethodID contextHubInfoSetMaxPacketLenBytes;
83
84    jmethodID contextHubServiceMsgReceiptCallback;
85    jmethodID contextHubServiceAddAppInstance;
86};
87
88struct context_hub_info_s {
89    uint32_t *cookies;
90    int numHubs;
91    const struct context_hub_t *hubs;
92    struct context_hub_module_t *contextHubModule;
93};
94
95struct app_instance_info_s {
96    uint32_t hubHandle; // Id of the hub this app is on
97    int instanceId; // systemwide unique instance id - assigned
98    struct hub_app_info appInfo; // returned from the HAL
99    uint64_t truncName; // Possibly truncated name - logging
100};
101
102struct contextHubServiceDb_s {
103    int initialized;
104    context_hub_info_s hubInfo;
105    jniInfo_s jniInfo;
106    std::queue<int> freeIds;
107    std::unordered_map<int, app_instance_info_s> appInstances;
108};
109
110}  // unnamed namespace
111
112static contextHubServiceDb_s db;
113
114int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
115                         void *cookie);
116
117const context_hub_t *get_hub_info(int hubHandle) {
118    if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
119        return &db.hubInfo.hubs[hubHandle];
120    }
121    return nullptr;
122}
123
124static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
125    const context_hub_t *info = get_hub_info(hubHandle);
126
127    if (info) {
128        return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
129    } else {
130        ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
131        return -1;
132    }
133}
134
135static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
136    const context_hub_t *info = get_hub_info(hubHandle);
137
138    if (info) {
139        msg->app_name = info->os_app_name;
140        return 0;
141    } else {
142        ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
143        return -1;
144    }
145}
146
147static int get_hub_id_for_hub_handle(int hubHandle) {
148    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
149      return -1;
150    } else {
151      return db.hubInfo.hubs[hubHandle].hub_id;
152    }
153}
154
155static int get_hub_id_for_app_instance(int id) {
156    if (!db.appInstances.count(id)) {
157        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
158        return -1;
159    }
160
161    int hubHandle = db.appInstances[id].hubHandle;
162
163    return db.hubInfo.hubs[hubHandle].hub_id;
164}
165
166static int get_app_instance_for_app_id(uint64_t app_id) {
167    auto end = db.appInstances.end();
168    for (auto current = db.appInstances.begin(); current != end; ++current) {
169        if (current->second.appInfo.app_name.id == app_id) {
170            return current->first;
171        }
172    }
173    ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id);
174    return -1;
175}
176
177static int set_dest_app(hub_message_t *msg, int id) {
178    if (!db.appInstances.count(id)) {
179        ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
180        return -1;
181    }
182
183    msg->app_name = db.appInstances[id].appInfo.app_name;
184    return 0;
185}
186
187static void send_query_for_apps() {
188    hub_message_t msg;
189
190    msg.message_type = CONTEXT_HUB_QUERY_APPS;
191    msg.message_len  = 0;
192
193    for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
194        ALOGD("Sending query for apps to hub %d", i);
195        set_os_app_as_destination(&msg, i);
196        if (send_msg_to_hub(&msg, i) != 0) {
197          ALOGW("Could not query hub %i for apps", i);
198        }
199    }
200}
201
202static int return_id(int id) {
203    // Note : This method is not thread safe.
204    // id returned is guarenteed to be in use
205    db.freeIds.push(id);
206    return 0;
207}
208
209static int generate_id(void) {
210    // Note : This method is not thread safe.
211    int retVal = -1;
212
213    if (!db.freeIds.empty()) {
214        retVal = db.freeIds.front();
215        db.freeIds.pop();
216    }
217
218    return retVal;
219}
220
221int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
222    // Not checking if the apps are indeed distinct
223    app_instance_info_s entry;
224    int appInstanceHandle = generate_id();
225
226    assert(appInfo);
227
228    if (appInstanceHandle < 0) {
229        ALOGE("Cannot find resources to add app instance %d",
230              appInstanceHandle);
231        return -1;
232    }
233
234    entry.appInfo = *appInfo;
235    entry.instanceId = appInstanceHandle;
236    entry.truncName = appInfo->app_name.id;
237    entry.hubHandle = hubHandle;
238    db.appInstances[appInstanceHandle] = entry;
239
240    // Finally - let the service know of this app instance
241    env->CallIntMethod(db.jniInfo.jContextHubService,
242                       db.jniInfo.contextHubServiceAddAppInstance,
243                       hubHandle, entry.instanceId, entry.truncName,
244                       entry.appInfo.version);
245
246    ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
247          " as appInstance %d", entry.truncName,
248          entry.hubHandle, appInstanceHandle);
249
250    return appInstanceHandle;
251}
252
253int delete_app_instance(int id) {
254    if (!db.appInstances.count(id)) {
255        return -1;
256    }
257
258    return_id(id);
259    db.appInstances.erase(id);
260
261    return 0;
262}
263
264
265static void initContextHubService() {
266    int err = 0;
267    db.hubInfo.hubs = nullptr;
268    db.hubInfo.numHubs = 0;
269    int i;
270
271    err = hw_get_module(CONTEXT_HUB_MODULE_ID,
272                        (hw_module_t const**)(&db.hubInfo.contextHubModule));
273
274    if (err) {
275      ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
276            strerror(-err));
277    }
278
279    // Prep for storing app info
280    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
281        db.freeIds.push(i);
282    }
283
284    if (db.hubInfo.contextHubModule) {
285        int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
286                                                                 &db.hubInfo.hubs);
287        ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
288        db.hubInfo.numHubs = retNumHubs;
289
290        if (db.hubInfo.numHubs > 0) {
291            db.hubInfo.numHubs = retNumHubs;
292            db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
293
294            if (!db.hubInfo.cookies) {
295                ALOGW("Ran out of memory allocating cookies, bailing");
296                return;
297            }
298
299            for (i = 0; i < db.hubInfo.numHubs; i++) {
300                db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
301                if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
302                                                                    context_hub_callback,
303                                                                    &db.hubInfo.cookies[i]) == 0) {
304                }
305            }
306        }
307
308        send_query_for_apps();
309    } else {
310        ALOGW("No Context Hub Module present");
311    }
312}
313
314static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) {
315    JNIEnv *env;
316
317    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
318      return -1;
319    }
320
321    jbyteArray jmsg = env->NewByteArray(msgLen);
322    if (jmsg == nullptr) {
323        ALOGW("Can't allocate %zu byte array", msgLen);
324        return -1;
325    }
326    jintArray jheader = env->NewIntArray(headerLen);
327    if (jheader == nullptr) {
328        env->DeleteLocalRef(jmsg);
329        ALOGW("Can't allocate %zu int array", headerLen);
330        return -1;
331    }
332
333    env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
334    env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
335
336    int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
337                          db.jniInfo.contextHubServiceMsgReceiptCallback,
338                          jheader, jmsg) != 0);
339    env->DeleteLocalRef(jmsg);
340    env->DeleteLocalRef(jheader);
341
342    return ret;
343}
344
345int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
346    JNIEnv *env;
347    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
348            return -1;
349    }
350
351    int numApps = msgLen/sizeof(hub_app_info);
352    hub_app_info info;
353    hub_app_info *unalignedInfoAddr = (hub_app_info*)msg;
354
355    for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
356        memcpy(&info, unalignedInfoAddr, sizeof(info));
357        add_app_instance(&info, hubHandle, env);
358    }
359
360    return 0;
361}
362
363
364int handle_os_message(uint32_t msgType, uint32_t hubHandle,
365                      char *msg, int msgLen) {
366    int retVal;
367
368    //ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
369    //      hubHandle, msgType, msgLen);
370
371    switch(msgType) {
372        case CONTEXT_HUB_APPS_ENABLE:
373            retVal = 0;
374            break;
375
376        case CONTEXT_HUB_APPS_DISABLE:
377            retVal = 0;
378            break;
379
380        case CONTEXT_HUB_LOAD_APP:
381            retVal = 0;
382            break;
383
384        case CONTEXT_HUB_UNLOAD_APP:
385            retVal = 0;
386            break;
387
388        case CONTEXT_HUB_QUERY_APPS:
389            retVal = handle_query_apps_response(msg, msgLen, hubHandle);
390            break;
391
392        case CONTEXT_HUB_QUERY_MEMORY:
393            retVal = 0;
394            break;
395
396        default:
397            retVal = -1;
398            break;
399
400    }
401
402    return retVal;
403}
404
405static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
406    int *ptr = (int *)cookie;
407
408    if (!ptr || *ptr >= db.hubInfo.numHubs) {
409        return false;
410    }
411
412    if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
413        return false;
414    } else {
415        return true;
416    }
417}
418
419int context_hub_callback(uint32_t hubId,
420                         const struct hub_message_t *msg,
421                         void *cookie) {
422    if (!msg) {
423        return -1;
424    }
425    if (!sanity_check_cookie(cookie, hubId)) {
426        ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
427              hubId, cookie);
428
429        return -1;
430    }
431
432    uint32_t messageType = msg->message_type;
433    uint32_t hubHandle = *(uint32_t*) cookie;
434
435    if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
436        handle_os_message(messageType, hubHandle, (char*) msg->message, msg->message_len);
437    } else {
438        int appHandle = get_app_instance_for_app_id(msg->app_name.id);
439        if (appHandle < 0) {
440            ALOGE("Filtering out message due to invalid App Instance.");
441        } else {
442            uint32_t msgHeader[MSG_HEADER_SIZE] = {};
443            msgHeader[HEADER_FIELD_MSG_TYPE] = messageType;
444            msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
445            msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
446            onMessageReceipt(msgHeader, MSG_HEADER_SIZE, (char*) msg->message, msg->message_len);
447        }
448    }
449
450    return 0;
451}
452
453static int init_jni(JNIEnv *env, jobject instance) {
454
455    if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
456        return -1;
457    }
458
459    db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
460
461    db.jniInfo.contextHubInfoClass =
462            env->FindClass("android/hardware/location/ContextHubInfo");
463
464    db.jniInfo.contextHubServiceClass =
465            env->FindClass("android/hardware/location/ContextHubService");
466
467    db.jniInfo.memoryRegionsClass =
468            env->FindClass("android/hardware/location/MemoryRegion");
469
470    db.jniInfo.contextHubInfoCtor =
471            env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
472    db.jniInfo.contextHubInfoSetId =
473            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
474    db.jniInfo.contextHubInfoSetName =
475            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
476                                "(Ljava/lang/String;)V");
477
478    db.jniInfo.contextHubInfoSetVendor =
479            env->GetMethodID(db.jniInfo.contextHubInfoClass,
480                                "setVendor", "(Ljava/lang/String;)V");
481    db.jniInfo.contextHubInfoSetToolchain =
482            env->GetMethodID(db.jniInfo.contextHubInfoClass,
483                                "setToolchain", "(Ljava/lang/String;)V");
484    db.jniInfo.contextHubInfoSetPlatformVersion =
485            env->GetMethodID(db.jniInfo.contextHubInfoClass,
486                                "setPlatformVersion", "(I)V");
487    db.jniInfo.contextHubInfoSetStaticSwVersion =
488            env->GetMethodID(db.jniInfo.contextHubInfoClass,
489                                "setStaticSwVersion", "(I)V");
490    db.jniInfo.contextHubInfoSetToolchainVersion =
491            env->GetMethodID(db.jniInfo.contextHubInfoClass,
492                                "setToolchainVersion", "(I)V");
493    db.jniInfo.contextHubInfoSetPeakMips =
494            env->GetMethodID(db.jniInfo.contextHubInfoClass,
495                                "setPeakMips", "(F)V");
496    db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
497            env->GetMethodID(db.jniInfo.contextHubInfoClass,
498                                "setStoppedPowerDrawMw", "(F)V");
499    db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
500            env->GetMethodID(db.jniInfo.contextHubInfoClass,
501                                "setSleepPowerDrawMw", "(F)V");
502    db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
503            env->GetMethodID(db.jniInfo.contextHubInfoClass,
504                                "setPeakPowerDrawMw", "(F)V");
505    db.jniInfo.contextHubInfoSetSupportedSensors =
506            env->GetMethodID(db.jniInfo.contextHubInfoClass,
507                                "setSupportedSensors", "([I)V");
508    db.jniInfo.contextHubInfoSetMemoryRegions =
509            env->GetMethodID(db.jniInfo.contextHubInfoClass,
510                                "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
511    db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
512             env->GetMethodID(db.jniInfo.contextHubInfoClass,
513                                "setMaxPacketLenBytes", "(I)V");
514
515
516    db.jniInfo.contextHubServiceMsgReceiptCallback =
517            env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
518                               "([I[B)I");
519    db.jniInfo.contextHubInfoSetName =
520            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
521            "(Ljava/lang/String;)V");
522
523    db.jniInfo.contextHubServiceAddAppInstance =
524                 env->GetMethodID(db.jniInfo.contextHubServiceClass,
525                                    "addAppInstance", "(IIJI)I");
526
527
528
529    return 0;
530}
531
532static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
533    jstring jstrBuf;
534    jintArray jintBuf;
535    jobjectArray jmemBuf;
536
537    int dummyConnectedSensors[] = {1, 2, 3, 4, 5};
538
539    jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
540                                  db.jniInfo.contextHubInfoCtor);
541    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
542
543    jstrBuf = env->NewStringUTF(hub->name);
544    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
545    env->DeleteLocalRef(jstrBuf);
546
547    jstrBuf = env->NewStringUTF(hub->vendor);
548    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
549    env->DeleteLocalRef(jstrBuf);
550
551    jstrBuf = env->NewStringUTF(hub->toolchain);
552    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
553    env->DeleteLocalRef(jstrBuf);
554
555    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
556    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
557    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
558    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
559                        hub->stopped_power_draw_mw);
560    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
561                        hub->sleep_power_draw_mw);
562    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
563                        hub->peak_power_draw_mw);
564    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
565                        hub->max_supported_msg_len);
566
567
568    // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors);
569    // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
570    //                               hub->connected_sensors);
571    jintBuf = env->NewIntArray(array_length(dummyConnectedSensors));
572    env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors);
573    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
574    env->DeleteLocalRef(jintBuf);
575
576    // We are not getting the memory regions from the CH Hal - change this when it is available
577    jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
578    // Note the zero size above. We do not need to set any elements
579    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
580    env->DeleteLocalRef(jmemBuf);
581
582
583    return jHub;
584}
585
586static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
587{
588    jobject hub;
589    jobjectArray retArray;
590
591    if (init_jni(env, instance) < 0) {
592        return nullptr;
593    }
594
595    initContextHubService();
596
597    if (db.hubInfo.numHubs > 1) {
598      ALOGW("Clamping the number of hubs to 1");
599      db.hubInfo.numHubs = 1;
600    }
601
602    retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
603
604    for(int i = 0; i < db.hubInfo.numHubs; i++) {
605        hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
606        env->SetObjectArrayElement(retArray, i, hub);
607    }
608
609    return retArray;
610}
611
612static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
613                              jbyteArray data_) {
614    jint retVal = -1; // Default to failure
615
616    jint *header = env->GetIntArrayElements(header_, 0);
617    unsigned int numHeaderElements = env->GetArrayLength(header_);
618    jbyte *data = env->GetByteArrayElements(data_, 0);
619    int dataBufferLength = env->GetArrayLength(data_);
620
621
622    if (numHeaderElements >= MSG_HEADER_SIZE) {
623        bool setAddressSuccess;
624        int hubId;
625        hub_message_t msg;
626
627        if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
628            setAddressSuccess = (set_os_app_as_destination(&msg, header[HEADER_FIELD_HUB_HANDLE]) == 0);
629            hubId = get_hub_id_for_hub_handle(header[HEADER_FIELD_HUB_HANDLE]);
630        } else {
631            setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
632            hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
633        }
634
635        if (setAddressSuccess && hubId >= 0) {
636            msg.message_type = header[HEADER_FIELD_MSG_TYPE];
637            msg.message_len = dataBufferLength;
638            msg.message = data;
639            retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
640        } else {
641          ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
642                header[HEADER_FIELD_APP_INSTANCE],
643                header[HEADER_FIELD_HUB_HANDLE],
644                (int)setAddressSuccess);
645        }
646    } else {
647        ALOGD("Malformed header len");
648    }
649
650    env->ReleaseIntArrayElements(header_, header, 0);
651    env->ReleaseByteArrayElements(data_, data, 0);
652
653    return retVal;
654}
655
656//--------------------------------------------------------------------------------------------------
657//
658static const JNINativeMethod gContextHubServiceMethods[] = {
659    {"nativeInitialize",
660             "()[Landroid/hardware/location/ContextHubInfo;",
661             (void*)nativeInitialize },
662    {"nativeSendMessage",
663            "([I[B)I",
664            (void*)nativeSendMessage }
665};
666
667}//namespace android
668
669using namespace android;
670
671int register_android_hardware_location_ContextHubService(JNIEnv *env)
672{
673    RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
674            gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
675
676    return 0;
677}
678