Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

209
src/fw/resource/resource.c Normal file
View file

@ -0,0 +1,209 @@
/*
* 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 "resource.h"
#include "resource_storage.h"
#include "resource_storage_builtin.h"
#include "resource_storage_flash.h"
#include "process_management/app_manager.h"
#include "drivers/flash.h"
#include "flash_region/flash_region.h"
#include "kernel/pbl_malloc.h"
#include "os/mutex.h"
#include "services/normal/process_management/app_storage.h"
#include "system/logging.h"
#include "system/passert.h"
// TODO: this may be replaced once apps become more dynamic
typedef struct {
ListNode list_node;
uint32_t id;
ResourceStoreEntry stored_resource;
} CachedResource;
PebbleRecursiveMutex *s_resource_mutex = NULL;
static CachedResource *s_resource_list = NULL;
static bool prv_resource_filter(ListNode *found_node, void *data) {
CachedResource *resource = (CachedResource *)found_node;
uint32_t resource_id = (uint32_t)data;
return (resource->id == resource_id);
}
static void prv_get_resource(ResAppNum app_num, uint32_t id, ResourceStoreEntry *entry) {
if (id < 1) {
*entry = (ResourceStoreEntry){0};
return;
}
mutex_lock_recursive(s_resource_mutex);
ListNode *node;
if (app_num == SYSTEM_APP &&
(node = list_find((ListNode *)s_resource_list, prv_resource_filter, (void *)(uintptr_t)id))) {
mutex_unlock_recursive(s_resource_mutex);
*entry = ((CachedResource *)node)->stored_resource;
return;
}
resource_storage_get_resource(app_num, id, entry);
mutex_unlock_recursive(s_resource_mutex);
}
//! initialize components needed for one apps resources
bool resource_init_app(ResAppNum app_num, const ResourceVersion *expected_version) {
// resource_id is ignored in this case, so we set it to 0
mutex_lock_recursive(s_resource_mutex);
bool rv = resource_storage_check(app_num, 0, expected_version);
mutex_unlock_recursive(s_resource_mutex);
return rv;
}
void resource_init(void) {
// see if there's a system bank waiting to be loaded
resource_storage_init();
s_resource_mutex = mutex_create_recursive();
}
uint32_t resource_get_and_cache(ResAppNum app_num, uint32_t resource_id) {
PBL_ASSERTN(app_num == SYSTEM_APP);
// get from resource store
mutex_lock_recursive(s_resource_mutex);
ResourceStoreEntry res;
resource_storage_get_resource(app_num, resource_id, &res);
if (res.id < 1) {
mutex_unlock_recursive(s_resource_mutex);
return 0;
}
// check if we already have something in cache for this resource
CachedResource *cached_resource = (CachedResource *)list_find((ListNode *)s_resource_list,
prv_resource_filter, (void *)(uintptr_t)resource_id);
if (cached_resource == NULL) {
cached_resource = kernel_malloc_check(sizeof(CachedResource));
*cached_resource = (CachedResource){};
cached_resource->id = resource_id;
s_resource_list = (CachedResource *)list_prepend((ListNode *)s_resource_list,
(ListNode *)cached_resource);
}
cached_resource->stored_resource = res;
mutex_unlock_recursive(s_resource_mutex);
return resource_id;
}
size_t resource_load_byte_range_system(ResAppNum app_num, uint32_t resource_id,
uint32_t offset, uint8_t *buffer, size_t num_bytes) {
PBL_ASSERTN(buffer);
if (!num_bytes) {
return 0;
}
mutex_lock_recursive(s_resource_mutex);
ResourceStoreEntry resource;
prv_get_resource(app_num, resource_id, &resource);
if (resource.id < 1) {
mutex_unlock_recursive(s_resource_mutex);
return 0;
}
if (offset + num_bytes > resource.length) {
if (offset >= resource.length) {
// Can't recover from trying to read from beyond the resource. Read nothing.
mutex_unlock_recursive(s_resource_mutex);
return 0;
}
// We want to stop the FW from doing this, so we added an assert
// but in the name of backwards compatibility, we let the app misbehave
num_bytes = resource.length - offset;
PBL_LOG(LOG_LEVEL_DEBUG, "Tried to read past end of resource, reading %d bytes",
(int)num_bytes);
}
size_t bytes_read = resource_storage_read(&resource, offset, buffer, num_bytes);
mutex_unlock_recursive(s_resource_mutex);
return bytes_read;
}
size_t resource_size(ResAppNum app_num, uint32_t resource_id) {
mutex_lock_recursive(s_resource_mutex);
ResourceStoreEntry resource;
prv_get_resource(app_num, resource_id, &resource);
mutex_unlock_recursive(s_resource_mutex);
return resource.length;
}
bool resource_bytes_are_readonly(void *bytes) {
return resource_storage_builtin_bytes_are_readonly(bytes) ||
resource_storage_flash_bytes_are_readonly(bytes);
}
const uint8_t *resource_get_readonly_bytes(ResAppNum app_num, uint32_t resource_id,
size_t *num_bytes_out, bool has_privileged_access) {
// we don't support memory-mapping for resources that don't belong to the system
if (app_num != SYSTEM_APP) {
return NULL;
}
mutex_lock_recursive(s_resource_mutex);
// FIXME PBL-28781: This operation touches flash. Even though this is the cleanest approach
// to detect if the resource is a builtin, it is a slow one. We should instead only search
// in the builtin table for the resource_ids and if there are no matches, bail early.
ResourceStoreEntry resource;
prv_get_resource(app_num, resource_id, &resource);
mutex_unlock_recursive(s_resource_mutex);
if (num_bytes_out) {
*num_bytes_out = resource.length;
}
return resource.impl->readonly_bytes(&resource, has_privileged_access);
}
ResourceVersion resource_get_version(ResAppNum app_num, uint32_t resource_id) {
mutex_lock_recursive(s_resource_mutex);
ResourceVersion v = resource_storage_get_version(app_num, resource_id);
mutex_unlock_recursive(s_resource_mutex);
return v;
}
ResourceVersion resource_get_system_version(void) {
return resource_get_version(0, 0);
}
bool resource_is_valid(ResAppNum app_num, uint32_t resource_id) {
mutex_lock_recursive(s_resource_mutex);
bool rv = resource_storage_check(app_num, resource_id, NULL /* No expected version */);
if (rv) {
ResourceStoreEntry entry;
prv_get_resource(app_num, resource_id, &entry);
rv = (entry.id != 0);
}
mutex_unlock_recursive(s_resource_mutex);
return rv;
}
bool resource_version_matches(const ResourceVersion *v1, const ResourceVersion *v2) {
return (v1->crc == v2->crc);
}