Geolocation
 Study

Related File and link

GonkGPSGeolocationProvider

header file

  • hardware/gps.h     -> for GpsInterface
  • public:
    • GetSingeton();

BUG 71130 - Add GPS support for gonk

nsGeolocation.cpp


#ifdef MOZ_WIDGET_GONK
#include "GonkGPSGeolocationProvider.h"
#endif

nsresult nsGeolocationService::Init()
{

#ifdef MOZ_WIDGET_GONK
  provider = GonkGPSGeolocationProvider::GetSingleton();
  if (provider)
    mProviders.AppendObject(provider);
#endif

}

GonkGPSGeolocationProvider.h

#include <hardware/gps.h> // for GpsInterface
#include "nsIGeolocationProvider.h"

class GonkGPSGeolocationProvider : public nsIGeolocationProvider
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIGEOLOCATIONPROVIDER
 
  static already_AddRefed<GonkGPSGeolocationProvider> GetSingleton();
  already_AddRefed<nsIGeolocationUpdate> GetLocationCallback();
 
private:
  /* Client should use GetSingleton() to get the provider instance. */
  GonkGPSGeolocationProvider();
  GonkGPSGeolocationProvider(const GonkGPSGeolocationProvider &);
  GonkGPSGeolocationProvider & operator = (const GonkGPSGeolocationProvider &);
  ~GonkGPSGeolocationProvider();
 
  const GpsInterface* GetGPSInterface(); 
  static GonkGPSGeolocationProvider* sSingleton;
 
  bool mStarted;
  const GpsInterface* mGpsInterface;
  nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
};

GonkGPSGeolocationProvider.cpp

static void LocationCallback(GpsLocation* location)
{
  provider = GonkGPSGeolocationProvider::GetSingleton();
  callback = provider->GetLocationCallback();    // mLocationCallback

  nsRefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude,
                                                                                                 location->longitude,
                                                                                                 location->altitude,
                                                                                                 location->accuracy,
                                                                                                 location->accuracy,
                                                                                                 location->bearing,
                                                                                                 location->speed,
                                                                                                 location->timestamp);
  callback->Update(somewhere);
}

static GpsCallbacks gCallbacks = {
  sizeof(GpsCallbacks),
  LocationCallback,
  NULL, /* StatusCallback */
  NULL, /* SvStatusCallback */
  NULL, /* NmeaCallback */
  NULL, /* SetCapabilitiesCallback */
  NULL, /* AcquireWakelockCallback */
  NULL, /* ReleaseWakelockCallback */
  CreateThreadCallback, /* Callback for creating a thread that can call into the JS code*/
};

GonkGPSGeolocationProvider.cpp

GonGPSGeolocationProvider::GonGPSGeolocationProvider()
  :  mStarted(false)
{
  mGpsInterface = GetGPSInterface();
}

GonGPSGeolocationProvider::~GonGPSGeolocationProvider()
{
  Shutdown(); // mGpsInterface->stop(); Then GeolocationUpdate->cleanup();
  sSingleton = NULL;
}

GonkGPSGeolocationProvider::Startup()
{
  mGpsInterface->init(&gCallbacks);
  // Then start(), set_position_mode();
 mStarted = true;
}

GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
{
  mLocationCallback = aCallback;
}

Bug 715788 - Add A-GPS support for gonk

2 AGpsCallbacks

mAGPSRILCallbacks = {
  AGPSRILSetIDCallback,
  // Dispatch a runnable that call “provider->RequestSetID(mFlags)"
  AGPSRILRefLocCallback,
  // Dispatch a runnable that call “provider->SetReferenceLocation()"
  CreateThreadCallback,
};

mAGPSCallbacks = {
  AGPSStatusCallback,
  CreateThreadCallback,
};

AGPSStatusCallback

AGPSStatusCallback
          switch (status->status)
          RequestDataConnection / ReleaseDataConnection

[ RequestDataConnection ]
const nsAdoptingString& apnName = Preferences::GetString("geo.gps.apn.name");
const nsAdoptingString& apnUser = Preferences::GetString("geo.gps.apn.user");
const nsAdoptingString& apnPass = Preferences::GetString("geo.gps.apn.password");

if (apnName && apnUser && apnPass) {
  mRIL->SetupDataCall(1 /* DATACALL_RADIOTECHNOLOGY_GSM */,
  apnName, apnUser, apnPass,
  3 /* DATACALL_AUTH_PAP_OR_CHAP */,
  NS_LITERAL_STRING("IP") /* pdptype */);
}


