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

Commit 22f11205 authored by Tianjie Xu's avatar Tianjie Xu
Browse files

Remove otafault

Now it's less beneficial to inject I/O faults since we don't see many of
them. Remove the library that mocks I/O failures. And switch to android::base
I/O when possible.

Bug: 113032079
Test: unit tests pass
Change-Id: I9f2a92b7ba80f4da6ff9e2abc27f2680138f942c
parent 102d14d6
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ cc_library_static {
        "libbz",
        "libcrypto",
        "libedify",
        "libotafault",
        "libotautil",
        "libz",
    ],
@@ -100,7 +99,6 @@ cc_binary {
        "libapplypatch_modes",
        "libapplypatch",
        "libedify",
        "libotafault",
        "libotautil",
        "libbspatch",
    ],
+46 −104
Original line number Diff line number Diff line
@@ -26,24 +26,25 @@
#include <sys/types.h>
#include <unistd.h>

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <openssl/sha.h>

#include "edify/expr.h"
#include "otafault/ota_io.h"
#include "otautil/paths.h"
#include "otautil/print_sha1.h"

static int LoadPartitionContents(const std::string& filename, FileContents* file);
static size_t FileSink(const unsigned char* data, size_t len, int fd);
static int GenerateTarget(const FileContents& source_file, const std::unique_ptr<Value>& patch,
                          const std::string& target_filename,
                          const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data);
