Update to AOSP 8.0 base

Change-Id: I29fe722b4eb9718765327902779046840a01433e
This commit is contained in:
Ethan Yonker
2017-09-08 06:50:54 -05:00
234 changed files with 15565 additions and 10849 deletions
+15
View File
@@ -0,0 +1,15 @@
BasedOnStyle: Google
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: true
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
PenaltyExcessCharacter: 32
Cpp11BracedListStyle: false
+73 -19
View File
@@ -104,24 +104,25 @@ LOCAL_CLANG := true
LOCAL_C_INCLUDES += \
system/vold \
system/extras/ext4_utils \
system/extras \
system/core/adb \
system/core/libsparse \
external/zlib
external/zlib \
$(LOCAL_PATH)/bootloader_message_twrp/include
LOCAL_C_INCLUDES += bionic
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport external/openssl/include
else
LOCAL_C_INCLUDES += external/boringssl/include
LOCAL_C_INCLUDES += external/boringssl/include external/libcxx/include
endif
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES :=
LOCAL_STATIC_LIBRARIES += libguitwrp
LOCAL_SHARED_LIBRARIES += libaosprecovery libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libtwadbbu libbootloader_message
LOCAL_SHARED_LIBRARIES += libcrecovery libtwadbbu libtwrpdigest
LOCAL_SHARED_LIBRARIES += libaosprecovery libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libtwadbbu libbootloader_message_twrp
LOCAL_SHARED_LIBRARIES += libcrecovery libtwadbbu libtwrpdigest libc++
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libstlport
@@ -132,13 +133,20 @@ ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/libmincrypt/includes
LOCAL_CFLAGS += -DUSE_OLD_VERIFIER
else
LOCAL_SHARED_LIBRARIES += libc++ libcrypto
LOCAL_SHARED_LIBRARIES += libcrypto
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 24; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libbase
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libziparchive
else
LOCAL_SHARED_LIBRARIES += libminzip
LOCAL_CFLAGS += -DUSE_MINZIP
endif
ifneq ($(wildcard system/core/libsparse/Android.mk),)
LOCAL_SHARED_LIBRARIES += libsparse
endif
@@ -161,14 +169,14 @@ ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
endif
LOCAL_C_INCLUDES += external/libselinux/include
LOCAL_SHARED_LIBRARIES += libselinux
ifneq ($(TARGET_USERIMAGES_USE_EXT4), true)
LOCAL_CFLAGS += -DUSE_EXT4
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_SHARED_LIBRARIES += libext4_utils
ifneq ($(wildcard external/lz4/Android.mk),)
LOCAL_STATIC_LIBRARIES += liblz4
endif
endif
#ifneq ($(TARGET_USERIMAGES_USE_EXT4), true)
# LOCAL_CFLAGS += -DUSE_EXT4
# LOCAL_C_INCLUDES += system/extras/ext4_utils
# LOCAL_SHARED_LIBRARIES += libext4_utils
# ifneq ($(wildcard external/lz4/Android.mk),)
# LOCAL_STATIC_LIBRARIES += liblz4
# endif
#endif
ifeq ($(AB_OTA_UPDATER),true)
LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
@@ -304,7 +312,7 @@ ifeq ($(TW_INCLUDE_CRYPTO), true)
endif
endif
WITH_CRYPTO_UTILS := \
$(if $(wildcard system/core/libcrypto_utils/Android.mk),true)
$(if $(wildcard system/core/libcrypto_utils/android_pubkey.c),true)
ifeq ($(TW_USE_MODEL_HARDWARE_ID_FOR_DEVICE_ID), true)
LOCAL_CFLAGS += -DTW_USE_MODEL_HARDWARE_ID_FOR_DEVICE_ID
endif
@@ -370,7 +378,8 @@ LOCAL_ADDITIONAL_DEPENDENCIES += \
mkfs.fat \
permissive.sh \
simg2img_twrp \
libbootloader_message \
libbootloader_message_twrp \
init.recovery.hlthchrg.rc \
init.recovery.service.rc
ifneq ($(TARGET_ARCH), arm64)
@@ -589,6 +598,37 @@ else
endif
include $(BUILD_SHARED_LIBRARY)
# libmounts (static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := mounts.cpp
LOCAL_CLANG := true
LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
LOCAL_MODULE := libmounts
include $(BUILD_STATIC_LIBRARY)
# librecovery (static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
install.cpp
LOCAL_CFLAGS := -Wno-unused-parameter -Werror
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
ifeq ($(AB_OTA_UPDATER),true)
LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
endif
LOCAL_MODULE := librecovery
LOCAL_STATIC_LIBRARIES := \
libminui \
libvintf_recovery \
libcrypto_utils \
libcrypto \
libbase
include $(BUILD_STATIC_LIBRARY)
# shared libaosprecovery for Apache code
# ===============================
include $(CLEAR_VARS)
@@ -596,7 +636,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libaosprecovery
LOCAL_MODULE_TAGS := eng optional
LOCAL_CFLAGS := -std=gnu++0x
LOCAL_SRC_FILES := adb_install.cpp asn1_decoder.cpp legacy_property_service.cpp set_metadata.cpp tw_atomic.cpp installcommand.cpp
LOCAL_SRC_FILES := adb_install.cpp legacy_property_service.cpp set_metadata.cpp tw_atomic.cpp installcommand.cpp zipwrap.cpp
LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils libfusesideload libselinux libminzip
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
@@ -608,15 +648,23 @@ endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 24; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libmincrypttwrp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/libmincrypt/includes
LOCAL_SRC_FILES += verifier24/verifier.cpp
LOCAL_SRC_FILES += verifier24/verifier.cpp verifier24/asn1_decoder.cpp
LOCAL_CFLAGS += -DUSE_OLD_VERIFIER
else
LOCAL_SHARED_LIBRARIES += libcrypto libbase
LOCAL_SRC_FILES += verifier.cpp
LOCAL_SRC_FILES += verifier.cpp asn1_decoder.cpp
endif
ifeq ($(AB_OTA_UPDATER),true)
LOCAL_CFLAGS += -DAB_OTA_UPDATER=1
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_SRC_FILES += otautil/ZipUtil.cpp otautil/SysUtil.cpp
LOCAL_SHARED_LIBRARIES += libziparchive libext4_utils libcrypto libcrypto_utils
LOCAL_STATIC_LIBRARIES += libvintf_recovery libfs_mgr liblogwrap libavb libvintf libtinyxml2 libz
LOCAL_WHOLE_STATIC_LIBRARIES +=
else
LOCAL_CFLAGS += -DUSE_MINZIP
endif
include $(BUILD_SHARED_LIBRARY)
@@ -638,6 +686,7 @@ include $(LOCAL_PATH)/tests/Android.mk \
$(LOCAL_PATH)/edify/Android.mk \
$(LOCAL_PATH)/otafault/Android.mk \
$(LOCAL_PATH)/bootloader_message/Android.mk \
$(LOCAL_PATH)/bootloader_message_twrp/Android.mk \
$(LOCAL_PATH)/updater/Android.mk \
$(LOCAL_PATH)/update_verifier/Android.mk \
$(LOCAL_PATH)/applypatch/Android.mk
@@ -647,6 +696,10 @@ ifeq ($(wildcard system/core/uncrypt/Android.mk),)
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 26; echo $$?),0)
TARGET_GLOBAL_CFLAGS += -DTW_USE_MINUI_WITH_DATA
CLANG_TARGET_GLOBAL_CFLAGS += -DTW_USE_MINUI_WITH_DATA
endif
include $(commands_recovery_local_path)/minadbd/Android.mk \
$(commands_recovery_local_path)/minui/Android.mk
else
@@ -669,6 +722,7 @@ include $(commands_recovery_local_path)/injecttwrp/Android.mk \
$(commands_recovery_local_path)/libcrecovery/Android.mk \
$(commands_recovery_local_path)/libblkid/Android.mk \
$(commands_recovery_local_path)/minuitwrp/Android.mk \
$(commands_recovery_local_path)/otautil/Android.mk \
$(commands_recovery_local_path)/openaes/Android.mk \
$(commands_recovery_local_path)/toolbox/Android.mk \
$(commands_recovery_local_path)/twrpTarMain/Android.mk \
-1
View File
@@ -1,4 +1,3 @@
**Team Win Recovery Project (TWRP)**
You can find a compiling guide [here](http://forum.xda-developers.com/showthread.php?t=1943625 "Guide").
+13 -10
View File
@@ -28,6 +28,8 @@
#include "ui.h"
#include "cutils/properties.h"
#include "install.h"
#include "common.h"
#include "adb_install.h"
#include "minadbd/fuse_adb_provider.h"
#include "fuse_sideload.h"
@@ -37,10 +39,7 @@
#include "verifier.h"
#endif
static RecoveryUI* ui = NULL;
void
set_usb_driver(bool enabled) {
static void set_usb_driver(bool enabled) {
int fd = open("/sys/class/android_usb/android0/enable", O_WRONLY);
if (fd < 0) {
/* These error messages show when built in older Android branches (e.g. Gingerbread)
@@ -65,20 +64,18 @@ set_usb_driver(bool enabled) {
}
}
static void
stop_adbd() {
static void stop_adbd() {
printf("Stopping adbd...\n");
property_set("ctl.stop", "adbd");
set_usb_driver(false);
}
bool is_ro_debuggable() {
static bool is_ro_debuggable() {
char value[PROPERTY_VALUE_MAX+1];
return (property_get("ro.debuggable", value, NULL) == 1 && value[0] == '1');
}
void
maybe_restart_adbd() {
char value[PROPERTY_VALUE_MAX+1];
static void maybe_restart_adbd() {
if (is_ro_debuggable()) {
printf("Restarting adbd...\n");
set_usb_driver(true);
@@ -96,6 +93,12 @@ apply_from_adb(const char* install_file, pid_t* child_pid) {
stop_adbd();
set_usb_driver(true);
/*
int apply_from_adb(RecoveryUI* ui, bool* wipe_cache, const char* install_file) {
modified_flash = true;
stop_adbd(ui);
set_usb_driver(ui, true);
ui->Print("\n\nNow send the package you want to apply\n"
"to the device with \"adb sideload <filename>\"...\n");
*/
+2 -2
View File
@@ -19,8 +19,8 @@
//class RecoveryUI;
void set_usb_driver(bool enabled);
void maybe_restart_adbd();
static void set_usb_driver(bool enabled);
static void maybe_restart_adbd();
int apply_from_adb(const char* install_file, pid_t* child_pid);
#endif
+151 -15
View File
@@ -31,6 +31,7 @@ $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
)
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include \
external/bzip2 \
external/zlib \
$(commands_recovery_local_path)
@@ -42,27 +43,99 @@ LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += $(RECOVERY_PATH)
LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz
# libapplypatch (static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
applypatch.cpp \
bspatch.cpp \
freecache.cpp \
imgpatch.cpp
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(commands_recovery_local_path)
LOCAL_STATIC_LIBRARIES := \
libotafault \
libbase \
libcrypto \
libbspatch \
libbz \
libz
LOCAL_WHOLE_STATIC_LIBRARIES += libmtdutils
LOCAL_CFLAGS := \
-DZLIB_CONST \
-Werror
include $(BUILD_STATIC_LIBRARY)
# libimgpatch (static library)
# ===============================
include $(CLEAR_VARS)
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bspatch.cpp \
imgpatch.cpp
LOCAL_MODULE := libimgpatch
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(commands_recovery_local_path)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := \
libcrypto \
libbspatch \
libbase \
libbz \
libz
LOCAL_CFLAGS := \
-DZLIB_CONST \
-Werror
include $(BUILD_STATIC_LIBRARY)
LOCAL_CLANG := true
LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp
# libimgpatch (host static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bspatch.cpp \
imgpatch.cpp
LOCAL_MODULE := libimgpatch
LOCAL_C_INCLUDES += $(RECOVERY_PATH)
LOCAL_MODULE_HOST_OS := linux
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(commands_recovery_local_path)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz
LOCAL_STATIC_LIBRARIES := \
libcrypto \
libbspatch \
libbase \
libbz \
libz
LOCAL_CFLAGS := \
-DZLIB_CONST \
-Werror
include $(BUILD_HOST_STATIC_LIBRARY)
endif # HOST_OS == linux
# libapplypatch_modes (static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
applypatch_modes.cpp
LOCAL_MODULE := libapplypatch_modes
LOCAL_C_INCLUDES := $(commands_recovery_local_path)
LOCAL_STATIC_LIBRARIES := \
libapplypatch \
libbase \
libedify \
libcrypto
LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
LOCAL_CLANG := true
LOCAL_SRC_FILES := main.cpp
# applypatch (target executable)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := applypatch_main.cpp
LOCAL_MODULE := applypatch
LOCAL_C_INCLUDES += $(RECOVERY_PATH)
LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \
@@ -70,15 +143,78 @@ LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypt
LOCAL_SHARED_LIBRARIES += libz libcutils libc
LOCAL_C_INCLUDES := $(commands_recovery_local_path)
LOCAL_STATIC_LIBRARIES := \
libapplypatch_modes \
libapplypatch \
libbase \
libedify \
libotafault \
libcrypto \
libbspatch \
libbz
LOCAL_SHARED_LIBRARIES := \
libbase \
libz \
libcutils
LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
libimgdiff_src_files := imgdiff.cpp
# libbsdiff is compiled with -D_FILE_OFFSET_BITS=64.
libimgdiff_cflags := \
-Werror \
-D_FILE_OFFSET_BITS=64
libimgdiff_static_libraries := \
libbsdiff \
libdivsufsort \
libdivsufsort64 \
libziparchive \
libutils \
liblog \
libbase \
libz
# libimgdiff (static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(libimgdiff_src_files)
LOCAL_MODULE := libimgdiff
LOCAL_CFLAGS := \
$(libimgdiff_cflags)
LOCAL_STATIC_LIBRARIES := \
$(libimgdiff_static_libraries)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
LOCAL_CLANG := true
LOCAL_SRC_FILES := imgdiff.cpp utils.cpp bsdiff.cpp
# libimgdiff (host static library)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(libimgdiff_src_files)
LOCAL_MODULE := libimgdiff
LOCAL_CFLAGS := \
$(libimgdiff_cflags)
LOCAL_STATIC_LIBRARIES := \
$(libimgdiff_static_libraries)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_HOST_STATIC_LIBRARY)
# imgdiff (host static executable)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := imgdiff_main.cpp
LOCAL_MODULE := imgdiff
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_C_INCLUDES += external/zlib external/bzip2
LOCAL_STATIC_LIBRARIES += libz libbz
LOCAL_CFLAGS := -Werror
LOCAL_STATIC_LIBRARIES := \
libimgdiff \
$(libimgdiff_static_libraries) \
libbz
include $(BUILD_HOST_EXECUTABLE)
+33
View File
@@ -0,0 +1,33 @@
# Copyright (C) 2016 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.
# This file is for building imgdiff in Chrome OS.
CPPFLAGS += -iquote.. -Iinclude
CXXFLAGS += -std=c++11 -O3 -Wall -Werror
LDLIBS += -lbz2 -lz
.PHONY: all clean
all: imgdiff libimgpatch.a
clean:
rm -f *.o imgdiff libimgpatch.a
imgdiff: imgdiff.o bsdiff.o utils.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDLIBS) -o $@ $^
libimgpatch.a utils.o: CXXFLAGS += -fPIC
libimgpatch.a: imgpatch.o bspatch.o utils.o
${AR} rcs $@ $^
+379 -623
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2016 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 "applypatch_modes.h"
// This program (applypatch) applies binary patches to files in a way that
// is safe (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
// See the comments to applypatch_modes() function.
int main(int argc, char** argv) {
return applypatch_modes(argc, const_cast<const char**>(argv));
}
@@ -14,61 +14,72 @@
* limitations under the License.
*/
#include "applypatch_modes.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include "applypatch.h"
#include "edify/expr.h"
#include "openssl/sha.h"
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <openssl/sha.h>
static int CheckMode(int argc, char** argv) {
#include "applypatch/applypatch.h"
#include "edify/expr.h"
static int CheckMode(int argc, const char** argv) {
if (argc < 3) {
return 2;
}
return applypatch_check(argv[2], argc-3, argv+3);
std::vector<std::string> sha1;
for (int i = 3; i < argc; i++) {
sha1.push_back(argv[i]);
}
return applypatch_check(argv[2], sha1);
}
static int SpaceMode(int argc, char** argv) {
static int SpaceMode(int argc, const char** argv) {
if (argc != 3) {
return 2;
}
char* endptr;
size_t bytes = strtol(argv[2], &endptr, 10);
if (bytes == 0 && endptr == argv[2]) {
size_t bytes;
if (!android::base::ParseUint(argv[2], &bytes) || bytes == 0) {
printf("can't parse \"%s\" as byte count\n\n", argv[2]);
return 1;
}
return CacheSizeCheck(bytes);
}
// Parse arguments (which should be of the form "<sha1>:<filename>"
// into the new parallel arrays *sha1s and *files.Returns true on
// success.
static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s,
// Parse arguments (which should be of the form "<sha1>:<filename>" into the
// new parallel arrays *sha1s and *files. Returns true on success.
static bool ParsePatchArgs(int argc, const char** argv, std::vector<std::string>* sha1s,
std::vector<FileContents>* files) {
uint8_t digest[SHA_DIGEST_LENGTH];
if (sha1s == nullptr) {
return false;
}
for (int i = 0; i < argc; ++i) {
char* colon = strchr(argv[i], ':');
if (colon == nullptr) {
printf("no ':' in patch argument \"%s\"\n", argv[i]);
std::vector<std::string> pieces = android::base::Split(argv[i], ":");
if (pieces.size() != 2) {
printf("failed to parse patch argument \"%s\"\n", argv[i]);
return false;
}
*colon = '\0';
++colon;
if (ParseSha1(argv[i], digest) != 0) {
uint8_t digest[SHA_DIGEST_LENGTH];
if (ParseSha1(pieces[0].c_str(), digest) != 0) {
printf("failed to parse sha1 \"%s\"\n", argv[i]);
return false;
}
sha1s->push_back(argv[i]);
sha1s->push_back(pieces[0]);
FileContents fc;
if (LoadFileContents(colon, &fc) != 0) {
if (LoadFileContents(pieces[1].c_str(), &fc) != 0) {
return false;
}
files->push_back(std::move(fc));
@@ -81,20 +92,17 @@ static int FlashMode(const char* src_filename, const char* tgt_filename,
return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size);
}
static int PatchMode(int argc, char** argv) {
static int PatchMode(int argc, const char** argv) {
FileContents bonusFc;
Value bonusValue;
Value* bonus = nullptr;
Value bonus(VAL_INVALID, "");
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
if (LoadFileContents(argv[2], &bonusFc) != 0) {
printf("failed to load bonus file %s\n", argv[2]);
return 1;
}
bonus = &bonusValue;
bonus->type = VAL_BLOB;
bonus->size = bonusFc.data.size();
bonus->data = reinterpret_cast<char*>(bonusFc.data.data());
bonus.type = VAL_BLOB;
bonus.data = std::string(bonusFc.data.cbegin(), bonusFc.data.cend());
argc -= 2;
argv += 2;
}
@@ -103,42 +111,38 @@ static int PatchMode(int argc, char** argv) {
return 2;
}
char* endptr;
size_t target_size = strtol(argv[4], &endptr, 10);
if (target_size == 0 && endptr == argv[4]) {
size_t target_size;
if (!android::base::ParseUint(argv[4], &target_size) || target_size == 0) {
printf("can't parse \"%s\" as byte count\n\n", argv[4]);
return 1;
}
// If no <src-sha1>:<patch> is provided, it is in flash mode.
if (argc == 5) {
if (bonus != nullptr) {
if (bonus.type != VAL_INVALID) {
printf("bonus file not supported in flash mode\n");
return 1;
}
return FlashMode(argv[1], argv[2], argv[3], target_size);
}
std::vector<char*> sha1s;
std::vector<std::string> sha1s;
std::vector<FileContents> files;
if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
printf("failed to parse patch args\n");
return 1;
}
std::vector<Value> patches(files.size());
std::vector<Value*> patch_ptrs(files.size());
std::vector<std::unique_ptr<Value>> patches;
for (size_t i = 0; i < files.size(); ++i) {
patches[i].type = VAL_BLOB;
patches[i].size = files[i].data.size();
patches[i].data = reinterpret_cast<char*>(files[i].data.data());
patch_ptrs[i] = &patches[i];
patches.push_back(std::make_unique<Value>(
VAL_BLOB, std::string(files[i].data.cbegin(), files[i].data.cend())));
}
return applypatch(argv[1], argv[2], argv[3], target_size,
patch_ptrs.size(), sha1s.data(),
patch_ptrs.data(), bonus);
return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus);
}
// This program applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// This program (applypatch) applies binary patches to files in a way that
// is safe (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
@@ -160,11 +164,11 @@ static int PatchMode(int argc, char** argv) {
// - otherwise, or if any error is encountered, exits with non-zero
// status.
//
// <src-file> (or <file> in check mode) may refer to an MTD partition
// <src-file> (or <file> in check mode) may refer to an EMMC partition
// to read the source data. See the comments for the
// LoadMTDContents() function above for the format of such a filename.
// LoadPartitionContents() function for the format of such a filename.
int main(int argc, char** argv) {
int applypatch_modes(int argc, const char** argv) {
if (argc < 2) {
usage:
printf(
@@ -175,8 +179,8 @@ int main(int argc, char** argv) {
" or %s -l\n"
"\n"
"Filenames may be of the form\n"
" MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
"to specify reading from or writing to an MTD partition.\n\n",
" EMMC:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
"to specify reading from or writing to an EMMC partition.\n\n",
argv[0], argv[0], argv[0], argv[0]);
return 2;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2016 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 _APPLYPATCH_MODES_H
#define _APPLYPATCH_MODES_H
int applypatch_modes(int argc, const char** argv);
#endif // _APPLYPATCH_MODES_H
-410
View File
@@ -1,410 +0,0 @@
/*
* Copyright (C) 2009 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.
*/
/*
* Most of this code comes from bsdiff.c from the bsdiff-4.3
* distribution, which is:
*/
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 AUTHOR ``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 AUTHOR 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.
*/
#include <sys/types.h>
#include <bzlib.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MIN(x,y) (((x)<(y)) ? (x) : (y))
static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h)
{
off_t i,j,k,x,tmp,jj,kk;
if(len<16) {
for(k=start;k<start+len;k+=j) {
j=1;x=V[I[k]+h];
for(i=1;k+i<start+len;i++) {
if(V[I[k+i]+h]<x) {
x=V[I[k+i]+h];
j=0;
};
if(V[I[k+i]+h]==x) {
tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
j++;
};
};
for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
if(j==1) I[k]=-1;
};
return;
};
x=V[I[start+len/2]+h];
jj=0;kk=0;
for(i=start;i<start+len;i++) {
if(V[I[i]+h]<x) jj++;
if(V[I[i]+h]==x) kk++;
};
jj+=start;kk+=jj;
i=start;j=0;k=0;
while(i<jj) {
if(V[I[i]+h]<x) {
i++;
} else if(V[I[i]+h]==x) {
tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
j++;
} else {
tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
while(jj+j<kk) {
if(V[I[jj+j]+h]==x) {
j++;
} else {
tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
if(jj>start) split(I,V,start,jj-start,h);
for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
if(jj==kk-1) I[jj]=-1;
if(start+len>kk) split(I,V,kk,start+len-kk,h);
}
static void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize)
{
off_t buckets[256];
off_t i,h,len;
for(i=0;i<256;i++) buckets[i]=0;
for(i=0;i<oldsize;i++) buckets[old[i]]++;
for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
for(i=255;i>0;i--) buckets[i]=buckets[i-1];
buckets[0]=0;
for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
I[0]=oldsize;
for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
V[oldsize]=0;
for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
I[0]=-1;
for(h=1;I[0]!=-(oldsize+1);h+=h) {
len=0;
for(i=0;i<oldsize+1;) {
if(I[i]<0) {
len-=I[i];
i-=I[i];
} else {
if(len) I[i-len]=-len;
len=V[I[i]]+1-i;
split(I,V,i,len,h);
i+=len;
len=0;
};
};
if(len) I[i-len]=-len;
};
for(i=0;i<oldsize+1;i++) I[V[i]]=i;
}
static off_t matchlen(u_char *olddata,off_t oldsize,u_char *newdata,off_t newsize)
{
off_t i;
for(i=0;(i<oldsize)&&(i<newsize);i++)
if(olddata[i]!=newdata[i]) break;
return i;
}
static off_t search(off_t *I,u_char *old,off_t oldsize,
u_char *newdata,off_t newsize,off_t st,off_t en,off_t *pos)
{
off_t x,y;
if(en-st<2) {
x=matchlen(old+I[st],oldsize-I[st],newdata,newsize);
y=matchlen(old+I[en],oldsize-I[en],newdata,newsize);
if(x>y) {
*pos=I[st];
return x;
} else {
*pos=I[en];
return y;
}
};
x=st+(en-st)/2;
if(memcmp(old+I[x],newdata,MIN(oldsize-I[x],newsize))<0) {
return search(I,old,oldsize,newdata,newsize,x,en,pos);
} else {
return search(I,old,oldsize,newdata,newsize,st,x,pos);
};
}
static void offtout(off_t x,u_char *buf)
{
off_t y;
if(x<0) y=-x; else y=x;
buf[0]=y%256;y-=buf[0];
y=y/256;buf[1]=y%256;y-=buf[1];
y=y/256;buf[2]=y%256;y-=buf[2];
y=y/256;buf[3]=y%256;y-=buf[3];
y=y/256;buf[4]=y%256;y-=buf[4];
y=y/256;buf[5]=y%256;y-=buf[5];
y=y/256;buf[6]=y%256;y-=buf[6];
y=y/256;buf[7]=y%256;
if(x<0) buf[7]|=0x80;
}
// This is main() from bsdiff.c, with the following changes:
//
// - old, oldsize, newdata, newsize are arguments; we don't load this
// data from files. old and newdata are owned by the caller; we
// don't free them at the end.
//
// - the "I" block of memory is owned by the caller, who passes a
// pointer to *I, which can be NULL. This way if we call
// bsdiff() multiple times with the same 'old' data, we only do
// the qsufsort() step the first time.
//
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize,
const char* patch_filename)
{
int fd;
off_t *I;
off_t scan,pos,len;
off_t lastscan,lastpos,lastoffset;
off_t oldscore,scsc;
off_t s,Sf,lenf,Sb,lenb;
off_t overlap,Ss,lens;
off_t i;
off_t dblen,eblen;
u_char *db,*eb;
u_char buf[8];
u_char header[32];
FILE * pf;
BZFILE * pfbz2;
int bz2err;
if (*IP == NULL) {
off_t* V;
*IP = reinterpret_cast<off_t*>(malloc((oldsize+1) * sizeof(off_t)));
V = reinterpret_cast<off_t*>(malloc((oldsize+1) * sizeof(off_t)));
qsufsort(*IP, V, old, oldsize);
free(V);
}
I = *IP;
if(((db=reinterpret_cast<u_char*>(malloc(newsize+1)))==NULL) ||
((eb=reinterpret_cast<u_char*>(malloc(newsize+1)))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
/* Create the patch file */
if ((pf = fopen(patch_filename, "w")) == NULL)
err(1, "%s", patch_filename);
/* Header is
0 8 "BSDIFF40"
8 8 length of bzip2ed ctrl block
16 8 length of bzip2ed diff block
24 8 length of new file */
/* File is
0 32 Header
32 ?? Bzip2ed ctrl block
?? ?? Bzip2ed diff block
?? ?? Bzip2ed extra block */
memcpy(header,"BSDIFF40",8);
offtout(0, header + 8);
offtout(0, header + 16);
offtout(newsize, header + 24);
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
/* Compute the differences, writing ctrl as we go */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan<newsize) {
oldscore=0;
for(scsc=scan+=len;scan<newsize;scan++) {
len=search(I,old,oldsize,newdata+scan,newsize-scan,
0,oldsize,&pos);
for(;scsc<scan+len;scsc++)
if((scsc+lastoffset<oldsize) &&
(old[scsc+lastoffset] == newdata[scsc]))
oldscore++;
if(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffset<oldsize) &&
(old[scan+lastoffset] == newdata[scan]))
oldscore--;
};
if((len!=oldscore) || (scan==newsize)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
if(old[lastpos+i]==newdata[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
lenb=0;
if(scan<newsize) {
s=0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(old[pos-i]==newdata[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
if(lastscan+lenf>scan-lenb) {
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;i<overlap;i++) {
if(newdata[lastscan+lenf-overlap+i]==
old[lastpos+lenf-overlap+i]) s++;
if(newdata[scan-lenb+i]==
old[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
lenf+=lens-overlap;
lenb-=lens;
};
for(i=0;i<lenf;i++)
db[dblen+i]=newdata[lastscan+i]-old[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=newdata[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
offtout(lenf,buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((scan-lenb)-(lastscan+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((pos-lenb)-(lastpos+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed ctrl data */
if ((len = ftello(pf)) == -1)
err(1, "ftello");
offtout(len-32, header + 8);
/* Write compressed diff data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, db, dblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed diff data */
if ((newsize = ftello(pf)) == -1)
err(1, "ftello");
offtout(newsize - len, header + 16);
/* Write compressed extra data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, eb, eblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Seek to the beginning, write the header, and close the file */
if (fseeko(pf, 0, SEEK_SET))
err(1, "fseeko");
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
if (fclose(pf))
err(1, "fclose");
/* Free the memory we used */
free(db);
free(eb);
return 0;
}
+21 -184
View File
@@ -21,16 +21,12 @@
// notice.
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <bzlib.h>
#include <bspatch.h>
#include "applypatch/applypatch.h"
#include "openssl/sha.h"
#include "applypatch.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
@@ -64,184 +60,25 @@ void ShowBSDiffLicense() {
);
}
static off_t offtin(u_char *buf)
{
off_t y;
y=buf[7]&0x7F;
y=y*256;y+=buf[6];
y=y*256;y+=buf[5];
y=y*256;y+=buf[4];
y=y*256;y+=buf[3];
y=y*256;y+=buf[2];
y=y*256;y+=buf[1];
y=y*256;y+=buf[0];
if(buf[7]&0x80) y=-y;
return y;
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch,
ssize_t patch_offset, SinkFn sink, void* token, SHA_CTX* ctx) {
auto sha_sink = [&](const uint8_t* data, size_t len) {
len = sink(data, len, token);
if (ctx) SHA1_Update(ctx, data, len);
return len;
};
return bsdiff::bspatch(old_data, old_size,
reinterpret_cast<const uint8_t*>(&patch->data[patch_offset]),
patch->data.size(), sha_sink);
}
int FillBuffer(unsigned char* buffer, int size, bz_stream* stream) {
stream->next_out = (char*)buffer;
stream->avail_out = size;
while (stream->avail_out > 0) {
int bzerr = BZ2_bzDecompress(stream);
if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) {
printf("bz error %d decompressing\n", bzerr);
return -1;
}
if (stream->avail_out > 0) {
printf("need %d more bytes\n", stream->avail_out);
}
}
return 0;
}
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx) {
std::vector<unsigned char> new_data;
if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) {
return -1;
}
if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) {
printf("short write of output: %d (%s)\n", errno, strerror(errno));
return 1;
}
if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size());
return 0;
}
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
std::vector<unsigned char>* new_data) {
// Patch data format:
// 0 8 "BSDIFF40"
// 8 8 X
// 16 8 Y
// 24 8 sizeof(newfile)
// 32 X bzip2(control block)
// 32+X Y bzip2(diff block)
// 32+X+Y ??? bzip2(extra block)
// with control block a set of triples (x,y,z) meaning "add x bytes
// from oldfile to x bytes from the diff block; copy y bytes from the
// extra block; seek forwards in oldfile by z bytes".
unsigned char* header = (unsigned char*) patch->data + patch_offset;
if (memcmp(header, "BSDIFF40", 8) != 0) {
printf("corrupt bsdiff patch file header (magic number)\n");
return 1;
}
ssize_t ctrl_len, data_len, new_size;
ctrl_len = offtin(header+8);
data_len = offtin(header+16);
new_size = offtin(header+24);
if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
printf("corrupt patch file header (data lengths)\n");
return 1;
}
int bzerr;
bz_stream cstream;
cstream.next_in = patch->data + patch_offset + 32;
cstream.avail_in = ctrl_len;
cstream.bzalloc = NULL;
cstream.bzfree = NULL;
cstream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) {
printf("failed to bzinit control stream (%d)\n", bzerr);
}
bz_stream dstream;
dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
dstream.avail_in = data_len;
dstream.bzalloc = NULL;
dstream.bzfree = NULL;
dstream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) {
printf("failed to bzinit diff stream (%d)\n", bzerr);
}
bz_stream estream;
estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
estream.bzalloc = NULL;
estream.bzfree = NULL;
estream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) {
printf("failed to bzinit extra stream (%d)\n", bzerr);
}
new_data->resize(new_size);
off_t oldpos = 0, newpos = 0;
off_t ctrl[3];
off_t len_read;
int i;
unsigned char buf[24];
while (newpos < new_size) {
// Read control data
if (FillBuffer(buf, 24, &cstream) != 0) {
printf("error while reading control stream\n");
return 1;
}
ctrl[0] = offtin(buf);
ctrl[1] = offtin(buf+8);
ctrl[2] = offtin(buf+16);
if (ctrl[0] < 0 || ctrl[1] < 0) {
printf("corrupt patch (negative byte counts)\n");
return 1;
}
// Sanity check
if (newpos + ctrl[0] > new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read diff string
if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) {
printf("error while reading diff stream\n");
return 1;
}
// Add old data to diff string
for (i = 0; i < ctrl[0]; ++i) {
if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
(*new_data)[newpos+i] += old_data[oldpos+i];
}
}
// Adjust pointers
newpos += ctrl[0];
oldpos += ctrl[0];
// Sanity check
if (newpos + ctrl[1] > new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read extra string
if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) {
printf("error while reading extra stream\n");
return 1;
}
// Adjust pointers
newpos += ctrl[1];
oldpos += ctrl[2];
}
BZ2_bzDecompressEnd(&cstream);
BZ2_bzDecompressEnd(&dstream);
BZ2_bzDecompressEnd(&estream);
return 0;
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, const Value* patch,
ssize_t patch_offset, std::vector<unsigned char>* new_data) {
auto vector_sink = [new_data](const uint8_t* data, size_t len) {
new_data->insert(new_data->end(), data, data + len);
return len;
};
return bsdiff::bspatch(old_data, old_size,
reinterpret_cast<const uint8_t*>(&patch->data[patch_offset]),
patch->data.size(), vector_sink);
}
+1 -1
View File
@@ -32,7 +32,7 @@
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include "applypatch.h"
#include "applypatch/applypatch.h"
static int EliminateOpenFiles(std::set<std::string>* files) {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
+693 -692
View File
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2016 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 "applypatch/imgdiff.h"
int main(int argc, char** argv) {
return imgdiff(argc, const_cast<const char**>(argv));
}
+213 -202
View File
@@ -14,31 +14,41 @@
* limitations under the License.
*/
// See imgdiff.c in this directory for a description of the patch file
// See imgdiff.cpp in this directory for a description of the patch file
// format.
#include <applypatch/imgpatch.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <vector>
#include "zlib.h"
#include "openssl/sha.h"
#include "applypatch.h"
#include "imgdiff.h"
#include "utils.h"
#include <applypatch/applypatch.h>
#include <applypatch/imgdiff.h>
#include <android-base/memory.h>
#include <openssl/sha.h>
#include <zlib.h>
static inline int64_t Read8(const void *address) {
return android::base::get_unaligned<int64_t>(address);
}
static inline int32_t Read4(const void *address) {
return android::base::get_unaligned<int32_t>(address);
}
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const unsigned char* patch_data, ssize_t patch_size,
SinkFn sink, void* token) {
Value patch = {VAL_BLOB, patch_size,
reinterpret_cast<char*>(const_cast<unsigned char*>(patch_data))};
return ApplyImagePatch(
old_data, old_size, &patch, sink, token, nullptr, nullptr);
Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size));
return ApplyImagePatch(old_data, old_size, &patch, sink, token, nullptr, nullptr);
}
/*
@@ -47,203 +57,204 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
* file, and update the SHA context with the output data as well.
* Return 0 on success.
*/
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx,
const Value* bonus_data) {
ssize_t pos = 12;
char* header = patch->data;
if (patch->size < 12) {
printf("patch too short to contain header\n");
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx, const Value* bonus_data) {
if (patch->data.size() < 12) {
printf("patch too short to contain header\n");
return -1;
}
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
// (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
// CHUNK_GZIP.)
size_t pos = 12;
const char* header = &patch->data[0];
if (memcmp(header, "IMGDIFF2", 8) != 0) {
printf("corrupt patch file header (magic number)\n");
return -1;
}
int num_chunks = Read4(header + 8);
for (int i = 0; i < num_chunks; ++i) {
// each chunk's header record starts with 4 bytes.
if (pos + 4 > patch->data.size()) {
printf("failed to read chunk %d record\n", i);
return -1;
}
int type = Read4(&patch->data[pos]);
pos += 4;
if (type == CHUNK_NORMAL) {
const char* normal_header = &patch->data[pos];
pos += 24;
if (pos > patch->data.size()) {
printf("failed to read chunk %d normal header data\n", i);
return -1;
}
}
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
// (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
// CHUNK_GZIP.)
if (memcmp(header, "IMGDIFF2", 8) != 0) {
printf("corrupt patch file header (magic number)\n");
size_t src_start = static_cast<size_t>(Read8(normal_header));
size_t src_len = static_cast<size_t>(Read8(normal_header + 8));
size_t patch_offset = static_cast<size_t>(Read8(normal_header + 16));
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
return -1;
}
}
ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, token, ctx);
} else if (type == CHUNK_RAW) {
const char* raw_header = &patch->data[pos];
pos += 4;
if (pos > patch->data.size()) {
printf("failed to read chunk %d raw header data\n", i);
return -1;
}
int num_chunks = Read4(header+8);
ssize_t data_len = Read4(raw_header);
int i;
for (i = 0; i < num_chunks; ++i) {
// each chunk's header record starts with 4 bytes.
if (pos + 4 > patch->size) {
printf("failed to read chunk %d record\n", i);
return -1;
if (pos + data_len > patch->data.size()) {
printf("failed to read chunk %d raw data\n", i);
return -1;
}
if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len);
if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len, token) !=
data_len) {
printf("failed to write chunk %d raw data\n", i);
return -1;
}
pos += data_len;
} else if (type == CHUNK_DEFLATE) {
// deflate chunks have an additional 60 bytes in their chunk header.
const char* deflate_header = &patch->data[pos];
pos += 60;
if (pos > patch->data.size()) {
printf("failed to read chunk %d deflate header data\n", i);
return -1;
}
size_t src_start = static_cast<size_t>(Read8(deflate_header));
size_t src_len = static_cast<size_t>(Read8(deflate_header + 8));
size_t patch_offset = static_cast<size_t>(Read8(deflate_header + 16));
size_t expanded_len = static_cast<size_t>(Read8(deflate_header + 24));
size_t target_len = static_cast<size_t>(Read8(deflate_header + 32));
int level = Read4(deflate_header + 40);
int method = Read4(deflate_header + 44);
int windowBits = Read4(deflate_header + 48);
int memLevel = Read4(deflate_header + 52);
int strategy = Read4(deflate_header + 56);
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
return -1;
}
// Decompress the source data; the chunk header tells us exactly
// how big we expect it to be when decompressed.
// Note: expanded_len will include the bonus data size if
// the patch was constructed with bonus data. The
// deflation will come up 'bonus_size' bytes short; these
// must be appended from the bonus_data value.
size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->data.size() : 0;
std::vector<unsigned char> expanded_source(expanded_len);
// inflate() doesn't like strm.next_out being a nullptr even with
// avail_out being zero (Z_STREAM_ERROR).
if (expanded_len != 0) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = src_len;
strm.next_in = old_data + src_start;
strm.avail_out = expanded_len;
strm.next_out = expanded_source.data();
int ret = inflateInit2(&strm, -15);
if (ret != Z_OK) {
printf("failed to init source inflation: %d\n", ret);
return -1;
}
int type = Read4(patch->data + pos);
pos += 4;
if (type == CHUNK_NORMAL) {
char* normal_header = patch->data + pos;
pos += 24;
if (pos > patch->size) {
printf("failed to read chunk %d normal header data\n", i);
return -1;
}
size_t src_start = Read8(normal_header);
size_t src_len = Read8(normal_header+8);
size_t patch_offset = Read8(normal_header+16);
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
return -1;
}
ApplyBSDiffPatch(old_data + src_start, src_len,
patch, patch_offset, sink, token, ctx);
} else if (type == CHUNK_RAW) {
char* raw_header = patch->data + pos;
pos += 4;
if (pos > patch->size) {
printf("failed to read chunk %d raw header data\n", i);
return -1;
}
ssize_t data_len = Read4(raw_header);
if (pos + data_len > patch->size) {
printf("failed to read chunk %d raw data\n", i);
return -1;
}
if (ctx) SHA1_Update(ctx, patch->data + pos, data_len);
if (sink((unsigned char*)patch->data + pos,
data_len, token) != data_len) {
printf("failed to write chunk %d raw data\n", i);
return -1;
}
pos += data_len;
} else if (type == CHUNK_DEFLATE) {
// deflate chunks have an additional 60 bytes in their chunk header.
char* deflate_header = patch->data + pos;
pos += 60;
if (pos > patch->size) {
printf("failed to read chunk %d deflate header data\n", i);
return -1;
}
size_t src_start = Read8(deflate_header);
size_t src_len = Read8(deflate_header+8);
size_t patch_offset = Read8(deflate_header+16);
size_t expanded_len = Read8(deflate_header+24);
int level = Read4(deflate_header+40);
int method = Read4(deflate_header+44);
int windowBits = Read4(deflate_header+48);
int memLevel = Read4(deflate_header+52);
int strategy = Read4(deflate_header+56);
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
return -1;
}
// Decompress the source data; the chunk header tells us exactly
// how big we expect it to be when decompressed.
// Note: expanded_len will include the bonus data size if
// the patch was constructed with bonus data. The
// deflation will come up 'bonus_size' bytes short; these
// must be appended from the bonus_data value.
size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->size : 0;
std::vector<unsigned char> expanded_source(expanded_len);
// inflate() doesn't like strm.next_out being a nullptr even with
// avail_out being zero (Z_STREAM_ERROR).
if (expanded_len != 0) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = src_len;
strm.next_in = (unsigned char*)(old_data + src_start);
strm.avail_out = expanded_len;
strm.next_out = expanded_source.data();
int ret;
ret = inflateInit2(&strm, -15);
if (ret != Z_OK) {
printf("failed to init source inflation: %d\n", ret);
return -1;
}
// Because we've provided enough room to accommodate the output
// data, we expect one call to inflate() to suffice.
ret = inflate(&strm, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END) {
printf("source inflation returned %d\n", ret);
return -1;
}
// We should have filled the output buffer exactly, except
// for the bonus_size.
if (strm.avail_out != bonus_size) {
printf("source inflation short by %zu bytes\n", strm.avail_out-bonus_size);
return -1;
}
inflateEnd(&strm);
if (bonus_size) {
memcpy(expanded_source.data() + (expanded_len - bonus_size),
bonus_data->data, bonus_size);
}
}
// Next, apply the bsdiff patch (in memory) to the uncompressed
// data.
std::vector<unsigned char> uncompressed_target_data;
if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len,
patch, patch_offset,
&uncompressed_target_data) != 0) {
return -1;
}
// Now compress the target data and append it to the output.
// we're done with the expanded_source data buffer, so we'll
// reuse that memory to receive the output of deflate.
if (expanded_source.size() < 32768U) {
expanded_source.resize(32768U);
}
{
std::vector<unsigned char>& temp_data = expanded_source;
// now the deflate stream
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = uncompressed_target_data.size();
strm.next_in = uncompressed_target_data.data();
int ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
if (ret != Z_OK) {
printf("failed to init uncompressed data deflation: %d\n", ret);
return -1;
}
do {
strm.avail_out = temp_data.size();
strm.next_out = temp_data.data();
ret = deflate(&strm, Z_FINISH);
ssize_t have = temp_data.size() - strm.avail_out;
if (sink(temp_data.data(), have, token) != have) {
printf("failed to write %ld compressed bytes to output\n",
(long)have);
return -1;
}
if (ctx) SHA1_Update(ctx, temp_data.data(), have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
}
} else {
printf("patch chunk %d is unknown type %d\n", i, type);
return -1;
// Because we've provided enough room to accommodate the output
// data, we expect one call to inflate() to suffice.
ret = inflate(&strm, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END) {
printf("source inflation returned %d\n", ret);
return -1;
}
}
// We should have filled the output buffer exactly, except
// for the bonus_size.
if (strm.avail_out != bonus_size) {
printf("source inflation short by %zu bytes\n", strm.avail_out - bonus_size);
return -1;
}
inflateEnd(&strm);
return 0;
if (bonus_size) {
memcpy(expanded_source.data() + (expanded_len - bonus_size), &bonus_data->data[0],
bonus_size);
}
}
// Next, apply the bsdiff patch (in memory) to the uncompressed data.
std::vector<unsigned char> uncompressed_target_data;
// TODO(senj): Remove the only usage of ApplyBSDiffPatchMem here,
// replace it with ApplyBSDiffPatch with a custom sink function that
// wraps the given sink function to stream output to save memory.
if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len, patch, patch_offset,
&uncompressed_target_data) != 0) {
return -1;
}
if (uncompressed_target_data.size() != target_len) {
printf("expected target len to be %zu, but it's %zu\n", target_len,
uncompressed_target_data.size());
return -1;
}
// Now compress the target data and append it to the output.
// we're done with the expanded_source data buffer, so we'll
// reuse that memory to receive the output of deflate.
if (expanded_source.size() < 32768U) {
expanded_source.resize(32768U);
}
{
std::vector<unsigned char>& temp_data = expanded_source;
// now the deflate stream
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = uncompressed_target_data.size();
strm.next_in = uncompressed_target_data.data();
int ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
if (ret != Z_OK) {
printf("failed to init uncompressed data deflation: %d\n", ret);
return -1;
}
do {
strm.avail_out = temp_data.size();
strm.next_out = temp_data.data();
ret = deflate(&strm, Z_FINISH);
ssize_t have = temp_data.size() - strm.avail_out;
if (sink(temp_data.data(), have, token) != have) {
printf("failed to write %zd compressed bytes to output\n", have);
return -1;
}
if (ctx) SHA1_Update(ctx, temp_data.data(), have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
}
} else {
printf("patch chunk %d is unknown type %d\n", i, type);
return -1;
}
}
return 0;
}
@@ -17,11 +17,15 @@
#ifndef _APPLYPATCH_H
#define _APPLYPATCH_H
#include <stdint.h>
#include <sys/stat.h>
#include <memory>
#include <string>
#include <vector>
#include "openssl/sha.h"
#include <openssl/sha.h>
#include "edify/expr.h"
struct FileContents {
@@ -39,33 +43,28 @@ struct FileContents {
typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*);
// applypatch.c
// applypatch.cpp
int ShowLicenses();
size_t FreeSpaceForFile(const char* filename);
int CacheSizeCheck(size_t bytes);
int ParseSha1(const char* str, uint8_t* digest);
int applypatch_flash(const char* source_filename, const char* target_filename,
const char* target_sha1_str, size_t target_size);
int applypatch(const char* source_filename,
const char* target_filename,
const char* target_sha1_str,
size_t target_size,
int num_patches,
char** const patch_sha1_str,
Value** patch_data,
Value* bonus_data);
const std::vector<std::string>& patch_sha1_str,
const std::vector<std::unique_ptr<Value>>& patch_data,
const Value* bonus_data);
int applypatch_check(const char* filename,
int num_patches,
char** const patch_sha1_str);
const std::vector<std::string>& patch_sha1_str);
int applypatch_flash(const char* source_filename, const char* target_filename,
const char* target_sha1_str, size_t target_size);
int LoadFileContents(const char* filename, FileContents* file);
int SaveFileContents(const char* filename, const FileContents* file);
void FreeFileContents(FileContents* file);
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int num_patches);
// bsdiff.cpp
// bspatch.cpp
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
@@ -14,17 +14,26 @@
* limitations under the License.
*/
#ifndef _APPLYPATCH_IMGDIFF_H
#define _APPLYPATCH_IMGDIFF_H
#include <stddef.h>
// Image patch chunk types
#define CHUNK_NORMAL 0
#define CHUNK_GZIP 1 // version 1 only
#define CHUNK_DEFLATE 2 // version 2 only
#define CHUNK_RAW 3 // version 2 only
#define CHUNK_NORMAL 0
#define CHUNK_GZIP 1 // version 1 only
#define CHUNK_DEFLATE 2 // version 2 only
#define CHUNK_RAW 3 // version 2 only
// The gzip header size is actually variable, but we currently don't
// support gzipped data with any of the optional fields, so for now it
// will always be ten bytes. See RFC 1952 for the definition of the
// gzip format.
#define GZIP_HEADER_LEN 10
static constexpr size_t GZIP_HEADER_LEN = 10;
// The gzip footer size really is fixed.
#define GZIP_FOOTER_LEN 8
static constexpr size_t GZIP_FOOTER_LEN = 8;
int imgdiff(int argc, const char** argv);
#endif // _APPLYPATCH_IMGDIFF_H
+6 -4
View File
@@ -14,13 +14,15 @@
* limitations under the License.
*/
#ifndef _IMGPATCH_H
#define _IMGPATCH_H
#ifndef _APPLYPATCH_IMGPATCH_H
#define _APPLYPATCH_IMGPATCH_H
typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*);
#include <sys/types.h>
using SinkFn = ssize_t (*)(const unsigned char*, ssize_t, void*);
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const unsigned char* patch_data, ssize_t patch_size,
SinkFn sink, void* token);
#endif //_IMGPATCH_H
#endif // _APPLYPATCH_IMGPATCH_H
+6
View File
@@ -0,0 +1,6 @@
# This file is for libimgpatch in Chrome OS.
Name: libimgpatch
Description: Apply imgdiff patch
Version: 0.0.1
Libs: -limgpatch -lbz2 -lz
-65
View File
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2009 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 <stdio.h>
#include "utils.h"
/** Write a 4-byte value to f in little-endian order. */
void Write4(int value, FILE* f) {
fputc(value & 0xff, f);
fputc((value >> 8) & 0xff, f);
fputc((value >> 16) & 0xff, f);
fputc((value >> 24) & 0xff, f);
}
/** Write an 8-byte value to f in little-endian order. */
void Write8(long long value, FILE* f) {
fputc(value & 0xff, f);
fputc((value >> 8) & 0xff, f);
fputc((value >> 16) & 0xff, f);
fputc((value >> 24) & 0xff, f);
fputc((value >> 32) & 0xff, f);
fputc((value >> 40) & 0xff, f);
fputc((value >> 48) & 0xff, f);
fputc((value >> 56) & 0xff, f);
}
int Read2(void* pv) {
unsigned char* p = reinterpret_cast<unsigned char*>(pv);
return (int)(((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
int Read4(void* pv) {
unsigned char* p = reinterpret_cast<unsigned char*>(pv);
return (int)(((unsigned int)p[3] << 24) |
((unsigned int)p[2] << 16) |
((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
long long Read8(void* pv) {
unsigned char* p = reinterpret_cast<unsigned char*>(pv);
return (long long)(((unsigned long long)p[7] << 56) |
((unsigned long long)p[6] << 48) |
((unsigned long long)p[5] << 40) |
((unsigned long long)p[4] << 32) |
((unsigned long long)p[3] << 24) |
((unsigned long long)p[2] << 16) |
((unsigned long long)p[1] << 8) |
(unsigned long long)p[0]);
}
+111 -144
View File
@@ -14,178 +14,145 @@
* limitations under the License.
*/
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include "asn1_decoder.h"
#include <stdint.h>
typedef struct asn1_context {
size_t length;
uint8_t* p;
int app_type;
} asn1_context_t;
static const int kMaskConstructed = 0xE0;
static const int kMaskTag = 0x7F;
static const int kMaskAppType = 0x1F;
static const int kTagOctetString = 0x04;
static const int kTagOid = 0x06;
static const int kTagSequence = 0x30;
static const int kTagSet = 0x31;
static const int kTagConstructed = 0xA0;
asn1_context_t* asn1_context_new(uint8_t* buffer, size_t length) {
asn1_context_t* ctx = (asn1_context_t*) calloc(1, sizeof(asn1_context_t));
if (ctx == NULL) {
return NULL;
}
ctx->p = buffer;
ctx->length = length;
return ctx;
int asn1_context::peek_byte() const {
if (length_ == 0) {
return -1;
}
return *p_;
}
void asn1_context_free(asn1_context_t* ctx) {
free(ctx);
int asn1_context::get_byte() {
if (length_ == 0) {
return -1;
}
int byte = *p_;
p_++;
length_--;
return byte;
}
static inline int peek_byte(asn1_context_t* ctx) {
if (ctx->length <= 0) {
return -1;
}
return *ctx->p;
bool asn1_context::skip_bytes(size_t num_skip) {
if (length_ < num_skip) {
return false;
}
p_ += num_skip;
length_ -= num_skip;
return true;
}
static inline int get_byte(asn1_context_t* ctx) {
if (ctx->length <= 0) {
return -1;
}
int byte = *ctx->p;
ctx->p++;
ctx->length--;
return byte;
}
static inline bool skip_bytes(asn1_context_t* ctx, size_t num_skip) {
if (ctx->length < num_skip) {
return false;
}
ctx->p += num_skip;
ctx->length -= num_skip;
bool asn1_context::decode_length(size_t* out_len) {
int num_octets = get_byte();
if (num_octets == -1) {
return false;
}
if ((num_octets & 0x80) == 0x00) {
*out_len = num_octets;
return true;
}
static bool decode_length(asn1_context_t* ctx, size_t* out_len) {
int num_octets = get_byte(ctx);
if (num_octets == -1) {
return false;
}
num_octets &= kMaskTag;
if (static_cast<size_t>(num_octets) >= sizeof(size_t)) {
return false;
}
size_t length = 0;
for (int i = 0; i < num_octets; ++i) {
int byte = get_byte();
if (byte == -1) {
return false;
}
if ((num_octets & 0x80) == 0x00) {
*out_len = num_octets;
return 1;
}
num_octets &= kMaskTag;
if ((size_t)num_octets >= sizeof(size_t)) {
return false;
}
size_t length = 0;
for (int i = 0; i < num_octets; ++i) {
int byte = get_byte(ctx);
if (byte == -1) {
return false;
}
length <<= 8;
length += byte;
}
*out_len = length;
return true;
length <<= 8;
length += byte;
}
*out_len = length;
return true;
}
/**
* Returns the constructed type and advances the pointer. E.g. A0 -> 0
*/
asn1_context_t* asn1_constructed_get(asn1_context_t* ctx) {
int type = get_byte(ctx);
if (type == -1 || (type & kMaskConstructed) != kTagConstructed) {
return NULL;
}
asn1_context* asn1_context::asn1_constructed_get() {
int type = get_byte();
if (type == -1 || (type & kMaskConstructed) != kTagConstructed) {
return nullptr;
}
size_t length;
if (!decode_length(&length) || length > length_) {
return nullptr;
}
asn1_context* app_ctx = new asn1_context(p_, length);
app_ctx->app_type_ = type & kMaskAppType;
return app_ctx;
}
bool asn1_context::asn1_constructed_skip_all() {
int byte = peek_byte();
while (byte != -1 && (byte & kMaskConstructed) == kTagConstructed) {
skip_bytes(1);
size_t length;
if (!decode_length(ctx, &length) || length > ctx->length) {
return NULL;
if (!decode_length(&length) || !skip_bytes(length)) {
return false;
}
asn1_context_t* app_ctx = asn1_context_new(ctx->p, length);
app_ctx->app_type = type & kMaskAppType;
return app_ctx;
byte = peek_byte();
}
return byte != -1;
}
bool asn1_constructed_skip_all(asn1_context_t* ctx) {
int byte = peek_byte(ctx);
while (byte != -1 && (byte & kMaskConstructed) == kTagConstructed) {
skip_bytes(ctx, 1);
size_t length;
if (!decode_length(ctx, &length) || !skip_bytes(ctx, length)) {
return false;
}
byte = peek_byte(ctx);
}
return byte != -1;
int asn1_context::asn1_constructed_type() const {
return app_type_;
}
int asn1_constructed_type(asn1_context_t* ctx) {
return ctx->app_type;
asn1_context* asn1_context::asn1_sequence_get() {
if ((get_byte() & kMaskTag) != kTagSequence) {
return nullptr;
}
size_t length;
if (!decode_length(&length) || length > length_) {
return nullptr;
}
return new asn1_context(p_, length);
}
asn1_context_t* asn1_sequence_get(asn1_context_t* ctx) {
if ((get_byte(ctx) & kMaskTag) != kTagSequence) {
return NULL;
}
size_t length;
if (!decode_length(ctx, &length) || length > ctx->length) {
return NULL;
}
return asn1_context_new(ctx->p, length);
asn1_context* asn1_context::asn1_set_get() {
if ((get_byte() & kMaskTag) != kTagSet) {
return nullptr;
}
size_t length;
if (!decode_length(&length) || length > length_) {
return nullptr;
}
return new asn1_context(p_, length);
}
asn1_context_t* asn1_set_get(asn1_context_t* ctx) {
if ((get_byte(ctx) & kMaskTag) != kTagSet) {
return NULL;
}
size_t length;
if (!decode_length(ctx, &length) || length > ctx->length) {
return NULL;
}
return asn1_context_new(ctx->p, length);
bool asn1_context::asn1_sequence_next() {
size_t length;
if (get_byte() == -1 || !decode_length(&length) || !skip_bytes(length)) {
return false;
}
return true;
}
bool asn1_sequence_next(asn1_context_t* ctx) {
size_t length;
if (get_byte(ctx) == -1 || !decode_length(ctx, &length) || !skip_bytes(ctx, length)) {
return false;
}
return true;
bool asn1_context::asn1_oid_get(const uint8_t** oid, size_t* length) {
if (get_byte() != kTagOid) {
return false;
}
if (!decode_length(length) || *length == 0 || *length > length_) {
return false;
}
*oid = p_;
return true;
}
bool asn1_oid_get(asn1_context_t* ctx, uint8_t** oid, size_t* length) {
if (get_byte(ctx) != kTagOid) {
return false;
}
if (!decode_length(ctx, length) || *length == 0 || *length > ctx->length) {
return false;
}
*oid = ctx->p;
return true;
}
bool asn1_octet_string_get(asn1_context_t* ctx, uint8_t** octet_string, size_t* length) {
if (get_byte(ctx) != kTagOctetString) {
return false;
}
if (!decode_length(ctx, length) || *length == 0 || *length > ctx->length) {
return false;
}
*octet_string = ctx->p;
return true;
bool asn1_context::asn1_octet_string_get(const uint8_t** octet_string, size_t* length) {
if (get_byte() != kTagOctetString) {
return false;
}
if (!decode_length(length) || *length == 0 || *length > length_) {
return false;
}
*octet_string = p_;
return true;
}
+31 -12
View File
@@ -14,23 +14,42 @@
* limitations under the License.
*/
#ifndef ASN1_DECODER_H_
#define ASN1_DECODER_H_
#include <stdint.h>
typedef struct asn1_context asn1_context_t;
class asn1_context {
public:
asn1_context(const uint8_t* buffer, size_t length) : p_(buffer), length_(length), app_type_(0) {}
int asn1_constructed_type() const;
asn1_context* asn1_constructed_get();
bool asn1_constructed_skip_all();
asn1_context* asn1_sequence_get();
asn1_context* asn1_set_get();
bool asn1_sequence_next();
bool asn1_oid_get(const uint8_t** oid, size_t* length);
bool asn1_octet_string_get(const uint8_t** octet_string, size_t* length);
asn1_context_t* asn1_context_new(uint8_t* buffer, size_t length);
void asn1_context_free(asn1_context_t* ctx);
asn1_context_t* asn1_constructed_get(asn1_context_t* ctx);
bool asn1_constructed_skip_all(asn1_context_t* ctx);
int asn1_constructed_type(asn1_context_t* ctx);
asn1_context_t* asn1_sequence_get(asn1_context_t* ctx);
asn1_context_t* asn1_set_get(asn1_context_t* ctx);
bool asn1_sequence_next(asn1_context_t* seq);
bool asn1_oid_get(asn1_context_t* ctx, uint8_t** oid, size_t* length);
bool asn1_octet_string_get(asn1_context_t* ctx, uint8_t** octet_string, size_t* length);
private:
static constexpr int kMaskConstructed = 0xE0;
static constexpr int kMaskTag = 0x7F;
static constexpr int kMaskAppType = 0x1F;
static constexpr int kTagOctetString = 0x04;
static constexpr int kTagOid = 0x06;
static constexpr int kTagSequence = 0x30;
static constexpr int kTagSet = 0x31;
static constexpr int kTagConstructed = 0xA0;
int peek_byte() const;
int get_byte();
bool skip_bytes(size_t num_skip);
bool decode_length(size_t* out_len);
const uint8_t* p_;
size_t length_;
int app_type_;
};
#endif /* ASN1_DECODER_H_ */
+7 -23
View File
@@ -14,32 +14,16 @@
LOCAL_PATH := $(call my-dir)
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 25; echo $$?),0)
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES := bootloader_message.cpp
LOCAL_MODULE := libbootloader_message
LOCAL_STATIC_LIBRARIES := libfs_mgr
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)
endif
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES := bootloader_message.cpp
LOCAL_MODULE := libbootloader_message
LOCAL_C_INCLUDES += bionic $(LOCAL_PATH)/include
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport
LOCAL_SHARED_LIBRARIES += libstlport
else
LOCAL_SHARED_LIBRARIES += libc++
endif
LOCAL_CFLAGS := -DEXCLUDE_FS_MGR
# ignore bootloader's factory reset command even when written to /misc
ifeq ($(TW_IGNORE_MISC_WIPE_DATA), true)
LOCAL_CFLAGS += -DIGNORE_MISC_WIPE_DATA
LOCAL_STATIC_LIBRARIES := libbase libfs_mgr
LOCAL_CFLAGS := -Werror
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 26; echo $$?),0)
TARGET_GLOBAL_CFLAGS += -DUSE_OLD_BOOTLOADER_MESSAGE
CLANG_TARGET_GLOBAL_CFLAGS += -DUSE_OLD_BOOTLOADER_MESSAGE
endif
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)
+96 -185
View File
@@ -19,31 +19,18 @@
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/system_properties.h>
#include <string>
#include <vector>
/*
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
*/
#ifndef EXCLUDE_FS_MGR
#include <fs_mgr.h>
#endif
static std::string misc_blkdev;
#ifdef USE_OLD_BOOTLOADER_MESSAGE
#include <sys/system_properties.h>
void set_misc_device(std::string name) {
misc_blkdev = name;
}
#ifndef EXCLUDE_FS_MGR
static struct fstab* read_fstab(std::string* err) {
// The fstab path is always "/fstab.${ro.hardware}".
std::string fstab_path = "/fstab.";
@@ -62,23 +49,28 @@ static struct fstab* read_fstab(std::string* err) {
#endif
static std::string get_misc_blk_device(std::string* err) {
#ifdef EXCLUDE_FS_MGR
return misc_blkdev;
#else
#ifdef USE_OLD_BOOTLOADER_MESSAGE
struct fstab* fstab = read_fstab(err);
if (fstab == nullptr) {
#else
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
#endif
if (!fstab) {
*err = "failed to read default fstab";
return "";
}
#ifdef USE_OLD_BOOTLOADER_MESSAGE
fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
#else
fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab.get(), "/misc");
#endif
if (record == nullptr) {
*err = "failed to find /misc partition";
return "";
}
return record->blk_device;
#endif
}
// In recovery mode, recovery can get started and try to access the misc
// device before the kernel has actually created it.
static bool wait_for_device(const std::string& blk_device, std::string* err) {
@@ -90,127 +82,94 @@ static bool wait_for_device(const std::string& blk_device, std::string* err) {
struct stat buf;
ret = stat(blk_device.c_str(), &buf);
if (ret == -1) {
char buffer[2048];
sprintf(buffer, "failed to stat %s try %d: %s\n",
blk_device.c_str(), tries, strerror(errno));
*err += buffer;
/*
*err += android::base::StringPrintf("failed to stat %s try %d: %s\n",
blk_device.c_str(), tries, strerror(errno));
*/
sleep(1);
}
} while (ret && tries < 10);
if (ret) {
*err += "failed to stat " + blk_device + "\n";
/*
*err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str());
*/
}
return ret == 0;
}
static bool read_misc_partition(void* p, size_t size, size_t offset, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
static bool read_misc_partition(void* p, size_t size, const std::string& misc_blk_device,
size_t offset, std::string* err) {
if (!wait_for_device(misc_blk_device, err)) {
return false;
}
int fd(open(misc_blk_device.c_str(), O_RDONLY));
if (fd < 0) {
*err = "failed to open " + misc_blk_device + ": ";
*err += strerror(errno);
/*
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
*err = "failed to lseek " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
*err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if (read(fd, p, size) != size) {
*err = "failed to read " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
if (!android::base::ReadFully(fd, p, size)) {
*err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
close(fd);
return true;
}
static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
*err = "no misc device set";
return false;
}
int fd = (open(misc_blk_device.c_str(), O_WRONLY | O_SYNC));
static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
size_t offset, std::string* err) {
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
if (fd == -1) {
*err = "failed to open " + misc_blk_device + ": ";
*err += strerror(errno);
/*
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
*err = "failed to lseek " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
*err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if (write(fd, p, size) != size) {
*err = "failed to write " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
if (!android::base::WriteFully(fd, p, size)) {
*err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
// TODO: O_SYNC and fsync duplicates each other?
if (fsync(fd) == -1) {
*err = "failed to fsync " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
*err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
close(fd);
return true;
}
bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
std::string* err) {
return read_misc_partition(boot, sizeof(*boot), misc_blk_device,
BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
}
bool read_bootloader_message(bootloader_message* boot, std::string* err) {
return read_misc_partition(boot, sizeof(*boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
return read_bootloader_message_from(boot, misc_blk_device, err);
}
bool write_bootloader_message_to(const bootloader_message& boot, const std::string& misc_blk_device,
std::string* err) {
return write_misc_partition(&boot, sizeof(boot), misc_blk_device,
BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
}
bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
return write_misc_partition(&boot, sizeof(boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
return write_bootloader_message_to(boot, misc_blk_device, err);
}
bool clear_bootloader_message(std::string* err) {
@@ -224,120 +183,72 @@ bool write_bootloader_message(const std::vector<std::string>& options, std::stri
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
for (const auto& s : options) {
strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
if (s.substr(s.size() - 1) != "\n") {
if (s.back() != '\n') {
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
}
return write_bootloader_message(boot, err);
}
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) {
bootloader_message boot;
if (!read_bootloader_message(&boot, err)) {
return false;
}
// Zero out the entire fields.
memset(boot.command, 0, sizeof(boot.command));
memset(boot.recovery, 0, sizeof(boot.recovery));
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
for (const auto& s : options) {
strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
if (s.back() != '\n') {
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
}
return write_bootloader_message(boot, err);
}
bool write_reboot_bootloader(std::string* err) {
bootloader_message boot;
if (!read_bootloader_message(&boot, err)) {
return false;
}
if (boot.command[0] != '\0') {
*err = "Bootloader command pending.";
return false;
}
strlcpy(boot.command, "bootonce-bootloader", sizeof(boot.command));
return write_bootloader_message(boot, err);
}
bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
package_data->resize(size);
return read_misc_partition(&(*package_data)[0], size, WIPE_PACKAGE_OFFSET_IN_MISC, err);
return read_misc_partition(&(*package_data)[0], size, misc_blk_device,
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
bool write_wipe_package(const std::string& package_data, std::string* err) {
return write_misc_partition(package_data.data(), package_data.size(),
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
return write_misc_partition(package_data.data(), package_data.size(), misc_blk_device,
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
extern "C" bool write_reboot_bootloader(void) {
std::string err;
return write_reboot_bootloader(&err);
}
extern "C" bool write_bootloader_message(const char* options) {
std::string err;
bootloader_message boot = {};
memcpy(&boot, options, sizeof(boot));
return write_bootloader_message(boot, &err);
}
static const char *COMMAND_FILE = "/cache/recovery/command";
static const int MAX_ARG_LENGTH = 4096;
static const int MAX_ARGS = 100;
// command line args come from, in decreasing precedence:
// - the actual command line
// - the bootloader control block (one per line, after "recovery")
// - the contents of COMMAND_FILE (one per line)
void
get_args(int *argc, char ***argv) {
bootloader_message boot = {};
std::string err;
if (!read_bootloader_message(&boot, &err)) {
printf("%s\n", err.c_str());
// If fails, leave a zeroed bootloader_message.
memset(&boot, 0, sizeof(boot));
}
//stage = strndup(boot.stage, sizeof(boot.stage));
if (boot.command[0] != 0 && boot.command[0] != 255) {
printf("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
}
if (boot.status[0] != 0 && boot.status[0] != 255) {
printf("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
}
// --- if arguments weren't supplied, look in the bootloader control block
if (*argc <= 1) {
boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
const char *arg = strtok(boot.recovery, "\n");
if (arg != NULL && !strcmp(arg, "recovery")) {
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = strdup(arg);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if ((arg = strtok(NULL, "\n")) == NULL) break;
// if the device does not have an own recovery key combo we just want to open TWRP after
// walking through the factory reset screen - without actually doing a factory reset
#ifdef IGNORE_MISC_WIPE_DATA
if (!strcmp(arg, "--wipe_data")) {
(*argv)[*argc] = "";
*argc = *argc -1;
printf("Bootloader arg \"%s\" ignored because TWRP was compiled with TW_IGNORE_MISC_WIPE_DATA\n", arg);
continue;
}
#endif
(*argv)[*argc] = strdup(arg);
}
printf("Got arguments from boot message\n");
} else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
printf("Bad boot message\n\"%.20s\"\n", boot.recovery);
}
}
// --- if that doesn't work, try the command file (if we have /cache).
if (*argc <= 1/* && has_cache*/) {
FILE *fp = fopen(COMMAND_FILE, "r");
if (fp != NULL) {
char *token;
char *argv0 = (*argv)[0];
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = argv0; // use the same program name
char buf[MAX_ARG_LENGTH];
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
token = strtok(buf, "\r\n");
if (token != NULL) {
(*argv)[*argc] = strdup(token); // Strip newline.
} else {
--*argc;
}
}
fclose(fp);
printf("Got arguments from %s\n", COMMAND_FILE);
}
}
// --> write the arguments we have back into the bootloader control block
// always boot into recovery after this (until finish_recovery() is called)
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
int i;
for (i = 1; i < *argc; ++i) {
strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
if (!write_bootloader_message(boot, &err)) {
printf("%s\n", err.c_str());
}
return write_bootloader_message({options}, &err);
}
@@ -17,23 +17,21 @@
#ifndef _BOOTLOADER_MESSAGE_H
#define _BOOTLOADER_MESSAGE_H
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
// Spaces used by misc partition are as below:
// 0 - 2K Bootloader Message
// 2K - 16K Used by Vendor's bootloader
// 0 - 2K For bootloader_message
// 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used
// as bootloader_message_ab struct)
// 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices
// Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
// are not configurable without changing all of them.
#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = BOARD_RECOVERY_BLDRMSG_OFFSET;
static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024 + BOOTLOADER_MESSAGE_OFFSET_IN_MISC;
#else
static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
#endif
/* Bootloader Message
/* Bootloader Message (2-KiB)
*
* This structure describes the content of a block in flash
* that is used for recovery and the bootloader to talk to
@@ -44,8 +42,9 @@ static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
* It is also updated by the bootloader when firmware update
* is complete (to boot into recovery for any final cleanup)
*
* The status field is written by the bootloader after the
* completion of an "update-radio" or "update-hboot" command.
* The status field was used by the bootloader after the completion
* of an "update-radio" or "update-hboot" command, which has been
* deprecated since Froyo.
*
* The recovery field is only written by linux and used
* for the system to send a message to recovery or the
@@ -56,18 +55,17 @@ static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
* package it is. If the value is of the format "#/#" (eg, "1/3"),
* the UI will add a simple indicator of that status.
*
* The slot_suffix field is used for A/B implementations where the
* bootloader does not set the androidboot.ro.boot.slot_suffix kernel
* commandline parameter. This is used by fs_mgr to mount /system and
* other partitions with the slotselect flag set in fstab. A/B
* implementations are free to use all 32 bytes and may store private
* data past the first NUL-byte in this field.
* We used to have slot_suffix field for A/B boot control metadata in
* this struct, which gets unintentionally cleared by recovery or
* uncrypt. Move it into struct bootloader_message_ab to avoid the
* issue.
*/
struct bootloader_message {
char command[32];
char status[32];
char recovery[768];
#ifdef USE_OLD_BOOTLOADER_MESSAGE
// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
@@ -76,23 +74,156 @@ struct bootloader_message {
char stage[32];
char slot_suffix[32];
char reserved[192];
#else
// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];
// The 'reserved' field used to be 224 bytes when it was initially
// carved off from the 1024-byte recovery field. Bump it up to
// 1184-byte so that the entire bootloader_message struct rounds up
// to 2048-byte.
char reserved[1184];
#endif
};
/**
* We must be cautious when changing the bootloader_message struct size,
* because A/B-specific fields may end up with different offsets.
*/
#if !defined(USE_OLD_BOOTLOADER_MESSAGE) && ((__STDC_VERSION__ >= 201112L) || defined(__cplusplus))
static_assert(sizeof(struct bootloader_message) == 2048,
"struct bootloader_message size changes, which may break A/B devices");
#endif
/**
* The A/B-specific bootloader message structure (4-KiB).
*
* We separate A/B boot control metadata from the regular bootloader
* message struct and keep it here. Everything that's A/B-specific
* stays after struct bootloader_message, which should be managed by
* the A/B-bootloader or boot control HAL.
*
* The slot_suffix field is used for A/B implementations where the
* bootloader does not set the androidboot.ro.boot.slot_suffix kernel
* commandline parameter. This is used by fs_mgr to mount /system and
* other partitions with the slotselect flag set in fstab. A/B
* implementations are free to use all 32 bytes and may store private
* data past the first NUL-byte in this field. It is encouraged, but
* not mandatory, to use 'struct bootloader_control' described below.
*/
struct bootloader_message_ab {
struct bootloader_message message;
char slot_suffix[32];
// Round up the entire struct to 4096-byte.
char reserved[2016];
};
/**
* Be cautious about the struct size change, in case we put anything post
* bootloader_message_ab struct (b/29159185).
*/
#if !defined(USE_OLD_BOOTLOADER_MESSAGE) && ((__STDC_VERSION__ >= 201112L) || defined(__cplusplus))
static_assert(sizeof(struct bootloader_message_ab) == 4096,
"struct bootloader_message_ab size changes");
#endif
#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */
#define BOOT_CTRL_VERSION 1
struct slot_metadata {
// Slot priority with 15 meaning highest priority, 1 lowest
// priority and 0 the slot is unbootable.
uint8_t priority : 4;
// Number of times left attempting to boot this slot.
uint8_t tries_remaining : 3;
// 1 if this slot has booted successfully, 0 otherwise.
uint8_t successful_boot : 1;
// 1 if this slot is corrupted from a dm-verity corruption, 0
// otherwise.
uint8_t verity_corrupted : 1;
// Reserved for further use.
uint8_t reserved : 7;
} __attribute__((packed));
/* Bootloader Control AB
*
* This struct can be used to manage A/B metadata. It is designed to
* be put in the 'slot_suffix' field of the 'bootloader_message'
* structure described above. It is encouraged to use the
* 'bootloader_control' structure to store the A/B metadata, but not
* mandatory.
*/
struct bootloader_control {
// NUL terminated active slot suffix.
char slot_suffix[4];
// Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
uint32_t magic;
// Version of struct being used (see BOOT_CTRL_VERSION).
uint8_t version;
// Number of slots being managed.
uint8_t nb_slot : 3;
// Number of times left attempting to boot recovery.
uint8_t recovery_tries_remaining : 3;
// Ensure 4-bytes alignment for slot_info field.
uint8_t reserved0[2];
// Per-slot information. Up to 4 slots.
struct slot_metadata slot_info[4];
// Reserved for further use.
uint8_t reserved1[8];
// CRC32 of all 28 bytes preceding this field (little endian
// format).
uint32_t crc32_le;
} __attribute__((packed));
#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
static_assert(sizeof(struct bootloader_control) ==
sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
"struct bootloader_control has wrong size");
#endif
#ifdef __cplusplus
#include <string>
#include <vector>
// Read bootloader message into boot. Error message will be set in err.
bool read_bootloader_message(bootloader_message* boot, std::string* err);
// Read bootloader message from the specified misc device into boot.
bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
std::string* err);
// Write bootloader message to BCB.
bool write_bootloader_message(const bootloader_message& boot, std::string* err);
// Write bootloader message to the specified BCB device.
bool write_bootloader_message_to(const bootloader_message& boot,
const std::string& misc_blk_device, std::string* err);
// Write bootloader message (boots into recovery with the options) to BCB. Will
// set the command and recovery fields, and reset the rest.
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err);
// Update bootloader message (boots into recovery with the options) to BCB. Will
// only update the command and recovery fields.
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err);
// Clear BCB.
bool clear_bootloader_message(std::string* err);
bool read_wipe_package(std::string* package_data, size_t size, std::string* err);
bool write_wipe_package(const std::string& package_data, std::string* err);
// Writes the reboot-bootloader reboot reason to the bootloader_message.
bool write_reboot_bootloader(std::string* err);
void set_misc_device(std::string name);
void get_args(int *argc, char ***argv);
// Read the wipe package from BCB (from offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool read_wipe_package(std::string* package_data, size_t size, std::string* err);
// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool write_wipe_package(const std::string& package_data, std::string* err);
#else
@@ -100,6 +231,7 @@ void get_args(int *argc, char ***argv);
// C Interface.
bool write_bootloader_message(const char* options);
bool write_reboot_bootloader(void);
#endif // ifdef __cplusplus
+35
View File
@@ -0,0 +1,35 @@
# Copyright (C) 2016 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES := bootloader_message.cpp
LOCAL_MODULE := libbootloader_message_twrp
LOCAL_C_INCLUDES += bionic $(LOCAL_PATH)/include
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 22; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport
LOCAL_SHARED_LIBRARIES += libstlport
else
LOCAL_C_INCLUDES += external/libcxx/include
LOCAL_SHARED_LIBRARIES += libc++
endif
LOCAL_CFLAGS := -Werror -std=c++11
# ignore bootloader's factory reset command even when written to /misc
ifeq ($(TW_IGNORE_MISC_WIPE_DATA), true)
LOCAL_CFLAGS += -DIGNORE_MISC_WIPE_DATA
endif
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_SHARED_LIBRARY)
@@ -0,0 +1,386 @@
/*
* Copyright (C) 2016 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 <bootloader_message_twrp/bootloader_message.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/system_properties.h>
#include <string>
#include <vector>
static std::string misc_blkdev;
void set_misc_device(const char* name) {
misc_blkdev = name;
}
static std::string get_misc_blk_device(std::string* err) {
*err = "";
return misc_blkdev;
}
// In recovery mode, recovery can get started and try to access the misc
// device before the kernel has actually created it.
static bool wait_for_device(const std::string& blk_device, std::string* err) {
int tries = 0;
int ret;
err->clear();
do {
++tries;
struct stat buf;
ret = stat(blk_device.c_str(), &buf);
if (ret == -1) {
char buffer[2048];
sprintf(buffer, "failed to stat %s try %d: %s\n",
blk_device.c_str(), tries, strerror(errno));
*err += buffer;
/*
*err += android::base::StringPrintf("failed to stat %s try %d: %s\n",
blk_device.c_str(), tries, strerror(errno));
*/
sleep(1);
}
} while (ret && tries < 10);
if (ret) {
*err += "failed to stat " + blk_device + "\n";
/*
*err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str());
*/
}
return ret == 0;
}
static bool read_misc_partition(void* p, size_t size, const std::string& misc_blk_device,
size_t offset, std::string* err) {
if (!wait_for_device(misc_blk_device, err)) {
return false;
}
int fd(open(misc_blk_device.c_str(), O_RDONLY));
if (fd < 0) {
*err = "failed to open " + misc_blk_device + ": ";
*err += strerror(errno);
/*
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
*err = "failed to lseek " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
*err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if ((size_t)read(fd, p, size) != size) {
*err = "failed to read " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
if (!android::base::ReadFully(fd, p, size)) {
*err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
close(fd);
return true;
}
static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
*err = "no misc device set";
return false;
}
int fd = (open(misc_blk_device.c_str(), O_WRONLY | O_SYNC));
if (fd == -1) {
*err = "failed to open " + misc_blk_device + ": ";
*err += strerror(errno);
/*
static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
size_t offset, std::string* err) {
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
*err = "failed to lseek " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
*err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
if ((size_t)write(fd, p, size) != size) {
*err = "failed to write " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
if (!android::base::WriteFully(fd, p, size)) {
*err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
// TODO: O_SYNC and fsync duplicates each other?
if (fsync(fd) == -1) {
*err = "failed to fsync " + misc_blk_device + ": ";
*err += strerror(errno);
close(fd);
/*
if (fsync(fd) == -1) {
*err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
strerror(errno));
*/
return false;
}
close(fd);
return true;
}
bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
std::string* err) {
return read_misc_partition(boot, sizeof(*boot), misc_blk_device,
BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
}
bool read_bootloader_message(bootloader_message* boot, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
return read_bootloader_message_from(boot, misc_blk_device, err);
}
bool write_bootloader_message_to(const bootloader_message& boot, __unused const std::string& misc_blk_device,
std::string* err) {
return write_misc_partition(&boot, sizeof(boot),
BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
}
bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
return write_bootloader_message_to(boot, misc_blk_device, err);
}
// libc++ in 5.1 does not know how to handle a std::string* so this craziness is needed
bool clear_bootloader_message(void* err) {
std::string &s = *(static_cast<std::string*>(err));
return clear_bootloader_message(&s);
}
bool clear_bootloader_message(std::string* err) {
bootloader_message boot = {};
return write_bootloader_message(boot, err);
}
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
bootloader_message boot = {};
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
for (const auto& s : options) {
strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
if (s.substr(s.size() - 1) != "\n") {
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
}
return write_bootloader_message(boot, err);
}
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) {
bootloader_message boot;
if (!read_bootloader_message(&boot, err)) {
return false;
}
// Zero out the entire fields.
memset(boot.command, 0, sizeof(boot.command));
memset(boot.recovery, 0, sizeof(boot.recovery));
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
for (const auto& s : options) {
strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
if (s.back() != '\n') {
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
}
return write_bootloader_message(boot, err);
}
bool write_reboot_bootloader(std::string* err) {
bootloader_message boot;
if (!read_bootloader_message(&boot, err)) {
return false;
}
if (boot.command[0] != '\0') {
*err = "Bootloader command pending.";
return false;
}
strlcpy(boot.command, "bootonce-bootloader", sizeof(boot.command));
return write_bootloader_message(boot, err);
}
bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
package_data->resize(size);
return read_misc_partition(&(*package_data)[0], size, misc_blk_device,
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
bool write_wipe_package(const std::string& package_data, std::string* err) {
std::string misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
return write_misc_partition(package_data.data(), package_data.size(),
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
extern "C" bool write_reboot_bootloader(void) {
std::string err;
return write_reboot_bootloader(&err);
}
extern "C" bool write_bootloader_message(const char* options) {
std::string err;
bootloader_message boot = {};
memcpy(&boot, options, sizeof(boot));
return write_bootloader_message(boot, &err);
}
static const char *COMMAND_FILE = "/cache/recovery/command";
static const int MAX_ARG_LENGTH = 4096;
static const int MAX_ARGS = 100;
// command line args come from, in decreasing precedence:
// - the actual command line
// - the bootloader control block (one per line, after "recovery")
// - the contents of COMMAND_FILE (one per line)
void
get_args(int *argc, char ***argv) {
bootloader_message boot = {};
std::string err;
if (!read_bootloader_message(&boot, &err)) {
printf("%s\n", err.c_str());
// If fails, leave a zeroed bootloader_message.
memset(&boot, 0, sizeof(boot));
}
//stage = strndup(boot.stage, sizeof(boot.stage));
if (boot.command[0] != 0 && boot.command[0] != 255) {
printf("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
}
if (boot.status[0] != 0 && boot.status[0] != 255) {
printf("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
}
// --- if arguments weren't supplied, look in the bootloader control block
if (*argc <= 1) {
boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
const char *arg = strtok(boot.recovery, "\n");
if (arg != NULL && !strcmp(arg, "recovery")) {
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = strdup(arg);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if ((arg = strtok(NULL, "\n")) == NULL) break;
// if the device does not have an own recovery key combo we just want to open TWRP after
// walking through the factory reset screen - without actually doing a factory reset
#ifdef IGNORE_MISC_WIPE_DATA
if (!strcmp(arg, "--wipe_data")) {
(*argv)[*argc] = "";
*argc = *argc -1;
printf("Bootloader arg \"%s\" ignored because TWRP was compiled with TW_IGNORE_MISC_WIPE_DATA\n", arg);
continue;
}
#endif
(*argv)[*argc] = strdup(arg);
}
printf("Got arguments from boot message\n");
} else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
printf("Bad boot message\n\"%.20s\"\n", boot.recovery);
}
}
// --- if that doesn't work, try the command file (if we have /cache).
if (*argc <= 1/* && has_cache*/) {
FILE *fp = fopen(COMMAND_FILE, "r");
if (fp != NULL) {
char *token;
char *argv0 = (*argv)[0];
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = argv0; // use the same program name
char buf[MAX_ARG_LENGTH];
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
token = strtok(buf, "\r\n");
if (token != NULL) {
(*argv)[*argc] = strdup(token); // Strip newline.
} else {
--*argc;
}
}
fclose(fp);
printf("Got arguments from %s\n", COMMAND_FILE);
}
}
// --> write the arguments we have back into the bootloader control block
// always boot into recovery after this (until finish_recovery() is called)
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
int i;
for (i = 1; i < *argc; ++i) {
strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
if (!write_bootloader_message(boot, &err)) {
printf("%s\n", err.c_str());
}
}
@@ -0,0 +1,236 @@
/*
* Copyright (C) 2008 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 _BOOTLOADER_MESSAGE_TWRP_H
#define _BOOTLOADER_MESSAGE_TWRP_H
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
// Spaces used by misc partition are as below:
// 0 - 2K For bootloader_message
// 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used
// as bootloader_message_ab struct)
// 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices
// Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
// are not configurable without changing all of them.
#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = BOARD_RECOVERY_BLDRMSG_OFFSET;
static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024 + BOOTLOADER_MESSAGE_OFFSET_IN_MISC;
#else
static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
#endif
/* Bootloader Message (2-KiB)
*
* This structure describes the content of a block in flash
* that is used for recovery and the bootloader to talk to
* each other.
*
* The command field is updated by linux when it wants to
* reboot into recovery or to update radio or bootloader firmware.
* It is also updated by the bootloader when firmware update
* is complete (to boot into recovery for any final cleanup)
*
* The status field was used by the bootloader after the completion
* of an "update-radio" or "update-hboot" command, which has been
* deprecated since Froyo.
*
* The recovery field is only written by linux and used
* for the system to send a message to recovery or the
* other way around.
*
* The stage field is written by packages which restart themselves
* multiple times, so that the UI can reflect which invocation of the
* package it is. If the value is of the format "#/#" (eg, "1/3"),
* the UI will add a simple indicator of that status.
*
* We used to have slot_suffix field for A/B boot control metadata in
* this struct, which gets unintentionally cleared by recovery or
* uncrypt. Move it into struct bootloader_message_ab to avoid the
* issue.
*/
struct bootloader_message {
char command[32];
char status[32];
char recovery[768];
// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];
// The 'reserved' field used to be 224 bytes when it was initially
// carved off from the 1024-byte recovery field. Bump it up to
// 1184-byte so that the entire bootloader_message struct rounds up
// to 2048-byte.
char reserved[1184];
};
/**
* We must be cautious when changing the bootloader_message struct size,
* because A/B-specific fields may end up with different offsets.
*/
/*#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
static_assert(sizeof(struct bootloader_message) == 2048,
"struct bootloader_message size changes, which may break A/B devices");
#endif*/
/**
* The A/B-specific bootloader message structure (4-KiB).
*
* We separate A/B boot control metadata from the regular bootloader
* message struct and keep it here. Everything that's A/B-specific
* stays after struct bootloader_message, which should be managed by
* the A/B-bootloader or boot control HAL.
*
* The slot_suffix field is used for A/B implementations where the
* bootloader does not set the androidboot.ro.boot.slot_suffix kernel
* commandline parameter. This is used by fs_mgr to mount /system and
* other partitions with the slotselect flag set in fstab. A/B
* implementations are free to use all 32 bytes and may store private
* data past the first NUL-byte in this field. It is encouraged, but
* not mandatory, to use 'struct bootloader_control' described below.
*/
struct bootloader_message_ab {
struct bootloader_message message;
char slot_suffix[32];
// Round up the entire struct to 4096-byte.
char reserved[2016];
};
/**
* Be cautious about the struct size change, in case we put anything post
* bootloader_message_ab struct (b/29159185).
*/
/*#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
static_assert(sizeof(struct bootloader_message_ab) == 4096,
"struct bootloader_message_ab size changes");
#endif*/
#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */
#define BOOT_CTRL_VERSION 1
struct slot_metadata {
// Slot priority with 15 meaning highest priority, 1 lowest
// priority and 0 the slot is unbootable.
uint8_t priority : 4;
// Number of times left attempting to boot this slot.
uint8_t tries_remaining : 3;
// 1 if this slot has booted successfully, 0 otherwise.
uint8_t successful_boot : 1;
// 1 if this slot is corrupted from a dm-verity corruption, 0
// otherwise.
uint8_t verity_corrupted : 1;
// Reserved for further use.
uint8_t reserved : 7;
} __attribute__((packed));
/* Bootloader Control AB
*
* This struct can be used to manage A/B metadata. It is designed to
* be put in the 'slot_suffix' field of the 'bootloader_message'
* structure described above. It is encouraged to use the
* 'bootloader_control' structure to store the A/B metadata, but not
* mandatory.
*/
struct bootloader_control {
// NUL terminated active slot suffix.
char slot_suffix[4];
// Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
uint32_t magic;
// Version of struct being used (see BOOT_CTRL_VERSION).
uint8_t version;
// Number of slots being managed.
uint8_t nb_slot : 3;
// Number of times left attempting to boot recovery.
uint8_t recovery_tries_remaining : 3;
// Ensure 4-bytes alignment for slot_info field.
uint8_t reserved0[2];
// Per-slot information. Up to 4 slots.
struct slot_metadata slot_info[4];
// Reserved for further use.
uint8_t reserved1[8];
// CRC32 of all 28 bytes preceding this field (little endian
// format).
uint32_t crc32_le;
} __attribute__((packed));
/*#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
static_assert(sizeof(struct bootloader_control) ==
sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
"struct bootloader_control has wrong size");
#endif*/
#ifdef __cplusplus
#include <string.h>
#include <vector>
// Read bootloader message into boot. Error message will be set in err.
bool read_bootloader_message(bootloader_message* boot, std::string* err);
// Read bootloader message from the specified misc device into boot.
bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
std::string* err);
// Write bootloader message to BCB.
bool write_bootloader_message(const bootloader_message& boot, std::string* err);
// Write bootloader message to the specified BCB device.
bool write_bootloader_message_to(const bootloader_message& boot,
const std::string& misc_blk_device, std::string* err);
// Write bootloader message (boots into recovery with the options) to BCB. Will
// set the command and recovery fields, and reset the rest.
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err);
// Update bootloader message (boots into recovery with the options) to BCB. Will
// only update the command and recovery fields.
bool update_bootloader_message(const std::vector<std::string>& options, std::string* err);
// Clear BCB.
bool clear_bootloader_message(void* err);
bool clear_bootloader_message(std::string* err);
// Writes the reboot-bootloader reboot reason to the bootloader_message.
bool write_reboot_bootloader(std::string* err);
// Read the wipe package from BCB (from offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool read_wipe_package(std::string* package_data, size_t size, std::string* err);
void set_misc_device(const char* name);
void get_args(int *argc, char ***argv);
// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool write_wipe_package(const std::string& package_data, std::string* err);
#else
#include <stdbool.h>
// C Interface.
bool write_bootloader_message(const char* options);
bool write_reboot_bootloader(void);
#endif // ifdef __cplusplus
#endif // _BOOTLOADER_MESSAGE_TWRP_H
+13 -2
View File
@@ -17,9 +17,9 @@
#ifndef RECOVERY_COMMON_H
#define RECOVERY_COMMON_H
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>
#ifdef __cplusplus
extern "C" {
@@ -40,18 +40,29 @@ extern "C" {
#define STRINGIFY(x) #x
#define EXPAND(x) STRINGIFY(x)
class RecoveryUI;
extern RecoveryUI* ui;
extern bool modified_flash;
//typedef struct fstab_rec Volume;
// The current stage, e.g. "1/2".
extern std::string stage;
// The reason argument provided in "--reason=".
extern const char* reason;
// fopen a file, mounting volumes and making parent dirs as necessary.
FILE* fopen_path(const char *path, const char *mode);
void ui_print(const char* format, ...);
bool is_ro_debuggable();
static bool is_ro_debuggable();
#ifdef __cplusplus
}
#endif
bool reboot(const std::string& command);
#endif // RECOVERY_COMMON_H
+1 -1
View File
@@ -60,7 +60,7 @@ Device::BuiltinAction Device::InvokeMenuItem(int menu_position) {
return menu_position < 0 ? NO_ACTION : MENU_ACTIONS[menu_position];
}
int Device::HandleMenuKey(int key, int visible) {
int Device::HandleMenuKey(int key, bool visible) {
if (!visible) {
return kNoAction;
}
+73 -79
View File
@@ -20,96 +20,90 @@
#include "ui.h"
class Device {
public:
Device(RecoveryUI* ui) : ui_(ui) { }
virtual ~Device() { }
public:
explicit Device(RecoveryUI* ui) : ui_(ui) {}
virtual ~Device() {}
// Called to obtain the UI object that should be used to display
// the recovery user interface for this device. You should not
// have called Init() on the UI object already, the caller will do
// that after this method returns.
virtual RecoveryUI* GetUI() { return ui_; }
// Called to obtain the UI object that should be used to display the recovery user interface for
// this device. You should not have called Init() on the UI object already, the caller will do
// that after this method returns.
virtual RecoveryUI* GetUI() {
return ui_;
}
// Called when recovery starts up (after the UI has been obtained
// and initialized and after the arguments have been parsed, but
// before anything else).
virtual void StartRecovery() { };
// Called when recovery starts up (after the UI has been obtained and initialized and after the
// arguments have been parsed, but before anything else).
virtual void StartRecovery() {};
// Called from the main thread when recovery is at the main menu
// and waiting for input, and a key is pressed. (Note that "at"
// the main menu does not necessarily mean the menu is visible;
// recovery will be at the main menu with it invisible after an
// unsuccessful operation [ie OTA package failure], or if recovery
// is started with no command.)
//
// key is the code of the key just pressed. (You can call
// IsKeyPressed() on the RecoveryUI object you returned from GetUI
// if you want to find out if other keys are held down.)
//
// visible is true if the menu is visible.
//
// Return one of the defined constants below in order to:
//
// - move the menu highlight (kHighlight{Up,Down})
// - invoke the highlighted item (kInvokeItem)
// - do nothing (kNoAction)
// - invoke a specific action (a menu position: any non-negative number)
virtual int HandleMenuKey(int key, int visible);
// Called from the main thread when recovery is at the main menu and waiting for input, and a key
// is pressed. (Note that "at" the main menu does not necessarily mean the menu is visible;
// recovery will be at the main menu with it invisible after an unsuccessful operation [ie OTA
// package failure], or if recovery is started with no command.)
//
// 'key' is the code of the key just pressed. (You can call IsKeyPressed() on the RecoveryUI
// object you returned from GetUI if you want to find out if other keys are held down.)
//
// 'visible' is true if the menu is visible.
//
// Returns one of the defined constants below in order to:
//
// - move the menu highlight (kHighlight{Up,Down})
// - invoke the highlighted item (kInvokeItem)
// - do nothing (kNoAction)
// - invoke a specific action (a menu position: any non-negative number)
virtual int HandleMenuKey(int key, bool visible);
enum BuiltinAction {
NO_ACTION = 0,
REBOOT = 1,
APPLY_SDCARD = 2,
// APPLY_CACHE was 3.
APPLY_ADB_SIDELOAD = 4,
WIPE_DATA = 5,
WIPE_CACHE = 6,
REBOOT_BOOTLOADER = 7,
SHUTDOWN = 8,
VIEW_RECOVERY_LOGS = 9,
MOUNT_SYSTEM = 10,
RUN_GRAPHICS_TEST = 11,
};
enum BuiltinAction {
NO_ACTION = 0,
REBOOT = 1,
APPLY_SDCARD = 2,
// APPLY_CACHE was 3.
APPLY_ADB_SIDELOAD = 4,
WIPE_DATA = 5,
WIPE_CACHE = 6,
REBOOT_BOOTLOADER = 7,
SHUTDOWN = 8,
VIEW_RECOVERY_LOGS = 9,
MOUNT_SYSTEM = 10,
RUN_GRAPHICS_TEST = 11,
};
// Return the list of menu items (an array of strings,
// NULL-terminated). The menu_position passed to InvokeMenuItem
// will correspond to the indexes into this array.
virtual const char* const* GetMenuItems();
// Return the list of menu items (an array of strings, NULL-terminated). The menu_position passed
// to InvokeMenuItem will correspond to the indexes into this array.
virtual const char* const* GetMenuItems();
// Perform a recovery action selected from the menu.
// 'menu_position' will be the item number of the selected menu
// item, or a non-negative number returned from
// device_handle_key(). The menu will be hidden when this is
// called; implementations can call ui_print() to print
// information to the screen. If the menu position is one of the
// builtin actions, you can just return the corresponding enum
// value. If it is an action specific to your device, you
// actually perform it here and return NO_ACTION.
virtual BuiltinAction InvokeMenuItem(int menu_position);
// Perform a recovery action selected from the menu. 'menu_position' will be the item number of
// the selected menu item, or a non-negative number returned from HandleMenuKey(). The menu will
// be hidden when this is called; implementations can call ui_print() to print information to the
// screen. If the menu position is one of the builtin actions, you can just return the
// corresponding enum value. If it is an action specific to your device, you actually perform it
// here and return NO_ACTION.
virtual BuiltinAction InvokeMenuItem(int menu_position);
static const int kNoAction = -1;
static const int kHighlightUp = -2;
static const int kHighlightDown = -3;
static const int kInvokeItem = -4;
static const int kNoAction = -1;
static const int kHighlightUp = -2;
static const int kHighlightDown = -3;
static const int kInvokeItem = -4;
// Called before and after we do a wipe data/factory reset operation,
// either via a reboot from the main system with the --wipe_data flag,
// or when the user boots into recovery image manually and selects the
// option from the menu, to perform whatever device-specific wiping
// actions are needed.
// Return true on success; returning false from PreWipeData will prevent
// the regular wipe, and returning false from PostWipeData will cause
// the wipe to be considered a failure.
virtual bool PreWipeData() { return true; }
virtual bool PostWipeData() { return true; }
// Called before and after we do a wipe data/factory reset operation, either via a reboot from the
// main system with the --wipe_data flag, or when the user boots into recovery image manually and
// selects the option from the menu, to perform whatever device-specific wiping actions as needed.
// Returns true on success; returning false from PreWipeData will prevent the regular wipe, and
// returning false from PostWipeData will cause the wipe to be considered a failure.
virtual bool PreWipeData() {
return true;
}
private:
RecoveryUI* ui_;
virtual bool PostWipeData() {
return true;
}
private:
RecoveryUI* ui_;
};
// The device-specific library must define this function (or the
// default one will be used, if there is no device-specific library).
// It returns the Device object that recovery should use.
// The device-specific library must define this function (or the default one will be used, if there
// is no device-specific library). It returns the Device object that recovery should use.
Device* make_device();
#endif // _DEVICE_H
+22 -8
View File
@@ -1,23 +1,36 @@
# Copyright 2009 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.
LOCAL_PATH := $(call my-dir)
edify_src_files := \
lexer.ll \
parser.yy \
expr.cpp
lexer.ll \
parser.yy \
expr.cpp
#
# Build the host-side command line tool
# Build the host-side command line tool (host executable)
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(edify_src_files) \
main.cpp
$(edify_src_files) \
edify_parser.cpp
LOCAL_CFLAGS := -Werror
LOCAL_CPPFLAGS := -g -O0
LOCAL_MODULE := edify
LOCAL_MODULE := edify_parser
LOCAL_YACCFLAGS := -v
LOCAL_CPPFLAGS += -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-deprecated-register
@@ -28,12 +41,13 @@ LOCAL_STATIC_LIBRARIES += libbase
include $(BUILD_HOST_EXECUTABLE)
#
# Build the device-side library
# Build the device-side library (static library)
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(edify_src_files)
LOCAL_CFLAGS := -Werror
LOCAL_CPPFLAGS := -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-deprecated-register
LOCAL_MODULE := libedify
+3
View File
@@ -1,3 +1,6 @@
edify
=====
Update scripts (from donut onwards) are written in a new little
scripting language ("edify") that is superficially somewhat similar to
the old one ("amend"). This is a brief overview of the new language.
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2009 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.
*/
/**
* This is a host-side tool for validating a given edify script file.
*
* We used to have edify test cases here, which have been moved to
* tests/component/edify_test.cpp.
*
* Caveat: It doesn't recognize functions defined through updater, which
* makes the tool less useful. We should either extend the tool or remove it.
*/
#include <errno.h>
#include <stdio.h>
#include <memory>
#include <string>
#include <android-base/file.h>
#include "expr.h"
static void ExprDump(int depth, const std::unique_ptr<Expr>& n, const std::string& script) {
printf("%*s", depth*2, "");
printf("%s %p (%d-%d) \"%s\"\n",
n->name.c_str(), n->fn, n->start, n->end,
script.substr(n->start, n->end - n->start).c_str());
for (size_t i = 0; i < n->argv.size(); ++i) {
ExprDump(depth+1, n->argv[i], script);
}
}
int main(int argc, char** argv) {
RegisterBuiltins();
if (argc != 2) {
printf("Usage: %s <edify script>\n", argv[0]);
return 1;
}
std::string buffer;
if (!android::base::ReadFileToString(argv[1], &buffer)) {
printf("%s: failed to read %s: %s\n", argv[0], argv[1], strerror(errno));
return 1;
}
std::unique_ptr<Expr> root;
int error_count = 0;
int error = parse_string(buffer.data(), &root, &error_count);
printf("parse returned %d; %d errors encountered\n", error, error_count);
if (error == 0 || error_count > 0) {
ExprDump(0, root, buffer);
State state(buffer, nullptr);
std::string result;
if (!Evaluate(&state, root, &result)) {
printf("result was NULL, message is: %s\n",
(state.errmsg.empty() ? "(NULL)" : state.errmsg.c_str()));
} else {
printf("result is [%s]\n", result.c_str());
}
}
return 0;
}
+250 -353
View File
@@ -14,201 +14,172 @@
* limitations under the License.
*/
#include <string.h>
#include <stdbool.h>
#include "expr.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "expr.h"
// Functions should:
//
// - return a malloc()'d string
// - if Evaluate() on any argument returns NULL, return NULL.
// - if Evaluate() on any argument returns nullptr, return nullptr.
int BooleanString(const char* s) {
return s[0] != '\0';
static bool BooleanString(const std::string& s) {
return !s.empty();
}
char* Evaluate(State* state, Expr* expr) {
Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
if (v == NULL) return NULL;
bool Evaluate(State* state, const std::unique_ptr<Expr>& expr, std::string* result) {
if (result == nullptr) {
return false;
}
std::unique_ptr<Value> v(expr->fn(expr->name.c_str(), state, expr->argv));
if (!v) {
return false;
}
if (v->type != VAL_STRING) {
ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type);
FreeValue(v);
return NULL;
return false;
}
char* result = v->data;
free(v);
return result;
*result = v->data;
return true;
}
Value* EvaluateValue(State* state, Expr* expr) {
return expr->fn(expr->name, state, expr->argc, expr->argv);
Value* EvaluateValue(State* state, const std::unique_ptr<Expr>& expr) {
return expr->fn(expr->name.c_str(), state, expr->argv);
}
Value* StringValue(char* str) {
if (str == NULL) return NULL;
Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value)));
v->type = VAL_STRING;
v->size = strlen(str);
v->data = str;
return v;
}
void FreeValue(Value* v) {
if (v == NULL) return;
free(v->data);
free(v);
}
Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc == 0) {
return StringValue(strdup(""));
Value* StringValue(const char* str) {
if (str == nullptr) {
return nullptr;
}
char** strings = reinterpret_cast<char**>(malloc(argc * sizeof(char*)));
int i;
for (i = 0; i < argc; ++i) {
strings[i] = NULL;
return new Value(VAL_STRING, str);
}
Value* StringValue(const std::string& str) {
return StringValue(str.c_str());
}
Value* ConcatFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
if (argv.empty()) {
return StringValue("");
}
char* result = NULL;
int length = 0;
for (i = 0; i < argc; ++i) {
strings[i] = Evaluate(state, argv[i]);
if (strings[i] == NULL) {
goto done;
std::string result;
for (size_t i = 0; i < argv.size(); ++i) {
std::string str;
if (!Evaluate(state, argv[i], &str)) {
return nullptr;
}
length += strlen(strings[i]);
result += str;
}
result = reinterpret_cast<char*>(malloc(length+1));
int p;
p = 0;
for (i = 0; i < argc; ++i) {
strcpy(result+p, strings[i]);
p += strlen(strings[i]);
}
result[p] = '\0';
done:
for (i = 0; i < argc; ++i) {
free(strings[i]);
}
free(strings);
return StringValue(result);
}
Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2 && argc != 3) {
free(state->errmsg);
state->errmsg = strdup("ifelse expects 2 or 3 arguments");
return NULL;
}
char* cond = Evaluate(state, argv[0]);
if (cond == NULL) {
return NULL;
Value* IfElseFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
if (argv.size() != 2 && argv.size() != 3) {
state->errmsg = "ifelse expects 2 or 3 arguments";
return nullptr;
}
if (BooleanString(cond) == true) {
free(cond);
return EvaluateValue(state, argv[1]);
} else {
if (argc == 3) {
free(cond);
return EvaluateValue(state, argv[2]);
} else {
return StringValue(cond);
}
std::string cond;
if (!Evaluate(state, argv[0], &cond)) {
return nullptr;
}
if (!cond.empty()) {
return EvaluateValue(state, argv[1]);
} else if (argv.size() == 3) {
return EvaluateValue(state, argv[2]);
}
return StringValue("");
}
Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
char* msg = NULL;
if (argc > 0) {
msg = Evaluate(state, argv[0]);
}
free(state->errmsg);
if (msg) {
Value* AbortFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
std::string msg;
if (!argv.empty() && Evaluate(state, argv[0], &msg)) {
state->errmsg = msg;
} else {
state->errmsg = strdup("called abort()");
state->errmsg = "called abort()";
}
return NULL;
return nullptr;
}
Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
if (v == NULL) {
return NULL;
Value* AssertFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
for (size_t i = 0; i < argv.size(); ++i) {
std::string result;
if (!Evaluate(state, argv[i], &result)) {
return nullptr;
}
int b = BooleanString(v);
free(v);
if (!b) {
int prefix_len;
if (result.empty()) {
int len = argv[i]->end - argv[i]->start;
char* err_src = reinterpret_cast<char*>(malloc(len + 20));
strcpy(err_src, "assert failed: ");
prefix_len = strlen(err_src);
memcpy(err_src + prefix_len, state->script + argv[i]->start, len);
err_src[prefix_len + len] = '\0';
free(state->errmsg);
state->errmsg = err_src;
return NULL;
state->errmsg = "assert failed: " + state->script.substr(argv[i]->start, len);
return nullptr;
}
}
return StringValue(strdup(""));
return StringValue("");
}
Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) {
return NULL;
Value* SleepFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
std::string val;
if (!Evaluate(state, argv[0], &val)) {
return nullptr;
}
int v;
if (!android::base::ParseInt(val.c_str(), &v, 0)) {
return nullptr;
}
int v = strtol(val, NULL, 10);
sleep(v);
return StringValue(val);
}
Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
if (v == NULL) {
return NULL;
Value* StdoutFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
for (size_t i = 0; i < argv.size(); ++i) {
std::string v;
if (!Evaluate(state, argv[i], &v)) {
return nullptr;
}
fputs(v, stdout);
free(v);
fputs(v.c_str(), stdout);
}
return StringValue(strdup(""));
return StringValue("");
}
Value* LogicalAndFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == true) {
free(left);
const std::vector<std::unique_ptr<Expr>>& argv) {
std::string left;
if (!Evaluate(state, argv[0], &left)) {
return nullptr;
}
if (BooleanString(left)) {
return EvaluateValue(state, argv[1]);
} else {
return StringValue(left);
return StringValue("");
}
}
Value* LogicalOrFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == false) {
free(left);
const std::vector<std::unique_ptr<Expr>>& argv) {
std::string left;
if (!Evaluate(state, argv[0], &left)) {
return nullptr;
}
if (!BooleanString(left)) {
return EvaluateValue(state, argv[1]);
} else {
return StringValue(left);
@@ -216,174 +187,144 @@ Value* LogicalOrFn(const char* name, State* state,
}
Value* LogicalNotFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) return NULL;
bool bv = BooleanString(val);
free(val);
return StringValue(strdup(bv ? "" : "t"));
const std::vector<std::unique_ptr<Expr>>& argv) {
std::string val;
if (!Evaluate(state, argv[0], &val)) {
return nullptr;
}
return StringValue(BooleanString(val) ? "" : "t");
}
Value* SubstringFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* needle = Evaluate(state, argv[0]);
if (needle == NULL) return NULL;
char* haystack = Evaluate(state, argv[1]);
if (haystack == NULL) {
free(needle);
return NULL;
const std::vector<std::unique_ptr<Expr>>& argv) {
std::string needle;
if (!Evaluate(state, argv[0], &needle)) {
return nullptr;
}
char* result = strdup(strstr(haystack, needle) ? "t" : "");
free(needle);
free(haystack);
std::string haystack;
if (!Evaluate(state, argv[1], &haystack)) {
return nullptr;
}
std::string result = (haystack.find(needle) != std::string::npos) ? "t" : "";
return StringValue(result);
}
Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
if (right == NULL) {
free(left);
return NULL;
Value* EqualityFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
std::string left;
if (!Evaluate(state, argv[0], &left)) {
return nullptr;
}
std::string right;
if (!Evaluate(state, argv[1], &right)) {
return nullptr;
}
char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
free(left);
free(right);
const char* result = (left == right) ? "t" : "";
return StringValue(result);
}
Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
if (right == NULL) {
free(left);
return NULL;
Value* InequalityFn(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv) {
std::string left;
if (!Evaluate(state, argv[0], &left)) {
return nullptr;
}
std::string right;
if (!Evaluate(state, argv[1], &right)) {
return nullptr;
}
char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
free(left);
free(right);
const char* result = (left != right) ? "t" : "";
return StringValue(result);
}
Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* left = EvaluateValue(state, argv[0]);
if (left == NULL) return NULL;
FreeValue(left);
Value* SequenceFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
std::unique_ptr<Value> left(EvaluateValue(state, argv[0]));
if (!left) {
return nullptr;
}
return EvaluateValue(state, argv[1]);
}
Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("less_than_int expects 2 arguments");
return NULL;
Value* LessThanIntFn(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv) {
if (argv.size() != 2) {
state->errmsg = "less_than_int expects 2 arguments";
return nullptr;
}
char* left;
char* right;
if (ReadArgs(state, argv, 2, &left, &right) < 0) return NULL;
bool result = false;
char* end;
long l_int = strtol(left, &end, 10);
if (left[0] == '\0' || *end != '\0') {
goto done;
std::vector<std::string> args;
if (!ReadArgs(state, argv, &args)) {
return nullptr;
}
long r_int;
r_int = strtol(right, &end, 10);
if (right[0] == '\0' || *end != '\0') {
goto done;
// Parse up to at least long long or 64-bit integers.
int64_t l_int;
if (!android::base::ParseInt(args[0].c_str(), &l_int)) {
state->errmsg = "failed to parse int in " + args[0];
return nullptr;
}
result = l_int < r_int;
int64_t r_int;
if (!android::base::ParseInt(args[1].c_str(), &r_int)) {
state->errmsg = "failed to parse int in " + args[1];
return nullptr;
}
done:
free(left);
free(right);
return StringValue(strdup(result ? "t" : ""));
return StringValue(l_int < r_int ? "t" : "");
}
Value* GreaterThanIntFn(const char* name, State* state,
int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("greater_than_int expects 2 arguments");
return NULL;
const std::vector<std::unique_ptr<Expr>>& argv) {
if (argv.size() != 2) {
state->errmsg = "greater_than_int expects 2 arguments";
return nullptr;
}
Expr* temp[2];
temp[0] = argv[1];
temp[1] = argv[0];
return LessThanIntFn(name, state, 2, temp);
}
Value* Literal(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup(name));
}
Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
va_list v;
va_start(v, count);
Expr* e = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
e->fn = fn;
e->name = "(operator)";
e->argc = count;
e->argv = reinterpret_cast<Expr**>(malloc(count * sizeof(Expr*)));
int i;
for (i = 0; i < count; ++i) {
e->argv[i] = va_arg(v, Expr*);
std::vector<std::string> args;
if (!ReadArgs(state, argv, &args)) {
return nullptr;
}
va_end(v);
e->start = loc.start;
e->end = loc.end;
return e;
// Parse up to at least long long or 64-bit integers.
int64_t l_int;
if (!android::base::ParseInt(args[0].c_str(), &l_int)) {
state->errmsg = "failed to parse int in " + args[0];
return nullptr;
}
int64_t r_int;
if (!android::base::ParseInt(args[1].c_str(), &r_int)) {
state->errmsg = "failed to parse int in " + args[1];
return nullptr;
}
return StringValue(l_int > r_int ? "t" : "");
}
Value* Literal(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
return StringValue(name);
}
// -----------------------------------------------------------------
// the function table
// -----------------------------------------------------------------
static int fn_entries = 0;
static int fn_size = 0;
NamedFunction* fn_table = NULL;
static std::unordered_map<std::string, Function> fn_table;
void RegisterFunction(const char* name, Function fn) {
if (fn_entries >= fn_size) {
fn_size = fn_size*2 + 1;
fn_table = reinterpret_cast<NamedFunction*>(realloc(fn_table, fn_size * sizeof(NamedFunction)));
void RegisterFunction(const std::string& name, Function fn) {
fn_table[name] = fn;
}
Function FindFunction(const std::string& name) {
if (fn_table.find(name) == fn_table.end()) {
return nullptr;
} else {
return fn_table[name];
}
fn_table[fn_entries].name = name;
fn_table[fn_entries].fn = fn;
++fn_entries;
}
static int fn_entry_compare(const void* a, const void* b) {
const char* na = ((const NamedFunction*)a)->name;
const char* nb = ((const NamedFunction*)b)->name;
return strcmp(na, nb);
}
void FinishRegistration() {
qsort(fn_table, fn_entries, sizeof(NamedFunction), fn_entry_compare);
}
Function FindFunction(const char* name) {
NamedFunction key;
key.name = name;
NamedFunction* nf = reinterpret_cast<NamedFunction*>(bsearch(&key, fn_table, fn_entries,
sizeof(NamedFunction), fn_entry_compare));
if (nf == NULL) {
return NULL;
}
return nf->fn;
}
void RegisterBuiltins() {
@@ -404,106 +345,56 @@ void RegisterBuiltins() {
// convenience methods for functions
// -----------------------------------------------------------------
// Evaluate the expressions in argv, giving 'count' char* (the ... is
// zero or more char** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadArgs(State* state, Expr* argv[], int count, ...) {
char** args = reinterpret_cast<char**>(malloc(count * sizeof(char*)));
va_list v;
va_start(v, count);
int i;
for (i = 0; i < count; ++i) {
args[i] = Evaluate(state, argv[i]);
if (args[i] == NULL) {
va_end(v);
int j;
for (j = 0; j < i; ++j) {
free(args[j]);
}
free(args);
return -1;
}
*(va_arg(v, char**)) = args[i];
}
va_end(v);
free(args);
return 0;
// Evaluate the expressions in argv, and put the results of strings in args. If any expression
// evaluates to nullptr, return false. Return true on success.
bool ReadArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::string>* args) {
return ReadArgs(state, argv, args, 0, argv.size());
}
// Evaluate the expressions in argv, giving 'count' Value* (the ... is
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...) {
Value** args = reinterpret_cast<Value**>(malloc(count * sizeof(Value*)));
va_list v;
va_start(v, count);
int i;
for (i = 0; i < count; ++i) {
args[i] = EvaluateValue(state, argv[i]);
if (args[i] == NULL) {
va_end(v);
int j;
for (j = 0; j < i; ++j) {
FreeValue(args[j]);
}
free(args);
return -1;
}
*(va_arg(v, Value**)) = args[i];
bool ReadArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::string>* args, size_t start, size_t len) {
if (args == nullptr) {
return false;
}
va_end(v);
free(args);
return 0;
if (start + len > argv.size()) {
return false;
}
for (size_t i = start; i < start + len; ++i) {
std::string var;
if (!Evaluate(state, argv[i], &var)) {
args->clear();
return false;
}
args->push_back(var);
}
return true;
}
// Evaluate the expressions in argv, returning an array of char*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// strings it contains.
char** ReadVarArgs(State* state, int argc, Expr* argv[]) {
char** args = (char**)malloc(argc * sizeof(char*));
int i = 0;
for (i = 0; i < argc; ++i) {
args[i] = Evaluate(state, argv[i]);
if (args[i] == NULL) {
int j;
for (j = 0; j < i; ++j) {
free(args[j]);
}
free(args);
return NULL;
}
}
return args;
// Evaluate the expressions in argv, and put the results of Value* in args. If any expression
// evaluate to nullptr, return false. Return true on success.
bool ReadValueArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::unique_ptr<Value>>* args) {
return ReadValueArgs(state, argv, args, 0, argv.size());
}
// Evaluate the expressions in argv, returning an array of Value*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// Values it contains.
Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) {
Value** args = (Value**)malloc(argc * sizeof(Value*));
int i = 0;
for (i = 0; i < argc; ++i) {
args[i] = EvaluateValue(state, argv[i]);
if (args[i] == NULL) {
int j;
for (j = 0; j < i; ++j) {
FreeValue(args[j]);
}
free(args);
return NULL;
}
bool ReadValueArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::unique_ptr<Value>>* args, size_t start, size_t len) {
if (args == nullptr) {
return false;
}
return args;
}
static void ErrorAbortV(State* state, const char* format, va_list ap) {
std::string buffer;
android::base::StringAppendV(&buffer, format, ap);
free(state->errmsg);
state->errmsg = strdup(buffer.c_str());
return;
if (len == 0 || start + len > argv.size()) {
return false;
}
for (size_t i = start; i < start + len; ++i) {
std::unique_ptr<Value> v(EvaluateValue(state, argv[i]));
if (!v) {
args->clear();
return false;
}
args->push_back(std::move(v));
}
return true;
}
// Use printf-style arguments to compose an error message to put into
@@ -511,7 +402,7 @@ static void ErrorAbortV(State* state, const char* format, va_list ap) {
Value* ErrorAbort(State* state, const char* format, ...) {
va_list ap;
va_start(ap, format);
ErrorAbortV(state, format, ap);
android::base::StringAppendV(&state->errmsg, format, ap);
va_end(ap);
return nullptr;
}
@@ -519,8 +410,14 @@ Value* ErrorAbort(State* state, const char* format, ...) {
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
va_list ap;
va_start(ap, format);
ErrorAbortV(state, format, ap);
android::base::StringAppendV(&state->errmsg, format, ap);
va_end(ap);
state->cause_code = cause_code;
return nullptr;
}
State::State(const std::string& script, void* cookie) :
script(script),
cookie(cookie) {
}
+80 -104
View File
@@ -19,27 +19,26 @@
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include "error_code.h"
#include "yydefs.h"
#define MAX_STRING_LEN 1024
struct State {
State(const std::string& script, void* cookie);
typedef struct Expr Expr;
// The source of the original script.
const std::string& script;
typedef struct {
// Optional pointer to app-specific data; the core of edify never
// uses this value.
void* cookie;
// The source of the original script. Must be NULL-terminated,
// and in writable memory (Evaluate may make temporary changes to
// it but will restore it when done).
char* script;
// The error message (if any) returned if the evaluation aborts.
// Should be NULL initially, will be either NULL or a malloc'd
// pointer after Evaluate() returns.
char* errmsg;
// Should be empty initially, will be either empty or a string that
// Evaluate() returns.
std::string errmsg;
// error code indicates the type of failure (e.g. failure to update system image)
// during the OTA process.
@@ -50,117 +49,95 @@ typedef struct {
CauseCode cause_code = kNoCause;
bool is_retry = false;
} State;
#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
#define VAL_BLOB 2
typedef struct {
int type;
ssize_t size;
char* data;
} Value;
typedef Value* (*Function)(const char* name, State* state,
int argc, Expr* argv[]);
struct Expr {
Function fn;
const char* name;
int argc;
Expr** argv;
int start, end;
};
// Take one of the Expr*s passed to the function as an argument,
// evaluate it, return the resulting Value. The caller takes
// ownership of the returned Value.
Value* EvaluateValue(State* state, Expr* expr);
enum ValueType {
VAL_INVALID = -1,
VAL_STRING = 1,
VAL_BLOB = 2,
};
// Take one of the Expr*s passed to the function as an argument,
// evaluate it, assert that it is a string, and return the resulting
// char*. The caller takes ownership of the returned char*. This is
// a convenience function for older functions that want to deal only
// with strings.
char* Evaluate(State* state, Expr* expr);
struct Value {
ValueType type;
std::string data;
Value(ValueType type, const std::string& str) :
type(type),
data(str) {}
};
struct Expr;
using Function = Value* (*)(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv);
struct Expr {
Function fn;
std::string name;
std::vector<std::unique_ptr<Expr>> argv;
int start, end;
Expr(Function fn, const std::string& name, int start, int end) :
fn(fn),
name(name),
start(start),
end(end) {}
};
// Evaluate the input expr, return the resulting Value.
Value* EvaluateValue(State* state, const std::unique_ptr<Expr>& expr);
// Evaluate the input expr, assert that it is a string, and update the result parameter. This
// function returns true if the evaluation succeeds. This is a convenience function for older
// functions that want to deal only with strings.
bool Evaluate(State* state, const std::unique_ptr<Expr>& expr, std::string* result);
// Glue to make an Expr out of a literal.
Value* Literal(const char* name, State* state, int argc, Expr* argv[]);
Value* Literal(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
// Functions corresponding to various syntactic sugar operators.
// ("concat" is also available as a builtin function, to concatenate
// more than two strings.)
Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
Value* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
// Convenience function for building expressions with a fixed number
// of arguments.
Expr* Build(Function fn, YYLTYPE loc, int count, ...);
Value* ConcatFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* LogicalAndFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* LogicalOrFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* LogicalNotFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* SubstringFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* EqualityFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* InequalityFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* SequenceFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
// Global builtins, registered by RegisterBuiltins().
Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
// For setting and getting the global error string (when returning
// NULL from a function).
void SetError(const char* message); // makes a copy
const char* GetError(); // retains ownership
void ClearError();
typedef struct {
const char* name;
Function fn;
} NamedFunction;
Value* IfElseFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* AssertFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
Value* AbortFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv);
// Register a new function. The same Function may be registered under
// multiple names, but a given name should only be used once.
void RegisterFunction(const char* name, Function fn);
void RegisterFunction(const std::string& name, Function fn);
// Register all the builtins.
void RegisterBuiltins();
// Call this after all calls to RegisterFunction() but before parsing
// any scripts to finish building the function table.
void FinishRegistration();
// Find the Function for a given name; return NULL if no such function
// exists.
Function FindFunction(const char* name);
Function FindFunction(const std::string& name);
// --- convenience functions for use in functions ---
// Evaluate the expressions in argv, giving 'count' char* (the ... is
// zero or more char** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadArgs(State* state, Expr* argv[], int count, ...);
// Evaluate the expressions in argv, and put the results of strings in args. If any expression
// evaluates to nullptr, return false. Return true on success.
bool ReadArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::string>* args);
bool ReadArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::string>* args, size_t start, size_t len);
// Evaluate the expressions in argv, giving 'count' Value* (the ... is
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...);
// Evaluate the expressions in argv, returning an array of char*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// strings it contains.
char** ReadVarArgs(State* state, int argc, Expr* argv[]);
// Evaluate the expressions in argv, returning an array of Value*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// Values it contains.
Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]);
// Evaluate the expressions in argv, and put the results of Value* in args. If any
// expression evaluate to nullptr, return false. Return true on success.
bool ReadValueArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::unique_ptr<Value>>* args);
bool ReadValueArgs(State* state, const std::vector<std::unique_ptr<Expr>>& argv,
std::vector<std::unique_ptr<Value>>* args, size_t start, size_t len);
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
@@ -172,12 +149,11 @@ Value* ErrorAbort(State* state, const char* format, ...)
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...)
__attribute__((format(printf, 3, 4)));
// Wrap a string into a Value, taking ownership of the string.
Value* StringValue(char* str);
// Copying the string into a Value.
Value* StringValue(const char* str);
// Free a Value object.
void FreeValue(Value* v);
Value* StringValue(const std::string& str);
int parse_string(const char* str, Expr** root, int* error_count);
int parse_string(const char* str, std::unique_ptr<Expr>* root, int* error_count);
#endif // _EXPRESSION_H
-219
View File
@@ -1,219 +0,0 @@
/*
* Copyright (C) 2009 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "expr.h"
#include "parser.h"
extern int yyparse(Expr** root, int* error_count);
int expect(const char* expr_str, const char* expected, int* errors) {
Expr* e;
char* result;
printf(".");
int error_count = parse_string(expr_str, &e, &error_count);
if (error_count > 0) {
printf("error parsing \"%s\" (%d errors)\n",
expr_str, error_count);
++*errors;
return 0;
}
State state;
state.cookie = NULL;
state.script = strdup(expr_str);
state.errmsg = NULL;
result = Evaluate(&state, e);
free(state.errmsg);
free(state.script);
if (result == NULL && expected != NULL) {
printf("error evaluating \"%s\"\n", expr_str);
++*errors;
return 0;
}
if (result == NULL && expected == NULL) {
return 1;
}
if (strcmp(result, expected) != 0) {
printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n",
expr_str, expected, result);
++*errors;
free(result);
return 0;
}
free(result);
return 1;
}
int test() {
int errors = 0;
expect("a", "a", &errors);
expect("\"a\"", "a", &errors);
expect("\"\\x61\"", "a", &errors);
expect("# this is a comment\n"
" a\n"
" \n",
"a", &errors);
// sequence operator
expect("a; b; c", "c", &errors);
// string concat operator
expect("a + b", "ab", &errors);
expect("a + \n \"b\"", "ab", &errors);
expect("a + b +\nc\n", "abc", &errors);
// string concat function
expect("concat(a, b)", "ab", &errors);
expect("concat(a,\n \"b\")", "ab", &errors);
expect("concat(a + b,\nc,\"d\")", "abcd", &errors);
expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors);
// logical and
expect("a && b", "b", &errors);
expect("a && \"\"", "", &errors);
expect("\"\" && b", "", &errors);
expect("\"\" && \"\"", "", &errors);
expect("\"\" && abort()", "", &errors); // test short-circuiting
expect("t && abort()", NULL, &errors);
// logical or
expect("a || b", "a", &errors);
expect("a || \"\"", "a", &errors);
expect("\"\" || b", "b", &errors);
expect("\"\" || \"\"", "", &errors);
expect("a || abort()", "a", &errors); // test short-circuiting
expect("\"\" || abort()", NULL, &errors);
// logical not
expect("!a", "", &errors);
expect("! \"\"", "t", &errors);
expect("!!a", "t", &errors);
// precedence
expect("\"\" == \"\" && b", "b", &errors);
expect("a + b == ab", "t", &errors);
expect("ab == a + b", "t", &errors);
expect("a + (b == ab)", "a", &errors);
expect("(ab == a) + b", "b", &errors);
// substring function
expect("is_substring(cad, abracadabra)", "t", &errors);
expect("is_substring(abrac, abracadabra)", "t", &errors);
expect("is_substring(dabra, abracadabra)", "t", &errors);
expect("is_substring(cad, abracxadabra)", "", &errors);
expect("is_substring(abrac, axbracadabra)", "", &errors);
expect("is_substring(dabra, abracadabrxa)", "", &errors);
// ifelse function
expect("ifelse(t, yes, no)", "yes", &errors);
expect("ifelse(!t, yes, no)", "no", &errors);
expect("ifelse(t, yes, abort())", "yes", &errors);
expect("ifelse(!t, abort(), no)", "no", &errors);
// if "statements"
expect("if t then yes else no endif", "yes", &errors);
expect("if \"\" then yes else no endif", "no", &errors);
expect("if \"\" then yes endif", "", &errors);
expect("if \"\"; t then yes endif", "yes", &errors);
// numeric comparisons
expect("less_than_int(3, 14)", "t", &errors);
expect("less_than_int(14, 3)", "", &errors);
expect("less_than_int(x, 3)", "", &errors);
expect("less_than_int(3, x)", "", &errors);
expect("greater_than_int(3, 14)", "", &errors);
expect("greater_than_int(14, 3)", "t", &errors);
expect("greater_than_int(x, 3)", "", &errors);
expect("greater_than_int(3, x)", "", &errors);
// big string
expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str(), &errors);
printf("\n");
return errors;
}
void ExprDump(int depth, Expr* n, char* script) {
printf("%*s", depth*2, "");
char temp = script[n->end];
script[n->end] = '\0';
printf("%s %p (%d-%d) \"%s\"\n",
n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end,
script+n->start);
script[n->end] = temp;
int i;
for (i = 0; i < n->argc; ++i) {
ExprDump(depth+1, n->argv[i], script);
}
}
int main(int argc, char** argv) {
RegisterBuiltins();
FinishRegistration();
if (argc == 1) {
return test() != 0;
}
FILE* f = fopen(argv[1], "r");
if (f == NULL) {
printf("%s: %s: No such file or directory\n", argv[0], argv[1]);
return 1;
}
char buffer[8192];
int size = fread(buffer, 1, 8191, f);
fclose(f);
buffer[size] = '\0';
Expr* root;
int error_count = 0;
int error = parse_string(buffer, &root, &error_count);
printf("parse returned %d; %d errors encountered\n", error, error_count);
if (error == 0 || error_count > 0) {
ExprDump(0, root, buffer);
State state;
state.cookie = NULL;
state.script = buffer;
state.errmsg = NULL;
char* result = Evaluate(&state, root);
if (result == NULL) {
printf("result was NULL, message is: %s\n",
(state.errmsg == NULL ? "(NULL)" : state.errmsg));
free(state.errmsg);
} else {
printf("result is [%s]\n", result);
}
}
return 0;
}
+38 -36
View File
@@ -19,6 +19,10 @@
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <string>
#include <vector>
#include "expr.h"
#include "yydefs.h"
#include "parser.h"
@@ -26,13 +30,26 @@
extern int gLine;
extern int gColumn;
void yyerror(Expr** root, int* error_count, const char* s);
int yyparse(Expr** root, int* error_count);
void yyerror(std::unique_ptr<Expr>* root, int* error_count, const char* s);
int yyparse(std::unique_ptr<Expr>* root, int* error_count);
struct yy_buffer_state;
void yy_switch_to_buffer(struct yy_buffer_state* new_buffer);
struct yy_buffer_state* yy_scan_string(const char* yystr);
// Convenience function for building expressions with a fixed number
// of arguments.
static Expr* Build(Function fn, YYLTYPE loc, size_t count, ...) {
va_list v;
va_start(v, count);
Expr* e = new Expr(fn, "(operator)", loc.start, loc.end);
for (size_t i = 0; i < count; ++i) {
e->argv.emplace_back(va_arg(v, Expr*));
}
va_end(v);
return e;
}
%}
%locations
@@ -40,10 +57,7 @@ struct yy_buffer_state* yy_scan_string(const char* yystr);
%union {
char* str;
Expr* expr;
struct {
int argc;
Expr** argv;
} args;
std::vector<std::unique_ptr<Expr>>* args;
}
%token AND OR SUBSTR SUPERSTR EQ NE IF THEN ELSE ENDIF
@@ -51,7 +65,10 @@ struct yy_buffer_state* yy_scan_string(const char* yystr);
%type <expr> expr
%type <args> arglist
%parse-param {Expr** root}
%destructor { delete $$; } expr
%destructor { delete $$; } arglist
%parse-param {std::unique_ptr<Expr>* root}
%parse-param {int* error_count}
%error-verbose
@@ -66,17 +83,11 @@ struct yy_buffer_state* yy_scan_string(const char* yystr);
%%
input: expr { *root = $1; }
input: expr { root->reset($1); }
;
expr: STRING {
$$ = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
$$->fn = Literal;
$$->name = $1;
$$->argc = 0;
$$->argv = NULL;
$$->start = @$.start;
$$->end = @$.end;
$$ = new Expr(Literal, $1, @$.start, @$.end);
}
| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
@@ -91,41 +102,32 @@ expr: STRING {
| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); }
| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
| STRING '(' arglist ')' {
$$ = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
$$->fn = FindFunction($1);
if ($$->fn == NULL) {
char buffer[256];
snprintf(buffer, sizeof(buffer), "unknown function \"%s\"", $1);
yyerror(root, error_count, buffer);
Function fn = FindFunction($1);
if (fn == nullptr) {
std::string msg = "unknown function \"" + std::string($1) + "\"";
yyerror(root, error_count, msg.c_str());
YYERROR;
}
$$->name = $1;
$$->argc = $3.argc;
$$->argv = $3.argv;
$$->start = @$.start;
$$->end = @$.end;
$$ = new Expr(fn, $1, @$.start, @$.end);
$$->argv = std::move(*$3);
}
;
arglist: /* empty */ {
$$.argc = 0;
$$.argv = NULL;
$$ = new std::vector<std::unique_ptr<Expr>>;
}
| expr {
$$.argc = 1;
$$.argv = reinterpret_cast<Expr**>(malloc(sizeof(Expr*)));
$$.argv[0] = $1;
$$ = new std::vector<std::unique_ptr<Expr>>;
$$->emplace_back($1);
}
| arglist ',' expr {
$$.argc = $1.argc + 1;
$$.argv = reinterpret_cast<Expr**>(realloc($$.argv, $$.argc * sizeof(Expr*)));
$$.argv[$$.argc-1] = $3;
$$->push_back(std::unique_ptr<Expr>($3));
}
;
%%
void yyerror(Expr** root, int* error_count, const char* s) {
void yyerror(std::unique_ptr<Expr>* root, int* error_count, const char* s) {
if (strlen(s) == 0) {
s = "syntax error";
}
@@ -133,7 +135,7 @@ void yyerror(Expr** root, int* error_count, const char* s) {
++*error_count;
}
int parse_string(const char* str, Expr** root, int* error_count) {
int parse_string(const char* str, std::unique_ptr<Expr>* root, int* error_count) {
yy_switch_to_buffer(yy_scan_string(str));
return yyparse(root, error_count);
}
+43 -41
View File
@@ -18,52 +18,54 @@
#define _ERROR_CODE_H_
enum ErrorCode {
kNoError = -1,
kLowBattery = 20,
kZipVerificationFailure,
kZipOpenFailure,
kBootreasonInBlacklist
kNoError = -1,
kLowBattery = 20,
kZipVerificationFailure,
kZipOpenFailure,
kBootreasonInBlacklist,
kPackageCompatibilityFailure,
};
enum CauseCode {
kNoCause = -1,
kArgsParsingFailure = 100,
kStashCreationFailure,
kFileOpenFailure,
kLseekFailure,
kFreadFailure,
kFwriteFailure,
kFsyncFailure,
kLibfecFailure,
kFileGetPropFailure,
kFileRenameFailure,
kSymlinkFailure,
kSetMetadataFailure,
kTune2FsFailure,
kRebootFailure,
kVendorFailure = 200
kNoCause = -1,
kArgsParsingFailure = 100,
kStashCreationFailure,
kFileOpenFailure,
kLseekFailure,
kFreadFailure,
kFwriteFailure,
kFsyncFailure,
kLibfecFailure,
kFileGetPropFailure,
kFileRenameFailure,
kSymlinkFailure,
kSetMetadataFailure,
kTune2FsFailure,
kRebootFailure,
kPackageExtractFileFailure,
kVendorFailure = 200
};
enum UncryptErrorCode {
kUncryptNoError = -1,
kUncryptErrorPlaceholder = 50,
kUncryptTimeoutError = 100,
kUncryptFileRemoveError,
kUncryptFileOpenError,
kUncryptSocketOpenError,
kUncryptSocketWriteError,
kUncryptSocketListenError,
kUncryptSocketAcceptError,
kUncryptFstabReadError,
kUncryptFileStatError,
kUncryptBlockOpenError,
kUncryptIoctlError,
kUncryptReadError,
kUncryptWriteError,
kUncryptFileSyncError,
kUncryptFileCloseError,
kUncryptFileRenameError,
kUncryptPackageMissingError,
kUncryptNoError = -1,
kUncryptErrorPlaceholder = 50,
kUncryptTimeoutError = 100,
kUncryptFileRemoveError,
kUncryptFileOpenError,
kUncryptSocketOpenError,
kUncryptSocketWriteError,
kUncryptSocketListenError,
kUncryptSocketAcceptError,
kUncryptFstabReadError,
kUncryptFileStatError,
kUncryptBlockOpenError,
kUncryptIoctlError,
kUncryptReadError,
kUncryptWriteError,
kUncryptFileSyncError,
kUncryptFileCloseError,
kUncryptFileRenameError,
kUncryptPackageMissingError,
};
#endif
#endif // _ERROR_CODE_H_
+20
View File
@@ -51,6 +51,26 @@ else
include $(BUILD_PREBUILT)
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.hlthchrg.rc
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_SRC_FILES := init.recovery.hlthchrg26.rc
include $(BUILD_PREBUILT)
else
include $(CLEAR_VARS)
LOCAL_MODULE := init.recovery.hlthchrg.rc
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_SRC_FILES := init.recovery.hlthchrg25.rc
include $(BUILD_PREBUILT)
endif
ifeq ($(TWRP_INCLUDE_LOGCAT), true)
ifeq ($(TARGET_USES_LOGD), true)
@@ -1,8 +0,0 @@
assert compatible_with("0.1") == "true"
assert file_contains("SYSTEM:build.prop", "ro.product.device=dream") == "true" || file_contains("SYSTEM:build.prop", "ro.build.product=dream") == "true"
assert file_contains("RECOVERY:default.prop", "ro.product.device=dream") == "true" || file_contains("RECOVERY:default.prop", "ro.build.product=dream") == "true"
assert getprop("ro.product.device") == "dream"
format BOOT:
format SYSTEM:
copy_dir PACKAGE:system SYSTEM:
write_raw_image PACKAGE:boot.img BOOT:
-6
View File
@@ -16,7 +16,6 @@ on early-init
restorecon /postinstall
start ueventd
start healthd
service set_permissive /sbin/permissive.sh
oneshot
@@ -46,7 +45,6 @@ on init
on fs
mount pstore pstore /sys/fs/pstore
mkdir /dev/usb-ffs 0770 shell shell
mkdir /dev/usb-ffs/adb 0770 shell shell
mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
@@ -104,10 +102,6 @@ service ueventd /sbin/ueventd
critical
seclabel u:r:ueventd:s0
service healthd /sbin/healthd -r
critical
seclabel u:r:healthd:s0
service adbd /sbin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
disabled
socket adbd stream 660 system system
+5
View File
@@ -0,0 +1,5 @@
# healthd for pre Android 8.0
service healthd /sbin/healthd -r
critical
seclabel u:r:healthd:s0
+5
View File
@@ -0,0 +1,5 @@
# charger for Android 8.0 and up
service charger /charger -r
critical
seclabel u:r:charger:s0
+5 -8
View File
@@ -23,6 +23,8 @@
#include <unistd.h>
#include <fcntl.h>
#include <android-base/file.h>
#include "fuse_sideload.h"
struct file_data {
@@ -41,14 +43,9 @@ static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32
return -EIO;
}
while (fetch_size > 0) {
ssize_t r = TEMP_FAILURE_RETRY(read(fd->fd, buffer, fetch_size));
if (r == -1) {
fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno));
return -EIO;
}
fetch_size -= r;
buffer += r;
if (!android::base::ReadFully(fd->fd, buffer, fetch_size)) {
fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno));
return -EIO;
}
return 0;
+7 -1
View File
@@ -38,7 +38,13 @@ else
LOCAL_SRC_FILES += hardwarekeyboard.cpp
endif
LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libminzip libaosprecovery libselinux
LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libaosprecovery libselinux
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libziparchive
else
LOCAL_SHARED_LIBRARIES += libminzip
LOCAL_CFLAGS += -DUSE_MINZIP
endif
LOCAL_MODULE := libguitwrp
#TWRP_EVENT_LOGGING := true
+1 -1
View File
@@ -43,11 +43,11 @@
#include "../adb_install.h"
#include "../fuse_sideload.h"
#include "blanktimer.hpp"
#include "../twinstall.h"
extern "C" {
#include "../twcommon.h"
#include "../variables.h"
#include "../twinstall.h"
#include "cutils/properties.h"
#include "../adb_install.h"
};
+19 -16
View File
@@ -39,12 +39,17 @@
#include <string>
#include <algorithm>
#ifdef USE_MINZIP
#include "../minzip/SysUtil.h"
#else
#include "../otautil/SysUtil.h"
#endif
extern "C" {
#include "../twcommon.h"
#include "../minzip/SysUtil.h"
#include "../minzip/Zip.h"
#include "gui.h"
}
#include "../zipwrap.hpp"
#include "../minuitwrp/minui.h"
#include "rapidxml.hpp"
@@ -664,7 +669,7 @@ int Page::NotifyVarChange(std::string varName, std::string value)
// transient data for loading themes
struct LoadingContext
{
ZipArchive* zip; // zip to load theme from, or NULL for the stock theme
ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
std::set<std::string> filenames; // to detect cyclic includes
std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
std::vector<xml_document<>*> xmldocs; // all loaded xml docs
@@ -806,7 +811,7 @@ void PageSet::MakeEmergencyConsoleIfNeeded()
}
}
int PageSet::LoadLanguage(char* languageFile, ZipArchive* package)
int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
{
xml_document<> lang;
xml_node<>* parent;
@@ -1182,7 +1187,7 @@ void PageSet::AddStringResource(std::string resource_source, std::string resourc
mResources->AddStringResource(resource_source, resource_name, value);
}
char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
size_t len;
char* buffer = NULL;
@@ -1219,19 +1224,18 @@ char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
close(fd);
} else {
LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
const ZipEntry* zipentry = mzFindZipEntry(package, filename.c_str());
if (zipentry == NULL) {
if (!package->EntryExists(filename)) {
LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
return NULL;
}
// Allocate the buffer for the file
len = mzGetZipEntryUncompLen(zipentry);
len = package->GetUncompressedSize(filename);
buffer = (char*) malloc(len + 1);
if (!buffer)
return NULL;
if (!mzExtractZipEntryToBuffer(package, zipentry, (unsigned char*) buffer)) {
if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
LOGERR("Unable to extract '%s'\n", filename.c_str());
free(buffer);
return NULL;
@@ -1295,14 +1299,13 @@ void PageManager::LoadLanguageListDir(string dir) {
closedir(d);
}
void PageManager::LoadLanguageList(ZipArchive* package) {
void PageManager::LoadLanguageList(ZipWrap* package) {
Language_List.clear();
if (TWFunc::Path_Exists(TWRES "customlanguages"))
TWFunc::removeDir(TWRES "customlanguages", true);
if (package) {
TWFunc::Recursive_Mkdir(TWRES "customlanguages");
struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
mzExtractRecursive(package, "languages", TWRES "customlanguages/", &timestamp, NULL, NULL, NULL);
package->ExtractRecursive("languages", TWRES "customlanguages/");
LoadLanguageListDir(TWRES "customlanguages/");
} else {
LoadLanguageListDir(TWRES "languages/");
@@ -1330,7 +1333,7 @@ void PageManager::LoadLanguage(string filename) {
int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
{
std::string mainxmlfilename = package;
ZipArchive zip;
ZipWrap zip;
char* languageFile = NULL;
char* baseLanguageFile = NULL;
PageSet* pageSet = NULL;
@@ -1371,7 +1374,7 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string
LOGERR("Failed to map '%s'\n", package.c_str());
goto error;
}
if (mzOpenZipArchive(map.addr, map.length, &zip)) {
if (!zip.Open(package.c_str(), &map)) {
LOGERR("Unable to open zip archive '%s'\n", package.c_str());
sysReleaseMap(&map);
goto error;
@@ -1414,7 +1417,7 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string
mCurrentSet = pageSet;
if (ctx.zip) {
mzCloseZipArchive(ctx.zip);
ctx.zip->Close();
sysReleaseMap(&map);
}
return ret;
@@ -1422,7 +1425,7 @@ int PageManager::LoadPackage(std::string name, std::string package, std::string
error:
// Sometimes we get here without a real error
if (ctx.zip) {
mzCloseZipArchive(ctx.zip);
ctx.zip->Close();
sysReleaseMap(&map);
}
return -1;
+4 -4
View File
@@ -21,7 +21,7 @@
#ifndef _PAGES_HEADER_HPP
#define _PAGES_HEADER_HPP
#include "../minzip/Zip.h"
#include "../zipwrap.hpp"
#include <vector>
#include <map>
#include <string>
@@ -116,7 +116,7 @@ public:
public:
int Load(LoadingContext& ctx, const std::string& filename);
int LoadLanguage(char* languageFile, ZipArchive* package);
int LoadLanguage(char* languageFile, ZipWrap* package);
void MakeEmergencyConsoleIfNeeded();
Page* FindPage(std::string name);
@@ -155,8 +155,8 @@ class PageManager
{
public:
// Used by GUI
static char* LoadFileToBuffer(std::string filename, ZipArchive* package);
static void LoadLanguageList(ZipArchive* package);
static char* LoadFileToBuffer(std::string filename, ZipWrap* package);
static void LoadLanguageList(ZipWrap* package);
static void LoadLanguage(std::string filename);
static int LoadPackage(std::string name, std::string package, std::string startpage);
static PageSet* SelectPackage(std::string name);
+12 -26
View File
@@ -30,7 +30,7 @@
#include <iomanip>
#include <fcntl.h>
#include "../minzip/Zip.h"
#include "../zipwrap.hpp"
extern "C" {
#include "../twcommon.h"
#include "gui.h"
@@ -42,38 +42,24 @@ extern "C" {
#define TMP_RESOURCE_NAME "/tmp/extract.bin"
Resource::Resource(xml_node<>* node, ZipArchive* pZip __unused)
Resource::Resource(xml_node<>* node, ZipWrap* pZip __unused)
{
if (node && node->first_attribute("name"))
mName = node->first_attribute("name")->value();
}
int Resource::ExtractResource(ZipArchive* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile)
int Resource::ExtractResource(ZipWrap* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile)
{
if (!pZip)
return -1;
std::string src = folderName + "/" + fileName + fileExtn;
const ZipEntry* binary = mzFindZipEntry(pZip, src.c_str());
if (binary == NULL) {
if (!pZip->ExtractEntry(src, destFile, 0666))
return -1;
}
unlink(destFile.c_str());
int fd = creat(destFile.c_str(), 0666);
if (fd < 0)
return -1;
int ret = 0;
if (!mzExtractZipEntryToFile(pZip, binary, fd))
ret = -1;
close(fd);
return ret;
return 0;
}
void Resource::LoadImage(ZipArchive* pZip, std::string file, gr_surface* surface)
void Resource::LoadImage(ZipWrap* pZip, std::string file, gr_surface* surface)
{
int rc = 0;
if (ExtractResource(pZip, "images", file, ".png", TMP_RESOURCE_NAME) == 0)
@@ -119,7 +105,7 @@ void Resource::CheckAndScaleImage(gr_surface source, gr_surface* destination, in
}
}
FontResource::FontResource(xml_node<>* node, ZipArchive* pZip)
FontResource::FontResource(xml_node<>* node, ZipWrap* pZip)
: Resource(node, pZip)
{
origFontSize = 0;
@@ -127,7 +113,7 @@ FontResource::FontResource(xml_node<>* node, ZipArchive* pZip)
LoadFont(node, pZip);
}
void FontResource::LoadFont(xml_node<>* node, ZipArchive* pZip)
void FontResource::LoadFont(xml_node<>* node, ZipWrap* pZip)
{
std::string file;
xml_attribute<>* attr;
@@ -192,7 +178,7 @@ void FontResource::DeleteFont() {
origFont = NULL;
}
void FontResource::Override(xml_node<>* node, ZipArchive* pZip) {
void FontResource::Override(xml_node<>* node, ZipWrap* pZip) {
if (!origFont) {
origFont = mFont;
} else if (mFont) {
@@ -207,7 +193,7 @@ FontResource::~FontResource()
DeleteFont();
}
ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip)
ImageResource::ImageResource(xml_node<>* node, ZipWrap* pZip)
: Resource(node, pZip)
{
std::string file;
@@ -238,7 +224,7 @@ ImageResource::~ImageResource()
res_free_surface(mSurface);
}
AnimationResource::AnimationResource(xml_node<>* node, ZipArchive* pZip)
AnimationResource::AnimationResource(xml_node<>* node, ZipWrap* pZip)
: Resource(node, pZip)
{
std::string file;
@@ -359,7 +345,7 @@ void ResourceManager::AddStringResource(std::string resource_source, std::string
mStrings[resource_name] = res;
}
void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip, std::string resource_source)
void ResourceManager::LoadResources(xml_node<>* resList, ZipWrap* pZip, std::string resource_source)
{
if (!resList)
return;
+10 -11
View File
@@ -25,8 +25,7 @@
#include <vector>
#include <map>
#include "rapidxml.hpp"
struct ZipArchive;
#include "../zipwrap.hpp"
extern "C" {
#include "../minuitwrp/minui.h"
@@ -36,7 +35,7 @@ extern "C" {
class Resource
{
public:
Resource(xml_node<>* node, ZipArchive* pZip);
Resource(xml_node<>* node, ZipWrap* pZip);
virtual ~Resource() {}
public:
@@ -46,27 +45,27 @@ private:
std::string mName;
protected:
static int ExtractResource(ZipArchive* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile);
static void LoadImage(ZipArchive* pZip, std::string file, gr_surface* surface);
static int ExtractResource(ZipWrap* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile);
static void LoadImage(ZipWrap* pZip, std::string file, gr_surface* surface);
static void CheckAndScaleImage(gr_surface source, gr_surface* destination, int retain_aspect);
};
class FontResource : public Resource
{
public:
FontResource(xml_node<>* node, ZipArchive* pZip);
FontResource(xml_node<>* node, ZipWrap* pZip);
virtual ~FontResource();
public:
void* GetResource() { return this ? mFont : NULL; }
int GetHeight() { return gr_ttf_getMaxFontHeight(this ? mFont : NULL); }
void Override(xml_node<>* node, ZipArchive* pZip);
void Override(xml_node<>* node, ZipWrap* pZip);
protected:
void* mFont;
private:
void LoadFont(xml_node<>* node, ZipArchive* pZip);
void LoadFont(xml_node<>* node, ZipWrap* pZip);
void DeleteFont();
private:
@@ -77,7 +76,7 @@ private:
class ImageResource : public Resource
{
public:
ImageResource(xml_node<>* node, ZipArchive* pZip);
ImageResource(xml_node<>* node, ZipWrap* pZip);
virtual ~ImageResource();
public:
@@ -92,7 +91,7 @@ protected:
class AnimationResource : public Resource
{
public:
AnimationResource(xml_node<>* node, ZipArchive* pZip);
AnimationResource(xml_node<>* node, ZipWrap* pZip);
virtual ~AnimationResource();
public:
@@ -112,7 +111,7 @@ public:
ResourceManager();
virtual ~ResourceManager();
void AddStringResource(std::string resource_source, std::string resource_name, std::string value);
void LoadResources(xml_node<>* resList, ZipArchive* pZip, std::string resource_source);
void LoadResources(xml_node<>* resList, ZipWrap* pZip, std::string resource_source);
public:
FontResource* FindFont(const std::string& name) const;
+488 -354
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -18,12 +18,8 @@
#define RECOVERY_INSTALL_H_
#include <string>
#include <ziparchive/zip_archive.h>
#include "common.h"
#include "minzip/Zip.h"
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED,
INSTALL_RETRY };
// Install the package specified by root_path. If INSTALL_SUCCESS is
// returned and *wipe_cache is true on exit, caller should wipe the
// cache partition.
@@ -36,6 +32,10 @@ bool verify_package(const unsigned char* package_data, size_t package_size);
// Read meta data file of the package, write its content in the string pointed by meta_data.
// Return true if succeed, otherwise return false.
bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data);
bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data);
// Verifes the compatibility info in a Treble-compatible package. Returns true directly if the
// entry doesn't exist.
bool verify_package_compatibility(ZipArchiveHandle package_zip);
#endif // RECOVERY_INSTALL_H_
+99 -25
View File
@@ -28,8 +28,11 @@
#include "common.h"
#include "installcommand.h"
#include "minzip/SysUtil.h"
#include "minzip/Zip.h"
#include "zipwrap.hpp"
#ifndef USE_MINZIP
#include <ziparchive/zip_archive.h>
#include <vintf/VintfObjectRecovery.h>
#endif
#ifdef USE_OLD_VERIFIER
#include "verifier24/verifier.h"
#else
@@ -57,15 +60,13 @@ static int parse_build_number(std::string str) {
return -1;
}
bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data) {
const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH);
if (meta_entry == nullptr) {
printf("Failed to find %s in update package.\n", METADATA_PATH);
return false;
}
bool read_metadata_from_package(ZipWrap* zip, std::string* meta_data) {
long size = zip->GetUncompressedSize(METADATA_PATH);
if (size <= 0)
return false;
meta_data->resize(meta_entry->uncompLen, '\0');
if (!mzReadZipEntry(zip, meta_entry, &(*meta_data)[0], meta_entry->uncompLen)) {
meta_data->resize(size, '\0');
if (!zip->ExtractToBuffer(METADATA_PATH, reinterpret_cast<uint8_t*>(&(*meta_data)[0]))) {
printf("Failed to read metadata in update package.\n");
return false;
}
@@ -73,7 +74,7 @@ bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data) {
}
// Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
static void read_source_target_build(ZipArchive* zip, std::vector<std::string>& log_buffer) {
static void read_source_target_build(ZipWrap* zip, std::vector<std::string>& log_buffer) {
std::string meta_data;
if (!read_metadata_from_package(zip, &meta_data)) {
return;
@@ -103,7 +104,7 @@ static void read_source_target_build(ZipArchive* zip, std::vector<std::string>&
// Parses the metadata of the OTA package in |zip| and checks whether we are
// allowed to accept this A/B package. Downgrading is not allowed unless
// explicitly enabled in the package and only for incremental packages.
static int check_newer_ab_build(ZipArchive* zip)
static int check_newer_ab_build(ZipWrap* zip)
{
std::string metadata_str;
if (!read_metadata_from_package(zip, &metadata_str)) {
@@ -185,7 +186,7 @@ static int check_newer_ab_build(ZipArchive* zip)
}
int
abupdate_binary_command(const char* path, ZipArchive* zip, int retry_count,
abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count,
int status_fd, std::vector<std::string>* cmd)
{
int ret = check_newer_ab_build(zip);
@@ -195,26 +196,22 @@ abupdate_binary_command(const char* path, ZipArchive* zip, int retry_count,
// For A/B updates we extract the payload properties to a buffer and obtain
// the RAW payload offset in the zip file.
const ZipEntry* properties_entry =
mzFindZipEntry(zip, AB_OTA_PAYLOAD_PROPERTIES);
if (!properties_entry) {
if (!zip->EntryExists(AB_OTA_PAYLOAD_PROPERTIES)) {
printf("Can't find %s\n", AB_OTA_PAYLOAD_PROPERTIES);
return INSTALL_CORRUPT;
}
std::vector<unsigned char> payload_properties(
mzGetZipEntryUncompLen(properties_entry));
if (!mzExtractZipEntryToBuffer(zip, properties_entry,
payload_properties.data())) {
zip->GetUncompressedSize(AB_OTA_PAYLOAD_PROPERTIES));
if (!zip->ExtractToBuffer(AB_OTA_PAYLOAD_PROPERTIES, payload_properties.data())) {
printf("Can't extract %s\n", AB_OTA_PAYLOAD_PROPERTIES);
return INSTALL_CORRUPT;
}
const ZipEntry* payload_entry = mzFindZipEntry(zip, AB_OTA_PAYLOAD);
if (!payload_entry) {
if (!zip->EntryExists(AB_OTA_PAYLOAD)) {
printf("Can't find %s\n", AB_OTA_PAYLOAD);
return INSTALL_CORRUPT;
}
long payload_offset = mzGetZipEntryOffset(payload_entry);
long payload_offset = zip->GetEntryOffset(AB_OTA_PAYLOAD);
*cmd = {
"/sbin/update_engine_sideload",
android::base::StringPrintf("--payload=file://%s", path),
@@ -229,8 +226,8 @@ abupdate_binary_command(const char* path, ZipArchive* zip, int retry_count,
#else
int
abupdate_binary_command(const char* path, ZipArchive* zip, int retry_count,
int status_fd, std::vector<std::string>* cmd)
abupdate_binary_command(__unused const char* path, __unused ZipWrap* zip, __unused int retry_count,
__unused int status_fd, __unused std::vector<std::string>* cmd)
{
printf("No support for AB OTA zips included\n");
return INSTALL_CORRUPT;
@@ -239,7 +236,7 @@ abupdate_binary_command(const char* path, ZipArchive* zip, int retry_count,
#endif
int
update_binary_command(const char* path, ZipArchive* zip, int retry_count,
update_binary_command(const char* path, int retry_count,
int status_fd, std::vector<std::string>* cmd)
{
char charfd[16];
@@ -258,3 +255,80 @@ update_binary_command(const char* path, ZipArchive* zip, int retry_count,
cmd->push_back("retry");
return 0;
}
#ifdef USE_MINZIP
bool verify_package_compatibility(ZipWrap *package_zip) {
if (package_zip->EntryExists("compatibility.zip"))
printf("Cannot verify treble package compatibility, must build TWRP in Oreo tree or higher.\n");
return true;
}
#else
// Verifes the compatibility info in a Treble-compatible package. Returns true directly if the
// entry doesn't exist. Note that the compatibility info is packed in a zip file inside the OTA
// package.
bool verify_package_compatibility(ZipWrap *zw) {
ZipArchiveHandle package_zip = zw->GetZipArchiveHandle();
printf("Verifying package compatibility...\n");
static constexpr const char* COMPATIBILITY_ZIP_ENTRY = "compatibility.zip";
ZipString compatibility_entry_name(COMPATIBILITY_ZIP_ENTRY);
ZipEntry compatibility_entry;
if (FindEntry(package_zip, compatibility_entry_name, &compatibility_entry) != 0) {
printf("Package doesn't contain %s entry\n", COMPATIBILITY_ZIP_ENTRY);
return true;
}
std::string zip_content(compatibility_entry.uncompressed_length, '\0');
int32_t ret;
if ((ret = ExtractToMemory(package_zip, &compatibility_entry,
reinterpret_cast<uint8_t*>(&zip_content[0]),
compatibility_entry.uncompressed_length)) != 0) {
printf("Failed to read %s: %s\n", COMPATIBILITY_ZIP_ENTRY, ErrorCodeString(ret));
return false;
}
ZipArchiveHandle zip_handle;
ret = OpenArchiveFromMemory(static_cast<void*>(const_cast<char*>(zip_content.data())),
zip_content.size(), COMPATIBILITY_ZIP_ENTRY, &zip_handle);
if (ret != 0) {
printf("Failed to OpenArchiveFromMemory: %s\n", ErrorCodeString(ret));
return false;
}
// Iterate all the entries inside COMPATIBILITY_ZIP_ENTRY and read the contents.
void* cookie;
ret = StartIteration(zip_handle, &cookie, nullptr, nullptr);
if (ret != 0) {
printf("Failed to start iterating zip entries: %s\n", ErrorCodeString(ret));
CloseArchive(zip_handle);
return false;
}
std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
std::vector<std::string> compatibility_info;
ZipEntry info_entry;
ZipString info_name;
while (Next(cookie, &info_entry, &info_name) == 0) {
std::string content(info_entry.uncompressed_length, '\0');
int32_t ret = ExtractToMemory(zip_handle, &info_entry, reinterpret_cast<uint8_t*>(&content[0]),
info_entry.uncompressed_length);
if (ret != 0) {
printf("Failed to read %s: %s\n", info_name.name, ErrorCodeString(ret));
CloseArchive(zip_handle);
return false;
}
compatibility_info.emplace_back(std::move(content));
}
CloseArchive(zip_handle);
// VintfObjectRecovery::CheckCompatibility returns zero on success.
std::string err;
int result = android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err);
if (result == 0) {
return true;
}
printf("Failed to verify package compatibility (result %i): %s\n", result, err.c_str());
return false;
}
#endif
+6 -4
View File
@@ -21,15 +21,17 @@
#include <string>
#include "minzip/Zip.h"
#include "zipwrap.hpp"
bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data);
bool read_metadata_from_package(ZipWrap* zip, std::string* meta_data);
int
abupdate_binary_command(const char* path, ZipArchive* zip, int retry_count,
abupdate_binary_command(const char* path, ZipWrap* zip, int retry_count,
int status_fd, std::vector<std::string>* cmd);
int
update_binary_command(const char* path, ZipArchive* zip, int retry_count,
update_binary_command(const char* path, int retry_count,
int status_fd, std::vector<std::string>* cmd);
bool verify_package_compatibility(ZipWrap *package_zip);
#endif // RECOVERY_INSTALL_COMMAND_H_
+3 -3
View File
@@ -12,10 +12,10 @@ minadbd_cflags := \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
adb_main.cpp \
fuse_adb_provider.cpp \
services.cpp \
../fuse_sideload.cpp
../fuse_sideload.cpp \
minadbd.cpp \
minadbd_services.cpp \
LOCAL_CLANG := true
LOCAL_MODULE := libminadbd
+1 -1
View File
@@ -3,6 +3,6 @@ minadbd, and services.c has been modified as follows:
- all services removed
- all host mode support removed
- sideload_service() added; this is the only service supported. It
- `sideload_service()` added; this is the only service supported. It
receives a single blob of data, writes it to a fixed filename, and
makes the process exit.
-2
View File
@@ -19,8 +19,6 @@
#include <string.h>
#include <errno.h>
#include "sysdeps.h"
#include "adb.h"
#include "adb_io.h"
#include "fuse_adb_provider.h"
+3 -3
View File
@@ -14,18 +14,18 @@
* limitations under the License.
*/
#include "minadbd.h"
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include "sysdeps.h"
#include "adb.h"
#include "adb_auth.h"
#include "transport.h"
int adb_server_main(int is_daemon, int server_port, int /* reply_fd */) {
int minadbd_main() {
adb_device_banner = "sideload";
signal(SIGPIPE, SIG_IGN);
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2016 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 MINADBD_H__
#define MINADBD_H__
int minadbd_main();
#endif
@@ -21,11 +21,10 @@
#include <string.h>
#include <unistd.h>
#include "sysdeps.h"
#include "adb.h"
#include "fdevent.h"
#include "fuse_adb_provider.h"
#include "sysdeps.h"
typedef struct stinfo stinfo;
@@ -62,12 +61,12 @@ static void sideload_host_service(int sfd, void* data) {
static int create_service_thread(void (*func)(int, void *), void *cookie) {
int s[2];
if(adb_socketpair(s)) {
if (adb_socketpair(s)) {
printf("cannot create service socket pair\n");
return -1;
}
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
stinfo* sti = static_cast<stinfo*>(malloc(sizeof(stinfo)));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = func;
sti->cookie = cookie;
+47 -4
View File
@@ -1,3 +1,17 @@
# 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -6,6 +20,7 @@ LOCAL_SRC_FILES := \
graphics.cpp \
graphics_drm.cpp \
graphics_fbdev.cpp \
graphics_overlay.cpp \
resources.cpp
LOCAL_C_INCLUDES := external/libcxx/include external/libpng
@@ -35,8 +50,21 @@ ifeq ($(TW_NEW_ION_HEAP), true)
LOCAL_CFLAGS += -DNEW_ION_HEAP
endif
LOCAL_WHOLE_STATIC_LIBRARIES += libdrm
LOCAL_STATIC_LIBRARIES += libpng
LOCAL_WHOLE_STATIC_LIBRARIES += \
libdrm
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0)
LOCAL_CFLAGS += -DHAS_LIBSYNC
LOCAL_WHOLE_STATIC_LIBRARIES += libsync_recovery
endif
LOCAL_STATIC_LIBRARIES := \
libpng \
libbase
LOCAL_CFLAGS := -Werror -std=c++14
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_MODULE := libminui
@@ -90,7 +118,14 @@ include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := libminui
LOCAL_WHOLE_STATIC_LIBRARIES += libminui
LOCAL_SHARED_LIBRARIES := libpng
LOCAL_SHARED_LIBRARIES := \
libpng \
libbase
LOCAL_CFLAGS := -Werror
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
@@ -98,7 +133,15 @@ LOCAL_MODULE := minuitest
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_SRC_FILES := main.cpp
LOCAL_STATIC_LIBRARIES := libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc
LOCAL_SHARED_LIBRARIES := libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc
LOCAL_C_INCLUDES := external/libcxx/include external/libpng
LOCAL_FORCE_STATIC_EXECUTABLE := true
ifneq ($(TARGET_ARCH), arm64)
ifneq ($(TARGET_ARCH), x86_64)
LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker
else
LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
endif
else
LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
endif
include $(BUILD_EXECUTABLE)
+135 -104
View File
@@ -15,17 +15,19 @@
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <linux/input.h>
#include <functional>
#include "minui.h"
#include "minui/minui.h"
#define MAX_DEVICES 16
#define MAX_MISC_FDS 16
@@ -34,9 +36,11 @@
#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
struct fd_info {
int fd;
ev_callback cb;
void* data;
int fd;
ev_callback cb;
#ifdef TW_USE_MINUI_WITH_DATA
void* data;
#endif
};
static int g_epoll_fd;
@@ -49,92 +53,105 @@ static unsigned ev_count = 0;
static unsigned ev_dev_count = 0;
static unsigned ev_misc_count = 0;
static bool test_bit(size_t bit, unsigned long* array) {
static bool test_bit(size_t bit, unsigned long* array) { // NOLINT
return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
}
#ifdef TW_USE_MINUI_WITH_DATA
int ev_init(ev_callback input_cb, void* data) {
bool epollctlfail = false;
#else
int ev_init(ev_callback input_cb) {
#endif
bool epollctlfail = false;
g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
if (g_epoll_fd == -1) {
return -1;
g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
if (g_epoll_fd == -1) {
return -1;
}
DIR* dir = opendir("/dev/input");
if (dir != NULL) {
dirent* de;
while ((de = readdir(dir))) {
// Use unsigned long to match ioctl's parameter type.
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
// fprintf(stderr,"/dev/input/%s\n", de->d_name);
if (strncmp(de->d_name, "event", 5)) continue;
int fd = openat(dirfd(dir), de->d_name, O_RDONLY);
if (fd == -1) continue;
// Read the evbits of the input device.
if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
close(fd);
continue;
}
// We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed.
if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
close(fd);
continue;
}
epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = &ev_fdinfo[ev_count];
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
close(fd);
epollctlfail = true;
continue;
}
ev_fdinfo[ev_count].fd = fd;
ev_fdinfo[ev_count].cb = std::move(input_cb);
#ifdef TW_USE_MINUI_WITH_DATA
ev_fdinfo[ev_count].data = data;
#endif
ev_count++;
ev_dev_count++;
if (ev_dev_count == MAX_DEVICES) break;
}
DIR* dir = opendir("/dev/input");
if (dir != NULL) {
dirent* de;
while ((de = readdir(dir))) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
closedir(dir);
}
// fprintf(stderr,"/dev/input/%s\n", de->d_name);
if (strncmp(de->d_name, "event", 5)) continue;
int fd = openat(dirfd(dir), de->d_name, O_RDONLY);
if (fd == -1) continue;
if (epollctlfail && !ev_count) {
close(g_epoll_fd);
g_epoll_fd = -1;
return -1;
}
// Read the evbits of the input device.
if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
close(fd);
continue;
}
// We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed.
if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
close(fd);
continue;
}
epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = &ev_fdinfo[ev_count];
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
close(fd);
epollctlfail = true;
continue;
}
ev_fdinfo[ev_count].fd = fd;
ev_fdinfo[ev_count].cb = input_cb;
ev_fdinfo[ev_count].data = data;
ev_count++;
ev_dev_count++;
if (ev_dev_count == MAX_DEVICES) break;
}
closedir(dir);
}
if (epollctlfail && !ev_count) {
close(g_epoll_fd);
g_epoll_fd = -1;
return -1;
}
return 0;
return 0;
}
int ev_get_epollfd(void) {
return g_epoll_fd;
}
#ifdef TW_USE_MINUI_WITH_DATA
int ev_add_fd(int fd, ev_callback cb, void* data) {
if (ev_misc_count == MAX_MISC_FDS || cb == NULL) {
return -1;
}
#else
int ev_add_fd(int fd, ev_callback cb) {
#endif
if (ev_misc_count == MAX_MISC_FDS || cb == NULL) {
return -1;
}
epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)&ev_fdinfo[ev_count];
int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
if (!ret) {
ev_fdinfo[ev_count].fd = fd;
ev_fdinfo[ev_count].cb = cb;
ev_fdinfo[ev_count].data = data;
ev_count++;
ev_misc_count++;
}
epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = static_cast<void*>(&ev_fdinfo[ev_count]);
int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
if (!ret) {
ev_fdinfo[ev_count].fd = fd;
ev_fdinfo[ev_count].cb = std::move(cb);
#ifdef TW_USE_MINUI_WITH_DATA
ev_fdinfo[ev_count].data = data;
#endif
ev_count++;
ev_misc_count++;
}
return ret;
return ret;
}
void ev_exit(void) {
@@ -155,13 +172,17 @@ int ev_wait(int timeout) {
}
void ev_dispatch(void) {
for (int n = 0; n < npolledevents; n++) {
fd_info* fdi = reinterpret_cast<fd_info*>(polledevents[n].data.ptr);
ev_callback cb = fdi->cb;
if (cb) {
cb(fdi->fd, polledevents[n].events, fdi->data);
}
for (int n = 0; n < npolledevents; n++) {
fd_info* fdi = static_cast<fd_info*>(polledevents[n].data.ptr);
const ev_callback& cb = fdi->cb;
if (cb) {
#ifdef TW_USE_MINUI_WITH_DATA
cb(fdi->fd, polledevents[n].events, fdi->data);
#else
cb(fdi->fd, polledevents[n].events);
#endif
}
}
}
int ev_get_input(int fd, uint32_t epevents, input_event* ev) {
@@ -174,37 +195,47 @@ int ev_get_input(int fd, uint32_t epevents, input_event* ev) {
return -1;
}
#ifdef TW_USE_MINUI_WITH_DATA
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
#else
int ev_sync_key_state(const ev_set_key_callback& set_key_cb) {
#endif
// Use unsigned long to match ioctl's parameter type.
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT
for (size_t i = 0; i < ev_dev_count; ++i) {
memset(ev_bits, 0, sizeof(ev_bits));
memset(key_bits, 0, sizeof(key_bits));
for (size_t i = 0; i < ev_dev_count; ++i) {
memset(ev_bits, 0, sizeof(ev_bits));
memset(key_bits, 0, sizeof(key_bits));
if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
continue;
}
if (!test_bit(EV_KEY, ev_bits)) {
continue;
}
if (ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits) == -1) {
continue;
}
for (int code = 0; code <= KEY_MAX; code++) {
if (test_bit(code, key_bits)) {
set_key_cb(code, 1, data);
}
}
if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
continue;
}
if (!test_bit(EV_KEY, ev_bits)) {
continue;
}
if (ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits) == -1) {
continue;
}
return 0;
for (int code = 0; code <= KEY_MAX; code++) {
if (test_bit(code, key_bits)) {
#ifdef TW_USE_MINUI_WITH_DATA
set_key_cb(code, 1, data);
#else
set_key_cb(code, 1);
#endif
}
}
}
return 0;
}
void ev_iterate_available_keys(std::function<void(int)> f) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
void ev_iterate_available_keys(const std::function<void(int)>& f) {
// Use unsigned long to match ioctl's parameter type.
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT
for (size_t i = 0; i < ev_dev_count; ++i) {
memset(ev_bits, 0, sizeof(ev_bits));
+53 -115
View File
@@ -14,22 +14,13 @@
* limitations under the License.
*/
#include <stdbool.h>
#include "graphics.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <time.h>
#include <memory>
#ifdef BOARD_USE_CUSTOM_RECOVERY_FONT
#include BOARD_USE_CUSTOM_RECOVERY_FONT
@@ -37,11 +28,14 @@
#include "font_10x18.h"
#endif
#include "minui.h"
#include "graphics.h"
#include "graphics_adf.h"
#include "graphics_drm.h"
#include "graphics_fbdev.h"
#include "graphics_overlay.h"
#include "minui/minui.h"
static GRFont* gr_font = NULL;
static minui_backend* gr_backend = NULL;
static MinuiBackend* gr_backend = nullptr;
static int overscan_percent = OVERSCAN_PERCENT;
static int overscan_offset_x = 0;
@@ -470,7 +464,7 @@ void gr_set_font(__attribute__ ((unused))const char* name) {
}
#else // TW_NO_MINUI_CUSTOM_FONTS
int gr_init_font(const char* name, GRFont** dest) {
GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
if (font == nullptr) {
return -1;
}
@@ -503,15 +497,15 @@ static void gr_init_font(void)
// fall back to the compiled-in font.
gr_font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
gr_font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
gr_font->texture->width = font.width;
gr_font->texture->height = font.height;
gr_font->texture->row_bytes = font.width;
gr_font->texture->pixel_bytes = 1;
unsigned char* bits = reinterpret_cast<unsigned char*>(malloc(font.width * font.height));
gr_font->texture->data = reinterpret_cast<unsigned char*>(bits);
unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
gr_font->texture->data = bits;
unsigned char data;
unsigned char* in = font.rundata;
@@ -525,131 +519,75 @@ static void gr_init_font(void)
}
#endif // TW_NO_MINUI_CUSTOM_FONTS
#if 0
// Exercises many of the gr_*() functions; useful for testing.
static void gr_test() {
GRSurface** images;
int frames;
int result = res_create_multi_surface("icon_installing", &frames, &images);
if (result < 0) {
printf("create surface %d\n", result);
gr_exit();
return;
}
time_t start = time(NULL);
int x;
for (x = 0; x <= 1200; ++x) {
if (x < 400) {
gr_color(0, 0, 0, 255);
} else {
gr_color(0, (x-400)%128, 0, 255);
}
gr_clear();
gr_color(255, 0, 0, 255);
GRSurface* frame = images[x%frames];
gr_blit(frame, 0, 0, frame->width, frame->height, x, 0);
gr_color(255, 0, 0, 128);
gr_fill(400, 150, 600, 350);
gr_color(255, 255, 255, 255);
gr_text(500, 225, "hello, world!", 0);
gr_color(255, 255, 0, 128);
gr_text(300+x, 275, "pack my box with five dozen liquor jugs", 1);
gr_color(0, 0, 255, 128);
gr_fill(gr_draw->width - 200 - x, 300, gr_draw->width - x, 500);
gr_draw = gr_backend->flip(gr_backend);
}
printf("getting end time\n");
time_t end = time(NULL);
printf("got end time\n");
printf("start %ld end %ld\n", (long)start, (long)end);
if (end > start) {
printf("%.2f fps\n", ((double)x) / (end-start));
}
}
#endif
void gr_flip() {
gr_draw = gr_backend->flip(gr_backend);
gr_draw = gr_backend->Flip();
}
int gr_init(void)
{
gr_init_font();
gr_draw = NULL;
gr_init_font();
auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendOverlay>() };
gr_draw = backend->Init();
#ifdef MSM_BSP
gr_backend = open_overlay();
if (gr_backend) {
gr_draw = gr_backend->init(gr_backend);
if (!gr_draw) {
gr_backend->exit(gr_backend);
} else
printf("Using overlay graphics.\n");
if (gr_draw) {
printf("Using overlay graphics.\n");
}
#endif
#ifndef MSM_BSP
if (!gr_backend || !gr_draw) {
gr_backend = open_adf();
if (gr_backend) {
gr_draw = gr_backend->init(gr_backend);
if (!gr_draw) {
gr_backend->exit(gr_backend);
} else
printf("Using adf graphics.\n");
}
if (!gr_draw) {
backend = std::make_unique<MinuiBackendAdf>();
gr_draw = backend->Init();
if (gr_draw)
printf("Using adf graphics.\n");
}
#else
printf("Skipping adf graphics because TW_TARGET_USES_QCOM_BSP := true\n");
#endif
if (!gr_backend || !gr_draw) {
gr_backend = open_drm();
gr_draw = gr_backend->init(gr_backend);
if (!gr_draw) {
backend = std::make_unique<MinuiBackendDrm>();
gr_draw = backend->Init();
if (gr_draw)
printf("Using drm graphics.\n");
}
if (!gr_backend || !gr_draw) {
gr_backend = open_fbdev();
gr_draw = gr_backend->init(gr_backend);
if (gr_draw == NULL) {
return -1;
} else
if (!gr_draw) {
backend = std::make_unique<MinuiBackendFbdev>();
gr_draw = backend->Init();
if (gr_draw)
printf("Using fbdev graphics.\n");
}
overscan_offset_x = gr_draw->width * overscan_percent / 100;
overscan_offset_y = gr_draw->height * overscan_percent / 100;
if (!gr_draw) {
return -1;
}
gr_flip();
gr_flip();
gr_backend = backend.release();
return 0;
overscan_offset_x = gr_draw->width * overscan_percent / 100;
overscan_offset_y = gr_draw->height * overscan_percent / 100;
gr_flip();
gr_flip();
return 0;
}
void gr_exit(void)
{
gr_backend->exit(gr_backend);
void gr_exit() {
delete gr_backend;
}
int gr_fb_width(void)
{
return gr_draw->width - 2*overscan_offset_x;
int gr_fb_width() {
return gr_draw->width - 2 * overscan_offset_x;
}
int gr_fb_height(void)
{
return gr_draw->height - 2*overscan_offset_y;
int gr_fb_height() {
return gr_draw->height - 2 * overscan_offset_y;
}
void gr_fb_blank(bool blank)
{
gr_backend->blank(gr_backend, blank);
void gr_fb_blank(bool blank) {
gr_backend->Blank(blank);
}
+13 -19
View File
@@ -17,28 +17,22 @@
#ifndef _GRAPHICS_H_
#define _GRAPHICS_H_
#include "minui.h"
#include "minui/minui.h"
// TODO: lose the function pointers.
struct minui_backend {
// Initializes the backend and returns a GRSurface* to draw into.
GRSurface* (*init)(minui_backend*);
class MinuiBackend {
public:
// Initializes the backend and returns a GRSurface* to draw into.
virtual GRSurface* Init() = 0;
// Causes the current drawing surface (returned by the most recent
// call to flip() or init()) to be displayed, and returns a new
// drawing surface.
GRSurface* (*flip)(minui_backend*);
// Causes the current drawing surface (returned by the most recent call to Flip() or Init()) to
// be displayed, and returns a new drawing surface.
virtual GRSurface* Flip() = 0;
// Blank (or unblank) the screen.
void (*blank)(minui_backend*, bool);
// Blank (or unblank) the screen.
virtual void Blank(bool) = 0;
// Device cleanup when drawing is done.
void (*exit)(minui_backend*);
// Device cleanup when drawing is done.
virtual ~MinuiBackend() {};
};
minui_backend* open_fbdev();
minui_backend* open_adf();
minui_backend* open_drm();
minui_backend* open_overlay();
#endif
#endif // _GRAPHICS_H_
+165 -213
View File
@@ -14,238 +14,190 @@
* limitations under the License.
*/
#include "graphics_adf.h"
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/cdefs.h>
#include <sys/mman.h>
#include <adf/adf.h>
#include "graphics.h"
struct adf_surface_pdata {
GRSurface base;
int fd;
__u32 offset;
__u32 pitch;
};
struct adf_pdata {
minui_backend base;
int intf_fd;
adf_id_t eng_id;
__u32 format;
unsigned int current_surface;
unsigned int n_surfaces;
adf_surface_pdata surfaces[2];
};
static GRSurface* adf_flip(minui_backend *backend);
static void adf_blank(minui_backend *backend, bool blank);
static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) {
memset(surf, 0, sizeof(*surf));
surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay,
mode->vdisplay, pdata->format, &surf->offset, &surf->pitch);
if (surf->fd < 0)
return surf->fd;
surf->base.width = mode->hdisplay;
surf->base.height = mode->vdisplay;
surf->base.row_bytes = surf->pitch;
surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
surf->base.data = reinterpret_cast<uint8_t*>(mmap(NULL,
surf->pitch * surf->base.height, PROT_WRITE,
MAP_SHARED, surf->fd, surf->offset));
if (surf->base.data == MAP_FAILED) {
close(surf->fd);
return -errno;
}
return 0;
}
static int adf_interface_init(adf_pdata *pdata)
{
adf_interface_data intf_data;
int ret = 0;
int err;
err = adf_get_interface_data(pdata->intf_fd, &intf_data);
if (err < 0)
return err;
err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]);
if (err < 0) {
fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
ret = err;
goto done;
}
err = adf_surface_init(pdata, &intf_data.current_mode,
&pdata->surfaces[1]);
if (err < 0) {
fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1]));
pdata->n_surfaces = 1;
} else {
pdata->n_surfaces = 2;
}
done:
adf_free_interface_data(&intf_data);
return ret;
}
static int adf_device_init(adf_pdata *pdata, adf_device *dev)
{
adf_id_t intf_id;
int intf_fd;
int err;
err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id,
&pdata->eng_id);
if (err < 0)
return err;
err = adf_device_attach(dev, pdata->eng_id, intf_id);
if (err < 0 && err != -EALREADY)
return err;
pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
if (pdata->intf_fd < 0)
return pdata->intf_fd;
err = adf_interface_init(pdata);
if (err < 0) {
close(pdata->intf_fd);
pdata->intf_fd = -1;
}
return err;
}
static GRSurface* adf_init(minui_backend *backend)
{
adf_pdata *pdata = (adf_pdata *)backend;
adf_id_t *dev_ids = NULL;
ssize_t n_dev_ids, i;
GRSurface* ret;
#if defined(RECOVERY_ABGR)
pdata->format = DRM_FORMAT_ABGR8888;
#elif defined(RECOVERY_BGRA)
pdata->format = DRM_FORMAT_BGRA8888;
#elif defined(RECOVERY_RGBA)
pdata->format = DRM_FORMAT_RGBA8888;
#elif defined(RECOVERY_RGBX)
pdata->format = DRM_FORMAT_RGBX8888;
#else
pdata->format = DRM_FORMAT_RGB565;
#ifdef HAS_LIBSYNC
#include <sync/sync.h>
#endif
n_dev_ids = adf_devices(&dev_ids);
if (n_dev_ids == 0) {
return NULL;
} else if (n_dev_ids < 0) {
fprintf(stderr, "enumerating adf devices failed: %s\n",
strerror(-n_dev_ids));
return NULL;
}
#include "minui/minui.h"
pdata->intf_fd = -1;
MinuiBackendAdf::MinuiBackendAdf() : intf_fd(-1), dev(), n_surfaces(0), surfaces() {}
for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) {
adf_device dev;
int MinuiBackendAdf::SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf) {
*surf = {};
surf->fence_fd = -1;
surf->fd = adf_interface_simple_buffer_alloc(intf_fd, mode->hdisplay, mode->vdisplay, format,
&surf->offset, &surf->pitch);
if (surf->fd < 0) {
return surf->fd;
}
int err = adf_device_open(dev_ids[i], O_RDWR, &dev);
if (err < 0) {
fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i],
strerror(-err));
continue;
}
surf->width = mode->hdisplay;
surf->height = mode->vdisplay;
surf->row_bytes = surf->pitch;
surf->pixel_bytes = (format == DRM_FORMAT_RGB565) ? 2 : 4;
err = adf_device_init(pdata, &dev);
if (err < 0)
fprintf(stderr, "initializing adf device %u failed: %s\n",
dev_ids[i], strerror(-err));
adf_device_close(&dev);
}
free(dev_ids);
if (pdata->intf_fd < 0)
return NULL;
ret = adf_flip(backend);
adf_blank(backend, true);
adf_blank(backend, false);
return ret;
}
static GRSurface* adf_flip(minui_backend *backend)
{
adf_pdata *pdata = (adf_pdata *)backend;
adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface];
int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id,
surf->base.width, surf->base.height, pdata->format, surf->fd,
surf->offset, surf->pitch, -1);
if (fence_fd >= 0)
close(fence_fd);
pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces;
return &pdata->surfaces[pdata->current_surface].base;
}
static void adf_blank(minui_backend *backend, bool blank)
{
adf_pdata *pdata = (adf_pdata *)backend;
adf_interface_blank(pdata->intf_fd,
blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
}
static void adf_surface_destroy(adf_surface_pdata *surf)
{
munmap(surf->base.data, surf->pitch * surf->base.height);
surf->data = static_cast<uint8_t*>(
mmap(nullptr, surf->pitch * surf->height, PROT_WRITE, MAP_SHARED, surf->fd, surf->offset));
if (surf->data == MAP_FAILED) {
int saved_errno = errno;
close(surf->fd);
return -saved_errno;
}
return 0;
}
static void adf_exit(minui_backend *backend)
{
adf_pdata *pdata = (adf_pdata *)backend;
unsigned int i;
int MinuiBackendAdf::InterfaceInit() {
adf_interface_data intf_data;
int err = adf_get_interface_data(intf_fd, &intf_data);
if (err < 0) return err;
for (i = 0; i < pdata->n_surfaces; i++)
adf_surface_destroy(&pdata->surfaces[i]);
if (pdata->intf_fd >= 0)
close(pdata->intf_fd);
free(pdata);
int ret = 0;
err = SurfaceInit(&intf_data.current_mode, &surfaces[0]);
if (err < 0) {
fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
ret = err;
goto done;
}
err = SurfaceInit(&intf_data.current_mode, &surfaces[1]);
if (err < 0) {
fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
surfaces[1] = {};
n_surfaces = 1;
} else {
n_surfaces = 2;
}
done:
adf_free_interface_data(&intf_data);
return ret;
}
minui_backend *open_adf()
{
adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
if (!pdata) {
perror("allocating adf backend failed");
return NULL;
int MinuiBackendAdf::DeviceInit(adf_device* dev) {
adf_id_t intf_id;
int err = adf_find_simple_post_configuration(dev, &format, 1, &intf_id, &eng_id);
if (err < 0) return err;
err = adf_device_attach(dev, eng_id, intf_id);
if (err < 0 && err != -EALREADY) return err;
intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
if (intf_fd < 0) return intf_fd;
err = InterfaceInit();
if (err < 0) {
close(intf_fd);
intf_fd = -1;
}
return err;
}
GRSurface* MinuiBackendAdf::Init() {
#if defined(RECOVERY_ABGR)
format = DRM_FORMAT_ABGR8888;
#elif defined(RECOVERY_BGRA)
format = DRM_FORMAT_BGRA8888;
#elif defined(RECOVERY_RGBA)
format = DRM_FORMAT_RGBA8888;
#elif defined(RECOVERY_RGBX)
format = DRM_FORMAT_RGBX8888;
#else
format = DRM_FORMAT_RGB565;
#endif
adf_id_t* dev_ids = nullptr;
ssize_t n_dev_ids = adf_devices(&dev_ids);
if (n_dev_ids == 0) {
return nullptr;
} else if (n_dev_ids < 0) {
fprintf(stderr, "enumerating adf devices failed: %s\n", strerror(-n_dev_ids));
return nullptr;
}
intf_fd = -1;
for (ssize_t i = 0; i < n_dev_ids && intf_fd < 0; i++) {
int err = adf_device_open(dev_ids[i], O_RDWR, &dev);
if (err < 0) {
fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i], strerror(-err));
continue;
}
pdata->base.init = adf_init;
pdata->base.flip = adf_flip;
pdata->base.blank = adf_blank;
pdata->base.exit = adf_exit;
return &pdata->base;
err = DeviceInit(&dev);
if (err < 0) {
fprintf(stderr, "initializing adf device %u failed: %s\n", dev_ids[i], strerror(-err));
adf_device_close(&dev);
}
}
free(dev_ids);
if (intf_fd < 0) return nullptr;
GRSurface* ret = Flip();
Blank(true);
Blank(false);
return ret;
}
void MinuiBackendAdf::Sync(__unused GRSurfaceAdf* surf) {
#ifdef HAS_LIBSYNC
static constexpr unsigned int warningTimeout = 3000;
if (surf == nullptr) return;
if (surf->fence_fd >= 0) {
int err = sync_wait(surf->fence_fd, warningTimeout);
if (err < 0) {
perror("adf sync fence wait error\n");
}
close(surf->fence_fd);
surf->fence_fd = -1;
}
#endif
}
GRSurface* MinuiBackendAdf::Flip() {
GRSurfaceAdf* surf = &surfaces[current_surface];
int fence_fd = adf_interface_simple_post(intf_fd, eng_id, surf->width, surf->height, format,
surf->fd, surf->offset, surf->pitch, -1);
if (fence_fd >= 0) surf->fence_fd = fence_fd;
current_surface = (current_surface + 1) % n_surfaces;
Sync(&surfaces[current_surface]);
return &surfaces[current_surface];
}
void MinuiBackendAdf::Blank(bool blank) {
adf_interface_blank(intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
}
void MinuiBackendAdf::SurfaceDestroy(GRSurfaceAdf* surf) {
munmap(surf->data, surf->pitch * surf->height);
close(surf->fence_fd);
close(surf->fd);
}
MinuiBackendAdf::~MinuiBackendAdf() {
adf_device_close(&dev);
for (unsigned int i = 0; i < n_surfaces; i++) {
SurfaceDestroy(&surfaces[i]);
}
if (intf_fd >= 0) close(intf_fd);
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2017 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 _GRAPHICS_ADF_H_
#define _GRAPHICS_ADF_H_
#include <adf/adf.h>
#include "graphics.h"
class GRSurfaceAdf : public GRSurface {
private:
int fence_fd;
int fd;
__u32 offset;
__u32 pitch;
friend class MinuiBackendAdf;
};
class MinuiBackendAdf : public MinuiBackend {
public:
GRSurface* Init() override;
GRSurface* Flip() override;
void Blank(bool) override;
~MinuiBackendAdf() override;
MinuiBackendAdf();
private:
int SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf);
int InterfaceInit();
int DeviceInit(adf_device* dev);
void SurfaceDestroy(GRSurfaceAdf* surf);
void Sync(GRSurfaceAdf* surf);
int intf_fd;
adf_id_t eng_id;
__u32 format;
adf_device dev;
unsigned int current_surface;
unsigned int n_surfaces;
GRSurfaceAdf surfaces[2];
};
#endif // _GRAPHICS_ADF_H_
+291 -373
View File
@@ -14,466 +14,384 @@
* limitations under the License.
*/
#include <drm_fourcc.h>
#include "graphics_drm.h"
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <drm_fourcc.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "minui.h"
#include "graphics.h"
#include "minui/minui.h"
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
struct drm_surface {
GRSurface base;
uint32_t fb_id;
uint32_t handle;
};
MinuiBackendDrm::MinuiBackendDrm()
: GRSurfaceDrms(), main_monitor_crtc(nullptr), main_monitor_connector(nullptr), drm_fd(-1) {}
static drm_surface *drm_surfaces[2];
static int current_buffer;
static drmModeCrtc *main_monitor_crtc;
static drmModeConnector *main_monitor_connector;
static int drm_fd = -1;
static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) {
if (crtc) {
drmModeSetCrtc(drm_fd, crtc->crtc_id,
0, // fb_id
0, 0, // x,y
NULL, // connectors
0, // connector_count
NULL); // mode
}
void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) {
if (crtc) {
drmModeSetCrtc(drm_fd, crtc->crtc_id,
0, // fb_id
0, 0, // x,y
nullptr, // connectors
0, // connector_count
nullptr); // mode
}
}
static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc,
struct drm_surface *surface) {
int32_t ret;
void MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface) {
int32_t ret = drmModeSetCrtc(drm_fd, crtc->crtc_id, surface->fb_id, 0, 0, // x,y
&main_monitor_connector->connector_id,
1, // connector_count
&main_monitor_crtc->mode);
ret = drmModeSetCrtc(drm_fd, crtc->crtc_id,
surface->fb_id,
0, 0, // x,y
&main_monitor_connector->connector_id,
1, // connector_count
&main_monitor_crtc->mode);
if (ret)
printf("drmModeSetCrtc failed ret=%d\n", ret);
if (ret) {
printf("drmModeSetCrtc failed ret=%d\n", ret);
}
}
static void drm_blank(minui_backend* backend __unused, bool blank) {
if (blank)
drm_disable_crtc(drm_fd, main_monitor_crtc);
else
drm_enable_crtc(drm_fd, main_monitor_crtc,
drm_surfaces[current_buffer]);
void MinuiBackendDrm::Blank(bool blank) {
if (blank) {
DrmDisableCrtc(drm_fd, main_monitor_crtc);
} else {
DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]);
}
}
static void drm_destroy_surface(struct drm_surface *surface) {
struct drm_gem_close gem_close;
int ret;
void MinuiBackendDrm::DrmDestroySurface(GRSurfaceDrm* surface) {
if (!surface) return;
if(!surface)
return;
if (surface->data) {
munmap(surface->data, surface->row_bytes * surface->height);
}
if (surface->base.data)
munmap(surface->base.data,
surface->base.row_bytes * surface->base.height);
if (surface->fb_id) {
ret = drmModeRmFB(drm_fd, surface->fb_id);
if (ret)
printf("drmModeRmFB failed ret=%d\n", ret);
if (surface->fb_id) {
int ret = drmModeRmFB(drm_fd, surface->fb_id);
if (ret) {
printf("drmModeRmFB failed ret=%d\n", ret);
}
}
if (surface->handle) {
memset(&gem_close, 0, sizeof(gem_close));
gem_close.handle = surface->handle;
if (surface->handle) {
drm_gem_close gem_close = {};
gem_close.handle = surface->handle;
ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
if (ret)
printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret);
int ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
if (ret) {
printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret);
}
}
free(surface);
delete surface;
}
static int drm_format_to_bpp(uint32_t format) {
switch(format) {
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB8888:
return 32;
case DRM_FORMAT_RGB565:
return 16;
default:
printf("Unknown format %d\n", format);
return 32;
}
switch (format) {
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_XRGB8888:
return 32;
case DRM_FORMAT_RGB565:
return 16;
default:
printf("Unknown format %d\n", format);
return 32;
}
}
static drm_surface *drm_create_surface(int width, int height) {
struct drm_surface *surface;
struct drm_mode_create_dumb create_dumb;
uint32_t format;
int ret;
surface = (struct drm_surface*)calloc(1, sizeof(*surface));
if (!surface) {
printf("Can't allocate memory\n");
return NULL;
}
GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) {
GRSurfaceDrm* surface = new GRSurfaceDrm;
*surface = {};
uint32_t format;
#if defined(RECOVERY_ABGR)
format = DRM_FORMAT_RGBA8888;
format = DRM_FORMAT_RGBA8888;
#elif defined(RECOVERY_BGRA)
format = DRM_FORMAT_ARGB8888;
format = DRM_FORMAT_ARGB8888;
#elif defined(RECOVERY_RGBA)
format = DRM_FORMAT_ABGR8888;
format = DRM_FORMAT_ARGB8888;
#elif defined(RECOVERY_RGBX)
format = DRM_FORMAT_XBGR8888;
format = DRM_FORMAT_XBGR8888;
#else
format = DRM_FORMAT_RGB565;
format = DRM_FORMAT_RGB565;
#endif
memset(&create_dumb, 0, sizeof(create_dumb));
create_dumb.height = height;
create_dumb.width = width;
create_dumb.bpp = drm_format_to_bpp(format);
create_dumb.flags = 0;
drm_mode_create_dumb create_dumb = {};
create_dumb.height = height;
create_dumb.width = width;
create_dumb.bpp = drm_format_to_bpp(format);
create_dumb.flags = 0;
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
if (ret) {
printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n",ret);
drm_destroy_surface(surface);
return NULL;
}
surface->handle = create_dumb.handle;
int ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
if (ret) {
printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n", ret);
DrmDestroySurface(surface);
return nullptr;
}
surface->handle = create_dumb.handle;
uint32_t handles[4], pitches[4], offsets[4];
uint32_t handles[4], pitches[4], offsets[4];
handles[0] = surface->handle;
pitches[0] = create_dumb.pitch;
offsets[0] = 0;
handles[0] = surface->handle;
pitches[0] = create_dumb.pitch;
offsets[0] = 0;
ret = drmModeAddFB2(drm_fd, width, height,
format, handles, pitches, offsets,
&(surface->fb_id), 0);
if (ret) {
printf("drmModeAddFB2 failed ret=%d\n", ret);
drm_destroy_surface(surface);
return NULL;
}
ret =
drmModeAddFB2(drm_fd, width, height, format, handles, pitches, offsets, &(surface->fb_id), 0);
if (ret) {
printf("drmModeAddFB2 failed ret=%d\n", ret);
DrmDestroySurface(surface);
return nullptr;
}
struct drm_mode_map_dumb map_dumb;
memset(&map_dumb, 0, sizeof(map_dumb));
map_dumb.handle = create_dumb.handle;
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
if (ret) {
printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n",ret);
drm_destroy_surface(surface);
return NULL;;
}
drm_mode_map_dumb map_dumb = {};
map_dumb.handle = create_dumb.handle;
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
if (ret) {
printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n", ret);
DrmDestroySurface(surface);
return nullptr;
}
surface->base.height = height;
surface->base.width = width;
surface->base.row_bytes = create_dumb.pitch;
surface->base.pixel_bytes = create_dumb.bpp / 8;
surface->base.data = (unsigned char*)
mmap(NULL,
surface->base.height * surface->base.row_bytes,
PROT_READ | PROT_WRITE, MAP_SHARED,
drm_fd, map_dumb.offset);
if (surface->base.data == MAP_FAILED) {
perror("mmap() failed");
drm_destroy_surface(surface);
return NULL;
}
surface->height = height;
surface->width = width;
surface->row_bytes = create_dumb.pitch;
surface->pixel_bytes = create_dumb.bpp / 8;
surface->data = static_cast<unsigned char*>(mmap(nullptr, surface->height * surface->row_bytes,
PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd,
map_dumb.offset));
if (surface->data == MAP_FAILED) {
perror("mmap() failed");
DrmDestroySurface(surface);
return nullptr;
}
return surface;
return surface;
}
static drmModeCrtc *find_crtc_for_connector(int fd,
drmModeRes *resources,
drmModeConnector *connector) {
int i, j;
drmModeEncoder *encoder;
int32_t crtc;
static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources,
drmModeConnector* connector) {
// Find the encoder. If we already have one, just use it.
drmModeEncoder* encoder;
if (connector->encoder_id) {
encoder = drmModeGetEncoder(fd, connector->encoder_id);
} else {
encoder = nullptr;
}
/*
* Find the encoder. If we already have one, just use it.
*/
if (connector->encoder_id)
encoder = drmModeGetEncoder(fd, connector->encoder_id);
else
encoder = NULL;
int32_t crtc;
if (encoder && encoder->crtc_id) {
crtc = encoder->crtc_id;
drmModeFreeEncoder(encoder);
return drmModeGetCrtc(fd, crtc);
}
if (encoder && encoder->crtc_id) {
crtc = encoder->crtc_id;
// Didn't find anything, try to find a crtc and encoder combo.
crtc = -1;
for (int i = 0; i < connector->count_encoders; i++) {
encoder = drmModeGetEncoder(fd, connector->encoders[i]);
if (encoder) {
for (int j = 0; j < resources->count_crtcs; j++) {
if (!(encoder->possible_crtcs & (1 << j))) continue;
crtc = resources->crtcs[j];
break;
}
if (crtc >= 0) {
drmModeFreeEncoder(encoder);
return drmModeGetCrtc(fd, crtc);
}
}
}
/*
* Didn't find anything, try to find a crtc and encoder combo.
*/
crtc = -1;
for (i = 0; i < connector->count_encoders; i++) {
encoder = drmModeGetEncoder(fd, connector->encoders[i]);
if (encoder) {
for (j = 0; j < resources->count_crtcs; j++) {
if (!(encoder->possible_crtcs & (1 << j)))
continue;
crtc = resources->crtcs[j];
break;
}
if (crtc >= 0) {
drmModeFreeEncoder(encoder);
return drmModeGetCrtc(fd, crtc);
}
}
}
return NULL;
return nullptr;
}
static drmModeConnector *find_used_connector_by_type(int fd,
drmModeRes *resources,
unsigned type) {
int i;
for (i = 0; i < resources->count_connectors; i++) {
drmModeConnector *connector;
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (connector) {
if ((connector->connector_type == type) &&
(connector->connection == DRM_MODE_CONNECTED) &&
(connector->count_modes > 0))
return connector;
drmModeFreeConnector(connector);
}
static drmModeConnector* find_used_connector_by_type(int fd, drmModeRes* resources, unsigned type) {
for (int i = 0; i < resources->count_connectors; i++) {
drmModeConnector* connector = drmModeGetConnector(fd, resources->connectors[i]);
if (connector) {
if ((connector->connector_type == type) && (connector->connection == DRM_MODE_CONNECTED) &&
(connector->count_modes > 0)) {
return connector;
}
drmModeFreeConnector(connector);
}
return NULL;
}
return nullptr;
}
static drmModeConnector *find_first_connected_connector(int fd,
drmModeRes *resources) {
int i;
for (i = 0; i < resources->count_connectors; i++) {
drmModeConnector *connector;
static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* resources) {
for (int i = 0; i < resources->count_connectors; i++) {
drmModeConnector* connector;
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (connector) {
if ((connector->count_modes > 0) &&
(connector->connection == DRM_MODE_CONNECTED))
return connector;
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (connector) {
if ((connector->count_modes > 0) && (connector->connection == DRM_MODE_CONNECTED))
return connector;
drmModeFreeConnector(connector);
}
drmModeFreeConnector(connector);
}
return NULL;
}
return nullptr;
}
static drmModeConnector *find_main_monitor(int fd, drmModeRes *resources,
uint32_t *mode_index) {
unsigned i = 0;
int modes;
/* Look for LVDS/eDP/DSI connectors. Those are the main screens. */
unsigned kConnectorPriority[] = {
DRM_MODE_CONNECTOR_LVDS,
DRM_MODE_CONNECTOR_eDP,
DRM_MODE_CONNECTOR_DSI,
};
drmModeConnector* MinuiBackendDrm::FindMainMonitor(int fd, drmModeRes* resources,
uint32_t* mode_index) {
/* Look for LVDS/eDP/DSI connectors. Those are the main screens. */
static constexpr unsigned kConnectorPriority[] = {
DRM_MODE_CONNECTOR_LVDS,
DRM_MODE_CONNECTOR_eDP,
DRM_MODE_CONNECTOR_DSI,
};
drmModeConnector *main_monitor_connector = NULL;
do {
main_monitor_connector = find_used_connector_by_type(fd,
resources,
kConnectorPriority[i]);
i++;
} while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority));
drmModeConnector* main_monitor_connector = nullptr;
unsigned i = 0;
do {
main_monitor_connector = find_used_connector_by_type(fd, resources, kConnectorPriority[i]);
i++;
} while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority));
/* If we didn't find a connector, grab the first one that is connected. */
if (!main_monitor_connector)
main_monitor_connector =
find_first_connected_connector(fd, resources);
/* If we didn't find a connector, grab the first one that is connected. */
if (!main_monitor_connector) {
main_monitor_connector = find_first_connected_connector(fd, resources);
}
/* If we still didn't find a connector, give up and return. */
if (!main_monitor_connector)
return NULL;
/* If we still didn't find a connector, give up and return. */
if (!main_monitor_connector) return nullptr;
*mode_index = 0;
for (modes = 0; modes < main_monitor_connector->count_modes; modes++) {
if (main_monitor_connector->modes[modes].type &
DRM_MODE_TYPE_PREFERRED) {
*mode_index = modes;
break;
}
*mode_index = 0;
for (int modes = 0; modes < main_monitor_connector->count_modes; modes++) {
if (main_monitor_connector->modes[modes].type & DRM_MODE_TYPE_PREFERRED) {
*mode_index = modes;
break;
}
}
return main_monitor_connector;
return main_monitor_connector;
}
static void disable_non_main_crtcs(int fd,
drmModeRes *resources,
drmModeCrtc* main_crtc) {
int i;
drmModeCrtc* crtc;
for (i = 0; i < resources->count_connectors; i++) {
drmModeConnector *connector;
connector = drmModeGetConnector(fd, resources->connectors[i]);
crtc = find_crtc_for_connector(fd, resources, connector);
if (crtc->crtc_id != main_crtc->crtc_id)
drm_disable_crtc(fd, crtc);
drmModeFreeCrtc(crtc);
void MinuiBackendDrm::DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc) {
for (int i = 0; i < resources->count_connectors; i++) {
drmModeConnector* connector = drmModeGetConnector(fd, resources->connectors[i]);
drmModeCrtc* crtc = find_crtc_for_connector(fd, resources, connector);
if (crtc->crtc_id != main_crtc->crtc_id) {
DrmDisableCrtc(fd, crtc);
}
drmModeFreeCrtc(crtc);
}
}
static GRSurface* drm_init(minui_backend* backend __unused) {
drmModeRes *res = NULL;
uint32_t selected_mode;
char *dev_name;
int width, height;
int ret, i;
GRSurface* MinuiBackendDrm::Init() {
drmModeRes* res = nullptr;
/* Consider DRM devices in order. */
for (i = 0; i < DRM_MAX_MINOR; i++) {
uint64_t cap = 0;
/* Consider DRM devices in order. */
for (int i = 0; i < DRM_MAX_MINOR; i++) {
char* dev_name;
int ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
if (ret < 0) continue;
ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
if (ret < 0)
continue;
drm_fd = open(dev_name, O_RDWR, 0);
free(dev_name);
if (drm_fd < 0) continue;
drm_fd = open(dev_name, O_RDWR, 0);
free(dev_name);
if (drm_fd < 0)
continue;
/* We need dumb buffers. */
ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
if (ret || cap == 0) {
close(drm_fd);
continue;
}
res = drmModeGetResources(drm_fd);
if (!res) {
close(drm_fd);
continue;
}
/* Use this device if it has at least one connected monitor. */
if (res->count_crtcs > 0 && res->count_connectors > 0)
if (find_first_connected_connector(drm_fd, res))
break;
drmModeFreeResources(res);
close(drm_fd);
res = NULL;
uint64_t cap = 0;
/* We need dumb buffers. */
ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
if (ret || cap == 0) {
close(drm_fd);
continue;
}
if (drm_fd < 0 || res == NULL) {
perror("cannot find/open a drm device");
return NULL;
res = drmModeGetResources(drm_fd);
if (!res) {
close(drm_fd);
continue;
}
main_monitor_connector = find_main_monitor(drm_fd,
res, &selected_mode);
if (!main_monitor_connector) {
printf("main_monitor_connector not found\n");
drmModeFreeResources(res);
close(drm_fd);
return NULL;
/* Use this device if it has at least one connected monitor. */
if (res->count_crtcs > 0 && res->count_connectors > 0) {
if (find_first_connected_connector(drm_fd, res)) break;
}
main_monitor_crtc = find_crtc_for_connector(drm_fd, res,
main_monitor_connector);
if (!main_monitor_crtc) {
printf("main_monitor_crtc not found\n");
drmModeFreeResources(res);
close(drm_fd);
return NULL;
}
disable_non_main_crtcs(drm_fd,
res, main_monitor_crtc);
main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode];
width = main_monitor_crtc->mode.hdisplay;
height = main_monitor_crtc->mode.vdisplay;
drmModeFreeResources(res);
drm_surfaces[0] = drm_create_surface(width, height);
drm_surfaces[1] = drm_create_surface(width, height);
if (!drm_surfaces[0] || !drm_surfaces[1]) {
drm_destroy_surface(drm_surfaces[0]);
drm_destroy_surface(drm_surfaces[1]);
drmModeFreeResources(res);
close(drm_fd);
return NULL;
}
current_buffer = 0;
drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]);
return &(drm_surfaces[0]->base);
}
static GRSurface* drm_flip(minui_backend* backend __unused) {
int ret;
ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id,
drm_surfaces[current_buffer]->fb_id, 0, NULL);
if (ret < 0) {
printf("drmModePageFlip failed ret=%d\n", ret);
return NULL;
}
current_buffer = 1 - current_buffer;
return &(drm_surfaces[current_buffer]->base);
}
static void drm_exit(minui_backend* backend __unused) {
drm_disable_crtc(drm_fd, main_monitor_crtc);
drm_destroy_surface(drm_surfaces[0]);
drm_destroy_surface(drm_surfaces[1]);
drmModeFreeCrtc(main_monitor_crtc);
drmModeFreeConnector(main_monitor_connector);
close(drm_fd);
drm_fd = -1;
res = nullptr;
}
if (drm_fd < 0 || res == nullptr) {
perror("cannot find/open a drm device");
return nullptr;
}
uint32_t selected_mode;
main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode);
if (!main_monitor_connector) {
printf("main_monitor_connector not found\n");
drmModeFreeResources(res);
close(drm_fd);
return nullptr;
}
main_monitor_crtc = find_crtc_for_connector(drm_fd, res, main_monitor_connector);
if (!main_monitor_crtc) {
printf("main_monitor_crtc not found\n");
drmModeFreeResources(res);
close(drm_fd);
return nullptr;
}
DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc);
main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode];
int width = main_monitor_crtc->mode.hdisplay;
int height = main_monitor_crtc->mode.vdisplay;
drmModeFreeResources(res);
GRSurfaceDrms[0] = DrmCreateSurface(width, height);
GRSurfaceDrms[1] = DrmCreateSurface(width, height);
if (!GRSurfaceDrms[0] || !GRSurfaceDrms[1]) {
// GRSurfaceDrms and drm_fd should be freed in d'tor.
return nullptr;
}
current_buffer = 0;
DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]);
return GRSurfaceDrms[0];
}
static minui_backend drm_backend = {
.init = drm_init,
.flip = drm_flip,
.blank = drm_blank,
.exit = drm_exit,
};
minui_backend* open_drm() {
return &drm_backend;
GRSurface* MinuiBackendDrm::Flip() {
int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id,
GRSurfaceDrms[current_buffer]->fb_id, 0, nullptr);
if (ret < 0) {
printf("drmModePageFlip failed ret=%d\n", ret);
return nullptr;
}
current_buffer = 1 - current_buffer;
return GRSurfaceDrms[current_buffer];
}
MinuiBackendDrm::~MinuiBackendDrm() {
DrmDisableCrtc(drm_fd, main_monitor_crtc);
DrmDestroySurface(GRSurfaceDrms[0]);
DrmDestroySurface(GRSurfaceDrms[1]);
drmModeFreeCrtc(main_monitor_crtc);
drmModeFreeConnector(main_monitor_connector);
close(drm_fd);
drm_fd = -1;
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2017 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 _GRAPHICS_DRM_H_
#define _GRAPHICS_DRM_H_
#include <stdint.h>
#include <xf86drmMode.h>
#include "graphics.h"
#include "minui/minui.h"
class GRSurfaceDrm : public GRSurface {
private:
uint32_t fb_id;
uint32_t handle;
friend class MinuiBackendDrm;
};
class MinuiBackendDrm : public MinuiBackend {
public:
GRSurface* Init() override;
GRSurface* Flip() override;
void Blank(bool) override;
~MinuiBackendDrm() override;
MinuiBackendDrm();
private:
void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc);
void DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface);
GRSurfaceDrm* DrmCreateSurface(int width, int height);
void DrmDestroySurface(GRSurfaceDrm* surface);
void DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc);
drmModeConnector* FindMainMonitor(int fd, drmModeRes* resources, uint32_t* mode_index);
GRSurfaceDrm* GRSurfaceDrms[2];
int current_buffer;
drmModeCrtc* main_monitor_crtc;
drmModeConnector* main_monitor_connector;
int drm_fd;
};
#endif // _GRAPHICS_DRM_H_
+124 -155
View File
@@ -14,51 +14,23 @@
* limitations under the License.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "graphics_fbdev.h"
#include <fcntl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <sys/cdefs.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include "minui/minui.h"
#include "minui.h"
#include "graphics.h"
MinuiBackendFbdev::MinuiBackendFbdev() : gr_draw(nullptr), fb_fd(-1) {}
static GRSurface* fbdev_init(minui_backend*);
static GRSurface* fbdev_flip(minui_backend*);
static void fbdev_blank(minui_backend*, bool);
static void fbdev_exit(minui_backend*);
static GRSurface gr_framebuffer[2];
static bool double_buffered;
static GRSurface* gr_draw = NULL;
static int displayed_buffer;
static fb_var_screeninfo vi;
static int fb_fd = -1;
static minui_backend my_backend = {
.init = fbdev_init,
.flip = fbdev_flip,
.blank = fbdev_blank,
.exit = fbdev_exit,
};
minui_backend* open_fbdev() {
return &my_backend;
}
static void fbdev_blank(minui_backend* backend __unused, bool blank)
{
void MinuiBackendFbdev::Blank(bool blank) {
#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
int fd;
char brightness[4];
@@ -80,136 +52,133 @@ static void fbdev_blank(minui_backend* backend __unused, bool blank)
#endif
}
static void set_displayed_framebuffer(unsigned n)
{
if (n > 1 || !double_buffered) return;
void MinuiBackendFbdev::SetDisplayedFramebuffer(unsigned n) {
if (n > 1 || !double_buffered) return;
vi.yres_virtual = gr_framebuffer[0].height * 2;
vi.yoffset = n * gr_framebuffer[0].height;
vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
perror("active fb swap failed");
}
displayed_buffer = n;
vi.yres_virtual = gr_framebuffer[0].height * 2;
vi.yoffset = n * gr_framebuffer[0].height;
vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
perror("active fb swap failed");
}
displayed_buffer = n;
}
static GRSurface* fbdev_init(minui_backend* backend) {
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd == -1) {
perror("cannot open fb0");
return NULL;
GRSurface* MinuiBackendFbdev::Init() {
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd == -1) {
perror("cannot open fb0");
return nullptr;
}
fb_fix_screeninfo fi;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
close(fd);
return nullptr;
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
perror("failed to get fb0 info");
close(fd);
return nullptr;
}
// We print this out for informational purposes only, but
// throughout we assume that the framebuffer device uses an RGBX
// pixel format. This is the case for every development device I
// have access to. For some of those devices (eg, hammerhead aka
// Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
// different format (XBGR) but actually produces the correct
// results on the display when you write RGBX.
//
// If you have a device that actually *needs* another pixel format
// (ie, BGRX, or 565), patches welcome...
printf(
"fb0 reports (possibly inaccurate):\n"
" vi.bits_per_pixel = %d\n"
" vi.red.offset = %3d .length = %3d\n"
" vi.green.offset = %3d .length = %3d\n"
" vi.blue.offset = %3d .length = %3d\n",
vi.bits_per_pixel, vi.red.offset, vi.red.length, vi.green.offset, vi.green.length,
vi.blue.offset, vi.blue.length);
void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (bits == MAP_FAILED) {
perror("failed to mmap framebuffer");
close(fd);
return nullptr;
}
memset(bits, 0, fi.smem_len);
gr_framebuffer[0].width = vi.xres;
gr_framebuffer[0].height = vi.yres;
gr_framebuffer[0].row_bytes = fi.line_length;
gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
gr_framebuffer[0].data = static_cast<uint8_t*>(bits);
memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
/* check if we can use double buffering */
if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
double_buffered = true;
memcpy(gr_framebuffer + 1, gr_framebuffer, sizeof(GRSurface));
gr_framebuffer[1].data =
gr_framebuffer[0].data + gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
gr_draw = gr_framebuffer + 1;
} else {
double_buffered = false;
// Without double-buffering, we allocate RAM for a buffer to
// draw in, and then "flipping" the buffer consists of a
// memcpy from the buffer we allocated to the framebuffer.
gr_draw = static_cast<GRSurface*>(malloc(sizeof(GRSurface)));
memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
gr_draw->data = static_cast<unsigned char*>(malloc(gr_draw->height * gr_draw->row_bytes));
if (!gr_draw->data) {
perror("failed to allocate in-memory surface");
return nullptr;
}
}
fb_fix_screeninfo fi;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
close(fd);
return NULL;
}
memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
fb_fd = fd;
SetDisplayedFramebuffer(0);
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
perror("failed to get fb0 info");
close(fd);
return NULL;
}
printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
// We print this out for informational purposes only, but
// throughout we assume that the framebuffer device uses an RGBX
// pixel format. This is the case for every development device I
// have access to. For some of those devices (eg, hammerhead aka
// Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
// different format (XBGR) but actually produces the correct
// results on the display when you write RGBX.
//
// If you have a device that actually *needs* another pixel format
// (ie, BGRX, or 565), patches welcome...
Blank(true);
Blank(false);
printf("fb0 reports (possibly inaccurate):\n"
" vi.bits_per_pixel = %d\n"
" vi.red.offset = %3d .length = %3d\n"
" vi.green.offset = %3d .length = %3d\n"
" vi.blue.offset = %3d .length = %3d\n",
vi.bits_per_pixel,
vi.red.offset, vi.red.length,
vi.green.offset, vi.green.length,
vi.blue.offset, vi.blue.length);
void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (bits == MAP_FAILED) {
perror("failed to mmap framebuffer");
close(fd);
return NULL;
}
memset(bits, 0, fi.smem_len);
gr_framebuffer[0].width = vi.xres;
gr_framebuffer[0].height = vi.yres;
gr_framebuffer[0].row_bytes = fi.line_length;
gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits);
memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
/* check if we can use double buffering */
if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
double_buffered = true;
memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface));
gr_framebuffer[1].data = gr_framebuffer[0].data +
gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
gr_draw = gr_framebuffer+1;
} else {
double_buffered = false;
// Without double-buffering, we allocate RAM for a buffer to
// draw in, and then "flipping" the buffer consists of a
// memcpy from the buffer we allocated to the framebuffer.
gr_draw = (GRSurface*) malloc(sizeof(GRSurface));
memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes);
if (!gr_draw->data) {
perror("failed to allocate in-memory surface");
return NULL;
}
}
memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
fb_fd = fd;
set_displayed_framebuffer(0);
printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
fbdev_blank(backend, true);
fbdev_blank(backend, false);
return gr_draw;
return gr_draw;
}
static GRSurface* fbdev_flip(minui_backend* backend __unused) {
if (double_buffered) {
// Change gr_draw to point to the buffer currently displayed,
// then flip the driver so we're displaying the other buffer
// instead.
gr_draw = gr_framebuffer + displayed_buffer;
set_displayed_framebuffer(1-displayed_buffer);
} else {
// Copy from the in-memory surface to the framebuffer.
memcpy(gr_framebuffer[0].data, gr_draw->data,
gr_draw->height * gr_draw->row_bytes);
}
return gr_draw;
GRSurface* MinuiBackendFbdev::Flip() {
if (double_buffered) {
// Change gr_draw to point to the buffer currently displayed,
// then flip the driver so we're displaying the other buffer
// instead.
gr_draw = gr_framebuffer + displayed_buffer;
SetDisplayedFramebuffer(1 - displayed_buffer);
} else {
// Copy from the in-memory surface to the framebuffer.
memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes);
}
return gr_draw;
}
static void fbdev_exit(minui_backend* backend __unused) {
close(fb_fd);
fb_fd = -1;
MinuiBackendFbdev::~MinuiBackendFbdev() {
close(fb_fd);
fb_fd = -1;
if (!double_buffered && gr_draw) {
free(gr_draw->data);
free(gr_draw);
}
gr_draw = NULL;
if (!double_buffered && gr_draw) {
free(gr_draw->data);
free(gr_draw);
}
gr_draw = nullptr;
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2017 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 _GRAPHICS_FBDEV_H_
#define _GRAPHICS_FBDEV_H_
#include <linux/fb.h>
#include "graphics.h"
#include "minui/minui.h"
class MinuiBackendFbdev : public MinuiBackend {
public:
GRSurface* Init() override;
GRSurface* Flip() override;
void Blank(bool) override;
~MinuiBackendFbdev() override;
MinuiBackendFbdev();
private:
void SetDisplayedFramebuffer(unsigned n);
GRSurface gr_framebuffer[2];
bool double_buffered;
GRSurface* gr_draw;
int displayed_buffer;
fb_var_screeninfo vi;
int fb_fd;
};
#endif // _GRAPHICS_FBDEV_H_
+60 -92
View File
@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include "graphics_overlay.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -34,50 +36,28 @@
#ifdef MSM_BSP
#include <linux/msm_mdp.h>
#include <linux/msm_ion.h>
#else
#define MSMFB_NEW_REQUEST 0
#endif
#include "minui.h"
#include "graphics.h"
#include "minui/minui.h"
#define MDP_V4_0 400
#define MAX_DISPLAY_DIM 2048
static GRSurface* overlay_init(minui_backend*);
static GRSurface* overlay_flip(minui_backend*);
static void overlay_blank(minui_backend*, bool);
static void overlay_exit(minui_backend*);
static GRSurface gr_framebuffer[2];
static bool double_buffered;
static GRSurface* gr_draw = NULL;
static int displayed_buffer;
static fb_var_screeninfo vi;
static int fb_fd = -1;
static bool isMDP5 = false;
static int leftSplit = 0;
static int rightSplit = 0;
#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
static size_t frame_size = 0;
MinuiBackendOverlay::MinuiBackendOverlay() :
gr_draw(nullptr),
fb_fd(-1),
isMDP5(false),
leftSplit(0),
rightSplit(0),
frame_size(0),
overlayL_id(MSMFB_NEW_REQUEST),
overlayR_id(MSMFB_NEW_REQUEST) {}
#ifdef MSM_BSP
typedef struct {
unsigned char *mem_buf;
int size;
int ion_fd;
int mem_fd;
struct ion_handle_data handle_data;
} memInfo;
//Left and right overlay id
static int overlayL_id = MSMFB_NEW_REQUEST;
static int overlayR_id = MSMFB_NEW_REQUEST;
static memInfo mem_info;
#
static int map_mdp_pixel_format()
int MinuiBackendOverlay::map_mdp_pixel_format()
{
int format = MDP_RGB_565;
#if defined(RECOVERY_BGRA)
@@ -91,66 +71,49 @@ static int map_mdp_pixel_format()
}
#endif // MSM_BSP
static minui_backend my_backend = {
.init = overlay_init,
.flip = overlay_flip,
.blank = overlay_blank,
.exit = overlay_exit,
};
bool target_has_overlay(char *version)
bool MinuiBackendOverlay::target_has_overlay()
{
int ret;
int mdp_version;
bool overlay_supported = false;
if (strlen(version) >= 8) {
if(!strncmp(version, "msmfb", strlen("msmfb"))) {
char str_ver[4];
memcpy(str_ver, version + strlen("msmfb"), 3);
str_ver[3] = '\0';
mdp_version = atoi(str_ver);
if (mdp_version >= MDP_V4_0) {
overlay_supported = true;
}
} else if (!strncmp(version, "mdssfb", strlen("mdssfb"))) {
overlay_supported = true;
isMDP5 = true;
}
}
return overlay_supported;
}
minui_backend* open_overlay() {
fb_fix_screeninfo fi;
int fd;
fd = open("/dev/graphics/fb0", O_RDWR);
if (fd < 0) {
perror("open_overlay cannot open fb0");
return NULL;
return false;
}
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
close(fd);
return NULL;
}
if (target_has_overlay(fi.id)) {
#ifdef MSM_BSP
close(fd);
return &my_backend;
#else
printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id);
#endif
return false;
}
close(fd);
return NULL;
if (strlen(fi.id) >= 8) {
if(!strncmp(fi.id, "msmfb", strlen("msmfb"))) {
char str_ver[4];
memcpy(str_ver, fi.id + strlen("msmfb"), 3);
str_ver[3] = '\0';
mdp_version = atoi(str_ver);
if (mdp_version >= MDP_V4_0) {
overlay_supported = true;
}
} else if (!strncmp(fi.id, "mdssfb", strlen("mdssfb"))) {
overlay_supported = true;
isMDP5 = true;
}
}
#ifndef MSM_BSP
if (overlay_supported)
printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id);
#endif
return overlay_supported;
}
static void overlay_blank(minui_backend* backend __unused, bool blank)
void MinuiBackendOverlay::Blank(bool blank)
{
#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
int fd;
@@ -173,7 +136,7 @@ static void overlay_blank(minui_backend* backend __unused, bool blank)
#endif
}
static void set_displayed_framebuffer(unsigned n)
void MinuiBackendOverlay::SetDisplayedFramebuffer(unsigned n)
{
if (n > 1 || !double_buffered) return;
@@ -187,7 +150,7 @@ static void set_displayed_framebuffer(unsigned n)
}
#ifdef MSM_BSP
void setDisplaySplit(void) {
void MinuiBackendOverlay::setDisplaySplit(void) {
char split[64] = {0};
if (!isMDP5)
return;
@@ -209,7 +172,7 @@ void setDisplaySplit(void) {
fclose(fp);
}
int getLeftSplit(void) {
int MinuiBackendOverlay::getLeftSplit(void) {
//Default even split for all displays with high res
int lSplit = vi.xres / 2;
@@ -220,11 +183,11 @@ int getLeftSplit(void) {
return lSplit;
}
int getRightSplit(void) {
int MinuiBackendOverlay::getRightSplit(void) {
return rightSplit;
}
int free_ion_mem(void) {
int MinuiBackendOverlay::free_ion_mem(void) {
int ret = 0;
if (mem_info.mem_buf)
@@ -247,7 +210,7 @@ int free_ion_mem(void) {
return 0;
}
int alloc_ion_mem(unsigned int size)
int MinuiBackendOverlay::alloc_ion_mem(unsigned int size)
{
int result;
struct ion_fd_data fd_data;
@@ -298,7 +261,7 @@ int alloc_ion_mem(unsigned int size)
return 0;
}
bool isDisplaySplit(void) {
bool MinuiBackendOverlay::isDisplaySplit(void) {
if (vi.xres > MAX_DISPLAY_DIM)
return true;
//check if right split is set by driver
@@ -308,7 +271,7 @@ bool isDisplaySplit(void) {
return false;
}
int allocate_overlay(int fd, GRSurface gr_fb[])
int MinuiBackendOverlay::allocate_overlay(int fd, GRSurface gr_fb[])
{
int ret = 0;
@@ -407,7 +370,7 @@ int allocate_overlay(int fd, GRSurface gr_fb[])
return 0;
}
int overlay_display_frame(int fd, void* data, size_t size)
int MinuiBackendOverlay::overlay_display_frame(int fd, void* data, size_t size)
{
int ret = 0;
struct msmfb_overlay_data ovdataL, ovdataR;
@@ -480,7 +443,7 @@ int overlay_display_frame(int fd, void* data, size_t size)
return ret;
}
static GRSurface* overlay_flip(minui_backend* backend __unused) {
GRSurface* MinuiBackendOverlay::Flip() {
if (double_buffered) {
#if defined(RECOVERY_BGRA)
// In case of BGRA, do some byte swapping
@@ -507,7 +470,7 @@ static GRSurface* overlay_flip(minui_backend* backend __unused) {
return gr_draw;
}
int free_overlay(int fd)
int MinuiBackendOverlay::free_overlay(int fd)
{
int ret = 0;
struct mdp_display_commit ext_commit;
@@ -557,7 +520,10 @@ int free_overlay(int fd)
return 0;
}
static GRSurface* overlay_init(minui_backend* backend) {
GRSurface* MinuiBackendOverlay::Init() {
if (!target_has_overlay())
return NULL;
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd == -1) {
perror("cannot open fb0");
@@ -662,7 +628,7 @@ static GRSurface* overlay_init(minui_backend* backend) {
return gr_draw;
}
static void overlay_exit(minui_backend* backend __unused) {
MinuiBackendOverlay::~MinuiBackendOverlay() {
free_overlay(fb_fd);
free_ion_mem();
@@ -680,15 +646,17 @@ static void overlay_exit(minui_backend* backend __unused) {
}
}
#else // MSM_BSP
static GRSurface* overlay_flip(minui_backend* backend __unused) {
GRSurface* MinuiBackendOverlay::Flip() {
return NULL;
}
static GRSurface* overlay_init(minui_backend* backend __unused) {
GRSurface* MinuiBackendOverlay::Init() {
target_has_overlay(); // Don't care about return value, just for logging
return NULL;
}
static void overlay_exit(minui_backend* backend __unused) {
MinuiBackendOverlay::~MinuiBackendOverlay() {
return;
}
#endif // MSM_BSP
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2017 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 _GRAPHICS_OVERLAY_H_
#define _GRAPHICS_OVERLAY_H_
#include <linux/fb.h>
#include "graphics.h"
#include "minui/minui.h"
#ifdef MSM_BSP
typedef struct {
unsigned char *mem_buf;
int size;
int ion_fd;
int mem_fd;
struct ion_handle_data handle_data;
} memInfo;
#endif
class MinuiBackendOverlay : public MinuiBackend {
public:
GRSurface* Init() override;
GRSurface* Flip() override;
void Blank(bool) override;
~MinuiBackendOverlay() override;
MinuiBackendOverlay();
private:
void SetDisplayedFramebuffer(unsigned n);
bool target_has_overlay();
#ifdef MSM_BSP
int map_mdp_pixel_format();
void setDisplaySplit(void);
int getLeftSplit(void);
int getRightSplit(void);
int free_ion_mem(void);
int alloc_ion_mem(unsigned int size);
bool isDisplaySplit(void);
int allocate_overlay(int fd, GRSurface gr_fb[]);
int overlay_display_frame(int fd, void* data, size_t size);
int free_overlay(int fd);
#endif
GRSurface gr_framebuffer[2];
bool double_buffered;
GRSurface* gr_draw;
int displayed_buffer;
fb_var_screeninfo vi;
int fb_fd;
bool isMDP5;
int leftSplit;
int rightSplit;
size_t frame_size;
int overlayL_id;
int overlayR_id;
};
#endif // _GRAPHICS_OVERLAY_H_
+246
View File
@@ -0,0 +1,246 @@
/*
* 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 _MINUI_H_
#define _MINUI_H_
#ifndef TW_USE_MINUI_21
#include <sys/types.h>
#include <functional>
#include <string>
//
// Graphics.
//
struct GRSurface {
int width;
int height;
int row_bytes;
int pixel_bytes;
unsigned char* data;
};
struct GRFont {
GRSurface* texture;
int char_width;
int char_height;
};
int gr_init();
void gr_exit();
int gr_fb_width();
int gr_fb_height();
void gr_flip();
void gr_fb_blank(bool blank);
void gr_clear(); // clear entire surface to current color
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void gr_fill(int x1, int y1, int x2, int y2);
void gr_texticon(int x, int y, GRSurface* icon);
#ifdef TW_NO_MINUI_CUSTOM_FONTS
void gr_text(int x, int y, const char *s, bool bold);
int gr_measure(const char *s);
void gr_font_size(int *x, int *y);
void gr_set_font(__attribute__ ((unused))const char* name);
#else
const GRFont* gr_sys_font();
int gr_init_font(const char* name, GRFont** dest);
void gr_text(const GRFont* font, int x, int y, const char *s, bool bold);
int gr_measure(const GRFont* font, const char *s);
void gr_font_size(const GRFont* font, int *x, int *y);
#endif
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
unsigned int gr_get_width(GRSurface* surface);
unsigned int gr_get_height(GRSurface* surface);
//
// Input events.
//
struct input_event;
#ifdef TW_USE_MINUI_WITH_DATA
typedef int (*ev_callback)(int fd, uint32_t epevents, void* data);
typedef int (*ev_set_key_callback)(int code, int value, void* data);
int ev_init(ev_callback input_cb, void* data);
int ev_add_fd(int fd, ev_callback cb, void* data);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
#else
using ev_callback = std::function<int(int fd, uint32_t epevents)>;
using ev_set_key_callback = std::function<int(int code, int value)>;
int ev_init(ev_callback input_cb);
int ev_add_fd(int fd, ev_callback cb);
int ev_sync_key_state(const ev_set_key_callback& set_key_cb);
#endif
void ev_exit();
void ev_iterate_available_keys(const std::function<void(int)>& f);
// 'timeout' has the same semantics as poll(2).
// 0 : don't block
// < 0 : block forever
// > 0 : block for 'timeout' milliseconds
int ev_wait(int timeout);
int ev_get_input(int fd, uint32_t epevents, input_event* ev);
void ev_dispatch();
int ev_get_epollfd();
//
// Resources
//
bool matches_locale(const std::string& prefix, const std::string& locale);
// res_create_*_surface() functions return 0 if no error, else
// negative.
//
// A "display" surface is one that is intended to be drawn to the
// screen with gr_blit(). An "alpha" surface is a grayscale image
// interpreted as an alpha mask used to render text in the current
// color (with gr_text() or gr_texticon()).
//
// All these functions load PNG images from "/res/images/${name}.png".
// Load a single display surface from a PNG image.
int res_create_display_surface(const char* name, GRSurface** pSurface);
// Load an array of display surfaces from a single PNG image. The PNG
// should have a 'Frames' text chunk whose value is the number of
// frames this image represents. The pixel data itself is interlaced
// by row.
int res_create_multi_display_surface(const char* name, int* frames,
int* fps, GRSurface*** pSurface);
int res_create_multi_display_surface(const char* name, int* frames,
GRSurface*** pSurface);
// Load a single alpha surface from a grayscale PNG image.
int res_create_alpha_surface(const char* name, GRSurface** pSurface);
// Load part of a grayscale PNG image that is the first match for the
// given locale. The image is expected to be a composite of multiple
// translations of the same text, with special added rows that encode
// the subimages' size and intended locale in the pixel data. See
// bootable/recovery/tools/recovery_l10n for an app that will generate
// these specialized images from Android resources.
int res_create_localized_alpha_surface(const char* name, const char* locale,
GRSurface** pSurface);
// Free a surface allocated by any of the res_create_*_surface()
// functions.
void res_free_surface(GRSurface* surface);
#else //ifndef TW_USE_MINUI_21
// This the old minui21/minui.h for compatibility with building TWRP
// in pre 6.0 trees.
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* gr_surface;
typedef unsigned short gr_pixel;
int gr_init(void);
void gr_exit(void);
int gr_fb_width(void);
int gr_fb_height(void);
gr_pixel *gr_fb_data(void);
void gr_flip(void);
void gr_fb_blank(bool blank);
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void gr_fill(int x1, int y1, int x2, int y2);
// system/core/charger uses different gr_print signatures in diferent
// Android versions, either with or without int bold.
int gr_text(int x, int y, const char *s, ...);
int gr_text_impl(int x, int y, const char *s, int bold);
void gr_texticon(int x, int y, gr_surface icon);
int gr_measure(const char *s);
void gr_font_size(int *x, int *y);
void gr_get_memory_surface(gr_surface);
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);
unsigned int gr_get_width(gr_surface surface);
unsigned int gr_get_height(gr_surface surface);
// input event structure, include <linux/input.h> for the definition.
// see http://www.mjmwired.net/kernel/Documentation/input/ for info.
struct input_event;
typedef int (*ev_callback)(int fd, uint32_t epevents, void *data);
typedef int (*ev_set_key_callback)(int code, int value, void *data);
int ev_init(ev_callback input_cb, void *data);
void ev_exit(void);
int ev_add_fd(int fd, ev_callback cb, void *data);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data);
/* timeout has the same semantics as for poll
* 0 : don't block
* < 0 : block forever
* > 0 : block for 'timeout' milliseconds
*/
int ev_wait(int timeout);
int ev_get_input(int fd, uint32_t epevents, struct input_event *ev);
void ev_dispatch(void);
int ev_get_epollfd(void);
// Resources
// Returns 0 if no error, else negative.
int res_create_surface(const char* name, gr_surface* pSurface);
// Load an array of display surfaces from a single PNG image. The PNG
// should have a 'Frames' text chunk whose value is the number of
// frames this image represents. The pixel data itself is interlaced
// by row.
int res_create_multi_display_surface(const char* name,
int* frames, gr_surface** pSurface);
int res_create_localized_surface(const char* name, gr_surface* pSurface);
void res_free_surface(gr_surface surface);
static inline int res_create_display_surface(const char* name, gr_surface* pSurface) {
return res_create_surface(name, pSurface);
}
// These are new graphics functions from 5.0 that were not available in
// 4.4 that are required by charger and healthd
void gr_clear();
#ifdef __cplusplus
}
#endif
#endif // ifndef TW_USE_MINUI_21
#endif // ifndef _MINUI_H_
+1 -1
View File
@@ -15,7 +15,7 @@
#include <time.h>
#include "minui.h"
#include <minui/minui.h>
#include "graphics.h"
int main() {
+15 -6
View File
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <functional>
#include <string>
//
// Graphics.
@@ -79,15 +80,23 @@ unsigned int gr_get_height(GRSurface* surface);
struct input_event;
// TODO: move these over to std::function.
#ifdef TW_USE_MINUI_WITH_DATA
typedef int (*ev_callback)(int fd, uint32_t epevents, void* data);
typedef int (*ev_set_key_callback)(int code, int value, void* data);
int ev_init(ev_callback input_cb, void* data);
void ev_exit();
int ev_add_fd(int fd, ev_callback cb, void* data);
void ev_iterate_available_keys(std::function<void(int)> f);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
#else
using ev_callback = std::function<int(int fd, uint32_t epevents)>;
using ev_set_key_callback = std::function<int(int code, int value)>;
int ev_init(ev_callback input_cb);
int ev_add_fd(int fd, ev_callback cb);
int ev_sync_key_state(const ev_set_key_callback& set_key_cb);
#endif
void ev_exit();
void ev_iterate_available_keys(const std::function<void(int)>& f);
// 'timeout' has the same semantics as poll(2).
// 0 : don't block
@@ -103,7 +112,7 @@ int ev_get_epollfd();
// Resources
//
bool matches_locale(const char* prefix, const char* locale);
bool matches_locale(const std::string& prefix, const std::string& locale);
// res_create_*_surface() functions return 0 if no error, else
// negative.
@@ -134,8 +143,8 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface);
// given locale. The image is expected to be a composite of multiple
// translations of the same text, with special added rows that encode
// the subimages' size and intended locale in the pixel data. See
// development/tools/recovery_l10n for an app that will generate these
// specialized images from Android resources.
// bootable/recovery/tools/recovery_l10n for an app that will generate
// these specialized images from Android resources.
int res_create_localized_alpha_surface(const char* name, const char* locale,
GRSurface** pSurface);
+45 -35
View File
@@ -14,29 +14,31 @@
* limitations under the License.
*/
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <regex>
#include <string>
#include <vector>
//#include <android-base/strings.h> // does not exist in 6.0
#include <png.h>
#include "minui.h"
#include "minui/minui.h"
#define SURFACE_DATA_ALIGNMENT 8
static GRSurface* malloc_surface(size_t data_size) {
size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT;
unsigned char* temp = reinterpret_cast<unsigned char*>(malloc(size));
unsigned char* temp = static_cast<unsigned char*>(malloc(size));
if (temp == NULL) return NULL;
GRSurface* surface = reinterpret_cast<GRSurface*>(temp);
surface->data = temp + sizeof(GRSurface) +
@@ -220,7 +222,7 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) {
png_set_bgr(png_ptr);
#endif
p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
p_row = static_cast<unsigned char*>(malloc(width * 4));
for (y = 0; y < height; ++y) {
png_read_row(png_ptr, p_row, NULL);
transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
@@ -280,7 +282,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
goto exit;
}
surface = reinterpret_cast<GRSurface**>(malloc(*frames * sizeof(GRSurface*)));
surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
if (surface == NULL) {
result = -8;
goto exit;
@@ -297,7 +299,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
png_set_bgr(png_ptr);
#endif
p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
p_row = static_cast<unsigned char*>(malloc(width * 4));
for (y = 0; y < height; ++y) {
png_read_row(png_ptr, p_row, NULL);
int frame = y % *frames;
@@ -307,7 +309,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
}
free(p_row);
*pSurface = reinterpret_cast<GRSurface**>(surface);
*pSurface = surface;
exit:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
@@ -315,7 +317,7 @@ exit:
if (result < 0) {
if (surface) {
for (int i = 0; i < *frames; ++i) {
if (surface[i]) free(surface[i]);
free(surface[i]);
}
free(surface);
}
@@ -378,14 +380,27 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) {
// This function tests if a locale string stored in PNG (prefix) matches
// the locale string provided by the system (locale).
bool matches_locale(const char* prefix, const char* locale) {
if (locale == NULL) return false;
bool matches_locale(const std::string& prefix, const std::string& locale) {
// According to the BCP 47 format, A locale string may consists of:
// language-{extlang}-{script}-{region}-{variant}
// The locale headers in PNG mostly consist of language-{region} except for sr-Latn, and some
// android's system locale can have the format language-{script}-{region}.
// Return true if the whole string of prefix matches the top part of
// locale. For instance, prefix == "en" matches locale == "en_US";
// and prefix == "zh_CN" matches locale == "zh_CN_#Hans".
// Return true if the whole string of prefix matches the top part of locale. Otherwise try to
// match the locale string without the {script} section.
// For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale
// == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN".
//if (android::base::StartsWith(locale, prefix.c_str())) { // does not exist in 6.0
if (strncmp(prefix.c_str(), locale.c_str(), prefix.length()) == 0) {
return true;
}
return (strncmp(prefix, locale, strlen(prefix)) == 0);
size_t separator = prefix.find('-');
if (separator == std::string::npos) {
return false;
}
std::regex loc_regex(prefix.substr(0, separator) + "-[A-Za-z]*" + prefix.substr(separator));
return std::regex_match(locale, loc_regex);
}
int res_create_localized_alpha_surface(const char* name,
@@ -397,18 +412,13 @@ int res_create_localized_alpha_surface(const char* name,
png_infop info_ptr = NULL;
png_uint_32 width, height;
png_byte channels;
unsigned char* row;
png_uint_32 y;
std::vector<unsigned char> row;
*pSurface = NULL;
if (locale == NULL) {
surface = malloc_surface(0);
surface->width = 0;
surface->height = 0;
surface->row_bytes = 0;
surface->pixel_bytes = 1;
goto exit;
return result;
}
result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
@@ -419,13 +429,13 @@ int res_create_localized_alpha_surface(const char* name,
goto exit;
}
row = reinterpret_cast<unsigned char*>(malloc(width));
row.resize(width);
for (y = 0; y < height; ++y) {
png_read_row(png_ptr, row, NULL);
png_read_row(png_ptr, row.data(), NULL);
int w = (row[1] << 8) | row[0];
int h = (row[3] << 8) | row[2];
int len = row[4];
char* loc = (char*)row+5;
__unused int len = row[4];
char* loc = reinterpret_cast<char*>(&row[5]);
if (y+1+h >= height || matches_locale(loc, locale)) {
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
@@ -442,16 +452,16 @@ int res_create_localized_alpha_surface(const char* name,
int i;
for (i = 0; i < h; ++i, ++y) {
png_read_row(png_ptr, row, NULL);
memcpy(surface->data + i*w, row, w);
png_read_row(png_ptr, row.data(), NULL);
memcpy(surface->data + i*w, row.data(), w);
}
*pSurface = reinterpret_cast<GRSurface*>(surface);
*pSurface = surface;
break;
} else {
int i;
for (i = 0; i < h; ++i, ++y) {
png_read_row(png_ptr, row, NULL);
png_read_row(png_ptr, row.data(), NULL);
}
}
}
+3
View File
@@ -180,6 +180,9 @@ ifneq ($(TW_INCLUDE_JPEG),)
LOCAL_SHARED_LIBRARIES += libjpeg
endif
LOCAL_STATIC_LIBRARIES += libpixelflinger_twrp
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 25; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libcutils liblog libutils
endif
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := libminuitwrp
+89
View File
@@ -0,0 +1,89 @@
/*
* 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 "mounts.h"
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <string>
#include <vector>
struct MountedVolume {
std::string device;
std::string mount_point;
std::string filesystem;
std::string flags;
};
std::vector<MountedVolume*> g_mounts_state;
bool scan_mounted_volumes() {
for (size_t i = 0; i < g_mounts_state.size(); ++i) {
delete g_mounts_state[i];
}
g_mounts_state.clear();
// Open and read mount table entries.
FILE* fp = setmntent("/proc/mounts", "re");
if (fp == NULL) {
return false;
}
mntent* e;
while ((e = getmntent(fp)) != NULL) {
MountedVolume* v = new MountedVolume;
v->device = e->mnt_fsname;
v->mount_point = e->mnt_dir;
v->filesystem = e->mnt_type;
v->flags = e->mnt_opts;
g_mounts_state.push_back(v);
}
endmntent(fp);
return true;
}
MountedVolume* find_mounted_volume_by_device(const char* device) {
for (size_t i = 0; i < g_mounts_state.size(); ++i) {
if (g_mounts_state[i]->device == device) return g_mounts_state[i];
}
return nullptr;
}
MountedVolume* find_mounted_volume_by_mount_point(const char* mount_point) {
for (size_t i = 0; i < g_mounts_state.size(); ++i) {
if (g_mounts_state[i]->mount_point == mount_point) return g_mounts_state[i];
}
return nullptr;
}
int unmount_mounted_volume(MountedVolume* volume) {
// Intentionally pass the empty string to umount if the caller tries
// to unmount a volume they already unmounted using this
// function.
std::string mount_point = volume->mount_point;
volume->mount_point.clear();
return umount(mount_point.c_str());
}
int remount_read_only(MountedVolume* volume) {
return mount(volume->device.c_str(), volume->mount_point.c_str(), volume->filesystem.c_str(),
MS_NOATIME | MS_NODEV | MS_NODIRATIME | MS_RDONLY | MS_REMOUNT, 0);
}
+9 -15
View File
@@ -14,25 +14,19 @@
* limitations under the License.
*/
#ifndef MTDUTILS_MOUNTS_H_
#define MTDUTILS_MOUNTS_H_
#ifndef MOUNTS_H_
#define MOUNTS_H_
typedef struct {
const char *device;
const char *mount_point;
const char *filesystem;
const char *flags;
} MountedVolume;
struct MountedVolume;
int scan_mounted_volumes(void);
bool scan_mounted_volumes();
const MountedVolume *find_mounted_volume_by_device(const char *device);
MountedVolume* find_mounted_volume_by_device(const char* device);
const MountedVolume *
find_mounted_volume_by_mount_point(const char *mount_point);
MountedVolume* find_mounted_volume_by_mount_point(const char* mount_point);
int unmount_mounted_volume(const MountedVolume *volume);
int unmount_mounted_volume(MountedVolume* volume);
int remount_read_only(const MountedVolume* volume);
int remount_read_only(MountedVolume* volume);
#endif // MTDUTILS_MOUNTS_H_
#endif
+38
View File
@@ -0,0 +1,38 @@
/*
* 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 MTDUTILS_MOUNTS_H_
#define MTDUTILS_MOUNTS_H_
typedef struct {
const char *device;
const char *mount_point;
const char *filesystem;
const char *flags;
} MountedVolume;
int scan_mounted_volumes(void);
const MountedVolume *find_mounted_volume_by_device(const char *device);
const MountedVolume *
find_mounted_volume_by_mount_point(const char *mount_point);
int unmount_mounted_volume(const MountedVolume *volume);
int remount_read_only(const MountedVolume* volume);
#endif // MTDUTILS_MOUNTS_H_
-143
View File
@@ -1,143 +0,0 @@
/*
* Copyright (C) 2008 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cutils/log.h"
#include "mtdutils.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "flash_image"
#define HEADER_SIZE 2048 // size of header to compare for equality
void die(const char *msg, ...) {
int err = errno;
va_list args;
va_start(args, msg);
char buf[1024];
vsnprintf(buf, sizeof(buf), msg, args);
va_end(args);
if (err != 0) {
strlcat(buf, ": ", sizeof(buf));
strlcat(buf, strerror(err), sizeof(buf));
}
fprintf(stderr, "%s\n", buf);
ALOGE("%s\n", buf);
exit(1);
}
/* Read an image file and write it to a flash partition. */
int main(int argc, char **argv) {
const MtdPartition *ptn;
MtdWriteContext *write;
void *data;
unsigned sz;
if (argc != 3) {
fprintf(stderr, "usage: %s partition file.img\n", argv[0]);
return 2;
}
if (mtd_scan_partitions() <= 0) die("error scanning partitions");
const MtdPartition *partition = mtd_find_partition_by_name(argv[1]);
if (partition == NULL) die("can't find %s partition", argv[1]);
// If the first part of the file matches the partition, skip writing
int fd = open(argv[2], O_RDONLY);
if (fd < 0) die("error opening %s", argv[2]);
char header[HEADER_SIZE];
int headerlen = TEMP_FAILURE_RETRY(read(fd, header, sizeof(header)));
if (headerlen <= 0) die("error reading %s header", argv[2]);
MtdReadContext *in = mtd_read_partition(partition);
if (in == NULL) {
ALOGW("error opening %s: %s\n", argv[1], strerror(errno));
// just assume it needs re-writing
} else {
char check[HEADER_SIZE];
int checklen = mtd_read_data(in, check, sizeof(check));
if (checklen <= 0) {
ALOGW("error reading %s: %s\n", argv[1], strerror(errno));
// just assume it needs re-writing
} else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
ALOGI("header is the same, not flashing %s\n", argv[1]);
return 0;
}
mtd_read_close(in);
}
// Skip the header (we'll come back to it), write everything else
ALOGI("flashing %s from %s\n", argv[1], argv[2]);
MtdWriteContext *out = mtd_write_partition(partition);
if (out == NULL) die("error writing %s", argv[1]);
char buf[HEADER_SIZE];
memset(buf, 0, headerlen);
int wrote = mtd_write_data(out, buf, headerlen);
if (wrote != headerlen) die("error writing %s", argv[1]);
int len;
while ((len = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) {
wrote = mtd_write_data(out, buf, len);
if (wrote != len) die("error writing %s", argv[1]);
}
if (len < 0) die("error reading %s", argv[2]);
if (mtd_write_close(out)) die("error closing %s", argv[1]);
// Now come back and write the header last
out = mtd_write_partition(partition);
if (out == NULL) die("error re-opening %s", argv[1]);
wrote = mtd_write_data(out, header, headerlen);
if (wrote != headerlen) die("error re-writing %s", argv[1]);
// Need to write a complete block, so write the rest of the first block
size_t block_size;
if (mtd_partition_info(partition, NULL, &block_size, NULL))
die("error getting %s block size", argv[1]);
if (TEMP_FAILURE_RETRY(lseek(fd, headerlen, SEEK_SET)) != headerlen)
die("error rewinding %s", argv[2]);
int left = block_size - headerlen;
while (left < 0) left += block_size;
while (left > 0) {
len = TEMP_FAILURE_RETRY(read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left));
if (len <= 0) die("error reading %s", argv[2]);
if (mtd_write_data(out, buf, len) != len)
die("error writing %s", argv[1]);
left -= len;
}
if (mtd_write_close(out)) die("error closing %s", argv[1]);
return 0;
}
+6 -9
View File
@@ -17,11 +17,12 @@
#ifndef MTDUTILS_MOUNTS_H_
#define MTDUTILS_MOUNTS_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct MountedVolume MountedVolume;
typedef struct {
const char *device;
const char *mount_point;
const char *filesystem;
const char *flags;
} MountedVolume;
int scan_mounted_volumes(void);
@@ -34,8 +35,4 @@ int unmount_mounted_volume(const MountedVolume *volume);
int remount_read_only(const MountedVolume* volume);
#ifdef __cplusplus
}
#endif
#endif // MTDUTILS_MOUNTS_H_
+1 -2
View File
@@ -52,11 +52,10 @@
#include "gui/pages.hpp"
#include "orscmd/orscmd.h"
#include "adbbu/libtwadbbu.hpp"
#include "twinstall.h"
extern "C" {
#include "twinstall.h"
#include "gui/gui.h"
#include "cutils/properties.h"
int TWinstall_zip(const char* path, int* wipe_cache);
}
OpenRecoveryScript::VoidFunction OpenRecoveryScript::call_after_cli_command;
+8 -3
View File
@@ -23,11 +23,13 @@ endif
include $(CLEAR_VARS)
otafault_static_libs := \
libbase \
libminzip \
libziparchive \
libz \
libselinux
libselinux \
libbase \
liblog
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := config.cpp ota_io.cpp
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := libotafault
@@ -38,12 +40,15 @@ LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs)
include $(BUILD_STATIC_LIBRARY)
# otafault_test (static executable)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := otafault_test
LOCAL_STATIC_LIBRARIES := $(otafault_static_libs)
LOCAL_CFLAGS := -Werror
LOCAL_C_INCLUDES := $(RECOVERY_PATH)
LOCAL_FORCE_STATIC_EXECUTABLE := true
+15 -9
View File
@@ -21,38 +21,42 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
#include <ziparchive/zip_archive.h>
#include "minzip/Zip.h"
#include "config.h"
#include "ota_io.h"
#define OTAIO_MAX_FNAME_SIZE 128
static ZipArchive* archive;
static ZipArchiveHandle archive;
static bool is_retry = false;
static std::map<std::string, bool> should_inject_cache;
static std::string get_type_path(const char* io_type) {
return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type);
}
void ota_io_init(ZipArchive* za) {
void ota_io_init(ZipArchiveHandle za, bool retry) {
archive = za;
is_retry = retry;
ota_set_fault_files();
}
bool should_fault_inject(const char* io_type) {
// archive will be NULL if we used an entry point other
// than updater/updater.cpp:main
if (archive == NULL) {
if (archive == nullptr || is_retry) {
return false;
}
const std::string type_path = get_type_path(io_type);
if (should_inject_cache.find(type_path) != should_inject_cache.end()) {
return should_inject_cache[type_path];
}
const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
should_inject_cache[type_path] = entry != nullptr;
return entry != NULL;
ZipString zip_type_path(type_path.c_str());
ZipEntry entry;
int status = FindEntry(archive, zip_type_path, &entry);
should_inject_cache[type_path] = (status == 0);
return (status == 0);
}
bool should_hit_cache() {
@@ -63,7 +67,9 @@ std::string fault_fname(const char* io_type) {
std::string type_path = get_type_path(io_type);
std::string fname;
fname.resize(OTAIO_MAX_FNAME_SIZE);
const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
mzReadZipEntry(archive, entry, &fname[0], OTAIO_MAX_FNAME_SIZE);
ZipString zip_type_path(type_path.c_str());
ZipEntry entry;
int status = FindEntry(archive, zip_type_path, &entry);
ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(&fname[0]), OTAIO_MAX_FNAME_SIZE);
return fname;
}
+2 -2
View File
@@ -41,7 +41,7 @@
#include <stdbool.h>
#include "minzip/Zip.h"
#include <ziparchive/zip_archive.h>
#define OTAIO_BASE_DIR ".libotafault"
#define OTAIO_READ "READ"
@@ -52,7 +52,7 @@
/*
* Initialize libotafault by providing a reference to the OTA package.
*/
void ota_io_init(ZipArchive* za);
void ota_io_init(ZipArchiveHandle zip, bool retry);
/*
* Return true if a config file is present for the given IO type.
+25 -6
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
#include <map>
#include "ota_io.h"
#include <errno.h>
#include <fcntl.h>
@@ -22,15 +22,17 @@
#include <sys/stat.h>
#include <unistd.h>
#include <map>
#include <memory>
#include "config.h"
#include "ota_io.h"
static std::map<intptr_t, const char*> filename_cache;
static std::string read_fault_file_name = "";
static std::string write_fault_file_name = "";
static std::string fsync_fault_file_name = "";
static bool get_hit_file(const char* cached_path, std::string ffn) {
static bool get_hit_file(const char* cached_path, const std::string& ffn) {
return should_hit_cache()
? !strncmp(cached_path, OTAIO_CACHE_FNAME, strlen(cached_path))
: !strncmp(cached_path, ffn.c_str(), strlen(cached_path));
@@ -68,17 +70,33 @@ FILE* ota_fopen(const char* path, const char* mode) {
return fh;
}
int ota_close(int fd) {
static int __ota_close(int fd) {
// descriptors can be reused, so make sure not to leave them in the cache
filename_cache.erase(fd);
return close(fd);
}
int ota_fclose(FILE* fh) {
filename_cache.erase((intptr_t)fh);
void OtaCloser::Close(int fd) {
__ota_close(fd);
}
int ota_close(unique_fd& fd) {
return __ota_close(fd.release());
}
static int __ota_fclose(FILE* fh) {
filename_cache.erase(reinterpret_cast<intptr_t>(fh));
return fclose(fh);
}
void OtaFcloser::operator()(FILE* f) const {
__ota_fclose(f);
};
int ota_fclose(unique_file& fh) {
return __ota_fclose(fh.release());
}
size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
if (should_fault_inject(OTAIO_READ)) {
auto cached = filename_cache.find((intptr_t)stream);
@@ -92,6 +110,7 @@ size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
}
}
size_t status = fread(ptr, size, nitems, stream);
// If I/O error occurs, set the retry-update flag.
if (status != nitems && errno == EIO) {
have_eio_error = true;
}
+20 -4
View File
@@ -26,6 +26,10 @@
#include <stdio.h>
#include <sys/stat.h>
#include <memory>
#include <android-base/unique_fd.h>
#define OTAIO_CACHE_FNAME "/cache/saved.file"
void ota_set_fault_files();
@@ -36,10 +40,6 @@ int ota_open(const char* path, int oflags, mode_t mode);
FILE* ota_fopen(const char* filename, const char* mode);
int ota_close(int fd);
int ota_fclose(FILE* fh);
size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream);
ssize_t ota_read(int fd, void* buf, size_t nbyte);
@@ -50,4 +50,20 @@ ssize_t ota_write(int fd, const void* buf, size_t nbyte);
int ota_fsync(int fd);
struct OtaCloser {
static void Close(int);
};
using unique_fd = android::base::unique_fd_impl<OtaCloser>;
int ota_close(unique_fd& fd);
struct OtaFcloser {
void operator()(FILE*) const;
};
using unique_file = std::unique_ptr<FILE, OtaFcloser>;
int ota_fclose(unique_file& fh);
#endif
+33
View File
@@ -0,0 +1,33 @@
# Copyright (C) 2016 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
SysUtil.cpp \
DirUtil.cpp \
ZipUtil.cpp \
ThermalUtil.cpp
LOCAL_STATIC_LIBRARIES := \
libselinux \
libbase
LOCAL_MODULE := libotautil
LOCAL_CFLAGS := \
-Werror \
-Wall
include $(BUILD_STATIC_LIBRARY)
+218
View File
@@ -0,0 +1,218 @@
/*
* 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 "DirUtil.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <string>
#include <selinux/label.h>
#include <selinux/selinux.h>
typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus;
static DirStatus
getPathDirStatus(const char *path)
{
struct stat st;
int err;
err = stat(path, &st);
if (err == 0) {
/* Something's there; make sure it's a directory.
*/
if (S_ISDIR(st.st_mode)) {
return DDIR;
}
errno = ENOTDIR;
return DILLEGAL;
} else if (errno != ENOENT) {
/* Something went wrong, or something in the path
* is bad. Can't do anything in this situation.
*/
return DILLEGAL;
}
return DMISSING;
}
int
dirCreateHierarchy(const char *path, int mode,
const struct utimbuf *timestamp, bool stripFileName,
struct selabel_handle *sehnd)
{
DirStatus ds;
/* Check for an empty string before we bother
* making any syscalls.
*/
if (path[0] == '\0') {
errno = ENOENT;
return -1;
}
// Allocate a path that we can modify; stick a slash on
// the end to make things easier.
std::string cpath = path;
if (stripFileName) {
// Strip everything after the last slash.
size_t pos = cpath.rfind('/');
if (pos == std::string::npos) {
errno = ENOENT;
return -1;
}
cpath.resize(pos + 1);
} else {
// Make sure that the path ends in a slash.
cpath.push_back('/');
}
/* See if it already exists.
*/
ds = getPathDirStatus(cpath.c_str());
if (ds == DDIR) {
return 0;
} else if (ds == DILLEGAL) {
return -1;
}
/* Walk up the path from the root and make each level.
* If a directory already exists, no big deal.
*/
const char *path_start = &cpath[0];
char *p = &cpath[0];
while (*p != '\0') {
/* Skip any slashes, watching out for the end of the string.
*/
while (*p != '\0' && *p == '/') {
p++;
}
if (*p == '\0') {
break;
}
/* Find the end of the next path component.
* We know that we'll see a slash before the NUL,
* because we added it, above.
*/
while (*p != '/') {
p++;
}
*p = '\0';
/* Check this part of the path and make a new directory
* if necessary.
*/
ds = getPathDirStatus(path_start);
if (ds == DILLEGAL) {
/* Could happen if some other process/thread is
* messing with the filesystem.
*/
return -1;
} else if (ds == DMISSING) {
int err;
char *secontext = NULL;
if (sehnd) {
selabel_lookup(sehnd, &secontext, path_start, mode);
setfscreatecon(secontext);
}
err = mkdir(path_start, mode);
if (secontext) {
freecon(secontext);
setfscreatecon(NULL);
}
if (err != 0) {
return -1;
}
if (timestamp != NULL && utime(path_start, timestamp)) {
return -1;
}
}
// else, this directory already exists.
// Repair the path and continue.
*p = '/';
}
return 0;
}
int
dirUnlinkHierarchy(const char *path)
{
struct stat st;
DIR *dir;
struct dirent *de;
int fail = 0;
/* is it a file or directory? */
if (lstat(path, &st) < 0) {
return -1;
}
/* a file, so unlink it */
if (!S_ISDIR(st.st_mode)) {
return unlink(path);
}
/* a directory, so open handle */
dir = opendir(path);
if (dir == NULL) {
return -1;
}
/* recurse over components */
errno = 0;
while ((de = readdir(dir)) != NULL) {
//TODO: don't blow the stack
char dn[PATH_MAX];
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
continue;
}
snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name);
if (dirUnlinkHierarchy(dn) < 0) {
fail = 1;
break;
}
errno = 0;
}
/* in case readdir or unlink_recursive failed */
if (fail || errno < 0) {
int save = errno;
closedir(dir);
errno = save;
return -1;
}
/* close directory handle */
if (closedir(dir) < 0) {
return -1;
}
/* delete target directory */
return rmdir(path);
}
+54
View File
@@ -0,0 +1,54 @@
/*
* 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 MINZIP_DIRUTIL_H_
#define MINZIP_DIRUTIL_H_
#include <stdbool.h>
#include <utime.h>
#ifdef __cplusplus
extern "C" {
#endif
struct selabel_handle;
/* Like "mkdir -p", try to guarantee that all directories
* specified in path are present, creating as many directories
* as necessary. The specified mode is passed to all mkdir
* calls; no modifications are made to umask.
*
* If stripFileName is set, everything after the final '/'
* is stripped before creating the directory hierarchy.
*
* If timestamp is non-NULL, new directories will be timestamped accordingly.
*
* Returns 0 on success; returns -1 (and sets errno) on failure
* (usually if some element of path is not a directory).
*/
int dirCreateHierarchy(const char *path, int mode,
const struct utimbuf *timestamp, bool stripFileName,
struct selabel_handle* sehnd);
/* rm -rf <path>
*/
int dirUnlinkHierarchy(const char *path);
#ifdef __cplusplus
}
#endif
#endif // MINZIP_DIRUTIL_H_
+212
View File
@@ -0,0 +1,212 @@
/*
* Copyright 2006 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 "SysUtil.h"
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <algorithm>
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
static bool sysMapFD(int fd, MemMapping* pMap) {
CHECK(pMap != nullptr);
struct stat sb;
if (fstat(fd, &sb) == -1) {
PLOG(ERROR) << "fstat(" << fd << ") failed";
return false;
}
void* memPtr = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (memPtr == MAP_FAILED) {
PLOG(ERROR) << "mmap(" << sb.st_size << ", R, PRIVATE, " << fd << ", 0) failed";
return false;
}
pMap->addr = static_cast<unsigned char*>(memPtr);
pMap->length = sb.st_size;
pMap->ranges.push_back({ memPtr, static_cast<size_t>(sb.st_size) });
return true;
}
// A "block map" which looks like this (from uncrypt/uncrypt.cpp):
//
// /dev/block/platform/msm_sdcc.1/by-name/userdata # block device
// 49652 4096 # file size in bytes, block size
// 3 # count of block ranges
// 1000 1008 # block range 0
// 2100 2102 # ... block range 1
// 30 33 # ... block range 2
//
// Each block range represents a half-open interval; the line "30 33"
// reprents the blocks [30, 31, 32].
static int sysMapBlockFile(const char* filename, MemMapping* pMap) {
CHECK(pMap != nullptr);
std::string content;
if (!android::base::ReadFileToString(filename, &content)) {
PLOG(ERROR) << "Failed to read " << filename;
return -1;
}
std::vector<std::string> lines = android::base::Split(android::base::Trim(content), "\n");
if (lines.size() < 4) {
LOG(ERROR) << "Block map file is too short: " << lines.size();
return -1;
}
size_t size;
unsigned int blksize;
if (sscanf(lines[1].c_str(), "%zu %u", &size, &blksize) != 2) {
LOG(ERROR) << "Failed to parse file size and block size: " << lines[1];
return -1;
}
size_t range_count;
if (sscanf(lines[2].c_str(), "%zu", &range_count) != 1) {
LOG(ERROR) << "Failed to parse block map header: " << lines[2];
return -1;
}
size_t blocks;
if (blksize != 0) {
blocks = ((size - 1) / blksize) + 1;
}
if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0 ||
lines.size() != 3 + range_count) {
LOG(ERROR) << "Invalid data in block map file: size " << size << ", blksize " << blksize
<< ", range_count " << range_count << ", lines " << lines.size();
return -1;
}
// Reserve enough contiguous address space for the whole file.
void* reserve = mmap64(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (reserve == MAP_FAILED) {
PLOG(ERROR) << "failed to reserve address space";
return -1;
}
const std::string& block_dev = lines[0];
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(block_dev.c_str(), O_RDONLY)));
if (fd == -1) {
PLOG(ERROR) << "failed to open block device " << block_dev;
munmap(reserve, blocks * blksize);
return -1;
}
pMap->ranges.resize(range_count);
unsigned char* next = static_cast<unsigned char*>(reserve);
size_t remaining_size = blocks * blksize;
bool success = true;
for (size_t i = 0; i < range_count; ++i) {
const std::string& line = lines[i + 3];
size_t start, end;
if (sscanf(line.c_str(), "%zu %zu\n", &start, &end) != 2) {
LOG(ERROR) << "failed to parse range " << i << " in block map: " << line;
success = false;
break;
}
size_t length = (end - start) * blksize;
if (end <= start || (end - start) > SIZE_MAX / blksize || length > remaining_size) {
LOG(ERROR) << "unexpected range in block map: " << start << " " << end;
success = false;
break;
}
void* addr = mmap64(next, length, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd,
static_cast<off64_t>(start) * blksize);
if (addr == MAP_FAILED) {
PLOG(ERROR) << "failed to map block " << i;
success = false;
break;
}
pMap->ranges[i].addr = addr;
pMap->ranges[i].length = length;
next += length;
remaining_size -= length;
}
if (success && remaining_size != 0) {
LOG(ERROR) << "ranges in block map are invalid: remaining_size = " << remaining_size;
success = false;
}
if (!success) {
munmap(reserve, blocks * blksize);
return -1;
}
pMap->addr = static_cast<unsigned char*>(reserve);
pMap->length = size;
LOG(INFO) << "mmapped " << range_count << " ranges";
return 0;
}
int sysMapFile(const char* fn, MemMapping* pMap) {
if (fn == nullptr || pMap == nullptr) {
LOG(ERROR) << "Invalid argument(s)";
return -1;
}
*pMap = {};
if (fn[0] == '@') {
if (sysMapBlockFile(fn + 1, pMap) != 0) {
LOG(ERROR) << "Map of '" << fn << "' failed";
return -1;
}
} else {
// This is a regular file.
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(fn, O_RDONLY)));
if (fd == -1) {
PLOG(ERROR) << "Unable to open '" << fn << "'";
return -1;
}
if (!sysMapFD(fd, pMap)) {
LOG(ERROR) << "Map of '" << fn << "' failed";
return -1;
}
}
return 0;
}
/*
* Release a memory mapping.
*/
void sysReleaseMap(MemMapping* pMap) {
std::for_each(pMap->ranges.cbegin(), pMap->ranges.cend(), [](const MappedRange& range) {
if (munmap(range.addr, range.length) == -1) {
PLOG(ERROR) << "munmap(" << range.addr << ", " << range.length << ") failed";
}
});
pMap->ranges.clear();
}
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright 2006 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 _OTAUTIL_SYSUTIL
#define _OTAUTIL_SYSUTIL
#include <sys/types.h>
#include <vector>
struct MappedRange {
void* addr;
size_t length;
};
/*
* Use this to keep track of mapped segments.
*/
struct MemMapping {
unsigned char* addr; /* start of data */
size_t length; /* length of data */
std::vector<MappedRange> ranges;
};
/*
* Map a file into a private, read-only memory segment. If 'fn'
* begins with an '@' character, it is a map of blocks to be mapped,
* otherwise it is treated as an ordinary file.
*
* On success, "pMap" is filled in, and zero is returned.
*/
int sysMapFile(const char* fn, MemMapping* pMap);
/*
* Release the pages associated with a shared memory segment.
*
* This does not free "pMap"; it just releases the memory.
*/
void sysReleaseMap(MemMapping* pMap);
#endif // _OTAUTIL_SYSUTIL
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 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 "ThermalUtil.h"
#include <dirent.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
static constexpr auto THERMAL_PREFIX = "/sys/class/thermal/";
static int thermal_filter(const dirent* de) {
if (android::base::StartsWith(de->d_name, "thermal_zone")) {
return 1;
}
return 0;
}
static std::vector<std::string> InitThermalPaths() {
dirent** namelist;
int n = scandir(THERMAL_PREFIX, &namelist, thermal_filter, alphasort);
if (n == -1) {
PLOG(ERROR) << "Failed to scandir " << THERMAL_PREFIX;
return {};
}
if (n == 0) {
LOG(ERROR) << "Failed to find CPU thermal info in " << THERMAL_PREFIX;
return {};
}
std::vector<std::string> thermal_paths;
while (n--) {
thermal_paths.push_back(THERMAL_PREFIX + std::string(namelist[n]->d_name) + "/temp");
free(namelist[n]);
}
free(namelist);
return thermal_paths;
}
int GetMaxValueFromThermalZone() {
static std::vector<std::string> thermal_paths = InitThermalPaths();
int max_temperature = -1;
for (const auto& path : thermal_paths) {
std::string content;
if (!android::base::ReadFileToString(path, &content)) {
PLOG(WARNING) << "Failed to read " << path;
continue;
}
int temperature;
if (!android::base::ParseInt(android::base::Trim(content), &temperature)) {
LOG(WARNING) << "Failed to parse integer in " << content;
continue;
}
max_temperature = std::max(temperature, max_temperature);
}
LOG(INFO) << "current maximum temperature: " << max_temperature;
return max_temperature;
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 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 OTAUTIL_THERMALUTIL_H
#define OTAUTIL_THERMALUTIL_H
// We can find the temperature reported by all sensors in /sys/class/thermal/thermal_zone*/temp.
// Their values are in millidegree Celsius; and we will log the maximum one.
int GetMaxValueFromThermalZone();
#endif // OTAUTIL_THERMALUTIL_H
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2016 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 "ZipUtil.h"
#include <errno.h>
#include <fcntl.h>
#include <utime.h>
#include <string>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
#include <ziparchive/zip_archive.h>
#include "DirUtil.h"
static constexpr mode_t UNZIP_DIRMODE = 0755;
static constexpr mode_t UNZIP_FILEMODE = 0644;
bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
const std::string& dest_path, const struct utimbuf* timestamp,
struct selabel_handle* sehnd) {
if (!zip_path.empty() && zip_path[0] == '/') {
LOG(ERROR) << "ExtractPackageRecursive(): zip_path must be a relative path " << zip_path;
return false;
}
if (dest_path.empty() || dest_path[0] != '/') {
LOG(ERROR) << "ExtractPackageRecursive(): dest_path must be an absolute path " << dest_path;
return false;
}
void* cookie;
std::string target_dir(dest_path);
if (dest_path.back() != '/') {
target_dir += '/';
}
std::string prefix_path(zip_path);
if (!zip_path.empty() && zip_path.back() != '/') {
prefix_path += '/';
}
const ZipString zip_prefix(prefix_path.c_str());
int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
if (ret != 0) {
LOG(ERROR) << "failed to start iterating zip entries.";
return false;
}
std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
ZipEntry entry;
ZipString name;
int extractCount = 0;
while (Next(cookie, &entry, &name) == 0) {
std::string entry_name(name.name, name.name + name.name_length);
CHECK_LE(prefix_path.size(), entry_name.size());
std::string path = target_dir + entry_name.substr(prefix_path.size());
// Skip dir.
if (path.back() == '/') {
continue;
}
//TODO(b/31917448) handle the symlink.
if (dirCreateHierarchy(path.c_str(), UNZIP_DIRMODE, timestamp, true, sehnd) != 0) {
LOG(ERROR) << "failed to create dir for " << path;
return false;
}
char *secontext = NULL;
if (sehnd) {
selabel_lookup(sehnd, &secontext, path.c_str(), UNZIP_FILEMODE);
setfscreatecon(secontext);
}
android::base::unique_fd fd(open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, UNZIP_FILEMODE));
if (fd == -1) {
PLOG(ERROR) << "Can't create target file \"" << path << "\"";
return false;
}
if (secontext) {
freecon(secontext);
setfscreatecon(NULL);
}
int err = ExtractEntryToFile(zip, &entry, fd);
if (err != 0) {
LOG(ERROR) << "Error extracting \"" << path << "\" : " << ErrorCodeString(err);
return false;
}
if (fsync(fd) != 0) {
PLOG(ERROR) << "Error syncing file descriptor when extracting \"" << path << "\"";
return false;
}
if (timestamp != nullptr && utime(path.c_str(), timestamp)) {
PLOG(ERROR) << "Error touching \"" << path << "\"";
return false;
}
LOG(INFO) << "Extracted file \"" << path << "\"";
++extractCount;
}
LOG(INFO) << "Extracted " << extractCount << " file(s)";
return true;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2016 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 _OTAUTIL_ZIPUTIL_H
#define _OTAUTIL_ZIPUTIL_H
#include <utime.h>
#include <string>
#include <selinux/label.h>
#include <ziparchive/zip_archive.h>
/*
* Inflate all files under zip_path to the directory specified by
* dest_path, which must exist and be a writable directory. The zip_path
* is allowed to be an empty string, in which case the whole package
* will be extracted.
*
* Directory entries are not extracted.
*
* The immediate children of zip_path will become the immediate
* children of dest_path; e.g., if the archive contains the entries
*
* a/b/c/one
* a/b/c/two
* a/b/c/d/three
*
* and ExtractPackageRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
* files will be
*
* /tmp/one
* /tmp/two
* /tmp/d/three
*
* If timestamp is non-NULL, file timestamps will be set accordingly.
*
* Returns true on success, false on failure.
*/
bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
const std::string& dest_path, const struct utimbuf* timestamp,
struct selabel_handle* sehnd);
#endif // _OTAUTIL_ZIPUTIL_H

Some files were not shown because too many files have changed in this diff Show More