mirror of
https://github.com/google/pebble.git
synced 2025-05-04 17:01:40 -04:00
159 lines
5.8 KiB
C
159 lines
5.8 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.
|
|
*/
|
|
|
|
#include "event_service_client.h"
|
|
#include "applib/applib_malloc.auto.h"
|
|
#include "plugin_service.h"
|
|
#include "plugin_service_private.h"
|
|
#include "syscall/syscall.h"
|
|
|
|
#include "process_state/app_state/app_state.h"
|
|
#include "process_state/worker_state/worker_state.h"
|
|
#include "system/logging.h"
|
|
#include "system/passert.h"
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Get our state variables
|
|
static PluginServiceState* prv_get_state(PebbleTask task) {
|
|
if (task == PebbleTask_Unknown) {
|
|
task = pebble_task_get_current();
|
|
}
|
|
if (task == PebbleTask_App) {
|
|
return app_state_get_plugin_service();
|
|
} else {
|
|
PBL_ASSERTN(task == PebbleTask_Worker);
|
|
return worker_state_get_plugin_service();
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Lookup the plugin service index from the UUID. We store the index in the event structure instead of the UUID
|
|
// so that we have payload room.
|
|
static uint16_t prv_get_service_index(Uuid *uuid) {
|
|
return sys_event_service_get_plugin_service_index(uuid);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Used by list_find to locate the handler for a specfic service index.
|
|
static bool prv_service_filter(ListNode *node, void *tp) {
|
|
PluginServiceEntry *info = (PluginServiceEntry *)node;
|
|
uint16_t service_idx = (uint16_t)(uintptr_t)tp;
|
|
return (info->service_index == service_idx);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Callback provided to the app_event_service. All events of type PEBBLE_PLUGIN_SERVICE_EVENT that get sent to
|
|
// this task trigger this callback. From here, we look up which user-supplied callback corresponds to the
|
|
// service index stored in the event structure and then pass control to that user-supplied callback.
|
|
static void prv_handle_event_service_event(PebbleEvent *e, void *context) {
|
|
PluginServiceState *state = prv_get_state(PebbleTask_Unknown);
|
|
uint16_t service_index = e->plugin_service.service_index;
|
|
|
|
ListNode *found;
|
|
ListNode *list = &state->subscribed_services;
|
|
found = list_find(list, prv_service_filter, (void*)(uintptr_t)service_index);
|
|
if (!found) {
|
|
return;
|
|
}
|
|
|
|
// Call the handler provided by the client
|
|
PluginServiceEntry *entry = (PluginServiceEntry *)found;
|
|
entry->handler(e->plugin_service.type, &e->plugin_service.data);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Subscribe to a specific plug-in service by uuid.
|
|
bool plugin_service_subscribe(Uuid *uuid, PluginServiceHandler handler) {
|
|
PluginServiceState *state = prv_get_state(PebbleTask_Unknown);
|
|
uint16_t service_index = prv_get_service_index(uuid);
|
|
|
|
ListNode *list = &state->subscribed_services;
|
|
if (list_find(list, prv_service_filter, (void*)(uintptr_t)service_index)) {
|
|
PBL_LOG(LOG_LEVEL_DEBUG, "Plug service handler already subscribed");
|
|
return false;
|
|
}
|
|
|
|
// Add to handlers list
|
|
PluginServiceEntry *entry = applib_type_zalloc(PluginServiceEntry);
|
|
if (!entry) {
|
|
PBL_LOG(LOG_LEVEL_ERROR, "OOM in plugin_service_subscribe");
|
|
return false;
|
|
}
|
|
entry->service_index = service_index;
|
|
entry->handler = handler;
|
|
list_append(list, &entry->list_node);
|
|
|
|
// Subscribe to the app event service if we haven't already
|
|
if (!state->subscribed_to_app_event_service) {
|
|
state->subscribed_to_app_event_service = true;
|
|
event_service_client_subscribe(&state->event_service_info);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Unsubscribe from a specific plug-in service by uuid.
|
|
bool plugin_service_unsubscribe(Uuid *uuid) {
|
|
PluginServiceState *state = prv_get_state(PebbleTask_Unknown);
|
|
uint16_t service_index = prv_get_service_index(uuid);
|
|
|
|
ListNode *found;
|
|
ListNode *list = &state->subscribed_services;
|
|
found = list_find(list, prv_service_filter, (void*)(uintptr_t)service_index);
|
|
if (!found) {
|
|
PBL_LOG(LOG_LEVEL_DEBUG, "Plug service handler already unsubscribed");
|
|
return true;
|
|
}
|
|
|
|
list_remove(found, NULL, NULL);
|
|
applib_free(found);
|
|
return true;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Send an event to all registered subscribers of the given plugin service identified by UUID.
|
|
void plugin_service_send_event(Uuid *uuid, uint8_t type, PluginEventData *data) {
|
|
uint16_t service_index = prv_get_service_index(uuid);
|
|
|
|
PebbleEvent event = {
|
|
.type = PEBBLE_PLUGIN_SERVICE_EVENT,
|
|
.plugin_service = {
|
|
.service_index = service_index,
|
|
.type = type,
|
|
.data = *data
|
|
},
|
|
};
|
|
sys_send_pebble_event_to_kernel(&event);
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------
|
|
// Init our state variables.
|
|
void plugin_service_state_init(PluginServiceState *state) {
|
|
*state = (PluginServiceState) {
|
|
.event_service_info = {
|
|
.type = PEBBLE_PLUGIN_SERVICE_EVENT,
|
|
.handler = &prv_handle_event_service_event,
|
|
},
|
|
};
|
|
}
|
|
|