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