~thomas-voss/location-service/fix-1347887

« back to all changes in this revision

Viewing changes to src/location_service/com/ubuntu/location/service/ichnaea_reporter.cpp

This MP consolidates multiple related changes together, with the goal of:

(1.) Make the service instance accessible via a cli. Useful for testing scenarios.
(2.) To cut down time-to-first-fix (ttff) by:
  (2.1) Leveraging SUPL and other supplementary data downloaded over ordinary data connections.
  (2.2) Enabling network-based positioning providers to acquire fast position estimates.

In more detail:

* Added tests for daemon and cli.
* Unified daemon and cli header and implementation files.
* Add a command-line interface to the service.
* Split up provider selection policy to rely on an interface ProviderEnumerator to ease in testing.
* Trimmed down on types.
* Removed connectivity API draft to prepare for simpler approach.
* Refactored includes.
* Added a configuration option to handle cell and wifi ID reporting.
* Add a mock for a connectivity API exposed to providers and reporters.
* Add units for connectivity api.
* Refactor cell class into namespace radio. Fixes: 1226204, 1248973, 1281817

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2012-2013 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License version 3,
 
6
 * as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Thomas Voß <thomas.voss@canonical.com>
 
17
 */
 
18
 
 
19
#include <com/ubuntu/location/service/ichnaea_reporter.h>
 
20
 
 
21
#include <com/ubuntu/location/logging.h>
 
22
 
 
23
#include <core/net/http/client.h>
 
24
#include <core/net/http/content_type.h>
 
25
#include <core/net/http/request.h>
 
26
#include <core/net/http/response.h>
 
27
#include <core/net/http/status.h>
 
28
 
 
29
#include <json/json.h>
 
30
 
 
31
#include <thread>
 
32
 
 
33
namespace json = Json;
 
34
namespace location = com::ubuntu::location;
 
35
 
 
36
location::service::ichnaea::Reporter::Reporter(
 
37
        const location::service::ichnaea::Reporter::Configuration& configuration)
 
38
    : http_client(core::net::http::make_client())
 
39
{
 
40
    auto uri = configuration.uri +
 
41
            ichnaea::submit::resource +
 
42
            configuration.key;
 
43
 
 
44
    submit_request_config = core::net::http::Request::Configuration::from_uri_as_string(uri);
 
45
    submit_request_config.ssl.verify_host = false;
 
46
    submit_request_config.ssl.verify_peer = false;
 
47
 
 
48
    if (not configuration.nick_name.empty())
 
49
        submit_request_config.header.add(Reporter::nick_name_header, configuration.nick_name);
 
50
}
 
51
 
 
52
location::service::ichnaea::Reporter::~Reporter()
 
53
{
 
54
    stop();
 
55
}
 
56
 
 
57
void location::service::ichnaea::Reporter::start()
 
58
{
 
59
    http_client_worker = std::move(
 
60
                std::thread
 
61
                {
 
62
                    [this]()
 
63
                    {
 
64
                        http_client->run();
 
65
                    }
 
66
                });
 
67
}
 
68
 
 
69
void location::service::ichnaea::Reporter::stop()
 
70
{
 
71
    http_client->stop();
 
72
 
 
73
    if (http_client_worker.joinable())
 
74
        http_client_worker.join();
 
75
}
 
76
 
 
77
void location::service::ichnaea::Reporter::report(
 
78
        const location::Update<location::Position>& update,
 
79
        const std::vector<location::connectivity::WirelessNetwork::Ptr>& wifis,
 
80
        const std::vector<location::connectivity::RadioCell::Ptr>& cells)
 
81
{
 
82
    json::Value submit;
 
83
    json::Value item;
 
84
 
 
85
    item[Json::radio] = "gsm"; // We currently only support gsm radio types.
 
86
    item[Json::lat] = update.value.latitude.value.value();
 
87
    item[Json::lon] = update.value.longitude.value.value();
 
88
 
 
89
    if (update.value.accuracy.horizontal)
 
90
        item[Json::accuracy] = (*update.value.accuracy.horizontal).value();
 
91
    if (update.value.altitude)
 
92
        item[Json::altitude] = (*update.value.altitude).value.value();
 
93
    if (update.value.accuracy.vertical)
 
94
        item[Json::altitude_accuracy] = (*update.value.accuracy.vertical).value();
 
95
 
 
96
    if (!wifis.empty())
 
97
        ichnaea::Reporter::convert_wifis_to_json(wifis, item[Json::wifi]);
 
98
 
 
99
    if (!cells.empty())
 
100
        ichnaea::Reporter::convert_cells_to_json(cells, item[Json::cell]);
 
101
 
 
102
    submit[Json::items].append(item);
 
103
 
 
104
    json::FastWriter writer;
 
105
 
 
106
    VLOG(10) << "Submitting: " << writer.write(submit);
 
107
 
 
108
    auto request = http_client->post(
 
109
                submit_request_config,
 
110
                writer.write(submit),
 
111
                core::net::http::ContentType::json);
 
112
 
 
113
    request->async_execute(
 
114
                core::net::http::Request::Handler()
 
115
                .on_response([](const core::net::http::Response& response)
 
116
                {
 
117
                    if (response.status != ichnaea::submit::success)
 
118
                        LOG(ERROR) << "Error submitting to ichnaea: " << response.body;
 
119
                    else
 
120
                        LOG(INFO) << "Succesfully submitted to ichnaea.";
 
121
                })
 
122
                .on_error([](const core::net::Error& e)
 
123
                {
 
124
                    LOG(ERROR) << "Networking error while submitting to ichnaea: " << e.what();
 
125
                }));
 
126
}
 
127
 
 
128
void location::service::ichnaea::Reporter::convert_wifis_to_json(
 
129
        const std::vector<location::connectivity::WirelessNetwork::Ptr>& wifis,
 
130
        json::Value& destination)
 
131
{
 
132
    for (const auto& wifi : wifis)
 
133
    {
 
134
        // We do not harvest any Wifi marked with '_nomap'.
 
135
        if (wifi->ssid().get().find("_nomap") != std::string::npos)
 
136
            continue;
 
137
 
 
138
        json::Value w;
 
139
        w[Json::Wifi::key] = wifi->bssid().get();
 
140
 
 
141
        if (wifi->frequency().get().is_valid())
 
142
            w[Json::Wifi::frequency] = static_cast<int>(wifi->frequency().get());
 
143
 
 
144
        // We have a relative signal strength percentage in the wifi record.
 
145
        // TODO(tvoss): Check how that could be translated to RSSI.
 
146
        //wifi[Json::Wifi::signal] = -50;
 
147
 
 
148
        destination.append(w);
 
149
    }
 
150
}
 
151
 
 
152
void location::service::ichnaea::Reporter::convert_cells_to_json(
 
153
        const std::vector<location::connectivity::RadioCell::Ptr>& cells,
 
154
        json::Value& destination)
 
155
{
 
156
    for (const auto& cell : cells)
 
157
    {
 
158
        json::Value c;
 
159
 
 
160
        switch (cell->type())
 
161
        {
 
162
        case connectivity::RadioCell::Type::gsm:
 
163
        {
 
164
            c[Json::Cell::radio] = "gsm";
 
165
 
 
166
            const auto& details = cell->gsm();
 
167
 
 
168
            if (details.mobile_country_code.is_valid())
 
169
                c[Json::Cell::mcc] = details.mobile_country_code.get();
 
170
            if (details.mobile_network_code.is_valid())
 
171
                c[Json::Cell::mnc] = details.mobile_network_code.get();
 
172
            if (details.location_area_code.is_valid())
 
173
                c[Json::Cell::lac] = details.location_area_code.get();
 
174
            if (details.id.is_valid())
 
175
                c[Json::Cell::cid] = details.id.get();
 
176
            if  (details.strength.is_valid())
 
177
                c[Json::Cell::asu] = details.strength.get();
 
178
 
 
179
            break;
 
180
        }
 
181
        case connectivity::RadioCell::Type::umts:
 
182
        {
 
183
            c[Json::Cell::radio] = "umts";
 
184
 
 
185
            const auto& details = cell->umts();
 
186
 
 
187
            if (details.mobile_country_code.is_valid())
 
188
                c[Json::Cell::mcc] = details.mobile_country_code.get();
 
189
            if (details.mobile_network_code.is_valid())
 
190
                c[Json::Cell::mnc] = details.mobile_network_code.get();
 
191
            if (details.location_area_code.is_valid())
 
192
                c[Json::Cell::lac] = details.location_area_code.get();
 
193
            if (details.id.is_valid())
 
194
                c[Json::Cell::cid] = details.id.get();
 
195
            if  (details.strength.is_valid())
 
196
                c[Json::Cell::asu] = details.strength.get();
 
197
 
 
198
            break;
 
199
        }
 
200
        case connectivity::RadioCell::Type::lte:
 
201
        {
 
202
            c[Json::Cell::radio] = "lte";
 
203
 
 
204
            const auto& details = cell->lte();
 
205
 
 
206
            if (details.mobile_country_code.is_valid())
 
207
                c[Json::Cell::mcc] = details.mobile_country_code.get();
 
208
            if (details.mobile_network_code.is_valid())
 
209
                c[Json::Cell::mnc] = details.mobile_network_code.get();
 
210
            if (details.tracking_area_code.is_valid())
 
211
                c[Json::Cell::lac] = details.tracking_area_code.get();
 
212
            if (details.id.is_valid())
 
213
                c[Json::Cell::cid] = details.id.get();
 
214
            if (details.physical_id.is_valid())
 
215
                c[Json::Cell::psc] = details.physical_id.get();
 
216
            if  (details.strength.is_valid())
 
217
                c[Json::Cell::asu] = details.strength.get();
 
218
            break;
 
219
        }
 
220
        default:
 
221
            break;
 
222
        }
 
223
 
 
224
        destination.append(c);
 
225
    }
 
226
}