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:
2026-07-11 03:21:24 -07:00
commit 042ffdb2d5
56 changed files with 12691 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
// 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.
package {
default_applicable_licenses: ["external_update_binary_edify_license"],
}
// external_update_binary is a standalone repo (not nested inside
// bootable/recovery), so this declares its own license module instead of
// depending on bootable/recovery's internal "bootable_recovery_license" name.
license {
name: "external_update_binary_edify_license",
visibility: [":__subpackages__"],
license_kinds: [
"SPDX-license-identifier-Apache-2.0",
],
license_text: [
"//external/update_binary:NOTICE",
],
}
cc_library_static {
name: "libedify",
host_supported: true,
vendor_available: true,
recovery_available: true,
srcs: [
"expr.cpp",
"lexer.ll",
"parser.yy",
],
cflags: [
"-Wall",
"-Werror",
"-Wno-deprecated-register",
"-Wno-unused-parameter",
],
export_include_dirs: [
"include",
],
local_include_dirs: [
"include",
],
static_libs: [
"libbase",
"libotautil",
],
}
+58
View File
@@ -0,0 +1,58 @@
# 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
#
# Build the host-side command line tool (host executable)
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(edify_src_files) \
edify_parser.cpp
LOCAL_CFLAGS := -Werror
LOCAL_CPPFLAGS := -g -O0
LOCAL_MODULE := edify_parser
LOCAL_YACCFLAGS := -v
LOCAL_CPPFLAGS += -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-deprecated-register
LOCAL_CLANG := true
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES += libbase
include $(BUILD_HOST_EXECUTABLE)
#
# 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
LOCAL_CLANG := true
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES += libbase
include $(BUILD_STATIC_LIBRARY)
+111
View File
@@ -0,0 +1,111 @@
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.
- The entire script is a single expression.
- All expressions are string-valued.
- String literals appear in double quotes. \n, \t, \", and \\ are
understood, as are hexadecimal escapes like \x4a.
- String literals consisting of only letters, numbers, colons,
underscores, slashes, and periods don't need to be in double quotes.
- The following words are reserved:
if then else endif
They have special meaning when unquoted. (In quotes, they are just
string literals.)
- When used as a boolean, the empty string is "false" and all other
strings are "true".
- All functions are actually macros (in the Lisp sense); the body of
the function can control which (if any) of the arguments are
evaluated. This means that functions can act as control
structures.
- Operators (like "&&" and "||") are just syntactic sugar for builtin
functions, so they can act as control structures as well.
- ";" is a binary operator; evaluating it just means to first evaluate
the left side, then the right. It can also appear after any
expression.
- Comments start with "#" and run to the end of the line.
Some examples:
- There's no distinction between quoted and unquoted strings; the
quotes are only needed if you want characters like whitespace to
appear in the string. The following expressions all evaluate to the
same string.
"a b"
a + " " + b
"a" + " " + "b"
"a\x20b"
a + "\x20b"
concat(a, " ", "b")
"concat"(a, " ", "b")
As shown in the last example, function names are just strings,
too. They must be string *literals*, however. This is not legal:
("con" + "cat")(a, " ", b) # syntax error!
- The ifelse() builtin takes three arguments: it evaluates exactly
one of the second and third, depending on whether the first one is
true. There is also some syntactic sugar to make expressions that
look like if/else statements:
# these are all equivalent
ifelse(something(), "yes", "no")
if something() then yes else no endif
if something() then "yes" else "no" endif
The else part is optional.
if something() then "yes" endif # if something() is false,
# evaluates to false
ifelse(condition(), "", abort()) # abort() only called if
# condition() is false
The last example is equivalent to:
assert(condition())
- The && and || operators can be used similarly; they evaluate their
second argument only if it's needed to determine the truth of the
expression. Their value is the value of the last-evaluated
argument:
file_exists("/data/system/bad") && delete("/data/system/bad")
file_exists("/data/system/missing") || create("/data/system/missing")
get_it() || "xxx" # returns value of get_it() if that value is
# true, otherwise returns "xxx"
- The purpose of ";" is to simulate imperative statements, of course,
but the operator can be used anywhere. Its value is the value of
its right side:
concat(a;b;c, d, e;f) # evaluates to "cdf"
A more useful example might be something like:
ifelse(condition(),
(first_step(); second_step();), # second ; is optional
alternative_procedure())
+425
View File
@@ -0,0 +1,425 @@
/*
* 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 "edify/expr.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.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 "otautil/error_code.h"
// Functions should:
//
// - return a malloc()'d string
// - if Evaluate() on any argument returns nullptr, return nullptr.
static bool BooleanString(const std::string& s) {
return !s.empty();
}
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 != Value::Type::STRING) {
ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type);
return false;
}
*result = v->data;
return true;
}
Value* EvaluateValue(State* state, const std::unique_ptr<Expr>& expr) {
return expr->fn(expr->name.c_str(), state, expr->argv);
}
Value* StringValue(const char* str) {
if (str == nullptr) {
return nullptr;
}
return new Value(Value::Type::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("");
}
std::string result;
for (size_t i = 0; i < argv.size(); ++i) {
std::string str;
if (!Evaluate(state, argv[i], &str)) {
return nullptr;
}
result += str;
}
return StringValue(result);
}
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;
}
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, 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 += "called abort()";
}
return nullptr;
}
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;
}
if (result.empty()) {
int len = argv[i]->end - argv[i]->start;
state->errmsg = "assert failed: " + state->script.substr(argv[i]->start, len);
return nullptr;
}
}
return StringValue("");
}
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;
}
sleep(v);
return StringValue(val);
}
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.c_str(), stdout);
}
return StringValue("");
}
Value* LogicalAndFn(const char* name, State* state,
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("");
}
}
Value* LogicalOrFn(const char* name, State* state,
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);
}
}
Value* LogicalNotFn(const char* name, State* state,
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,
const std::vector<std::unique_ptr<Expr>>& argv) {
std::string needle;
if (!Evaluate(state, argv[0], &needle)) {
return nullptr;
}
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, 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;
}
const char* result = (left == right) ? "t" : "";
return StringValue(result);
}
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;
}
const char* result = (left != right) ? "t" : "";
return StringValue(result);
}
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,
const std::vector<std::unique_ptr<Expr>>& argv) {
if (argv.size() != 2) {
state->errmsg = "less_than_int expects 2 arguments";
return nullptr;
}
std::vector<std::string> args;
if (!ReadArgs(state, argv, &args)) {
return nullptr;
}
// 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* GreaterThanIntFn(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv) {
if (argv.size() != 2) {
state->errmsg = "greater_than_int expects 2 arguments";
return nullptr;
}
std::vector<std::string> args;
if (!ReadArgs(state, argv, &args)) {
return nullptr;
}
// 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 std::unordered_map<std::string, Function> fn_table;
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];
}
}
void RegisterBuiltins() {
RegisterFunction("ifelse", IfElseFn);
RegisterFunction("abort", AbortFn);
RegisterFunction("assert", AssertFn);
RegisterFunction("concat", ConcatFn);
RegisterFunction("is_substring", SubstringFn);
RegisterFunction("stdout", StdoutFn);
RegisterFunction("sleep", SleepFn);
RegisterFunction("less_than_int", LessThanIntFn);
RegisterFunction("greater_than_int", GreaterThanIntFn);
}
// -----------------------------------------------------------------
// convenience methods for functions
// -----------------------------------------------------------------
// 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());
}
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;
}
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, 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());
}
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;
}
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
// *state. Returns nullptr.
Value* ErrorAbort(State* state, const char* format, ...) {
va_list ap;
va_start(ap, format);
android::base::StringAppendV(&state->errmsg, format, ap);
va_end(ap);
return nullptr;
}
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
std::string err_message;
va_list ap;
va_start(ap, format);
android::base::StringAppendV(&err_message, format, ap);
va_end(ap);
// Ensure that there's exactly one line break at the end of the error message.
state->errmsg = android::base::Trim(err_message) + "\n";
state->cause_code = cause_code;
return nullptr;
}
State::State(const std::string& script, UpdaterInterface* interface)
: script(script), updater(interface), error_code(kNoError), cause_code(kNoCause) {}
+159
View File
@@ -0,0 +1,159 @@
/*
* 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.
*/
#ifndef _EXPRESSION_H
#define _EXPRESSION_H
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include "edify/updater_interface.h"
// Forward declaration to avoid including "otautil/error_code.h".
enum ErrorCode : int;
enum CauseCode : int;
struct State {
State(const std::string& script, UpdaterInterface* cookie);
// The source of the original script.
const std::string& script;
// A pointer to app-specific data; the libedify doesn't use this value.
UpdaterInterface* updater;
// The error message (if any) returned if the evaluation aborts.
// 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.
ErrorCode error_code;
// cause code provides more detailed reason of an OTA failure (e.g. fsync error)
// in addition to the error code.
CauseCode cause_code;
bool is_retry = false;
};
struct Value {
enum class Type {
STRING = 1,
BLOB = 2,
};
Value(Type type, std::string str) : type(type), data(std::move(str)) {}
Type type;
std::string data;
};
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, 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, 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, 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 std::string& name, Function fn);
// Register all the builtins.
void RegisterBuiltins();
// Find the Function for a given name; return NULL if no such function
// exists.
Function FindFunction(const std::string& name);
// --- convenience functions for use in functions ---
// 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, 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.
Value* ErrorAbort(State* state, const char* format, ...)
__attribute__((format(printf, 2, 3), deprecated));
// ErrorAbort has an optional (but recommended) argument 'cause_code'. If the cause code
// is set, it will be logged into last_install and provides reason of OTA failures.
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...)
__attribute__((format(printf, 3, 4)));
// Copying the string into a Value.
Value* StringValue(const char* str);
Value* StringValue(const std::string& str);
int ParseString(const std::string& str, std::unique_ptr<Expr>* root, int* error_count);
#endif // _EXPRESSION_H
+48
View File
@@ -0,0 +1,48 @@
/*
* 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 <stdint.h>
#include <string>
#include <string_view>
struct ZipArchive;
typedef ZipArchive* ZipArchiveHandle;
class UpdaterRuntimeInterface;
class UpdaterInterface {
public:
virtual ~UpdaterInterface() = default;
// Writes the message to command pipe, adds a new line in the end.
virtual void WriteToCommandPipe(const std::string_view message, bool flush = false) const = 0;
// Sends over the message to recovery to print it on the screen.
virtual void UiPrint(const std::string_view message) const = 0;
// Given the name of the block device, returns |name| for updates on the device; or the file path
// to the fake block device for simulations.
virtual std::string FindBlockDeviceName(const std::string_view name) const = 0;
virtual UpdaterRuntimeInterface* GetRuntime() const = 0;
virtual ZipArchiveHandle GetPackageHandle() const = 0;
virtual std::string GetResult() const = 0;
virtual uint8_t* GetMappedPackageAddress() const = 0;
virtual size_t GetMappedPackageLength() const = 0;
};
@@ -0,0 +1,77 @@
/*
* 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 <string>
#include <string_view>
#include <vector>
// This class serves as the base to updater runtime. It wraps the runtime dependent functions; and
// updates on device and host simulations can have different implementations. e.g. block devices
// during host simulation merely a temporary file. With this class, the caller side in registered
// updater's functions will stay the same for both update and simulation.
class UpdaterRuntimeInterface {
public:
virtual ~UpdaterRuntimeInterface() = default;
// Returns true if it's a runtime instance for simulation.
virtual bool IsSimulator() const = 0;
// Returns the value of system property |key|. If the property doesn't exist, returns
// |default_value|.
virtual std::string GetProperty(const std::string_view key,
const std::string_view default_value) const = 0;
// Given the name of the block device, returns |name| for updates on the device; or the file path
// to the fake block device for simulations.
virtual std::string FindBlockDeviceName(const std::string_view name) const = 0;
// Mounts the |location| on |mount_point|. Returns 0 on success.
virtual 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) = 0;
// Returns true if |mount_point| is mounted.
virtual bool IsMounted(const std::string_view mount_point) const = 0;
// Unmounts the |mount_point|. Returns a pair of results with the first value indicating
// if the |mount_point| is mounted, and the second value indicating the result of umount(2).
virtual std::pair<bool, int> Unmount(const std::string_view mount_point) = 0;
// Reads |filename| and puts its value to |content|.
virtual bool ReadFileToString(const std::string_view filename, std::string* content) const = 0;
// Updates the content of |filename| with |content|.
virtual bool WriteStringToFile(const std::string_view content,
const std::string_view filename) const = 0;
// Wipes the first |len| bytes of block device in |filename|.
virtual int WipeBlockDevice(const std::string_view filename, size_t len) const = 0;
// Starts a child process and runs the program with |args|. Uses vfork(2) if |is_vfork| is true.
virtual int RunProgram(const std::vector<std::string>& args, bool is_vfork) const = 0;
// Runs tune2fs with arguments |args|.
virtual int Tune2Fs(const std::vector<std::string>& args) const = 0;
// Dynamic partition related functions.
virtual bool MapPartitionOnDeviceMapper(const std::string& partition_name, std::string* path) = 0;
virtual bool UnmapPartitionOnDeviceMapper(const std::string& partition_name) = 0;
virtual bool UpdateDynamicPartitions(const std::string_view op_list_value) = 0;
// On devices supports A/B, add current slot suffix to arg. Otherwise, return |arg| as is.
virtual std::string AddSlotSuffix(const std::string_view arg) const = 0;
};
+112
View File
@@ -0,0 +1,112 @@
%{
/*
* 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 <string.h>
#include <string>
#include "edify/expr.h"
#include "yydefs.h"
#include "parser.h"
int gLine = 1;
int gColumn = 1;
int gPos = 0;
std::string string_buffer;
#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \
gColumn+=yyleng; gPos+=yyleng;} while(0)
%}
%x STR
%option noinput
%option nounput
%option noyywrap
%%
\" {
BEGIN(STR);
string_buffer.clear();
yylloc.start = gPos;
++gColumn;
++gPos;
}
<STR>{
\" {
++gColumn;
++gPos;
BEGIN(INITIAL);
yylval.str = strdup(string_buffer.c_str());
yylloc.end = gPos;
return STRING;
}
\\n { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\n'); }
\\t { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\t'); }
\\\" { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\"'); }
\\\\ { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\\'); }
\\x[0-9a-fA-F]{2} {
gColumn += yyleng;
gPos += yyleng;
int val;
sscanf(yytext+2, "%x", &val);
string_buffer.push_back(static_cast<char>(val));
}
\n {
++gLine;
++gPos;
gColumn = 1;
string_buffer.push_back(yytext[0]);
}
. {
++gColumn;
++gPos;
string_buffer.push_back(yytext[0]);
}
}
if ADVANCE; return IF;
then ADVANCE; return THEN;
else ADVANCE; return ELSE;
endif ADVANCE; return ENDIF;
[a-zA-Z0-9_:/.]+ {
ADVANCE;
yylval.str = strdup(yytext);
return STRING;
}
\&\& ADVANCE; return AND;
\|\| ADVANCE; return OR;
== ADVANCE; return EQ;
!= ADVANCE; return NE;
[+(),!;] ADVANCE; return yytext[0];
[ \t]+ ADVANCE;
(#.*)?\n gPos += yyleng; ++gLine; gColumn = 1;
. return BAD;
+145
View File
@@ -0,0 +1,145 @@
%{
/*
* 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <string>
#include <vector>
#include <android-base/macros.h>
#include "edify/expr.h"
#include "yydefs.h"
#include "parser.h"
extern int gLine;
extern int gColumn;
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
%union {
char* str;
Expr* expr;
std::vector<std::unique_ptr<Expr>>* args;
}
%token AND OR SUBSTR SUPERSTR EQ NE IF THEN ELSE ENDIF
%token <str> STRING BAD
%type <expr> expr
%type <args> arglist
%destructor { delete $$; } expr
%destructor { delete $$; } arglist
%parse-param {std::unique_ptr<Expr>* root}
%parse-param {int* error_count}
%define parse.error verbose
/* declarations in increasing order of precedence */
%left ';'
%left ','
%left OR
%left AND
%left EQ NE
%left '+'
%right '!'
%%
input: expr { root->reset($1); }
;
expr: STRING {
$$ = new Expr(Literal, $1, @$.start, @$.end);
}
| '(' expr ')' { $$ = $2; $$->start=@$.start; $$->end=@$.end; }
| expr ';' { $$ = $1; $$->start=@1.start; $$->end=@1.end; }
| expr ';' expr { $$ = Build(SequenceFn, @$, 2, $1, $3); }
| error ';' expr { $$ = $3; $$->start=@$.start; $$->end=@$.end; }
| expr '+' expr { $$ = Build(ConcatFn, @$, 2, $1, $3); }
| expr EQ expr { $$ = Build(EqualityFn, @$, 2, $1, $3); }
| expr NE expr { $$ = Build(InequalityFn, @$, 2, $1, $3); }
| expr AND expr { $$ = Build(LogicalAndFn, @$, 2, $1, $3); }
| expr OR expr { $$ = Build(LogicalOrFn, @$, 2, $1, $3); }
| '!' expr { $$ = Build(LogicalNotFn, @$, 1, $2); }
| 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 ')' {
Function fn = FindFunction($1);
if (fn == nullptr) {
std::string msg = "unknown function \"" + std::string($1) + "\"";
yyerror(root, error_count, msg.c_str());
YYERROR;
}
$$ = new Expr(fn, $1, @$.start, @$.end);
$$->argv = std::move(*$3);
}
;
arglist: /* empty */ {
$$ = new std::vector<std::unique_ptr<Expr>>;
}
| expr {
$$ = new std::vector<std::unique_ptr<Expr>>;
$$->emplace_back($1);
}
| arglist ',' expr {
UNUSED($1);
$$->push_back(std::unique_ptr<Expr>($3));
}
;
%%
void yyerror(std::unique_ptr<Expr>* root, int* error_count, const char* s) {
if (strlen(s) == 0) {
s = "syntax error";
}
printf("line %d col %d: %s\n", gLine, gColumn, s);
++*error_count;
}
int ParseString(const std::string& str, std::unique_ptr<Expr>* root, int* error_count) {
yy_switch_to_buffer(yy_scan_string(str.c_str()));
return yyparse(root, error_count);
}
+38
View File
@@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef _YYDEFS_H_
#define _YYDEFS_H_
#define YYLTYPE YYLTYPE
typedef struct {
int start, end;
} YYLTYPE;
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (N) { \
(Current).start = YYRHSLOC(Rhs, 1).start; \
(Current).end = YYRHSLOC(Rhs, N).end; \
} else { \
(Current).start = YYRHSLOC(Rhs, 0).start; \
(Current).end = YYRHSLOC(Rhs, 0).end; \
} \
} while (0)
int yylex();
#endif