From 42c45e2b66790a7fe97acf7a300b025d79f2aa57 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 31 Jul 2018 09:37:12 -0700 Subject: Dynamically load device-specific recovery UI lib. We used to statically link the device-specific recovery UI extension (`TARGET_RECOVERY_UI_LIB`) into `recovery`. Such a logic can't be easily migrated to Soong, as modules specified by `TARGET_RECOVERY_UI_LIB` may not be built with Soong. Instead of porting all the device-specific codes over, this CL builds and installs the UI lib as a shared library with Android.mk. `recovery` dlopen(3)'s and dlsym(3)'s `make_device` to invoke the device-specific UI lib on start. Note that in order to make dlopen(3) actually working, we have to switch `recovery` to be dynamically linked (we will make the move later anyway). Bug: 110380063 Test: Build and boot into marlin recovery image. Check that device-specific recovery UI is successfully loaded. Change-Id: Ia9861c7559a95f3f50676534540c0cb87cae4574 --- Android.mk | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++---- device.h | 4 +++ recovery_main.cpp | 28 +++++++++++++++++- tests/Android.mk | 2 +- 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/Android.mk b/Android.mk index 0540bdbc6..9542080ca 100644 --- a/Android.mk +++ b/Android.mk @@ -28,7 +28,32 @@ recovery_common_cflags := \ -Werror \ -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION) -# librecovery_ui (static library) +# librecovery_ui_ext (shared library) +# =================================== +include $(CLEAR_VARS) + +LOCAL_MODULE := librecovery_ui_ext + +# LOCAL_MODULE_PATH for shared libraries is unsupported in multiarch builds. +LOCAL_MULTILIB := first + +ifeq ($(TARGET_IS_64_BIT),true) +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib64 +else +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib +endif + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + $(TARGET_RECOVERY_UI_LIB) + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + liblog \ + librecovery_ui + +include $(BUILD_SHARED_LIBRARY) + +# librecovery_ui (shared library) # =============================== include $(CLEAR_VARS) LOCAL_SRC_FILES := \ @@ -40,21 +65,56 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := librecovery_ui +LOCAL_CFLAGS := $(recovery_common_cflags) + +LOCAL_MULTILIB := first + +ifeq ($(TARGET_IS_64_BIT),true) +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib64 +else +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/lib +endif + LOCAL_STATIC_LIBRARIES := \ libminui \ libotautil \ - libbase + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libpng \ + libz \ + +include $(BUILD_SHARED_LIBRARY) + +# librecovery_ui (static library) +# =============================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + device.cpp \ + screen_ui.cpp \ + ui.cpp \ + vr_ui.cpp \ + wear_ui.cpp + +LOCAL_MODULE := librecovery_ui LOCAL_CFLAGS := $(recovery_common_cflags) +LOCAL_STATIC_LIBRARIES := \ + libminui \ + libotautil \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libpng \ + libz \ + include $(BUILD_STATIC_LIBRARY) librecovery_static_libraries := \ - $(TARGET_RECOVERY_UI_LIB) \ libbootloader_message \ libfusesideload \ libminadbd \ - librecovery_ui \ libminui \ libverifier \ libotautil \ @@ -112,8 +172,6 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := recovery -LOCAL_FORCE_STATIC_EXECUTABLE := true - LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/bin # Cannot link with LLD: undefined symbol: UsbNoPermissionsLongHelpText @@ -124,8 +182,12 @@ LOCAL_CFLAGS := $(recovery_common_cflags) LOCAL_STATIC_LIBRARIES := \ librecovery \ + librecovery_ui_default \ $(librecovery_static_libraries) +LOCAL_SHARED_LIBRARIES := \ + librecovery_ui \ + LOCAL_HAL_STATIC_LIBRARIES := libhealthd LOCAL_REQUIRED_MODULES := \ @@ -154,6 +216,17 @@ LOCAL_REQUIRED_MODULES += \ recovery-refresh endif +LOCAL_REQUIRED_MODULES += \ + librecovery_ui_ext + +# TODO(b/110380063): Explicitly install the following shared libraries to recovery, until `recovery` +# module is built with Soong (with `recovery: true` flag). +LOCAL_REQUIRED_MODULES += \ + libbase.recovery \ + liblog.recovery \ + libpng.recovery \ + libz.recovery \ + include $(BUILD_EXECUTABLE) include \ diff --git a/device.h b/device.h index cbecc4371..a6ad62788 100644 --- a/device.h +++ b/device.h @@ -119,8 +119,12 @@ class Device { std::unique_ptr ui_; }; +// Disable name mangling, as this function will be loaded via dlsym(3). +extern "C" { + // 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 diff --git a/recovery_main.cpp b/recovery_main.cpp index c79d7d8d8..9a9890de0 100644 --- a/recovery_main.cpp +++ b/recovery_main.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -329,7 +330,32 @@ int main(int argc, char** argv) { printf("locale is [%s]\n", locale.c_str()); - Device* device = make_device(); + static constexpr const char* kDefaultLibRecoveryUIExt = "librecovery_ui_ext.so"; + // Intentionally not calling dlclose(3) to avoid potential gotchas (e.g. `make_device` may have + // handed out pointers to code or static [or thread-local] data and doesn't collect them all back + // in on dlclose). + void* librecovery_ui_ext = dlopen(kDefaultLibRecoveryUIExt, RTLD_NOW); + + using MakeDeviceType = decltype(&make_device); + MakeDeviceType make_device_func = nullptr; + if (librecovery_ui_ext == nullptr) { + printf("Failed to dlopen %s: %s\n", kDefaultLibRecoveryUIExt, dlerror()); + } else { + reinterpret_cast(make_device_func) = dlsym(librecovery_ui_ext, "make_device"); + if (make_device_func == nullptr) { + printf("Failed to dlsym make_device: %s\n", dlerror()); + } + } + + Device* device; + if (make_device_func == nullptr) { + printf("Falling back to the default make_device() instead\n"); + device = make_device(); + } else { + printf("Loading make_device from %s\n", kDefaultLibRecoveryUIExt); + device = (*make_device_func)(); + } + if (android::base::GetBoolProperty("ro.boot.quiescent", false)) { printf("Quiescent recovery mode.\n"); device->ResetUI(new StubRecoveryUI()); diff --git a/tests/Android.mk b/tests/Android.mk index e68e77eb0..58ef3a2af 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -155,10 +155,10 @@ libupdater_static_libraries := \ librecovery_static_libraries := \ librecovery \ - $(TARGET_RECOVERY_UI_LIB) \ libbootloader_message \ libfusesideload \ libminadbd \ + librecovery_ui_default \ librecovery_ui \ libminui \ libverifier \ -- cgit v1.2.3