From c1a5e26fd905df829c6e2bbc24b0500af4a5b357 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 22 May 2019 14:34:12 -0700 Subject: Implement an update simulator to verify BB OTA packages on host Implement the simulator runtime and build the updater simulator as a host executable. The code to parse the target-files and mocks the block devices will be submitted in the follow-up. Bug: 131911365 Test: unit tests pass Change-Id: Ib1ba939aec8333ca68a45139514d772ad7a27ad8 --- otautil/Android.bp | 8 +-- tests/Android.bp | 4 +- updater/Android.bp | 61 ++++++++++++++++-- updater/Android.mk | 85 +++++++++++++++++++------ updater/include/updater/simulator_runtime.h | 58 +++++++++++++++++ updater/include/updater/target_files.h | 36 +++++++++++ updater/simulator_runtime.cpp | 97 +++++++++++++++++++++++++++++ updater/target_files.cpp | 26 ++++++++ updater/update_simulator_main.cpp | 76 ++++++++++++++++++++++ updater/updater.cpp | 3 +- 10 files changed, 424 insertions(+), 30 deletions(-) create mode 100644 updater/include/updater/simulator_runtime.h create mode 100644 updater/include/updater/target_files.h create mode 100644 updater/simulator_runtime.cpp create mode 100644 updater/target_files.cpp create mode 100644 updater/update_simulator_main.cpp diff --git a/otautil/Android.bp b/otautil/Android.bp index 73398c3aa..871dcae9a 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -24,12 +24,16 @@ cc_library_static { // Minimal set of files to support host build. srcs: [ + "dirutil.cpp", "paths.cpp", "rangeset.cpp", + "sysutil.cpp", ], shared_libs: [ "libbase", + "libcutils", + "libselinux", ], export_include_dirs: [ @@ -39,12 +43,10 @@ cc_library_static { target: { android: { srcs: [ - "dirutil.cpp", "logging.cpp", "mounts.cpp", "parse_install_logs.cpp", "roots.cpp", - "sysutil.cpp", "thermalutil.cpp", ], @@ -57,10 +59,8 @@ cc_library_static { ], shared_libs: [ - "libcutils", "libext4_utils", "libfs_mgr", - "libselinux", ], export_static_lib_headers: [ diff --git a/tests/Android.bp b/tests/Android.bp index 67a65ae9e..4969c087b 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -108,6 +108,7 @@ cc_test { defaults: [ "recovery_test_defaults", "libupdater_defaults", + "libupdater_device_defaults", ], test_suites: ["device-tests"], @@ -121,7 +122,8 @@ cc_test { "libfusesideload", "libminui", "libotautil", - "libupdater", + "libupdater_device", + "libupdater_core", "libupdate_verifier", "libgtest_prod", diff --git a/updater/Android.bp b/updater/Android.bp index 72f8bc9b3..a66155b3a 100644 --- a/updater/Android.bp +++ b/updater/Android.bp @@ -30,7 +30,6 @@ cc_defaults { "libfec", "libfec_rs", "libverity_tree", - "libfs_mgr", "libgtest_prod", "liblog", "liblp", @@ -46,6 +45,14 @@ cc_defaults { "libcrypto_utils", "libcutils", "libutils", + ], +} + +cc_defaults { + name: "libupdater_device_defaults", + + static_libs: [ + "libfs_mgr", "libtune2fs", "libext2_com_err", @@ -54,11 +61,13 @@ cc_defaults { "libext2_uuid", "libext2_e2p", "libext2fs", - ], + ] } cc_library_static { - name: "libupdater", + name: "libupdater_core", + + host_supported: true, defaults: [ "recovery_defaults", @@ -68,12 +77,33 @@ cc_library_static { srcs: [ "blockimg.cpp", "commands.cpp", - "dynamic_partitions.cpp", "install.cpp", "updater.cpp", + ], + + export_include_dirs: [ + "include", + ], +} + +cc_library_static { + name: "libupdater_device", + + defaults: [ + "recovery_defaults", + "libupdater_defaults", + "libupdater_device_defaults", + ], + + srcs: [ + "dynamic_partitions.cpp", "updater_runtime.cpp", ], + static_libs: [ + "libupdater_core", + ], + include_dirs: [ "external/e2fsprogs/misc", ], @@ -82,3 +112,26 @@ cc_library_static { "include", ], } + +cc_library_host_static { + name: "libupdater_host", + + defaults: [ + "recovery_defaults", + "libupdater_defaults", + ], + + srcs: [ + "simulator_runtime.cpp", + "target_files.cpp", + ], + + static_libs: [ + "libupdater_core", + "libfstab", + ], + + export_include_dirs: [ + "include", + ], +} diff --git a/updater/Android.mk b/updater/Android.mk index 0178239e0..b8b5e5a70 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -33,7 +33,6 @@ updater_common_static_libraries := \ libfec \ libfec_rs \ libverity_tree \ - libfs_mgr \ libgtest_prod \ liblog \ liblp \ @@ -48,9 +47,24 @@ updater_common_static_libraries := \ libcrypto \ libcrypto_utils \ libcutils \ - libutils \ - libtune2fs \ - $(tune2fs_static_libraries) + libutils + + +# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function +# named "Register_()". Here we emit a little C function that +# gets #included by updater.cpp. It calls all those registration +# functions. +# $(1): the path to the register.inc file +# $(2): a list of TARGET_RECOVERY_UPDATER_LIBS +define generate-register-inc + $(hide) mkdir -p $(dir $(1)) + $(hide) echo "" > $(1) + $(hide) $(foreach lib,$(2),echo "extern void Register_$(lib)(void);" >> $(1);) + $(hide) echo "void RegisterDeviceExtensions() {" >> $(1) + $(hide) $(foreach lib,$(2),echo " Register_$(lib)();" >> $(1);) + $(hide) echo "}" >> $(1) +endef + # updater (static executable) # =============================== @@ -69,33 +83,26 @@ LOCAL_CFLAGS := \ -Werror LOCAL_STATIC_LIBRARIES := \ - libupdater \ + libupdater_device \ + libupdater_core \ $(TARGET_RECOVERY_UPDATER_LIBS) \ $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \ - $(updater_common_static_libraries) + $(updater_common_static_libraries) \ + libfs_mgr \ + libtune2fs \ + $(tune2fs_static_libraries) -# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function -# named "Register_()". Here we emit a little C function that -# gets #included by updater.c. It calls all those registration -# functions. +LOCAL_MODULE_CLASS := EXECUTABLES +inc := $(call local-generated-sources-dir)/register.inc # Devices can also add libraries to TARGET_RECOVERY_UPDATER_EXTRA_LIBS. # These libs are also linked in with updater, but we don't try to call # any sort of registration function for these. Use this variable for # any subsidiary static libraries required for your registered # extension libs. - -LOCAL_MODULE_CLASS := EXECUTABLES -inc := $(call local-generated-sources-dir)/register.inc - $(inc) : libs := $(TARGET_RECOVERY_UPDATER_LIBS) $(inc) : - $(hide) mkdir -p $(dir $@) - $(hide) echo "" > $@ - $(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@;) - $(hide) echo "void RegisterDeviceExtensions() {" >> $@ - $(hide) $(foreach lib,$(libs),echo " Register_$(lib)();" >> $@;) - $(hide) echo "}" >> $@ + $(call generate-register-inc,$@,$(libs)) LOCAL_GENERATED_SOURCES := $(inc) @@ -104,3 +111,41 @@ inc := LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_EXECUTABLE) + + +# update_host_simulator (static executable) +# =============================== +include $(CLEAR_VARS) + +LOCAL_MODULE := update_host_simulator + +LOCAL_SRC_FILES := \ + update_simulator_main.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include + +LOCAL_CFLAGS := \ + -Wall \ + -Werror + +LOCAL_STATIC_LIBRARIES := \ + libupdater_host \ + libupdater_core \ + $(TARGET_RECOVERY_UPDATER_HOST_LIBS) \ + $(TARGET_RECOVERY_UPDATER_HOST_EXTRA_LIBS) \ + $(updater_common_static_libraries) \ + libfstab + +LOCAL_MODULE_CLASS := EXECUTABLES +inc := $(call local-generated-sources-dir)/register.inc + +$(inc) : libs := $(TARGET_RECOVERY_UPDATER_HOST_LIBS) +$(inc) : + $(call generate-register-inc,$@,$(libs)) + +LOCAL_GENERATED_SOURCES := $(inc) + +inc := + +include $(BUILD_HOST_EXECUTABLE) diff --git a/updater/include/updater/simulator_runtime.h b/updater/include/updater/simulator_runtime.h new file mode 100644 index 000000000..93fa2a4e5 --- /dev/null +++ b/updater/include/updater/simulator_runtime.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "edify/updater_runtime_interface.h" +#include "updater/target_files.h" + +class SimulatorRuntime : public UpdaterRuntimeInterface { + public: + explicit SimulatorRuntime(TargetFiles* source) : source_(source) {} + + bool IsSimulator() const override { + return true; + } + + std::string GetProperty(const std::string_view key, + const std::string_view default_value) const override; + + int Mount(const std::string_view location, const std::string_view mount_point, + const std::string_view fs_type, const std::string_view mount_options) override; + bool IsMounted(const std::string_view mount_point) const override; + std::pair Unmount(const std::string_view mount_point) override; + + bool ReadFileToString(const std::string_view filename, std::string* content) const override; + bool WriteStringToFile(const std::string_view content, + const std::string_view filename) const override; + + int WipeBlockDevice(const std::string_view filename, size_t len) const override; + int RunProgram(const std::vector& args, bool is_vfork) const override; + int Tune2Fs(const std::vector& args) const override; + + private: + std::string FindBlockDeviceName(const std::string_view name) const override; + + TargetFiles* source_; + std::map> mounted_partitions_; +}; diff --git a/updater/include/updater/target_files.h b/updater/include/updater/target_files.h new file mode 100644 index 000000000..9ef1a5bf3 --- /dev/null +++ b/updater/include/updater/target_files.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include + +// This class parses a given target file for the build properties and image files. Then it creates +// and maintains the temporary files to simulate the block devices on host. +class TargetFiles { + public: + TargetFiles(std::string path, std::string work_dir) + : path_(std::move(path)), work_dir_(std::move(work_dir)) {} + + std::string GetProperty(const std::string_view key, const std::string_view default_value) const; + + std::string FindBlockDeviceName(const std::string_view name) const; + + private: + std::string path_; // Path to the target file. + + std::string work_dir_; // A temporary directory to store the extracted image files +}; diff --git a/updater/simulator_runtime.cpp b/updater/simulator_runtime.cpp new file mode 100644 index 000000000..c3b3d951c --- /dev/null +++ b/updater/simulator_runtime.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019 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 "updater/simulator_runtime.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "otautil/mounts.h" +#include "otautil/sysutil.h" + +std::string SimulatorRuntime::GetProperty(const std::string_view key, + const std::string_view default_value) const { + return source_->GetProperty(key, default_value); +} + +int SimulatorRuntime::Mount(const std::string_view location, const std::string_view mount_point, + const std::string_view /* fs_type */, + const std::string_view /* mount_options */) { + if (auto mounted_location = mounted_partitions_.find(mount_point); + mounted_location != mounted_partitions_.end() && mounted_location->second != location) { + LOG(ERROR) << mount_point << " has been mounted at " << mounted_location->second; + return -1; + } + + mounted_partitions_.emplace(mount_point, location); + return 0; +} + +bool SimulatorRuntime::IsMounted(const std::string_view mount_point) const { + return mounted_partitions_.find(mount_point) != mounted_partitions_.end(); +} + +std::pair SimulatorRuntime::Unmount(const std::string_view mount_point) { + if (!IsMounted(mount_point)) { + return { false, -1 }; + } + + mounted_partitions_.erase(std::string(mount_point)); + return { true, 0 }; +} + +std::string SimulatorRuntime::FindBlockDeviceName(const std::string_view name) const { + return source_->FindBlockDeviceName(name); +} + +// TODO(xunchang) implement the utility functions in simulator. +int SimulatorRuntime::RunProgram(const std::vector& args, bool /* is_vfork */) const { + LOG(INFO) << "Running program with args " << android::base::Join(args, " "); + return 0; +} + +int SimulatorRuntime::Tune2Fs(const std::vector& args) const { + LOG(INFO) << "Running Tune2Fs with args " << android::base::Join(args, " "); + return 0; +} + +int SimulatorRuntime::WipeBlockDevice(const std::string_view filename, size_t /* len */) const { + LOG(INFO) << "SKip wiping block device " << filename; + return 0; +} + +bool SimulatorRuntime::ReadFileToString(const std::string_view filename, + std::string* /* content */) const { + LOG(INFO) << "SKip reading filename " << filename; + return true; +} + +bool SimulatorRuntime::WriteStringToFile(const std::string_view content, + const std::string_view filename) const { + LOG(INFO) << "SKip writing " << content.size() << " bytes to file " << filename; + return true; +} diff --git a/updater/target_files.cpp b/updater/target_files.cpp new file mode 100644 index 000000000..53671dd9d --- /dev/null +++ b/updater/target_files.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 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 "updater/target_files.h" + +std::string TargetFiles::GetProperty(const std::string_view /*key*/, + const std::string_view default_value) const { + return std::string(default_value); +} + +std::string TargetFiles::FindBlockDeviceName(const std::string_view name) const { + return std::string(name); +} diff --git a/updater/update_simulator_main.cpp b/updater/update_simulator_main.cpp new file mode 100644 index 000000000..d10453c2f --- /dev/null +++ b/updater/update_simulator_main.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "otautil/error_code.h" +#include "otautil/paths.h" +#include "updater/blockimg.h" +#include "updater/install.h" +#include "updater/simulator_runtime.h" +#include "updater/target_files.h" +#include "updater/updater.h" + +int main(int argc, char** argv) { + // Write the logs to stdout. + android::base::InitLogging(argv, &android::base::StderrLogger); + + if (argc != 3 && argc != 4) { + LOG(ERROR) << "unexpected number of arguments: " << argc << std::endl + << "Usage: " << argv[0] << " "; + return 1; + } + + // TODO(xunchang) implement a commandline parser, e.g. it can take an oem property so that the + // file_getprop() will return correct value. + + std::string source_target_file = argv[1]; + std::string package_name = argv[2]; + + // Configure edify's functions. + RegisterBuiltins(); + RegisterInstallFunctions(); + RegisterBlockImageFunctions(); + + TemporaryFile temp_saved_source; + TemporaryFile temp_last_command; + TemporaryDir temp_stash_base; + + Paths::Get().set_cache_temp_source(temp_saved_source.path); + Paths::Get().set_last_command_file(temp_last_command.path); + Paths::Get().set_stash_directory_base(temp_stash_base.path); + + TemporaryFile cmd_pipe; + + TemporaryDir source_temp_dir; + TargetFiles source(source_target_file, source_temp_dir.path); + + Updater updater(std::make_unique(&source)); + if (!updater.Init(cmd_pipe.release(), package_name, false)) { + return 1; + } + + if (!updater.RunUpdate()) { + return 1; + } + + LOG(INFO) << "\nscript succeeded, result: " << updater.GetResult(); + + return 0; +} diff --git a/updater/updater.cpp b/updater/updater.cpp index 426c6dce0..8f4a6ede5 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -175,7 +175,8 @@ bool Updater::ReadEntryToString(ZipArchiveHandle za, const std::string& entry_na int extract_err = ExtractToMemory(za, &entry, reinterpret_cast(&content->at(0)), entry.uncompressed_length); if (extract_err != 0) { - LOG(ERROR) << "failed to read script from package: " << ErrorCodeString(extract_err); + LOG(ERROR) << "failed to read " << entry_name + << " from package: " << ErrorCodeString(extract_err); return false; } -- cgit v1.2.3