blob: 7b88d31af23ec7e3456264a4f90f26d3da9a6993 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CHRE_CORE_GNSS_MANAGER_H_
#define CHRE_CORE_GNSS_MANAGER_H_
#include <cstdint>
#include "chre/core/api_manager_common.h"
#include "chre/core/nanoapp.h"
#include "chre/core/settings.h"
#include "chre/platform/platform_gnss.h"
#include "chre/util/non_copyable.h"
#include "chre/util/system/debug_dump.h"
#include "chre/util/time.h"
namespace chre {
class GnssManager;
/**
* A helper class that manages requests for a GNSS location or measurement
* session.
*/
class GnssSession {
public:
/**
* Adds a request to a session asynchronously. The result is delivered
* through a CHRE_EVENT_GNSS_ASYNC_RESULT event.
*
* @param nanoapp The nanoapp adding the request.
* @param minInterval The minimum reporting interval for results.
* @param timeToNext The amount of time that the GNSS system is allowed to
* delay generating a report.
* @param cookie A cookie that is round-tripped to provide context to the
* nanoapp making the request.
*
* @return true if the request was accepted for processing.
*/
bool addRequest(Nanoapp *nanoapp, Milliseconds minInterval,
Milliseconds minTimeToNext, const void *cookie);
/**
* Removes a request from a session asynchronously. The result is delivered
* through a CHRE_EVENT_GNSS_ASYNC_RESULT event.
*
* @param nanoapp The nanoapp removing the request.
* @param cookie A cookie that is round-tripped to provide context to the
* nanoapp making the request.
*
* @return true if the request was accepted for processing.
*/
bool removeRequest(Nanoapp *nanoapp, const void *cookie);
/**
* Checks if a nanoapp has an open session request.
*
* @param nanoapp The nanoapp removing the request.
*
* @return whether the nanoapp has an active request.
*/
bool nanoappHasRequest(Nanoapp *nanoapp) const;
/**
* Handles the result of a request to the PlatformGnss to request a change to
* the session.
*
* @param enabled true if the session is currently active.
* @param errorCode an error code that is used to indicate success or what
* type of error has occured. See chreError enum in the CHRE API for
* additional details.
*/
void handleStatusChange(bool enabled, uint8_t errorCode);
/**
* Handles a CHRE GNSS report (location/data) event.
*
* @param event The GNSS report event provided to the GNSS session. This
* memory is guaranteed not to be modified until it has been explicitly
* released through the PlatformGnss instance.
*/
void handleReportEvent(void *event);
/**
* @return true if an async response is pending from GNSS. This method should
* be used to check if a GNSS session request is in flight.
*/
bool asyncResponsePending() const {
return !mStateTransitions.empty() || mInternalRequestPending;
}
/**
* Invoked when the host notifies CHRE of a settings change.
*
* @param setting The setting that changed.
* @param enabled Whether setting is enabled or not.
*/
void onSettingChanged(Setting setting, bool enabled);
/**
* Updates the platform GNSS request according to the current state. It should
* be used to synchronize the GNSS to the desired state, e.g. for setting
* updates or handling a state resync request.
*
* @param forceUpdate If true, force the platform GNSS request to be made.
*
* @return true if the invocation resulted in dispatching an internal
* request to control the platform layer
*/
bool updatePlatformRequest(bool forceUpdate = false);
/**
* Invoked as a result of a requestStateResync() callback from the GNSS PAL.
* Runs in the context of the CHRE thread.
*/
void handleRequestStateResyncCallbackSync();
/**
* Prints state in a string buffer. Must only be called from the context of
* the main CHRE thread.
*
* @param debugDump The debug dump wrapper where a string can be printed
* into one of the buffers.
*/
void logStateToBuffer(DebugDumpWrapper &debugDump) const;
private:
/**
* Tracks a nanoapp that has subscribed to a session and the reporting
* interval.
*/
struct Request {
//! The nanoapp instance ID that made this request.
uint32_t nanoappInstanceId;
//! The interval of results requested.
Milliseconds minInterval;
};
//! Internal struct with data needed to log last X session requests
struct SessionRequestLog {
SessionRequestLog(Nanoseconds timestampIn, uint16_t instanceIdIn,
Milliseconds intervalIn, bool startIn)
: timestamp(timestampIn),
instanceId(instanceIdIn),
interval(intervalIn),
start(startIn) {}
Nanoseconds timestamp;
uint16_t instanceId;
Milliseconds interval;
bool start;
};
/**
* Tracks the state of the GNSS engine.
*/
struct StateTransition {
//! The cookie provided to the CHRE API when the nanoapp requested a
//! change to the state of the GNSS engine.
const void *cookie;
//! The nanoapp instance ID that prompted the change.
uint16_t nanoappInstanceId;
//! The target state of the GNSS engine.
bool enable;
//! The target minimum reporting interval for the GNSS engine. This is only
//! valid if enable is set to true.
Milliseconds minInterval;
};
//! The event type of the session's report data.
const uint16_t kReportEventType;
//! The request type to start and stop a session.
uint8_t mStartRequestType;
uint8_t mStopRequestType;
//! The session name, used in logging state.
const char *mName;
//! The maximum number of pending state transitions allowed.
static constexpr size_t kMaxGnssStateTransitions = 8;
//! The queue of state transitions for the GNSS engine. Only one asynchronous
//! state transition can be in flight at one time. Any further requests are
//! queued here.
ArrayQueue<StateTransition, kMaxGnssStateTransitions> mStateTransitions;
//! The list of most recent session request logs
static constexpr size_t kNumSessionRequestLogs = 10;
ArrayQueue<SessionRequestLog, kNumSessionRequestLogs> mSessionRequestLogs;
//! The request multiplexer for GNSS session requests.
DynamicVector<Request> mRequests;
//! The current report interval being sent to the session. This is only valid
//! if the mRequests is non-empty.
Milliseconds mCurrentInterval = Milliseconds(UINT64_MAX);
//! The state of the last successful request to the platform.
bool mPlatformEnabled = false;
//! True if a request from the CHRE framework is currently pending.
bool mInternalRequestPending = false;
//! True if a setting change event is pending to be processed.
bool mSettingChangePending = false;
//! True if a state resync callback is pending to be processed.
bool mResyncPending = false;
// Allows GnssManager to access constructor.
friend class GnssManager;
//! The histogram of error codes for collected errors, the index of this array
//! corresponds to the type of the errorcode
uint32_t mGnssErrorHistogram[CHRE_ERROR_SIZE] = {0};
/**
* Constructs a GnssSesson.
*
* @param reportEventType The report event type of this GNSS session.
* Currently, only CHRE_EVENT_GNSS_LOCATION for a location session and
* CHRE_EVENT_GNSS_LOCATION for a measurement session are supported.
*/
GnssSession(uint16_t reportEventType);
/**
* Configures the GNSS engine to be enabled/disabled. If enable is set to true
* then the minInterval and minTimeToNext values are valid.
*
* @param nanoapp The nanoapp requesting the state change for the engine.
* @param enable Whether to enable or disable the engine.
* @param minInterval The minimum reporting interval requested by the nanoapp.
* @param minTimeToNext The minimum time to the next report.
* @param cookie The cookie provided by the nanoapp to round-trip for context.
*
* @return true if the request was accepted.
*/
bool configure(Nanoapp *nanoapp, bool enable, Milliseconds minInterval,
Milliseconds minTimeToNext, const void *cookie);
/**
* Checks if a nanoapp has an open session request.
*
* @param instanceId The nanoapp instance ID to search for.
* @param requestIndex A pointer to an index to populate if the nanoapp has an
* open session request.
*
* @return true if the provided instanceId was found.
*/
bool nanoappHasRequest(uint16_t instanceId,
size_t *requestIndex = nullptr) const;
/**
* Adds a request for a session to the queue of state transitions.
*
* @param instanceId The nanoapp instance ID requesting a session.
* @param enable Whether the session is being enabled or disabled for this
* nanoapp.
* @param minInterval The minimum interval requested by the nanoapp.
* @param cookie A cookie that is round-tripped to the nanoapp for context.
*
* @return true if the state transition was added to the queue.
*/
bool addRequestToQueue(uint16_t instanceId, bool enable,
Milliseconds minInterval, const void *cookie);
/**
* @return true if the session is currently enabled.
*/
bool isEnabled() const;
/**
* Determines if a change to the session state is required given a set of
* parameters.
*
* @param requestedState The target state requested by a nanoapp.
* @param minInterval The minimum reporting interval.
* @param nanoappHasRequest If the nanoapp already has a request.
* @param requestIndex The index of the request in the list of open requests
* if nanoappHasRequest is set to true.
*
* @return true if a state transition is required.
*/
bool stateTransitionIsRequired(bool requestedState, Milliseconds minInterval,
bool nanoappHasRequest,
size_t requestIndex) const;
/**
* Updates the session requests given a nanoapp and the interval requested.
*
* @param enable true if enabling the session.
* @param minInterval the minimum reporting interval if enable is true.
* @param instanceId the nanoapp instance ID that owns the request.
*
* @return true if the session request list was updated.
*/
bool updateRequests(bool enable, Milliseconds minInterval,
uint16_t instanceId);
/**
* Posts the result of a GNSS session add/remove request.
*
* @param instanceId The nanoapp instance ID that made the request.
* @param success true if the operation was successful.
* @param enable true if enabling the session.
* @param minInterval the minimum reporting interval.
* @param errorCode the error code as a result of this operation.
* @param cookie the cookie that the nanoapp is provided for context.
*
* @return true if the event was successfully posted.
*/
bool postAsyncResultEvent(uint16_t instanceId, bool success, bool enable,
Milliseconds minInterval, uint8_t errorCode,
const void *cookie);
/**
* Calls through to postAsyncResultEvent but invokes FATAL_ERROR if the
* event is not posted successfully. This is used in asynchronous contexts
* where a nanoapp could be stuck waiting for a response but CHRE failed to
* enqueue one. For parameter details,
* @see postAsyncResultEvent
*/
void postAsyncResultEventFatal(uint16_t instanceId, bool success, bool enable,
Milliseconds minInterval, uint8_t errorCode,
const void *cookie);
/**
* Handles the result of a request to PlatformGnss to change the state of
* the session. See the handleStatusChange method which may be called from
* any thread. This method is intended to be invoked on the CHRE event loop
* thread.
*
* @param enabled true if the session was enabled
* @param errorCode an error code that is provided to indicate success.
*/
void handleStatusChangeSync(bool enabled, uint8_t errorCode);
/**
* Releases a GNSS report event after nanoapps have consumed it.
*
* @param eventType the type of event being freed.
* @param eventData a pointer to the scan event to release.
*/
static void freeReportEventCallback(uint16_t eventType, void *eventData);
/**
* Configures PlatformGnss based on session settings.
*
* @return true if PlatformGnss has accepted the setting.
*/
bool controlPlatform(bool enable, Milliseconds minInterval,
Milliseconds minTimeToNext);
/**
* Add a log to list of session logs possibly pushing out the oldest log.
*
* @param nanoappInstanceId the instance of id of nanoapp requesting
* @param interval the interval in milliseconds for request
* @param start true if the is a start request, false if a stop request
*/
void addSessionRequestLog(uint16_t nanoappInstanceId, Milliseconds interval,
bool start);
/**
* Dispatches pending state transitions on the queue until the first one
* succeeds.
*/
void dispatchQueuedStateTransitions();
};
/**
* The GnssManager handles platform init, capability query, and delagates debug
* dump and all GNSS request management to GnssSession(s), which includes
* multiplexing multiple requests into one for the platform to handle.
*
* This class is effectively a singleton as there can only be one instance of
* the PlatformGnss instance.
*/
class GnssManager : public NonCopyable {
public:
/**
* Constructs a GnssManager.
*/
GnssManager();
/**
* Initializes the underlying platform-specific GNSS module. Must be called
* prior to invoking any other methods in this class.
*/
void init();
/**
* @return the GNSS capabilities exposed by this platform.
*/
uint32_t getCapabilities();
GnssSession &getLocationSession() {
return mLocationSession;
};
GnssSession &getMeasurementSession() {
return mMeasurementSession;
};
/**
* Invoked when the host notifies CHRE of a settings change.
*
* @param setting The setting that changed.
* @param enabled Whether setting is enabled or not.
*/
void onSettingChanged(Setting setting, bool enabled);
/**
* Invoked as a result of a requestStateResync() callback from the GNSS PAL.
* Runs asynchronously in the context of the callback immediately.
*/
void handleRequestStateResyncCallback();
/**
* Invoked as a result of a requestStateResync() callback from the GNSS PAL.
* Runs in the context of the CHRE thread.
*/
void handleRequestStateResyncCallbackSync();
/**
* @param nanoapp The nanoapp invoking
* chreGnssConfigurePassiveLocationListener.
* @param enable true to enable the configuration.
*
* @return true if the configuration succeeded.
*/
bool configurePassiveLocationListener(Nanoapp *nanoapp, bool enable);
/**
* Prints state in a string buffer. Must only be called from the context of
* the main CHRE thread.
*
* @param debugDump The debug dump wrapper where a string can be printed
* into one of the buffers.
*/
void logStateToBuffer(DebugDumpWrapper &debugDump) const;
/**
* Disables the location session, the measurement session and the passive
* location listener associated to a nanoapp.
*
* @param nanoapp A non-null pointer to the nanoapp.
*
* @return The number of subscriptions disabled.
*/
uint32_t disableAllSubscriptions(Nanoapp *nanoapp);
private:
// Allows GnssSession to access mPlatformGnss.
friend class GnssSession;
//! The platform GNSS interface.
PlatformGnss mPlatformGnss;
//! The instance of location session.
GnssSession mLocationSession;
//! The instance of measurement session.
GnssSession mMeasurementSession;
//! The list of instance ID of nanoapps that has a passive location listener
//! request.
DynamicVector<uint16_t> mPassiveLocationListenerNanoapps;
//! true if the passive location listener is enabled at the platform.
bool mPlatformPassiveLocationListenerEnabled;
/**
* @param nanoappInstanceId The instance ID of the nanoapp to check.
* @param index If non-null and this function returns true, stores the index
* of mPassiveLocationListenerNanoapps where the instance ID is stored.
*
* @return true if the nanoapp currently has a passive location listener
* request.
*/
bool nanoappHasPassiveLocationListener(uint16_t nanoappInstanceId,
size_t *index = nullptr);
/**
* Helper function to invoke configurePassiveLocationListener at the platform
* and handle the result.
*
* @param enable true to enable the configuration.
*
* @return true if success.
*/
bool platformConfigurePassiveLocationListener(bool enable);
};
} // namespace chre
#endif // CHRE_CORE_GNSS_MANAGER_H_