mirror of
https://github.com/google/pebble.git
synced 2025-05-29 22:43:12 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
209
src/fw/resource/resource.c
Normal file
209
src/fw/resource/resource.c
Normal 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);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue