blob: 79df5046792b7ff060e32a621fd4ec2c8ffa8984 [file] [log] [blame]
[email protected]b7c377e2013-01-15 10:00:391// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/network/geolocation_handler.h"
6
avi6e1a22d2015-12-21 03:43:207#include <stddef.h>
8#include <stdint.h>
9
[email protected]b7c377e2013-01-15 10:00:3910#include "base/bind.h"
[email protected]afa339d72013-06-11 06:32:5111#include "base/strings/string_number_conversions.h"
[email protected]b7c377e2013-01-15 10:00:3912#include "base/values.h"
13#include "chromeos/dbus/dbus_thread_manager.h"
14#include "chromeos/dbus/shill_manager_client.h"
15#include "third_party/cros_system_api/dbus/service_constants.h"
16
17namespace chromeos {
18
skylarceaf50cb2017-02-14 01:16:2819namespace {
20
21constexpr const char* kDevicePropertyNames[] = {
22 shill::kGeoWifiAccessPointsProperty, shill::kGeoCellTowersProperty};
23
Niranjan Kumar4c2ce9f2017-10-03 22:28:5124std::string HexToDecimal(std::string hex_str) {
25 return std::to_string(std::stoi(hex_str, nullptr, 16));
26}
27
skylarceaf50cb2017-02-14 01:16:2828} // namespace
29
[email protected]b7c377e2013-01-15 10:00:3930GeolocationHandler::GeolocationHandler()
skylarceaf50cb2017-02-14 01:16:2831 : cellular_enabled_(false), wifi_enabled_(false), weak_ptr_factory_(this) {}
[email protected]b7c377e2013-01-15 10:00:3932
33GeolocationHandler::~GeolocationHandler() {
34 ShillManagerClient* manager_client =
35 DBusThreadManager::Get()->GetShillManagerClient();
36 if (manager_client)
37 manager_client->RemovePropertyChangedObserver(this);
38}
39
40void GeolocationHandler::Init() {
41 ShillManagerClient* manager_client =
42 DBusThreadManager::Get()->GetShillManagerClient();
43 manager_client->GetProperties(
44 base::Bind(&GeolocationHandler::ManagerPropertiesCallback,
45 weak_ptr_factory_.GetWeakPtr()));
46 manager_client->AddPropertyChangedObserver(this);
47}
48
[email protected]b7c377e2013-01-15 10:00:3949bool GeolocationHandler::GetWifiAccessPoints(
avi6e1a22d2015-12-21 03:43:2050 WifiAccessPointVector* access_points,
51 int64_t* age_ms) {
[email protected]b7c377e2013-01-15 10:00:3952 if (!wifi_enabled_)
53 return false;
skylarceaf50cb2017-02-14 01:16:2854 // Always request updated info.
55 RequestGeolocationObjects();
[email protected]b7c377e2013-01-15 10:00:3956 // If no data has been received, return false.
skylarceaf50cb2017-02-14 01:16:2857 if (geolocation_received_time_.is_null() || wifi_access_points_.size() == 0)
[email protected]b7c377e2013-01-15 10:00:3958 return false;
59 if (access_points)
60 *access_points = wifi_access_points_;
61 if (age_ms) {
62 base::TimeDelta dtime = base::Time::Now() - geolocation_received_time_;
63 *age_ms = dtime.InMilliseconds();
64 }
65 return true;
66}
67
skylarceaf50cb2017-02-14 01:16:2868bool GeolocationHandler::GetNetworkInformation(
69 WifiAccessPointVector* access_points,
70 CellTowerVector* cell_towers) {
71 if (!cellular_enabled_ && !wifi_enabled_)
72 return false;
73
74 // Always request updated info.
75 RequestGeolocationObjects();
76
77 // If no data has been received, return false.
78 if (geolocation_received_time_.is_null())
79 return false;
80
81 if (cell_towers)
82 *cell_towers = cell_towers_;
83 if (access_points)
84 *access_points = wifi_access_points_;
85
86 return true;
87}
88
[email protected]b7c377e2013-01-15 10:00:3989void GeolocationHandler::OnPropertyChanged(const std::string& key,
90 const base::Value& value) {
91 HandlePropertyChanged(key, value);
92}
93
94//------------------------------------------------------------------------------
95// Private methods
96
97void GeolocationHandler::ManagerPropertiesCallback(
98 DBusMethodCallStatus call_status,
99 const base::DictionaryValue& properties) {
skylarceaf50cb2017-02-14 01:16:28100 const base::Value* value = nullptr;
[email protected]547396c52013-09-24 07:24:56101 if (properties.Get(shill::kEnabledTechnologiesProperty, &value) && value)
102 HandlePropertyChanged(shill::kEnabledTechnologiesProperty, *value);
[email protected]b7c377e2013-01-15 10:00:39103}
104
105void GeolocationHandler::HandlePropertyChanged(const std::string& key,
106 const base::Value& value) {
[email protected]547396c52013-09-24 07:24:56107 if (key != shill::kEnabledTechnologiesProperty)
[email protected]b7c377e2013-01-15 10:00:39108 return;
skylarceaf50cb2017-02-14 01:16:28109 const base::ListValue* technologies = nullptr;
[email protected]b7c377e2013-01-15 10:00:39110 if (!value.GetAsList(&technologies) || !technologies)
111 return;
112 bool wifi_was_enabled = wifi_enabled_;
skylarceaf50cb2017-02-14 01:16:28113 bool cellular_was_enabled = cellular_enabled_;
114 cellular_enabled_ = false;
[email protected]b7c377e2013-01-15 10:00:39115 wifi_enabled_ = false;
116 for (base::ListValue::const_iterator iter = technologies->begin();
117 iter != technologies->end(); ++iter) {
118 std::string technology;
jdoerriea5676c62017-04-11 18:09:14119 iter->GetAsString(&technology);
[email protected]547396c52013-09-24 07:24:56120 if (technology == shill::kTypeWifi) {
[email protected]b7c377e2013-01-15 10:00:39121 wifi_enabled_ = true;
skylarceaf50cb2017-02-14 01:16:28122 } else if (technology == shill::kTypeCellular) {
123 cellular_enabled_ = true;
[email protected]b7c377e2013-01-15 10:00:39124 }
skylarceaf50cb2017-02-14 01:16:28125 if (wifi_enabled_ && cellular_enabled_)
126 break;
[email protected]b7c377e2013-01-15 10:00:39127 }
skylarceaf50cb2017-02-14 01:16:28128
129 // Request initial location data.
130 if ((!wifi_was_enabled && wifi_enabled_) ||
131 (!cellular_was_enabled && cellular_enabled_)) {
132 RequestGeolocationObjects();
133 }
[email protected]b7c377e2013-01-15 10:00:39134}
135
skylarceaf50cb2017-02-14 01:16:28136void GeolocationHandler::RequestGeolocationObjects() {
[email protected]b7c377e2013-01-15 10:00:39137 DBusThreadManager::Get()->GetShillManagerClient()->GetNetworksForGeolocation(
138 base::Bind(&GeolocationHandler::GeolocationCallback,
139 weak_ptr_factory_.GetWeakPtr()));
140}
141
142void GeolocationHandler::GeolocationCallback(
143 DBusMethodCallStatus call_status,
144 const base::DictionaryValue& properties) {
145 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
146 LOG(ERROR) << "Failed to get Geolocation data: " << call_status;
147 return;
148 }
149 wifi_access_points_.clear();
skylarceaf50cb2017-02-14 01:16:28150 cell_towers_.clear();
[email protected]b7c377e2013-01-15 10:00:39151 if (properties.empty())
152 return; // No enabled devices, don't update received time.
153
154 // Dictionary<device_type, entry_list>
skylarceaf50cb2017-02-14 01:16:28155 // Example dict returned from shill:
156 // {
157 // kGeoWifiAccessPointsProperty: [ {kGeoMacAddressProperty: mac_value, ...},
158 // ...
159 // ],
160 // kGeoCellTowersProperty: [ {kGeoCellIdProperty: cell_id_value, ...}, ... ]
161 // }
vmpstr843b41a2017-03-01 21:15:03162 for (auto* device_type : kDevicePropertyNames) {
skylarceaf50cb2017-02-14 01:16:28163 if (!properties.HasKey(device_type)) {
[email protected]b7c377e2013-01-15 10:00:39164 continue;
165 }
skylarceaf50cb2017-02-14 01:16:28166
167 const base::ListValue* entry_list = nullptr;
168 if (!properties.GetList(device_type, &entry_list)) {
169 LOG(WARNING) << "Geolocation dictionary value not a List: "
170 << device_type;
171 continue;
172 }
173
[email protected]b7c377e2013-01-15 10:00:39174 // List[Dictionary<key, value_str>]
175 for (size_t i = 0; i < entry_list->GetSize(); ++i) {
skylarceaf50cb2017-02-14 01:16:28176 const base::DictionaryValue* entry = nullptr;
[email protected]b7c377e2013-01-15 10:00:39177 if (!entry_list->GetDictionary(i, &entry) || !entry) {
178 LOG(WARNING) << "Geolocation list value not a Dictionary: " << i;
179 continue;
180 }
skylarceaf50cb2017-02-14 01:16:28181 if (device_type == shill::kGeoWifiAccessPointsProperty) {
182 AddAccessPointFromDict(entry);
183 } else if (device_type == shill::kGeoCellTowersProperty) {
184 AddCellTowerFromDict(entry);
[email protected]b7c377e2013-01-15 10:00:39185 }
[email protected]b7c377e2013-01-15 10:00:39186 }
187 }
188 geolocation_received_time_ = base::Time::Now();
189}
190
skylarceaf50cb2017-02-14 01:16:28191void GeolocationHandler::AddAccessPointFromDict(
192 const base::DictionaryValue* entry) {
193 // Docs: developers.google.com/maps/documentation/business/geolocation
194 WifiAccessPoint wap;
195
196 std::string age_str;
197 if (entry->GetString(shill::kGeoAgeProperty, &age_str)) {
198 int64_t age_ms;
199 if (base::StringToInt64(age_str, &age_ms)) {
200 wap.timestamp =
201 base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms);
202 }
203 }
204 entry->GetString(shill::kGeoMacAddressProperty, &wap.mac_address);
205
206 std::string strength_str;
207 if (entry->GetString(shill::kGeoSignalStrengthProperty, &strength_str))
208 base::StringToInt(strength_str, &wap.signal_strength);
209
210 std::string signal_str;
211 if (entry->GetString(shill::kGeoSignalToNoiseRatioProperty, &signal_str)) {
212 base::StringToInt(signal_str, &wap.signal_to_noise);
213 }
214
215 std::string channel_str;
216 if (entry->GetString(shill::kGeoChannelProperty, &channel_str))
217 base::StringToInt(channel_str, &wap.channel);
218
219 wifi_access_points_.push_back(wap);
220}
221
222void GeolocationHandler::AddCellTowerFromDict(
223 const base::DictionaryValue* entry) {
224 // Docs: developers.google.com/maps/documentation/business/geolocation
Niranjan Kumar4c2ce9f2017-10-03 22:28:51225
226 // Create object.
skylarceaf50cb2017-02-14 01:16:28227 CellTower ct;
228
Niranjan Kumar4c2ce9f2017-10-03 22:28:51229 // Read time fields into object.
skylarceaf50cb2017-02-14 01:16:28230 std::string age_str;
231 if (entry->GetString(shill::kGeoAgeProperty, &age_str)) {
232 int64_t age_ms;
233 if (base::StringToInt64(age_str, &age_ms)) {
234 ct.timestamp =
235 base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms);
236 }
237 }
Niranjan Kumar4c2ce9f2017-10-03 22:28:51238
239 // Read hex fields into object.
240 std::string hex_cell_id;
241 if (entry->GetString(shill::kGeoCellIdProperty, &hex_cell_id)) {
242 ct.ci = HexToDecimal(hex_cell_id);
243 }
244
245 std::string hex_lac;
246 if (entry->GetString(shill::kGeoLocationAreaCodeProperty, &hex_lac)) {
247 ct.lac = HexToDecimal(hex_lac);
248 }
249
250 // Read decimal fields into object.
skylarceaf50cb2017-02-14 01:16:28251 entry->GetString(shill::kGeoMobileCountryCodeProperty, &ct.mcc);
252 entry->GetString(shill::kGeoMobileNetworkCodeProperty, &ct.mnc);
253
Niranjan Kumar4c2ce9f2017-10-03 22:28:51254 // Add new object to vector.
skylarceaf50cb2017-02-14 01:16:28255 cell_towers_.push_back(ct);
256}
257
[email protected]b7c377e2013-01-15 10:00:39258} // namespace chromeos