[ ReleaseDataConnection ]
mRIL->DeactivateDataCall(mCid, NS_LITERAL_STRING("Close SUPL session"));


@Bug 832925 - API changed
mRIL->DeactivateDataCallByType(NS_LITERAL_STRING(“supl"));

Star from ::Init

void GonkGPSGeolocationProvider::Init()
{

  mGpsInterface = GetGPSInterface();
  mGpsInterface->init(&mCallbacks);

  mAGpsInterface->init(&mAGPSCallbacks);
  mAGpsRilInterface->init(&mAGPSRILCallbacks);

  NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS));
}

StartGPS

void GonkGPSGeolocationProvider::StartGPS()
{
  if (mSupportsMSA || mSupportsMSB) {
    SetupAGPS();
  }

  // Setup positionMode : GPS_POSITION_MODE_STANDALONE
  //                                GPS_POSITION_MODE_  MS_ASSISTED / MS_BASED
  // update = kDefaultPeriod, if mSupportScheduling =0

  mGpsInterface->set_position_mode(positionMode,
                                   GPS_POSITION_RECURRENCE_PERIODIC,
                                   update, 0, 0);
  // #if DEBUG_GPS, mGpsInterface->delete_aiding_data(GPS_DELETE_ALL);

  mGpsInterface->start();
}

SetupAGPS

void GonkGPSGeolocationProvider::SetupAGPS()
{
  suplServer = Preferences::GetCString("geo.gps.supl_server");
  suplPort = Preferences::GetInt("geo.gps.supl_port", -1);
  mAGpsInterface->set_server(AGPS_TYPE_SUPL, suplServer.get(), suplPort);

  // Setup network state listener
  nsIInterfaceRequestor* ireq =          
  dom::gonk::SystemWorkerManager::GetInterfaceRequestor();
  mRIL = do_GetInterface(ireq);
  mRIL->RegisterDataCallCallback(this);
}

DataCallStateChanged

// nsIRILDataCallback interface

GonkGPSGeolocationProvider::DataCallStateChanged (nsIRILDataCallInfo* aDataCall)
{
  switch (callState)
    NETWORK_STATE_CONNECTED:
      mAGpsInterface->data_conn_open
    NETWORK_STATE_DISCONNECTED:
      mAGpsInterface->data_conn_closed
}
GonkGPSGeolocationProvider::ReceiveDataCallList (nsIRILDataCallInfo** aDataCalls, PRUint32 aLength)

Bug 1032063 - Call update_network_state and update_network_availability when network state changes for A-GPS

Bug 1032063

NS_IMETHODIMP
GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
                                    const char* aTopic,
                                    const char16_t* aData)
{
#ifdef MOZ_B2G_RIL
           if (!strcmp(aTopic, kNetworkConnStateChangedTopic)){
                    // we can observe network state change here
          }
#endif
}

Bug 977725 - MLS Geolocation seeding GONK Provider

nsGeolocation.cpp

nsGeolocationService::Init()
{
  #ifdef MOZ_WIDGET_GONK
    mProvider = do_CreateInstance(GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID);
  #endif

   ...

  if (Preferences::GetBool("geo.provider.use_mls", false)) {
    mProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
  }

}

GonkGPSGeolocationProvider.cpp

GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
{
  NS_IMETHOD RUN() {
+    provider->mLastGPSDerivedLocationTime = PR_Now();
  }
}

void GonkGPSGeolocationProvider::InjectLocation(double latitude, double longitude, float accuracy)
{
     mGpsInterface->inject_location(latitude, longitude, accuracy);
     // Injects current location from another location provider (typically cell ID). 
     //latitude and longitude are measured in degrees expected accuracy is measured in meters
}

GonkGPSGeolocationProvider.cpp

NS_IMPL_ISUPPORTS1(GonkGPSGeolocationProvider::NetworkLocationUpdate,
                                    nsIGeolocationUpdate)

NS_IMETHODIMP
GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position)
{
  // get coords
  nsCOMPtr<nsIDOMGeoPositionCoords> coords;
  position->GetCoords(getter_AddRefs(coords))

  // if we haven't seen anything the GPS device for 1s,
  // use this location.
  provider->mLocationCallback->Update(position);

  // get lat, lon, acc
  coords->GetLatitude(&lat);
  coords->GetLongitude(&lon);
  coords->GetAccuracy(&acc);
  provider -> InjectLocation(lat, lon, acc)
}

GonkGPSGeolocationProvider.cpp

