blob: 60eed8e6d7165ebc30f8e68c47ac015e00aeab60 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "GnssCallbackJni"
#include "GnssCallback.h"
#include <hardware_legacy/power.h>
#define WAKE_LOCK_NAME "GPS"
namespace android::gnss {
using android::hardware::gnss::V1_0::GnssLocationFlags;
using binder::Status;
using hardware::hidl_vec;
using hardware::Return;
using hardware::Void;
using GnssLocationAidl = android::hardware::gnss::GnssLocation;
using GnssSignalType = android::hardware::gnss::GnssSignalType;
using GnssLocation_V1_0 = android::hardware::gnss::V1_0::GnssLocation;
using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation;
using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
jmethodID method_reportGnssServiceDied;
namespace {
jclass class_arrayList;
jclass class_gnssSignalType;
jmethodID method_arrayListAdd;
jmethodID method_arrayListCtor;
jmethodID method_gnssSignalTypeCreate;
jmethodID method_reportLocation;
jmethodID method_reportStatus;
jmethodID method_reportSvStatus;
jmethodID method_reportNmea;
jmethodID method_setTopHalCapabilities;
jmethodID method_setSignalTypeCapabilities;
jmethodID method_setGnssYearOfHardware;
jmethodID method_setGnssHardwareModelName;
jmethodID method_requestLocation;
jmethodID method_requestUtcTime;
// Returns true if location has lat/long information.
inline bool hasLatLong(const GnssLocationAidl& location) {
return (location.gnssLocationFlags & hardware::gnss::GnssLocation::HAS_LAT_LONG) != 0;
}
// Returns true if location has lat/long information.
inline bool hasLatLong(const GnssLocation_V1_0& location) {
return (static_cast<uint32_t>(location.gnssLocationFlags) & GnssLocationFlags::HAS_LAT_LONG) !=
0;
}
// Returns true if location has lat/long information.
inline bool hasLatLong(const GnssLocation_V2_0& location) {
return hasLatLong(location.v1_0);
}
inline jboolean boolToJbool(bool value) {
return value ? JNI_TRUE : JNI_FALSE;
}
// Must match the value from GnssMeasurement.java
const uint32_t SVID_FLAGS_HAS_BASEBAND_CN0 = (1 << 4);
} // anonymous namespace
bool isSvStatusRegistered = false;
bool isNmeaRegistered = false;
void Gnss_class_init_once(JNIEnv* env, jclass& clazz) {
method_reportLocation =
env->GetMethodID(clazz, "reportLocation", "(ZLandroid/location/Location;)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(IZ)V");
method_setSignalTypeCapabilities =
env->GetMethodID(clazz, "setSignalTypeCapabilities", "(Ljava/util/List;)V");
method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
method_setGnssHardwareModelName =
env->GetMethodID(clazz, "setGnssHardwareModelName", "(Ljava/lang/String;)V");
method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(ZZ)V");
method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
jclass arrayListClass = env->FindClass("java/util/ArrayList");
class_arrayList = (jclass)env->NewGlobalRef(arrayListClass);
method_arrayListCtor = env->GetMethodID(class_arrayList, "<init>", "()V");
method_arrayListAdd = env->GetMethodID(class_arrayList, "add", "(Ljava/lang/Object;)Z");
jclass gnssSignalTypeClass = env->FindClass("android/location/GnssSignalType");
class_gnssSignalType = (jclass)env->NewGlobalRef(gnssSignalTypeClass);
method_gnssSignalTypeCreate =
env->GetStaticMethodID(class_gnssSignalType, "create",
"(IDLjava/lang/String;)Landroid/location/GnssSignalType;");
}
Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
ALOGD("%s: %du\n", __func__, capabilities);
bool isAdrCapabilityKnown = (getInterfaceVersion() >= 3) ? true : false;
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities,
isAdrCapabilityKnown);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Status::ok();
}
namespace {
jobject translateSingleSignalType(JNIEnv* env, const GnssSignalType& signalType) {
jstring jstringCodeType = env->NewStringUTF(signalType.codeType.c_str());
jobject signalTypeObject =
env->CallStaticObjectMethod(class_gnssSignalType, method_gnssSignalTypeCreate,
signalType.constellation, signalType.carrierFrequencyHz,
jstringCodeType);
env->DeleteLocalRef(jstringCodeType);
return signalTypeObject;
}
} // anonymous namespace
Status GnssCallbackAidl::gnssSetSignalTypeCapabilitiesCb(
const std::vector<GnssSignalType>& signalTypes) {
ALOGD("%s: %d signal types", __func__, (int)signalTypes.size());
JNIEnv* env = getJniEnv();
jobject arrayList = env->NewObject(class_arrayList, method_arrayListCtor);
for (auto& signalType : signalTypes) {
jobject signalTypeObject = translateSingleSignalType(env, signalType);
env->CallBooleanMethod(arrayList, method_arrayListAdd, signalTypeObject);
// Delete Local Refs
env->DeleteLocalRef(signalTypeObject);
}
env->CallVoidMethod(mCallbacksObj, method_setSignalTypeCapabilities, arrayList);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(arrayList);
return Status::ok();
}
Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Status::ok();
}
Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
GnssCallbackHidl::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
return Status::ok();
}
Status GnssCallbackAidl::gnssLocationCb(const hardware::gnss::GnssLocation& location) {
GnssCallbackHidl::gnssLocationCbImpl<hardware::gnss::GnssLocation>(location);
return Status::ok();
}
Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
// In AIDL v1, if no listener is registered, do not report nmea to the framework.
if (getInterfaceVersion() <= 1) {
if (!isNmeaRegistered) {
return Status::ok();
}
}
JNIEnv* env = getJniEnv();
/*
* The Java code will call back to read these values.
* We do this to avoid creating unnecessary String objects.
*/
GnssCallbackHidl::sNmeaString = nmea.c_str();
GnssCallbackHidl::sNmeaStringLength = nmea.size();
env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Status::ok();
}
Status GnssCallbackAidl::gnssAcquireWakelockCb() {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
return Status::ok();
}
Status GnssCallbackAidl::gnssReleaseWakelockCb() {
release_wake_lock(WAKE_LOCK_NAME);
return Status::ok();
}
Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
jstring jstringName = env->NewStringUTF(info.name.c_str());
env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
if (jstringName) {
env->DeleteLocalRef(jstringName);
}
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Status::ok();
}
Status GnssCallbackAidl::gnssRequestTimeCb() {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Status::ok();
}
Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
const bool isUserEmergency) {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
boolToJbool(isUserEmergency));
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Status::ok();
}
// Implementation of IGnssCallbackHidl
Return<void> GnssCallbackHidl::gnssNameCb(const android::hardware::hidl_string& name) {
ALOGD("%s: name=%s\n", __func__, name.c_str());
JNIEnv* env = getJniEnv();
jstring jstringName = env->NewStringUTF(name.c_str());
env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
if (jstringName) {
env->DeleteLocalRef(jstringName);
}
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
const char* GnssCallbackHidl::sNmeaString = nullptr;
size_t GnssCallbackHidl::sNmeaStringLength = 0;
template <class T>
Return<void> GnssCallbackHidl::gnssLocationCbImpl(const T& location) {
JNIEnv* env = getJniEnv();
jobject jLocation = translateGnssLocation(env, location);
env->CallVoidMethod(mCallbacksObj, method_reportLocation, boolToJbool(hasLatLong(location)),
jLocation);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(jLocation);
return Void();
}
Return<void> GnssCallbackHidl::gnssLocationCb(const GnssLocation_V1_0& location) {
return gnssLocationCbImpl<GnssLocation_V1_0>(location);
}
Return<void> GnssCallbackHidl::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
return gnssLocationCbImpl<GnssLocation_V2_0>(location);
}
Return<void> GnssCallbackHidl::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
template <>
uint32_t GnssCallbackHidl::getHasBasebandCn0DbHzFlag(
const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svStatus) {
return SVID_FLAGS_HAS_BASEBAND_CN0;
}
template <>
uint32_t GnssCallbackHidl::getHasBasebandCn0DbHzFlag(
const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
return SVID_FLAGS_HAS_BASEBAND_CN0;
}
template <>
double GnssCallbackHidl::getBasebandCn0DbHz(
const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
return svInfoList[i].basebandCN0DbHz;
}
template <>
double GnssCallbackHidl::getBasebandCn0DbHz(
const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
return svInfoList[i].basebandCN0DbHz;
}
template <>
uint32_t GnssCallbackHidl::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
return svStatus.numSvs;
}
template <>
uint32_t GnssCallbackHidl::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
size_t i) {
return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
}
template <>
uint32_t GnssCallbackHidl::getConstellationType(
const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
}
template <class T_list, class T_sv_info>
Return<void> GnssCallbackHidl::gnssSvStatusCbImpl(const T_list& svStatus) {
// In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
if (!isSvStatusRegistered) {
return Void();
}
JNIEnv* env = getJniEnv();
uint32_t listSize = getGnssSvInfoListSize(svStatus);
jintArray svidWithFlagArray = env->NewIntArray(listSize);
jfloatArray cn0Array = env->NewFloatArray(listSize);
jfloatArray elevArray = env->NewFloatArray(listSize);
jfloatArray azimArray = env->NewFloatArray(listSize);
jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
/*
* Read GNSS SV info.
*/
for (size_t i = 0; i < listSize; ++i) {
enum ShiftWidth : uint8_t { SVID_SHIFT_WIDTH = 12, CONSTELLATION_TYPE_SHIFT_WIDTH = 8 };
const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
(getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
static_cast<uint32_t>(info.svFlag);
cn0s[i] = info.cN0Dbhz;
elev[i] = info.elevationDegrees;
azim[i] = info.azimuthDegrees;
carrierFreq[i] = info.carrierFrequencyHz;
svidWithFlags[i] |= getHasBasebandCn0DbHzFlag(svStatus);
basebandCn0s[i] = getBasebandCn0DbHz(svStatus, i);
}
env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
env->ReleaseFloatArrayElements(elevArray, elev, 0);
env->ReleaseFloatArrayElements(azimArray, azim, 0);
env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
env->CallVoidMethod(mCallbacksObj, method_reportSvStatus, static_cast<jint>(listSize),
svidWithFlagArray, cn0Array, elevArray, azimArray, carrierFreqArray,
basebandCn0Array);
env->DeleteLocalRef(svidWithFlagArray);
env->DeleteLocalRef(cn0Array);
env->DeleteLocalRef(elevArray);
env->DeleteLocalRef(azimArray);
env->DeleteLocalRef(carrierFreqArray);
env->DeleteLocalRef(basebandCn0Array);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
Return<void> GnssCallbackHidl::gnssNmeaCb(int64_t timestamp,
const ::android::hardware::hidl_string& nmea) {
// In HIDL, if no listener is registered, do not report nmea to the framework.
if (!isNmeaRegistered) {
return Void();
}
JNIEnv* env = getJniEnv();
/*
* The Java code will call back to read these values.
* We do this to avoid creating unnecessary String objects.
*/
sNmeaString = nmea.c_str();
sNmeaStringLength = nmea.size();
env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
Return<void> GnssCallbackHidl::gnssSetCapabilitesCb(uint32_t capabilities) {
ALOGD("%s: %du\n", __func__, capabilities);
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities,
/* isAdrCapabilityKnown= */ false);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
Return<void> GnssCallbackHidl::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
return GnssCallbackHidl::gnssSetCapabilitesCb(capabilities);
}
Return<void> GnssCallbackHidl::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
return GnssCallbackHidl::gnssSetCapabilitesCb(capabilities);
}
Return<void> GnssCallbackHidl::gnssAcquireWakelockCb() {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
return Void();
}
Return<void> GnssCallbackHidl::gnssReleaseWakelockCb() {
release_wake_lock(WAKE_LOCK_NAME);
return Void();
}
Return<void> GnssCallbackHidl::gnssRequestTimeCb() {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
Return<void> GnssCallbackHidl::gnssRequestLocationCb(const bool independentFromGnss) {
return GnssCallbackHidl::gnssRequestLocationCb_2_0(independentFromGnss, /* isUserEmergency= */
false);
}
Return<void> GnssCallbackHidl::gnssRequestLocationCb_2_0(const bool independentFromGnss,
const bool isUserEmergency) {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
boolToJbool(isUserEmergency));
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
Return<void> GnssCallbackHidl::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
} // namespace android::gnss