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