• 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 <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