tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WindowsLocationProvider.cpp (10662B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "WindowsLocationProvider.h"
      8 
      9 #include "GeolocationPosition.h"
     10 #include "MLSFallback.h"
     11 #include "WindowsLocationParent.h"
     12 #include "mozilla/Logging.h"
     13 #include "mozilla/dom/GeolocationPositionErrorBinding.h"
     14 #include "mozilla/dom/WindowsUtilsParent.h"
     15 #include "mozilla/glean/DomGeolocationMetrics.h"
     16 #include "mozilla/ipc/UtilityProcessManager.h"
     17 #include "mozilla/ipc/UtilityProcessSandboxing.h"
     18 #include "nsComponentManagerUtils.h"
     19 #include "prtime.h"
     20 
     21 namespace mozilla::dom {
     22 
     23 LazyLogModule gWindowsLocationProviderLog("WindowsLocationProvider");
     24 #define LOG(...) \
     25  MOZ_LOG(gWindowsLocationProviderLog, LogLevel::Debug, (__VA_ARGS__))
     26 
     27 class MLSUpdate : public nsIGeolocationUpdate {
     28 public:
     29  NS_DECL_ISUPPORTS
     30  NS_DECL_NSIGEOLOCATIONUPDATE
     31  explicit MLSUpdate(nsIGeolocationUpdate* aCallback) : mCallback(aCallback) {}
     32 
     33 private:
     34  nsCOMPtr<nsIGeolocationUpdate> mCallback;
     35  virtual ~MLSUpdate() {}
     36 };
     37 
     38 NS_IMPL_ISUPPORTS(MLSUpdate, nsIGeolocationUpdate);
     39 
     40 NS_IMETHODIMP
     41 MLSUpdate::Update(nsIDOMGeoPosition* aPosition) {
     42  if (!mCallback) {
     43    return NS_ERROR_FAILURE;
     44  }
     45 
     46  nsCOMPtr<nsIDOMGeoPositionCoords> coords;
     47  aPosition->GetCoords(getter_AddRefs(coords));
     48  if (!coords) {
     49    return NS_ERROR_FAILURE;
     50  }
     51  return mCallback->Update(aPosition);
     52 }
     53 NS_IMETHODIMP
     54 MLSUpdate::NotifyError(uint16_t aError) {
     55  if (!mCallback) {
     56    return NS_ERROR_FAILURE;
     57  }
     58  nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
     59  return callback->NotifyError(aError);
     60 }
     61 
     62 NS_IMPL_ISUPPORTS(WindowsLocationProvider, nsIGeolocationProvider)
     63 
     64 WindowsLocationProvider::WindowsLocationProvider() {
     65  LOG("WindowsLocationProvider::WindowsLocationProvider(%p)", this);
     66  MOZ_ASSERT(XRE_IsParentProcess());
     67  MaybeCreateLocationActor();
     68 }
     69 
     70 WindowsLocationProvider::~WindowsLocationProvider() {
     71  LOG("WindowsLocationProvider::~WindowsLocationProvider(%p,%p,%p)", this,
     72      mActor.get(), mActorPromise.get());
     73  Send__delete__();
     74  ReleaseUtilityProcess();
     75  CancelMLSProvider();
     76 }
     77 
     78 void WindowsLocationProvider::MaybeCreateLocationActor() {
     79  LOG("WindowsLocationProvider::MaybeCreateLocationActor(%p)", this);
     80  if (mActor || mActorPromise) {
     81    return;
     82  }
     83 
     84  auto utilityProc = mozilla::ipc::UtilityProcessManager::GetSingleton();
     85  MOZ_ASSERT(utilityProc);
     86 
     87  // Create a PWindowsLocation actor in the Windows utility process.
     88  // This will attempt to launch the process if it doesn't already exist.
     89  RefPtr<WindowsLocationProvider> self = this;
     90  auto wuPromise = utilityProc->GetWindowsUtilsPromise();
     91  mActorPromise = wuPromise->Then(
     92      GetCurrentSerialEventTarget(), __func__,
     93      [self](RefPtr<WindowsUtilsParent> const& wup) {
     94        self->mActorPromise = nullptr;
     95        auto actor = MakeRefPtr<WindowsLocationParent>(self);
     96        if (!wup->SendPWindowsLocationConstructor(actor)) {
     97          LOG("WindowsLocationProvider(%p) SendPWindowsLocationConstructor "
     98              "failed",
     99              self.get());
    100          actor->DetachFromLocationProvider();
    101          self->mActor = nullptr;
    102          return WindowsLocationPromise::CreateAndReject(false, __func__);
    103        }
    104        LOG("WindowsLocationProvider connected to actor (%p,%p,%p)", self.get(),
    105            self->mActor.get(), self->mActorPromise.get());
    106        self->mActor = actor;
    107        return WindowsLocationPromise::CreateAndResolve(self->mActor, __func__);
    108      },
    109      [self](::mozilla::ipc::LaunchError&& err) {
    110        LOG("WindowsLocationProvider failed to connect to actor: [%s, %lX] "
    111            "(%p,%p,%p)",
    112            err.FunctionName().get(), err.ErrorCode(), self.get(),
    113            self->mActor.get(), self->mActorPromise.get());
    114        self->mActorPromise = nullptr;
    115        return WindowsLocationPromise::CreateAndReject(false, __func__);
    116      });
    117 
    118  if (mActor) {
    119    // Utility process already existed and mActorPromise was resolved
    120    // immediately.
    121    mActorPromise = nullptr;
    122  }
    123 }
    124 
    125 void WindowsLocationProvider::ReleaseUtilityProcess() {
    126  LOG("WindowsLocationProvider::ReleaseUtilityProcess(%p)", this);
    127  auto utilityProc = mozilla::ipc::UtilityProcessManager::GetIfExists();
    128  if (utilityProc) {
    129    utilityProc->ReleaseWindowsUtils();
    130  }
    131 }
    132 
    133 template <typename Fn>
    134 bool WindowsLocationProvider::WhenActorIsReady(Fn&& fn) {
    135  if (mActor) {
    136    return fn(mActor);
    137  }
    138 
    139  if (mActorPromise) {
    140    mActorPromise->Then(
    141        GetCurrentSerialEventTarget(), __func__,
    142        [fn](const RefPtr<WindowsLocationParent>& actor) {
    143          (void)fn(actor.get());
    144          return actor;
    145        },
    146        [](bool) { return false; });
    147    return true;
    148  }
    149 
    150  // The remote process failed to start.
    151  return false;
    152 }
    153 
    154 bool WindowsLocationProvider::SendStartup() {
    155  LOG("WindowsLocationProvider::SendStartup(%p)", this);
    156  MaybeCreateLocationActor();
    157  return WhenActorIsReady(
    158      [](WindowsLocationParent* actor) { return actor->SendStartup(); });
    159 }
    160 
    161 bool WindowsLocationProvider::SendRegisterForReport(
    162    nsIGeolocationUpdate* aCallback) {
    163  LOG("WindowsLocationProvider::SendRegisterForReport(%p)", this);
    164  RefPtr<WindowsLocationProvider> self = this;
    165  RefPtr<nsIGeolocationUpdate> cb = aCallback;
    166  return WhenActorIsReady([self, cb](WindowsLocationParent* actor) {
    167    MOZ_ASSERT(!self->mCallback);
    168    if (actor->SendRegisterForReport()) {
    169      self->mCallback = cb;
    170      return true;
    171    }
    172    return false;
    173  });
    174 }
    175 
    176 bool WindowsLocationProvider::SendUnregisterForReport() {
    177  LOG("WindowsLocationProvider::SendUnregisterForReport(%p)", this);
    178  RefPtr<WindowsLocationProvider> self = this;
    179  return WhenActorIsReady([self](WindowsLocationParent* actor) {
    180    self->mCallback = nullptr;
    181    if (actor->SendUnregisterForReport()) {
    182      return true;
    183    }
    184    return false;
    185  });
    186 }
    187 
    188 bool WindowsLocationProvider::SendSetHighAccuracy(bool aEnable) {
    189  LOG("WindowsLocationProvider::SendSetHighAccuracy(%p)", this);
    190  return WhenActorIsReady([aEnable](WindowsLocationParent* actor) {
    191    return actor->SendSetHighAccuracy(aEnable);
    192  });
    193 }
    194 
    195 bool WindowsLocationProvider::Send__delete__() {
    196  LOG("WindowsLocationProvider::Send__delete__(%p)", this);
    197  return WhenActorIsReady([self = RefPtr{this}](WindowsLocationParent*) {
    198    if (WindowsLocationParent::Send__delete__(self->mActor)) {
    199      if (self->mActor) {
    200        self->mActor->DetachFromLocationProvider();
    201        self->mActor = nullptr;
    202      }
    203      return true;
    204    }
    205    return false;
    206  });
    207 }
    208 
    209 void WindowsLocationProvider::RecvUpdate(
    210    RefPtr<nsIDOMGeoPosition> aGeoPosition) {
    211  LOG("WindowsLocationProvider::RecvUpdate(%p)", this);
    212  if (!mCallback) {
    213    return;
    214  }
    215 
    216  mCallback->Update(aGeoPosition.get());
    217 
    218  if (!mEverUpdated) {
    219    mEverUpdated = true;
    220    // Saw signal without MLS fallback
    221    glean::geolocation::fallback
    222        .EnumGet(glean::geolocation::FallbackLabel::eNone)
    223        .Add();
    224  }
    225 }
    226 
    227 void WindowsLocationProvider::RecvFailed(uint16_t err) {
    228  LOG("WindowsLocationProvider::RecvFailed(%p)", this);
    229  // Cannot get current location at this time.  We use MLS instead.
    230  if (mMLSProvider || !mCallback) {
    231    return;
    232  }
    233 
    234  if (NS_SUCCEEDED(CreateAndWatchMLSProvider(mCallback))) {
    235    return;
    236  }
    237 
    238  // No ILocation and no MLS, so we have failed completely.
    239  // We keep strong references to objects that we need to guarantee
    240  // will live past the NotifyError callback.
    241  RefPtr<WindowsLocationProvider> self = this;
    242  nsCOMPtr<nsIGeolocationUpdate> callback = mCallback;
    243  callback->NotifyError(err);
    244 }
    245 
    246 void WindowsLocationProvider::ActorStopped() {
    247  // ActorDestroy has run.  Make sure UtilityProcessHost no longer tries to use
    248  // it.
    249  ReleaseUtilityProcess();
    250 
    251  if (mWatching) {
    252    // Treat as remote geolocation error, which will cause it to fallback
    253    // to MLS if it hasn't already.
    254    mWatching = false;
    255    RecvFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
    256    return;
    257  }
    258 
    259  MOZ_ASSERT(!mActorPromise);
    260  if (mActor) {
    261    mActor->DetachFromLocationProvider();
    262    mActor = nullptr;
    263  }
    264 }
    265 
    266 NS_IMETHODIMP
    267 WindowsLocationProvider::Startup() {
    268  LOG("WindowsLocationProvider::Startup(%p, %p, %p)", this, mActor.get(),
    269      mActorPromise.get());
    270  // If this fails, we will use the MLS fallback.
    271  SendStartup();
    272  return NS_OK;
    273 }
    274 
    275 NS_IMETHODIMP
    276 WindowsLocationProvider::Watch(nsIGeolocationUpdate* aCallback) {
    277  LOG("WindowsLocationProvider::Watch(%p, %p, %p, %p, %d)", this, mActor.get(),
    278      mActorPromise.get(), aCallback, mWatching);
    279  if (mWatching) {
    280    return NS_OK;
    281  }
    282 
    283  if (SendRegisterForReport(aCallback)) {
    284    mWatching = true;
    285    return NS_OK;
    286  }
    287 
    288  // Couldn't send request.  We will use MLS instead.
    289  return CreateAndWatchMLSProvider(aCallback);
    290 }
    291 
    292 NS_IMETHODIMP
    293 WindowsLocationProvider::Shutdown() {
    294  LOG("WindowsLocationProvider::Shutdown(%p, %p, %p)", this, mActor.get(),
    295      mActorPromise.get());
    296 
    297  if (mWatching) {
    298    SendUnregisterForReport();
    299    mWatching = false;
    300  }
    301 
    302  CancelMLSProvider();
    303  return NS_OK;
    304 }
    305 
    306 NS_IMETHODIMP
    307 WindowsLocationProvider::SetHighAccuracy(bool enable) {
    308  LOG("WindowsLocationProvider::SetHighAccuracy(%p, %p, %p, %s)", this,
    309      mActor.get(), mActorPromise.get(), enable ? "true" : "false");
    310  if (mMLSProvider) {
    311    // Ignored when running MLS fallback.
    312    return NS_OK;
    313  }
    314 
    315  if (!SendSetHighAccuracy(enable)) {
    316    return NS_ERROR_FAILURE;
    317  }
    318 
    319  // Since we SendSetHighAccuracy asynchronously, we cannot say for sure
    320  // that it will succeed.  If it does fail then we will get a
    321  // RecvFailed IPC message, which will cause a fallback to MLS.
    322  return NS_OK;
    323 }
    324 
    325 nsresult WindowsLocationProvider::CreateAndWatchMLSProvider(
    326    nsIGeolocationUpdate* aCallback) {
    327  LOG("WindowsLocationProvider::CreateAndWatchMLSProvider"
    328      "(%p, %p, %p, %p, %p)",
    329      this, mMLSProvider.get(), mActor.get(), mActorPromise.get(), aCallback);
    330 
    331  if (mMLSProvider) {
    332    return NS_OK;
    333  }
    334 
    335  mMLSProvider = new MLSFallback(0);
    336  return mMLSProvider->Startup(new MLSUpdate(aCallback));
    337 }
    338 
    339 void WindowsLocationProvider::CancelMLSProvider() {
    340  LOG("WindowsLocationProvider::CancelMLSProvider"
    341      "(%p, %p, %p, %p, %p)",
    342      this, mMLSProvider.get(), mActor.get(), mActorPromise.get(),
    343      mCallback.get());
    344 
    345  if (!mMLSProvider) {
    346    return;
    347  }
    348 
    349  mMLSProvider->Shutdown(MLSFallback::ShutdownReason::ProviderShutdown);
    350  mMLSProvider = nullptr;
    351 }
    352 
    353 #undef LOG
    354 
    355 }  // namespace mozilla::dom