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

Unverified Commit a2c0d15d authored by Michael Bestas's avatar Michael Bestas
Browse files

Bring back file-based OTA edify functions

Author: Tom Marshall <tdm.code@gmail.com>
Date:   Wed Oct 25 20:27:08 2017 +0200

    Revert "kill package_extract_dir"

    changes for P:
     - bring back the mkdir_recursively variant which takes a timestamp.
     - add libziparchive dependency
     - fix otautil header paths

    changes for Q:
     - change ziputil naming convention to lowercase

    This reverts commit 53c38b15381ace565227e49104a6fd64c4c28dcc.

    Change-Id: I71c488e96a1f23aace3c38fc283aae0165129a12

Author: Tom Marshall <tdm.code@gmail.com>
Date:   Thu Dec 14 22:37:17 2017 +0100

    Revert "Remove the obsolete package_extract_dir() test"

    This reverts commit bb7e005a7906b02857ba328c5dfb11f1f3cb938e.

    Change-Id: I643235d6605d7da2a189eca10ec999b25c23e1f9

Author: Tom Marshall <tdm.code@gmail.com>
Date:   Wed Aug 23 18:14:00 2017 +0000

    Revert "updater: Remove some obsoleted functions for file-based OTA."

    This reverts commit 63d786cf22cb44fe32e8b9c1f18b32da3c9d2e1b.

    These functions will be used for third party OTA zips, so keep them.

    Change-Id: I24b67ba4c86f8f86d0a41429a395fece1a383efd

Author: Stricted <info@stricted.net>
Date:   Mon Mar 12 18:11:56 2018 +0100

    recovery: updater: Fix SymlinkFn args

    Change-Id: If2ba1b7a8b5ac471a2db84f352273fd0ea7c81a2

Author: Simon Shields <simon@lineageos.org>
Date:   Thu Aug 9 01:17:21 2018 +1000

    Revert "updater: Remove dead make_parents()."

    This reverts commit 5902691764e041bfed8edbc66a72e0854d18dfda.

    Change-Id: I69eadf1a091f6ecd45531789dedf72a178a055ba

Author: Simon Shields <simon@lineageos.org>
Date:   Thu Aug 9 01:20:40 2018 +1000

    Revert "otautil: Delete dirUnlinkHierarchy()."

    changes for P:
     - Fix missing PATH_MAX macro from limits.h

    This reverts commit 7934985e0cac4a3849418af3b8c9671f4d61078a.

    Change-Id: I67ce71a1644b58a393dce45a6c3dee97830b9ee4

Author: XiNGRZ <chenxingyu92@gmail.com>
Date:   Tue Dec 3 14:31:56 2019 +0800

    updater: Fix lost capabilities of set_metadata

    This was broken since Android O. During a file-based incremental OTA,
    capability flags were cleared but not being set again properly, leading
    some critical processes (e.g. surfaceflinger and pm-service) fails.

    For more details, see: https://android.googlesource.com/platform/system/core/+/65b8d749f71d7962831e87600dd6137566c3c281

    Change-Id: I20e616cd83ec1cd1b79717a6703919316ad77938

[mikeioannina]: Squash for Q and run through clang-format

[Chippa_a]: Adapt for Android R updater and libziparchive API

Change-Id: I91973bc9e9f8d100688c0112fda9043fd45eb86a
parent 951a7b93
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <string_view>
#include <vector>

struct selabel_handle;

// This class serves as the base to updater runtime. It wraps the runtime dependent functions; and
// updates on device and host simulations can have different implementations. e.g. block devices
// during host simulation merely a temporary file. With this class, the caller side in registered
@@ -74,4 +76,8 @@ class UpdaterRuntimeInterface {

  // On devices supports A/B, add current slot suffix to arg. Otherwise, return |arg| as is.
  virtual std::string AddSlotSuffix(const std::string_view arg) const = 0;

  virtual struct selabel_handle* sehandle() const {
    return nullptr;
  }
};
+206 −0
Original line number Diff line number Diff line
@@ -339,6 +339,212 @@ TEST_F(UpdaterTest, file_getprop) {
    expect("", script6, kNoCause);
}

