From 86450fa579d2d1073b234b8314a0dc4dff7e2fb4 Mon Sep 17 00:00:00 2001 From: Anil Admal Date: Mon, 11 Mar 2019 15:31:05 -0700 Subject: [PATCH] Add new GNSS capabilities for year of hardware deprecation (HAL) The following capabilities need to be added to the GNSS HAL interface to enforce support through the CTS/VTS tests. -Add low power mode capability. -Add satellite blacklisting capability. -Add measurement corrections capability and move capabilities in IGnssCallback.hal that are specific to measurement correctons to its own sub-HAL measurement_corrections@1.0. Bug: 128028791 Bug: 127434062 Bug: 128309220 Test: Tested on cuttlefish using default implementation and VTS tests Change-Id: I60dbd2ce3cce3cb871aa5f6b690ef881f8dc5705 --- current.txt | 7 +-- gnss/2.0/IGnssCallback.hal | 39 ++++++++++---- gnss/2.0/default/Gnss.cpp | 5 +- .../default/GnssMeasurementCorrections.cpp | 13 +++++ gnss/2.0/default/GnssMeasurementCorrections.h | 1 + gnss/2.0/types.hal | 2 +- gnss/2.0/vts/functional/gnss_hal_test.cpp | 29 +++++++++++ gnss/2.0/vts/functional/gnss_hal_test.h | 16 ++++++ .../vts/functional/gnss_hal_test_cases.cpp | 52 ++++++++++++++----- gnss/measurement_corrections/1.0/Android.bp | 1 + .../1.0/IMeasurementCorrections.hal | 17 ++++-- .../1.0/IMeasurementCorrectionsCallback.hal | 50 ++++++++++++++++++ 12 files changed, 200 insertions(+), 32 deletions(-) create mode 100644 gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal diff --git a/current.txt b/current.txt index 75b297d2c7..93638a05c1 100644 --- a/current.txt +++ b/current.txt @@ -465,12 +465,13 @@ f27baaa587bc3dd9b740cb6928ab812b9b7d105b5187663938aee578105f3c39 android.hardwar 2e5ad983734069e84a760004b32da0d09e4170c05380abe27e6eb80e4aa70d5a android.hardware.gnss@2.0::IAGnssCallback 1f4ac068a88a72360280d94a7f6fd7c63813c1eea4891a0eb01394d3e7e775f2 android.hardware.gnss@2.0::IAGnssRil 6e2f9a44375a0ae0b49ca7d711cb88945189d398535078408269e1e85889061d android.hardware.gnss@2.0::IGnss -d815623a6d1ba4abf21248b84eca70a2bfab03058a88b68a29c063ce8aee6b5c android.hardware.gnss@2.0::IGnssCallback +782dfc724272f279985de348c824197357941382f73c0083f0344d8ec594d2a8 android.hardware.gnss@2.0::IGnssCallback ecc966c68bddbd95c8dae782b84204cf01c75734675e8769963f3b5106ec128b android.hardware.gnss@2.0::IGnssConfiguration c67759f5d6387d273b66729180d03690e827f0b6b8d4e13ce2ff42d31b224065 android.hardware.gnss@2.0::IGnssMeasurement 3dd30a3ca77ef5ab109a55ba603ff816ae5019436886093dccf8fd6a068f85f1 android.hardware.gnss@2.0::IGnssMeasurementCallback -9e66234e65bcde75733d75d8b5d5cc094c2a5e14b074a25cd3f9ad141dc56f60 android.hardware.gnss@2.0::types -50623a69a88b1c8a05738e4af7d5f78e905f415ccb0e84c99d0a71ea182e9393 android.hardware.gnss.measurement_corrections@1.0::IMeasurementCorrections +4bcd767dd05304b4722c6521c7ed8d4a05faf6022f228f2c088379c647871f7c android.hardware.gnss@2.0::types +d4cc8d91930d5a1a62deb0d97d398510a115ce3ede2d2978738651b9d01b11c3 android.hardware.gnss.measurement_corrections@1.0::IMeasurementCorrections +3eec9763db9b101644f14175b77c9954047445a468e9c743fd402d472d4aa97e android.hardware.gnss.measurement_corrections@1.0::IMeasurementCorrectionsCallback 6ef12cd95df73f8f80c25eb035d98ca4594f9cee571fdabea838a0b6016dd908 android.hardware.gnss.measurement_corrections@1.0::types 0d278956d7fc6fdf9ca9c42962ff2d73967bbb1c9f0b3e0b58d71b7095c286bc android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControl 0d99e34500cfc2d40b684cb4dea7ebd89d4aff9f5315ed36b33442a7a88c138c android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback diff --git a/gnss/2.0/IGnssCallback.hal b/gnss/2.0/IGnssCallback.hal index 7924b641bc..4c31cf5208 100644 --- a/gnss/2.0/IGnssCallback.hal +++ b/gnss/2.0/IGnssCallback.hal @@ -21,7 +21,7 @@ import @1.1::IGnssCallback; import GnssLocation; /** - * The interface is required for the HAL to communicate certain information + * This interface is required for the HAL to communicate certain information * like status and location info back to the platform, the platform implements * the interfaces and passes a handle to the HAL. */ @@ -29,17 +29,36 @@ interface IGnssCallback extends @1.1::IGnssCallback { /** Flags for the gnssSetCapabilities callback. */ @export(name="", value_prefix="GPS_CAPABILITY_") - enum Capabilities : @1.0::IGnssCallback.Capabilities { - /** GNSS supports line-of-sight satellite identification measurement Corrections */ - MEASUREMENT_CORRECTIONS_LOS_SATS = 1 << 8, - /** GNSS supports per satellite excess-path-length measurement Corrections */ - MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 1 << 9, - /** GNSS supports reflecting planes measurement Corrections */ - MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 1 << 10 + enum Capabilities : uint32_t { + /** + * GNSS HAL schedules fixes for RECURRENCE_PERIODIC mode. + * If this is not set, then the framework will use 1000ms for + * minInterval and must call start() and stop() to schedule the GNSS. + */ + SCHEDULING = 1 << 0, + /** GNSS supports MS-Based AGNSS mode */ + MSB = 1 << 1, + /** GNSS supports MS-Assisted AGNSS mode */ + MSA = 1 << 2, + /** GNSS supports single-shot fixes */ + SINGLE_SHOT = 1 << 3, + /** GNSS supports on demand time injection */ + ON_DEMAND_TIME = 1 << 4, + /** + * Values for the flags removed from IGnssCallback.hal@1.0 Capabilities + * enum are marked as reserved and not reused here to avoid confusion. + */ + RESERVED_1 = 1 << 5, + RESERVED_2 = 1 << 6, + RESERVED_3 = 1 << 7, + /** GNSS supports low power mode */ + LOW_POWER_MODE = 1 << 8, + /** GNSS supports blacklisting satellites */ + SATELLITE_BLACKLIST = 1 << 9 }; /** - * Callback to inform framework of the GNSS engine's capabilities. + * Callback to inform framework of the GNSS HAL implementation's capabilities. * * @param capabilities Capability parameter is a bit field of the Capabilities enum. */ @@ -75,4 +94,4 @@ interface IGnssCallback extends @1.1::IGnssCallback { * during-call to E911, or up to 5 minutes after end-of-call or text to E911). */ gnssRequestLocationCb_2_0(bool independentFromGnss, bool isUserEmergency); -}; \ No newline at end of file +}; diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp index ee6da5374c..1dfdadbffb 100644 --- a/gnss/2.0/default/Gnss.cpp +++ b/gnss/2.0/default/Gnss.cpp @@ -269,8 +269,9 @@ Return Gnss::setCallback_2_0(const sp& callback) { sGnssCallback_2_0 = callback; - uint32_t capabilities = static_cast(V1_0::IGnssCallback::Capabilities::MEASUREMENTS); - auto ret = sGnssCallback_2_0->gnssSetCapabilitesCb(capabilities); + using Capabilities = V2_0::IGnssCallback::Capabilities; + const auto capabilities = Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; + auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } diff --git a/gnss/2.0/default/GnssMeasurementCorrections.cpp b/gnss/2.0/default/GnssMeasurementCorrections.cpp index cbf34ba9c3..2bf5601820 100644 --- a/gnss/2.0/default/GnssMeasurementCorrections.cpp +++ b/gnss/2.0/default/GnssMeasurementCorrections.cpp @@ -54,6 +54,19 @@ Return GnssMeasurementCorrections::setCorrections(const MeasurementCorrect return true; } +Return GnssMeasurementCorrections::setCallback( + const sp& callback) { + using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities; + auto ret = + callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH | + Capabilities::REFLECTING_PLANE); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + return false; + } + return true; +} + } // namespace implementation } // namespace V1_0 } // namespace measurement_corrections diff --git a/gnss/2.0/default/GnssMeasurementCorrections.h b/gnss/2.0/default/GnssMeasurementCorrections.h index f758bc8a08..4339bed55d 100644 --- a/gnss/2.0/default/GnssMeasurementCorrections.h +++ b/gnss/2.0/default/GnssMeasurementCorrections.h @@ -38,6 +38,7 @@ using ::android::hardware::Void; struct GnssMeasurementCorrections : public IMeasurementCorrections { // Methods from V1_0::IMeasurementCorrections follow. Return setCorrections(const MeasurementCorrections& corrections) override; + Return setCallback(const sp& callback) override; }; } // namespace implementation diff --git a/gnss/2.0/types.hal b/gnss/2.0/types.hal index 4abb6048c9..21b64f93d7 100644 --- a/gnss/2.0/types.hal +++ b/gnss/2.0/types.hal @@ -69,7 +69,7 @@ struct GnssLocation { * * This clock information can be obtained from SystemClock.elapsedRealtimeNanos(), when the GNSS * is attached straight to the AP/SOC. When it is attached to a separate module the timestamp - * needs to be estimatedd by syncing the notion of time via PTP or some other mechanism. + * needs to be estimated by syncing the notion of time via PTP or some other mechanism. */ ElapsedRealtime elapsedRealtime; }; \ No newline at end of file diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp index c564f41a03..b2b62fcd29 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -77,6 +77,16 @@ void GnssHalTest::SetUpGnssCallback() { EXPECT_EQ(capabilities_called_count_, 1); EXPECT_EQ(info_called_count_, 1); EXPECT_EQ(name_called_count_, 1); + + // Setup measurement corrections callback. + auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); + ASSERT_TRUE(measurementCorrections.isOk()); + sp iMeasurementCorrections = measurementCorrections; + if (iMeasurementCorrections != nullptr) { + sp iMeasurementCorrectionsCallback = + new GnssMeasurementCorrectionsCallback(*this); + iMeasurementCorrections->setCallback(iMeasurementCorrectionsCallback); + } } void GnssHalTest::StopAndClearLocations() { @@ -176,6 +186,16 @@ std::cv_status GnssHalTest::wait(int timeout_seconds) { return status; } +std::cv_status GnssHalTest::waitForMeasurementCorrectionsCapabilities(int timeout_seconds) { + std::unique_lock lock(mtx_); + auto status = std::cv_status::no_timeout; + while (measurement_corrections_capabilities_called_count_ == 0) { + status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds)); + if (status == std::cv_status::timeout) return status; + } + return status; +} + Return GnssHalTest::GnssCallback::gnssSetSystemInfoCb( const IGnssCallback::GnssSystemInfo& info) { ALOGI("Info received, year %d", info.yearOfHw); @@ -243,3 +263,12 @@ Return GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_0( parent_.notify(); return Void(); } + +Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( + uint32_t capabilities) { + ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities); + parent_.measurement_corrections_capabilities_called_count_++; + parent_.last_measurement_corrections_capabilities_ = capabilities; + parent_.notify(); + return Void(); +} diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h index 31750a6641..7354aeae34 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.h +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -28,6 +28,7 @@ using android::hardware::Return; using android::hardware::Void; +using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback; using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::IGnss; using android::hardware::gnss::V2_0::IGnssCallback; @@ -73,6 +74,8 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { /* Test code calls this function to wait for a callback */ std::cv_status wait(int timeout_seconds); + std::cv_status waitForMeasurementCorrectionsCapabilities(int timeout_seconds); + /* Callback class for data & Event. */ class GnssCallback : public IGnssCallback { public: @@ -136,6 +139,17 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { Return gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override; }; + /* Callback class for GnssMeasurementCorrections. */ + class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback { + public: + GnssHalTest& parent_; + GnssMeasurementCorrectionsCallback(GnssHalTest& parent) : parent_(parent){}; + virtual ~GnssMeasurementCorrectionsCallback() = default; + + // Methods from V1_0::IMeasurementCorrectionsCallback follow. + Return setCapabilitiesCb(uint32_t capabilities) override; + }; + /* * SetUpGnssCallback: * Set GnssCallback and verify the result. @@ -192,12 +206,14 @@ class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { */ int info_called_count_; int capabilities_called_count_; + int measurement_corrections_capabilities_called_count_; int location_called_count_; int measurement_called_count_; int name_called_count_; IGnssCallback::GnssSystemInfo last_info_; uint32_t last_capabilities_; + uint32_t last_measurement_corrections_capabilities_; GnssLocation_2_0 last_location_; IGnssMeasurementCallback_2_0::GnssData last_measurement_; android::hardware::hidl_string last_name_; diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp index 67fda89fc0..f3559c5788 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -38,6 +38,7 @@ using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrec using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; using android::hardware::gnss::V1_0::IGnssNi; using android::hardware::gnss::V2_0::ElapsedRealtimeFlags; +using android::hardware::gnss::V2_0::IGnssCallback; using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl; /* @@ -50,23 +51,21 @@ TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {} /* * TestGnssMeasurementCallback: - * Gets the GnssMeasurementExtension and verify that it returns an actual extension. + * Gets the GnssMeasurementExtension and verifies that it returns an actual extension. */ TEST_F(GnssHalTest, TestGnssMeasurementCallback) { auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0(); auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1(); auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); - ASSERT_TRUE(gnssMeasurement_2_0.isOk() || gnssMeasurement_1_1.isOk() || + ASSERT_TRUE(gnssMeasurement_2_0.isOk() && gnssMeasurement_1_1.isOk() && gnssMeasurement_1_0.isOk()); - if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) { - sp iGnssMeas_2_0 = gnssMeasurement_2_0; - sp iGnssMeas_1_1 = gnssMeasurement_1_1; - sp iGnssMeas_1_0 = gnssMeasurement_1_0; - // At least one interface is non-null. - int numNonNull = (int)(iGnssMeas_2_0 != nullptr) + (int)(iGnssMeas_1_1 != nullptr) + - (int)(iGnssMeas_1_0 != nullptr); - ASSERT_TRUE(numNonNull >= 1); - } + sp iGnssMeas_2_0 = gnssMeasurement_2_0; + sp iGnssMeas_1_1 = gnssMeasurement_1_1; + sp iGnssMeas_1_0 = gnssMeasurement_1_0; + // At least one interface is non-null. + int numNonNull = (int)(iGnssMeas_2_0 != nullptr) + (int)(iGnssMeas_1_1 != nullptr) + + (int)(iGnssMeas_1_0 != nullptr); + ASSERT_TRUE(numNonNull >= 1); } /* @@ -266,9 +265,31 @@ TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) { EXPECT_TRUE(result); } +/* + * TestGnssMeasurementCorrectionsCapabilities: + * If the GnssMeasurementCorrectionsExtension is not null, verifies that the measurement corrections + * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH + * capability flag is set. + */ +TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { + auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); + ASSERT_TRUE(measurementCorrections.isOk()); + sp iMeasurementCorrections = measurementCorrections; + if (iMeasurementCorrections == nullptr) { + return; + } + + const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5; + waitForMeasurementCorrectionsCapabilities(kMeasurementCorrectionsCapabilitiesTimeoutSeconds); + ASSERT_TRUE(measurement_corrections_capabilities_called_count_ > 0); + using Capabilities = IMeasurementCorrectionsCallback::Capabilities; + ASSERT_TRUE((last_measurement_corrections_capabilities_ & + (Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH)) != 0); +} + /* * TestGnssMeasurementCorrections: - * Gets the GnssMeasurementCorrectionsExtension and verifies that it supports the + * If the GnssMeasurementCorrectionsExtension is not null, verifies that it supports the * gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method. */ TEST_F(GnssHalTest, TestGnssMeasurementCorrections) { @@ -276,8 +297,13 @@ TEST_F(GnssHalTest, TestGnssMeasurementCorrections) { auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); ASSERT_TRUE(measurementCorrections.isOk()); sp iMeasurementCorrections = measurementCorrections; - ASSERT_NE(iMeasurementCorrections, nullptr); + if (iMeasurementCorrections == nullptr) { + return; + } + const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5; + waitForMeasurementCorrectionsCapabilities(kMeasurementCorrectionsCapabilitiesTimeoutSeconds); + ASSERT_TRUE(measurement_corrections_capabilities_called_count_ > 0); // Set a mock MeasurementCorrections. auto result = iMeasurementCorrections->setCorrections(Utils::getMockMeasurementCorrections()); ASSERT_TRUE(result.isOk()); diff --git a/gnss/measurement_corrections/1.0/Android.bp b/gnss/measurement_corrections/1.0/Android.bp index 4aac7e04c8..456b55c0ef 100644 --- a/gnss/measurement_corrections/1.0/Android.bp +++ b/gnss/measurement_corrections/1.0/Android.bp @@ -9,6 +9,7 @@ hidl_interface { srcs: [ "types.hal", "IMeasurementCorrections.hal", + "IMeasurementCorrectionsCallback.hal", ], interfaces: [ "android.hardware.gnss@1.0", diff --git a/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal b/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal index 934d10f64a..1fa32f4317 100644 --- a/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal +++ b/gnss/measurement_corrections/1.0/IMeasurementCorrections.hal @@ -16,11 +16,12 @@ package android.hardware.gnss.measurement_corrections@1.0; +import IMeasurementCorrectionsCallback; + /** * Interface for measurement corrections support. */ interface IMeasurementCorrections { - /** * Injects measurement corrections to be used by the HAL to improve the GNSS location output. * @@ -35,5 +36,15 @@ interface IMeasurementCorrections { * * @return success Whether the HAL can accept & use these corrections. */ - setCorrections(MeasurementCorrections corrections) generates (bool success); -}; + setCorrections(MeasurementCorrections corrections) generates (bool success); + + /** + * Opens the interface and provides the callback routines to the implementation of this + * interface. + * + * @param callback Callback interface for IMeasurementCorrections. + * + * @return success Returns true on success. + */ + setCallback(IMeasurementCorrectionsCallback callback) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal b/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal new file mode 100644 index 0000000000..91d131192b --- /dev/null +++ b/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.hal @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 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. + */ + +package android.hardware.gnss.measurement_corrections@1.0; + +/** + * GNSS measurement corrections callback interface. + */ +interface IMeasurementCorrectionsCallback { + + /** + * Flags to indicate supported measurement corrections capabilities + * + * Either the LOS_SATS or the EXCESS_PATH_LENGTH capability must be supported. + */ + enum Capabilities : uint32_t { + /** GNSS supports line-of-sight satellite identification measurement corrections */ + LOS_SATS = 1 << 0, + /** GNSS supports per satellite excess-path-length measurement corrections */ + EXCESS_PATH_LENGTH = 1 << 1, + /** GNSS supports reflecting planes measurement corrections */ + REFLECTING_PLANE = 1 << 2 + }; + + /** + * Callback to inform framework the measurement correction specific capabilities of the GNSS + * HAL implementation. + * + * The GNSS HAL must call this method immediately after the framework opens the measurement + * corrections interface. + * + * @param capabilities Supported measurement corrections capabilities. It is mandatory to + * support either LOS_STATS or EXCESS_PATH_LENGTH capability. + * + */ + setCapabilitiesCb(bitfield capabilities); +}; \ No newline at end of file