com_android_server_location_GnssLocationProvider.cpp revision 8ad4430c57539d8b4cb5856bd9cfc3ba06ca6343
1/*
2 * Copyright (C) 2008 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 LOG_TAG "GnssLocationProvider"
18
19#define LOG_NDEBUG 0
20
21#include "JNIHelp.h"
22#include "jni.h"
23#include "hardware/hardware.h"
24#include "hardware/gps_internal.h"
25#include "hardware_legacy/power.h"
26#include "utils/Log.h"
27#include "utils/misc.h"
28#include "android_runtime/AndroidRuntime.h"
29#include "android_runtime/Log.h"
30
31#include <arpa/inet.h>
32#include <limits>
33#include <linux/in.h>
34#include <linux/in6.h>
35#include <pthread.h>
36#include <string.h>
37
38static jobject mCallbacksObj = NULL;
39
40static jmethodID method_reportLocation;
41static jmethodID method_reportStatus;
42static jmethodID method_reportSvStatus;
43static jmethodID method_reportAGpsStatus;
44static jmethodID method_reportNmea;
45static jmethodID method_setEngineCapabilities;
46static jmethodID method_setGnssYearOfHardware;
47static jmethodID method_xtraDownloadRequest;
48static jmethodID method_reportNiNotification;
49static jmethodID method_requestRefLocation;
50static jmethodID method_requestSetID;
51static jmethodID method_requestUtcTime;
52static jmethodID method_reportGeofenceTransition;
53static jmethodID method_reportGeofenceStatus;
54static jmethodID method_reportGeofenceAddStatus;
55static jmethodID method_reportGeofenceRemoveStatus;
56static jmethodID method_reportGeofencePauseStatus;
57static jmethodID method_reportGeofenceResumeStatus;
58static jmethodID method_reportMeasurementData;
59static jmethodID method_reportNavigationMessages;
60
61static const GpsInterface* sGpsInterface = NULL;
62static const GpsXtraInterface* sGpsXtraInterface = NULL;
63static const AGpsInterface* sAGpsInterface = NULL;
64static const GpsNiInterface* sGpsNiInterface = NULL;
65static const GpsDebugInterface* sGpsDebugInterface = NULL;
66static const AGpsRilInterface* sAGpsRilInterface = NULL;
67static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
68static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
69static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
70static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
71
72#define GPS_MAX_SATELLITE_COUNT 32
73#define GNSS_MAX_SATELLITE_COUNT 64
74
75#define SVID_SHIFT_WIDTH 7
76#define CONSTELLATION_TYPE_SHIFT_WIDTH 3
77
78// temporary storage for GPS callbacks
79static GnssSvInfo sGnssSvList[GNSS_MAX_SATELLITE_COUNT];
80static size_t sGnssSvListSize;
81static const char* sNmeaString;
82static int sNmeaStringLength;
83
84#define WAKE_LOCK_NAME  "GPS"
85
86namespace android {
87
88static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
89    if (env->ExceptionCheck()) {
90        ALOGE("An exception was thrown by callback '%s'.", methodName);
91        LOGE_EX(env);
92        env->ExceptionClear();
93    }
94}
95
96static void location_callback(GpsLocation* location)
97{
98    JNIEnv* env = AndroidRuntime::getJNIEnv();
99    env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
100            (jdouble)location->latitude, (jdouble)location->longitude,
101            (jdouble)location->altitude,
102            (jfloat)location->speed, (jfloat)location->bearing,
103            (jfloat)location->accuracy, (jlong)location->timestamp);
104    checkAndClearExceptionFromCallback(env, __FUNCTION__);
105}
106
107static void status_callback(GpsStatus* status)
108{
109    JNIEnv* env = AndroidRuntime::getJNIEnv();
110    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
111    checkAndClearExceptionFromCallback(env, __FUNCTION__);
112}
113
114static void sv_status_callback(GpsSvStatus* sv_status)
115{
116    JNIEnv* env = AndroidRuntime::getJNIEnv();
117    size_t status_size = sv_status->size;
118    // Some drives doesn't set the size field correctly. Assume GpsSvStatus_v1
119    // if it doesn't provide a valid size.
120    if (status_size == 0) {
121        ALOGW("Invalid size of GpsSvStatus found: %zd.", status_size);
122    }
123    sGnssSvListSize = sv_status->num_svs;
124    // Clamp the list size. Legacy GpsSvStatus has only 32 elements in sv_list.
125    if (sGnssSvListSize > GPS_MAX_SATELLITE_COUNT) {
126        ALOGW("Too many satellites %zd. Clamps to %d.",
127              sGnssSvListSize,
128              GPS_MAX_SATELLITE_COUNT);
129        sGnssSvListSize = GPS_MAX_SATELLITE_COUNT;
130    }
131    uint32_t ephemeris_mask = sv_status->ephemeris_mask;
132    uint32_t almanac_mask = sv_status->almanac_mask;
133    uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
134    for (size_t i = 0; i < sGnssSvListSize; i++) {
135        GnssSvInfo& info = sGnssSvList[i];
136        info.svid = sv_status->sv_list[i].prn;
137        if (info.svid >=1 && info.svid <= 32) {
138            info.constellation = GNSS_CONSTELLATION_GPS;
139        } else {
140            ALOGD("Unknown constellation type with Svid = %d.", info.svid);
141            info.constellation = GNSS_CONSTELLATION_UNKNOWN;
142        }
143        info.c_n0_dbhz = sv_status->sv_list[i].snr;
144        info.elevation = sv_status->sv_list[i].elevation;
145        info.azimuth = sv_status->sv_list[i].azimuth;
146        info.flags = GNSS_SV_FLAGS_NONE;
147        if (info.svid > 0 && info.svid <= 32) {
148            int32_t this_svid_mask = (1 << (info.svid - 1));
149            if ((ephemeris_mask & this_svid_mask) != 0) {
150                info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
151            }
152            if ((almanac_mask & this_svid_mask) != 0) {
153                info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
154            }
155            if ((used_in_fix_mask & this_svid_mask) != 0) {
156                info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
157            }
158        }
159    }
160    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
161    checkAndClearExceptionFromCallback(env, __FUNCTION__);
162}
163
164static void gnss_sv_status_callback(GnssSvStatus* sv_status) {
165    JNIEnv* env = AndroidRuntime::getJNIEnv();
166    size_t status_size = sv_status->size;
167    // Check the size, and reject the object that has invalid size.
168    if (status_size != sizeof(GnssSvStatus)) {
169        ALOGE("Invalid size of GnssSvStatus found: %zd.", status_size);
170        return;
171    }
172    sGnssSvListSize = sv_status->num_svs;
173    // Clamp the list size
174    if (sGnssSvListSize > GNSS_MAX_SATELLITE_COUNT) {
175        ALOGD("Too many satellites %zd. Clamps to %d.",
176              sGnssSvListSize,
177              GNSS_MAX_SATELLITE_COUNT);
178        sGnssSvListSize = GNSS_MAX_SATELLITE_COUNT;
179    }
180    // Copy GNSS SV info into sGnssSvList, if any.
181    if (sGnssSvListSize > 0) {
182        memcpy(sGnssSvList,
183               sv_status->gnss_sv_list,
184               sizeof(GnssSvInfo) * sGnssSvListSize);
185    }
186    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
187    checkAndClearExceptionFromCallback(env, __FUNCTION__);
188}
189
190static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
191{
192    JNIEnv* env = AndroidRuntime::getJNIEnv();
193    // The Java code will call back to read these values
194    // We do this to avoid creating unnecessary String objects
195    sNmeaString = nmea;
196    sNmeaStringLength = length;
197    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
198    checkAndClearExceptionFromCallback(env, __FUNCTION__);
199}
200
201static void set_system_info_callback(const GnssSystemInfo* info) {
202    ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
203    JNIEnv* env = AndroidRuntime::getJNIEnv();
204    env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
205                        info->year_of_hw);
206    checkAndClearExceptionFromCallback(env, __FUNCTION__);
207}
208
209static void set_capabilities_callback(uint32_t capabilities)
210{
211    ALOGD("set_capabilities_callback: %du\n", capabilities);
212    JNIEnv* env = AndroidRuntime::getJNIEnv();
213    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
214    checkAndClearExceptionFromCallback(env, __FUNCTION__);
215}
216
217static void acquire_wakelock_callback()
218{
219    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
220}
221
222static void release_wakelock_callback()
223{
224    release_wake_lock(WAKE_LOCK_NAME);
225}
226
227static void request_utc_time_callback()
228{
229    JNIEnv* env = AndroidRuntime::getJNIEnv();
230    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
231    checkAndClearExceptionFromCallback(env, __FUNCTION__);
232}
233
234static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
235{
236    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
237}
238
239GpsCallbacks sGpsCallbacks = {
240    sizeof(GpsCallbacks),
241    location_callback,
242    status_callback,
243    sv_status_callback,
244    nmea_callback,
245    set_capabilities_callback,
246    acquire_wakelock_callback,
247    release_wakelock_callback,
248    create_thread_callback,
249    request_utc_time_callback,
250    set_system_info_callback,
251    gnss_sv_status_callback,
252};
253
254static void xtra_download_request_callback()
255{
256    JNIEnv* env = AndroidRuntime::getJNIEnv();
257    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
258    checkAndClearExceptionFromCallback(env, __FUNCTION__);
259}
260
261GpsXtraCallbacks sGpsXtraCallbacks = {
262    xtra_download_request_callback,
263    create_thread_callback,
264};
265
266static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order)
267{
268    if (INADDR_NONE == ip) {
269        return NULL;
270    }
271
272    JNIEnv* env = AndroidRuntime::getJNIEnv();
273    jbyteArray byteArray = env->NewByteArray(4);
274    if (byteArray == NULL) {
275        ALOGE("Unable to allocate byte array for IPv4 address");
276        return NULL;
277    }
278
279    jbyte ipv4[4];
280    if (net_order) {
281        ALOGV("Converting IPv4 address(net_order) %x", ip);
282        memcpy(ipv4, &ip, sizeof(ipv4));
283    } else {
284        ALOGV("Converting IPv4 address(host_order) %x", ip);
285        //endianess transparent conversion from int to char[]
286        ipv4[0] = (jbyte) (ip & 0xFF);
287        ipv4[1] = (jbyte)((ip>>8) & 0xFF);
288        ipv4[2] = (jbyte)((ip>>16) & 0xFF);
289        ipv4[3] = (jbyte) (ip>>24);
290    }
291
292    env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4);
293    return byteArray;
294}
295
296static void agps_status_callback(AGpsStatus* agps_status)
297{
298    JNIEnv* env = AndroidRuntime::getJNIEnv();
299    jbyteArray byteArray = NULL;
300    bool isSupported = false;
301
302    size_t status_size = agps_status->size;
303    if (status_size == sizeof(AGpsStatus)) {
304      ALOGV("AGpsStatus is V3: %zd", status_size);
305      switch (agps_status->addr.ss_family)
306      {
307      case AF_INET:
308          {
309            struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr);
310            uint32_t ipAddr = *(uint32_t*)&(in->sin_addr);
311            byteArray = convert_to_ipv4(ipAddr, true /* net_order */);
312            if (ipAddr == INADDR_NONE || byteArray != NULL) {
313                isSupported = true;
314            }
315            IF_ALOGD() {
316                // log the IP for reference in case there is a bogus value pushed by HAL
317                char str[INET_ADDRSTRLEN];
318                inet_ntop(AF_INET, &(in->sin_addr), str, INET_ADDRSTRLEN);
319                ALOGD("AGPS IP is v4: %s", str);
320            }
321          }
322          break;
323      case AF_INET6:
324          {
325            struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr);
326            byteArray = env->NewByteArray(16);
327            if (byteArray != NULL) {
328                env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr));
329                isSupported = true;
330            } else {
331                ALOGE("Unable to allocate byte array for IPv6 address.");
332            }
333            IF_ALOGD() {
334                // log the IP for reference in case there is a bogus value pushed by HAL
335                char str[INET6_ADDRSTRLEN];
336                inet_ntop(AF_INET6, &(in6->sin6_addr), str, INET6_ADDRSTRLEN);
337                ALOGD("AGPS IP is v6: %s", str);
338            }
339          }
340          break;
341      default:
342          ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family);
343          break;
344      }
345    } else if (status_size >= sizeof(AGpsStatus_v2)) {
346      ALOGV("AGpsStatus is V2+: %zd", status_size);
347      // for back-compatibility reasons we check in v2 that the data structure size is greater or
348      // equal to the declared size in gps.h
349      uint32_t ipaddr = agps_status->ipaddr;
350      ALOGV("AGPS IP is v4: %x", ipaddr);
351      byteArray = convert_to_ipv4(ipaddr, false /* net_order */);
352      if (ipaddr == INADDR_NONE || byteArray != NULL) {
353          isSupported = true;
354      }
355    } else if (status_size >= sizeof(AGpsStatus_v1)) {
356        ALOGV("AGpsStatus is V1+: %zd", status_size);
357        // because we have to check for >= with regards to v2, we also need to relax the check here
358        // and only make sure that the size is at least what we expect
359        isSupported = true;
360    } else {
361        ALOGE("Invalid size of AGpsStatus found: %zd.", status_size);
362    }
363
364    if (isSupported) {
365        jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
366        ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
367        env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type,
368                            agps_status->status, byteArray);
369
370        checkAndClearExceptionFromCallback(env, __FUNCTION__);
371    } else {
372        ALOGD("Skipping calling method_reportAGpsStatus.");
373    }
374
375    if (byteArray) {
376        env->DeleteLocalRef(byteArray);
377    }
378}
379
380AGpsCallbacks sAGpsCallbacks = {
381    agps_status_callback,
382    create_thread_callback,
383};
384
385static void gps_ni_notify_callback(GpsNiNotification *notification)
386{
387    ALOGD("gps_ni_notify_callback\n");
388    JNIEnv* env = AndroidRuntime::getJNIEnv();
389    jstring requestor_id = env->NewStringUTF(notification->requestor_id);
390    jstring text = env->NewStringUTF(notification->text);
391    jstring extras = env->NewStringUTF(notification->extras);
392
393    if (requestor_id && text && extras) {
394        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
395            notification->notification_id, notification->ni_type,
396            notification->notify_flags, notification->timeout,
397            notification->default_response, requestor_id, text,
398            notification->requestor_id_encoding,
399            notification->text_encoding, extras);
400    } else {
401        ALOGE("out of memory in gps_ni_notify_callback\n");
402    }
403
404    if (requestor_id)
405        env->DeleteLocalRef(requestor_id);
406    if (text)
407        env->DeleteLocalRef(text);
408    if (extras)
409        env->DeleteLocalRef(extras);
410    checkAndClearExceptionFromCallback(env, __FUNCTION__);
411}
412
413GpsNiCallbacks sGpsNiCallbacks = {
414    gps_ni_notify_callback,
415    create_thread_callback,
416};
417
418static void agps_request_set_id(uint32_t flags)
419{
420    JNIEnv* env = AndroidRuntime::getJNIEnv();
421    env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
422    checkAndClearExceptionFromCallback(env, __FUNCTION__);
423}
424
425static void agps_request_ref_location(uint32_t flags)
426{
427    JNIEnv* env = AndroidRuntime::getJNIEnv();
428    env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
429    checkAndClearExceptionFromCallback(env, __FUNCTION__);
430}
431
432AGpsRilCallbacks sAGpsRilCallbacks = {
433    agps_request_set_id,
434    agps_request_ref_location,
435    create_thread_callback,
436};
437
438static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
439        int32_t transition, GpsUtcTime timestamp)
440{
441    JNIEnv* env = AndroidRuntime::getJNIEnv();
442
443    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
444            location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
445            (jdouble)location->altitude,
446            (jfloat)location->speed, (jfloat)location->bearing,
447            (jfloat)location->accuracy, (jlong)location->timestamp,
448            transition, timestamp);
449    checkAndClearExceptionFromCallback(env, __FUNCTION__);
450};
451
452static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
453{
454    JNIEnv* env = AndroidRuntime::getJNIEnv();
455    jint flags = 0;
456    jdouble latitude = 0;
457    jdouble longitude = 0;
458    jdouble altitude = 0;
459    jfloat speed = 0;
460    jfloat bearing = 0;
461    jfloat accuracy = 0;
462    jlong timestamp = 0;
463    if (location != NULL) {
464        flags = location->flags;
465        latitude = location->latitude;
466        longitude = location->longitude;
467        altitude = location->altitude;
468        speed = location->speed;
469        bearing = location->bearing;
470        accuracy = location->accuracy;
471        timestamp = location->timestamp;
472    }
473
474    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
475            flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
476    checkAndClearExceptionFromCallback(env, __FUNCTION__);
477};
478
479static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
480{
481    JNIEnv* env = AndroidRuntime::getJNIEnv();
482    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
483        ALOGE("Error in geofence_add_callback: %d\n", status);
484    }
485    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
486    checkAndClearExceptionFromCallback(env, __FUNCTION__);
487};
488
489static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
490{
491    JNIEnv* env = AndroidRuntime::getJNIEnv();
492    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
493        ALOGE("Error in geofence_remove_callback: %d\n", status);
494    }
495    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
496    checkAndClearExceptionFromCallback(env, __FUNCTION__);
497};
498
499static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
500{
501    JNIEnv* env = AndroidRuntime::getJNIEnv();
502    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
503        ALOGE("Error in geofence_resume_callback: %d\n", status);
504    }
505    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
506    checkAndClearExceptionFromCallback(env, __FUNCTION__);
507};
508
509static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
510{
511    JNIEnv* env = AndroidRuntime::getJNIEnv();
512    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
513        ALOGE("Error in geofence_pause_callback: %d\n", status);
514    }
515    env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
516    checkAndClearExceptionFromCallback(env, __FUNCTION__);
517};
518
519GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
520    gps_geofence_transition_callback,
521    gps_geofence_status_callback,
522    gps_geofence_add_callback,
523    gps_geofence_remove_callback,
524    gps_geofence_pause_callback,
525    gps_geofence_resume_callback,
526    create_thread_callback,
527};
528
529static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
530    int err;
531    hw_module_t* module;
532
533    method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
534    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
535    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
536    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
537    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
538    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
539    method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
540    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
541    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
542            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
543    method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
544    method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
545    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
546    method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
547            "(IIDDDFFFJIJ)V");
548    method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
549            "(IIDDDFFFJ)V");
550    method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
551            "(II)V");
552    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
553            "(II)V");
554    method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
555            "(II)V");
556    method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
557            "(II)V");
558    method_reportMeasurementData = env->GetMethodID(
559            clazz,
560            "reportMeasurementData",
561            "(Landroid/location/GnssMeasurementsEvent;)V");
562    method_reportNavigationMessages = env->GetMethodID(
563            clazz,
564            "reportNavigationMessage",
565            "(Landroid/location/GnssNavigationMessage;)V");
566
567    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
568    if (err == 0) {
569        hw_device_t* device;
570        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
571        if (err == 0) {
572            gps_device_t* gps_device = (gps_device_t *)device;
573            sGpsInterface = gps_device->get_gps_interface(gps_device);
574        }
575    }
576    if (sGpsInterface) {
577        sGpsXtraInterface =
578            (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
579        sAGpsInterface =
580            (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
581        sGpsNiInterface =
582            (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
583        sGpsDebugInterface =
584            (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
585        sAGpsRilInterface =
586            (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
587        sGpsGeofencingInterface =
588            (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
589        sGpsMeasurementInterface =
590            (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
591        sGpsNavigationMessageInterface =
592            (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
593                    GPS_NAVIGATION_MESSAGE_INTERFACE);
594        sGnssConfigurationInterface =
595            (const GnssConfigurationInterface*)sGpsInterface->get_extension(
596                    GNSS_CONFIGURATION_INTERFACE);
597    }
598}
599
600static jboolean android_location_GnssLocationProvider_is_supported(
601        JNIEnv* /* env */, jclass /* clazz */)
602{
603    return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
604}
605
606static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
607        JNIEnv* /* env */, jclass /* clazz */)
608{
609    return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
610}
611
612static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
613        JNIEnv* /* env */, jclass /* jclazz */)
614{
615    return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
616}
617
618static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj)
619{
620    // this must be set before calling into the HAL library
621    if (!mCallbacksObj)
622        mCallbacksObj = env->NewGlobalRef(obj);
623
624    // fail if the main interface fails to initialize
625    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
626        return JNI_FALSE;
627
628    // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
629    // but continue to allow the rest of the GPS interface to work.
630    if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
631        sGpsXtraInterface = NULL;
632    if (sAGpsInterface)
633        sAGpsInterface->init(&sAGpsCallbacks);
634    if (sGpsNiInterface)
635        sGpsNiInterface->init(&sGpsNiCallbacks);
636    if (sAGpsRilInterface)
637        sAGpsRilInterface->init(&sAGpsRilCallbacks);
638    if (sGpsGeofencingInterface)
639        sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
640
641    return JNI_TRUE;
642}
643
644static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
645{
646    if (sGpsInterface)
647        sGpsInterface->cleanup();
648}
649
650static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
651        jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
652        jint preferred_time)
653{
654    if (sGpsInterface) {
655        if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
656                preferred_time) == 0) {
657            return JNI_TRUE;
658        } else {
659            return JNI_FALSE;
660        }
661    }
662    else
663        return JNI_FALSE;
664}
665
666static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
667{
668    if (sGpsInterface) {
669        if (sGpsInterface->start() == 0) {
670            return JNI_TRUE;
671        } else {
672            return JNI_FALSE;
673        }
674    }
675    else
676        return JNI_FALSE;
677}
678
679static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
680{
681    if (sGpsInterface) {
682        if (sGpsInterface->stop() == 0) {
683            return JNI_TRUE;
684        } else {
685            return JNI_FALSE;
686        }
687    }
688    else
689        return JNI_FALSE;
690}
691
692static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
693                                                                    jobject /* obj */,
694                                                                    jint flags)
695{
696    if (sGpsInterface)
697        sGpsInterface->delete_aiding_data(flags);
698}
699
700static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
701        jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray,
702        jfloatArray azumArray)
703{
704    // this should only be called from within a call to reportSvStatus
705    jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
706    jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
707    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
708    jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
709
710    // GNSS SV info.
711    for (size_t i = 0; i < sGnssSvListSize; ++i) {
712        const GnssSvInfo& info = sGnssSvList[i];
713        svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
714            (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
715            info.flags;
716        cn0s[i] = info.c_n0_dbhz;
717        elev[i] = info.elevation;
718        azim[i] = info.azimuth;
719    }
720
721    env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
722    env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
723    env->ReleaseFloatArrayElements(elevArray, elev, 0);
724    env->ReleaseFloatArrayElements(azumArray, azim, 0);
725    return (jint) sGnssSvListSize;
726}
727
728static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
729        JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
730{
731    AGpsRefLocation location;
732
733    if (!sAGpsRilInterface) {
734        ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
735        return;
736    }
737
738    switch(type) {
739        case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
740        case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
741            location.type = type;
742            location.u.cellID.mcc = mcc;
743            location.u.cellID.mnc = mnc;
744            location.u.cellID.lac = lac;
745            location.u.cellID.cid = cid;
746            break;
747        default:
748            ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
749            return;
750            break;
751    }
752    sAGpsRilInterface->set_ref_location(&location, sizeof(location));
753}
754
755static void android_location_GnssLocationProvider_agps_send_ni_message(JNIEnv* env,
756        jobject /* obj */, jbyteArray ni_msg, jint size)
757{
758    size_t sz;
759
760    if (!sAGpsRilInterface) {
761        ALOGE("no AGPS RIL interface in send_ni_message");
762        return;
763    }
764    if (size < 0)
765        return;
766    sz = (size_t)size;
767    jbyte* b = env->GetByteArrayElements(ni_msg, 0);
768    sAGpsRilInterface->ni_message((uint8_t *)b,sz);
769    env->ReleaseByteArrayElements(ni_msg,b,0);
770}
771
772static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
773                                                             jint type, jstring  setid_string)
774{
775    if (!sAGpsRilInterface) {
776        ALOGE("no AGPS RIL interface in agps_set_id");
777        return;
778    }
779
780    const char *setid = env->GetStringUTFChars(setid_string, NULL);
781    sAGpsRilInterface->set_set_id(type, setid);
782    env->ReleaseStringUTFChars(setid_string, setid);
783}
784
785static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
786                                            jbyteArray nmeaArray, jint buffer_size)
787{
788    // this should only be called from within a call to reportNmea
789    jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
790    int length = sNmeaStringLength;
791    if (length > buffer_size)
792        length = buffer_size;
793    memcpy(nmea, sNmeaString, length);
794    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
795    return (jint) length;
796}
797
798static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
799        jlong time, jlong timeReference, jint uncertainty)
800{
801    if (sGpsInterface)
802        sGpsInterface->inject_time(time, timeReference, uncertainty);
803}
804
805static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
806        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
807{
808    if (sGpsInterface)
809        sGpsInterface->inject_location(latitude, longitude, accuracy);
810}
811
812static jboolean android_location_GnssLocationProvider_supports_xtra(
813        JNIEnv* /* env */, jobject /* obj */)
814{
815    return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
816}
817
818static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
819        jbyteArray data, jint length)
820{
821    if (!sGpsXtraInterface) {
822        ALOGE("no XTRA interface in inject_xtra_data");
823        return;
824    }
825
826    jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
827    sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
828    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
829}
830
831static void android_location_GnssLocationProvider_agps_data_conn_open(
832        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
833{
834    if (!sAGpsInterface) {
835        ALOGE("no AGPS interface in agps_data_conn_open");
836        return;
837    }
838    if (apn == NULL) {
839        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
840        return;
841    }
842
843    const char *apnStr = env->GetStringUTFChars(apn, NULL);
844
845    size_t interface_size = sAGpsInterface->size;
846    if (interface_size == sizeof(AGpsInterface)) {
847        sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
848    } else if (interface_size == sizeof(AGpsInterface_v1)) {
849        sAGpsInterface->data_conn_open(apnStr);
850    } else {
851        ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size);
852    }
853
854    env->ReleaseStringUTFChars(apn, apnStr);
855}
856
857static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
858                                                                       jobject /* obj */)
859{
860    if (!sAGpsInterface) {
861        ALOGE("no AGPS interface in agps_data_conn_closed");
862        return;
863    }
864    sAGpsInterface->data_conn_closed();
865}
866
867static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
868                                                                       jobject /* obj */)
869{
870    if (!sAGpsInterface) {
871        ALOGE("no AGPS interface in agps_data_conn_failed");
872        return;
873    }
874    sAGpsInterface->data_conn_failed();
875}
876
877static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
878        jint type, jstring hostname, jint port)
879{
880    if (!sAGpsInterface) {
881        ALOGE("no AGPS interface in set_agps_server");
882        return;
883    }
884    const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
885    sAGpsInterface->set_server(type, c_hostname, port);
886    env->ReleaseStringUTFChars(hostname, c_hostname);
887}
888
889static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
890      jobject /* obj */, jint notifId, jint response)
891{
892    if (!sGpsNiInterface) {
893        ALOGE("no NI interface in send_ni_response");
894        return;
895    }
896
897    sGpsNiInterface->respond(notifId, response);
898}
899
900static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
901                                                                       jobject /* obj */) {
902    jstring result = NULL;
903    if (sGpsDebugInterface) {
904        const size_t maxLength = 2047;
905        char buffer[maxLength+1];
906        size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
907        if (length > maxLength) length = maxLength;
908        buffer[length] = 0;
909        result = env->NewStringUTF(buffer);
910    }
911    return result;
912}
913
914static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
915        jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
916{
917
918    if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
919        if (extraInfo) {
920            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
921            sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
922            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
923        } else {
924            sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
925        }
926
927        // update_network_availability callback was not included in original AGpsRilInterface
928        if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
929                && sAGpsRilInterface->update_network_availability) {
930            const char *c_apn = env->GetStringUTFChars(apn, NULL);
931            sAGpsRilInterface->update_network_availability(available, c_apn);
932            env->ReleaseStringUTFChars(apn, c_apn);
933        }
934    }
935}
936
937static jboolean android_location_GnssLocationProvider_is_geofence_supported(
938        JNIEnv* /* env */, jobject /* obj */)
939{
940    return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
941}
942
943static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */,
944        jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
945        jint last_transition, jint monitor_transition, jint notification_responsiveness,
946        jint unknown_timer) {
947    if (sGpsGeofencingInterface != NULL) {
948        sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
949                radius, last_transition, monitor_transition, notification_responsiveness,
950                unknown_timer);
951        return JNI_TRUE;
952    } else {
953        ALOGE("Geofence interface not available");
954    }
955    return JNI_FALSE;
956}
957
958static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */,
959        jobject /* obj */, jint geofence_id) {
960    if (sGpsGeofencingInterface != NULL) {
961        sGpsGeofencingInterface->remove_geofence_area(geofence_id);
962        return JNI_TRUE;
963    } else {
964        ALOGE("Geofence interface not available");
965    }
966    return JNI_FALSE;
967}
968
969static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */,
970        jobject /* obj */, jint geofence_id) {
971    if (sGpsGeofencingInterface != NULL) {
972        sGpsGeofencingInterface->pause_geofence(geofence_id);
973        return JNI_TRUE;
974    } else {
975        ALOGE("Geofence interface not available");
976    }
977    return JNI_FALSE;
978}
979
980static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */,
981        jobject /* obj */, jint geofence_id, jint monitor_transition) {
982    if (sGpsGeofencingInterface != NULL) {
983        sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
984        return JNI_TRUE;
985    } else {
986        ALOGE("Geofence interface not available");
987    }
988    return JNI_FALSE;
989}
990
991template<class T>
992class JavaMethodHelper {
993  public:
994   // Helper function to call setter on a Java object.
995   static void callJavaMethod(
996           JNIEnv* env,
997           jclass clazz,
998           jobject object,
999           const char* method_name,
1000           T value);
1001
1002  private:
1003    static const char *const signature_;
1004};
1005
1006template<class T>
1007void JavaMethodHelper<T>::callJavaMethod(
1008        JNIEnv* env,
1009        jclass clazz,
1010        jobject object,
1011        const char* method_name,
1012        T value) {
1013    jmethodID method = env->GetMethodID(clazz, method_name, signature_);
1014    env->CallVoidMethod(object, method, value);
1015}
1016
1017class JavaObject {
1018  public:
1019   JavaObject(JNIEnv* env, const char* class_name);
1020   virtual ~JavaObject();
1021
1022   template<class T>
1023   void callSetter(const char* method_name, T value);
1024   template<class T>
1025   void callSetter(const char* method_name, T* value, size_t size);
1026   jobject get();
1027
1028  private:
1029   JNIEnv* env_;
1030   jclass clazz_;
1031   jobject object_;
1032};
1033
1034JavaObject::JavaObject(JNIEnv* env, const char* class_name) : env_(env) {
1035    clazz_ = env_->FindClass(class_name);
1036    jmethodID ctor = env->GetMethodID(clazz_, "<init>", "()V");
1037    object_ = env_->NewObject(clazz_, ctor);
1038}
1039
1040JavaObject::~JavaObject() {
1041    env_->DeleteLocalRef(clazz_);
1042}
1043
1044template<class T>
1045void JavaObject::callSetter(const char* method_name, T value) {
1046    JavaMethodHelper<T>::callJavaMethod(
1047            env_, clazz_, object_, method_name, value);
1048}
1049
1050template<>
1051void JavaObject::callSetter(
1052        const char* method_name, uint8_t* value, size_t size) {
1053    jbyteArray array = env_->NewByteArray(size);
1054    env_->SetByteArrayRegion(array, 0, size, (jbyte*) value);
1055    jmethodID method = env_->GetMethodID(
1056            clazz_,
1057            method_name,
1058            "([B)V");
1059    env_->CallVoidMethod(object_, method, array);
1060}
1061
1062jobject JavaObject::get() {
1063    return object_;
1064}
1065
1066// Define Java method signatures for all known types.
1067
1068template<>
1069const char *const JavaMethodHelper<uint8_t>::signature_ = "(B)V";
1070template<>
1071const char *const JavaMethodHelper<int8_t>::signature_ = "(B)V";
1072template<>
1073const char *const JavaMethodHelper<int16_t>::signature_ = "(S)V";
1074template<>
1075const char *const JavaMethodHelper<uint16_t>::signature_ = "(S)V";
1076template<>
1077const char *const JavaMethodHelper<int32_t>::signature_ = "(I)V";
1078template<>
1079const char *const JavaMethodHelper<uint32_t>::signature_ = "(I)V";
1080template<>
1081const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V";
1082template<>
1083const char *const JavaMethodHelper<float>::signature_ = "(F)V";
1084template<>
1085const char *const JavaMethodHelper<double>::signature_ = "(D)V";
1086template<>
1087const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
1088
1089#define SET(setter, value) object.callSetter("set" # setter, (value))
1090
1091// If you want to check if a flag is not set, use SET_IF_NOT(FLAG, setter,
1092// value) to do that. SET_IF(!FLAG, setter, value) won't compile.
1093//
1094// This macros generates compilation error if the provided 'flag' is not a
1095// single token. For example, 'GNSS_CLOCK_HAS_BIAS' can be accepted, but
1096// '!GNSS_CLOCK_HAS_DRIFT' will fail to compile.
1097#define SET_IF(flag, setter, value) do { \
1098        if (flags & flag) { \
1099            JavaObject& name_check_##flag = object; \
1100            name_check_##flag.callSetter("set" # setter, (value)); \
1101        } \
1102    } while (false)
1103#define SET_IF_NOT(flag, setter, value) do { \
1104        if (!(flags & flag)) { \
1105            JavaObject& name_check_##flag = object; \
1106            name_check_##flag.callSetter("set" # setter, (value)); \
1107        } \
1108    } while (false)
1109
1110static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
1111    static uint32_t discontinuity_count_to_handle_old_clock_type = 0;
1112    JavaObject object(env, "android/location/GnssClock");
1113    GpsClockFlags flags = clock->flags;
1114
1115    SET_IF(GPS_CLOCK_HAS_LEAP_SECOND,
1116           LeapSecond,
1117           static_cast<int32_t>(clock->leap_second));
1118
1119    // GnssClock only supports the more effective HW_CLOCK type, so type
1120    // handling and documentation complexity has been removed.  To convert the
1121    // old GPS_CLOCK types (active only in a limited number of older devices),
1122    // the GPS time information is handled as an always discontinuous HW clock,
1123    // with the GPS time information put into the full_bias_ns instead - so that
1124    // time_ns - full_bias_ns = local estimate of GPS time. Additionally, the
1125    // sign of full_bias_ns and bias_ns has flipped between GpsClock &
1126    // GnssClock, so that is also handled below.
1127    switch (clock->type) {
1128      case GPS_CLOCK_TYPE_UNKNOWN:
1129        // Clock type unsupported.
1130        ALOGE("Unknown clock type provided.");
1131        break;
1132      case GPS_CLOCK_TYPE_LOCAL_HW_TIME:
1133        // Already local hardware time. No need to do anything.
1134        break;
1135      case GPS_CLOCK_TYPE_GPS_TIME:
1136        // GPS time, need to convert.
1137        flags |= GPS_CLOCK_HAS_FULL_BIAS;
1138        clock->full_bias_ns = clock->time_ns;
1139        clock->time_ns = 0;
1140        SET(HardwareClockDiscontinuityCount,
1141            discontinuity_count_to_handle_old_clock_type++);
1142        break;
1143    }
1144
1145    SET(TimeNanos, clock->time_ns);
1146    SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
1147           TimeUncertaintyNanos,
1148           clock->time_uncertainty_ns);
1149
1150    // Definition of sign for full_bias_ns & bias_ns has been changed since N,
1151    // so flip signs here.
1152    SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, -(clock->full_bias_ns));
1153    SET_IF(GPS_CLOCK_HAS_BIAS, BiasNanos, -(clock->bias_ns));
1154
1155    SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
1156           BiasUncertaintyNanos,
1157           clock->bias_uncertainty_ns);
1158    SET_IF(GPS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
1159    SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
1160           DriftUncertaintyNanosPerSecond,
1161           clock->drift_uncertainty_nsps);
1162
1163    return object.get();
1164}
1165
1166static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
1167    JavaObject object(env, "android/location/GnssClock");
1168    GnssClockFlags flags = clock->flags;
1169
1170    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
1171           LeapSecond,
1172           static_cast<int32_t>(clock->leap_second));
1173    SET(TimeNanos, clock->time_ns);
1174    SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
1175           TimeUncertaintyNanos,
1176           clock->time_uncertainty_ns);
1177    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
1178    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
1179    SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
1180           BiasUncertaintyNanos,
1181           clock->bias_uncertainty_ns);
1182    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
1183    SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
1184           DriftUncertaintyNanosPerSecond,
1185           clock->drift_uncertainty_nsps);
1186
1187    SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
1188
1189    return object.get();
1190}
1191
1192static jobject translate_gps_measurement(JNIEnv* env,
1193                                         GpsMeasurement* measurement) {
1194    JavaObject object(env, "android/location/GnssMeasurement");
1195    GpsMeasurementFlags flags = measurement->flags;
1196    SET(Svid, static_cast<int32_t>(measurement->prn));
1197    if (measurement->prn >= 1 && measurement->prn <= 32) {
1198        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
1199    } else {
1200        ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
1201        SET(ConstellationType,
1202            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
1203    }
1204    SET(TimeOffsetNanos, measurement->time_offset_ns);
1205    SET(State, static_cast<int32_t>(measurement->state));
1206    SET(ReceivedSvTimeNanos, measurement->received_gps_tow_ns);
1207    SET(ReceivedSvTimeUncertaintyNanos,
1208        measurement->received_gps_tow_uncertainty_ns);
1209    SET(Cn0DbHz, measurement->c_n0_dbhz);
1210    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
1211    SET(PseudorangeRateUncertaintyMetersPerSecond,
1212        measurement->pseudorange_rate_uncertainty_mps);
1213    SET(AccumulatedDeltaRangeState,
1214        static_cast<int32_t>(measurement->accumulated_delta_range_state));
1215    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
1216    SET(AccumulatedDeltaRangeUncertaintyMeters,
1217        measurement->accumulated_delta_range_uncertainty_m);
1218    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
1219           CarrierFrequencyHz,
1220           measurement->carrier_frequency_hz);
1221    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
1222           CarrierCycles,
1223           measurement->carrier_cycles);
1224    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
1225           CarrierPhase,
1226           measurement->carrier_phase);
1227    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
1228           CarrierPhaseUncertainty,
1229           measurement->carrier_phase_uncertainty);
1230    SET(MultipathIndicator,
1231        static_cast<int32_t>(measurement->multipath_indicator));
1232    SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
1233
1234    return object.get();
1235}
1236
1237static jobject translate_gnss_measurement(JNIEnv* env,
1238                                          GnssMeasurement* measurement) {
1239    JavaObject object(env, "android/location/GnssMeasurement");
1240
1241    GnssMeasurementFlags flags = measurement->flags;
1242
1243    SET(Svid, static_cast<int32_t>(measurement->svid));
1244    SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
1245    SET(TimeOffsetNanos, measurement->time_offset_ns);
1246    SET(State, static_cast<int32_t>(measurement->state));
1247    SET(ReceivedSvTimeNanos, measurement->received_sv_time_in_ns);
1248    SET(ReceivedSvTimeUncertaintyNanos,
1249        measurement->received_sv_time_uncertainty_in_ns);
1250    SET(Cn0DbHz, measurement->c_n0_dbhz);
1251    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
1252    SET(PseudorangeRateUncertaintyMetersPerSecond,
1253        measurement->pseudorange_rate_uncertainty_mps);
1254    SET(AccumulatedDeltaRangeState,
1255        static_cast<int32_t>(measurement->accumulated_delta_range_state));
1256    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
1257    SET(AccumulatedDeltaRangeUncertaintyMeters,
1258        measurement->accumulated_delta_range_uncertainty_m);
1259    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
1260           CarrierFrequencyHz,
1261           measurement->carrier_frequency_hz);
1262    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
1263           CarrierCycles,
1264           measurement->carrier_cycles);
1265    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
1266           CarrierPhase,
1267           measurement->carrier_phase);
1268    SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
1269           CarrierPhaseUncertainty,
1270           measurement->carrier_phase_uncertainty);
1271    SET(MultipathIndicator,
1272        static_cast<int32_t>(measurement->multipath_indicator));
1273    SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
1274
1275    return object.get();
1276}
1277
1278static jobjectArray translate_gps_measurements(JNIEnv* env,
1279                                               GpsMeasurement* measurements,
1280                                               size_t count) {
1281    if (count == 0) {
1282        return NULL;
1283    }
1284
1285    jclass gnssMeasurementClass = env->FindClass(
1286            "android/location/GnssMeasurement");
1287    jobjectArray gnssMeasurementArray = env->NewObjectArray(
1288            count,
1289            gnssMeasurementClass,
1290            NULL /* initialElement */);
1291
1292    for (uint16_t i = 0; i < count; ++i) {
1293        jobject gnssMeasurement = translate_gps_measurement(
1294            env,
1295            &measurements[i]);
1296        env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
1297        env->DeleteLocalRef(gnssMeasurement);
1298    }
1299
1300    env->DeleteLocalRef(gnssMeasurementClass);
1301    return gnssMeasurementArray;
1302}
1303
1304static jobjectArray translate_gnss_measurements(JNIEnv* env,
1305                                                GnssMeasurement* measurements,
1306                                                size_t count) {
1307    if (count == 0) {
1308        return NULL;
1309    }
1310
1311    jclass gnssMeasurementClass = env->FindClass(
1312            "android/location/GnssMeasurement");
1313    jobjectArray gnssMeasurementArray = env->NewObjectArray(
1314            count,
1315            gnssMeasurementClass,
1316            NULL /* initialElement */);
1317
1318    for (uint16_t i = 0; i < count; ++i) {
1319        jobject gnssMeasurement = translate_gnss_measurement(
1320            env,
1321            &measurements[i]);
1322        env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement);
1323        env->DeleteLocalRef(gnssMeasurement);
1324    }
1325
1326    env->DeleteLocalRef(gnssMeasurementClass);
1327    return gnssMeasurementArray;
1328}
1329
1330static void set_measurement_data(JNIEnv *env,
1331                                 jobject clock,
1332                                 jobjectArray measurementArray) {
1333    jclass gnssMeasurementsEventClass = env->FindClass(
1334            "android/location/GnssMeasurementsEvent");
1335    jmethodID gnssMeasurementsEventCtor = env->GetMethodID(
1336        gnssMeasurementsEventClass,
1337        "<init>",
1338        "(Landroid/location/GnssClock;[Landroid/location/GnssMeasurement;)V");
1339
1340    jobject gnssMeasurementsEvent = env->NewObject(
1341        gnssMeasurementsEventClass,
1342        gnssMeasurementsEventCtor,
1343        clock,
1344        measurementArray);
1345    env->CallVoidMethod(mCallbacksObj,
1346                        method_reportMeasurementData,
1347                        gnssMeasurementsEvent);
1348    checkAndClearExceptionFromCallback(env, __FUNCTION__);
1349    env->DeleteLocalRef(gnssMeasurementsEventClass);
1350    env->DeleteLocalRef(gnssMeasurementsEvent);
1351}
1352
1353static void measurement_callback(GpsData* data) {
1354    JNIEnv* env = AndroidRuntime::getJNIEnv();
1355    if (data == NULL) {
1356        ALOGE("Invalid data provided to gps_measurement_callback");
1357        return;
1358    }
1359    if (data->size != sizeof(GpsData)) {
1360        ALOGE("Invalid GpsData size found in gps_measurement_callback, "
1361              "size=%zd",
1362              data->size);
1363        return;
1364    }
1365
1366    jobject clock;
1367    jobjectArray measurementArray;
1368    clock = translate_gps_clock(env, &data->clock);
1369    measurementArray = translate_gps_measurements(
1370            env, data->measurements, data->measurement_count);
1371    set_measurement_data(env, clock, measurementArray);
1372
1373    env->DeleteLocalRef(clock);
1374    env->DeleteLocalRef(measurementArray);
1375}
1376
1377static void gnss_measurement_callback(GnssData* data) {
1378    JNIEnv* env = AndroidRuntime::getJNIEnv();
1379    if (data == NULL) {
1380        ALOGE("Invalid data provided to gps_measurement_callback");
1381        return;
1382    }
1383    if (data->size != sizeof(GnssData)) {
1384        ALOGE("Invalid GnssData size found in gnss_measurement_callback, "
1385              "size=%zd",
1386              data->size);
1387        return;
1388    }
1389
1390    jobject clock;
1391    jobjectArray measurementArray;
1392    clock = translate_gnss_clock(env, &data->clock);
1393    measurementArray = translate_gnss_measurements(
1394            env, data->measurements, data->measurement_count);
1395    set_measurement_data(env, clock, measurementArray);
1396
1397    env->DeleteLocalRef(clock);
1398    env->DeleteLocalRef(measurementArray);
1399}
1400
1401GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
1402    sizeof(GpsMeasurementCallbacks),
1403    measurement_callback,
1404    gnss_measurement_callback,
1405};
1406
1407static jboolean android_location_GnssLocationProvider_is_measurement_supported(
1408        JNIEnv* env,
1409        jclass clazz) {
1410    if (sGpsMeasurementInterface != NULL) {
1411        return JNI_TRUE;
1412    }
1413    return JNI_FALSE;
1414}
1415
1416static jboolean android_location_GnssLocationProvider_start_measurement_collection(
1417        JNIEnv* env,
1418        jobject obj) {
1419    if (sGpsMeasurementInterface == NULL) {
1420        ALOGE("Measurement interface is not available.");
1421        return JNI_FALSE;
1422    }
1423
1424    int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
1425    if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
1426        ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
1427        return JNI_FALSE;
1428    }
1429
1430    return JNI_TRUE;
1431}
1432
1433static jboolean android_location_GnssLocationProvider_stop_measurement_collection(
1434        JNIEnv* env,
1435        jobject obj) {
1436    if (sGpsMeasurementInterface == NULL) {
1437        ALOGE("Measurement interface not available");
1438        return JNI_FALSE;
1439    }
1440
1441    sGpsMeasurementInterface->close();
1442    return JNI_TRUE;
1443}
1444
1445static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
1446    size_t dataLength = message->data_length;
1447    uint8_t* data = message->data;
1448    if (dataLength == 0 || data == NULL) {
1449        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
1450        return NULL;
1451    }
1452    JavaObject object(env, "android/location/GnssNavigationMessage");
1453    SET(Svid, static_cast<int32_t>(message->prn));
1454    if (message->prn >=1 && message->prn <= 32) {
1455        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
1456        // Legacy driver doesn't set the higher byte to constellation type
1457        // correctly. Set the higher byte to 'GPS'.
1458        SET(Type, static_cast<int32_t>(message->type | 0x0100));
1459    } else {
1460        ALOGD("Unknown constellation type with Svid = %d.", message->prn);
1461        SET(ConstellationType,
1462            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
1463        SET(Type, static_cast<int32_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
1464    }
1465    SET(MessageId, static_cast<int32_t>(message->message_id));
1466    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
1467    object.callSetter("setData", data, dataLength);
1468    SET(Status, static_cast<int32_t>(message->status));
1469    return object.get();
1470}
1471
1472static jobject translate_gnss_navigation_message(
1473        JNIEnv* env, GnssNavigationMessage* message) {
1474    size_t dataLength = message->data_length;
1475    uint8_t* data = message->data;
1476    if (dataLength == 0 || data == NULL) {
1477        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
1478        return NULL;
1479    }
1480    JavaObject object(env, "android/location/GnssNavigationMessage");
1481    SET(Type, static_cast<int32_t>(message->type));
1482    SET(Svid, static_cast<int32_t>(message->svid));
1483    SET(MessageId, static_cast<int32_t>(message->message_id));
1484    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
1485    object.callSetter("setData", data, dataLength);
1486    SET(Status, static_cast<int32_t>(message->status));
1487    return object.get();
1488}
1489
1490static void navigation_message_callback(GpsNavigationMessage* message) {
1491    if (message == NULL) {
1492        ALOGE("Invalid Navigation Message provided to callback");
1493        return;
1494    }
1495    if (message->size != sizeof(GpsNavigationMessage)) {
1496        ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
1497        return;
1498    }
1499    JNIEnv* env = AndroidRuntime::getJNIEnv();
1500    jobject navigationMessage = translate_gps_navigation_message(env, message);
1501    env->CallVoidMethod(mCallbacksObj,
1502                        method_reportNavigationMessages,
1503                        navigationMessage);
1504    env->DeleteLocalRef(navigationMessage);
1505}
1506
1507static void gnss_navigation_message_callback(GnssNavigationMessage* message) {
1508    if (message == NULL) {
1509        ALOGE("Invalid Navigation Message provided to callback");
1510        return;
1511    }
1512    if (message->size != sizeof(GnssNavigationMessage)) {
1513        ALOGE("Invalid GnssNavigationMessage size found: %zd", message->size);
1514        return;
1515    }
1516    JNIEnv* env = AndroidRuntime::getJNIEnv();
1517    jobject navigationMessage = translate_gnss_navigation_message(env, message);
1518    env->CallVoidMethod(mCallbacksObj,
1519                        method_reportNavigationMessages,
1520                        navigationMessage);
1521    env->DeleteLocalRef(navigationMessage);
1522}
1523
1524GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
1525    sizeof(GpsNavigationMessageCallbacks),
1526    navigation_message_callback,
1527    gnss_navigation_message_callback,
1528};
1529
1530static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
1531        JNIEnv* env,
1532        jclass clazz) {
1533    if(sGpsNavigationMessageInterface != NULL) {
1534        return JNI_TRUE;
1535    }
1536    return JNI_FALSE;
1537}
1538
1539static jboolean android_location_GnssLocationProvider_start_navigation_message_collection(
1540        JNIEnv* env,
1541        jobject obj) {
1542    if (sGpsNavigationMessageInterface == NULL) {
1543        ALOGE("Navigation Message interface is not available.");
1544        return JNI_FALSE;
1545    }
1546
1547    int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
1548    if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
1549        ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
1550        return JNI_FALSE;
1551    }
1552
1553    return JNI_TRUE;
1554}
1555
1556static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection(
1557        JNIEnv* env,
1558        jobject obj) {
1559    if (sGpsNavigationMessageInterface == NULL) {
1560        ALOGE("Navigation Message interface is not available.");
1561        return JNI_FALSE;
1562    }
1563
1564    sGpsNavigationMessageInterface->close();
1565    return JNI_TRUE;
1566}
1567
1568static void android_location_GnssLocationProvider_configuration_update(JNIEnv* env, jobject obj,
1569        jstring config_content)
1570{
1571    if (!sGnssConfigurationInterface) {
1572        ALOGE("no GPS configuration interface in configuraiton_update");
1573        return;
1574    }
1575    const char *data = env->GetStringUTFChars(config_content, NULL);
1576    ALOGD("GPS configuration:\n %s", data);
1577    sGnssConfigurationInterface->configuration_update(
1578            data, env->GetStringUTFLength(config_content));
1579    env->ReleaseStringUTFChars(config_content, data);
1580}
1581
1582static const JNINativeMethod sMethods[] = {
1583     /* name, signature, funcPtr */
1584    {"class_init_native", "()V", (void *)android_location_GnssLocationProvider_class_init_native},
1585    {"native_is_supported", "()Z", (void*)android_location_GnssLocationProvider_is_supported},
1586    {"native_is_agps_ril_supported", "()Z",
1587            (void*)android_location_GnssLocationProvider_is_agps_ril_supported},
1588    {"native_is_gnss_configuration_supported", "()Z",
1589            (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
1590    {"native_init", "()Z", (void*)android_location_GnssLocationProvider_init},
1591    {"native_cleanup", "()V", (void*)android_location_GnssLocationProvider_cleanup},
1592    {"native_set_position_mode",
1593            "(IIIII)Z",
1594            (void*)android_location_GnssLocationProvider_set_position_mode},
1595    {"native_start", "()Z", (void*)android_location_GnssLocationProvider_start},
1596    {"native_stop", "()Z", (void*)android_location_GnssLocationProvider_stop},
1597    {"native_delete_aiding_data",
1598            "(I)V",
1599            (void*)android_location_GnssLocationProvider_delete_aiding_data},
1600    {"native_read_sv_status",
1601            "([I[F[F[F)I",
1602            (void*)android_location_GnssLocationProvider_read_sv_status},
1603    {"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
1604    {"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
1605    {"native_inject_location",
1606            "(DDF)V",
1607            (void*)android_location_GnssLocationProvider_inject_location},
1608    {"native_supports_xtra", "()Z", (void*)android_location_GnssLocationProvider_supports_xtra},
1609    {"native_inject_xtra_data",
1610            "([BI)V",
1611            (void*)android_location_GnssLocationProvider_inject_xtra_data},
1612    {"native_agps_data_conn_open",
1613            "(Ljava/lang/String;I)V",
1614            (void*)android_location_GnssLocationProvider_agps_data_conn_open},
1615    {"native_agps_data_conn_closed",
1616            "()V",
1617            (void*)android_location_GnssLocationProvider_agps_data_conn_closed},
1618    {"native_agps_data_conn_failed",
1619            "()V",
1620            (void*)android_location_GnssLocationProvider_agps_data_conn_failed},
1621    {"native_agps_set_id",
1622            "(ILjava/lang/String;)V",
1623            (void*)android_location_GnssLocationProvider_agps_set_id},
1624    {"native_agps_set_ref_location_cellid",
1625            "(IIIII)V",
1626            (void*)android_location_GnssLocationProvider_agps_set_reference_location_cellid},
1627    {"native_set_agps_server",
1628            "(ILjava/lang/String;I)V",
1629            (void*)android_location_GnssLocationProvider_set_agps_server},
1630    {"native_send_ni_response",
1631            "(II)V",
1632            (void*)android_location_GnssLocationProvider_send_ni_response},
1633    {"native_agps_ni_message",
1634            "([BI)V",
1635            (void *)android_location_GnssLocationProvider_agps_send_ni_message},
1636    {"native_get_internal_state",
1637            "()Ljava/lang/String;",
1638            (void*)android_location_GnssLocationProvider_get_internal_state},
1639    {"native_update_network_state",
1640            "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
1641            (void*)android_location_GnssLocationProvider_update_network_state },
1642    {"native_is_geofence_supported",
1643            "()Z",
1644            (void*) android_location_GnssLocationProvider_is_geofence_supported},
1645    {"native_add_geofence",
1646            "(IDDDIIII)Z",
1647            (void *)android_location_GnssLocationProvider_add_geofence},
1648    {"native_remove_geofence",
1649            "(I)Z",
1650            (void *)android_location_GnssLocationProvider_remove_geofence},
1651    {"native_pause_geofence", "(I)Z", (void *)android_location_GnssLocationProvider_pause_geofence},
1652    {"native_resume_geofence",
1653            "(II)Z",
1654            (void *)android_location_GnssLocationProvider_resume_geofence},
1655    {"native_is_measurement_supported",
1656            "()Z",
1657            (void*) android_location_GnssLocationProvider_is_measurement_supported},
1658    {"native_start_measurement_collection",
1659            "()Z",
1660            (void*) android_location_GnssLocationProvider_start_measurement_collection},
1661    {"native_stop_measurement_collection",
1662            "()Z",
1663            (void*) android_location_GnssLocationProvider_stop_measurement_collection},
1664    {"native_is_navigation_message_supported",
1665            "()Z",
1666            (void*) android_location_GnssLocationProvider_is_navigation_message_supported},
1667    {"native_start_navigation_message_collection",
1668            "()Z",
1669            (void*) android_location_GnssLocationProvider_start_navigation_message_collection},
1670    {"native_stop_navigation_message_collection",
1671            "()Z",
1672            (void*) android_location_GnssLocationProvider_stop_navigation_message_collection},
1673    {"native_configuration_update",
1674            "(Ljava/lang/String;)V",
1675            (void*)android_location_GnssLocationProvider_configuration_update},
1676};
1677
1678int register_android_server_location_GnssLocationProvider(JNIEnv* env)
1679{
1680    return jniRegisterNativeMethods(
1681            env,
1682            "com/android/server/location/GnssLocationProvider",
1683            sMethods,
1684            NELEM(sMethods));
1685}
1686
1687} /* namespace android */
1688