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
This commit is contained in:
Tao Bao 2018-07-31 09:37:12 -07:00
parent f2bc68cfe1
commit 42c45e2b66
4 changed files with 111 additions and 8 deletions

View file

@ -28,6 +28,64 @@ recovery_common_cflags := \
-Werror \
-DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
# 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 := \
device.cpp \
screen_ui.cpp \
ui.cpp \
vr_ui.cpp \
wear_ui.cpp
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 \
LOCAL_SHARED_LIBRARIES := \
libbase \
libpng \
libz \
include $(BUILD_SHARED_LIBRARY)
# librecovery_ui (static library)
# ===============================
include $(CLEAR_VARS)
@ -40,21 +98,23 @@ LOCAL_SRC_FILES := \
LOCAL_MODULE := librecovery_ui
LOCAL_CFLAGS := $(recovery_common_cflags)
LOCAL_STATIC_LIBRARIES := \
libminui \
libotautil \
libbase
LOCAL_CFLAGS := $(recovery_common_cflags)
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 \

View file

@ -119,8 +119,12 @@ class Device {
std::unique_ptr<RecoveryUI> 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

View file

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@ -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<void*&>(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());

View file

@ -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 \