Enable update_engine to access OTA package via file descriptor
Due to the restriction of Treble, update_engine cannot access to OTA
packages located on non-core domain area.
(e.g. /data/vendor/upgrade/xxx.zip)
To solve such problem, update_engine needs to have a new interface
which accepts a file descriptor (FD) of OTA package file instead of
its URI and to read package file while updating via FD.
Test: Manual update
Bug: 130209137
Change-Id: Ieb7173dc958ba3eb21af708e616ef7078cd17b3e
diff --git a/binder_bindings/android/os/IUpdateEngine.aidl b/binder_bindings/android/os/IUpdateEngine.aidl
index c0e29f5..cde05be 100644
--- a/binder_bindings/android/os/IUpdateEngine.aidl
+++ b/binder_bindings/android/os/IUpdateEngine.aidl
@@ -26,6 +26,11 @@
in long payload_size,
in String[] headerKeyValuePairs);
/** @hide */
+ void applyPayloadFd(in FileDescriptor fd,
+ in long payload_offset,
+ in long payload_size,
+ in String[] headerKeyValuePairs);
+ /** @hide */
boolean bind(IUpdateEngineCallback callback);
/** @hide */
boolean unbind(IUpdateEngineCallback callback);
diff --git a/binder_service_android.cc b/binder_service_android.cc
index 137694a..1799438 100644
--- a/binder_service_android.cc
+++ b/binder_service_android.cc
@@ -16,14 +16,18 @@
#include "update_engine/binder_service_android.h"
+#include <android-base/unique_fd.h>
#include <base/bind.h>
#include <base/logging.h>
#include <binderwrapper/binder_wrapper.h>
#include <brillo/errors/error.h>
#include <utils/String8.h>
+using android::base::unique_fd;
using android::binder::Status;
using android::os::IUpdateEngineCallback;
+using std::string;
+using std::vector;
using update_engine::UpdateEngineStatus;
namespace {
@@ -94,9 +98,9 @@
const android::String16& url,
int64_t payload_offset,
int64_t payload_size,
- const std::vector<android::String16>& header_kv_pairs) {
- const std::string payload_url{android::String8{url}.string()};
- std::vector<std::string> str_headers;
+ const vector<android::String16>& header_kv_pairs) {
+ const string payload_url{android::String8{url}.string()};
+ vector<string> str_headers;
str_headers.reserve(header_kv_pairs.size());
for (const auto& header : header_kv_pairs) {
str_headers.emplace_back(android::String8{header}.string());
@@ -110,6 +114,25 @@
return Status::ok();
}
+Status BinderUpdateEngineAndroidService::applyPayloadFd(
+ const ::android::base::unique_fd& fd,
+ int64_t payload_offset,
+ int64_t payload_size,
+ const vector<android::String16>& header_kv_pairs) {
+ vector<string> str_headers;
+ str_headers.reserve(header_kv_pairs.size());
+ for (const auto& header : header_kv_pairs) {
+ str_headers.emplace_back(android::String8{header}.string());
+ }
+
+ brillo::ErrorPtr error;
+ if (!service_delegate_->ApplyPayload(
+ fd.get(), payload_offset, payload_size, str_headers, &error)) {
+ return ErrorPtrToStatus(error);
+ }
+ return Status::ok();
+}
+
Status BinderUpdateEngineAndroidService::suspend() {
brillo::ErrorPtr error;
if (!service_delegate_->SuspendUpdate(&error))
diff --git a/binder_service_android.h b/binder_service_android.h
index d8c4e9c..ec4a93b 100644
--- a/binder_service_android.h
+++ b/binder_service_android.h
@@ -53,6 +53,11 @@
int64_t payload_offset,
int64_t payload_size,
const std::vector<android::String16>& header_kv_pairs) override;
+ android::binder::Status applyPayloadFd(
+ const ::android::base::unique_fd& fd,
+ int64_t payload_offset,
+ int64_t payload_size,
+ const std::vector<android::String16>& header_kv_pairs) override;
android::binder::Status bind(
const android::sp<android::os::IUpdateEngineCallback>& callback,
bool* return_value) override;
diff --git a/common/file_fetcher.cc b/common/file_fetcher.cc
index 3836e54..7134fd6 100644
--- a/common/file_fetcher.cc
+++ b/common/file_fetcher.cc
@@ -43,8 +43,9 @@
// static
bool FileFetcher::SupportedUrl(const string& url) {
// Note that we require the file path to start with a "/".
- return base::StartsWith(
- url, "file:///", base::CompareCase::INSENSITIVE_ASCII);
+ return (
+ base::StartsWith(url, "file:///", base::CompareCase::INSENSITIVE_ASCII) ||
+ base::StartsWith(url, "fd://", base::CompareCase::INSENSITIVE_ASCII));
}
FileFetcher::~FileFetcher() {
@@ -67,12 +68,20 @@
return;
}
- string file_path = url.substr(strlen("file://"));
- stream_ =
- brillo::FileStream::Open(base::FilePath(file_path),
- brillo::Stream::AccessMode::READ,
- brillo::FileStream::Disposition::OPEN_EXISTING,
- nullptr);
+ string file_path;
+
+ if (base::StartsWith(url, "fd://", base::CompareCase::INSENSITIVE_ASCII)) {
+ int fd = std::stoi(url.substr(strlen("fd://")));
+ file_path = url;
+ stream_ = brillo::FileStream::FromFileDescriptor(fd, false, nullptr);
+ } else {
+ file_path = url.substr(strlen("file://"));
+ stream_ =
+ brillo::FileStream::Open(base::FilePath(file_path),
+ brillo::Stream::AccessMode::READ,
+ brillo::FileStream::Disposition::OPEN_EXISTING,
+ nullptr);
+ }
if (!stream_) {
LOG(ERROR) << "Couldn't open " << file_path;
@@ -183,5 +192,4 @@
transfer_in_progress_ = false;
transfer_paused_ = false;
}
-
} // namespace chromeos_update_engine
diff --git a/common/utils.cc b/common/utils.cc
index 34d97a2..e7b6975 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -1064,6 +1064,16 @@
}
}
+string GetFilePath(int fd) {
+ base::FilePath proc("/proc/self/fd/" + std::to_string(fd));
+ base::FilePath file_name;
+
+ if (!base::ReadSymbolicLink(proc, &file_name)) {
+ return "not found";
+ }
+ return file_name.value();
+}
+
} // namespace utils
} // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index 9160d9f..9dca9e8 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -304,6 +304,9 @@
// reboot. Returns whether it succeeded getting the boot_id.
bool GetBootId(std::string* boot_id);
+// This function gets the file path of the file pointed to by FileDiscriptor.
+std::string GetFilePath(int fd);
+
// Divide |x| by |y| and round up to the nearest integer.
constexpr uint64_t DivRoundUp(uint64_t x, uint64_t y) {
return (x + y - 1) / y;
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 7d1c59e..b4ac2f5 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -507,4 +507,13 @@
ExpectInvalidParseRollbackKeyVersion("1.99999");
}
+TEST(UtilsTest, GetFilePathTest) {
+ test_utils::ScopedTempFile file;
+ int fd = HANDLE_EINTR(open(file.path().c_str(), O_RDONLY));
+ EXPECT_GE(fd, 0);
+ EXPECT_EQ(file.path(), utils::GetFilePath(fd));
+ EXPECT_EQ("not found", utils::GetFilePath(-1));
+ IGNORE_EINTR(close(fd));
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 2e7b6d4..766b27c 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -19,6 +19,7 @@
#include <base/format_macros.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include "update_engine/common/utils.h"
@@ -80,11 +81,18 @@
base::StringPrintf(", system_version: %s", system_version.c_str());
}
+ string url_str = download_url;
+ if (base::StartsWith(
+ url_str, "fd://", base::CompareCase::INSENSITIVE_ASCII)) {
+ int fd = std::stoi(url_str.substr(strlen("fd://")));
+ url_str = utils::GetFilePath(fd);
+ }
+
LOG(INFO) << "InstallPlan: " << (is_resume ? "resume" : "new_update")
<< version_str
<< ", source_slot: " << BootControlInterface::SlotName(source_slot)
<< ", target_slot: " << BootControlInterface::SlotName(target_slot)
- << ", url: " << download_url << payloads_str << partitions_str
+ << ", url: " << url_str << payloads_str << partitions_str
<< ", hash_checks_mandatory: "
<< utils::ToString(hash_checks_mandatory)
<< ", powerwash_required: " << utils::ToString(powerwash_required)
diff --git a/service_delegate_android_interface.h b/service_delegate_android_interface.h
index 5267bb0..6bd75b6 100644
--- a/service_delegate_android_interface.h
+++ b/service_delegate_android_interface.h
@@ -47,6 +47,13 @@
const std::vector<std::string>& key_value_pair_headers,
brillo::ErrorPtr* error) = 0;
+ virtual bool ApplyPayload(
+ int fd,
+ int64_t payload_offset,
+ int64_t payload_size,
+ const std::vector<std::string>& key_value_pair_headers,
+ brillo::ErrorPtr* error) = 0;
+
// Suspend an ongoing update. Returns true if there was an update ongoing and
// it was suspended. In case of failure, it returns false and sets |error|
// accordingly.
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 1cc8505..97c53ec 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -22,6 +22,7 @@
#include <utility>
#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
#include <base/bind.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
@@ -55,6 +56,7 @@
#include "update_engine/libcurl_http_fetcher.h"
#endif
+using android::base::unique_fd;
using base::Bind;
using base::Time;
using base::TimeDelta;
@@ -288,6 +290,19 @@
return true;
}
+bool UpdateAttempterAndroid::ApplyPayload(
+ int fd,
+ int64_t payload_offset,
+ int64_t payload_size,
+ const vector<string>& key_value_pair_headers,
+ brillo::ErrorPtr* error) {
+ payload_fd_.reset(dup(fd));
+ const string payload_url = "fd://" + std::to_string(payload_fd_.get());
+
+ return ApplyPayload(
+ payload_url, payload_offset, payload_size, key_value_pair_headers, error);
+}
+
bool UpdateAttempterAndroid::SuspendUpdate(brillo::ErrorPtr* error) {
if (!processor_->IsRunning())
return LogAndSetError(error, FROM_HERE, "No ongoing update to suspend.");
@@ -583,6 +598,7 @@
(error_code == ErrorCode::kSuccess ? UpdateStatus::UPDATED_NEED_REBOOT
: UpdateStatus::IDLE);
SetStatusAndNotify(new_status);
+ payload_fd_.reset();
// The network id is only applicable to one download attempt and once it's
// done the network id should not be re-used anymore.
diff --git a/update_attempter_android.h b/update_attempter_android.h
index c4710ad..7e1949d 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -23,6 +23,7 @@
#include <string>
#include <vector>
+#include <android-base/unique_fd.h>
#include <base/time/time.h>
#include "update_engine/client_library/include/update_engine/update_status.h"
@@ -65,6 +66,11 @@
int64_t payload_size,
const std::vector<std::string>& key_value_pair_headers,
brillo::ErrorPtr* error) override;
+ bool ApplyPayload(int fd,
+ int64_t payload_offset,
+ int64_t payload_size,
+ const std::vector<std::string>& key_value_pair_headers,
+ brillo::ErrorPtr* error) override;
bool SuspendUpdate(brillo::ErrorPtr* error) override;
bool ResumeUpdate(brillo::ErrorPtr* error) override;
bool CancelUpdate(brillo::ErrorPtr* error) override;
@@ -191,6 +197,8 @@
std::unique_ptr<MetricsReporterInterface> metrics_reporter_;
+ ::android::base::unique_fd payload_fd_;
+
DISALLOW_COPY_AND_ASSIGN(UpdateAttempterAndroid);
};