Files
pebble/src/fw/services/normal/app_outbox_service.h
2025-01-27 11:38:16 -08:00

123 lines
5.1 KiB
C

/*
* Copyright 2024 Google LLC
*
* 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.
*/
#pragma once
#include "applib/app_outbox.h"
#include "kernel/events.h"
#include "kernel/pebble_tasks.h"
#include "util/list.h"
#include <stdint.h>
#include <stddef.h>
// Design goals of this module:
//
// - Provide a generic mechanism to pass variable-length data from app to kernel service.
// - Have the data be read directly from an app-provided buffer (in app space).
// - Asynchronous: a "sent" callback should execute on the (app) task that created the outbox, when
// the transfer is completed.
// - Simple status results: the "sent" callback should be called with a simple status code that
// indicates whether the transfer was successful or not.
// - Use is limited only to the hard-coded set of permitted use cases and their handlers, to avoid
// abuse of the API by misbehaving apps.
// - The kernel manages the existence of service instances. If data is sent while the service is not
// registered, the sent_handler should be called right away with a failure.
// - Allow adding a message while there is already one or more waiting in the outbox.
//
// Non-goals:
//
// - Ability to cancel messages that have already been added to the outbox (could be added easily
// in the future)
typedef enum {
AppOutboxServiceTagInvalid = -1,
AppOutboxServiceTagAppMessageSender,
#ifdef UNITTEST
AppOutboxServiceTagUnitTest,
#endif
NumAppOutboxServiceTag,
} AppOutboxServiceTag;
//! To be called once at boot.
void app_outbox_service_init(void);
//! Cleans up all pending messages. To be called by the app manager when an app is terminated.
//! @note This will *NOT* invoke the `sent_handler`s of the pending messages.
void app_outbox_service_cleanup_all_pending_messages(void);
//! Cleans up any pending app outbox events in the queue towards the kernel, that have not been
//! processed.
void app_outbox_service_cleanup_event(PebbleEvent *event);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Sender (App) API
//! @see app_outbox_send for documentation
////////////////////////////////////////////////////////////////////////////////////////////////////
// Owner / Receiver (Kernel) API
typedef struct {
ListNode node;
//! Pointer to message data
//! @note This will reside in app's memory space and never in kernel memory space. Therefore the
//! contents should be sanity checked carefully.
const uint8_t *data;
//! The length of `data` in bytes
size_t length;
//! Callback to execute on app task, when the data is consumed by the receiver.
AppOutboxSentHandler sent_handler;
//! User context to pass into the `sent_handler` callback.
void *cb_ctx;
//! Additional user data that will be allocated by app_outbox_service, on behalf of the receiving
//! kernel service. This can be used to store any state needed to parse and process the message.
//! The buffer will be zeroed out just before the message handler gets called.
uint8_t consumer_data[];
} AppOutboxMessage;
//! Callback to indicate there is a message added.
//! @note Only `consumer_data` is allowed to be mutated by the client!
typedef void (*AppOutboxMessageHandler)(AppOutboxMessage *message);
//! Can be used by the receiving kernel service to check whether message has been cancelled in the
//! mean time. Note that app_outbox_service_consume_message() still MUST be called with a cancelled
//! message at some point in time, to clean up the resources associated with it.
bool app_outbox_service_is_message_cancelled(AppOutboxMessage *message);
//! Registers a consumer for a specific app outbox service tag.
//! @param consumer_data_size The additional space that will be allocated for context by the app
//! outbox service, on behalf of the consumer. The extra space will be appended to the message that
//! gets passed into `message_handler`.
void app_outbox_service_register(AppOutboxServiceTag service_tag,
AppOutboxMessageHandler message_handler,
PebbleTask consumer_task,
size_t consumer_data_size);
//! Will invoke the sender's `sent_handler` with the status on the app task.
//! @param message Pointer to the message to be consumed. Note that this message will have been
//! free'd after this function returns and should not be used thereafter.
void app_outbox_service_consume_message(AppOutboxMessage *message, AppOutboxStatus status);
//! Closes the outbox.
//! This will call the `sent_handler` callback for all messages in the outbox with
//! AppOutboxStatusConsumerDoesNotExist.
void app_outbox_service_unregister(AppOutboxServiceTag service_tag);