From 7e303cfeb85373323eeeb2ebe83ba3184c9d7bfa Mon Sep 17 00:00:00 2001 From: that Date: Thu, 6 Mar 2014 07:57:43 +0100 Subject: Support pre-KitKat properties for update-binary Google changed the in-memory format for storing properties in 4.4. Zips containing an older update-binary expect the old format, otherwise assertions on properties in the update script fail. This is just enough of the old property service to copy the properties to the legacy format before running the updater. Change-Id: I404680384bdc5e952609e295029ab0a0faf743a5 --- Android.mk | 2 +- legacy_properties.h | 104 +++++++++++++++++++++++ legacy_property_service.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++ legacy_property_service.h | 25 ++++++ twinstall.cpp | 32 ++++++- 5 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 legacy_properties.h create mode 100644 legacy_property_service.c create mode 100644 legacy_property_service.h diff --git a/Android.mk b/Android.mk index 013e4e1b5..46098cccf 100644 --- a/Android.mk +++ b/Android.mk @@ -322,7 +322,7 @@ ifeq ($(TARGET_BOARD_PLATFORM),rk30xx) LOCAL_CFLAGS += -DRK3066 endif LOCAL_C_INCLUDES := bootable/recovery/libmincrypt/includes -LOCAL_SRC_FILES = adb_install.cpp bootloader.cpp verifier.cpp mtdutils/mtdutils.c +LOCAL_SRC_FILES = adb_install.cpp bootloader.cpp verifier.cpp mtdutils/mtdutils.c legacy_property_service.c LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils LOCAL_STATIC_LIBRARIES += libmincrypttwrp diff --git a/legacy_properties.h b/legacy_properties.h new file mode 100644 index 000000000..9eb6bc751 --- /dev/null +++ b/legacy_properties.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _INCLUDE_LEGACY_PROPERTIES_H +#define _INCLUDE_LEGACY_PROPERTIES_H + +#include + +typedef struct prop_area prop_area; +typedef struct prop_msg prop_msg; + +#define PROP_AREA_MAGIC 0x504f5250 +#define PROP_AREA_VERSION 0x45434f76 + +#define PROP_SERVICE_NAME "property_service" + +/* #define PROP_MAX_ENTRIES 247 */ +/* 247 -> 32620 bytes (<32768) */ + +#define TOC_NAME_LEN(toc) ((toc) >> 24) +#define TOC_TO_INFO(area, toc) ((prop_info*) (((char*) area) + ((toc) & 0xFFFFFF))) + +struct prop_area { + unsigned volatile count; + unsigned volatile serial; + unsigned magic; + unsigned version; + unsigned reserved[4]; + unsigned toc[1]; +}; + +#define SERIAL_VALUE_LEN(serial) ((serial) >> 24) +#define SERIAL_DIRTY(serial) ((serial) & 1) + +struct prop_info { + char name[PROP_NAME_MAX]; + unsigned volatile serial; + char value[PROP_VALUE_MAX]; +}; + +struct prop_msg +{ + unsigned cmd; + char name[PROP_NAME_MAX]; + char value[PROP_VALUE_MAX]; +}; + +#define PROP_MSG_SETPROP 1 + +/* +** Rules: +** +** - there is only one writer, but many readers +** - prop_area.count will never decrease in value +** - once allocated, a prop_info's name will not change +** - once allocated, a prop_info's offset will not change +** - reading a value requires the following steps +** 1. serial = pi->serial +** 2. if SERIAL_DIRTY(serial), wait*, then goto 1 +** 3. memcpy(local, pi->value, SERIAL_VALUE_LEN(serial) + 1) +** 4. if pi->serial != serial, goto 2 +** +** - writing a value requires the following steps +** 1. pi->serial = pi->serial | 1 +** 2. memcpy(pi->value, local_value, value_len) +** 3. pi->serial = (value_len << 24) | ((pi->serial + 1) & 0xffffff) +** +** Improvements: +** - maintain the toc sorted by pi->name to allow lookup +** by binary search +** +*/ + +#define PROP_PATH_RAMDISK_DEFAULT "/default.prop" +#define PROP_PATH_SYSTEM_BUILD "/system/build.prop" +#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop" +#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop" + +#endif diff --git a/legacy_property_service.c b/legacy_property_service.c new file mode 100644 index 000000000..0dc95ad48 --- /dev/null +++ b/legacy_property_service.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "legacy_properties.h" + +#include +#include +#include "legacy_property_service.h" + + +static int persistent_properties_loaded = 0; +static int property_area_inited = 0; + +static int property_set_fd = -1; + + +typedef struct { + void *data; + size_t size; + int fd; +} workspace; + +static int init_workspace(workspace *w, size_t size) +{ + void *data; + int fd; + + /* dev is a tmpfs that we can use to carve a shared workspace + * out of, so let's do that... + */ + fd = open("/dev/__legacy_properties__", O_RDWR | O_CREAT, 0600); + if (fd < 0) + return -1; + + if (ftruncate(fd, size) < 0) + goto out; + + data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(data == MAP_FAILED) + goto out; + + close(fd); + + fd = open("/dev/__legacy_properties__", O_RDONLY); + if (fd < 0) + return -1; + + unlink("/dev/__legacy_properties__"); + + w->data = data; + w->size = size; + w->fd = fd; + return 0; + +out: + close(fd); + return -1; +} + +/* (8 header words + 247 toc words) = 1020 bytes */ +/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */ + +#define PA_COUNT_MAX 247 +#define PA_INFO_START 1024 +#define PA_SIZE 32768 + +static workspace pa_workspace; +static prop_info *pa_info_array; + +prop_area *__legacy_property_area__; + +static int init_property_area(void) +{ + prop_area *pa; + + if(pa_info_array) + return -1; + + if(init_workspace(&pa_workspace, PA_SIZE)) + return -1; + + fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC); + + pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START); + + pa = pa_workspace.data; + memset(pa, 0, PA_SIZE); + pa->magic = PROP_AREA_MAGIC; + pa->version = PROP_AREA_VERSION; + + /* plug into the lib property services */ + __legacy_property_area__ = pa; + property_area_inited = 1; + return 0; +} + +static void update_prop_info(prop_info *pi, const char *value, unsigned len) +{ + pi->serial = pi->serial | 1; + memcpy(pi->value, value, len + 1); + pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff); + __futex_wake(&pi->serial, INT32_MAX); +} + +static const prop_info *__legacy_property_find(const char *name) +{ + prop_area *pa = __legacy_property_area__; + unsigned count = pa->count; + unsigned *toc = pa->toc; + unsigned len = strlen(name); + prop_info *pi; + + while(count--) { + unsigned entry = *toc++; + if(TOC_NAME_LEN(entry) != len) continue; + + pi = TOC_TO_INFO(pa, entry); + if(memcmp(name, pi->name, len)) continue; + + return pi; + } + + return 0; +} + +static int legacy_property_set(const char *name, const char *value) +{ + prop_area *pa; + prop_info *pi; + + int namelen = strlen(name); + int valuelen = strlen(value); + + if(namelen >= PROP_NAME_MAX) return -1; + if(valuelen >= PROP_VALUE_MAX) return -1; + if(namelen < 1) return -1; + + pi = (prop_info*) __legacy_property_find(name); + + + if(pi != 0) { + /* ro.* properties may NEVER be modified once set */ + if(!strncmp(name, "ro.", 3)) return -1; + + pa = __legacy_property_area__; + update_prop_info(pi, value, valuelen); + pa->serial++; + __futex_wake(&pa->serial, INT32_MAX); + } else { + pa = __legacy_property_area__; + if(pa->count == PA_COUNT_MAX) return -1; + + pi = pa_info_array + pa->count; + pi->serial = (valuelen << 24); + memcpy(pi->name, name, namelen + 1); + memcpy(pi->value, value, valuelen + 1); + + pa->toc[pa->count] = + (namelen << 24) | (((unsigned) pi) - ((unsigned) pa)); + + pa->count++; + pa->serial++; + __futex_wake(&pa->serial, INT32_MAX); + } + + return 0; +} + +void legacy_get_property_workspace(int *fd, int *sz) +{ + *fd = pa_workspace.fd; + *sz = pa_workspace.size; +} + +static void copy_property_to_legacy(const char *key, const char *value, void *cookie) +{ + legacy_property_set(key, value); +} + +void legacy_properties_init() +{ + init_property_area(); + property_list(copy_property_to_legacy, 0); +} + diff --git a/legacy_property_service.h b/legacy_property_service.h new file mode 100644 index 000000000..172055fa2 --- /dev/null +++ b/legacy_property_service.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2007 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 _LEGACY_PROPERTY_H +#define _LEGACY_PROPERTY_H + +#include + +void legacy_get_property_workspace(int *fd, int *sz); +void legacy_properties_init(); + +#endif /* _LEGACY_PROPERTY_H */ diff --git a/twinstall.cpp b/twinstall.cpp index af12ce36f..b3b9b774b 100644 --- a/twinstall.cpp +++ b/twinstall.cpp @@ -48,6 +48,34 @@ #include "twrp-functions.hpp" extern "C" { #include "gui/gui.h" + #include "legacy_property_service.h" +} + +static const char* properties_path = "/dev/__properties__"; +static const char* properties_path_renamed = "/dev/__properties_kk__"; + +static void switch_to_legacy_properties() +{ + char tmp[32]; + int propfd, propsz; + legacy_properties_init(); + legacy_get_property_workspace(&propfd, &propsz); + sprintf(tmp, "%d,%d", dup(propfd), propsz); + setenv("ANDROID_PROPERTY_WORKSPACE", tmp, 1); + + if (TWFunc::Path_Exists(properties_path)) { + // hide real properties so that the updater uses the envvar to find the legacy format properties + if (rename(properties_path, properties_path_renamed) != 0) + LOGERR("Renaming properties failed: %s (assertions in old installers may fail)\n", strerror(errno)); + } +} + +static void switch_to_new_properties() +{ + if (TWFunc::Path_Exists(properties_path_renamed)) { + if (rename(properties_path_renamed, properties_path) != 0) + LOGERR("Restoring properties failed: %s\n", strerror(errno)); + } } static int Run_Update_Binary(const char *path, ZipArchive *Zip, int* wipe_cache) { @@ -127,8 +155,9 @@ static int Run_Update_Binary(const char *path, ZipArchive *Zip, int* wipe_cache) pid_t pid = fork(); if (pid == 0) { + switch_to_legacy_properties(); close(pipe_fd[0]); - execv(Temp_Binary.c_str(), (char* const*)args); + execve(Temp_Binary.c_str(), (char* const*)args, environ); printf("E:Can't execute '%s'\n", Temp_Binary.c_str()); _exit(-1); } @@ -175,6 +204,7 @@ static int Run_Update_Binary(const char *path, ZipArchive *Zip, int* wipe_cache) fclose(child_data); waitpid(pid, &status, 0); + switch_to_new_properties(); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOGERR("Error executing updater binary in zip '%s'\n", path); return INSTALL_ERROR; -- cgit v1.2.3