• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 "GnssUtilsJni"
18 
19 #include "Utils.h"
20 
21 #include <android/hardware/gnss/1.0/IGnss.h>
22 #include <android/hardware/gnss/2.0/IGnss.h>
23 #include <android_location_flags.h>
24 #include <utils/SystemClock.h>
25 /*
26  * Save a pointer to JavaVm to attach/detach threads executing
27  * callback methods that need to make JNI calls.
28  */
29 JavaVM* android::ScopedJniThreadAttach::sJvm;
30 
31 namespace location_flags = android::location::flags;
32 
33 namespace android {
34 
35 namespace {
36 
37 thread_local std::unique_ptr<ScopedJniThreadAttach> tJniThreadAttacher;
38 jmethodID method_locationCtor;
39 
40 } // anonymous namespace
41 
42 jclass class_location;
43 
44 namespace gnss {
Utils_class_init_once(JNIEnv * env)45 void Utils_class_init_once(JNIEnv* env) {
46     jclass locationClass = env->FindClass("android/location/Location");
47     class_location = (jclass)env->NewGlobalRef(locationClass);
48     method_locationCtor = env->GetMethodID(class_location, "<init>", "(Ljava/lang/String;)V");
49 }
50 } // namespace gnss
51 
52 jobject mCallbacksObj = nullptr;
53 
getCallbacksObj()54 jobject& getCallbacksObj() {
55     return mCallbacksObj;
56 }
57 
58 using GnssLocation_V1_0 = android::hardware::gnss::V1_0::GnssLocation;
59 using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation;
60 
61 // Define Java method signatures for all known types.
62 template <>
63 const char* const JavaMethodHelper<uint8_t>::signature_ = "(B)V";
64 template <>
65 const char* const JavaMethodHelper<int8_t>::signature_ = "(B)V";
66 template <>
67 const char* const JavaMethodHelper<int16_t>::signature_ = "(S)V";
68 template <>
69 const char* const JavaMethodHelper<uint16_t>::signature_ = "(S)V";
70 template <>
71 const char* const JavaMethodHelper<int32_t>::signature_ = "(I)V";
72 template <>
73 const char* const JavaMethodHelper<uint32_t>::signature_ = "(I)V";
74 template <>
75 const char* const JavaMethodHelper<int64_t>::signature_ = "(J)V";
76 template <>
77 const char* const JavaMethodHelper<uint64_t>::signature_ = "(J)V";
78 template <>
79 const char* const JavaMethodHelper<float>::signature_ = "(F)V";
80 template <>
81 const char* const JavaMethodHelper<double>::signature_ = "(D)V";
82 template <>
83 const char* const JavaMethodHelper<bool>::signature_ = "(Z)V";
84 template <>
85 const char* const JavaMethodHelper<jstring>::signature_ = "(Ljava/lang/String;)V";
86 template <>
87 const char* const JavaMethodHelper<jdoubleArray>::signature_ = "([D)V";
88 
checkAidlStatus(const android::binder::Status & status,const char * errorMessage)89 jboolean checkAidlStatus(const android::binder::Status& status, const char* errorMessage) {
90     if (!status.isOk()) {
91         ALOGE("%s AIDL transport error: %s", errorMessage, status.toString8().c_str());
92         return JNI_FALSE;
93     }
94     return JNI_TRUE;
95 }
96 
checkHidlReturn(hardware::Return<bool> & result,const char * errorMessage)97 jboolean checkHidlReturn(hardware::Return<bool>& result, const char* errorMessage) {
98     if (!result.isOk()) {
99         logHidlError(result, errorMessage);
100         return JNI_FALSE;
101     } else if (!result) {
102         ALOGE("%s", errorMessage);
103         return JNI_FALSE;
104     } else {
105         return JNI_TRUE;
106     }
107 }
108 
checkAndClearExceptionFromCallback(JNIEnv * env,const char * methodName)109 void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
110     if (env->ExceptionCheck()) {
111         ALOGE("An exception was thrown by callback '%s'.", methodName);
112         LOGE_EX(env);
113         env->ExceptionClear();
114     }
115 }
116 
callObjectMethodIgnoringResult(JNIEnv * env,jobject obj,jmethodID mid,...)117 void callObjectMethodIgnoringResult(JNIEnv* env, jobject obj, jmethodID mid, ...) {
118     va_list args;
119     va_start(args, mid);
120     env->DeleteLocalRef(env->CallObjectMethodV(obj, mid, args));
121     va_end(args);
122 }
123 
JavaObject(JNIEnv * env,jclass clazz,jmethodID defaultCtor)124 JavaObject::JavaObject(JNIEnv* env, jclass clazz, jmethodID defaultCtor)
125       : env_(env), clazz_(clazz) {
126     object_ = env_->NewObject(clazz_, defaultCtor);
127 }
128 
JavaObject(JNIEnv * env,jclass clazz,jmethodID stringCtor,const char * sz_arg_1)129 JavaObject::JavaObject(JNIEnv* env, jclass clazz, jmethodID stringCtor, const char* sz_arg_1)
130       : env_(env), clazz_(clazz) {
131     jstring szArg = env->NewStringUTF(sz_arg_1);
132     object_ = env_->NewObject(clazz_, stringCtor, szArg);
133     if (szArg) {
134         env_->DeleteLocalRef(szArg);
135     }
136 }
137 
JavaObject(JNIEnv * env,jclass clazz,jobject object)138 JavaObject::JavaObject(JNIEnv* env, jclass clazz, jobject object)
139       : env_(env), clazz_(clazz), object_(object) {}
140 
141 template <>
callSetter(const char * method_name,uint8_t * value,size_t size)142 void JavaObject::callSetter(const char* method_name, uint8_t* value, size_t size) {
143     jbyteArray array = env_->NewByteArray(size);
144     env_->SetByteArrayRegion(array, 0, size, reinterpret_cast<jbyte*>(value));
145     jmethodID method = env_->GetMethodID(clazz_, method_name, "([B)V");
146     env_->CallVoidMethod(object_, method, array);
147     env_->DeleteLocalRef(array);
148 }
149 
getJniEnv()150 JNIEnv* getJniEnv() {
151     JNIEnv* env = AndroidRuntime::getJNIEnv();
152 
153     /*
154      * If env is nullptr, the thread is not already attached to
155      * JNI. It is attached below and the destructor for ScopedJniThreadAttach
156      * will detach it on thread exit.
157      */
158     if (env == nullptr) {
159         tJniThreadAttacher.reset(new ScopedJniThreadAttach());
160         env = tJniThreadAttacher->getEnv();
161     }
162 
163     return env;
164 }
165 
166 template <>
translateGnssLocation(JNIEnv * env,const android::hardware::gnss::GnssLocation & location)167 jobject translateGnssLocation(JNIEnv* env, const android::hardware::gnss::GnssLocation& location) {
168     JavaObject object(env, class_location, method_locationCtor, "gps");
169 
170     uint32_t flags = static_cast<uint32_t>(location.gnssLocationFlags);
171     if (flags & android::hardware::gnss::GnssLocation::HAS_LAT_LONG) {
172         SET(Latitude, location.latitudeDegrees);
173         SET(Longitude, location.longitudeDegrees);
174     }
175     if (flags & android::hardware::gnss::GnssLocation::HAS_ALTITUDE) {
176         SET(Altitude, location.altitudeMeters);
177     }
178     if (flags & android::hardware::gnss::GnssLocation::HAS_SPEED) {
179         SET(Speed, (float)location.speedMetersPerSec);
180     }
181     if (flags & android::hardware::gnss::GnssLocation::HAS_BEARING) {
182         SET(Bearing, (float)location.bearingDegrees);
183     }
184     if (flags & android::hardware::gnss::GnssLocation::HAS_HORIZONTAL_ACCURACY) {
185         SET(Accuracy, (float)location.horizontalAccuracyMeters);
186     }
187     if (flags & android::hardware::gnss::GnssLocation::HAS_VERTICAL_ACCURACY) {
188         SET(VerticalAccuracyMeters, (float)location.verticalAccuracyMeters);
189     }
190     if (flags & android::hardware::gnss::GnssLocation::HAS_SPEED_ACCURACY) {
191         SET(SpeedAccuracyMetersPerSecond, (float)location.speedAccuracyMetersPerSecond);
192     }
193     if (flags & android::hardware::gnss::GnssLocation::HAS_BEARING_ACCURACY) {
194         SET(BearingAccuracyDegrees, (float)location.bearingAccuracyDegrees);
195     }
196     SET(Time, location.timestampMillis);
197 
198     flags = static_cast<uint32_t>(location.elapsedRealtime.flags);
199     if (flags & android::hardware::gnss::ElapsedRealtime::HAS_TIMESTAMP_NS) {
200         if (location_flags::replace_future_elapsed_realtime_jni() &&
201             location.elapsedRealtime.timestampNs > android::elapsedRealtimeNano()) {
202             SET(ElapsedRealtimeNanos, android::elapsedRealtimeNano());
203         } else {
204             SET(ElapsedRealtimeNanos, location.elapsedRealtime.timestampNs);
205         }
206     } else {
207         SET(ElapsedRealtimeNanos, android::elapsedRealtimeNano());
208     }
209     if (flags & android::hardware::gnss::ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS) {
210         SET(ElapsedRealtimeUncertaintyNanos,
211             static_cast<double>(location.elapsedRealtime.timeUncertaintyNs));
212     }
213 
214     return object.get();
215 }
216 
217 template <>
translateGnssLocation(JNIEnv * env,const GnssLocation_V1_0 & location)218 jobject translateGnssLocation(JNIEnv* env, const GnssLocation_V1_0& location) {
219     JavaObject object(env, class_location, method_locationCtor, "gps");
220 
221     uint16_t flags = static_cast<uint16_t>(location.gnssLocationFlags);
222     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_LAT_LONG) {
223         SET(Latitude, location.latitudeDegrees);
224         SET(Longitude, location.longitudeDegrees);
225     }
226     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_ALTITUDE) {
227         SET(Altitude, location.altitudeMeters);
228     }
229     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED) {
230         SET(Speed, location.speedMetersPerSec);
231     }
232     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING) {
233         SET(Bearing, location.bearingDegrees);
234     }
235     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
236         SET(Accuracy, location.horizontalAccuracyMeters);
237     }
238     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
239         SET(VerticalAccuracyMeters, location.verticalAccuracyMeters);
240     }
241     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_SPEED_ACCURACY) {
242         SET(SpeedAccuracyMetersPerSecond, location.speedAccuracyMetersPerSecond);
243     }
244     if (flags & android::hardware::gnss::V1_0::GnssLocationFlags::HAS_BEARING_ACCURACY) {
245         SET(BearingAccuracyDegrees, location.bearingAccuracyDegrees);
246     }
247     SET(Time, location.timestamp);
248     SET(ElapsedRealtimeNanos, android::elapsedRealtimeNano());
249 
250     return object.get();
251 }
252 
253 template <>
translateGnssLocation(JNIEnv * env,const GnssLocation_V2_0 & location)254 jobject translateGnssLocation(JNIEnv* env, const GnssLocation_V2_0& location) {
255     JavaObject object(env, class_location, translateGnssLocation(env, location.v1_0));
256 
257     const uint16_t flags = static_cast<uint16_t>(location.elapsedRealtime.flags);
258 
259     // Overwrite ElapsedRealtimeNanos when available from HAL.
260     if (flags & android::hardware::gnss::V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) {
261         SET(ElapsedRealtimeNanos, location.elapsedRealtime.timestampNs);
262     }
263 
264     if (flags & android::hardware::gnss::V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) {
265         SET(ElapsedRealtimeUncertaintyNanos,
266             static_cast<double>(location.elapsedRealtime.timeUncertaintyNs));
267     }
268 
269     return object.get();
270 }
271 
272 } // namespace android
273