Merge "getevent: O_RDWR -> O_RDONLY | O_CLOEXEC"
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index cd42b56..fda3889 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -51,7 +51,7 @@
int statusCode = capture_shell_command("getprop ro.build.version.sdk", &sdkVersionOutputBuffer,
&sdkVersionErrorBuffer);
- if (statusCode == 0 && statusCode == 0 && sdkVersionOutputBuffer.size() > 0) {
+ if (statusCode == 0 && sdkVersionOutputBuffer.size() > 0) {
api_level = strtol((char*)sdkVersionOutputBuffer.data(), NULL, 10);
}
@@ -107,7 +107,7 @@
const char* kChmodCommandPattern = "chmod 777 %sdeployagent.sh";
std::string chmodCommand =
android::base::StringPrintf(kChmodCommandPattern, kDeviceAgentPath);
- int ret = send_shell_command(chmodCommand.c_str());
+ int ret = send_shell_command(chmodCommand);
return (ret == 0);
} else {
return false;
@@ -248,7 +248,7 @@
std::vector<char> extractErrorBuffer;
int statusCode;
DeployAgentFileCallback cb(outputFp, &extractErrorBuffer, &statusCode);
- int ret = send_shell_command(extractCommand.c_str(), false, &cb);
+ int ret = send_shell_command(extractCommand, false, &cb);
if (ret == 0) {
return cb.getBytesWritten();
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 3414d53..f32b5d5 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// This is required because no Android.bp can include a library defined in an
+// Android.mk. Eventually should kill libfastboot (defined in Android.mk)
cc_library_host_static {
name: "libfastboot2",
@@ -56,6 +58,23 @@
linux: {
srcs: ["usb_linux.cpp"],
},
+
+ darwin: {
+ srcs: ["usb_osx.cpp"],
+
+ host_ldlibs: [
+ "-framework CoreFoundation",
+ "-framework IOKit",
+ ],
+ },
+
+ windows: {
+ srcs: ["usb_windows.cpp"],
+
+ host_ldlibs: [
+ "-lws2_32",
+ ],
+ },
},
cflags: [
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index a679143..7da0a9f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -64,6 +64,7 @@
LOCAL_C_INCLUDES_windows := development/host/windows/usb/api
LOCAL_CFLAGS := $(fastboot_cflags)
LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
+LOCAL_CPP_STD := c++17
LOCAL_CXX_STL := $(fastboot_stl)
LOCAL_HEADER_LIBRARIES := bootimg_headers
LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
@@ -82,7 +83,6 @@
LOCAL_CFLAGS := $(fastboot_cflags)
LOCAL_CFLAGS_darwin := $(fastboot_cflags_darwin)
-LOCAL_CPP_STD := c++17
LOCAL_CXX_STL := $(fastboot_stl)
LOCAL_HEADER_LIBRARIES := bootimg_headers
LOCAL_LDLIBS_darwin := $(fastboot_ldlibs_darwin)
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index db6d5d6..20c3359 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -104,9 +104,10 @@
void* data;
int64_t sz;
int fd;
+ int64_t image_size;
};
-static struct {
+struct Image {
const char* nickname;
const char* img_name;
const char* sig_name;
@@ -114,7 +115,9 @@
bool optional_if_no_image;
bool optional_if_no_partition;
bool IsSecondary() const { return nickname == nullptr; }
-} images[] = {
+};
+
+static Image images[] = {
// clang-format off
{ "boot", "boot.img", "boot.sig", "boot", false, false },
{ nullptr, "boot_other.img", "boot.sig", "boot", true, false },
@@ -128,7 +131,6 @@
"product_services",
true, true },
{ "recovery", "recovery.img", "recovery.sig", "recovery", true, false },
- { "super", "super.img", "super.sig", "super", true, true },
{ "system", "system.img", "system.sig", "system", false, true },
{ nullptr, "system_other.img", "system.sig", "system", true, false },
{ "vbmeta", "vbmeta.img", "vbmeta.sig", "vbmeta", true, false },
@@ -773,6 +775,13 @@
return false;
}
+ if (sparse_file* s = sparse_file_import_auto(fd, false, false)) {
+ buf->image_size = sparse_file_len(s, false, false);
+ sparse_file_destroy(s);
+ } else {
+ buf->image_size = sz;
+ }
+
lseek64(fd, 0, SEEK_SET);
int64_t limit = get_sparse_limit(sz);
if (limit) {
@@ -1044,6 +1053,11 @@
}
}
+static bool is_userspace_fastboot() {
+ std::string value;
+ return fb_getvar("is-userspace", &value) && value == "yes";
+}
+
static bool if_partition_exists(const std::string& partition, const std::string& slot) {
std::string has_slot;
std::string partition_name = partition;
@@ -1158,7 +1172,42 @@
fb_queue_command("signature", "installing signature");
}
-static void do_flashall(const std::string& slot_override, bool skip_secondary) {
+static bool is_logical(const std::string& partition) {
+ std::string value;
+ return fb_getvar("is-logical:" + partition, &value) && value == "yes";
+}
+
+static void update_super_partition(bool force_wipe) {
+ if (!if_partition_exists("super", "")) {
+ return;
+ }
+ std::string image = find_item_given_name("super_empty.img");
+ if (access(image.c_str(), R_OK) < 0) {
+ return;
+ }
+
+ if (!is_userspace_fastboot()) {
+ die("Must have userspace fastboot to flash logical partitions");
+ }
+
+ int fd = open(image.c_str(), O_RDONLY);
+ if (fd < 0) {
+ die("could not open '%s': %s", image.c_str(), strerror(errno));
+ }
+ fb_queue_download_fd("super", fd, get_file_size(fd));
+
+ std::string command = "update-super:super";
+ if (force_wipe) {
+ command += ":wipe";
+ }
+ fb_queue_command(command, "Updating super partition");
+
+ // We need these commands to have finished before proceeding, since
+ // otherwise "getvar is-logical" may not return a correct answer below.
+ fb_execute_queue();
+}
+
+static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
std::string fname;
queue_info_dump();
@@ -1188,6 +1237,10 @@
}
}
+ update_super_partition(wipe);
+
+ // List of partitions to flash and their slots.
+ std::vector<std::pair<const Image*, std::string>> entries;
for (size_t i = 0; i < arraysize(images); i++) {
const char* slot = NULL;
if (images[i].IsSecondary()) {
@@ -1196,21 +1249,38 @@
slot = slot_override.c_str();
}
if (!slot) continue;
- fname = find_item_given_name(images[i].img_name);
+ entries.emplace_back(&images[i], slot);
+
+ // Resize any logical partition to 0, so each partition is reset to 0
+ // extents, and will achieve more optimal allocation.
+ auto resize_partition = [](const std::string& partition) -> void {
+ if (is_logical(partition)) {
+ fb_queue_resize_partition(partition, "0");
+ }
+ };
+ do_for_partitions(images[i].part_name, slot, resize_partition, false);
+ }
+
+ // Flash each partition in the list if it has a corresponding image.
+ for (const auto& [image, slot] : entries) {
+ fname = find_item_given_name(image->img_name);
fastboot_buffer buf;
if (!load_buf(fname.c_str(), &buf)) {
- if (images[i].optional_if_no_image) continue;
- die("could not load '%s': %s", images[i].img_name, strerror(errno));
+ if (image->optional_if_no_image) continue;
+ die("could not load '%s': %s", image->img_name, strerror(errno));
}
- if (images[i].optional_if_no_partition &&
- !if_partition_exists(images[i].part_name, slot)) {
+ if (image->optional_if_no_partition &&
+ !if_partition_exists(image->part_name, slot)) {
continue;
}
auto flashall = [&](const std::string &partition) {
do_send_signature(fname.c_str());
+ if (is_logical(partition)) {
+ fb_queue_resize_partition(partition, std::to_string(buf.image_size));
+ }
flash_buf(partition.c_str(), &buf);
};
- do_for_partitions(images[i].part_name, slot, flashall, false);
+ do_for_partitions(image->part_name, slot, flashall, false);
}
if (slot_override == "all") {
@@ -1648,9 +1718,9 @@
} else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
- do_flashall(slot_override, true);
+ do_flashall(slot_override, true, wants_wipe);
} else {
- do_flashall(slot_override, skip_secondary);
+ do_flashall(slot_override, skip_secondary, wants_wipe);
}
wants_reboot = true;
} else if (command == "update") {
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index b0ac2ef..fc6a16b 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -8,7 +8,7 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/wait.h>
#else
#include <tchar.h>
@@ -27,7 +27,7 @@
using android::base::StringPrintf;
using android::base::unique_fd;
-#ifdef WIN32
+#ifdef _WIN32
static int exec_cmd(const char* path, const char** argv, const char** envp) {
std::string cmd;
int i = 0;
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index 9a68ff3..301534b 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -28,4 +28,14 @@
"libsparse",
],
+ // Static libs (libfastboot2) shared library dependencies are not transitively included
+ // This is needed to avoid link time errors when building for mac
+ target: {
+ darwin: {
+ host_ldlibs: [
+ "-framework CoreFoundation",
+ "-framework IOKit",
+ ],
+ },
+ }
}
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index efbf43c..e47d0fd 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -133,4 +133,6 @@
class UserdataPartition : public ExtensionsPartition<true> {};
+class SparseTestPartition : public ExtensionsPartition<true> {};
+
} // end namespace fastboot
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 8dd46bc..14bf5bf 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -80,6 +80,9 @@
std::vector<std::pair<std::string, extension::Configuration::PackedInfoTest>>
PACKED_XML_SUCCESS_TESTS;
std::vector<std::pair<std::string, extension::Configuration::PackedInfoTest>> PACKED_XML_FAIL_TESTS;
+// This only has 1 or zero elements so it will disappear from gtest when empty
+std::vector<std::pair<std::string, extension::Configuration::PartitionInfo>>
+ SINGLE_PARTITION_XML_WRITE_HASHABLE;
const std::string DEFAULT_OUPUT_NAME = "out.img";
// const char scratch_partition[] = "userdata";
@@ -135,6 +138,22 @@
return true;
}
+bool SparseToBuf(sparse_file* sf, std::vector<char>* out, bool with_crc = false) {
+ int64_t len = sparse_file_len(sf, true, with_crc);
+ if (len <= 0) {
+ return false;
+ }
+ out->clear();
+ auto cb = [](void* priv, const void* data, size_t len) {
+ auto vec = static_cast<std::vector<char>*>(priv);
+ const char* cbuf = static_cast<const char*>(data);
+ vec->insert(vec->end(), cbuf, cbuf + len);
+ return 0;
+ };
+
+ return !sparse_file_callback(sf, true, with_crc, cb, out);
+}
+
// Only allow alphanumeric, _, -, and .
const auto not_allowed = [](char c) -> int {
return !(isalnum(c) || c == '_' || c == '-' || c == '.');
@@ -524,6 +543,42 @@
EXPECT_EQ(fb->Flash("userdata"), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
}
+TEST_F(Conformance, SparseVersionCheck) {
+ SparseWrapper sparse(4096, 4096);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ std::vector<char> buf;
+ ASSERT_TRUE(SparseToBuf(*sparse, &buf)) << "Sparse buffer creation failed";
+ // Invalid, right after magic
+ buf[4] = 0xff;
+ ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
+ ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
+
+ // It can either reject this download or reject it during flash
+ if (HandleResponse() != DEVICE_FAIL) {
+ EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
+ << "Flashing an invalid sparse version should fail " << sparse.Rep();
+ }
+}
+
+TEST_F(Conformance, SparseCRCCheck) {
+ SparseWrapper sparse(4096, 4096);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ std::vector<char> buf = RandomBuf(4096);
+ ASSERT_EQ(sparse_file_add_data(*sparse, buf.data(), buf.size(), 0), 0)
+ << "Adding data failed to sparse file: " << sparse.Rep();
+ ASSERT_TRUE(SparseToBuf(*sparse, &buf, true)) << "Sparse buffer creation failed";
+ // Flip a bit in the crc
+ buf.back() = buf.back() ^ 0x01;
+ ASSERT_EQ(DownloadCommand(buf.size()), SUCCESS) << "Device rejected download command";
+ ASSERT_EQ(SendBuffer(buf), SUCCESS) << "Downloading payload failed";
+ printf("%02x\n", (unsigned char)buf.back());
+ // It can either reject this download or reject it during flash
+ if (HandleResponse() != DEVICE_FAIL) {
+ EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
+ << "Flashing an invalid sparse version should fail " << sparse.Rep();
+ }
+}
+
TEST_F(UnlockPermissions, Download) {
std::vector<char> buf{'a', 'o', 's', 'p'};
EXPECT_EQ(fb->Download(buf), SUCCESS) << "Download 4-byte payload failed";
@@ -767,6 +822,47 @@
}
}
+TEST_F(Fuzz, SparseZeroLength) {
+ SparseWrapper sparse(4096, 0);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ RetCode ret = fb->Download(*sparse);
+ // Two ways to handle it
+ if (ret != DEVICE_FAIL) { // if lazily parsed it better fail on a flash
+ EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
+ << "Flashing zero length sparse image did not fail: " << sparse.Rep();
+ }
+ ret = fb->Download(*sparse, true);
+ if (ret != DEVICE_FAIL) { // if lazily parsed it better fail on a flash
+ EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
+ << "Flashing zero length sparse image did not fail " << sparse.Rep();
+ }
+}
+
+TEST_F(Fuzz, SparseTooManyChunks) {
+ SparseWrapper sparse(4096, 4096); // 1 block, but we send two chunks that will use 2 blocks
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ std::vector<char> buf = RandomBuf(4096);
+ ASSERT_EQ(sparse_file_add_data(*sparse, buf.data(), buf.size(), 0), 0)
+ << "Adding data failed to sparse file: " << sparse.Rep();
+ // We take advantage of the fact the sparse library does not check this
+ ASSERT_EQ(sparse_file_add_fill(*sparse, 0xdeadbeef, 4096, 1), 0)
+ << "Adding fill to sparse file failed: " << sparse.Rep();
+
+ RetCode ret = fb->Download(*sparse);
+ // Two ways to handle it
+ if (ret != DEVICE_FAIL) { // if lazily parsed it better fail on a flash
+ EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
+ << "Flashing sparse image with 'total_blks' in header 1 too small did not fail "
+ << sparse.Rep();
+ }
+ ret = fb->Download(*sparse, true);
+ if (ret != DEVICE_FAIL) { // if lazily parsed it better fail on a flash
+ EXPECT_EQ(fb->Flash("userdata"), DEVICE_FAIL)
+ << "Flashing sparse image with 'total_blks' in header 1 too small did not fail "
+ << sparse.Rep();
+ }
+}
+
TEST_F(Fuzz, USBResetSpam) {
auto start = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed;
@@ -1379,6 +1475,109 @@
INSTANTIATE_TEST_CASE_P(XMLOEM, ExtensionsOemConformance, ::testing::ValuesIn(OEM_XML_TESTS));
+// Sparse Tests
+TEST_P(SparseTestPartition, SparseSingleBlock) {
+ const std::string name = GetParam().first;
+ auto part_info = GetParam().second;
+ const std::string part_name = name + (part_info.slots ? "_a" : "");
+ SparseWrapper sparse(4096, 4096);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ std::vector<char> buf = RandomBuf(4096);
+ ASSERT_EQ(sparse_file_add_data(*sparse, buf.data(), buf.size(), 0), 0)
+ << "Adding data failed to sparse file: " << sparse.Rep();
+
+ EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
+ EXPECT_EQ(fb->Flash(part_name), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
+ std::string hash, hash_new, err_msg;
+ int retcode;
+ ASSERT_TRUE(PartitionHash(fb.get(), part_name, &hash, &retcode, &err_msg)) << err_msg;
+ ASSERT_EQ(retcode, 0) << err_msg;
+ // Now flash it the non-sparse way
+ EXPECT_EQ(fb->FlashPartition(part_name, buf), SUCCESS) << "Flashing image failed: ";
+ ASSERT_TRUE(PartitionHash(fb.get(), part_name, &hash_new, &retcode, &err_msg)) << err_msg;
+ ASSERT_EQ(retcode, 0) << err_msg;
+
+ EXPECT_EQ(hash, hash_new) << "Flashing a random buffer of 4096 using sparse and non-sparse "
+ "methods did not result in the same hash";
+}
+
+TEST_P(SparseTestPartition, SparseFill) {
+ const std::string name = GetParam().first;
+ auto part_info = GetParam().second;
+ const std::string part_name = name + (part_info.slots ? "_a" : "");
+ int64_t size = (max_dl / 4096) * 4096;
+ SparseWrapper sparse(4096, size);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ ASSERT_EQ(sparse_file_add_fill(*sparse, 0xdeadbeef, size, 0), 0)
+ << "Adding data failed to sparse file: " << sparse.Rep();
+
+ EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
+ EXPECT_EQ(fb->Flash(part_name), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
+ std::string hash, hash_new, err_msg;
+ int retcode;
+ ASSERT_TRUE(PartitionHash(fb.get(), part_name, &hash, &retcode, &err_msg)) << err_msg;
+ ASSERT_EQ(retcode, 0) << err_msg;
+ // Now flash it the non-sparse way
+ std::vector<char> buf(size);
+ for (auto iter = buf.begin(); iter < buf.end(); iter += 4) {
+ iter[0] = 0xef;
+ iter[1] = 0xbe;
+ iter[2] = 0xad;
+ iter[3] = 0xde;
+ }
+ EXPECT_EQ(fb->FlashPartition(part_name, buf), SUCCESS) << "Flashing image failed: ";
+ ASSERT_TRUE(PartitionHash(fb.get(), part_name, &hash_new, &retcode, &err_msg)) << err_msg;
+ ASSERT_EQ(retcode, 0) << err_msg;
+
+ EXPECT_EQ(hash, hash_new) << "Flashing a random buffer of 4096 using sparse and non-sparse "
+ "methods did not result in the same hash";
+}
+
+// This tests to make sure it does not overwrite previous flashes
+TEST_P(SparseTestPartition, SparseMultiple) {
+ const std::string name = GetParam().first;
+ auto part_info = GetParam().second;
+ const std::string part_name = name + (part_info.slots ? "_a" : "");
+ int64_t size = (max_dl / 4096) * 4096;
+ SparseWrapper sparse(4096, size / 2);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ ASSERT_EQ(sparse_file_add_fill(*sparse, 0xdeadbeef, size / 2, 0), 0)
+ << "Adding data failed to sparse file: " << sparse.Rep();
+ EXPECT_EQ(fb->Download(*sparse), SUCCESS) << "Download sparse failed: " << sparse.Rep();
+ EXPECT_EQ(fb->Flash(part_name), SUCCESS) << "Flashing sparse failed: " << sparse.Rep();
+
+ SparseWrapper sparse2(4096, size / 2);
+ ASSERT_TRUE(*sparse) << "Sparse image creation failed";
+ std::vector<char> buf = RandomBuf(size / 2);
+ ASSERT_EQ(sparse_file_add_data(*sparse2, buf.data(), buf.size(), (size / 2) / 4096), 0)
+ << "Adding data failed to sparse file: " << sparse2.Rep();
+ EXPECT_EQ(fb->Download(*sparse2), SUCCESS) << "Download sparse failed: " << sparse2.Rep();
+ EXPECT_EQ(fb->Flash(part_name), SUCCESS) << "Flashing sparse failed: " << sparse2.Rep();
+
+ std::string hash, hash_new, err_msg;
+ int retcode;
+ ASSERT_TRUE(PartitionHash(fb.get(), part_name, &hash, &retcode, &err_msg)) << err_msg;
+ ASSERT_EQ(retcode, 0) << err_msg;
+ // Now flash it the non-sparse way
+ std::vector<char> fbuf(size);
+ for (auto iter = fbuf.begin(); iter < fbuf.begin() + size / 2; iter += 4) {
+ iter[0] = 0xef;
+ iter[1] = 0xbe;
+ iter[2] = 0xad;
+ iter[3] = 0xde;
+ }
+ fbuf.assign(buf.begin(), buf.end());
+ EXPECT_EQ(fb->FlashPartition(part_name, fbuf), SUCCESS) << "Flashing image failed: ";
+ ASSERT_TRUE(PartitionHash(fb.get(), part_name, &hash_new, &retcode, &err_msg)) << err_msg;
+ ASSERT_EQ(retcode, 0) << err_msg;
+
+ EXPECT_EQ(hash, hash_new) << "Flashing a random buffer of 4096 using sparse and non-sparse "
+ "methods did not result in the same hash";
+}
+
+INSTANTIATE_TEST_CASE_P(XMLSparseTest, SparseTestPartition,
+ ::testing::ValuesIn(SINGLE_PARTITION_XML_WRITE_HASHABLE));
+
void GenerateXmlTests(const extension::Configuration& config) {
// Build the getvar tests
for (const auto it : config.getvars) {
@@ -1430,6 +1629,10 @@
std::make_tuple(part_info->first, part_info->second));
}
+ if (!PARTITION_XML_WRITE_HASHABLE.empty()) {
+ SINGLE_PARTITION_XML_WRITE_HASHABLE.push_back(PARTITION_XML_WRITE_HASHABLE.front());
+ }
+
// Build oem tests
for (const auto it : config.oem) {
auto oem_cmd = it.second;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 78151d5..fb57715 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -16,6 +16,7 @@
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <linux/fs.h>
#include <selinux/selinux.h>
#include <stdio.h>
@@ -23,7 +24,9 @@
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/types.h>
+#include <sys/vfs.h>
#include <unistd.h>
#include <map>
@@ -35,6 +38,8 @@
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <ext4_utils/ext4_utils.h>
#include <fs_mgr_overlayfs.h>
#include <fstab/fstab.h>
@@ -96,9 +101,26 @@
return "";
}
+// At less than 1% free space return value of false,
+// means we will try to wrap with overlayfs.
+bool fs_mgr_filesystem_has_space(const char* mount_point) {
+ // If we have access issues to find out space remaining, return true
+ // to prevent us trying to override with overlayfs.
+ struct statvfs vst;
+ if (statvfs(mount_point, &vst)) return true;
+
+ static constexpr int percent = 1; // 1%
+
+ return (vst.f_bfree >= (vst.f_blocks * percent / 100));
+}
+
bool fs_mgr_overlayfs_enabled(const struct fstab_rec* fsrec) {
// readonly filesystem, can not be mount -o remount,rw
- return "squashfs"s == fsrec->fs_type;
+ // if squashfs or if free space is (near) zero making such a remount
+ // virtually useless, or if there are shared blocks that prevent remount,rw
+ return ("squashfs"s == fsrec->fs_type) ||
+ fs_mgr_has_shared_blocks(fsrec->mount_point, fsrec->blk_device) ||
+ !fs_mgr_filesystem_has_space(fsrec->mount_point);
}
constexpr char upper_name[] = "upper";
@@ -175,6 +197,7 @@
auto fsrec_mount_point = fsrec->mount_point;
if (!fsrec_mount_point) return false;
+ if (!fsrec->blk_device) return false;
if (!fsrec->fs_type) return false;
@@ -477,3 +500,25 @@
}
#endif // ALLOW_ADBD_DISABLE_VERITY != 0
+
+bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
+ struct statfs fs;
+ if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
+ (fs.f_type != EXT4_SUPER_MAGIC)) {
+ return false;
+ }
+
+ android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
+ if (fd < 0) return false;
+
+ struct ext4_super_block sb;
+ if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
+ (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
+ return false;
+ }
+
+ struct fs_info info;
+ if (ext4_parse_sb(&sb, &info) < 0) return false;
+
+ return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
+}
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 1d2ff03..ceb45de 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -18,7 +18,10 @@
#include <fstab/fstab.h>
+#include <string>
+
bool fs_mgr_overlayfs_mount_all();
bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
bool* change = nullptr);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
+bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
diff --git a/init/Android.bp b/init/Android.bp
index 84a78e2..a2c49d0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -59,33 +59,24 @@
},
},
static_libs: [
- "libbootloader_message",
- "libfs_mgr",
- "libfec",
- "libfec_rs",
- "libhidl-gen-utils",
- "libsquashfs_utils",
- "liblogwrap",
- "libext4_utils",
"libseccomp_policy",
- "libcrypto_utils",
- "libsparse",
"libprocessgroup",
"libavb",
- "libkeyutils",
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
"libpropertyinfoparser",
],
shared_libs: [
- "libcutils",
"libbase",
- "libc",
- "liblog",
- "libcrypto",
- "libc++",
+ "libbootloader_message",
+ "libcutils",
"libdl",
- "libz",
+ "libext4_utils",
+ "libfs_mgr",
+ "libhidl-gen-utils",
+ "libkeyutils",
+ "liblog",
+ "liblogwrap",
"libselinux",
],
}
@@ -160,6 +151,7 @@
cc_test {
name: "init_tests",
defaults: ["init_defaults"],
+ compile_multilib: "first",
srcs: [
"devices_test.cpp",
"init_test.cpp",
diff --git a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
index 8c5cff6..0956fe6 100644
--- a/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
+++ b/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp
@@ -167,7 +167,7 @@
// TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
return translate_error(rc);
} else {
- ALOGE("Received %d byte response\n", rsp_size);
+ ALOGV("Received %d byte response\n", rsp_size);
}
const uint8_t* p = recv_buf;