Merge "Support starting fuse from a block map"
diff --git a/fuse_sideload/fuse_provider.cpp b/fuse_sideload/fuse_provider.cpp
index 5ee6e24..8fa1b5c 100644
--- a/fuse_sideload/fuse_provider.cpp
+++ b/fuse_sideload/fuse_provider.cpp
@@ -49,6 +49,11 @@
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 @@
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) {
diff --git a/fuse_sideload/include/fuse_provider.h b/fuse_sideload/include/fuse_provider.h
index 8d4ea40..3cdaef3 100644
--- a/fuse_sideload/include/fuse_provider.h
+++ b/fuse_sideload/include/fuse_provider.h
@@ -44,6 +44,8 @@
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 @@
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 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:
diff --git a/install/Android.bp b/install/Android.bp
index 4696e50..89cc3f2 100644
--- a/install/Android.bp
+++ b/install/Android.bp
@@ -61,7 +61,7 @@
srcs: [
"adb_install.cpp",
"asn1_decoder.cpp",
- "fuse_sdcard_install.cpp",
+ "fuse_install.cpp",
"install.cpp",
"package.cpp",
"verifier.cpp",
diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_install.cpp
similarity index 80%
rename from install/fuse_sdcard_install.cpp
rename to install/fuse_install.cpp
index 9fdb2f3..ffde4a3 100644
--- a/install/fuse_sdcard_install.cpp
+++ b/install/fuse_install.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 @@
// 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 @@
// 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 @@
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;
}
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/fuse_install.h
similarity index 62%
rename from install/include/install/fuse_sdcard_install.h
rename to install/include/install/fuse_install.h
index e5bb01f..63b116a 100644
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/fuse_install.h
@@ -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);
diff --git a/minadbd/fuse_adb_provider.h b/minadbd/fuse_adb_provider.h
index c5561e5..43c07d2 100644
--- a/minadbd/fuse_adb_provider.h
+++ b/minadbd/fuse_adb_provider.h
@@ -29,6 +29,10 @@
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_;
diff --git a/recovery.cpp b/recovery.cpp
index db66ea7..b18a8e7 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -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 @@
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);
diff --git a/tests/unit/fuse_provider_test.cpp b/tests/unit/fuse_provider_test.cpp
index c5995dd..37f99f9 100644
--- a/tests/unit/fuse_provider_test.cpp
+++ b/tests/unit/fuse_provider_test.cpp
@@ -44,7 +44,8 @@
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) {
diff --git a/tests/unit/fuse_sideload_test.cpp b/tests/unit/fuse_sideload_test.cpp
index 6add99f..ea89503 100644
--- a/tests/unit/fuse_sideload_test.cpp
+++ b/tests/unit/fuse_sideload_test.cpp
@@ -40,6 +40,10 @@
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) {