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 <cutils/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