@@ -54,26 +55,13 @@ int LoadFileContents(const std::string& filename, FileContents* file) {
    return LoadPartitionContents(filename, file);
  }

  struct stat sb;
  if (stat(filename.c_str(), &sb) == -1) {
    PLOG(ERROR) << "Failed to stat \"" << filename << "\"";
  std::string data;
  if (!android::base::ReadFileToString(filename, &data)) {
    PLOG(ERROR) << "Failed to read \"" << filename << "\"";
    return -1;
  }

  std::vector<unsigned char> data(sb.st_size);
  unique_file f(ota_fopen(filename.c_str(), "rb"));
  if (!f) {
    PLOG(ERROR) << "Failed to open \"" << filename << "\"";
    return -1;
  }

  size_t bytes_read = ota_fread(data.data(), 1, data.size(), f.get());
  if (bytes_read != data.size()) {
    LOG(ERROR) << "Short read of \"" << filename << "\" (" << bytes_read << " bytes of "
               << data.size() << ")";
    return -1;
  }
  file->data = std::move(data);
  file->data = std::vector<unsigned char>(data.begin(), data.end());
  SHA1(file->data.data(), file->data.size(), file->sha1);
  return 0;
}
@@ -110,8 +98,8 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file
  std::sort(pairs.begin(), pairs.end());

  const char* partition = pieces[1].c_str();
  unique_file dev(ota_fopen(partition, "rb"));
  if (!dev) {
  android::base::unique_fd dev(open(partition, O_RDONLY));
  if (dev == -1) {
    PLOG(ERROR) << "Failed to open eMMC partition \"" << partition << "\"";
    return -1;
  }
@@ -121,8 +109,7 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file

  // Allocate enough memory to hold the largest size.
  std::vector<unsigned char> buffer(pairs[pair_count - 1].first);
  unsigned char* buffer_ptr = buffer.data();
  size_t buffer_size = 0;  // # bytes read so far
  size_t offset = 0;  // # bytes read so far
  bool found = false;

  for (const auto& pair : pairs) {
@@ -131,19 +118,16 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file

    // Read enough additional bytes to get us up to the next size. (Again,
    // we're trying the possibilities in order of increasing size).
    size_t next = current_size - buffer_size;
    if (next > 0) {
      size_t read = ota_fread(buffer_ptr, 1, next, dev.get());
      if (next != read) {
        LOG(ERROR) << "Short read (" << read << " bytes of " << next << ") for partition \""
                   << partition << "\"";
    if (current_size - offset > 0) {
      if (!android::base::ReadFully(dev, buffer.data() + offset, current_size - offset)) {
        PLOG(ERROR) << "Failed to read " << current_size - offset << " bytes of data at offset "
                    << offset << " for partition " << partition;
        return -1;
      }
      SHA1_Update(&sha_ctx, buffer_ptr, read);
      buffer_size += read;
      buffer_ptr += read;
    }

      SHA1_Update(&sha_ctx, buffer.data() + offset, current_size - offset);
      offset = current_size;
    }
    // Duplicate the SHA context and finalize the duplicate so we can
    // check it against this pair's expected hash.
    SHA_CTX temp_ctx;
@@ -173,31 +157,31 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file

  SHA1_Final(file->sha1, &sha_ctx);

  buffer.resize(buffer_size);
  buffer.resize(offset);
  file->data = std::move(buffer);

  return 0;
}

int SaveFileContents(const std::string& filename, const FileContents* file) {
  unique_fd fd(
      ota_open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR));
  android::base::unique_fd fd(
      open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR));
  if (fd == -1) {
    PLOG(ERROR) << "Failed to open \"" << filename << "\" for write";
    return -1;
  }

  size_t bytes_written = FileSink(file->data.data(), file->data.size(), fd);
  if (bytes_written != file->data.size()) {
    PLOG(ERROR) << "Short write of \"" << filename << "\" (" << bytes_written << " bytes of "
                << file->data.size();
  if (!android::base::WriteFully(fd, file->data.data(), file->data.size())) {
    PLOG(ERROR) << "Failed to write " << file->data.size() << " bytes of data to " << filename;
    return -1;
  }
  if (ota_fsync(fd) != 0) {

  if (fsync(fd) != 0) {
    PLOG(ERROR) << "Failed to fsync \"" << filename << "\"";
    return -1;
  }
  if (ota_close(fd) != 0) {

  if (close(fd.release()) != 0) {
    PLOG(ERROR) << "Failed to close \"" << filename << "\"";
    return -1;
  }
@@ -215,42 +199,36 @@ static int WriteToPartition(const unsigned char* data, size_t len, const std::st
    return -1;
  }

  const char* partition = pieces[1].c_str();
  unique_fd fd(ota_open(partition, O_RDWR));
  size_t start = 0;
  bool success = false;
  for (size_t attempt = 0; attempt < 2; ++attempt) {
    std::string partition = pieces[1];
    android::base::unique_fd fd(open(partition.c_str(), O_RDWR));
    if (fd == -1) {
      PLOG(ERROR) << "Failed to open \"" << partition << "\"";
      return -1;
    }

  size_t start = 0;
  bool success = false;
  for (size_t attempt = 0; attempt < 2; ++attempt) {
    if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
      PLOG(ERROR) << "Failed to seek to " << start << " on \"" << partition << "\"";
      return -1;
    }
    while (start < len) {
      size_t to_write = len - start;
      if (to_write > 1 << 20) to_write = 1 << 20;

      ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data + start, to_write));
      if (written == -1) {
        PLOG(ERROR) << "Failed to write to \"" << partition << "\"";
    if (!android::base::WriteFully(fd, data + start, len - start)) {
      PLOG(ERROR) << "Failed to write " << len - start << " bytes to \"" << partition << "\"";
      return -1;
    }
      start += written;
    }

    if (ota_fsync(fd) != 0) {
    if (fsync(fd) != 0) {
      PLOG(ERROR) << "Failed to sync \"" << partition << "\"";
      return -1;
    }
    if (ota_close(fd) != 0) {
    if (close(fd.release()) != 0) {
      PLOG(ERROR) << "Failed to close \"" << partition << "\"";
      return -1;
    }

    fd.reset(ota_open(partition, O_RDONLY));
    fd.reset(open(partition.c_str(), O_RDONLY));
    if (fd == -1) {
      PLOG(ERROR) << "Failed to reopen \"" << partition << "\" for verification";
      return -1;
@@ -258,13 +236,12 @@ static int WriteToPartition(const unsigned char* data, size_t len, const std::st

    // Drop caches so our subsequent verification read won't just be reading the cache.
    sync();
    unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY));
    if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
      PLOG(ERROR) << "Failed to write to /proc/sys/vm/drop_caches";
    std::string drop_cache = "/proc/sys/vm/drop_caches";
    if (!android::base::WriteStringToFile("3\n", drop_cache)) {
      PLOG(ERROR) << "Failed to write to " << drop_cache;
    } else {
      LOG(INFO) << "  caches dropped";
    }
    ota_close(dc);
    sleep(1);

    // Verify.
@@ -281,21 +258,9 @@ static int WriteToPartition(const unsigned char* data, size_t len, const std::st
        to_read = sizeof(buffer);
      }

      size_t so_far = 0;
      while (so_far < to_read) {
        ssize_t read_count = TEMP_FAILURE_RETRY(ota_read(fd, buffer + so_far, to_read - so_far));
        if (read_count == -1) {
      if (!android::base::ReadFully(fd, buffer, to_read)) {
        PLOG(ERROR) << "Failed to verify-read " << partition << " at " << p;
        return -1;
        } else if (read_count == 0) {
          LOG(ERROR) << "Verify-reading " << partition << " reached unexpected EOF at " << p;
          return -1;
        }
        if (static_cast<size_t>(read_count) < to_read) {
          LOG(INFO) << "Short verify-read " << partition << " at " << p << ": expected " << to_read
                    << " actual " << read_count;
        }
        so_far += read_count;
      }

      if (memcmp(buffer, data + p, to_read) != 0) {
@@ -311,16 +276,10 @@ static int WriteToPartition(const unsigned char* data, size_t len, const std::st
      break;
    }

    if (ota_close(fd) != 0) {
    if (close(fd.release()) != 0) {
      PLOG(ERROR) << "Failed to close " << partition;
      return -1;
    }

    fd.reset(ota_open(partition, O_RDWR));
    if (fd == -1) {
      PLOG(ERROR) << "Failed to reopen " << partition << " for next attempt";
      return -1;
    }
  }

  if (!success) {
@@ -328,10 +287,6 @@ static int WriteToPartition(const unsigned char* data, size_t len, const std::st
    return -1;
  }

  if (ota_close(fd) == -1) {
    PLOG(ERROR) << "Failed to close " << partition;
    return -1;
  }
  sync();

  return 0;
@@ -407,19 +362,6 @@ int ShowLicenses() {
  return 0;
}

static size_t FileSink(const unsigned char* data, size_t len, int fd) {
  size_t done = 0;
  while (done < len) {
    ssize_t wrote = TEMP_FAILURE_RETRY(ota_write(fd, data + done, len - done));
    if (wrote == -1) {
      PLOG(ERROR) << "Failed to write " << len - done << " bytes";
      return done;
    }
    done += wrote;
  }
  return done;
}

int applypatch(const char* source_filename, const char* target_filename,
               const char* target_sha1_str, size_t /* target_size */,
               const std::vector<std::string>& patch_sha1s,

otafault/Android.bp

deleted100644 → 0
+0 −68
Original line number Diff line number Diff line
// Copyright (C) 2017 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.

cc_library_static {
    name: "libotafault",

    host_supported: true,

    srcs: [
        "config.cpp",
        "ota_io.cpp",
    ],

    static_libs: [
        "libbase",
        "liblog",
        "libziparchive",
    ],

    export_include_dirs: [
        "include",
    ],

    cflags: [
        "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
        "-Wall",
        "-Werror",
        "-Wthread-safety",
        "-Wthread-safety-negative",
    ],

    target: {
        darwin: {
            enabled: false,
        },
    },
}

cc_test {
    name: "otafault_test",

    srcs: ["test.cpp"],

    cflags: [
        "-Wall",
        "-Werror",
    ],

    static_executable: true,

    static_libs: [
        "libotafault",
        "libziparchive",
        "libbase",
        "liblog",
    ],
}

otafault/config.cpp

deleted100644 → 0
+0 −75
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 "otafault/config.h"

#include <map>
#include <string>

#include <android-base/stringprintf.h>
#include <ziparchive/zip_archive.h>

#include "otafault/ota_io.h"

#define OTAIO_MAX_FNAME_SIZE 128

static ZipArchiveHandle archive;
static bool is_retry = false;
static std::map<std::string, bool> should_inject_cache;

static std::string get_type_path(const char* io_type) {
    return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type);
}

void ota_io_init(ZipArchiveHandle za, bool retry) {
    archive = za;
    is_retry = retry;
    ota_set_fault_files();
}

bool should_fault_inject(const char* io_type) {
    // archive will be NULL if we used an entry point other
    // than updater/updater.cpp:main
    if (archive == nullptr || is_retry) {
        return false;
    }
    const std::string type_path = get_type_path(io_type);
    if (should_inject_cache.find(type_path) != should_inject_cache.end()) {
        return should_inject_cache[type_path];
    }
    ZipString zip_type_path(type_path.c_str());
    ZipEntry entry;
    int status = FindEntry(archive, zip_type_path, &entry);
    should_inject_cache[type_path] = (status == 0);
    return (status == 0);
}

bool should_hit_cache() {
    return should_fault_inject(OTAIO_CACHE);
}

std::string fault_fname(const char* io_type) {
    std::string type_path = get_type_path(io_type);
    std::string fname;
    fname.resize(OTAIO_MAX_FNAME_SIZE);
    ZipString zip_type_path(type_path.c_str());
    ZipEntry entry;
    if (FindEntry(archive, zip_type_path, &entry) != 0) {
        return {};
    }
    ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(&fname[0]), OTAIO_MAX_FNAME_SIZE);
    return fname;
}
+0 −72
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.
 */

/*
 * Read configuration files in the OTA package to determine which files, if any, will trigger
 * errors.
 *
 * OTA packages can be modified to trigger errors by adding a top-level directory called
 * .libotafault, which may optionally contain up to three files called READ, WRITE, and FSYNC.
 * Each one of these optional files contains the name of a single file on the device disk which
 * will cause an IO error on the first call of the appropriate I/O action to that file.
 *
 * Example:
 * ota.zip
 *   <normal package contents>
 *   .libotafault
 *     WRITE
 *
 * If the contents of the file WRITE were /system/build.prop, the first write action to
 * /system/build.prop would fail with EIO. Note that READ and FSYNC files are absent, so these
 * actions will not cause an error.
 */

#ifndef _UPDATER_OTA_IO_CFG_H_
#define _UPDATER_OTA_IO_CFG_H_

#include <string>

#include <ziparchive/zip_archive.h>

#define OTAIO_BASE_DIR ".libotafault"
#define OTAIO_READ "READ"
#define OTAIO_WRITE "WRITE"
#define OTAIO_FSYNC "FSYNC"
#define OTAIO_CACHE "CACHE"

/*
 * Initialize libotafault by providing a reference to the OTA package.
 */
void ota_io_init(ZipArchiveHandle zip, bool retry);

/*
 * Return true if a config file is present for the given IO type.
 */
bool should_fault_inject(const char* io_type);

/*
 * Return true if an EIO should occur on the next hit to /cache/saved.file
 * instead of the next hit to the specified file.
 */
bool should_hit_cache();

/*
 * Return the name of the file that should cause an error for the
 * given IO type.
 */
std::string fault_fname(const char* io_type);

#endif
Loading