summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/mozstumbler/MozStumbler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/gonk/mozstumbler/MozStumbler.cpp')
-rw-r--r--dom/system/gonk/mozstumbler/MozStumbler.cpp426
1 files changed, 426 insertions, 0 deletions
diff --git a/dom/system/gonk/mozstumbler/MozStumbler.cpp b/dom/system/gonk/mozstumbler/MozStumbler.cpp
new file mode 100644
index 000000000..61e09e705
--- /dev/null
+++ b/dom/system/gonk/mozstumbler/MozStumbler.cpp
@@ -0,0 +1,426 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MozStumbler.h"
+#include "nsDataHashtable.h"
+#include "nsGeoPosition.h"
+#include "nsNetCID.h"
+#include "nsPrintfCString.h"
+#include "StumblerLogging.h"
+#include "WriteStumbleOnThread.h"
+#include "../GeolocationUtil.h"
+
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIMobileConnectionInfo.h"
+#include "nsIMobileConnectionService.h"
+#include "nsIMobileCellInfo.h"
+#include "nsIMobileNetworkInfo.h"
+#include "nsINetworkInterface.h"
+#include "nsIRadioInterfaceLayer.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+
+NS_IMPL_ISUPPORTS(StumblerInfo, nsICellInfoListCallback, nsIWifiScanResultsReady)
+
+class RequestCellInfoEvent : public Runnable {
+public:
+ RequestCellInfoEvent(StumblerInfo *callback)
+ : mRequestCallback(callback)
+ {}
+
+ NS_IMETHOD Run() override {
+ MOZ_ASSERT(NS_IsMainThread());
+ // Get Cell Info
+ nsCOMPtr<nsIMobileConnectionService> service =
+ do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
+
+ if (!service) {
+ STUMBLER_ERR("Stumbler-can not get nsIMobileConnectionService \n");
+ return NS_OK;
+ }
+ nsCOMPtr<nsIMobileConnection> connection;
+ uint32_t numberOfRilServices = 1, cellInfoNum = 0;
+
+ service->GetNumItems(&numberOfRilServices);
+ for (uint32_t rilNum = 0; rilNum < numberOfRilServices; rilNum++) {
+ service->GetItemByServiceId(rilNum /* Client Id */, getter_AddRefs(connection));
+ if (!connection) {
+ STUMBLER_ERR("Stumbler-can not get nsIMobileConnection by ServiceId %d \n", rilNum);
+ } else {
+ cellInfoNum++;
+ connection->GetCellInfoList(mRequestCallback);
+ }
+ }
+ mRequestCallback->SetCellInfoResponsesExpected(cellInfoNum);
+
+ // Get Wifi AP Info
+ nsCOMPtr<nsIInterfaceRequestor> ir = do_GetService("@mozilla.org/telephony/system-worker-manager;1");
+ nsCOMPtr<nsIWifi> wifi = do_GetInterface(ir);
+ if (!wifi) {
+ mRequestCallback->SetWifiInfoResponseReceived();
+ STUMBLER_ERR("Stumbler-can not get nsIWifi interface\n");
+ return NS_OK;
+ }
+ wifi->GetWifiScanResults(mRequestCallback);
+ return NS_OK;
+ }
+private:
+ RefPtr<StumblerInfo> mRequestCallback;
+};
+
+void
+MozStumble(nsGeoPosition* position)
+{
+ if (WriteStumbleOnThread::IsFileWaitingForUpload()) {
+ nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+ MOZ_ASSERT(target);
+ // Knowing that file is waiting to upload, and no collection will take place,
+ // just trigger the thread with an empty string.
+ nsCOMPtr<nsIRunnable> event = new WriteStumbleOnThread(EmptyCString());
+ target->Dispatch(event, NS_DISPATCH_NORMAL);
+ return;
+ }
+
+ nsCOMPtr<nsIDOMGeoPositionCoords> coords;
+ position->GetCoords(getter_AddRefs(coords));
+ if (!coords) {
+ return;
+ }
+
+ double latitude, longitude;
+ coords->GetLatitude(&latitude);
+ coords->GetLongitude(&longitude);
+
+ const double kMinChangeInMeters = 30;
+ static int64_t lastTime_ms = 0;
+ static double sLastLat = 0;
+ static double sLastLon = 0;
+ double delta = -1.0;
+ int64_t timediff = (PR_Now() / PR_USEC_PER_MSEC) - lastTime_ms;
+
+ if (0 != sLastLon || 0 != sLastLat) {
+ delta = CalculateDeltaInMeter(latitude, longitude, sLastLat, sLastLon);
+ }
+ STUMBLER_DBG("Stumbler-Location. [%f , %f] time_diff:%lld, delta : %f\n",
+ longitude, latitude, timediff, delta);
+
+ // Consecutive GPS locations must be 30 meters and 3 seconds apart
+ if (lastTime_ms == 0 || ((timediff >= STUMBLE_INTERVAL_MS) && (delta > kMinChangeInMeters))){
+ lastTime_ms = (PR_Now() / PR_USEC_PER_MSEC);
+ sLastLat = latitude;
+ sLastLon = longitude;
+ RefPtr<StumblerInfo> requestCallback = new StumblerInfo(position);
+ RefPtr<RequestCellInfoEvent> runnable = new RequestCellInfoEvent(requestCallback);
+ NS_DispatchToMainThread(runnable);
+ } else {
+ STUMBLER_DBG("Stumbler-GPS locations less than 30 meters and 3 seconds. Ignore!\n");
+ }
+}
+
+void
+StumblerInfo::SetWifiInfoResponseReceived()
+{
+ mIsWifiInfoResponseReceived = true;
+
+ if (mIsWifiInfoResponseReceived && mCellInfoResponsesReceived == mCellInfoResponsesExpected) {
+ STUMBLER_DBG("Call DumpStumblerInfo from SetWifiInfoResponseReceived\n");
+ DumpStumblerInfo();
+ }
+}
+
+void
+StumblerInfo::SetCellInfoResponsesExpected(uint8_t count)
+{
+ mCellInfoResponsesExpected = count;
+ STUMBLER_DBG("SetCellInfoNum (%d)\n", count);
+
+ if (mIsWifiInfoResponseReceived && mCellInfoResponsesReceived == mCellInfoResponsesExpected) {
+ STUMBLER_DBG("Call DumpStumblerInfo from SetCellInfoResponsesExpected\n");
+ DumpStumblerInfo();
+ }
+}
+
+
+#define TEXT_LAT NS_LITERAL_CSTRING("latitude")
+#define TEXT_LON NS_LITERAL_CSTRING("longitude")
+#define TEXT_ACC NS_LITERAL_CSTRING("accuracy")
+#define TEXT_ALT NS_LITERAL_CSTRING("altitude")
+#define TEXT_ALTACC NS_LITERAL_CSTRING("altitudeAccuracy")
+#define TEXT_HEAD NS_LITERAL_CSTRING("heading")
+#define TEXT_SPD NS_LITERAL_CSTRING("speed")
+
+nsresult
+StumblerInfo::LocationInfoToString(nsACString& aLocDesc)
+{
+ nsCOMPtr<nsIDOMGeoPositionCoords> coords;
+ mPosition->GetCoords(getter_AddRefs(coords));
+ if (!coords) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsDataHashtable<nsCStringHashKey, double> info;
+
+ double val;
+ coords->GetLatitude(&val);
+ info.Put(TEXT_LAT, val);
+ coords->GetLongitude(&val);
+ info.Put(TEXT_LON, val);
+ coords->GetAccuracy(&val);
+ info.Put(TEXT_ACC, val);
+ coords->GetAltitude(&val);
+ info.Put(TEXT_ALT, val);
+ coords->GetAltitudeAccuracy(&val);
+ info.Put(TEXT_ALTACC, val);
+ coords->GetHeading(&val);
+ info.Put(TEXT_HEAD, val);
+ coords->GetSpeed(&val);
+ info.Put(TEXT_SPD, val);
+
+ for (auto it = info.Iter(); !it.Done(); it.Next()) {
+ const nsACString& key = it.Key();
+ val = it.UserData();
+ if (!IsNaN(val)) {
+ aLocDesc += nsPrintfCString("\"%s\":%f,", key.BeginReading(), val);
+ }
+ }
+
+ aLocDesc += nsPrintfCString("\"timestamp\":%lld,", PR_Now() / PR_USEC_PER_MSEC).get();
+ return NS_OK;
+}
+
+#define TEXT_RADIOTYPE NS_LITERAL_CSTRING("radioType")
+#define TEXT_MCC NS_LITERAL_CSTRING("mobileCountryCode")
+#define TEXT_MNC NS_LITERAL_CSTRING("mobileNetworkCode")
+#define TEXT_LAC NS_LITERAL_CSTRING("locationAreaCode")
+#define TEXT_CID NS_LITERAL_CSTRING("cellId")
+#define TEXT_PSC NS_LITERAL_CSTRING("psc")
+#define TEXT_STRENGTH_ASU NS_LITERAL_CSTRING("asu")
+#define TEXT_STRENGTH_DBM NS_LITERAL_CSTRING("signalStrength")
+#define TEXT_REGISTERED NS_LITERAL_CSTRING("serving")
+#define TEXT_TIMEING_ADVANCE NS_LITERAL_CSTRING("timingAdvance")
+
+template <class T> void
+ExtractCommonNonCDMACellInfoItems(nsCOMPtr<T>& cell, nsDataHashtable<nsCStringHashKey, int32_t>& info)
+{
+ int32_t mcc, mnc, cid, sig;
+
+ cell->GetMcc(&mcc);
+ cell->GetMnc(&mnc);
+ cell->GetCid(&cid);
+ cell->GetSignalStrength(&sig);
+
+ info.Put(TEXT_MCC, mcc);
+ info.Put(TEXT_MNC, mnc);
+ info.Put(TEXT_CID, cid);
+ info.Put(TEXT_STRENGTH_ASU, sig);
+}
+
+void
+StumblerInfo::CellNetworkInfoToString(nsACString& aCellDesc)
+{
+ aCellDesc += "\"cellTowers\": [";
+
+ for (uint32_t idx = 0; idx < mCellInfo.Length() ; idx++) {
+ const char* radioType = 0;
+ int32_t type;
+ mCellInfo[idx]->GetType(&type);
+ bool registered;
+ mCellInfo[idx]->GetRegistered(&registered);
+ if (idx) {
+ aCellDesc += ",{";
+ } else {
+ aCellDesc += "{";
+ }
+
+ STUMBLER_DBG("type=%d\n", type);
+
+ nsDataHashtable<nsCStringHashKey, int32_t> info;
+ info.Put(TEXT_REGISTERED, registered);
+
+ if(type == nsICellInfo::CELL_INFO_TYPE_GSM) {
+ radioType = "gsm";
+ nsCOMPtr<nsIGsmCellInfo> gsmCellInfo = do_QueryInterface(mCellInfo[idx]);
+ ExtractCommonNonCDMACellInfoItems(gsmCellInfo, info);
+ int32_t lac;
+ gsmCellInfo->GetLac(&lac);
+ info.Put(TEXT_LAC, lac);
+ } else if (type == nsICellInfo::CELL_INFO_TYPE_WCDMA) {
+ radioType = "wcdma";
+ nsCOMPtr<nsIWcdmaCellInfo> wcdmaCellInfo = do_QueryInterface(mCellInfo[idx]);
+ ExtractCommonNonCDMACellInfoItems(wcdmaCellInfo, info);
+ int32_t lac, psc;
+ wcdmaCellInfo->GetLac(&lac);
+ wcdmaCellInfo->GetPsc(&psc);
+ info.Put(TEXT_LAC, lac);
+ info.Put(TEXT_PSC, psc);
+ } else if (type == nsICellInfo::CELL_INFO_TYPE_CDMA) {
+ radioType = "cdma";
+ nsCOMPtr<nsICdmaCellInfo> cdmaCellInfo = do_QueryInterface(mCellInfo[idx]);
+ int32_t mnc, lac, cid, sig;
+ cdmaCellInfo->GetSystemId(&mnc);
+ cdmaCellInfo->GetNetworkId(&lac);
+ cdmaCellInfo->GetBaseStationId(&cid);
+ info.Put(TEXT_MNC, mnc);
+ info.Put(TEXT_LAC, lac);
+ info.Put(TEXT_CID, cid);
+
+ cdmaCellInfo->GetEvdoDbm(&sig);
+ if (sig < 0 || sig == nsICellInfo::UNKNOWN_VALUE) {
+ cdmaCellInfo->GetCdmaDbm(&sig);
+ }
+ if (sig > -1 && sig != nsICellInfo::UNKNOWN_VALUE) {
+ sig *= -1;
+ info.Put(TEXT_STRENGTH_DBM, sig);
+ }
+ } else if (type == nsICellInfo::CELL_INFO_TYPE_LTE) {
+ radioType = "lte";
+ nsCOMPtr<nsILteCellInfo> lteCellInfo = do_QueryInterface(mCellInfo[idx]);
+ ExtractCommonNonCDMACellInfoItems(lteCellInfo, info);
+ int32_t lac, timingAdvance, pcid, rsrp;
+ lteCellInfo->GetTac(&lac);
+ lteCellInfo->GetTimingAdvance(&timingAdvance);
+ lteCellInfo->GetPcid(&pcid);
+ lteCellInfo->GetRsrp(&rsrp);
+ info.Put(TEXT_LAC, lac);
+ info.Put(TEXT_TIMEING_ADVANCE, timingAdvance);
+ info.Put(TEXT_PSC, pcid);
+ if (rsrp != nsICellInfo::UNKNOWN_VALUE) {
+ info.Put(TEXT_STRENGTH_DBM, rsrp * -1);
+ }
+ }
+
+ aCellDesc += nsPrintfCString("\"%s\":\"%s\"", TEXT_RADIOTYPE.get(), radioType);
+ for (auto it = info.Iter(); !it.Done(); it.Next()) {
+ const nsACString& key = it.Key();
+ int32_t value = it.UserData();
+ if (value != nsICellInfo::UNKNOWN_VALUE) {
+ aCellDesc += nsPrintfCString(",\"%s\":%d", key.BeginReading(), value);
+ }
+ }
+
+ aCellDesc += "}";
+ }
+ aCellDesc += "]";
+}
+
+void
+StumblerInfo::DumpStumblerInfo()
+{
+ if (!mIsWifiInfoResponseReceived || mCellInfoResponsesReceived != mCellInfoResponsesExpected) {
+ STUMBLER_DBG("CellInfoReceived=%d (Expected=%d), WifiInfoResponseReceived=%d\n",
+ mCellInfoResponsesReceived, mCellInfoResponsesExpected, mIsWifiInfoResponseReceived);
+ return;
+ }
+ mIsWifiInfoResponseReceived = false;
+ mCellInfoResponsesReceived = 0;
+
+ nsAutoCString desc;
+ nsresult rv = LocationInfoToString(desc);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ STUMBLER_ERR("LocationInfoToString failed, skip this dump");
+ return;
+ }
+
+ CellNetworkInfoToString(desc);
+ desc += mWifiDesc;
+
+ STUMBLER_DBG("dispatch write event to thread\n");
+ nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+ MOZ_ASSERT(target);
+
+ nsCOMPtr<nsIRunnable> event = new WriteStumbleOnThread(desc);
+ target->Dispatch(event, NS_DISPATCH_NORMAL);
+}
+
+NS_IMETHODIMP
+StumblerInfo::NotifyGetCellInfoList(uint32_t count, nsICellInfo** aCellInfos)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ STUMBLER_DBG("There are %d cellinfo in the result\n", count);
+
+ for (uint32_t i = 0; i < count; i++) {
+ mCellInfo.AppendElement(aCellInfos[i]);
+ }
+ mCellInfoResponsesReceived++;
+ DumpStumblerInfo();
+ return NS_OK;
+}
+
+NS_IMETHODIMP StumblerInfo::NotifyGetCellInfoListFailed(const nsAString& error)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mCellInfoResponsesReceived++;
+ STUMBLER_ERR("NotifyGetCellInfoListFailedm CellInfoReadyNum=%d, mCellInfoResponsesExpected=%d, mIsWifiInfoResponseReceived=%d",
+ mCellInfoResponsesReceived, mCellInfoResponsesExpected, mIsWifiInfoResponseReceived);
+ DumpStumblerInfo();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StumblerInfo::Onready(uint32_t count, nsIWifiScanResult** results)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ STUMBLER_DBG("There are %d wifiAPinfo in the result\n",count);
+
+ mWifiDesc += ",\"wifiAccessPoints\": [";
+ bool firstItem = true;
+ for (uint32_t i = 0 ; i < count ; i++) {
+ nsString ssid;
+ results[i]->GetSsid(ssid);
+ if (ssid.IsEmpty()) {
+ STUMBLER_DBG("no ssid, skip this AP\n");
+ continue;
+ }
+
+ if (ssid.Length() >= 6) {
+ if (StringEndsWith(ssid, NS_LITERAL_STRING("_nomap"))) {
+ STUMBLER_DBG("end with _nomap. skip this AP(ssid :%s)\n", ssid.get());
+ continue;
+ }
+ }
+
+ if (firstItem) {
+ mWifiDesc += "{";
+ firstItem = false;
+ } else {
+ mWifiDesc += ",{";
+ }
+
+ // mac address
+ nsString bssid;
+ results[i]->GetBssid(bssid);
+ // 00:00:00:00:00:00 --> 000000000000
+ bssid.StripChars(":");
+ mWifiDesc += "\"macAddress\":\"";
+ mWifiDesc += NS_ConvertUTF16toUTF8(bssid);
+
+ uint32_t signal;
+ results[i]->GetSignalStrength(&signal);
+ mWifiDesc += "\",\"signalStrength\":";
+ mWifiDesc.AppendInt(signal);
+
+ mWifiDesc += "}";
+ }
+ mWifiDesc += "]";
+
+ mIsWifiInfoResponseReceived = true;
+ DumpStumblerInfo();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+StumblerInfo::Onfailure()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ STUMBLER_ERR("GetWifiScanResults Onfailure\n");
+ mIsWifiInfoResponseReceived = true;
+ DumpStumblerInfo();
+ return NS_OK;
+}
+