nsCOMPtr<nsIGeolocationProvider> mNetworkLocationProvider;

GonkGPSGeolocationProvider::Startup()
{
  mNetworkLocationProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
  if (mNetworkLocationProvider) {
    nsresult rv = mNetworkLocationProvider->Startup();
    if (NS_SUCCEEDED(rv)) {
      nsRefPtr<NetworkLocationUpdate> update = new NetworkLocationUpdate();
      mNetworkLocationProvider->Watch(update);
    }
  }
  mLastGPSDerivedLocationTime = 0;
}

GonkGPSGeolocationProvider::Shutdown()
{
  mNetworkLocationProvider->Shutdown();
  mNetworkLocationProvider = nullptr
}

Stumbler for FxOS Planning

Phase 0

  • Bug 1091570 & 1154435
  • Bug Study (Main related)
    • Bug 71130 - Add GPS support for gonk
    • Bug 715788 - Add A-GPS support for gonk
    • Bug 977725 - MLS Geolocation seeding GONK Provider
    • Bug 989692 - Add GPS Debugging Logging
  • Full understanding of GonkGPSGeolocationProvider.cpp/h
  • Date : to 4/30

Phase 1

  • GPS location arrives (1 stumble observation per min, 50KB per day, limited to 250 KB on disk)
       - WiFi Scan & get Cell info.
       - Convert [location, CellTowever, WiFiAp] into JSON
  • An key for enabling and disabling
  • Date : 5/5 ~ 5/22 (3 weeks)
  • Checkpoint : 5/25

Phase 2

  •  Upload
    • when the JSON file reaches (~50KB) // up to 250KB
    • when the JSON file is (~1day) old, // up to 5 days
      • Delete any data older than 5 days
      • convert to gzip
      • Delete uploaded file
  • Date : 5/26 ~ 6/12 (3 weeks)
  • Checkpoint : 6/15

Phase 3

  •  Other case study
    • Store the JSON in a proper position. (security issue)
    • How to reduce cellular data usage. (preferentially upload when connected to WiFi)
    • ...
  • Date : 6/16 ~ ?

Stumbler for FxOS Planning - phase 1

GonkGPSGeolocationProvider::Watch

  • parameter : nsIGeolocationUpdate* aCallback
  • mCallback = aCallback;
  • dom/geolocation/nsGeolocation.cpp
    • nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
      • mProvider->Startup(), mProvider->Watch(this)
  • dom/ipc/ContentChild.cpp
    • ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)

mCallback->Update(mPosition)

GonkGPSGeolocationProvider::LocationCallback

  • Android GPS interface
    • mCallbacks.location_cb = LocationCallback;
    • Callback with location information. Can only be called from a thread created by create_thread_cb.
  • parameter : GpsLocation* location
  • nsRefPtr<nsGeoPosition> somewhere = new nsGeoPosition(..., ..., ...)
  • NS_DispatchToMainThread(new UpdateLocationEvent(somewhere));
    • provider->mLocationCallback->Update (gaia will know the position change)

GonkGPSGeolocationProvider:

NetworkLocationUpdate::Update

  • parameter : nsIDOMGeoPosition *position
  • nsCOMPtr<nsIDOMGeoPositionCoords> coords;
    • position->GetCoords(getter_AddRefs(coords));
  • Use "sLastMLSPosLon , sLastMLSPosLat" to calculate delta.
    • delta > kMinMLSCoordChangeInMeters
      • provider->mLocationCallback->Update(position);
    • delta <= kMinMLSCoordChangeInMeters
      • mLocationCallback->Update(provider->mLastGPSPosition);
  • provider->InjectLocation(lat, lon, acc);

Wifi Scan related

  • /dom/system/NetworkGeolocationProvider.js
    • search "xhr"
    • adb shell logcat | grep -E "WIFI Geo" -i , need to enable "Geolocation output in logcat" from developer menu
  • Ask Henry about how to do wifi scan in C++
  •  
      let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
                                                  xhr.response.location.lng,
                                                  xhr.response.accuracy);

      this.notifyListener("update", [newLocation]);

WIFI GEO LOG

Plan

  • Add a dump function in "GonkGPSGeolocationProvider::LocationCallback"
    • One day a file (Max:50KB). Need to delete old data.
    • (My proposal-1) One day a folder. Check the folder size.
    • (My proposal-2) One file less than 12.5KB. So there should be less than 4 file a day.
  • nsFileStreams - OutputStreams or InputStream
  • nsIFile API reference

