Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 090b6283 authored by Tianjie Xu's avatar Tianjie Xu Committed by Gerrit Code Review
Browse files

Merge "Support starting fuse from a block map"

parents 9b76970e f6158eb9
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -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) {
+14 −3
Original line number Diff line number Diff line
@@ -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:
+1 −1
Original line number Diff line number Diff line
@@ -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",
+47 −24
Original line number Diff line number Diff line
@@ -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;
  }

  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", 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;
    umount2(SDCARD_ROOT, MNT_DETACH);
  }

  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;
  return run_fuse_sideload(std::move(file_data_reader)) == 0;
}

  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;
}
+8 −1
Original line number Diff line number Diff line
@@ -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);
Loading