1 /*
2  * Copyright (C) 2017 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 "GnssHalTest"
18 
19 #include <android/hidl/manager/1.2/IServiceManager.h>
20 #include <hidl/ServiceManagement.h>
21 
22 #include <gnss_hal_test.h>
23 #include <chrono>
24 #include "Utils.h"
25 
26 using ::android::hardware::hidl_string;
27 using ::android::hardware::hidl_vec;
28 
29 using ::android::hardware::gnss::common::Utils;
30 
31 // Implementations for the main test class for GNSS HAL
GnssHalTest()32 GnssHalTest::GnssHalTest()
33     : info_called_count_(0),
34       capabilities_called_count_(0),
35       location_called_count_(0),
36       name_called_count_(0),
37       notify_count_(0) {}
38 
SetUp()39 void GnssHalTest::SetUp() {
40     gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
41         GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
42     list_gnss_sv_status_.clear();
43     ASSERT_NE(gnss_hal_, nullptr);
44 
45     SetUpGnssCallback();
46 }
47 
TearDown()48 void GnssHalTest::TearDown() {
49     if (gnss_hal_ != nullptr) {
50         gnss_hal_->cleanup();
51     }
52     if (notify_count_ > 0) {
53         ALOGW("%d unprocessed callbacks discarded", notify_count_);
54     }
55 }
56 
SetUpGnssCallback()57 void GnssHalTest::SetUpGnssCallback() {
58     gnss_cb_ = new GnssCallback(*this);
59     ASSERT_NE(gnss_cb_, nullptr);
60 
61     auto result = gnss_hal_->setCallback_1_1(gnss_cb_);
62     if (!result.isOk()) {
63         ALOGE("result of failed setCallback %s", result.description().c_str());
64     }
65 
66     ASSERT_TRUE(result.isOk());
67     ASSERT_TRUE(result);
68 
69     /*
70      * All capabilities, name and systemInfo callbacks should trigger
71      */
72     EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
73     EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
74     EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
75 
76     EXPECT_EQ(capabilities_called_count_, 1);
77     EXPECT_EQ(info_called_count_, 1);
78     EXPECT_EQ(name_called_count_, 1);
79 }
80 
StopAndClearLocations()81 void GnssHalTest::StopAndClearLocations() {
82     auto result = gnss_hal_->stop();
83 
84     EXPECT_TRUE(result.isOk());
85     EXPECT_TRUE(result);
86 
87     /*
88      * Clear notify/waiting counter, allowing up till the timeout after
89      * the last reply for final startup messages to arrive (esp. system
90      * info.)
91      */
92     while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
93     }
94     location_called_count_ = 0;
95 }
96 
SetPositionMode(const int min_interval_msec,const bool low_power_mode)97 void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
98     const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
99     const int kPreferredTimeMsec = 0;  // Ideally immediate
100 
101     auto result = gnss_hal_->setPositionMode_1_1(
102         IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
103         min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
104 
105     ASSERT_TRUE(result.isOk());
106     EXPECT_TRUE(result);
107 }
108 
StartAndCheckFirstLocation()109 bool GnssHalTest::StartAndCheckFirstLocation() {
110     auto result = gnss_hal_->start();
111 
112     EXPECT_TRUE(result.isOk());
113     EXPECT_TRUE(result);
114 
115     /*
116      * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
117      * so allow time to demodulate ephemeris over the air.
118      */
119     const int kFirstGnssLocationTimeoutSeconds = 75;
120 
121     wait(kFirstGnssLocationTimeoutSeconds);
122     EXPECT_EQ(location_called_count_, 1);
123 
124     if (location_called_count_ > 0) {
125         // don't require speed on first fix
126         CheckLocation(last_location_, false);
127         return true;
128     }
129     return false;
130 }
131 
CheckLocation(GnssLocation & location,bool check_speed)132 void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) {
133     bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
134 
135     Utils::checkLocation(location, check_speed, check_more_accuracies);
136 }
137 
StartAndCheckLocations(int count)138 void GnssHalTest::StartAndCheckLocations(int count) {
139     const int kMinIntervalMsec = 500;
140     const int kLocationTimeoutSubsequentSec = 2;
141     const bool kLowPowerMode = false;
142 
143     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
144 
145     EXPECT_TRUE(StartAndCheckFirstLocation());
146 
147     for (int i = 1; i < count; i++) {
148         EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec));
149         EXPECT_EQ(location_called_count_, i + 1);
150         // Don't cause confusion by checking details if no location yet
151         if (location_called_count_ > 0) {
152             // Should be more than 1 location by now, but if not, still don't check first fix speed
153             CheckLocation(last_location_, location_called_count_ > 1);
154         }
155     }
156 }
157 
IsGnssHalVersion_1_1() const158 bool GnssHalTest::IsGnssHalVersion_1_1() const {
159     using ::android::hidl::manager::V1_2::IServiceManager;
160     sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
161 
162     bool hasGnssHalVersion_1_1 = false;
163     manager->listManifestByInterface(
164             "android.hardware.gnss@1.1::IGnss",
165             [&hasGnssHalVersion_1_1](const hidl_vec<hidl_string>& registered) {
166                 ASSERT_EQ(1, registered.size());
167                 hasGnssHalVersion_1_1 = true;
168             });
169 
170     bool hasGnssHalVersion_2_0 = false;
171     manager->listManifestByInterface(
172             "android.hardware.gnss@2.0::IGnss",
173             [&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
174                 hasGnssHalVersion_2_0 = registered.size() != 0;
175             });
176 
177     return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
178 }
179 
startLocationAndGetNonGpsConstellation()180 GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation() {
181     const int kLocationsToAwait = 3;
182 
183     StartAndCheckLocations(kLocationsToAwait);
184 
185     // Tolerate 1 less sv status to handle edge cases in reporting.
186     EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
187     ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
188           (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
189 
190     // Find first non-GPS constellation
191     GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
192     for (const auto& gnss_sv_status : list_gnss_sv_status_) {
193         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
194             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
195             if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
196                 (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
197                 (gnss_sv.constellation != GnssConstellationType::GPS)) {
198                 // found a non-GPS constellation
199                 constellation_to_blacklist = gnss_sv.constellation;
200                 break;
201             }
202         }
203         if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
204             break;
205         }
206     }
207 
208     if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
209         ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
210         // Proceed functionally to return something.
211         constellation_to_blacklist = GnssConstellationType::GLONASS;
212     }
213     return constellation_to_blacklist;
214 }
215 
notify()216 void GnssHalTest::notify() {
217     std::unique_lock<std::mutex> lock(mtx_);
218     notify_count_++;
219     cv_.notify_one();
220 }
221 
wait(int timeout_seconds)222 std::cv_status GnssHalTest::wait(int timeout_seconds) {
223     std::unique_lock<std::mutex> lock(mtx_);
224 
225     auto status = std::cv_status::no_timeout;
226     while (notify_count_ == 0) {
227         status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds));
228         if (status == std::cv_status::timeout) return status;
229     }
230     notify_count_--;
231     return status;
232 }
233 
gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo & info)234 Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
235     const IGnssCallback::GnssSystemInfo& info) {
236     ALOGI("Info received, year %d", info.yearOfHw);
237     parent_.info_called_count_++;
238     parent_.last_info_ = info;
239     parent_.notify();
240     return Void();
241 }
242 
gnssSetCapabilitesCb(uint32_t capabilities)243 Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
244     ALOGI("Capabilities received %d", capabilities);
245     parent_.capabilities_called_count_++;
246     parent_.last_capabilities_ = capabilities;
247     parent_.notify();
248     return Void();
249 }
250 
gnssNameCb(const android::hardware::hidl_string & name)251 Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
252     ALOGI("Name received: %s", name.c_str());
253     parent_.name_called_count_++;
254     parent_.last_name_ = name;
255     parent_.notify();
256     return Void();
257 }
258 
gnssLocationCb(const GnssLocation & location)259 Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
260     ALOGI("Location received");
261     parent_.location_called_count_++;
262     parent_.last_location_ = location;
263     parent_.notify();
264     return Void();
265 }
266 
gnssSvStatusCb(const IGnssCallback::GnssSvStatus & svStatus)267 Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(
268     const IGnssCallback::GnssSvStatus& svStatus) {
269     ALOGI("GnssSvStatus received");
270     parent_.list_gnss_sv_status_.emplace_back(svStatus);
271     return Void();
272 }
273