TEST_F(UpdaterTest, delete) {
  // Delete none.
  expect("0", "delete()", kNoCause);
  expect("0", "delete(\"/doesntexist\")", kNoCause);
  expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\")", kNoCause);
  expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\", \"/doesntexist3\")", kNoCause);

  // Delete one file.
  TemporaryFile temp_file1;
  ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path));
  std::string script1("delete(\"" + std::string(temp_file1.path) + "\")");
  expect("1", script1.c_str(), kNoCause);

  // Delete two files.
  TemporaryFile temp_file2;
  ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file2.path));
  TemporaryFile temp_file3;
  ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file3.path));
  std::string script2("delete(\"" + std::string(temp_file2.path) + "\", \"" +
                      std::string(temp_file3.path) + "\")");
  expect("2", script2.c_str(), kNoCause);

  // Delete already deleted files.
  expect("0", script2.c_str(), kNoCause);

  // Delete one out of three.
  TemporaryFile temp_file4;
  ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file4.path));
  std::string script3("delete(\"/doesntexist1\", \"" + std::string(temp_file4.path) +
                      "\", \"/doesntexist2\")");
  expect("1", script3.c_str(), kNoCause);
}

TEST_F(UpdaterTest, rename) {
  // rename() expects two arguments.
  expect(nullptr, "rename()", kArgsParsingFailure);
  expect(nullptr, "rename(\"arg1\")", kArgsParsingFailure);
  expect(nullptr, "rename(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);

  // src_name or dst_name cannot be empty.
  expect(nullptr, "rename(\"\", \"arg2\")", kArgsParsingFailure);
  expect(nullptr, "rename(\"arg1\", \"\")", kArgsParsingFailure);

  // File doesn't exist (both of src and dst).
  expect(nullptr, "rename(\"/doesntexist\", \"/doesntexisteither\")", kFileRenameFailure);

  // Can't create parent directory.
  TemporaryFile temp_file1;
  ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path));
  std::string script1("rename(\"" + std::string(temp_file1.path) + "\", \"/proc/0/file1\")");
  expect(nullptr, script1.c_str(), kFileRenameFailure);

  // Rename.
  TemporaryFile temp_file2;
  std::string script2("rename(\"" + std::string(temp_file1.path) + "\", \"" +
                      std::string(temp_file2.path) + "\")");
  expect(temp_file2.path, script2.c_str(), kNoCause);

  // Already renamed.
  expect(temp_file2.path, script2.c_str(), kNoCause);

  // Parents create successfully.
  TemporaryFile temp_file3;
  TemporaryDir td;
  std::string temp_dir(td.path);
  std::string dst_file = temp_dir + "/aaa/bbb/a.txt";
  std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + dst_file + "\")");
  expect(dst_file.c_str(), script3.c_str(), kNoCause);

  // Clean up the temp files under td.
  ASSERT_EQ(0, unlink(dst_file.c_str()));
  ASSERT_EQ(0, rmdir((temp_dir + "/aaa/bbb").c_str()));
  ASSERT_EQ(0, rmdir((temp_dir + "/aaa").c_str()));
}

TEST_F(UpdaterTest, symlink) {
  // symlink expects 1+ argument.
  expect(nullptr, "symlink()", kArgsParsingFailure);

  // symlink should fail if src is an empty string.
  TemporaryFile temp_file1;
  std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")");
  expect(nullptr, script1.c_str(), kSymlinkFailure);

  std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"src1\", \"\")");
  expect(nullptr, script2.c_str(), kSymlinkFailure);

  // symlink failed to remove old src.
  std::string script3("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")");
  expect(nullptr, script3.c_str(), kSymlinkFailure);

  // symlink can create symlinks.
  TemporaryFile temp_file;
  std::string content = "magicvalue";
  ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path));

  TemporaryDir td;
  std::string src1 = std::string(td.path) + "/symlink1";
  std::string src2 = std::string(td.path) + "/symlink2";
  std::string script4("symlink(\"" + std::string(temp_file.path) + "\", \"" + src1 + "\", \"" +
                      src2 + "\")");
  expect("t", script4.c_str(), kNoCause);

  // Verify the created symlinks.
  struct stat sb;
  ASSERT_TRUE(lstat(src1.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode));
  ASSERT_TRUE(lstat(src2.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode));

  // Clean up the leftovers.
  ASSERT_EQ(0, unlink(src1.c_str()));
  ASSERT_EQ(0, unlink(src2.c_str()));
}

