Home | History | Annotate | Download | only in gps
      1 /*
      2  * Copyright (C) 2017 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 /* This implements a GPS hardware HAL library for cuttlefish.
     18  * A produced shared library is placed in /system/lib/hw/gps.gce.so, and
     19  * loaded by hardware/libhardware/hardware.c code which is called from
     20  * android_location_GpsLocationProvider.cpp
     21  */
     22 
     23 #include <errno.h>
     24 #include <pthread.h>
     25 #include <stdint.h>
     26 #include <unistd.h>
     27 
     28 #include <log/log.h>
     29 #include <cutils/sockets.h>
     30 #include <hardware/gps.h>
     31 
     32 #include "guest/hals/gps/gps_thread.h"
     33 #include "guest/libs/platform_support/api_level_fixes.h"
     34 
     35 static GpsState _gps_state;
     36 
     37 // Cleans up GpsState data structure.
     38 static void gps_state_cleanup(GpsState* s) {
     39   char cmd = CMD_QUIT;
     40 
     41   write(s->control[0], &cmd, 1);
     42   if (s->thread > 0) {
     43     pthread_join(s->thread, NULL);
     44   }
     45 
     46   close(s->control[0]);
     47   close(s->control[1]);
     48   close(s->fd);
     49 
     50   s->thread = 0;
     51   s->control[0] = -1;
     52   s->control[1] = -1;
     53   s->fd = -1;
     54   s->init = 0;
     55 }
     56 
     57 static int gce_gps_init(GpsCallbacks* callbacks) {
     58   D("%s: called", __FUNCTION__);
     59   // Stop if the framework does not fulfill its interface contract.
     60   // We don't want to return an error and continue to ensure that we
     61   // catch framework breaks ASAP and to give a tombstone to track down the
     62   // offending code.
     63   LOG_ALWAYS_FATAL_IF(!callbacks->location_cb);
     64   LOG_ALWAYS_FATAL_IF(!callbacks->status_cb);
     65   LOG_ALWAYS_FATAL_IF(!callbacks->sv_status_cb);
     66   LOG_ALWAYS_FATAL_IF(!callbacks->nmea_cb);
     67   LOG_ALWAYS_FATAL_IF(!callbacks->set_capabilities_cb);
     68   LOG_ALWAYS_FATAL_IF(!callbacks->acquire_wakelock_cb);
     69   LOG_ALWAYS_FATAL_IF(!callbacks->release_wakelock_cb);
     70   LOG_ALWAYS_FATAL_IF(!callbacks->create_thread_cb);
     71   LOG_ALWAYS_FATAL_IF(!callbacks->request_utc_time_cb);
     72   if (!_gps_state.init) {
     73     _gps_state.init = 1;
     74     _gps_state.control[0] = -1;
     75     _gps_state.control[1] = -1;
     76     _gps_state.thread = 0;
     77 
     78     _gps_state.fd = socket_local_client(
     79         "gps_broadcasts", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
     80     if (_gps_state.fd < 0) {
     81       ALOGE("no GPS emulation detected.");
     82       goto Fail;
     83     }
     84     D("GPS HAL will receive data from remoter via gps_broadcasts channel.");
     85 
     86     if (socketpair(AF_LOCAL, SOCK_STREAM, 0, _gps_state.control) < 0) {
     87       ALOGE("could not create thread control socket pair: %s", strerror(errno));
     88       goto Fail;
     89     }
     90 
     91     _gps_state.callbacks = *callbacks;
     92     ALOGE("Starting thread callback=%p", callbacks->location_cb);
     93     _gps_state.thread = callbacks->create_thread_cb(
     94         "gps_state_thread", gps_state_thread, &_gps_state);
     95     if (!_gps_state.thread) {
     96       ALOGE("could not create GPS thread: %s", strerror(errno));
     97       goto Fail;
     98     }
     99   }
    100 
    101   if (_gps_state.fd < 0) return -1;
    102   return 0;
    103 
    104 Fail:
    105   gps_state_cleanup(&_gps_state);
    106   return -1;
    107 }
    108 
    109 static void gce_gps_cleanup() {
    110   D("%s: called", __FUNCTION__);
    111   if (_gps_state.init) gps_state_cleanup(&_gps_state);
    112 }
    113 
    114 static int gce_gps_start() {
    115   if (!_gps_state.init) {
    116     ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
    117     return -1;
    118   }
    119 
    120   char cmd = CMD_START;
    121   int ret;
    122   do {
    123     ret = write(_gps_state.control[0], &cmd, 1);
    124   } while (ret < 0 && errno == EINTR);
    125 
    126   if (ret != 1) {
    127     D("%s: could not send CMD_START command: ret=%d: %s", __FUNCTION__, ret,
    128       strerror(errno));
    129     return -1;
    130   }
    131 
    132   return 0;
    133 }
    134 
    135 static int gce_gps_stop() {
    136   D("%s: called", __FUNCTION__);
    137   if (!_gps_state.init) {
    138     ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
    139     return -1;
    140   }
    141 
    142   char cmd = CMD_STOP;
    143   int ret;
    144 
    145   do {
    146     ret = write(_gps_state.control[0], &cmd, 1);
    147   } while (ret < 0 && errno == EINTR);
    148 
    149   if (ret != 1) {
    150     ALOGE("%s: could not send CMD_STOP command: ret=%d: %s", __FUNCTION__, ret,
    151           strerror(errno));
    152     return -1;
    153   }
    154   return 0;
    155 }
    156 
    157 static int gce_gps_inject_time(GpsUtcTime /*time*/, int64_t /*time_ref*/,
    158                                int /*uncertainty*/) {
    159   D("%s: called", __FUNCTION__);
    160   if (!_gps_state.init) {
    161     ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
    162     return -1;
    163   }
    164 
    165   return 0;
    166 }
    167 
    168 static int gce_gps_inject_location(double /*latitude*/, double /*longitude*/,
    169                                    float /*accuracy*/) {
    170   D("%s: called", __FUNCTION__);
    171   if (!_gps_state.init) {
    172     ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
    173     return -1;
    174   }
    175 
    176   return 0;
    177 }
    178 
    179 static void gce_gps_delete_aiding_data(GpsAidingData /*flags*/) {
    180   D("%s: called", __FUNCTION__);
    181   if (!_gps_state.init) {
    182     ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
    183     return;
    184   }
    185 }
    186 
    187 static int gce_gps_set_position_mode(GpsPositionMode mode,
    188                                      GpsPositionRecurrence recurrence,
    189                                      uint32_t min_interval,
    190                                      uint32_t preferred_accuracy,
    191                                      uint32_t preferred_time) {
    192   D("%s: called", __FUNCTION__);
    193   if (!_gps_state.init) {
    194     ALOGE("%s: called with uninitialized gps_state!", __FUNCTION__);
    195     return -1;
    196   }
    197   ALOGE("%s(mode=%d, recurrence=%d, min_interval=%" PRIu32
    198         ", "
    199         "preferred_accuracy=%" PRIu32 ", preferred_time=%" PRIu32
    200         ") unimplemented",
    201         __FUNCTION__, mode, recurrence, min_interval, preferred_accuracy,
    202         preferred_time);
    203   return 0;
    204 }
    205 
    206 static const void* gce_gps_get_extension(const char* name) {
    207   D("%s: called", __FUNCTION__);
    208   // It is normal for this to be called before init.
    209   ALOGE("%s(%s): called but not implemented.", __FUNCTION__,
    210         name ? name : "NULL");
    211   return NULL;
    212 }
    213 
    214 static const GpsInterface gceGpsInterface = {
    215     sizeof(GpsInterface),
    216     gce_gps_init,
    217     gce_gps_start,
    218     gce_gps_stop,
    219     gce_gps_cleanup,
    220     gce_gps_inject_time,
    221     gce_gps_inject_location,
    222     gce_gps_delete_aiding_data,
    223     gce_gps_set_position_mode,
    224     gce_gps_get_extension,
    225 };
    226 
    227 const GpsInterface* gps_get_gps_interface(struct gps_device_t* /*dev*/) {
    228   return &gceGpsInterface;
    229 }
    230 
    231 static int open_gps(const struct hw_module_t* module, char const* /*name*/,
    232                     struct hw_device_t** device) {
    233   struct gps_device_t* dev =
    234       (struct gps_device_t*)malloc(sizeof(struct gps_device_t));
    235   LOG_FATAL_IF(!dev, "%s: malloc returned NULL.", __FUNCTION__);
    236   memset(dev, 0, sizeof(*dev));
    237 
    238   dev->common.tag = HARDWARE_DEVICE_TAG;
    239   dev->common.version = 0;
    240   dev->common.module = (struct hw_module_t*)module;
    241   dev->get_gps_interface = gps_get_gps_interface;
    242 
    243   *device = (struct hw_device_t*)dev;
    244   return 0;
    245 }
    246 
    247 static struct hw_module_methods_t gps_module_methods = {
    248     VSOC_STATIC_INITIALIZER(open) open_gps};
    249 
    250 struct hw_module_t HAL_MODULE_INFO_SYM = {
    251     VSOC_STATIC_INITIALIZER(tag) HARDWARE_MODULE_TAG,
    252     VSOC_STATIC_INITIALIZER(version_major) 1,
    253     VSOC_STATIC_INITIALIZER(version_minor) 0,
    254     VSOC_STATIC_INITIALIZER(id) GPS_HARDWARE_MODULE_ID,
    255     VSOC_STATIC_INITIALIZER(name) "GCE GPS Module",
    256     VSOC_STATIC_INITIALIZER(author) "The Android Open Source Project",
    257     VSOC_STATIC_INITIALIZER(methods) & gps_module_methods,
    258 };
    259