Date-1.json

Date-2.json

Date-3.json

Date-4.json

All files are less than "12.5 KB"

Date-1.json

Date-2.json

Date-3.json

Date-4.json

Date-1.json

Remove

Rename

Rename

Rename

When Data-4.json is more than 12.5 KB

Title Text

alphan@alphan-BM6875-BM6675-BP6375:~/tools/flash_tool/B2G-flash-tool/pvt$ adb shell logcat

I/GeckoConsole(17391): *** WIFI GEO: server returned status: 200 --> {"location":{"lat":25.0326761,"lng":121.5662895},"accuracy":100}
I/Gecko   (17391): *** WIFI GEO: server returned status: 200 --> {"location":{"lat":25.0326761,"lng":121.5662895},"accuracy":100}
I/GeckoConsole(17391): geo: Using MLS, GPS age:1431067501.553000s, MLS Delta:0.000000m
I/GeckoConsole(17391): geo: injecting location (25.032676, 121.566289) accuracy: 100.000000

 

 

Get Cell Tower Info

  • Ref : 實作 nsIMobileConnectionCallback
  • https://dxr.mozilla.org/mozilla-central/source/dom/mobileconnection/MobileConnectionCallback.h
  • https://dxr.mozilla.org/mozilla-central/source/dom/mobileconnection/MobileConnectionCallback.cpp
interface nsIMobileConnection : nsISupports
{
  /**
   * Request all of the current cell information known to the radio, including
   * neighboring cells.
   *
   * @param callback
   *        Called when request is finished. See nsICellInfoListCallback
   *        for details.	
   */
  void getCellInfoList(in nsICellInfoListCallback callback);
}

Get Cell Tower Info

  • https://dxr.mozilla.org/mozilla-central/source/dom/mobileconnection/MobileConnectionCallback.cpp#85
MobileConnection::GetSupportedNetworkTypes(nsTArray<MobileNetworkType>& aTypes) const

aTypes.AppendElement(static_cast<MobileNetworkType>(type));

Stumbler for FxOS Planning - phase 2

Geosubmit

  • http://mozilla-ichnaea.readthedocs.org/en/latest/api/index.html#geosubmit
  • [purpose]  Submit data about nearby cell and WiFi networks
  • Geosubmit requests are submitted using a POST request to the URL:
    • https://location.services.mozilla.com/v1/geosubmit?key=<API_KEY>
  • Geosubmit requests are submitted using a POST request with a JSON body. (as stumble-feeding-1.json)

Http Request

  • Header Reference:
    • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
    • (Hanno Schlichting [:hannosch])The geosubmit endpoint accepts all of this data in gzip, if you set the HTTP header to "Content-Encoding: gzip". Depending on when and how things get stored to the local disk, you might be able to store data as gzip locally as well, and at transmission time, just stream the local file into the HTTPS connection.
  • Useful Firefox Addon
    • https://addons.mozilla.org/en-us/firefox/addon/modify-headers/
    • Help to modify header to simulate the results of different headers.

Sample Code in Gecko

#include "nsIXMLHttpRequest.h" 

 nsCOMPtr<nsIXMLHttpRequest> mXhr; 

  if (mXhr != nullptr) { 
    mXhr->SlowAbort(); 
    mXhr = nullptr; 
  } 

  nsresult rv; 
  mXhr = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv); 

  NS_NAMED_LITERAL_CSTRING(getString, "GET"); 
  const nsAString& empty = EmptyString(); 

  nsCOMPtr<nsIScriptSecurityManager> secman = 
    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); 
  NS_ENSURE_SUCCESS(rv, rv); 

  nsCOMPtr<nsIPrincipal> systemPrincipal; 
  rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); 
  NS_ENSURE_SUCCESS(rv, rv); 

  rv = mXhr->Init(systemPrincipal, nullptr, nullptr, nullptr); 
  NS_ENSURE_SUCCESS(rv, rv);

Sample Code in Gecko

  NS_NAMED_LITERAL_CSTRING(url, "你想連的網址"); 
  rv = mXhr->Open(getString, url, false, empty, empty); 
  NS_ENSURE_SUCCESS(rv, rv); 

  mXhr->SetRequestHeader(NS_LITERAL_CSTRING("你設定的header"), NS_LITERAL_CSTRING("application/json")); 
  mXhr->SetMozBackgroundRequest(true); 

  rv = mXhr->Send(nullptr); 

Related Listeners we can add