TEST_F(UpdaterTest, package_extract_dir) {
  // package_extract_dir expects 2 arguments.
  expect(nullptr, "package_extract_dir()", kArgsParsingFailure);
  expect(nullptr, "package_extract_dir(\"arg1\")", kArgsParsingFailure);
  expect(nullptr, "package_extract_dir(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);

  std::string zip_path = from_testdata_base("ziptest_valid.zip");
  ZipArchiveHandle handle;
  ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));

  // Need to set up the ziphandle.
  SetUpdaterOtaPackageHandle(handle);

  // Extract "b/c.txt" and "b/d.txt" with package_extract_dir("b", "<dir>").
  TemporaryDir td;
  std::string temp_dir(td.path);
  std::string script("package_extract_dir(\"b\", \"" + temp_dir + "\")");
  expect("t", script.c_str(), kNoCause, &updater_);

  // Verify.
  std::string data;
  std::string file_c = temp_dir + "/c.txt";
  ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
  ASSERT_EQ(kCTxtContents, data);

  std::string file_d = temp_dir + "/d.txt";
  ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
  ASSERT_EQ(kDTxtContents, data);

  // Modify the contents in order to retry. It's expected to be overwritten.
  ASSERT_TRUE(android::base::WriteStringToFile("random", file_c));
  ASSERT_TRUE(android::base::WriteStringToFile("random", file_d));

  // Extract again and verify.
  expect("t", script.c_str(), kNoCause, &updater_);

  ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
  ASSERT_EQ(kCTxtContents, data);
  ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
  ASSERT_EQ(kDTxtContents, data);

  // Clean up the temp files under td.
  ASSERT_EQ(0, unlink(file_c.c_str()));
  ASSERT_EQ(0, unlink(file_d.c_str()));

  // Extracting "b/" (with slash) should give the same result.
  script = "package_extract_dir(\"b/\", \"" + temp_dir + "\")";
  expect("t", script.c_str(), kNoCause, &updater_);

  ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
  ASSERT_EQ(kCTxtContents, data);
  ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
  ASSERT_EQ(kDTxtContents, data);

  ASSERT_EQ(0, unlink(file_c.c_str()));
  ASSERT_EQ(0, unlink(file_d.c_str()));

  // Extracting "" is allowed. The entries will carry the path name.
  script = "package_extract_dir(\"\", \"" + temp_dir + "\")";
  expect("t", script.c_str(), kNoCause, &updater_);

  std::string file_a = temp_dir + "/a.txt";
  ASSERT_TRUE(android::base::ReadFileToString(file_a, &data));
  ASSERT_EQ(kATxtContents, data);
  std::string file_b = temp_dir + "/b.txt";
  ASSERT_TRUE(android::base::ReadFileToString(file_b, &data));
  ASSERT_EQ(kBTxtContents, data);
  std::string file_b_c = temp_dir + "/b/c.txt";
  ASSERT_TRUE(android::base::ReadFileToString(file_b_c, &data));
  ASSERT_EQ(kCTxtContents, data);
  std::string file_b_d = temp_dir + "/b/d.txt";
  ASSERT_TRUE(android::base::ReadFileToString(file_b_d, &data));
  ASSERT_EQ(kDTxtContents, data);

  ASSERT_EQ(0, unlink(file_a.c_str()));
  ASSERT_EQ(0, unlink(file_b.c_str()));
  ASSERT_EQ(0, unlink(file_b_c.c_str()));
  ASSERT_EQ(0, unlink(file_b_d.c_str()));
  ASSERT_EQ(0, rmdir((temp_dir + "/b").c_str()));

  // Extracting non-existent entry should still give "t".
  script = "package_extract_dir(\"doesntexist\", \"" + temp_dir + "\")";
  expect("t", script.c_str(), kNoCause, &updater_);

  // Only relative zip_path is allowed.
  script = "package_extract_dir(\"/b\", \"" + temp_dir + "\")";
  expect("", script.c_str(), kNoCause, &updater_);

  // Only absolute dest_path is allowed.
  script = "package_extract_dir(\"b\", \"path\")";
  expect("", script.c_str(), kNoCause, &updater_);
}

// TODO: Test extracting to block device.
TEST_F(UpdaterTest, package_extract_file) {
  // package_extract_file expects 1 or 2 arguments.
+4 −2
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@

#include "edify/updater_runtime_interface.h"

struct selabel_handle;

class UpdaterRuntime : public UpdaterRuntimeInterface {
 public:
  explicit UpdaterRuntime(struct selabel_handle* sehandle) : sehandle_(sehandle) {}
@@ -58,6 +56,10 @@ class UpdaterRuntime : public UpdaterRuntimeInterface {
  bool UpdateDynamicPartitions(const std::string_view op_list_value) override;
  std::string AddSlotSuffix(const std::string_view arg) const override;

  struct selabel_handle* sehandle() const override {
    return sehandle_;
  }

 private:
  struct selabel_handle* sehandle_{ nullptr };
};
+445 −0

File changed.

Preview size limit exceeded, changes collapsed.