diff options
Diffstat (limited to 'hal/gonk/GonkSensorsInterface.cpp')
-rw-r--r-- | hal/gonk/GonkSensorsInterface.cpp | 494 |
1 files changed, 0 insertions, 494 deletions
diff --git a/hal/gonk/GonkSensorsInterface.cpp b/hal/gonk/GonkSensorsInterface.cpp deleted file mode 100644 index 51e1ff50c..000000000 --- a/hal/gonk/GonkSensorsInterface.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=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 "GonkSensorsInterface.h" -#include "GonkSensorsPollInterface.h" -#include "GonkSensorsRegistryInterface.h" -#include "HalLog.h" -#include <mozilla/ipc/DaemonSocket.h> -#include <mozilla/ipc/DaemonSocketConnector.h> -#include <mozilla/ipc/ListenSocket.h> - -namespace mozilla { -namespace hal { - -using namespace mozilla::ipc; - -// -// GonkSensorsResultHandler -// - -void -GonkSensorsResultHandler::OnError(SensorsError aError) -{ - HAL_ERR("Received error code %d", static_cast<int>(aError)); -} - -void -GonkSensorsResultHandler::Connect() -{ } - -void -GonkSensorsResultHandler::Disconnect() -{ } - -GonkSensorsResultHandler::~GonkSensorsResultHandler() -{ } - -// -// GonkSensorsNotificationHandler -// - -void -GonkSensorsNotificationHandler::BackendErrorNotification(bool aCrashed) -{ - if (aCrashed) { - HAL_ERR("Sensors backend crashed"); - } else { - HAL_ERR("Error in sensors backend"); - } -} - -GonkSensorsNotificationHandler::~GonkSensorsNotificationHandler() -{ } - -// -// GonkSensorsProtocol -// - -class GonkSensorsProtocol final - : public DaemonSocketIOConsumer - , public GonkSensorsRegistryModule - , public GonkSensorsPollModule -{ -public: - GonkSensorsProtocol(); - - void SetConnection(DaemonSocket* aConnection); - - already_AddRefed<DaemonSocketResultHandler> FetchResultHandler( - const DaemonSocketPDUHeader& aHeader); - - // Methods for |SensorsRegistryModule| and |SensorsPollModule| - // - - nsresult Send(DaemonSocketPDU* aPDU, - DaemonSocketResultHandler* aRes) override; - - // Methods for |DaemonSocketIOConsumer| - // - - void Handle(DaemonSocketPDU& aPDU) override; - void StoreResultHandler(const DaemonSocketPDU& aPDU) override; - -private: - void HandleRegistrySvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - void HandlePollSvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - - DaemonSocket* mConnection; - nsTArray<RefPtr<DaemonSocketResultHandler>> mResultHandlerQ; -}; - -GonkSensorsProtocol::GonkSensorsProtocol() -{ } - -void -GonkSensorsProtocol::SetConnection(DaemonSocket* aConnection) -{ - mConnection = aConnection; -} - -already_AddRefed<DaemonSocketResultHandler> -GonkSensorsProtocol::FetchResultHandler(const DaemonSocketPDUHeader& aHeader) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - if (aHeader.mOpcode & 0x80) { - return nullptr; // Ignore notifications - } - - RefPtr<DaemonSocketResultHandler> res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - - return res.forget(); -} - -void -GonkSensorsProtocol::HandleRegistrySvc( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - GonkSensorsRegistryModule::HandleSvc(aHeader, aPDU, aRes); -} - -void -GonkSensorsProtocol::HandlePollSvc( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - GonkSensorsPollModule::HandleSvc(aHeader, aPDU, aRes); -} - -// |SensorsRegistryModule|, |SensorsPollModule| - -nsresult -GonkSensorsProtocol::Send(DaemonSocketPDU* aPDU, - DaemonSocketResultHandler* aRes) -{ - MOZ_ASSERT(mConnection); - MOZ_ASSERT(aPDU); - - aPDU->SetConsumer(this); - aPDU->SetResultHandler(aRes); - aPDU->UpdateHeader(); - - if (mConnection->GetConnectionStatus() == SOCKET_DISCONNECTED) { - HAL_ERR("Sensors socket is disconnected"); - return NS_ERROR_FAILURE; - } - - mConnection->SendSocketData(aPDU); // Forward PDU to data channel - - return NS_OK; -} - -// |DaemonSocketIOConsumer| - -void -GonkSensorsProtocol::Handle(DaemonSocketPDU& aPDU) -{ - static void (GonkSensorsProtocol::* const HandleSvc[])( - const DaemonSocketPDUHeader&, DaemonSocketPDU&, - DaemonSocketResultHandler*) = { - [GonkSensorsRegistryModule::SERVICE_ID] = - &GonkSensorsProtocol::HandleRegistrySvc, - [GonkSensorsPollModule::SERVICE_ID] = - &GonkSensorsProtocol::HandlePollSvc - }; - - DaemonSocketPDUHeader header; - - if (NS_FAILED(UnpackPDU(aPDU, header))) { - return; - } - if (!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc)) || - !HandleSvc[header.mService]) { - HAL_ERR("Sensors service %d unknown", header.mService); - return; - } - - RefPtr<DaemonSocketResultHandler> res = FetchResultHandler(header); - - (this->*(HandleSvc[header.mService]))(header, aPDU, res); -} - -void -GonkSensorsProtocol::StoreResultHandler(const DaemonSocketPDU& aPDU) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - mResultHandlerQ.AppendElement(aPDU.GetResultHandler()); -} - -// -// GonkSensorsInterface -// - -GonkSensorsInterface* -GonkSensorsInterface::GetInstance() -{ - static GonkSensorsInterface* sGonkSensorsInterface; - - if (sGonkSensorsInterface) { - return sGonkSensorsInterface; - } - - sGonkSensorsInterface = new GonkSensorsInterface(); - - return sGonkSensorsInterface; -} - -void -GonkSensorsInterface::SetNotificationHandler( - GonkSensorsNotificationHandler* aNotificationHandler) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mNotificationHandler = aNotificationHandler; -} - -/* - * The connect procedure consists of several steps. - * - * (1) Start listening for the command channel's socket connection: We - * do this before anything else, so that we don't miss connection - * requests from the Sensors daemon. This step will create a listen - * socket. - * - * (2) Start the Sensors daemon: When the daemon starts up it will open - * a socket connection to Gecko and thus create the data channel. - * Gecko already opened the listen socket in step (1). Step (2) ends - * with the creation of the data channel. - * - * (3) Signal success to the caller. - * - * If any step fails, we roll-back the procedure and signal an error to the - * caller. - */ -void -GonkSensorsInterface::Connect(GonkSensorsNotificationHandler* aNotificationHandler, - GonkSensorsResultHandler* aRes) -{ -#define BASE_SOCKET_NAME "sensorsd" - static unsigned long POSTFIX_LENGTH = 16; - - // If we could not cleanup properly before and an old - // instance of the daemon is still running, we kill it - // here. - mozilla::hal::StopSystemService("sensorsd"); - - mNotificationHandler = aNotificationHandler; - - mResultHandlerQ.AppendElement(aRes); - - if (!mProtocol) { - mProtocol = MakeUnique<GonkSensorsProtocol>(); - } - - if (!mListenSocket) { - mListenSocket = new ListenSocket(this, LISTEN_SOCKET); - } - - // Init, step 1: Listen for data channel... */ - - if (!mDataSocket) { - mDataSocket = new DaemonSocket(mProtocol.get(), this, DATA_SOCKET); - } else if (mDataSocket->GetConnectionStatus() == SOCKET_CONNECTED) { - // Command channel should not be open; let's close it. - mDataSocket->Close(); - } - - // The listen socket's name is generated with a random postfix. This - // avoids naming collisions if we still have a listen socket from a - // previously failed cleanup. It also makes it hard for malicious - // external programs to capture the socket name or connect before - // the daemon can do so. If no random postfix can be generated, we - // simply use the base name as-is. - nsresult rv = DaemonSocketConnector::CreateRandomAddressString( - NS_LITERAL_CSTRING(BASE_SOCKET_NAME), POSTFIX_LENGTH, mListenSocketName); - if (NS_FAILED(rv)) { - mListenSocketName.AssignLiteral(BASE_SOCKET_NAME); - } - - rv = mListenSocket->Listen(new DaemonSocketConnector(mListenSocketName), - mDataSocket); - if (NS_FAILED(rv)) { - OnConnectError(DATA_SOCKET); - return; - } - - // The protocol implementation needs a data channel for - // sending commands to the daemon. We set it here, because - // this is the earliest time when it's available. - mProtocol->SetConnection(mDataSocket); -} - -/* - * Disconnecting is inverse to connecting. - * - * (1) Close data socket: We close the data channel and the daemon will - * will notice. Once we see the socket's disconnect, we continue with - * the cleanup. - * - * (2) Close listen socket: The listen socket is not active any longer - * and we simply close it. - * - * (3) Signal success to the caller. - * - * We don't have to stop the daemon explicitly. It will cleanup and quit - * after it noticed the closing of the data channel - * - * Rolling back half-completed cleanups is not possible. In the case of - * an error, we simply push forward and try to recover during the next - * initialization. - */ -void -GonkSensorsInterface::Disconnect(GonkSensorsResultHandler* aRes) -{ - mNotificationHandler = nullptr; - - // Cleanup, step 1: Close data channel - mDataSocket->Close(); - - mResultHandlerQ.AppendElement(aRes); -} - -GonkSensorsRegistryInterface* -GonkSensorsInterface::GetSensorsRegistryInterface() -{ - if (mRegistryInterface) { - return mRegistryInterface.get(); - } - - mRegistryInterface = MakeUnique<GonkSensorsRegistryInterface>(mProtocol.get()); - - return mRegistryInterface.get(); -} - -GonkSensorsPollInterface* -GonkSensorsInterface::GetSensorsPollInterface() -{ - if (mPollInterface) { - return mPollInterface.get(); - } - - mPollInterface = MakeUnique<GonkSensorsPollInterface>(mProtocol.get()); - - return mPollInterface.get(); -} - -GonkSensorsInterface::GonkSensorsInterface() - : mNotificationHandler(nullptr) -{ } - -GonkSensorsInterface::~GonkSensorsInterface() -{ } - -void -GonkSensorsInterface::DispatchError(GonkSensorsResultHandler* aRes, - SensorsError aError) -{ - DaemonResultRunnable1<GonkSensorsResultHandler, void, - SensorsError, SensorsError>::Dispatch( - aRes, &GonkSensorsResultHandler::OnError, - ConstantInitOp1<SensorsError>(aError)); -} - -void -GonkSensorsInterface::DispatchError( - GonkSensorsResultHandler* aRes, nsresult aRv) -{ - SensorsError error; - - if (NS_FAILED(Convert(aRv, error))) { - error = SENSORS_ERROR_FAIL; - } - DispatchError(aRes, error); -} - -// |DaemonSocketConsumer|, |ListenSocketConsumer| - -void -GonkSensorsInterface::OnConnectSuccess(int aIndex) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); - - switch (aIndex) { - case LISTEN_SOCKET: { - // Init, step 2: Start Sensors daemon - nsCString args("-a "); - args.Append(mListenSocketName); - mozilla::hal::StartSystemService("sensorsd", args.get()); - } - break; - case DATA_SOCKET: - if (!mResultHandlerQ.IsEmpty()) { - // Init, step 3: Signal success - RefPtr<GonkSensorsResultHandler> res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - if (res) { - res->Connect(); - } - } - break; - } -} - -void -GonkSensorsInterface::OnConnectError(int aIndex) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); - - switch (aIndex) { - case DATA_SOCKET: - // Stop daemon and close listen socket - mozilla::hal::StopSystemService("sensorsd"); - mListenSocket->Close(); - // fall through - case LISTEN_SOCKET: - if (!mResultHandlerQ.IsEmpty()) { - // Signal error to caller - RefPtr<GonkSensorsResultHandler> res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - if (res) { - DispatchError(res, SENSORS_ERROR_FAIL); - } - } - break; - } -} - -/* - * Disconnects can happend - * - * (a) during startup, - * (b) during regular service, or - * (c) during shutdown. - * - * For cases (a) and (c), |mResultHandlerQ| contains an element. For - * case (b) |mResultHandlerQ| will be empty. This distinguishes a crash in - * the daemon. The following procedure to recover from crashes consists of - * several steps for case (b). - * - * (1) Close listen socket. - * (2) Wait for all sockets to be disconnected and inform caller about - * the crash. - * (3) After all resources have been cleaned up, let the caller restart - * the daemon. - */ -void -GonkSensorsInterface::OnDisconnect(int aIndex) -{ - MOZ_ASSERT(NS_IsMainThread()); - - switch (aIndex) { - case DATA_SOCKET: - // Cleanup, step 2 (Recovery, step 1): Close listen socket - mListenSocket->Close(); - break; - case LISTEN_SOCKET: - // Cleanup, step 3: Signal success to caller - if (!mResultHandlerQ.IsEmpty()) { - RefPtr<GonkSensorsResultHandler> res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - if (res) { - res->Disconnect(); - } - } - break; - } - - /* For recovery make sure all sockets disconnected, in order to avoid - * the remaining disconnects interfere with the restart procedure. - */ - if (mNotificationHandler && mResultHandlerQ.IsEmpty()) { - if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED && - mDataSocket->GetConnectionStatus() == SOCKET_DISCONNECTED) { - // Recovery, step 2: Notify the caller to prepare the restart procedure. - mNotificationHandler->BackendErrorNotification(true); - mNotificationHandler = nullptr; - } - } -} - -} // namespace hal -} // namespace mozilla |