/*
 *    Since xmlHttpRequest is an ansync call, we can add the following listeners
 */

  // 抓好資料時的 handler (你應該不用 listen 這個) 
  nsCOMPtr<mozilla::dom::EventTarget> target(do_QueryInterface(mXhr)); 
  rv = target->AddEventListener(NS_LITERAL_STRING("load"), this, false); 
  NS_ENSURE_SUCCESS(rv, rv); 

  // onerror 
  rv = target->AddEventListener(NS_LITERAL_STRING("error"), this, false); 
  NS_ENSURE_SUCCESS(rv, rv); 

How/Where to Upload

  • API key?
    • This gets set as part of the configure process, via a --with-mozilla-api-keyfile argument.
    • https://dxr.mozilla.org/mozilla-central/source/configure.in#4009
  • geo.wifi.url
    • https://dxr.mozilla.org/mozilla-central/source/b2g/app/b2g.js#203
    • used in https://dxr.mozilla.org/mozilla-central/source/dom/system/NetworkGeolocationProvider.js#489
    • let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");

HTTP Methods

  • HTTP Methods: GET vs. POST
    • http://www.w3schools.com/tags/ref_httpmethods.asp
  • Get
    • Requests data from a specified resource
    • Remain in browser history
    • Less secure comapred to POST
  • POST
    • Submits data to be processed to a specified resource
    • Not saved in browser history

Gecko Implementation

  • Timeout
    • SetTimeout(uint32_t aTimeout, ErrorResult& aRv);
    • Set a timeout of 60 seconds
    • We should retry the upload later.
  • ...
    • Requests data from a specified resource
  • .....

Stumbler for FxOS phase 1 - Architecture (Draft)

Architecture-1

  • Entry point
  • GonkGPSGeolocationProvider::LocationCallback
    • nsRefPtr<StumblerInfo> sRequestCallback = new StumblerInfo(somewhere);
    • 3 seconds AND 30 meters must be exceeded in order to stumble
    • trigger runnable(RequestCellInfoEvent) to main thread.
      • connection->GetCellInfoList(mRequestCallback);
      • wifi->GetWifiScanResults(mRequestCallback);

Architecture-2

  • StumblerInfo
  • Inherbit
    • "nsIcellInfoListCallback"
      • NotifyGetCellInfoList : callback with the number of cellinfo (count) and the array of cellinfo (aCellInfos)
      • NotifyGetCellInfoListFailed
    • "nsIWifiScanResultsReady"
      • Onready : callback with the number of WifiScanResult (count) and the array of wifinfo (results)
      • Onfailure

Architecture-3

  • StumblerInfo
    • mCellinfo : Save valid cellinfo into this nsTArray
    • mWifiDesc : wifi AP info needed by stumble.
    • mPosition : GPS location from GPS
    • CelInfoReady: To know if cellinfo is ready
    • WifiInfoReady:To know if cellinfo is ready
      • Call "DumpStumblerInfo()" when "CellInfoRead" and "WifiInfoReady" are ready.
        • Dump all needed information (location, celltower, wifi ap) into a string and post a task( DumpStumblerFeedingEvent(desc) ) to IO thread.

Architecture-4

  • DumpStumblerFeedingEvent
    • Inherit Task
    • mDesc : the information we need to write to the stumble
    • Run() :
      • Check the existing file to see what file we can write.
      • If needed, we call "RemoveOldestFile" to remove the oldest one.
      • Dump all info into ".gz" files
    • RemoveOldestFile(int FileNum)

Date-1.json.gz

Date-2.json.gz

Date-3.json.gz

Date-4.json.gz

All files are less than "12.5 KB"

Date-1.json.gz

Date-1.json.gz

Remove

Rename

Rename

Rename

When Data-4.json is more than 12.5 KB

Date-4.json.gz

Date-3.json.gz

Date-2.json.gz

#define OLDEST_FILE_NUMBER 1
#define MAXFILENUM 4
#define MAXFILESIZE_KB 12.5 * 1024

feeding-1.json.gz

Date-1.json.gz

Move to Upload List

Rename

Rename

Rename

When Data-4.json is more than 12.5 KB

feeding-4.json.gz

feeding-3.json.gz

feeding-2.json.gz

upload01.json.gz

Move to Upload List

upload02.json.gz

upload03.json.gz

upload04.json.gz

#define OLDEST_FILE_NUMBER 1
#define MAXUPLOADFILENUM 15
#define MAXFILESIZE_KB 12.5 * 1024

Stumbler on B2G

By Alphan Chen

Stumbler on B2G

  • 1,230