Merge "Add UpdaterRuntime class" am: e7b3c5698e am: c6d7065880
am: 3445bf5352
Change-Id: Iee5015a8c6c6c86c6a3dd5516cc48afd02c7874d
This commit is contained in:
@@ -421,5 +421,5 @@ Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
State::State(const std::string& script, void* cookie)
|
||||
: script(script), cookie(cookie), error_code(kNoError), cause_code(kNoCause) {}
|
||||
State::State(const std::string& script, UpdaterInterface* interface)
|
||||
: script(script), updater(interface), error_code(kNoError), cause_code(kNoCause) {}
|
||||
|
||||
@@ -23,19 +23,20 @@
|
||||
#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, void* cookie);
|
||||
State(const std::string& script, UpdaterInterface* cookie);
|
||||
|
||||
// The source of the original script.
|
||||
const std::string& script;
|
||||
|
||||
// Optional pointer to app-specific data; the core of edify never
|
||||
// uses this value.
|
||||
void* cookie;
|
||||
// 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
|
||||
|
||||
47
edify/include/edify/updater_interface.h
Normal file
47
edify/include/edify/updater_interface.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
69
edify/include/edify/updater_runtime_interface.h
Normal file
69
edify/include/edify/updater_runtime_interface.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
@@ -52,13 +52,14 @@
|
||||
#include "updater/blockimg.h"
|
||||
#include "updater/install.h"
|
||||
#include "updater/updater.h"
|
||||
#include "updater/updater_runtime.h"
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
using PackageEntries = std::unordered_map<std::string, std::string>;
|
||||
|
||||
static void expect(const char* expected, const std::string& expr_str, CauseCode cause_code,
|
||||
Updater* updater = nullptr) {
|
||||
Updater* updater) {
|
||||
std::unique_ptr<Expr> e;
|
||||
int error_count = 0;
|
||||
ASSERT_EQ(0, ParseString(expr_str, &e, &error_count));
|
||||
@@ -83,6 +84,11 @@ static void expect(const char* expected, const std::string& expr_str, CauseCode
|
||||
ASSERT_EQ(cause_code, state.cause_code);
|
||||
}
|
||||
|
||||
static void expect(const char* expected, const std::string& expr_str, CauseCode cause_code) {
|
||||
Updater updater;
|
||||
expect(expected, expr_str, cause_code, &updater);
|
||||
}
|
||||
|
||||
static void BuildUpdatePackage(const PackageEntries& entries, int fd) {
|
||||
FILE* zip_file_ptr = fdopen(fd, "wb");
|
||||
ZipWriter zip_writer(zip_file_ptr);
|
||||
@@ -168,9 +174,9 @@ class UpdaterTestBase {
|
||||
|
||||
// Set up the handler, command_pipe, patch offset & length.
|
||||
TemporaryFile temp_pipe;
|
||||
ASSERT_TRUE(updater_.Init(temp_pipe.release(), zip_file.path, false, nullptr));
|
||||
ASSERT_TRUE(updater_.Init(temp_pipe.release(), zip_file.path, false));
|
||||
ASSERT_TRUE(updater_.RunUpdate());
|
||||
ASSERT_EQ(result, updater_.result());
|
||||
ASSERT_EQ(result, updater_.GetResult());
|
||||
|
||||
// Parse the cause code written to the command pipe.
|
||||
int received_cause_code = kNoCause;
|
||||
|
||||
@@ -71,6 +71,7 @@ cc_library_static {
|
||||
"dynamic_partitions.cpp",
|
||||
"install.cpp",
|
||||
"updater.cpp",
|
||||
"updater_runtime.cpp",
|
||||
],
|
||||
|
||||
include_dirs: [
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "edify/expr.h"
|
||||
#include "edify/updater_interface.h"
|
||||
#include "otautil/dirutil.h"
|
||||
#include "otautil/error_code.h"
|
||||
#include "otautil/paths.h"
|
||||
@@ -61,7 +62,6 @@
|
||||
#include "otautil/rangeset.h"
|
||||
#include "private/commands.h"
|
||||
#include "updater/install.h"
|
||||
#include "updater/updater.h"
|
||||
|
||||
// Set this to 0 to interpret 'erase' transfers to mean do a
|
||||
// BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret
|
||||
@@ -1669,8 +1669,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
auto updater = static_cast<Updater*>(state->cookie);
|
||||
ZipArchiveHandle za = updater->package_handle();
|
||||
auto updater = state->updater;
|
||||
auto block_device_path = updater->FindBlockDeviceName(blockdev_filename->data);
|
||||
if (block_device_path.empty()) {
|
||||
LOG(ERROR) << "Block device path for " << blockdev_filename->data << " not found. " << name
|
||||
<< " failed.";
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
ZipArchiveHandle za = updater->GetPackageHandle();
|
||||
if (za == nullptr) {
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -1690,15 +1697,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
params.fd.reset(TEMP_FAILURE_RETRY(open(blockdev_filename->data.c_str(), O_RDWR)));
|
||||
params.fd.reset(TEMP_FAILURE_RETRY(open(block_device_path.c_str(), O_RDWR)));
|
||||
if (params.fd == -1) {
|
||||
failure_type = errno == EIO ? kEioFailure : kFileOpenFailure;
|
||||
PLOG(ERROR) << "open \"" << blockdev_filename->data << "\" failed";
|
||||
PLOG(ERROR) << "open \"" << block_device_path << "\" failed";
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
uint8_t digest[SHA_DIGEST_LENGTH];
|
||||
if (!Sha1DevicePath(blockdev_filename->data, digest)) {
|
||||
if (!Sha1DevicePath(block_device_path, digest)) {
|
||||
return StringValue("");
|
||||
}
|
||||
params.stashbase = print_sha1(digest);
|
||||
@@ -1711,8 +1718,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
|
||||
struct stat sb;
|
||||
int result = stat(updated_marker.c_str(), &sb);
|
||||
if (result == 0) {
|
||||
LOG(INFO) << "Skipping already updated partition " << blockdev_filename->data
|
||||
<< " based on marker";
|
||||
LOG(INFO) << "Skipping already updated partition " << block_device_path << " based on marker";
|
||||
return StringValue("t");
|
||||
}
|
||||
} else {
|
||||
@@ -1910,7 +1916,7 @@ pbiudone:
|
||||
LOG(INFO) << "stashed " << params.stashed << " blocks";
|
||||
LOG(INFO) << "max alloc needed was " << params.buffer.size();
|
||||
|
||||
const char* partition = strrchr(blockdev_filename->data.c_str(), '/');
|
||||
const char* partition = strrchr(block_device_path.c_str(), '/');
|
||||
if (partition != nullptr && *(partition + 1) != 0) {
|
||||
updater->WriteToCommandPipe(
|
||||
android::base::StringPrintf("log bytes_written_%s: %" PRIu64, partition + 1,
|
||||
@@ -2078,10 +2084,17 @@ Value* RangeSha1Fn(const char* name, State* state, const std::vector<std::unique
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
android::base::unique_fd fd(open(blockdev_filename->data.c_str(), O_RDWR));
|
||||
auto block_device_path = state->updater->FindBlockDeviceName(blockdev_filename->data);
|
||||
if (block_device_path.empty()) {
|
||||
LOG(ERROR) << "Block device path for " << blockdev_filename->data << " not found. " << name
|
||||
<< " failed.";
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
android::base::unique_fd fd(open(block_device_path.c_str(), O_RDWR));
|
||||
if (fd == -1) {
|
||||
CauseCode cause_code = errno == EIO ? kEioFailure : kFileOpenFailure;
|
||||
ErrorAbort(state, cause_code, "open \"%s\" failed: %s", blockdev_filename->data.c_str(),
|
||||
ErrorAbort(state, cause_code, "open \"%s\" failed: %s", block_device_path.c_str(),
|
||||
strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -2095,7 +2108,7 @@ Value* RangeSha1Fn(const char* name, State* state, const std::vector<std::unique
|
||||
std::vector<uint8_t> buffer(BLOCKSIZE);
|
||||
for (const auto& [begin, end] : rs) {
|
||||
if (!check_lseek(fd, static_cast<off64_t>(begin) * BLOCKSIZE, SEEK_SET)) {
|
||||
ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data.c_str(),
|
||||
ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", block_device_path.c_str(),
|
||||
strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -2103,7 +2116,7 @@ Value* RangeSha1Fn(const char* name, State* state, const std::vector<std::unique
|
||||
for (size_t j = begin; j < end; ++j) {
|
||||
if (!android::base::ReadFully(fd, buffer.data(), BLOCKSIZE)) {
|
||||
CauseCode cause_code = errno == EIO ? kEioFailure : kFreadFailure;
|
||||
ErrorAbort(state, cause_code, "failed to read %s: %s", blockdev_filename->data.c_str(),
|
||||
ErrorAbort(state, cause_code, "failed to read %s: %s", block_device_path.c_str(),
|
||||
strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -2142,10 +2155,17 @@ Value* CheckFirstBlockFn(const char* name, State* state,
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
android::base::unique_fd fd(open(arg_filename->data.c_str(), O_RDONLY));
|
||||
auto block_device_path = state->updater->FindBlockDeviceName(arg_filename->data);
|
||||
if (block_device_path.empty()) {
|
||||
LOG(ERROR) << "Block device path for " << arg_filename->data << " not found. " << name
|
||||
<< " failed.";
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
android::base::unique_fd fd(open(block_device_path.c_str(), O_RDONLY));
|
||||
if (fd == -1) {
|
||||
CauseCode cause_code = errno == EIO ? kEioFailure : kFileOpenFailure;
|
||||
ErrorAbort(state, cause_code, "open \"%s\" failed: %s", arg_filename->data.c_str(),
|
||||
ErrorAbort(state, cause_code, "open \"%s\" failed: %s", block_device_path.c_str(),
|
||||
strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -2155,7 +2175,7 @@ Value* CheckFirstBlockFn(const char* name, State* state,
|
||||
|
||||
if (ReadBlocks(blk0, &block0_buffer, fd) == -1) {
|
||||
CauseCode cause_code = errno == EIO ? kEioFailure : kFreadFailure;
|
||||
ErrorAbort(state, cause_code, "failed to read %s: %s", arg_filename->data.c_str(),
|
||||
ErrorAbort(state, cause_code, "failed to read %s: %s", block_device_path.c_str(),
|
||||
strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -2171,10 +2191,9 @@ Value* CheckFirstBlockFn(const char* name, State* state,
|
||||
uint16_t mount_count = *reinterpret_cast<uint16_t*>(&block0_buffer[0x400 + 0x34]);
|
||||
|
||||
if (mount_count > 0) {
|
||||
auto updater = static_cast<Updater*>(state->cookie);
|
||||
updater->UiPrint(
|
||||
state->updater->UiPrint(
|
||||
android::base::StringPrintf("Device was remounted R/W %" PRIu16 " times", mount_count));
|
||||
updater->UiPrint(
|
||||
state->updater->UiPrint(
|
||||
android::base::StringPrintf("Last remount happened on %s", ctime(&mount_time)));
|
||||
}
|
||||
|
||||
@@ -2211,14 +2230,21 @@ Value* BlockImageRecoverFn(const char* name, State* state,
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
auto block_device_path = state->updater->FindBlockDeviceName(filename->data);
|
||||
if (block_device_path.empty()) {
|
||||
LOG(ERROR) << "Block device path for " << filename->data << " not found. " << name
|
||||
<< " failed.";
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
// Output notice to log when recover is attempted
|
||||
LOG(INFO) << filename->data << " image corrupted, attempting to recover...";
|
||||
LOG(INFO) << block_device_path << " image corrupted, attempting to recover...";
|
||||
|
||||
// When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
|
||||
fec::io fh(filename->data, O_RDWR);
|
||||
fec::io fh(block_device_path, O_RDWR);
|
||||
|
||||
if (!fh) {
|
||||
ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(),
|
||||
ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", block_device_path.c_str(),
|
||||
strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
@@ -2244,7 +2270,7 @@ Value* BlockImageRecoverFn(const char* name, State* state,
|
||||
|
||||
if (fh.pread(buffer, BLOCKSIZE, static_cast<off64_t>(j) * BLOCKSIZE) != BLOCKSIZE) {
|
||||
ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s",
|
||||
filename->data.c_str(), j, strerror(errno));
|
||||
block_device_path.c_str(), j, strerror(errno));
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
@@ -2260,7 +2286,7 @@ Value* BlockImageRecoverFn(const char* name, State* state,
|
||||
// read and check if the errors field value has increased.
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "..." << filename->data << " image recovered successfully.";
|
||||
LOG(INFO) << "..." << block_device_path << " image recovered successfully.";
|
||||
return StringValue("t");
|
||||
}
|
||||
|
||||
|
||||
@@ -21,45 +21,53 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "edify/expr.h"
|
||||
#include "edify/updater_interface.h"
|
||||
#include "otautil/error_code.h"
|
||||
#include "otautil/sysutil.h"
|
||||
|
||||
struct selabel_handle;
|
||||
class UpdaterRuntime;
|
||||
|
||||
class Updater {
|
||||
class Updater : public UpdaterInterface {
|
||||
public:
|
||||
~Updater();
|
||||
explicit Updater(std::unique_ptr<UpdaterRuntimeInterface> run_time)
|
||||
: runtime_(std::move(run_time)) {}
|
||||
|
||||
Updater();
|
||||
|
||||
~Updater() override;
|
||||
|
||||
// Memory-maps the OTA package and opens it as a zip file. Also sets up the command pipe and
|
||||
// selabel handle. TODO(xunchang) implement a run time environment class and move sehandle there.
|
||||
bool Init(int fd, const std::string& package_filename, bool is_retry,
|
||||
struct selabel_handle* sehandle);
|
||||
// UpdaterRuntime.
|
||||
bool Init(int fd, const std::string_view package_filename, bool is_retry);
|
||||
|
||||
// Parses and evaluates the updater-script in the OTA package. Reports the error code if the
|
||||
// evaluation fails.
|
||||
bool RunUpdate();
|
||||
|
||||
// Writes the message to command pipe, adds a new line in the end.
|
||||
void WriteToCommandPipe(const std::string& message, bool flush = false) const;
|
||||
void WriteToCommandPipe(const std::string_view message, bool flush = false) const override;
|
||||
|
||||
// Sends over the message to recovery to print it on the screen.
|
||||
void UiPrint(const std::string& message) const;
|
||||
void UiPrint(const std::string_view message) const override;
|
||||
|
||||
ZipArchiveHandle package_handle() const {
|
||||
std::string FindBlockDeviceName(const std::string_view name) const override;
|
||||
|
||||
UpdaterRuntimeInterface* GetRuntime() const override {
|
||||
return runtime_.get();
|
||||
}
|
||||
ZipArchiveHandle GetPackageHandle() const override {
|
||||
return package_handle_;
|
||||
}
|
||||
struct selabel_handle* sehandle() const {
|
||||
return sehandle_;
|
||||
}
|
||||
std::string result() const {
|
||||
std::string GetResult() const override {
|
||||
return result_;
|
||||
}
|
||||
|
||||
uint8_t* GetMappedPackageAddress() const {
|
||||
uint8_t* GetMappedPackageAddress() const override {
|
||||
return mapped_package_.addr;
|
||||
}
|
||||
|
||||
@@ -76,13 +84,15 @@ class Updater {
|
||||
// Parses the error code embedded in state->errmsg; and reports the error code and cause code.
|
||||
void ParseAndReportErrorCode(State* state);
|
||||
|
||||
std::unique_ptr<UpdaterRuntimeInterface> runtime_;
|
||||
|
||||
MemMapping mapped_package_;
|
||||
ZipArchiveHandle package_handle_{ nullptr };
|
||||
std::string updater_script_;
|
||||
|
||||
bool is_retry_{ false };
|
||||
std::unique_ptr<FILE, decltype(&fclose)> cmd_pipe_{ nullptr, fclose };
|
||||
struct selabel_handle* sehandle_{ nullptr };
|
||||
|
||||
std::string result_;
|
||||
std::vector<std::string> skipped_functions_;
|
||||
};
|
||||
|
||||
58
updater/include/updater/updater_runtime.h
Normal file
58
updater/include/updater/updater_runtime.h
Normal file
@@ -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 <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "edify/updater_runtime_interface.h"
|
||||
|
||||
struct selabel_handle;
|
||||
struct Partition;
|
||||
|
||||
class UpdaterRuntime : public UpdaterRuntimeInterface {
|
||||
public:
|
||||
explicit UpdaterRuntime(struct selabel_handle* sehandle) : sehandle_(sehandle) {}
|
||||
~UpdaterRuntime() override = default;
|
||||
|
||||
bool IsSimulator() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GetProperty(const std::string_view key,
|
||||
const std::string_view default_value) const override;
|
||||
|
||||
std::string FindBlockDeviceName(const std::string_view name) 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<bool, int> 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<std::string>& args, bool is_vfork) const override;
|
||||
int Tune2Fs(const std::vector<std::string>& args) const override;
|
||||
|
||||
struct selabel_handle* sehandle_{ nullptr };
|
||||
};
|
||||
@@ -57,12 +57,25 @@
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "edify/expr.h"
|
||||
#include "edify/updater_interface.h"
|
||||
#include "edify/updater_runtime_interface.h"
|
||||
#include "otautil/dirutil.h"
|
||||
#include "otautil/error_code.h"
|
||||
#include "otautil/mounts.h"
|
||||
#include "otautil/print_sha1.h"
|
||||
#include "otautil/sysutil.h"
|
||||
#include "updater/updater.h"
|
||||
|
||||
static bool UpdateBlockDeviceNameForPartition(UpdaterInterface* updater, Partition* partition) {
|
||||
CHECK(updater);
|
||||
std::string name = updater->FindBlockDeviceName(partition->name);
|
||||
if (name.empty()) {
|
||||
LOG(ERROR) << "Failed to find the block device " << partition->name;
|
||||
return false;
|
||||
}
|
||||
|
||||
partition->name = std::move(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is the updater side handler for ui_print() in edify script. Contents will be sent over to
|
||||
// the recovery side for on-screen display.
|
||||
@@ -73,7 +86,7 @@ Value* UIPrintFn(const char* name, State* state, const std::vector<std::unique_p
|
||||
}
|
||||
|
||||
std::string buffer = android::base::Join(args, "");
|
||||
static_cast<Updater*>(state->cookie)->UiPrint(buffer);
|
||||
state->updater->UiPrint(buffer);
|
||||
return StringValue(buffer);
|
||||
}
|
||||
|
||||
@@ -99,7 +112,7 @@ Value* PackageExtractFileFn(const char* name, State* state,
|
||||
const std::string& zip_path = args[0];
|
||||
const std::string& dest_path = args[1];
|
||||
|
||||
ZipArchiveHandle za = static_cast<Updater*>(state->cookie)->package_handle();
|
||||
ZipArchiveHandle za = state->updater->GetPackageHandle();
|
||||
ZipEntry entry;
|
||||
if (FindEntry(za, zip_path, &entry) != 0) {
|
||||
LOG(ERROR) << name << ": no " << zip_path << " in package";
|
||||
@@ -142,7 +155,7 @@ Value* PackageExtractFileFn(const char* name, State* state,
|
||||
}
|
||||
const std::string& zip_path = args[0];
|
||||
|
||||
ZipArchiveHandle za = static_cast<Updater*>(state->cookie)->package_handle();
|
||||
ZipArchiveHandle za = state->updater->GetPackageHandle();
|
||||
ZipEntry entry;
|
||||
if (FindEntry(za, zip_path, &entry) != 0) {
|
||||
return ErrorAbort(state, kPackageExtractFileFailure, "%s(): no %s in package", name,
|
||||
@@ -197,6 +210,11 @@ Value* PatchPartitionCheckFn(const char* name, State* state,
|
||||
args[1].c_str(), err.c_str());
|
||||
}
|
||||
|
||||
if (!UpdateBlockDeviceNameForPartition(state->updater, &source) ||
|
||||
!UpdateBlockDeviceNameForPartition(state->updater, &target)) {
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
bool result = PatchPartitionCheck(target, source);
|
||||
return StringValue(result ? "t" : "");
|
||||
}
|
||||
@@ -238,6 +256,11 @@ Value* PatchPartitionFn(const char* name, State* state,
|
||||
return ErrorAbort(state, kArgsParsingFailure, "%s(): Invalid patch arg", name);
|
||||
}
|
||||
|
||||
if (!UpdateBlockDeviceNameForPartition(state->updater, &source) ||
|
||||
!UpdateBlockDeviceNameForPartition(state->updater, &target)) {
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
bool result = PatchPartition(target, source, *values[0], nullptr);
|
||||
return StringValue(result ? "t" : "");
|
||||
}
|
||||
@@ -281,24 +304,8 @@ Value* MountFn(const char* name, State* state, const std::vector<std::unique_ptr
|
||||
name);
|
||||
}
|
||||
|
||||
auto updater = static_cast<Updater*>(state->cookie);
|
||||
{
|
||||
char* secontext = nullptr;
|
||||
if (updater->sehandle()) {
|
||||
selabel_lookup(updater->sehandle(), &secontext, mount_point.c_str(), 0755);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
|
||||
mkdir(mount_point.c_str(), 0755);
|
||||
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (mount(location.c_str(), mount_point.c_str(), fs_type.c_str(),
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME, mount_options.c_str()) < 0) {
|
||||
auto updater = state->updater;
|
||||
if (updater->GetRuntime()->Mount(location, mount_point, fs_type, mount_options) != 0) {
|
||||
updater->UiPrint(android::base::StringPrintf("%s: Failed to mount %s at %s: %s", name,
|
||||
location.c_str(), mount_point.c_str(),
|
||||
strerror(errno)));
|
||||
@@ -324,9 +331,8 @@ Value* IsMountedFn(const char* name, State* state, const std::vector<std::unique
|
||||
"mount_point argument to unmount() can't be empty");
|
||||
}
|
||||
|
||||
scan_mounted_volumes();
|
||||
MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str());
|
||||
if (vol == nullptr) {
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
if (!updater_runtime->IsMounted(mount_point)) {
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
@@ -347,42 +353,20 @@ Value* UnmountFn(const char* name, State* state, const std::vector<std::unique_p
|
||||
"mount_point argument to unmount() can't be empty");
|
||||
}
|
||||
|
||||
auto updater = static_cast<Updater*>(state->cookie);
|
||||
scan_mounted_volumes();
|
||||
MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str());
|
||||
if (vol == nullptr) {
|
||||
auto updater = state->updater;
|
||||
auto [mounted, result] = updater->GetRuntime()->Unmount(mount_point);
|
||||
if (!mounted) {
|
||||
updater->UiPrint(
|
||||
android::base::StringPrintf("Failed to unmount %s: No such volume", mount_point.c_str()));
|
||||
return nullptr;
|
||||
} else {
|
||||
int ret = unmount_mounted_volume(vol);
|
||||
if (ret != 0) {
|
||||
updater->UiPrint(android::base::StringPrintf("Failed to unmount %s: %s", mount_point.c_str(),
|
||||
strerror(errno)));
|
||||
}
|
||||
} else if (result != 0) {
|
||||
updater->UiPrint(android::base::StringPrintf("Failed to unmount %s: %s", mount_point.c_str(),
|
||||
strerror(errno)));
|
||||
}
|
||||
|
||||
return StringValue(mount_point);
|
||||
}
|
||||
|
||||
static int exec_cmd(const std::vector<std::string>& args) {
|
||||
CHECK(!args.empty());
|
||||
auto argv = StringVectorToNullTerminatedArray(args);
|
||||
|
||||
pid_t child;
|
||||
if ((child = vfork()) == 0) {
|
||||
execv(argv[0], argv.data());
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(child, &status, 0);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
LOG(ERROR) << args[0] << " failed with status " << WEXITSTATUS(status);
|
||||
}
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
// format(fs_type, partition_type, location, fs_size, mount_point)
|
||||
//
|
||||
// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location>
|
||||
@@ -427,6 +411,7 @@ Value* FormatFn(const char* name, State* state, const std::vector<std::unique_pt
|
||||
fs_size.c_str());
|
||||
}
|
||||
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
if (fs_type == "ext4") {
|
||||
std::vector<std::string> mke2fs_args = {
|
||||
"/system/bin/mke2fs", "-t", "ext4", "-b", "4096", location
|
||||
@@ -435,12 +420,13 @@ Value* FormatFn(const char* name, State* state, const std::vector<std::unique_pt
|
||||
mke2fs_args.push_back(std::to_string(size / 4096LL));
|
||||
}
|
||||
|
||||
if (auto status = exec_cmd(mke2fs_args); status != 0) {
|
||||
if (auto status = updater_runtime->RunProgram(mke2fs_args, true); status != 0) {
|
||||
LOG(ERROR) << name << ": mke2fs failed (" << status << ") on " << location;
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
if (auto status = exec_cmd({ "/system/bin/e2fsdroid", "-e", "-a", mount_point, location });
|
||||
if (auto status = updater_runtime->RunProgram(
|
||||
{ "/system/bin/e2fsdroid", "-e", "-a", mount_point, location }, true);
|
||||
status != 0) {
|
||||
LOG(ERROR) << name << ": e2fsdroid failed (" << status << ") on " << location;
|
||||
return StringValue("");
|
||||
@@ -459,12 +445,13 @@ Value* FormatFn(const char* name, State* state, const std::vector<std::unique_pt
|
||||
if (size >= 512) {
|
||||
f2fs_args.push_back(std::to_string(size / 512));
|
||||
}
|
||||
if (auto status = exec_cmd(f2fs_args); status != 0) {
|
||||
if (auto status = updater_runtime->RunProgram(f2fs_args, true); status != 0) {
|
||||
LOG(ERROR) << name << ": make_f2fs failed (" << status << ") on " << location;
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
if (auto status = exec_cmd({ "/system/bin/sload_f2fs", "-t", mount_point, location });
|
||||
if (auto status = updater_runtime->RunProgram(
|
||||
{ "/system/bin/sload_f2fs", "-t", mount_point, location }, true);
|
||||
status != 0) {
|
||||
LOG(ERROR) << name << ": sload_f2fs failed (" << status << ") on " << location;
|
||||
return StringValue("");
|
||||
@@ -503,8 +490,7 @@ Value* ShowProgressFn(const char* name, State* state,
|
||||
sec_str.c_str());
|
||||
}
|
||||
|
||||
auto updater = static_cast<Updater*>(state->cookie);
|
||||
updater->WriteToCommandPipe(android::base::StringPrintf("progress %f %d", frac, sec));
|
||||
state->updater->WriteToCommandPipe(android::base::StringPrintf("progress %f %d", frac, sec));
|
||||
|
||||
return StringValue(frac_str);
|
||||
}
|
||||
@@ -527,8 +513,7 @@ Value* SetProgressFn(const char* name, State* state,
|
||||
frac_str.c_str());
|
||||
}
|
||||
|
||||
auto updater = static_cast<Updater*>(state->cookie);
|
||||
updater->WriteToCommandPipe(android::base::StringPrintf("set_progress %f", frac));
|
||||
state->updater->WriteToCommandPipe(android::base::StringPrintf("set_progress %f", frac));
|
||||
|
||||
return StringValue(frac_str);
|
||||
}
|
||||
@@ -541,7 +526,9 @@ Value* GetPropFn(const char* name, State* state, const std::vector<std::unique_p
|
||||
if (!Evaluate(state, argv[0], &key)) {
|
||||
return nullptr;
|
||||
}
|
||||
std::string value = android::base::GetProperty(key, "");
|
||||
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
std::string value = updater_runtime->GetProperty(key, "");
|
||||
|
||||
return StringValue(value);
|
||||
}
|
||||
@@ -566,7 +553,8 @@ Value* FileGetPropFn(const char* name, State* state,
|
||||
const std::string& key = args[1];
|
||||
|
||||
std::string buffer;
|
||||
if (!android::base::ReadFileToString(filename, &buffer)) {
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
if (!updater_runtime->ReadFileToString(filename, &buffer)) {
|
||||
ErrorAbort(state, kFreadFailure, "%s: failed to read %s", name, filename.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
@@ -628,7 +616,7 @@ Value* WipeCacheFn(const char* name, State* state, const std::vector<std::unique
|
||||
argv.size());
|
||||
}
|
||||
|
||||
static_cast<Updater*>(state->cookie)->WriteToCommandPipe("wipe_cache");
|
||||
state->updater->WriteToCommandPipe("wipe_cache");
|
||||
return StringValue("t");
|
||||
}
|
||||
|
||||
@@ -642,26 +630,8 @@ Value* RunProgramFn(const char* name, State* state, const std::vector<std::uniqu
|
||||
return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
|
||||
}
|
||||
|
||||
auto exec_args = StringVectorToNullTerminatedArray(args);
|
||||
LOG(INFO) << "about to run program [" << exec_args[0] << "] with " << argv.size() << " args";
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == 0) {
|
||||
execv(exec_args[0], exec_args.data());
|
||||
PLOG(ERROR) << "run_program: execv failed";
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(child, &status, 0);
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
LOG(ERROR) << "run_program: child exited with status " << WEXITSTATUS(status);
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
LOG(ERROR) << "run_program: child terminated by signal " << WTERMSIG(status);
|
||||
}
|
||||
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
auto status = updater_runtime->RunProgram(args, false);
|
||||
return StringValue(std::to_string(status));
|
||||
}
|
||||
|
||||
@@ -679,7 +649,8 @@ Value* ReadFileFn(const char* name, State* state, const std::vector<std::unique_
|
||||
const std::string& filename = args[0];
|
||||
|
||||
std::string contents;
|
||||
if (android::base::ReadFileToString(filename, &contents)) {
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
if (updater_runtime->ReadFileToString(filename, &contents)) {
|
||||
return new Value(Value::Type::STRING, std::move(contents));
|
||||
}
|
||||
|
||||
@@ -708,12 +679,12 @@ Value* WriteValueFn(const char* name, State* state, const std::vector<std::uniqu
|
||||
}
|
||||
|
||||
const std::string& value = args[0];
|
||||
if (!android::base::WriteStringToFile(value, filename)) {
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
if (!updater_runtime->WriteStringToFile(value, filename)) {
|
||||
PLOG(ERROR) << name << ": Failed to write to \"" << filename << "\"";
|
||||
return StringValue("");
|
||||
} else {
|
||||
return StringValue("t");
|
||||
}
|
||||
return StringValue("t");
|
||||
}
|
||||
|
||||
// Immediately reboot the device. Recovery is not finished normally,
|
||||
@@ -839,16 +810,10 @@ Value* WipeBlockDeviceFn(const char* name, State* state, const std::vector<std::
|
||||
if (!android::base::ParseUint(len_str.c_str(), &len)) {
|
||||
return nullptr;
|
||||
}
|
||||
android::base::unique_fd fd(open(filename.c_str(), O_WRONLY));
|
||||
if (fd == -1) {
|
||||
PLOG(ERROR) << "Failed to open " << filename;
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
// The wipe_block_device function in ext4_utils returns 0 on success and 1
|
||||
// for failure.
|
||||
int status = wipe_block_device(fd, len);
|
||||
return StringValue((status == 0) ? "t" : "");
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
int status = updater_runtime->WipeBlockDevice(filename, len);
|
||||
return StringValue(status == 0 ? "t" : "");
|
||||
}
|
||||
|
||||
Value* EnableRebootFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
|
||||
@@ -856,7 +821,7 @@ Value* EnableRebootFn(const char* name, State* state, const std::vector<std::uni
|
||||
return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %zu", name,
|
||||
argv.size());
|
||||
}
|
||||
static_cast<Updater*>(state->cookie)->WriteToCommandPipe("enable_reboot");
|
||||
state->updater->WriteToCommandPipe("enable_reboot");
|
||||
return StringValue("t");
|
||||
}
|
||||
|
||||
@@ -872,10 +837,8 @@ Value* Tune2FsFn(const char* name, State* state, const std::vector<std::unique_p
|
||||
|
||||
// tune2fs expects the program name as its first arg.
|
||||
args.insert(args.begin(), "tune2fs");
|
||||
auto tune2fs_args = StringVectorToNullTerminatedArray(args);
|
||||
|
||||
// tune2fs changes the filesystem parameters on an ext2 filesystem; it returns 0 on success.
|
||||
if (auto result = tune2fs_main(tune2fs_args.size() - 1, tune2fs_args.data()); result != 0) {
|
||||
auto updater_runtime = state->updater->GetRuntime();
|
||||
if (auto result = updater_runtime->Tune2Fs(args); result != 0) {
|
||||
return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", name, result);
|
||||
}
|
||||
return StringValue("t");
|
||||
|
||||
@@ -24,14 +24,17 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "updater/updater_runtime.h"
|
||||
|
||||
Updater::Updater() : Updater(std::make_unique<UpdaterRuntime>(nullptr)) {}
|
||||
|
||||
Updater::~Updater() {
|
||||
if (package_handle_) {
|
||||
CloseArchive(package_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
bool Updater::Init(int fd, const std::string& package_filename, bool is_retry,
|
||||
struct selabel_handle* sehandle) {
|
||||
bool Updater::Init(int fd, const std::string_view package_filename, bool is_retry) {
|
||||
// Set up the pipe for sending commands back to the parent process.
|
||||
cmd_pipe_.reset(fdopen(fd, "wb"));
|
||||
if (!cmd_pipe_) {
|
||||
@@ -41,12 +44,12 @@ bool Updater::Init(int fd, const std::string& package_filename, bool is_retry,
|
||||
|
||||
setlinebuf(cmd_pipe_.get());
|
||||
|
||||
if (!mapped_package_.MapFile(package_filename)) {
|
||||
if (!mapped_package_.MapFile(std::string(package_filename))) {
|
||||
LOG(ERROR) << "failed to map package " << package_filename;
|
||||
return false;
|
||||
}
|
||||
if (int open_err = OpenArchiveFromMemory(mapped_package_.addr, mapped_package_.length,
|
||||
package_filename.c_str(), &package_handle_);
|
||||
std::string(package_filename).c_str(), &package_handle_);
|
||||
open_err != 0) {
|
||||
LOG(ERROR) << "failed to open package " << package_filename << ": "
|
||||
<< ErrorCodeString(open_err);
|
||||
@@ -58,14 +61,12 @@ bool Updater::Init(int fd, const std::string& package_filename, bool is_retry,
|
||||
|
||||
is_retry_ = is_retry;
|
||||
|
||||
sehandle_ = sehandle;
|
||||
if (!sehandle_) {
|
||||
fprintf(cmd_pipe_.get(), "ui_print Warning: No file_contexts\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Updater::RunUpdate() {
|
||||
CHECK(runtime_);
|
||||
|
||||
// Parse the script.
|
||||
std::unique_ptr<Expr> root;
|
||||
int error_count = 0;
|
||||
@@ -86,6 +87,9 @@ bool Updater::RunUpdate() {
|
||||
if (result_.empty() && state.cause_code != kNoCause) {
|
||||
fprintf(cmd_pipe_.get(), "log cause: %d\n", state.cause_code);
|
||||
}
|
||||
for (const auto& func : skipped_functions_) {
|
||||
LOG(WARNING) << "Skipped executing function " << func;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -93,17 +97,17 @@ bool Updater::RunUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Updater::WriteToCommandPipe(const std::string& message, bool flush) const {
|
||||
fprintf(cmd_pipe_.get(), "%s\n", message.c_str());
|
||||
void Updater::WriteToCommandPipe(const std::string_view message, bool flush) const {
|
||||
fprintf(cmd_pipe_.get(), "%s\n", std::string(message).c_str());
|
||||
if (flush) {
|
||||
fflush(cmd_pipe_.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Updater::UiPrint(const std::string& message) const {
|
||||
void Updater::UiPrint(const std::string_view message) const {
|
||||
// "line1\nline2\n" will be split into 3 tokens: "line1", "line2" and "".
|
||||
// so skip sending empty strings to ui.
|
||||
std::vector<std::string> lines = android::base::Split(message, "\n");
|
||||
std::vector<std::string> lines = android::base::Split(std::string(message), "\n");
|
||||
for (const auto& line : lines) {
|
||||
if (!line.empty()) {
|
||||
fprintf(cmd_pipe_.get(), "ui_print %s\n", line.c_str());
|
||||
@@ -116,6 +120,10 @@ void Updater::UiPrint(const std::string& message) const {
|
||||
LOG(INFO) << message;
|
||||
}
|
||||
|
||||
std::string Updater::FindBlockDeviceName(const std::string_view name) const {
|
||||
return runtime_->FindBlockDeviceName(name);
|
||||
}
|
||||
|
||||
void Updater::ParseAndReportErrorCode(State* state) {
|
||||
CHECK(state);
|
||||
if (state->errmsg.empty()) {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "updater/dynamic_partitions.h"
|
||||
#include "updater/install.h"
|
||||
#include "updater/updater.h"
|
||||
#include "updater/updater_runtime.h"
|
||||
|
||||
// Generated by the makefile, this function defines the
|
||||
// RegisterDeviceExtensions() function, which calls all the
|
||||
@@ -95,8 +96,8 @@ int main(int argc, char** argv) {
|
||||
auto sehandle = selinux_android_file_context_handle();
|
||||
selinux_android_set_sehandle(sehandle);
|
||||
|
||||
Updater updater;
|
||||
if (!updater.Init(fd, package_name, is_retry, sehandle)) {
|
||||
Updater updater(std::make_unique<UpdaterRuntime>(sehandle));
|
||||
if (!updater.Init(fd, package_name, is_retry)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
132
updater/updater_runtime.cpp
Normal file
132
updater/updater_runtime.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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/updater_runtime.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <ext4_utils/wipe.h>
|
||||
#include <selinux/label.h>
|
||||
#include <tune2fs.h>
|
||||
|
||||
#include "otautil/mounts.h"
|
||||
#include "otautil/sysutil.h"
|
||||
|
||||
std::string UpdaterRuntime::GetProperty(const std::string_view key,
|
||||
const std::string_view default_value) const {
|
||||
return android::base::GetProperty(std::string(key), std::string(default_value));
|
||||
}
|
||||
|
||||
std::string UpdaterRuntime::FindBlockDeviceName(const std::string_view name) const {
|
||||
return std::string(name);
|
||||
}
|
||||
|
||||
int UpdaterRuntime::Mount(const std::string_view location, const std::string_view mount_point,
|
||||
const std::string_view fs_type, const std::string_view mount_options) {
|
||||
std::string mount_point_string(mount_point);
|
||||
char* secontext = nullptr;
|
||||
if (sehandle_) {
|
||||
selabel_lookup(sehandle_, &secontext, mount_point_string.c_str(), 0755);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
|
||||
mkdir(mount_point_string.c_str(), 0755);
|
||||
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(nullptr);
|
||||
}
|
||||
|
||||
return mount(std::string(location).c_str(), mount_point_string.c_str(),
|
||||
std::string(fs_type).c_str(), MS_NOATIME | MS_NODEV | MS_NODIRATIME,
|
||||
std::string(mount_options).c_str());
|
||||
}
|
||||
|
||||
bool UpdaterRuntime::IsMounted(const std::string_view mount_point) const {
|
||||
scan_mounted_volumes();
|
||||
MountedVolume* vol = find_mounted_volume_by_mount_point(std::string(mount_point).c_str());
|
||||
return vol != nullptr;
|
||||
}
|
||||
|
||||
std::pair<bool, int> UpdaterRuntime::Unmount(const std::string_view mount_point) {
|
||||
scan_mounted_volumes();
|
||||
MountedVolume* vol = find_mounted_volume_by_mount_point(std::string(mount_point).c_str());
|
||||
if (vol == nullptr) {
|
||||
return { false, -1 };
|
||||
}
|
||||
|
||||
int ret = unmount_mounted_volume(vol);
|
||||
return { true, ret };
|
||||
}
|
||||
|
||||
bool UpdaterRuntime::ReadFileToString(const std::string_view filename, std::string* content) const {
|
||||
return android::base::ReadFileToString(std::string(filename), content);
|
||||
}
|
||||
|
||||
bool UpdaterRuntime::WriteStringToFile(const std::string_view content,
|
||||
const std::string_view filename) const {
|
||||
return android::base::WriteStringToFile(std::string(content), std::string(filename));
|
||||
}
|
||||
|
||||
int UpdaterRuntime::WipeBlockDevice(const std::string_view filename, size_t len) const {
|
||||
android::base::unique_fd fd(open(std::string(filename).c_str(), O_WRONLY));
|
||||
if (fd == -1) {
|
||||
PLOG(ERROR) << "Failed to open " << filename;
|
||||
return false;
|
||||
}
|
||||
// The wipe_block_device function in ext4_utils returns 0 on success and 1 for failure.
|
||||
return wipe_block_device(fd, len);
|
||||
}
|
||||
|
||||
int UpdaterRuntime::RunProgram(const std::vector<std::string>& args, bool is_vfork) const {
|
||||
CHECK(!args.empty());
|
||||
auto argv = StringVectorToNullTerminatedArray(args);
|
||||
LOG(INFO) << "about to run program [" << args[0] << "] with " << argv.size() << " args";
|
||||
|
||||
pid_t child = is_vfork ? vfork() : fork();
|
||||
if (child == 0) {
|
||||
execv(argv[0], argv.data());
|
||||
PLOG(ERROR) << "run_program: execv failed";
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(child, &status, 0);
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
LOG(ERROR) << "run_program: child exited with status " << WEXITSTATUS(status);
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
LOG(ERROR) << "run_program: child terminated by signal " << WTERMSIG(status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int UpdaterRuntime::Tune2Fs(const std::vector<std::string>& args) const {
|
||||
auto tune2fs_args = StringVectorToNullTerminatedArray(args);
|
||||
// tune2fs changes the filesystem parameters on an ext2 filesystem; it returns 0 on success.
|
||||
return tune2fs_main(tune2fs_args.size() - 1, tune2fs_args.data());
|
||||
}
|
||||
Reference in New Issue
Block a user