Restore applypatch/updater/edify for non-A/B OTA support
Google deleted this source from bootable/recovery outright (commit c7ebad5f, "rm -rf non-AB code", 2024-04-05) — confirmed present at android-14, absent at android-16.0.0_r4. The runtime side (install.cpp's SetUpNonAbUpdateCommands) and build-side packaging (ota_from_target_files.py's GenerateNonAbOtaPackage) both survived; only the source that builds the update-binary executable itself was removed. Sourced from TeamWin's android_bootable_recovery (android-14.1), the only living copy found, with install/ZipUtil.cpp, get_args.cpp, and set_metadata.cpp intentionally left out (only wired into TeamWin's modified install.cpp, which PawletOS isn't adopting — twrpinstall carries its own independent copies). Kept as its own repo, not folded into a recovery fork, so it's buildable independent of whichever recovery UI ends up in use.
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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 <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "edify/expr.h"
|
||||
#include "otautil/error_code.h"
|
||||
#include "otautil/paths.h"
|
||||
#include "updater/blockimg.h"
|
||||
#include "updater/build_info.h"
|
||||
#include "updater/dynamic_partitions.h"
|
||||
#include "updater/install.h"
|
||||
#include "updater/simulator_runtime.h"
|
||||
#include "updater/updater.h"
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
void Usage(std::string_view name) {
|
||||
LOG(INFO) << "Usage: " << name << "[--oem_settings <oem_property_file>]"
|
||||
<< "[--skip_functions <skip_function_file>]"
|
||||
<< " --source <source_target_file>"
|
||||
<< " --ota_package <ota_package>";
|
||||
}
|
||||
|
||||
Value* SimulatorPlaceHolderFn(const char* name, State* /* state */,
|
||||
const std::vector<std::unique_ptr<Expr>>& /* argv */) {
|
||||
LOG(INFO) << "Skip function " << name << " in host simulation";
|
||||
return StringValue("t");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Write the logs to stdout.
|
||||
android::base::InitLogging(argv, &android::base::StderrLogger);
|
||||
|
||||
std::string oem_settings;
|
||||
std::string skip_function_file;
|
||||
std::string source_target_file;
|
||||
std::string package_name;
|
||||
std::string work_dir;
|
||||
bool keep_images = false;
|
||||
|
||||
constexpr struct option OPTIONS[] = {
|
||||
{ "keep_images", no_argument, nullptr, 0 },
|
||||
{ "oem_settings", required_argument, nullptr, 0 },
|
||||
{ "ota_package", required_argument, nullptr, 0 },
|
||||
{ "skip_functions", required_argument, nullptr, 0 },
|
||||
{ "source", required_argument, nullptr, 0 },
|
||||
{ "work_dir", required_argument, nullptr, 0 },
|
||||
{ nullptr, 0, nullptr, 0 },
|
||||
};
|
||||
|
||||
int arg;
|
||||
int option_index;
|
||||
while ((arg = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) {
|
||||
if (arg != 0) {
|
||||
LOG(ERROR) << "Invalid command argument";
|
||||
Usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto option_name = OPTIONS[option_index].name;
|
||||
// The same oem property file used during OTA generation. It's needed for file_getprop() to
|
||||
// return the correct value for the source build.
|
||||
if (option_name == "oem_settings"s) {
|
||||
oem_settings = optarg;
|
||||
} else if (option_name == "skip_functions"s) {
|
||||
skip_function_file = optarg;
|
||||
} else if (option_name == "source"s) {
|
||||
source_target_file = optarg;
|
||||
} else if (option_name == "ota_package"s) {
|
||||
package_name = optarg;
|
||||
} else if (option_name == "keep_images"s) {
|
||||
keep_images = true;
|
||||
} else if (option_name == "work_dir"s) {
|
||||
work_dir = optarg;
|
||||
} else {
|
||||
Usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (source_target_file.empty() || package_name.empty()) {
|
||||
Usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Configure edify's functions.
|
||||
RegisterBuiltins();
|
||||
RegisterInstallFunctions();
|
||||
RegisterBlockImageFunctions();
|
||||
RegisterDynamicPartitionsFunctions();
|
||||
|
||||
if (!skip_function_file.empty()) {
|
||||
std::string content;
|
||||
if (!android::base::ReadFileToString(skip_function_file, &content)) {
|
||||
PLOG(ERROR) << "Failed to read " << skip_function_file;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto lines = android::base::Split(content, "\n");
|
||||
for (const auto& line : lines) {
|
||||
if (line.empty() || android::base::StartsWith(line, "#")) {
|
||||
continue;
|
||||
}
|
||||
RegisterFunction(line, SimulatorPlaceHolderFn);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (work_dir.empty()) {
|
||||
work_dir = source_temp_dir.path;
|
||||
}
|
||||
|
||||
BuildInfo source_build_info(work_dir, keep_images);
|
||||
if (!source_build_info.ParseTargetFile(source_target_file, false)) {
|
||||
LOG(ERROR) << "Failed to parse the target file " << source_target_file;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!oem_settings.empty()) {
|
||||
CHECK_EQ(0, access(oem_settings.c_str(), R_OK));
|
||||
source_build_info.SetOemSettings(oem_settings);
|
||||
}
|
||||
|
||||
Updater updater(std::make_unique<SimulatorRuntime>(&source_build_info));
|
||||
if (!updater.Init(cmd_pipe.release(), package_name, false)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!updater.RunUpdate()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
LOG(INFO) << "\nscript succeeded, result: " << updater.GetResult();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user