Home | History | Annotate | Download | only in jni
      1 /*
      2 ** Copyright 2006, 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 DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
     18 #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
     19 #define LOG_TAG "BluetoothService.cpp"
     20 
     21 #include "android_bluetooth_common.h"
     22 #include "android_runtime/AndroidRuntime.h"
     23 #include "JNIHelp.h"
     24 #include "jni.h"
     25 #include "utils/Log.h"
     26 #include "utils/misc.h"
     27 
     28 #include <ctype.h>
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <stdlib.h>
     32 #include <errno.h>
     33 #include <unistd.h>
     34 
     35 #include <sys/socket.h>
     36 #include <sys/ioctl.h>
     37 #include <fcntl.h>
     38 
     39 #ifdef HAVE_BLUETOOTH
     40 #include <dbus/dbus.h>
     41 #include <bluedroid/bluetooth.h>
     42 #endif
     43 
     44 #include <cutils/properties.h>
     45 
     46 namespace android {
     47 
     48 #define BLUETOOTH_CLASS_ERROR 0xFF000000
     49 #define PROPERTIES_NREFS 10
     50 
     51 #ifdef HAVE_BLUETOOTH
     52 // We initialize these variables when we load class
     53 // android.server.BluetoothService
     54 static jfieldID field_mNativeData;
     55 static jfieldID field_mEventLoop;
     56 
     57 typedef struct {
     58     JNIEnv *env;
     59     DBusConnection *conn;
     60     const char *adapter;  // dbus object name of the local adapter
     61 } native_data_t;
     62 
     63 extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
     64                                                            jobject);
     65 extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
     66                                             DBusMessage *msg,
     67                                             void *data);
     68 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
     69 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
     70 void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
     71 
     72 
     73 /** Get native data stored in the opaque (Java code maintained) pointer mNativeData
     74  *  Perform quick sanity check, if there are any problems return NULL
     75  */
     76 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
     77     native_data_t *nat =
     78             (native_data_t *)(env->GetIntField(object, field_mNativeData));
     79     if (nat == NULL || nat->conn == NULL) {
     80         LOGE("Uninitialized native data\n");
     81         return NULL;
     82     }
     83     return nat;
     84 }
     85 #endif
     86 
     87 static void classInitNative(JNIEnv* env, jclass clazz) {
     88     LOGV(__FUNCTION__);
     89 #ifdef HAVE_BLUETOOTH
     90     field_mNativeData = get_field(env, clazz, "mNativeData", "I");
     91     field_mEventLoop = get_field(env, clazz, "mEventLoop",
     92             "Landroid/server/BluetoothEventLoop;");
     93 #endif
     94 }
     95 
     96 /* Returns true on success (even if adapter is present but disabled).
     97  * Return false if dbus is down, or another serious error (out of memory)
     98 */
     99 static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
    100     LOGV(__FUNCTION__);
    101 #ifdef HAVE_BLUETOOTH
    102     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
    103     if (NULL == nat) {
    104         LOGE("%s: out of memory!", __FUNCTION__);
    105         return false;
    106     }
    107     nat->env = env;
    108 
    109     env->SetIntField(object, field_mNativeData, (jint)nat);
    110     DBusError err;
    111     dbus_error_init(&err);
    112     dbus_threads_init_default();
    113     nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    114     if (dbus_error_is_set(&err)) {
    115         LOGE("Could not get onto the system bus: %s", err.message);
    116         dbus_error_free(&err);
    117         return false;
    118     }
    119     dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
    120 #endif  /*HAVE_BLUETOOTH*/
    121     return true;
    122 }
    123 
    124 static const char *get_adapter_path(JNIEnv* env, jobject object) {
    125 #ifdef HAVE_BLUETOOTH
    126     event_loop_native_data_t *event_nat =
    127         get_EventLoop_native_data(env, env->GetObjectField(object,
    128                                                            field_mEventLoop));
    129     if (event_nat == NULL)
    130         return NULL;
    131     return event_nat->adapter;
    132 #else
    133     return NULL;
    134 #endif
    135 }
    136 
    137 // This function is called when the adapter is enabled.
    138 static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
    139     LOGV(__FUNCTION__);
    140 #ifdef HAVE_BLUETOOTH
    141     native_data_t *nat =
    142         (native_data_t *)env->GetIntField(object, field_mNativeData);
    143     event_loop_native_data_t *event_nat =
    144         get_EventLoop_native_data(env, env->GetObjectField(object,
    145                                                            field_mEventLoop));
    146     // Register agent for remote devices.
    147     const char *device_agent_path = "/android/bluetooth/remote_device_agent";
    148     static const DBusObjectPathVTable agent_vtable = {
    149                  NULL, agent_event_filter, NULL, NULL, NULL, NULL };
    150 
    151     if (!dbus_connection_register_object_path(nat->conn, device_agent_path,
    152                                               &agent_vtable, event_nat)) {
    153         LOGE("%s: Can't register object path %s for remote device agent!",
    154                                __FUNCTION__, device_agent_path);
    155         return JNI_FALSE;
    156     }
    157 #endif /*HAVE_BLUETOOTH*/
    158     return JNI_TRUE;
    159 }
    160 
    161 static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
    162     LOGV(__FUNCTION__);
    163 #ifdef HAVE_BLUETOOTH
    164     native_data_t *nat =
    165                (native_data_t *)env->GetIntField(object, field_mNativeData);
    166     if (nat != NULL) {
    167         const char *device_agent_path =
    168             "/android/bluetooth/remote_device_agent";
    169         dbus_connection_unregister_object_path (nat->conn, device_agent_path);
    170     }
    171 #endif /*HAVE_BLUETOOTH*/
    172     return JNI_TRUE;
    173 }
    174 
    175 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
    176     LOGV(__FUNCTION__);
    177 #ifdef HAVE_BLUETOOTH
    178     native_data_t *nat =
    179         (native_data_t *)env->GetIntField(object, field_mNativeData);
    180     if (nat) {
    181         free(nat);
    182         nat = NULL;
    183     }
    184 #endif
    185 }
    186 
    187 static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
    188     LOGV(__FUNCTION__);
    189 #ifdef HAVE_BLUETOOTH
    190     native_data_t *nat = get_native_data(env, object);
    191     if (nat) {
    192         return (env->NewStringUTF(get_adapter_path(env, object)));
    193     }
    194 #endif
    195     return NULL;
    196 }
    197 
    198 
    199 static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
    200     LOGV(__FUNCTION__);
    201 #ifdef HAVE_BLUETOOTH
    202     DBusMessage *msg = NULL;
    203     DBusMessage *reply = NULL;
    204     DBusError err;
    205     const char *name;
    206     jboolean ret = JNI_FALSE;
    207 
    208     native_data_t *nat = get_native_data(env, object);
    209     if (nat == NULL) {
    210         goto done;
    211     }
    212 
    213     dbus_error_init(&err);
    214 
    215     /* Compose the command */
    216     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    217                                        get_adapter_path(env, object),
    218                                        DBUS_ADAPTER_IFACE, "StartDiscovery");
    219 
    220     if (msg == NULL) {
    221         if (dbus_error_is_set(&err)) {
    222             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    223         }
    224         goto done;
    225     }
    226 
    227     /* Send the command. */
    228     reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    229     if (dbus_error_is_set(&err)) {
    230          LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    231          ret = JNI_FALSE;
    232          goto done;
    233     }
    234 
    235     ret = JNI_TRUE;
    236 done:
    237     if (reply) dbus_message_unref(reply);
    238     if (msg) dbus_message_unref(msg);
    239     return ret;
    240 #else
    241     return JNI_FALSE;
    242 #endif
    243 }
    244 
    245 static void stopDiscoveryNative(JNIEnv *env, jobject object) {
    246     LOGV(__FUNCTION__);
    247 #ifdef HAVE_BLUETOOTH
    248     DBusMessage *msg = NULL;
    249     DBusMessage *reply = NULL;
    250     DBusError err;
    251     const char *name;
    252     jstring ret;
    253     native_data_t *nat;
    254 
    255     dbus_error_init(&err);
    256 
    257     nat = get_native_data(env, object);
    258     if (nat == NULL) {
    259         goto done;
    260     }
    261 
    262     /* Compose the command */
    263     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    264                                        get_adapter_path(env, object),
    265                                        DBUS_ADAPTER_IFACE, "StopDiscovery");
    266     if (msg == NULL) {
    267         if (dbus_error_is_set(&err))
    268             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    269         goto done;
    270     }
    271 
    272     /* Send the command. */
    273     reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    274     if (dbus_error_is_set(&err)) {
    275         if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized",
    276                    strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) {
    277             // hcid sends this if there is no active discovery to cancel
    278             LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
    279             dbus_error_free(&err);
    280         } else {
    281             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    282         }
    283     }
    284 
    285 done:
    286     if (msg) dbus_message_unref(msg);
    287     if (reply) dbus_message_unref(reply);
    288 #endif
    289 }
    290 
    291 static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) {
    292     LOGV(__FUNCTION__);
    293 #ifdef HAVE_BLUETOOTH
    294     native_data_t *nat = get_native_data(env, object);
    295     DBusError err;
    296     jbyte *hash, *randomizer;
    297     jbyteArray byteArray = NULL;
    298     int hash_len, r_len;
    299     if (nat) {
    300        DBusMessage *reply = dbus_func_args(env, nat->conn,
    301                            get_adapter_path(env, object),
    302                            DBUS_ADAPTER_IFACE, "ReadLocalOutOfBandData",
    303                            DBUS_TYPE_INVALID);
    304        if (!reply) return NULL;
    305 
    306        dbus_error_init(&err);
    307        if (dbus_message_get_args(reply, &err,
    308                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hash_len,
    309                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &r_len,
    310                                 DBUS_TYPE_INVALID)) {
    311           if (hash_len == 16 && r_len == 16) {
    312                byteArray = env->NewByteArray(32);
    313                if (byteArray) {
    314                    env->SetByteArrayRegion(byteArray, 0, 16, hash);
    315                    env->SetByteArrayRegion(byteArray, 16, 16, randomizer);
    316                }
    317            } else {
    318                LOGE("readAdapterOutOfBandDataNative: Hash len = %d, R len = %d",
    319                                                                   hash_len, r_len);
    320            }
    321        } else {
    322           LOG_AND_FREE_DBUS_ERROR(&err);
    323        }
    324        dbus_message_unref(reply);
    325        return byteArray;
    326     }
    327 #endif
    328     return NULL;
    329 }
    330 
    331 static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
    332                                          jstring address, jint timeout_ms) {
    333     LOGV(__FUNCTION__);
    334 #ifdef HAVE_BLUETOOTH
    335     native_data_t *nat = get_native_data(env, object);
    336     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    337     struct event_loop_native_data_t *eventLoopNat =
    338             get_EventLoop_native_data(env, eventLoop);
    339 
    340     if (nat && eventLoopNat) {
    341         const char *c_address = env->GetStringUTFChars(address, NULL);
    342         LOGV("... address = %s", c_address);
    343         char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
    344         const char *capabilities = "DisplayYesNo";
    345         const char *agent_path = "/android/bluetooth/remote_device_agent";
    346 
    347         strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
    348         bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
    349                                         onCreatePairedDeviceResult, // callback
    350                                         context_address,
    351                                         eventLoopNat,
    352                                         get_adapter_path(env, object),
    353                                         DBUS_ADAPTER_IFACE,
    354                                         "CreatePairedDevice",
    355                                         DBUS_TYPE_STRING, &c_address,
    356                                         DBUS_TYPE_OBJECT_PATH, &agent_path,
    357                                         DBUS_TYPE_STRING, &capabilities,
    358                                         DBUS_TYPE_INVALID);
    359         env->ReleaseStringUTFChars(address, c_address);
    360         return ret ? JNI_TRUE : JNI_FALSE;
    361 
    362     }
    363 #endif
    364     return JNI_FALSE;
    365 }
    366 
    367 static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object,
    368                                                 jstring address, jint timeout_ms) {
    369     LOGV(__FUNCTION__);
    370 #ifdef HAVE_BLUETOOTH
    371     native_data_t *nat = get_native_data(env, object);
    372     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    373     struct event_loop_native_data_t *eventLoopNat =
    374             get_EventLoop_native_data(env, eventLoop);
    375 
    376     if (nat && eventLoopNat) {
    377         const char *c_address = env->GetStringUTFChars(address, NULL);
    378         LOGV("... address = %s", c_address);
    379         char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
    380         const char *capabilities = "DisplayYesNo";
    381         const char *agent_path = "/android/bluetooth/remote_device_agent";
    382 
    383         strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
    384         bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
    385                                         onCreatePairedDeviceResult, // callback
    386                                         context_address,
    387                                         eventLoopNat,
    388                                         get_adapter_path(env, object),
    389                                         DBUS_ADAPTER_IFACE,
    390                                         "CreatePairedDeviceOutOfBand",
    391                                         DBUS_TYPE_STRING, &c_address,
    392                                         DBUS_TYPE_OBJECT_PATH, &agent_path,
    393                                         DBUS_TYPE_STRING, &capabilities,
    394                                         DBUS_TYPE_INVALID);
    395         env->ReleaseStringUTFChars(address, c_address);
    396         return ret ? JNI_TRUE : JNI_FALSE;
    397     }
    398 #endif
    399     return JNI_FALSE;
    400 }
    401 
    402 static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
    403                                           jstring path,
    404                                           jstring pattern, jint attr_id) {
    405 #ifdef HAVE_BLUETOOTH
    406     LOGV(__FUNCTION__);
    407     native_data_t *nat = get_native_data(env, object);
    408     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    409     struct event_loop_native_data_t *eventLoopNat =
    410             get_EventLoop_native_data(env, eventLoop);
    411     if (nat && eventLoopNat) {
    412         const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
    413         const char *c_path = env->GetStringUTFChars(path, NULL);
    414         LOGV("... pattern = %s", c_pattern);
    415         LOGV("... attr_id = %#X", attr_id);
    416         DBusMessage *reply =
    417             dbus_func_args(env, nat->conn, c_path,
    418                            DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
    419                            DBUS_TYPE_STRING, &c_pattern,
    420                            DBUS_TYPE_UINT16, &attr_id,
    421                            DBUS_TYPE_INVALID);
    422         env->ReleaseStringUTFChars(pattern, c_pattern);
    423         env->ReleaseStringUTFChars(path, c_path);
    424         return reply ? dbus_returns_int32(env, reply) : -1;
    425     }
    426 #endif
    427     return -1;
    428 }
    429 
    430 static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
    431                                            jstring address) {
    432     LOGV(__FUNCTION__);
    433     jboolean result = JNI_FALSE;
    434 #ifdef HAVE_BLUETOOTH
    435     native_data_t *nat = get_native_data(env, object);
    436     if (nat) {
    437         const char *c_address = env->GetStringUTFChars(address, NULL);
    438         DBusError err;
    439         dbus_error_init(&err);
    440         LOGV("... address = %s", c_address);
    441         DBusMessage *reply =
    442             dbus_func_args_timeout(env, nat->conn, -1,
    443                                    get_adapter_path(env, object),
    444                                    DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
    445                                    DBUS_TYPE_STRING, &c_address,
    446                                    DBUS_TYPE_INVALID);
    447         env->ReleaseStringUTFChars(address, c_address);
    448         if (!reply) {
    449             if (dbus_error_is_set(&err)) {
    450                 LOG_AND_FREE_DBUS_ERROR(&err);
    451             } else
    452                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    453             return JNI_FALSE;
    454         } else {
    455             result = JNI_TRUE;
    456         }
    457         dbus_message_unref(reply);
    458     }
    459 #endif
    460     return JNI_FALSE;
    461 }
    462 
    463 static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
    464     LOGV(__FUNCTION__);
    465 #ifdef HAVE_BLUETOOTH
    466     native_data_t *nat = get_native_data(env, object);
    467     if (nat) {
    468         const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
    469         bool ret = dbus_func_args_async(env, nat->conn, -1,
    470                                         NULL,
    471                                         NULL,
    472                                         NULL,
    473                                         get_adapter_path(env, object),
    474                                         DBUS_ADAPTER_IFACE,
    475                                         "RemoveDevice",
    476                                         DBUS_TYPE_OBJECT_PATH, &c_object_path,
    477                                         DBUS_TYPE_INVALID);
    478         env->ReleaseStringUTFChars(object_path, c_object_path);
    479         return ret ? JNI_TRUE : JNI_FALSE;
    480     }
    481 #endif
    482     return JNI_FALSE;
    483 }
    484 
    485 static jint enableNative(JNIEnv *env, jobject object) {
    486 #ifdef HAVE_BLUETOOTH
    487     LOGV(__FUNCTION__);
    488     return bt_enable();
    489 #endif
    490     return -1;
    491 }
    492 
    493 static jint disableNative(JNIEnv *env, jobject object) {
    494 #ifdef HAVE_BLUETOOTH
    495     LOGV(__FUNCTION__);
    496     return bt_disable();
    497 #endif
    498     return -1;
    499 }
    500 
    501 static jint isEnabledNative(JNIEnv *env, jobject object) {
    502 #ifdef HAVE_BLUETOOTH
    503     LOGV(__FUNCTION__);
    504     return bt_is_enabled();
    505 #endif
    506     return -1;
    507 }
    508 
    509 static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
    510                                              jstring address, bool confirm,
    511                                              int nativeData) {
    512 #ifdef HAVE_BLUETOOTH
    513     LOGV(__FUNCTION__);
    514     native_data_t *nat = get_native_data(env, object);
    515     if (nat) {
    516         DBusMessage *msg = (DBusMessage *)nativeData;
    517         DBusMessage *reply;
    518         if (confirm) {
    519             reply = dbus_message_new_method_return(msg);
    520         } else {
    521             reply = dbus_message_new_error(msg,
    522                 "org.bluez.Error.Rejected", "User rejected confirmation");
    523         }
    524 
    525         if (!reply) {
    526             LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or"
    527                   "RequestPairingConsent to D-Bus\n", __FUNCTION__);
    528             dbus_message_unref(msg);
    529             return JNI_FALSE;
    530         }
    531 
    532         dbus_connection_send(nat->conn, reply, NULL);
    533         dbus_message_unref(msg);
    534         dbus_message_unref(reply);
    535         return JNI_TRUE;
    536     }
    537 #endif
    538     return JNI_FALSE;
    539 }
    540 
    541 static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
    542                          int passkey, int nativeData) {
    543 #ifdef HAVE_BLUETOOTH
    544     LOGV(__FUNCTION__);
    545     native_data_t *nat = get_native_data(env, object);
    546     if (nat) {
    547         DBusMessage *msg = (DBusMessage *)nativeData;
    548         DBusMessage *reply = dbus_message_new_method_return(msg);
    549         if (!reply) {
    550             LOGE("%s: Cannot create message reply to return Passkey code to "
    551                  "D-Bus\n", __FUNCTION__);
    552             dbus_message_unref(msg);
    553             return JNI_FALSE;
    554         }
    555 
    556         dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey,
    557                                  DBUS_TYPE_INVALID);
    558 
    559         dbus_connection_send(nat->conn, reply, NULL);
    560         dbus_message_unref(msg);
    561         dbus_message_unref(reply);
    562         return JNI_TRUE;
    563     }
    564 #endif
    565     return JNI_FALSE;
    566 }
    567 
    568 static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address,
    569                          jbyteArray hash, jbyteArray randomizer, int nativeData) {
    570 #ifdef HAVE_BLUETOOTH
    571     LOGV(__FUNCTION__);
    572     native_data_t *nat = get_native_data(env, object);
    573     if (nat) {
    574         DBusMessage *msg = (DBusMessage *)nativeData;
    575         DBusMessage *reply = dbus_message_new_method_return(msg);
    576         jbyte *h_ptr = env->GetByteArrayElements(hash, NULL);
    577         jbyte *r_ptr = env->GetByteArrayElements(randomizer, NULL);
    578         if (!reply) {
    579             LOGE("%s: Cannot create message reply to return remote OOB data to "
    580                  "D-Bus\n", __FUNCTION__);
    581             dbus_message_unref(msg);
    582             return JNI_FALSE;
    583         }
    584 
    585         dbus_message_append_args(reply,
    586                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &h_ptr, 16,
    587                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, 16,
    588                                 DBUS_TYPE_INVALID);
    589 
    590         env->ReleaseByteArrayElements(hash, h_ptr, 0);
    591         env->ReleaseByteArrayElements(randomizer, r_ptr, 0);
    592 
    593         dbus_connection_send(nat->conn, reply, NULL);
    594         dbus_message_unref(msg);
    595         dbus_message_unref(reply);
    596         return JNI_TRUE;
    597     }
    598 #endif
    599     return JNI_FALSE;
    600 }
    601 
    602 static jboolean setAuthorizationNative(JNIEnv *env, jobject object, jstring address,
    603                          jboolean val, int nativeData) {
    604 #ifdef HAVE_BLUETOOTH
    605     LOGV(__FUNCTION__);
    606     native_data_t *nat = get_native_data(env, object);
    607     if (nat) {
    608         DBusMessage *msg = (DBusMessage *)nativeData;
    609         DBusMessage *reply;
    610         if (val) {
    611             reply = dbus_message_new_method_return(msg);
    612         } else {
    613             reply = dbus_message_new_error(msg,
    614                     "org.bluez.Error.Rejected", "Authorization rejected");
    615         }
    616         if (!reply) {
    617             LOGE("%s: Cannot create message reply D-Bus\n", __FUNCTION__);
    618             dbus_message_unref(msg);
    619             return JNI_FALSE;
    620         }
    621 
    622         dbus_connection_send(nat->conn, reply, NULL);
    623         dbus_message_unref(msg);
    624         dbus_message_unref(reply);
    625         return JNI_TRUE;
    626     }
    627 #endif
    628     return JNI_FALSE;
    629 }
    630 
    631 static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
    632                          jstring pin, int nativeData) {
    633 #ifdef HAVE_BLUETOOTH
    634     LOGV(__FUNCTION__);
    635     native_data_t *nat = get_native_data(env, object);
    636     if (nat) {
    637         DBusMessage *msg = (DBusMessage *)nativeData;
    638         DBusMessage *reply = dbus_message_new_method_return(msg);
    639         if (!reply) {
    640             LOGE("%s: Cannot create message reply to return PIN code to "
    641                  "D-Bus\n", __FUNCTION__);
    642             dbus_message_unref(msg);
    643             return JNI_FALSE;
    644         }
    645 
    646         const char *c_pin = env->GetStringUTFChars(pin, NULL);
    647 
    648         dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
    649                                  DBUS_TYPE_INVALID);
    650 
    651         dbus_connection_send(nat->conn, reply, NULL);
    652         dbus_message_unref(msg);
    653         dbus_message_unref(reply);
    654         env->ReleaseStringUTFChars(pin, c_pin);
    655         return JNI_TRUE;
    656     }
    657 #endif
    658     return JNI_FALSE;
    659 }
    660 
    661 static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
    662                                             jstring address, int nativeData) {
    663 #ifdef HAVE_BLUETOOTH
    664     LOGV(__FUNCTION__);
    665     native_data_t *nat = get_native_data(env, object);
    666     if (nat) {
    667         DBusMessage *msg = (DBusMessage *)nativeData;
    668         DBusMessage *reply = dbus_message_new_error(msg,
    669                 "org.bluez.Error.Canceled", "Pairing User Input was canceled");
    670         if (!reply) {
    671             LOGE("%s: Cannot create message reply to return cancelUserInput to"
    672                  "D-BUS\n", __FUNCTION__);
    673             dbus_message_unref(msg);
    674             return JNI_FALSE;
    675         }
    676 
    677         dbus_connection_send(nat->conn, reply, NULL);
    678         dbus_message_unref(msg);
    679         dbus_message_unref(reply);
    680         return JNI_TRUE;
    681     }
    682 #endif
    683     return JNI_FALSE;
    684 }
    685 
    686 static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
    687                                                     jstring path)
    688 {
    689 #ifdef HAVE_BLUETOOTH
    690     LOGV(__FUNCTION__);
    691     native_data_t *nat = get_native_data(env, object);
    692     if (nat) {
    693         DBusMessage *msg, *reply;
    694         DBusError err;
    695         dbus_error_init(&err);
    696 
    697         const char *c_path = env->GetStringUTFChars(path, NULL);
    698         reply = dbus_func_args_timeout(env,
    699                                    nat->conn, -1, c_path,
    700                                    DBUS_DEVICE_IFACE, "GetProperties",
    701                                    DBUS_TYPE_INVALID);
    702         env->ReleaseStringUTFChars(path, c_path);
    703 
    704         if (!reply) {
    705             if (dbus_error_is_set(&err)) {
    706                 LOG_AND_FREE_DBUS_ERROR(&err);
    707             } else
    708                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    709             return NULL;
    710         }
    711         env->PushLocalFrame(PROPERTIES_NREFS);
    712 
    713         DBusMessageIter iter;
    714         jobjectArray str_array = NULL;
    715         if (dbus_message_iter_init(reply, &iter))
    716            str_array =  parse_remote_device_properties(env, &iter);
    717         dbus_message_unref(reply);
    718 
    719         env->PopLocalFrame(NULL);
    720 
    721         return str_array;
    722     }
    723 #endif
    724     return NULL;
    725 }
    726 
    727 static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
    728 #ifdef HAVE_BLUETOOTH
    729     LOGV(__FUNCTION__);
    730     native_data_t *nat = get_native_data(env, object);
    731     if (nat) {
    732         DBusMessage *msg, *reply;
    733         DBusError err;
    734         dbus_error_init(&err);
    735 
    736         reply = dbus_func_args_timeout(env,
    737                                    nat->conn, -1, get_adapter_path(env, object),
    738                                    DBUS_ADAPTER_IFACE, "GetProperties",
    739                                    DBUS_TYPE_INVALID);
    740         if (!reply) {
    741             if (dbus_error_is_set(&err)) {
    742                 LOG_AND_FREE_DBUS_ERROR(&err);
    743             } else
    744                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    745             return NULL;
    746         }
    747         env->PushLocalFrame(PROPERTIES_NREFS);
    748 
    749         DBusMessageIter iter;
    750         jobjectArray str_array = NULL;
    751         if (dbus_message_iter_init(reply, &iter))
    752             str_array = parse_adapter_properties(env, &iter);
    753         dbus_message_unref(reply);
    754 
    755         env->PopLocalFrame(NULL);
    756         return str_array;
    757     }
    758 #endif
    759     return NULL;
    760 }
    761 
    762 static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
    763                                          void *value, jint type) {
    764 #ifdef HAVE_BLUETOOTH
    765     LOGV(__FUNCTION__);
    766     native_data_t *nat = get_native_data(env, object);
    767     if (nat) {
    768         DBusMessage *reply, *msg;
    769         DBusMessageIter iter;
    770         DBusError err;
    771         const char *c_key = env->GetStringUTFChars(key, NULL);
    772         dbus_error_init(&err);
    773 
    774         msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    775                                            get_adapter_path(env, object),
    776                                            DBUS_ADAPTER_IFACE, "SetProperty");
    777         if (!msg) {
    778             LOGE("%s: Can't allocate new method call for GetProperties!",
    779                   __FUNCTION__);
    780             env->ReleaseStringUTFChars(key, c_key);
    781             return JNI_FALSE;
    782         }
    783 
    784         dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
    785         dbus_message_iter_init_append(msg, &iter);
    786         append_variant(&iter, type, value);
    787 
    788         reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    789         dbus_message_unref(msg);
    790 
    791         env->ReleaseStringUTFChars(key, c_key);
    792 
    793         if (!reply) {
    794             if (dbus_error_is_set(&err)) {
    795                 LOG_AND_FREE_DBUS_ERROR(&err);
    796             } else
    797                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    798             return JNI_FALSE;
    799         }
    800         return JNI_TRUE;
    801     }
    802 #endif
    803     return JNI_FALSE;
    804 }
    805 
    806 static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
    807                                                jstring value) {
    808 #ifdef HAVE_BLUETOOTH
    809     const char *c_value = env->GetStringUTFChars(value, NULL);
    810     jboolean ret =  setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING);
    811     env->ReleaseStringUTFChars(value, (char *)c_value);
    812     return ret;
    813 #else
    814     return JNI_FALSE;
    815 #endif
    816 }
    817 
    818 static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
    819                                                jint value) {
    820 #ifdef HAVE_BLUETOOTH
    821     return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
    822 #else
    823     return JNI_FALSE;
    824 #endif
    825 }
    826 
    827 static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
    828                                                jint value) {
    829 #ifdef HAVE_BLUETOOTH
    830     return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
    831 #else
    832     return JNI_FALSE;
    833 #endif
    834 }
    835 
    836 static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path,
    837                                                jstring key, void *value, jint type) {
    838 #ifdef HAVE_BLUETOOTH
    839     LOGV(__FUNCTION__);
    840     native_data_t *nat = get_native_data(env, object);
    841     if (nat) {
    842         DBusMessage *reply, *msg;
    843         DBusMessageIter iter;
    844         DBusError err;
    845 
    846         const char *c_key = env->GetStringUTFChars(key, NULL);
    847         const char *c_path = env->GetStringUTFChars(path, NULL);
    848 
    849         dbus_error_init(&err);
    850         msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    851                                           c_path, DBUS_DEVICE_IFACE, "SetProperty");
    852         if (!msg) {
    853             LOGE("%s: Can't allocate new method call for device SetProperty!", __FUNCTION__);
    854             env->ReleaseStringUTFChars(key, c_key);
    855             env->ReleaseStringUTFChars(path, c_path);
    856             return JNI_FALSE;
    857         }
    858 
    859         dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
    860         dbus_message_iter_init_append(msg, &iter);
    861         append_variant(&iter, type, value);
    862 
    863         reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    864         dbus_message_unref(msg);
    865 
    866         env->ReleaseStringUTFChars(key, c_key);
    867         env->ReleaseStringUTFChars(path, c_path);
    868         if (!reply) {
    869             if (dbus_error_is_set(&err)) {
    870                 LOG_AND_FREE_DBUS_ERROR(&err);
    871             } else
    872             LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    873             return JNI_FALSE;
    874         }
    875         return JNI_TRUE;
    876     }
    877 #endif
    878     return JNI_FALSE;
    879 }
    880 
    881 static jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object,
    882                                                      jstring path, jstring key, jint value) {
    883 #ifdef HAVE_BLUETOOTH
    884     return setDevicePropertyNative(env, object, path, key,
    885                                         (void *)&value, DBUS_TYPE_BOOLEAN);
    886 #else
    887     return JNI_FALSE;
    888 #endif
    889 }
    890 
    891 
    892 static jboolean createDeviceNative(JNIEnv *env, jobject object,
    893                                                 jstring address) {
    894     LOGV(__FUNCTION__);
    895 #ifdef HAVE_BLUETOOTH
    896     native_data_t *nat = get_native_data(env, object);
    897     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    898     struct event_loop_native_data_t *eventLoopNat =
    899             get_EventLoop_native_data(env, eventLoop);
    900 
    901     if (nat && eventLoopNat) {
    902         const char *c_address = env->GetStringUTFChars(address, NULL);
    903         LOGV("... address = %s", c_address);
    904         char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
    905         strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
    906 
    907         bool ret = dbus_func_args_async(env, nat->conn, -1,
    908                                         onCreateDeviceResult,
    909                                         context_address,
    910                                         eventLoopNat,
    911                                         get_adapter_path(env, object),
    912                                         DBUS_ADAPTER_IFACE,
    913                                         "CreateDevice",
    914                                         DBUS_TYPE_STRING, &c_address,
    915                                         DBUS_TYPE_INVALID);
    916         env->ReleaseStringUTFChars(address, c_address);
    917         return ret ? JNI_TRUE : JNI_FALSE;
    918     }
    919 #endif
    920     return JNI_FALSE;
    921 }
    922 
    923 static jboolean discoverServicesNative(JNIEnv *env, jobject object,
    924                                                jstring path, jstring pattern) {
    925     LOGV(__FUNCTION__);
    926 #ifdef HAVE_BLUETOOTH
    927     native_data_t *nat = get_native_data(env, object);
    928     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    929     struct event_loop_native_data_t *eventLoopNat =
    930             get_EventLoop_native_data(env, eventLoop);
    931 
    932     if (nat && eventLoopNat) {
    933         const char *c_path = env->GetStringUTFChars(path, NULL);
    934         const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
    935         int len = env->GetStringLength(path) + 1;
    936         char *context_path = (char *)calloc(len, sizeof(char));
    937         strlcpy(context_path, c_path, len);  // for callback
    938 
    939         LOGV("... Object Path = %s", c_path);
    940         LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern));
    941 
    942         bool ret = dbus_func_args_async(env, nat->conn, -1,
    943                                         onDiscoverServicesResult,
    944                                         context_path,
    945                                         eventLoopNat,
    946                                         c_path,
    947                                         DBUS_DEVICE_IFACE,
    948                                         "DiscoverServices",
    949                                         DBUS_TYPE_STRING, &c_pattern,
    950                                         DBUS_TYPE_INVALID);
    951         env->ReleaseStringUTFChars(path, c_path);
    952         env->ReleaseStringUTFChars(pattern, c_pattern);
    953         return ret ? JNI_TRUE : JNI_FALSE;
    954     }
    955 #endif
    956     return JNI_FALSE;
    957 }
    958 
    959 static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
    960         jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
    961     LOGV(__FUNCTION__);
    962 #ifdef HAVE_BLUETOOTH
    963     native_data_t *nat = get_native_data(env, object);
    964     if (nat) {
    965         const char *c_name = env->GetStringUTFChars(name, NULL);
    966         LOGV("... name = %s", c_name);
    967         LOGV("... uuid1 = %llX", uuidMsb);
    968         LOGV("... uuid2 = %llX", uuidLsb);
    969         LOGV("... channel = %d", channel);
    970         DBusMessage *reply = dbus_func_args(env, nat->conn,
    971                            get_adapter_path(env, object),
    972                            DBUS_ADAPTER_IFACE, "AddRfcommServiceRecord",
    973                            DBUS_TYPE_STRING, &c_name,
    974                            DBUS_TYPE_UINT64, &uuidMsb,
    975                            DBUS_TYPE_UINT64, &uuidLsb,
    976                            DBUS_TYPE_UINT16, &channel,
    977                            DBUS_TYPE_INVALID);
    978         env->ReleaseStringUTFChars(name, c_name);
    979         return reply ? dbus_returns_uint32(env, reply) : -1;
    980     }
    981 #endif
    982     return -1;
    983 }
    984 
    985 static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
    986     LOGV(__FUNCTION__);
    987 #ifdef HAVE_BLUETOOTH
    988     native_data_t *nat = get_native_data(env, object);
    989     if (nat) {
    990         LOGV("... handle = %X", handle);
    991         DBusMessage *reply = dbus_func_args(env, nat->conn,
    992                            get_adapter_path(env, object),
    993                            DBUS_ADAPTER_IFACE, "RemoveServiceRecord",
    994                            DBUS_TYPE_UINT32, &handle,
    995                            DBUS_TYPE_INVALID);
    996         return reply ? JNI_TRUE : JNI_FALSE;
    997     }
    998 #endif
    999     return JNI_FALSE;
   1000 }
   1001 
   1002 static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object_path,
   1003                                      jint num_slots) {
   1004     LOGV(__FUNCTION__);
   1005 #ifdef HAVE_BLUETOOTH
   1006     native_data_t *nat = get_native_data(env, object);
   1007     if (nat) {
   1008         const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
   1009         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1010                            get_adapter_path(env, object),
   1011                            DBUS_ADAPTER_IFACE, "SetLinkTimeout",
   1012                            DBUS_TYPE_OBJECT_PATH, &c_object_path,
   1013                            DBUS_TYPE_UINT32, &num_slots,
   1014                            DBUS_TYPE_INVALID);
   1015         env->ReleaseStringUTFChars(object_path, c_object_path);
   1016         return reply ? JNI_TRUE : JNI_FALSE;
   1017     }
   1018 #endif
   1019     return JNI_FALSE;
   1020 }
   1021 
   1022 static JNINativeMethod sMethods[] = {
   1023      /* name, signature, funcPtr */
   1024     {"classInitNative", "()V", (void*)classInitNative},
   1025     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
   1026     {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative},
   1027     {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative},
   1028     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
   1029     {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
   1030 
   1031     {"isEnabledNative", "()I", (void *)isEnabledNative},
   1032     {"enableNative", "()I", (void *)enableNative},
   1033     {"disableNative", "()I", (void *)disableNative},
   1034 
   1035     {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative},
   1036     {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
   1037       (void *)getDevicePropertiesNative},
   1038     {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
   1039       (void *)setAdapterPropertyStringNative},
   1040     {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z",
   1041       (void *)setAdapterPropertyBooleanNative},
   1042     {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z",
   1043       (void *)setAdapterPropertyIntegerNative},
   1044 
   1045     {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
   1046     {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
   1047 
   1048     {"readAdapterOutOfBandDataNative", "()[B", (void *)readAdapterOutOfBandDataNative},
   1049     {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
   1050     {"createPairedDeviceOutOfBandNative", "(Ljava/lang/String;I)Z",
   1051                                     (void *)createPairedDeviceOutOfBandNative},
   1052     {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
   1053     {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
   1054     {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
   1055       (void *)getDeviceServiceChannelNative},
   1056 
   1057     {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
   1058             (void *)setPairingConfirmationNative},
   1059     {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
   1060     {"setRemoteOutOfBandDataNative", "(Ljava/lang/String;[B[BI)Z", (void *)setRemoteOutOfBandDataNative},
   1061     {"setAuthorizationNative", "(Ljava/lang/String;ZI)Z", (void *)setAuthorizationNative},
   1062     {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
   1063     {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
   1064             (void *)cancelPairingUserInputNative},
   1065     {"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
   1066             (void *)setDevicePropertyBooleanNative},
   1067     {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
   1068     {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
   1069     {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative},
   1070     {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative},
   1071     {"setLinkTimeoutNative", "(Ljava/lang/String;I)Z", (void *)setLinkTimeoutNative},
   1072 };
   1073 
   1074 int register_android_server_BluetoothService(JNIEnv *env) {
   1075     return AndroidRuntime::registerNativeMethods(env,
   1076                 "android/server/BluetoothService", sMethods, NELEM(sMethods));
   1077 }
   1078 
   1079 } /* namespace android */
   1080