Merge "Support starting fuse from a block map"
This commit is contained in:
commit
090b62832f
9 changed files with 88 additions and 33 deletions
|
@ -49,6 +49,11 @@ FuseFileDataProvider::FuseFileDataProvider(const std::string& path, uint32_t blo
|
|||
fuse_block_size_ = block_size;
|
||||
}
|
||||
|
||||
std::unique_ptr<FuseDataProvider> FuseFileDataProvider::CreateFromFile(const std::string& path,
|
||||
uint32_t block_size) {
|
||||
return std::make_unique<FuseFileDataProvider>(path, block_size);
|
||||
}
|
||||
|
||||
bool FuseFileDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
|
||||
uint32_t start_block) const {
|
||||
uint64_t offset = static_cast<uint64_t>(start_block) * fuse_block_size_;
|
||||
|
@ -127,7 +132,7 @@ bool FuseBlockDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<FuseBlockDataProvider> FuseBlockDataProvider::CreateFromBlockMap(
|
||||
std::unique_ptr<FuseDataProvider> FuseBlockDataProvider::CreateFromBlockMap(
|
||||
const std::string& block_map_path, uint32_t fuse_block_size) {
|
||||
auto block_map = BlockMapData::ParseBlockMapFile(block_map_path);
|
||||
if (!block_map) {
|
||||
|
|
|
@ -44,6 +44,8 @@ class FuseDataProvider {
|
|||
virtual bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
|
||||
uint32_t start_block) const = 0;
|
||||
|
||||
virtual bool Valid() const = 0;
|
||||
|
||||
virtual void Close() {}
|
||||
|
||||
protected:
|
||||
|
@ -60,10 +62,13 @@ class FuseFileDataProvider : public FuseDataProvider {
|
|||
public:
|
||||
FuseFileDataProvider(const std::string& path, uint32_t block_size);
|
||||
|
||||
static std::unique_ptr<FuseDataProvider> CreateFromFile(const std::string& path,
|
||||
uint32_t block_size);
|
||||
|
||||
bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
|
||||
uint32_t start_block) const override;
|
||||
|
||||
bool Valid() const {
|
||||
bool Valid() const override {
|
||||
return fd_ != -1;
|
||||
}
|
||||
|
||||
|
@ -78,14 +83,20 @@ class FuseFileDataProvider : public FuseDataProvider {
|
|||
class FuseBlockDataProvider : public FuseDataProvider {
|
||||
public:
|
||||
// Constructs the fuse provider from the block map.
|
||||
static std::unique_ptr<FuseBlockDataProvider> CreateFromBlockMap(
|
||||
const std::string& block_map_path, uint32_t fuse_block_size);
|
||||
static std::unique_ptr<FuseDataProvider> CreateFromBlockMap(const std::string& block_map_path,
|
||||
uint32_t fuse_block_size);
|
||||
|
||||
RangeSet ranges() const {
|
||||
return ranges_;
|
||||
}
|
||||
|
||||
bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
|
||||
uint32_t start_block) const override;
|
||||
|
||||
bool Valid() const override {
|
||||
return fd_ != -1;
|
||||
}
|
||||
|
||||
void Close() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -61,7 +61,7 @@ cc_library_static {
|
|||
srcs: [
|
||||
"adb_install.cpp",
|
||||
"asn1_decoder.cpp",
|
||||
"fuse_sdcard_install.cpp",
|
||||
"fuse_install.cpp",
|
||||
"install.cpp",
|
||||
"package.cpp",
|
||||
"verifier.cpp",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "install/fuse_sdcard_install.h"
|
||||
#include "install/fuse_install.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
|
@ -27,6 +27,7 @@
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
@ -74,7 +75,8 @@ static std::string BrowseDirectory(const std::string& path, Device* device, Reco
|
|||
// Skip "." and ".." entries.
|
||||
if (name == "." || name == "..") continue;
|
||||
dirs.push_back(name + "/");
|
||||
} else if (de->d_type == DT_REG && android::base::EndsWithIgnoreCase(name, ".zip")) {
|
||||
} else if (de->d_type == DT_REG && (android::base::EndsWithIgnoreCase(name, ".zip") ||
|
||||
android::base::EndsWithIgnoreCase(name, ".map"))) {
|
||||
entries.push_back(name);
|
||||
}
|
||||
}
|
||||
|
@ -119,42 +121,37 @@ static std::string BrowseDirectory(const std::string& path, Device* device, Reco
|
|||
// Unreachable.
|
||||
}
|
||||
|
||||
static bool StartSdcardFuse(const std::string& path) {
|
||||
auto file_data_reader = std::make_unique<FuseFileDataProvider>(path, 65536);
|
||||
static bool StartInstallPackageFuse(std::string_view path) {
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr auto FUSE_BLOCK_SIZE = 65536;
|
||||
bool is_block_map = android::base::ConsumePrefix(&path, "@");
|
||||
auto file_data_reader =
|
||||
is_block_map ? FuseBlockDataProvider::CreateFromBlockMap(std::string(path), FUSE_BLOCK_SIZE)
|
||||
: FuseFileDataProvider::CreateFromFile(std::string(path), FUSE_BLOCK_SIZE);
|
||||
|
||||
if (!file_data_reader->Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
|
||||
// that our open file continues to work but new references see it as unmounted.
|
||||
umount2("/sdcard", MNT_DETACH);
|
||||
if (android::base::StartsWith(path, SDCARD_ROOT)) {
|
||||
// The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so
|
||||
// that our open file continues to work but new references see it as unmounted.
|
||||
umount2(SDCARD_ROOT, MNT_DETACH);
|
||||
}
|
||||
|
||||
return run_fuse_sideload(std::move(file_data_reader)) == 0;
|
||||
}
|
||||
|
||||
InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui) {
|
||||
if (ensure_path_mounted(SDCARD_ROOT) != 0) {
|
||||
LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
|
||||
return INSTALL_ERROR;
|
||||
}
|
||||
|
||||
std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
|
||||
if (path.empty()) {
|
||||
LOG(ERROR) << "\n-- No package file selected.\n";
|
||||
ensure_path_unmounted(SDCARD_ROOT);
|
||||
return INSTALL_ERROR;
|
||||
}
|
||||
|
||||
ui->Print("\n-- Install %s ...\n", path.c_str());
|
||||
SetSdcardUpdateBootloaderMessage();
|
||||
|
||||
InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui) {
|
||||
// We used to use fuse in a thread as opposed to a process. Since accessing
|
||||
// through fuse involves going from kernel to userspace to kernel, it leads
|
||||
// to deadlock when a page fault occurs. (Bug: 26313124)
|
||||
pid_t child;
|
||||
if ((child = fork()) == 0) {
|
||||
bool status = StartSdcardFuse(path);
|
||||
bool status = StartInstallPackageFuse(path);
|
||||
|
||||
_exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
@ -203,6 +200,32 @@ InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui) {
|
|||
LOG(ERROR) << "Error exit from the fuse process: " << WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
InstallResult ApplyFromSdcard(Device* device) {
|
||||
auto ui = device->GetUI();
|
||||
if (ensure_path_mounted(SDCARD_ROOT) != 0) {
|
||||
LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
|
||||
return INSTALL_ERROR;
|
||||
}
|
||||
|
||||
std::string path = BrowseDirectory(SDCARD_ROOT, device, ui);
|
||||
if (path.empty()) {
|
||||
LOG(ERROR) << "\n-- No package file selected.\n";
|
||||
ensure_path_unmounted(SDCARD_ROOT);
|
||||
return INSTALL_ERROR;
|
||||
}
|
||||
|
||||
// Hint the install function to read from a block map file.
|
||||
if (android::base::EndsWithIgnoreCase(path, ".map")) {
|
||||
path = "@" + path;
|
||||
}
|
||||
|
||||
ui->Print("\n-- Install %s ...\n", path.c_str());
|
||||
SetSdcardUpdateBootloaderMessage();
|
||||
|
||||
auto result = InstallWithFuseFromPath(path, ui);
|
||||
ensure_path_unmounted(SDCARD_ROOT);
|
||||
return result;
|
||||
}
|
|
@ -16,8 +16,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "install/install.h"
|
||||
#include "recovery_ui/device.h"
|
||||
#include "recovery_ui/ui.h"
|
||||
|
||||
InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui);
|
||||
// Starts FUSE with the package from |path| as the data source. And installs the package from
|
||||
// |FUSE_SIDELOAD_HOST_PATHNAME|. The |path| can point to the location of a package zip file or a
|
||||
// block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map.
|
||||
InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui);
|
||||
|
||||
InstallResult ApplyFromSdcard(Device* device);
|
|
@ -29,6 +29,10 @@ class FuseAdbDataProvider : public FuseDataProvider {
|
|||
bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size,
|
||||
uint32_t start_block) const override;
|
||||
|
||||
bool Valid() const override {
|
||||
return fd_ != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
// The underlying source to read data from (i.e. the one that talks to the host).
|
||||
int fd_;
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#include "common.h"
|
||||
#include "fsck_unshare_blocks.h"
|
||||
#include "install/adb_install.h"
|
||||
#include "install/fuse_sdcard_install.h"
|
||||
#include "install/fuse_install.h"
|
||||
#include "install/install.h"
|
||||
#include "install/package.h"
|
||||
#include "install/wipe_data.h"
|
||||
|
@ -408,7 +408,7 @@ static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status)
|
|||
status = ApplyFromAdb(device, false /* rescue_mode */, &reboot_action);
|
||||
} else {
|
||||
adb = false;
|
||||
status = ApplyFromSdcard(device, ui);
|
||||
status = ApplyFromSdcard(device);
|
||||
}
|
||||
|
||||
ui->Print("\nInstall from %s completed with status %d.\n", adb ? "ADB" : "SD card", status);
|
||||
|
|
|
@ -44,7 +44,8 @@ TEST(FuseBlockMapTest, CreateFromBlockMap_smoke) {
|
|||
ASSERT_TRUE(block_map_data);
|
||||
ASSERT_EQ(10000, block_map_data->file_size());
|
||||
ASSERT_EQ(4096, block_map_data->fuse_block_size());
|
||||
ASSERT_EQ(RangeSet({ { 10, 11 }, { 20, 21 }, { 22, 23 } }), block_map_data->ranges());
|
||||
ASSERT_EQ(RangeSet({ { 10, 11 }, { 20, 21 }, { 22, 23 } }),
|
||||
static_cast<FuseBlockDataProvider*>(block_map_data.get())->ranges());
|
||||
}
|
||||
|
||||
TEST(FuseBlockMapTest, ReadBlockAlignedData_smoke) {
|
||||
|
|
|
@ -40,6 +40,10 @@ class FuseTestDataProvider : public FuseDataProvider {
|
|||
bool ReadBlockAlignedData(uint8_t*, uint32_t, uint32_t) const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Valid() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SideloadTest, run_fuse_sideload_wrong_parameters) {
|
||||
|
|
Loading…
Reference in a new issue