Merge "Call markBootAttempt when serice manager available"
diff --git a/adb/Android.bp b/adb/Android.bp
index a9ccc84..53f4404 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -24,7 +24,6 @@
"-Wno-missing-field-initializers",
"-Wvla",
],
- cpp_std: "gnu++17",
rtti: true,
use_version_lib: true,
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 22f8e8d..07b5747 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1579,15 +1579,20 @@
}
return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
}
+ // clang-format off
else if (!strcmp(argv[0], "remount") ||
!strcmp(argv[0], "reboot") ||
!strcmp(argv[0], "reboot-bootloader") ||
+ !strcmp(argv[0], "reboot-fastboot") ||
!strcmp(argv[0], "usb") ||
!strcmp(argv[0], "disable-verity") ||
!strcmp(argv[0], "enable-verity")) {
+ // clang-format on
std::string command;
if (!strcmp(argv[0], "reboot-bootloader")) {
command = "reboot:bootloader";
+ } else if (!strcmp(argv[0], "reboot-fastboot")) {
+ command = "reboot:fastboot";
} else if (argc > 1) {
command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
} else {
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index dfd9a0a..1534792 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,14 +26,10 @@
#include <unistd.h>
#include <algorithm>
-#include <map>
#include <mutex>
#include <string>
-#include <thread>
#include <vector>
-#include <android-base/thread_annotations.h>
-
#if !ADB_HOST
#include <android-base/properties.h>
#include <log/log_properties.h>
@@ -41,150 +37,9 @@
#include "adb.h"
#include "adb_io.h"
-#include "adb_utils.h"
-#include "sysdeps/chrono.h"
#include "transport.h"
#include "types.h"
-// The standard (RFC 1122 - 4.2.2.13) says that if we call close on a
-// socket while we have pending data, a TCP RST should be sent to the
-// other end to notify it that we didn't read all of its data. However,
-// this can result in data that we've successfully written out to be dropped
-// on the other end. To avoid this, instead of immediately closing a
-// socket, call shutdown on it instead, and then read from the file
-// descriptor until we hit EOF or an error before closing.
-struct LingeringSocketCloser {
- LingeringSocketCloser() = default;
- ~LingeringSocketCloser() = delete;
-
- // Defer thread creation until it's needed, because we need for there to
- // only be one thread when dropping privileges in adbd.
- void Start() {
- CHECK(!thread_.joinable());
-
- int fds[2];
- if (adb_socketpair(fds) != 0) {
- PLOG(FATAL) << "adb_socketpair failed";
- }
-
- set_file_block_mode(fds[0], false);
- set_file_block_mode(fds[1], false);
-
- notify_fd_read_.reset(fds[0]);
- notify_fd_write_.reset(fds[1]);
-
- thread_ = std::thread([this]() { Run(); });
- }
-
- void EnqueueSocket(unique_fd socket) {
- // Shutdown the socket in the outgoing direction only, so that
- // we don't have the same problem on the opposite end.
- adb_shutdown(socket.get(), SHUT_WR);
- set_file_block_mode(socket.get(), false);
-
- std::lock_guard<std::mutex> lock(mutex_);
- int fd = socket.get();
- SocketInfo info = {
- .fd = std::move(socket),
- .deadline = std::chrono::steady_clock::now() + 1s,
- };
-
- D("LingeringSocketCloser received fd %d", fd);
-
- fds_.emplace(fd, std::move(info));
- if (adb_write(notify_fd_write_, "", 1) == -1 && errno != EAGAIN) {
- PLOG(FATAL) << "failed to write to LingeringSocketCloser notify fd";
- }
- }
-
- private:
- std::vector<adb_pollfd> GeneratePollFds() {
- std::lock_guard<std::mutex> lock(mutex_);
- std::vector<adb_pollfd> result;
- result.push_back(adb_pollfd{.fd = notify_fd_read_, .events = POLLIN});
- for (auto& [fd, _] : fds_) {
- result.push_back(adb_pollfd{.fd = fd, .events = POLLIN});
- }
- return result;
- }
-
- void Run() {
- while (true) {
- std::vector<adb_pollfd> pfds = GeneratePollFds();
- int rc = adb_poll(pfds.data(), pfds.size(), 1000);
- if (rc == -1) {
- PLOG(FATAL) << "poll failed in LingeringSocketCloser";
- }
-
- std::lock_guard<std::mutex> lock(mutex_);
- if (rc == 0) {
- // Check deadlines.
- auto now = std::chrono::steady_clock::now();
- for (auto it = fds_.begin(); it != fds_.end();) {
- if (now > it->second.deadline) {
- D("LingeringSocketCloser closing fd %d due to deadline", it->first);
- it = fds_.erase(it);
- } else {
- D("deadline still not expired for fd %d", it->first);
- ++it;
- }
- }
- continue;
- }
-
- for (auto& pfd : pfds) {
- if ((pfd.revents & POLLIN) == 0) {
- continue;
- }
-
- // Empty the fd.
- ssize_t rc;
- char buf[32768];
- while ((rc = adb_read(pfd.fd, buf, sizeof(buf))) > 0) {
- continue;
- }
-
- if (pfd.fd == notify_fd_read_) {
- continue;
- }
-
- auto it = fds_.find(pfd.fd);
- if (it == fds_.end()) {
- LOG(FATAL) << "fd is missing";
- }
-
- if (rc == -1 && errno == EAGAIN) {
- if (std::chrono::steady_clock::now() > it->second.deadline) {
- D("LingeringSocketCloser closing fd %d due to deadline", pfd.fd);
- } else {
- continue;
- }
- } else if (rc == -1) {
- D("LingeringSocketCloser closing fd %d due to error %d", pfd.fd, errno);
- } else {
- D("LingeringSocketCloser closing fd %d due to EOF", pfd.fd);
- }
-
- fds_.erase(it);
- }
- }
- }
-
- std::thread thread_;
- unique_fd notify_fd_read_;
- unique_fd notify_fd_write_;
-
- struct SocketInfo {
- unique_fd fd;
- std::chrono::steady_clock::time_point deadline;
- };
-
- std::mutex mutex_;
- std::map<int, SocketInfo> fds_ GUARDED_BY(mutex_);
-};
-
-static auto& socket_closer = *new LingeringSocketCloser();
-
static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
@@ -388,12 +243,10 @@
D("LS(%d): destroying fde.fd=%d", s->id, s->fd);
- // Defer thread creation until it's needed, because we need for there to
- // only be one thread when dropping privileges in adbd.
- static std::once_flag once;
- std::call_once(once, []() { socket_closer.Start(); });
-
- socket_closer.EnqueueSocket(fdevent_release(s->fde));
+ /* IMPORTANT: the remove closes the fd
+ ** that belongs to this socket
+ */
+ fdevent_destroy(s->fde);
remove_socket(s);
delete s;
diff --git a/adb/test_device.py b/adb/test_device.py
index 4c45a73..c3166ff 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -35,8 +35,6 @@
import time
import unittest
-from datetime import datetime
-
import adb
def requires_root(func):
@@ -1337,63 +1335,6 @@
self.device.forward_remove("tcp:{}".format(local_port))
-class SocketTest(DeviceTest):
- def test_socket_flush(self):
- """Test that we handle socket closure properly.
-
- If we're done writing to a socket, closing before the other end has
- closed will send a TCP_RST if we have incoming data queued up, which
- may result in data that we've written being discarded.
-
- Bug: http://b/74616284
- """
- s = socket.create_connection(("localhost", 5037))
-
- def adb_length_prefixed(string):
- encoded = string.encode("utf8")
- result = b"%04x%s" % (len(encoded), encoded)
- return result
-
- if "ANDROID_SERIAL" in os.environ:
- transport_string = "host:transport:" + os.environ["ANDROID_SERIAL"]
- else:
- transport_string = "host:transport-any"
-
- s.sendall(adb_length_prefixed(transport_string))
- response = s.recv(4)
- self.assertEquals(b"OKAY", response)
-
- shell_string = "shell:sleep 0.5; dd if=/dev/zero bs=1m count=1 status=none; echo foo"
- s.sendall(adb_length_prefixed(shell_string))
-
- response = s.recv(4)
- self.assertEquals(b"OKAY", response)
-
- # Spawn a thread that dumps garbage into the socket until failure.
- def spam():
- buf = b"\0" * 16384
- try:
- while True:
- s.sendall(buf)
- except Exception as ex:
- print(ex)
-
- thread = threading.Thread(target=spam)
- thread.start()
-
- time.sleep(1)
-
- received = b""
- while True:
- read = s.recv(512)
- if len(read) == 0:
- break
- received += read
-
- self.assertEquals(1024 * 1024 + len("foo\n"), len(received))
- thread.join()
-
-
if sys.platform == "win32":
# From https://stackoverflow.com/a/38749458
import os
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index ff7a75c..4934f5a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -556,17 +556,11 @@
return mounts;
}
- // Manually check dm state because stunted fstab (w/o system as root) borken
- auto& dm = DeviceMapper::Instance();
- auto found = false;
- for (auto& system : {"system", "vroot"}) {
- if (dm.GetState(system) == DmDeviceState::INVALID) continue;
- std::vector<DeviceMapper::TargetInfo> table;
- found = !dm.GetTableStatus(system, &table) || table.empty() || table[0].data.empty() ||
- (table[0].data[0] == 'C') || (table[0].data[0] == 'V');
- if (found) break;
- }
- if (!found) mounts.emplace_back("/system");
+ // We have a stunted fstab (w/o system or / ) passed in by the caller,
+ // verity claims are assumed accurate because they are collected internally
+ // from fs_mgr_fstab_default() from within fs_mgr_update_verity_state(),
+ // Can (re)evaluate /system with impunity since we know it is ever-present.
+ mounts.emplace_back("/system");
return mounts;
}
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 69dc065..bbdec5b 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -51,6 +51,7 @@
"liblp",
"libbase",
"libfs_mgr",
+ "libsparse",
],
srcs: [
"builder_test.cpp",
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 97b15bd..743a3fe 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -150,7 +150,7 @@
}
BlockDeviceInfo device_info;
if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
- builder->set_block_device_info(device_info);
+ builder->UpdateBlockDeviceInfo(device_info);
}
return builder;
}
@@ -217,10 +217,6 @@
}
}
}
-
- device_info_.alignment = geometry_.alignment;
- device_info_.alignment_offset = geometry_.alignment_offset;
- device_info_.logical_block_size = geometry_.logical_block_size;
return true;
}
@@ -239,24 +235,23 @@
metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
// Check that device properties are sane.
- device_info_ = device_info;
- if (device_info_.size % LP_SECTOR_SIZE != 0) {
+ if (device_info.size % LP_SECTOR_SIZE != 0) {
LERROR << "Block device size must be a multiple of 512.";
return false;
}
- if (device_info_.logical_block_size % LP_SECTOR_SIZE != 0) {
+ if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
LERROR << "Logical block size must be a multiple of 512.";
return false;
}
- if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
+ if (device_info.alignment_offset % LP_SECTOR_SIZE != 0) {
LERROR << "Alignment offset is not sector-aligned.";
return false;
}
- if (device_info_.alignment % LP_SECTOR_SIZE != 0) {
+ if (device_info.alignment % LP_SECTOR_SIZE != 0) {
LERROR << "Partition alignment is not sector-aligned.";
return false;
}
- if (device_info_.alignment_offset > device_info_.alignment) {
+ if (device_info.alignment_offset > device_info.alignment) {
LERROR << "Partition alignment offset is greater than its alignment.";
return false;
}
@@ -267,20 +262,21 @@
uint64_t reserved =
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
uint64_t total_reserved = reserved * 2;
- if (device_info_.size < total_reserved) {
+ if (device_info.size < total_reserved) {
LERROR << "Attempting to create metadata on a block device that is too small.";
return false;
}
// Compute the first free sector, factoring in alignment.
- uint64_t free_area = AlignTo(reserved, device_info_.alignment, device_info_.alignment_offset);
+ uint64_t free_area =
+ AlignTo(total_reserved, device_info.alignment, device_info.alignment_offset);
uint64_t first_sector = free_area / LP_SECTOR_SIZE;
// Compute the last free sector, which is inclusive. We subtract 1 to make
// sure that logical partitions won't overlap with the same sector as the
// backup metadata, which could happen if the block device was not aligned
// to LP_SECTOR_SIZE.
- uint64_t last_sector = ((device_info_.size - reserved) / LP_SECTOR_SIZE) - 1;
+ uint64_t last_sector = (device_info.size / LP_SECTOR_SIZE) - 1;
// If this check fails, it means either (1) we did not have free space to
// allocate a single sector, or (2) we did, but the alignment was high
@@ -296,7 +292,7 @@
// computation, then we abort. Note that the last sector is inclusive,
// so we have to account for that.
uint64_t num_free_sectors = last_sector - first_sector + 1;
- uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
+ uint64_t sectors_per_block = device_info.logical_block_size / LP_SECTOR_SIZE;
if (num_free_sectors < sectors_per_block) {
LERROR << "Not enough space to allocate any partition tables.";
return false;
@@ -307,9 +303,9 @@
geometry_.last_logical_sector = last_sector;
geometry_.metadata_max_size = metadata_max_size;
geometry_.metadata_slot_count = metadata_slot_count;
- geometry_.alignment = device_info_.alignment;
- geometry_.alignment_offset = device_info_.alignment_offset;
- geometry_.block_device_size = device_info_.size;
+ geometry_.alignment = device_info.alignment;
+ geometry_.alignment_offset = device_info.alignment_offset;
+ geometry_.block_device_size = device_info.size;
geometry_.logical_block_size = device_info.logical_block_size;
if (!AddGroup("default", 0)) {
@@ -460,7 +456,7 @@
free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
}
- const uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
+ const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
CHECK_NE(sectors_per_block, 0);
CHECK(sectors_needed % sectors_per_block == 0);
@@ -578,32 +574,44 @@
// Note: when reading alignment info from the Kernel, we don't assume it
// is aligned to the sector size, so we round up to the nearest sector.
uint64_t lba = sector * LP_SECTOR_SIZE;
- uint64_t aligned = AlignTo(lba, device_info_.alignment, device_info_.alignment_offset);
+ uint64_t aligned = AlignTo(lba, geometry_.alignment, geometry_.alignment_offset);
return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
}
-void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
- device_info_.size = device_info.size;
+bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const {
+ info->size = geometry_.block_device_size;
+ info->alignment = geometry_.alignment;
+ info->alignment_offset = geometry_.alignment_offset;
+ info->logical_block_size = geometry_.logical_block_size;
+ return true;
+}
- // Note that if the logical block size changes, we're probably in trouble:
- // we could have already built extents that will only work on the previous
- // size.
- DCHECK(partitions_.empty() ||
- device_info_.logical_block_size == device_info.logical_block_size);
+bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) {
+ if (device_info.size != geometry_.block_device_size) {
+ LERROR << "Device size does not match (got " << device_info.size << ", expected "
+ << geometry_.block_device_size << ")";
+ return false;
+ }
+ if (device_info.logical_block_size != geometry_.logical_block_size) {
+ LERROR << "Device logical block size does not match (got " << device_info.logical_block_size
+ << ", expected " << geometry_.logical_block_size << ")";
+ return false;
+ }
// The kernel does not guarantee these values are present, so we only
// replace existing values if the new values are non-zero.
if (device_info.alignment) {
- device_info_.alignment = device_info.alignment;
+ geometry_.alignment = device_info.alignment;
}
if (device_info.alignment_offset) {
- device_info_.alignment_offset = device_info.alignment_offset;
+ geometry_.alignment_offset = device_info.alignment_offset;
}
+ return true;
}
bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
// Align the space needed up to the nearest sector.
- uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
+ uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
uint64_t old_size = partition->size();
if (aligned_size > old_size) {
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index c916b44..ffa7d3b 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -48,8 +48,8 @@
LinearExtent* extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
- // The first logical sector will be (4096+1024*2)/512 = 12.
- EXPECT_EQ(extent->physical_sector(), 12);
+ // The first logical sector will be (8192+1024*4)/512 = 12.
+ EXPECT_EQ(extent->physical_sector(), 24);
// Test resizing to the same size.
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -78,7 +78,7 @@
extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(extent->physical_sector(), 12);
+ EXPECT_EQ(extent->physical_sector(), 24);
// Test shrinking to 0.
builder->ResizePartition(system, 0);
@@ -127,7 +127,7 @@
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
// Test a large alignment offset thrown in.
device_info.alignment_offset = 753664;
@@ -136,7 +136,7 @@
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
- EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
// Alignment offset without alignment doesn't mean anything.
device_info.alignment = 0;
@@ -150,8 +150,8 @@
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
- EXPECT_EQ(exported->geometry.first_logical_sector, 78);
- EXPECT_EQ(exported->geometry.last_logical_sector, 1973);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 150);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2045);
// Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024;
@@ -159,8 +159,8 @@
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
- EXPECT_EQ(exported->geometry.first_logical_sector, 72);
- EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 160);
+ EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
}
TEST(liblp, InternalPartitionAlignment) {
@@ -247,11 +247,11 @@
ASSERT_NE(system2, nullptr);
ASSERT_NE(vendor1, nullptr);
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
- EXPECT_EQ(system1->physical_sector(), 12);
+ EXPECT_EQ(system1->physical_sector(), 24);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(system2->physical_sector(), 204);
+ EXPECT_EQ(system2->physical_sector(), 216);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(vendor1->physical_sector(), 140);
+ EXPECT_EQ(vendor1->physical_sector(), 152);
EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
}
@@ -297,13 +297,11 @@
EXPECT_EQ(geometry.struct_size, sizeof(geometry));
EXPECT_EQ(geometry.metadata_max_size, 1024);
EXPECT_EQ(geometry.metadata_slot_count, 2);
- EXPECT_EQ(geometry.first_logical_sector, 12);
- EXPECT_EQ(geometry.last_logical_sector, 2035);
+ EXPECT_EQ(geometry.first_logical_sector, 24);
+ EXPECT_EQ(geometry.last_logical_sector, 2047);
static const size_t kMetadataSpace =
- (kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
- uint64_t space_at_end = kDiskSize - (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
- EXPECT_GE(space_at_end, kMetadataSpace);
+ ((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace);
// Verify header.
@@ -361,9 +359,9 @@
LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
- EXPECT_EQ(system1->physical_sector(), 12);
+ EXPECT_EQ(system1->physical_sector(), 24);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(system2->physical_sector(), 204);
+ EXPECT_EQ(system2->physical_sector(), 216);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
}
@@ -437,22 +435,37 @@
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
- EXPECT_EQ(builder->block_device_info().size, device_info.size);
- EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
- EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
- EXPECT_EQ(builder->block_device_info().logical_block_size, device_info.logical_block_size);
+ BlockDeviceInfo new_info;
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+
+ EXPECT_EQ(new_info.size, device_info.size);
+ EXPECT_EQ(new_info.alignment, device_info.alignment);
+ EXPECT_EQ(new_info.alignment_offset, device_info.alignment_offset);
+ EXPECT_EQ(new_info.logical_block_size, device_info.logical_block_size);
device_info.alignment = 0;
device_info.alignment_offset = 2048;
- builder->set_block_device_info(device_info);
- EXPECT_EQ(builder->block_device_info().alignment, 4096);
- EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
+ ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.alignment, 4096);
+ EXPECT_EQ(new_info.alignment_offset, device_info.alignment_offset);
device_info.alignment = 8192;
device_info.alignment_offset = 0;
- builder->set_block_device_info(device_info);
- EXPECT_EQ(builder->block_device_info().alignment, 8192);
- EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
+ ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.alignment, 8192);
+ EXPECT_EQ(new_info.alignment_offset, 2048);
+
+ new_info.size += 4096;
+ ASSERT_FALSE(builder->UpdateBlockDeviceInfo(new_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.size, 1024 * 1024);
+
+ new_info.logical_block_size = 512;
+ ASSERT_FALSE(builder->UpdateBlockDeviceInfo(new_info));
+ ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
+ EXPECT_EQ(new_info.logical_block_size, 4096);
}
TEST(liblp, InvalidBlockSize) {
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 742b1d0..8716988 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -19,8 +19,6 @@
#include <limits.h>
#include <android-base/file.h>
-#include <android-base/unique_fd.h>
-#include <sparse/sparse.h>
#include "reader.h"
#include "utility.h"
@@ -89,41 +87,36 @@
return WriteToImageFile(fd, input);
}
-// We use an object to build the sparse file since it requires that data
-// pointers be held alive until the sparse file is destroyed. It's easier
-// to do this when the data pointers are all in one place.
-class SparseBuilder {
- public:
- SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images);
-
- bool Build();
- bool Export(const char* file);
- bool IsValid() const { return file_ != nullptr; }
-
- private:
- bool AddData(const std::string& blob, uint64_t sector);
- bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
- int OpenImageFile(const std::string& file);
- bool SectorToBlock(uint64_t sector, uint32_t* block);
-
- const LpMetadata& metadata_;
- const LpMetadataGeometry& geometry_;
- uint32_t block_size_;
- std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
- std::string primary_blob_;
- std::string backup_blob_;
- std::map<std::string, std::string> images_;
- std::vector<android::base::unique_fd> temp_fds_;
-};
-
SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
const std::map<std::string, std::string>& images)
: metadata_(metadata),
geometry_(metadata.geometry),
block_size_(block_size),
- file_(sparse_file_new(block_size_, geometry_.block_device_size), sparse_file_destroy),
- images_(images) {}
+ file_(nullptr, sparse_file_destroy),
+ images_(images) {
+ if (block_size % LP_SECTOR_SIZE != 0) {
+ LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
+ return;
+ }
+ if (metadata.geometry.block_device_size % block_size != 0) {
+ LERROR << "Device size must be a multiple of the block size, " << block_size;
+ return;
+ }
+ if (metadata.geometry.metadata_max_size % block_size != 0) {
+ LERROR << "Metadata max size must be a multiple of the block size, " << block_size;
+ return;
+ }
+
+ uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
+ if (num_blocks >= UINT_MAX) {
+ // libsparse counts blocks in unsigned 32-bit integers, so we check to
+ // make sure we're not going to overflow.
+ LERROR << "Block device is too large to encode with libsparse.";
+ return;
+ }
+
+ file_.reset(sparse_file_new(block_size_, geometry_.block_device_size));
+}
bool SparseBuilder::Export(const char* file) {
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
@@ -174,16 +167,12 @@
std::string metadata_blob = SerializeMetadata(metadata_);
metadata_blob.resize(geometry_.metadata_max_size);
- std::string all_metadata;
- for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
- all_metadata += metadata_blob;
+ // Two copies of geometry, then two copies of each metadata slot.
+ all_metadata_ += geometry_blob + geometry_blob;
+ for (size_t i = 0; i < geometry_.metadata_slot_count * 2; i++) {
+ all_metadata_ += metadata_blob;
}
-
- // Metadata immediately follows geometry, and we write the same metadata
- // to all slots. Note that we don't bother trying to write skip chunks
- // here since it's a small amount of data.
- primary_blob_ = geometry_blob + all_metadata;
- if (!AddData(primary_blob_, 0)) {
+ if (!AddData(all_metadata_, 0)) {
return false;
}
@@ -202,17 +191,6 @@
LERROR << "Partition image was specified but no partition was found.";
return false;
}
-
- // The backup area contains all metadata slots, and then geometry. Similar
- // to before we write the metadata to every slot.
- int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
- uint64_t backups_start = geometry_.block_device_size + backup_offset;
- uint64_t backup_sector = backups_start / LP_SECTOR_SIZE;
-
- backup_blob_ = all_metadata + geometry_blob;
- if (!AddData(backup_blob_, backup_sector)) {
- return false;
- }
return true;
}
@@ -336,22 +314,6 @@
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
const std::map<std::string, std::string>& images) {
- if (block_size % LP_SECTOR_SIZE != 0) {
- LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
- return false;
- }
- if (metadata.geometry.block_device_size % block_size != 0) {
- LERROR << "Device size must be a multiple of the block size, " << block_size;
- return false;
- }
- uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
- if (num_blocks >= UINT_MAX) {
- // libsparse counts blocks in unsigned 32-bit integers, so we check to
- // make sure we're not going to overflow.
- LERROR << "Block device is too large to encode with libsparse.";
- return false;
- }
-
SparseBuilder builder(metadata, block_size, images);
if (!builder.IsValid()) {
LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index 3a999b8..a9ef8ce 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -14,7 +14,14 @@
* limitations under the License.
*/
+#include <stdint.h>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <android-base/unique_fd.h>
#include <liblp/liblp.h>
+#include <sparse/sparse.h>
namespace android {
namespace fs_mgr {
@@ -25,5 +32,34 @@
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
bool WriteToImageFile(int fd, const LpMetadata& metadata);
+// We use an object to build the sparse file since it requires that data
+// pointers be held alive until the sparse file is destroyed. It's easier
+// to do this when the data pointers are all in one place.
+class SparseBuilder {
+ public:
+ SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images);
+
+ bool Build();
+ bool Export(const char* file);
+ bool IsValid() const { return file_ != nullptr; }
+
+ sparse_file* file() const { return file_.get(); }
+
+ private:
+ bool AddData(const std::string& blob, uint64_t sector);
+ bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
+ int OpenImageFile(const std::string& file);
+ bool SectorToBlock(uint64_t sector, uint32_t* block);
+
+ const LpMetadata& metadata_;
+ const LpMetadataGeometry& geometry_;
+ uint32_t block_size_;
+ std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
+ std::string all_metadata_;
+ std::map<std::string, std::string> images_;
+ std::vector<android::base::unique_fd> temp_fds_;
+};
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index a6044d0..8dbba84 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -215,10 +215,8 @@
uint64_t AllocatableSpace() const;
uint64_t UsedSpace() const;
- // Merge new block device information into previous values. Alignment values
- // are only overwritten if the new values are non-zero.
- void set_block_device_info(const BlockDeviceInfo& device_info);
- const BlockDeviceInfo& block_device_info() const { return device_info_; }
+ bool GetBlockDeviceInfo(BlockDeviceInfo* info) const;
+ bool UpdateBlockDeviceInfo(const BlockDeviceInfo& info);
private:
MetadataBuilder();
@@ -238,7 +236,6 @@
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
std::vector<std::unique_ptr<PartitionGroup>> groups_;
- BlockDeviceInfo device_info_;
};
// Read BlockDeviceInfo for a given block device. This always returns false
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 7d1a2a9..a4ff1a7 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 3
+#define LP_METADATA_MAJOR_VERSION 4
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -58,13 +58,13 @@
* +--------------------+
* | Disk Geometry |
* +--------------------+
- * | Metadata |
+ * | Geometry Backup |
* +--------------------+
- * | Logical Partitions |
+ * | Metadata |
* +--------------------+
* | Backup Metadata |
* +--------------------+
- * | Geometry Backup |
+ * | Logical Partitions |
* +--------------------+
*/
#define LP_METADATA_DEFAULT_PARTITION_NAME "super"
@@ -72,8 +72,8 @@
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
-/* This structure is stored at sector 0 in the first 4096 bytes of the
- * partition, and again in the very last 4096 bytes. It is never modified and
+/* This structure is stored at block 0 in the first 4096 bytes of the
+ * partition, and again in the following block. It is never modified and
* describes how logical partition information can be located.
*/
typedef struct LpMetadataGeometry {
@@ -99,8 +99,8 @@
uint32_t metadata_slot_count;
/* 48: First usable sector for allocating logical partitions. this will be
- * the first sector after the initial 4096 geometry block, followed by the
- * space consumed by metadata_max_size*metadata_slot_count.
+ * the first sector after the initial geometry blocks, followed by the
+ * space consumed by metadata_max_size*metadata_slot_count*2.
*/
uint64_t first_logical_sector;
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 01de3ac..220d651 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -290,13 +290,13 @@
char corruption[LP_METADATA_GEOMETRY_SIZE];
memset(corruption, 0xff, sizeof(corruption));
- // Corrupt the first 4096 bytes of the disk.
- ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
+ // Corrupt the primary geometry.
+ ASSERT_GE(lseek(fd, GetPrimaryGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
- // Corrupt the last 4096 bytes too.
- ASSERT_GE(lseek(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END), 0);
+ // Corrupt the backup geometry.
+ ASSERT_GE(lseek(fd, GetBackupGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
@@ -310,14 +310,16 @@
char corruption[kMetadataSize];
memset(corruption, 0xff, sizeof(corruption));
- ASSERT_GE(lseek(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET), 0);
+ off_t offset = GetPrimaryMetadataOffset(metadata->geometry, 0);
+
+ ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
- off_t offset = LP_METADATA_GEOMETRY_SIZE + kMetadataSize * 2;
+ offset = GetBackupMetadataOffset(metadata->geometry, 0);
// Corrupt the backup metadata.
- ASSERT_GE(lseek(fd, -offset, SEEK_END), 0);
+ ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
@@ -535,3 +537,36 @@
ASSERT_GE(new_table->partitions.size(), 1);
ASSERT_EQ(GetPartitionName(new_table->partitions[0]), GetPartitionName(imported->partitions[0]));
}
+
+// Test that writing a sparse image can be read back.
+TEST(liblp, FlashSparseImage) {
+ unique_fd fd = CreateFakeDisk();
+ ASSERT_GE(fd, 0);
+
+ BlockDeviceInfo device_info(kDiskSize, 0, 0, 512);
+ unique_ptr<MetadataBuilder> builder =
+ MetadataBuilder::New(device_info, kMetadataSize, kMetadataSlots);
+ ASSERT_NE(builder, nullptr);
+ ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+
+ unique_ptr<LpMetadata> exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+
+ // Build the sparse file.
+ SparseBuilder sparse(*exported.get(), 512, {});
+ ASSERT_TRUE(sparse.IsValid());
+ sparse_file_verbose(sparse.file());
+ ASSERT_TRUE(sparse.Build());
+
+ // Write it to the fake disk.
+ ASSERT_NE(lseek(fd.get(), 0, SEEK_SET), -1);
+ int ret = sparse_file_write(sparse.file(), fd.get(), false, false, false);
+ ASSERT_EQ(ret, 0);
+
+ // Verify that we can read both sets of metadata.
+ LpMetadataGeometry geometry;
+ ASSERT_TRUE(ReadPrimaryGeometry(fd.get(), &geometry));
+ ASSERT_TRUE(ReadBackupGeometry(fd.get(), &geometry));
+ ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
+ ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 005d493..835df9b 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -120,13 +120,9 @@
return true;
}
-// Read and validate geometry information from a block device that holds
-// logical partitions. If the information is corrupted, this will attempt
-// to read it from a secondary backup location.
-bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
- // Read the first 4096 bytes.
+bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
- if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed";
return false;
}
@@ -134,12 +130,12 @@
PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
return false;
}
- if (ParseGeometry(buffer.get(), geometry)) {
- return true;
- }
+ return ParseGeometry(buffer.get(), geometry);
+}
- // Try the backup copy in the last 4096 bytes.
- if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) {
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
+ if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE;
return false;
}
@@ -151,6 +147,16 @@
return ParseGeometry(buffer.get(), geometry);
}
+// Read and validate geometry information from a block device that holds
+// logical partitions. If the information is corrupted, this will attempt
+// to read it from a secondary backup location.
+bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) {
+ if (ReadPrimaryGeometry(fd, geometry)) {
+ return true;
+ }
+ return ReadBackupGeometry(fd, geometry);
+}
+
static bool ValidateTableBounds(const LpMetadataHeader& header,
const LpMetadataTableDescriptor& table) {
if (table.offset > header.tables_size) {
@@ -315,7 +321,7 @@
std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
uint32_t slot_number) {
int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
- if (SeekFile64(fd, offset, SEEK_END) < 0) {
+ if (SeekFile64(fd, offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index 9f6ca6e..24b2611 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -36,6 +36,8 @@
std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, const void* buffer,
size_t size);
bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry);
+bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry);
+bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry);
// These functions assume a valid geometry and slot number.
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index b08f96c..2f7692f 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -56,10 +56,18 @@
return lseek(fd, offset, whence);
}
+int64_t GetPrimaryGeometryOffset() {
+ return 0;
+}
+
+int64_t GetBackupGeometryOffset() {
+ return LP_METADATA_GEOMETRY_SIZE;
+}
+
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
- int64_t offset = LP_METADATA_GEOMETRY_SIZE + geometry.metadata_max_size * slot_number;
+ int64_t offset = (LP_METADATA_GEOMETRY_SIZE * 2) + geometry.metadata_max_size * slot_number;
CHECK(offset + geometry.metadata_max_size <=
int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
return offset;
@@ -67,7 +75,7 @@
int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
- int64_t start = int64_t(-LP_METADATA_GEOMETRY_SIZE) -
+ int64_t start = LP_METADATA_GEOMETRY_SIZE * 2 +
int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
return start + int64_t(geometry.metadata_max_size * slot_number);
}
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 6ef5124..61e7d31 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -38,6 +38,10 @@
// error. After calling this, the position of |fd| may have changed.
bool GetDescriptorSize(int fd, uint64_t* size);
+// Return the offset of the primary or backup geometry.
+int64_t GetPrimaryGeometryOffset();
+int64_t GetBackupGeometryOffset();
+
// Return the offset of a primary metadata slot, relative to the start of the
// device.
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number);
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 7bf42ae..ff50e09 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -42,15 +42,17 @@
0,
1024 * 1024,
4096};
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 4096 + 16384 * 3);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 8192);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 8192 + 16384);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 8192 + 16384 * 2);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 8192 + 16384 * 3);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), -4096 - 16384 * 1);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), -4096 - 16384 * 2);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), -4096 - 16384 * 3);
- EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), -4096 - 16384 * 4);
+ static const uint64_t backup_start = 8192 + 16384 * 4;
+
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3);
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2);
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1);
+ EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), backup_start + 16384 * 0);
}
TEST(liblp, AlignTo) {
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 2415629..0c0cc49 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -106,15 +106,13 @@
// metadata.
uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
- if (reserved_size > blockdevice_size ||
- reserved_size > geometry.first_logical_sector * LP_SECTOR_SIZE) {
+ uint64_t total_reserved = reserved_size * 2;
+
+ if (total_reserved > blockdevice_size ||
+ total_reserved > geometry.first_logical_sector * LP_SECTOR_SIZE) {
LERROR << "Not enough space to store all logical partition metadata slots.";
return false;
}
- if (blockdevice_size - reserved_size < (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE) {
- LERROR << "Not enough space to backup all logical partition metadata slots.";
- return false;
- }
if (blockdevice_size != metadata.geometry.block_device_size) {
LERROR << "Block device size " << blockdevice_size
<< " does not match metadata requested size " << metadata.geometry.block_device_size;
@@ -162,12 +160,12 @@
const std::string& blob,
const std::function<bool(int, const std::string&)>& writer) {
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
- int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_END);
+ int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
if (abs_offset == (int64_t)-1) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset;
return false;
}
- if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) {
+ if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset
<< " is within logical partition bounds, sector " << geometry.last_logical_sector;
return false;
@@ -211,7 +209,7 @@
// Write geometry to the first and last 4096 bytes of the device.
std::string blob = SerializeGeometry(metadata.geometry);
- if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
return false;
}
@@ -219,7 +217,7 @@
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
- if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
+ if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
return false;
}
diff --git a/init/README.md b/init/README.md
index 02a65d5..c56d295 100644
--- a/init/README.md
+++ b/init/README.md
@@ -213,7 +213,8 @@
`interface <interface name> <instance name>`
> Associates this service with a list of the HIDL services that it provides. The interface name
must be a fully-qualified name and not a value name. This is used to allow hwservicemanager to
- lazily start services.
+ lazily start services. When multiple interfaces are served, this tag should be used multiple
+ times.
For example: interface vendor.foo.bar@1.0::IBaz default
`ioprio <class> <priority>`
diff --git a/init/stable_properties.h b/init/stable_properties.h
index 4972d10..baef833 100644
--- a/init/stable_properties.h
+++ b/init/stable_properties.h
@@ -31,6 +31,7 @@
static const std::set<std::string> kExportedActionableProperties = {
"dev.bootcomplete",
"init.svc.console",
+ "init.svc.dumpstatez",
"init.svc.mediadrm",
"init.svc.surfaceflinger",
"init.svc.zygote",
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 4723606..56a0679 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -194,26 +194,26 @@
return true;
}
-void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
+bool Elf::GetInfo(Memory* memory, uint64_t* size) {
if (!IsValidElf(memory)) {
- *valid = false;
- return;
+ return false;
}
*size = 0;
- *valid = true;
- // Now read the section header information.
uint8_t class_type;
if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
- return;
+ return false;
}
+
+ // Get the maximum size of the elf data from the header.
if (class_type == ELFCLASS32) {
ElfInterface32::GetMaxSize(memory, size);
} else if (class_type == ELFCLASS64) {
ElfInterface64::GetMaxSize(memory, size);
} else {
- *valid = false;
+ return false;
}
+ return true;
}
bool Elf::IsValidPc(uint64_t pc) {
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 64005ae..52b7535 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -53,10 +53,8 @@
return nullptr;
}
- bool valid;
uint64_t max_size;
- Elf::GetInfo(memory.get(), &valid, &max_size);
- if (!valid) {
+ if (!Elf::GetInfo(memory.get(), &max_size)) {
// Init as if the whole file is an elf.
if (memory->Init(name, 0)) {
elf_offset = offset;
@@ -109,11 +107,7 @@
// first part of the elf file. This is done if the linker rosegment
// option is used.
std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
- bool valid;
- uint64_t max_size;
- Elf::GetInfo(memory.get(), &valid, &max_size);
- if (valid) {
- // Valid elf, we are done.
+ if (Elf::IsValidElf(memory.get())) {
return memory.release();
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 099cc9e..ee1cd1a 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -190,6 +190,12 @@
FillInDexFrame();
// Clear the dex pc so that we don't repeat this frame later.
regs_->set_dex_pc(0);
+
+ // Make sure there is enough room for the real frame.
+ if (frames_.size() == max_frames_) {
+ last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
+ break;
+ }
}
FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index f4cdbda..9af859d 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -94,7 +94,7 @@
static bool IsValidElf(Memory* memory);
- static void GetInfo(Memory* memory, bool* valid, uint64_t* size);
+ static bool GetInfo(Memory* memory, uint64_t* size);
static uint64_t GetLoadBias(Memory* memory);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 4369030..831d3b5 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -946,6 +946,33 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, dex_pc_max_frames) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ regs_.set_pc(0x1000);
+ regs_.set_sp(0x10000);
+ regs_.FakeSetDexPc(0xa3400);
+
+ Unwinder unwinder(1, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x400U, frame->rel_pc);
+ EXPECT_EQ(0xa3400U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/fake/fake.vdex", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0xa3000U, frame->map_start);
+ EXPECT_EQ(0xa4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame_static) {
FrameData frame;
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 018b1a9..32d7901 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -103,7 +103,8 @@
off64_t offset;
};
-typedef void* ZipArchiveHandle;
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
/*
* Open a Zip archive, and sets handle to the value of the opaque
@@ -144,7 +145,7 @@
* this handle for any further operations without an intervening
* call to one of the OpenArchive variants.
*/
-void CloseArchive(ZipArchiveHandle handle);
+void CloseArchive(ZipArchiveHandle archive);
/*
* Find an entry in the Zip archive, by name. |entryName| must be a null
@@ -162,7 +163,7 @@
* On non-Windows platforms this method does not modify internal state and
* can be called concurrently.
*/
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data);
+int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data);
/*
* Start iterating over all entries of a zip file. The order of iteration
@@ -177,8 +178,8 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
- const ZipString* optional_suffix);
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+ const ZipString* optional_prefix, const ZipString* optional_suffix);
/*
* Advance to the next element in the zipfile in iteration order.
@@ -203,7 +204,7 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd);
+int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
/**
* Uncompress a given zip entry to the memory region at |begin| and of
@@ -213,9 +214,9 @@
*
* Returns 0 on success and negative values on failure.
*/
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size);
+int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size);
-int GetFileDescriptor(const ZipArchiveHandle handle);
+int GetFileDescriptor(const ZipArchiveHandle archive);
const char* ErrorCodeString(int32_t error_code);
@@ -226,7 +227,7 @@
* Stream the uncompressed data through the supplied function,
* passing cookie to it each time it gets called.
*/
-int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
ProcessZipEntryFunction func, void* cookie);
#endif
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6a3db6b..4221ee7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -517,8 +517,7 @@
/*
* Close a ZipArchive, closing the file and freeing the contents.
*/
-void CloseArchive(ZipArchiveHandle handle) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+void CloseArchive(ZipArchiveHandle archive) {
ALOGV("Closing archive %p", archive);
delete archive;
}
@@ -745,10 +744,8 @@
}
};
-int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
- const ZipString* optional_suffix) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
-
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+ const ZipString* optional_prefix, const ZipString* optional_suffix) {
if (archive == NULL || archive->hash_table == NULL) {
ALOGW("Zip: Invalid ZipArchiveHandle");
return kInvalidHandle;
@@ -766,8 +763,7 @@
delete reinterpret_cast<IterationHandle*>(cookie);
}
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data) {
- const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data) {
if (entryName.name_length == 0) {
ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
return kInvalidEntryName;
@@ -1116,8 +1112,7 @@
return 0;
}
-int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer) {
- ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
+int32_t ExtractToWriter(ZipArchiveHandle archive, ZipEntry* entry, zip_archive::Writer* writer) {
const uint16_t method = entry->method;
// this should default to kUnknownCompressionMethod.
@@ -1145,18 +1140,18 @@
return return_value;
}
-int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size) {
+int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size) {
MemoryWriter writer(begin, size);
- return ExtractToWriter(handle, entry, &writer);
+ return ExtractToWriter(archive, entry, &writer);
}
-int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd) {
+int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd) {
auto writer = FileWriter::Create(fd, entry);
if (!writer.IsValid()) {
return kIoError;
}
- return ExtractToWriter(handle, entry, &writer);
+ return ExtractToWriter(archive, entry, &writer);
}
const char* ErrorCodeString(int32_t error_code) {
@@ -1173,8 +1168,8 @@
return "Unknown return code";
}
-int GetFileDescriptor(const ZipArchiveHandle handle) {
- return reinterpret_cast<ZipArchive*>(handle)->mapped_zip.GetFileDescriptor();
+int GetFileDescriptor(const ZipArchiveHandle archive) {
+ return archive->mapped_zip.GetFileDescriptor();
}
ZipString::ZipString(const char* entry_name) : name(reinterpret_cast<const uint8_t*>(entry_name)) {
@@ -1198,10 +1193,10 @@
void* cookie_;
};
-int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
+int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
ProcessZipEntryFunction func, void* cookie) {
ProcessWriter writer(func, cookie);
- return ExtractToWriter(handle, entry, &writer);
+ return ExtractToWriter(archive, entry, &writer);
}
#endif //! defined(_WIN32)
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index 1e2df2f..4d39dd9 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -57,7 +57,7 @@
#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
#define LLK_BLACKLIST_UID_DEFAULT ""
#define LLK_BLACKLIST_STACK_PROPERTY "ro.llk.blacklist.process.stack"
-#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd"
+#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd,apexd"
/* clang-format on */
__END_DECLS
diff --git a/lmkd/include/lmkd.h b/lmkd/include/lmkd.h
index fe6364d..e8f51da 100644
--- a/lmkd/include/lmkd.h
+++ b/lmkd/include/lmkd.h
@@ -30,6 +30,7 @@
LMK_TARGET = 0, /* Associate minfree with oom_adj_score */
LMK_PROCPRIO, /* Register a process and set its oom_adj_score */
LMK_PROCREMOVE, /* Unregister a process */
+ LMK_PROCPURGE, /* Purge all registered processes */
};
/*
@@ -142,6 +143,15 @@
return 2 * sizeof(int);
}
+/*
+ * Prepare LMK_PROCPURGE packet and return packet size in bytes.
+ * Warning: no checks performed, caller should ensure valid parameters.
+ */
+inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
+ packet[0] = htonl(LMK_PROCPURGE);
+ return sizeof(int);
+}
+
__END_DECLS
#endif /* _LMKD_H_ */
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 8b68dca..3a3d5db 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -612,9 +612,38 @@
}
lmkd_pack_get_procremove(packet, ¶ms);
+ /*
+ * WARNING: After pid_remove() procp is freed and can't be used!
+ * Therefore placed at the end of the function.
+ */
pid_remove(params.pid);
}
+static void cmd_procpurge() {
+ int i;
+ struct proc *procp;
+ struct proc *next;
+
+ if (use_inkernel_interface) {
+ return;
+ }
+
+ for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
+ procadjslot_list[i].next = &procadjslot_list[i];
+ procadjslot_list[i].prev = &procadjslot_list[i];
+ }
+
+ for (i = 0; i < PIDHASH_SZ; i++) {
+ procp = pidhash[i];
+ while (procp) {
+ next = procp->pidhash_next;
+ free(procp);
+ procp = next;
+ }
+ }
+ memset(&pidhash[0], 0, sizeof(pidhash));
+}
+
static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet) {
int i;
struct lmk_target target;
@@ -757,6 +786,11 @@
goto wronglen;
cmd_procremove(packet);
break;
+ case LMK_PROCPURGE:
+ if (nargs != 0)
+ goto wronglen;
+ cmd_procpurge();
+ break;
default:
ALOGE("Received unknown command code %d", cmd);
return;
@@ -1135,6 +1169,7 @@
char *taskname;
int tasksize;
int r;
+ int result = -1;
#ifdef LMKD_LOG_STATS
struct memory_stat mem_st = {};
@@ -1143,14 +1178,12 @@
taskname = proc_get_name(pid);
if (!taskname) {
- pid_remove(pid);
- return -1;
+ goto out;
}
tasksize = proc_get_size(pid);
if (tasksize <= 0) {
- pid_remove(pid);
- return -1;
+ goto out;
}
#ifdef LMKD_LOG_STATS
@@ -1169,13 +1202,12 @@
r = kill(pid, SIGKILL);
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
taskname, pid, uid, procp->oomadj, tasksize * page_k);
- pid_remove(pid);
TRACE_KILL_END();
if (r) {
ALOGE("kill(%d): errno=%d", pid, errno);
- return -1;
+ goto out;
} else {
#ifdef LMKD_LOG_STATS
if (memory_stat_parse_result == 0) {
@@ -1187,10 +1219,16 @@
-1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1);
}
#endif
- return tasksize;
+ result = tasksize;
}
- return tasksize;
+out:
+ /*
+ * WARNING: After pid_remove() procp is freed and can't be used!
+ * Therefore placed at the end of the function.
+ */
+ pid_remove(pid);
+ return result;
}
/*
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 658e079..bd17555 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -42,7 +42,7 @@
LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
- entry = (*it);
+ entry = it->get();
if (entry->mClient == client) {
if (!entry->isWatchingMultiple(mLogMask)) {
LogTimeEntry::unlock();
@@ -63,31 +63,12 @@
}
}
entry->triggerReader_Locked();
- if (entry->runningReader_Locked()) {
- LogTimeEntry::unlock();
- return;
- }
- entry->incRef_Locked();
- break;
+ LogTimeEntry::unlock();
+ return;
}
it++;
}
- if (it == times.end()) {
- // Create LogTimeEntry in notifyNewLog() ?
- if (mTail == (unsigned long)-1) {
- LogTimeEntry::unlock();
- return;
- }
- entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask,
- mPid, mStart, mTimeout);
- times.push_front(entry);
- }
-
- client->incRef();
-
- // release client and entry reference counts once done
- entry->startReader_Locked();
LogTimeEntry::unlock();
}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 543dfc3..ceaf393 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -27,36 +27,11 @@
class FlushCommand : public SocketClientCommand {
LogReader& mReader;
- bool mNonBlock;
- unsigned long mTail;
log_mask_t mLogMask;
- pid_t mPid;
- log_time mStart;
- uint64_t mTimeout;
public:
- // for opening a reader
- explicit FlushCommand(LogReader& reader, bool nonBlock, unsigned long tail,
- log_mask_t logMask, pid_t pid, log_time start,
- uint64_t timeout)
- : mReader(reader),
- mNonBlock(nonBlock),
- mTail(tail),
- mLogMask(logMask),
- mPid(pid),
- mStart(start),
- mTimeout((start != log_time::EPOCH) ? timeout : 0) {
- }
-
- // for notification of an update
explicit FlushCommand(LogReader& reader, log_mask_t logMask)
- : mReader(reader),
- mNonBlock(false),
- mTail(-1),
- mLogMask(logMask),
- mPid(0),
- mStart(log_time::EPOCH),
- mTimeout(0) {
+ : mReader(reader), mLogMask(logMask) {
}
virtual void runSocketCommand(SocketClient* client);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index fd1b8b2..fbdbf79 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -105,10 +105,8 @@
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
- if (entry->owned_Locked()) {
- entry->triggerReader_Locked();
- }
+ LogTimeEntry* entry = times->get();
+ entry->triggerReader_Locked();
times++;
}
@@ -409,17 +407,15 @@
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
- if (entry->owned_Locked()) {
- if (!entry->mNonBlock) {
- end_always = true;
- break;
- }
- // it passing mEnd is blocked by the following checks.
- if (!end_set || (end <= entry->mEnd)) {
- end = entry->mEnd;
- end_set = true;
- }
+ LogTimeEntry* entry = times->get();
+ if (!entry->mNonBlock) {
+ end_always = true;
+ break;
+ }
+ // it passing mEnd is blocked by the following checks.
+ if (!end_set || (end <= entry->mEnd)) {
+ end = entry->mEnd;
+ end_set = true;
}
times++;
}
@@ -710,8 +706,8 @@
// Region locked?
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
- if (entry->owned_Locked() && entry->isWatching(id) &&
+ LogTimeEntry* entry = times->get();
+ if (entry->isWatching(id) &&
(!oldest || (oldest->mStart > entry->mStart) ||
((oldest->mStart == entry->mStart) &&
(entry->mTimeout.tv_sec || entry->mTimeout.tv_nsec)))) {
@@ -1052,9 +1048,9 @@
LogTimeEntry::wrlock();
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
- LogTimeEntry* entry = (*times);
+ LogTimeEntry* entry = times->get();
// Killer punch
- if (entry->owned_Locked() && entry->isWatching(id)) {
+ if (entry->isWatching(id)) {
entry->release_Locked();
}
times++;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 2b6556d..13c7af3 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -41,6 +41,7 @@
runOnEachSocket(&command);
}
+// Note returning false will release the SocketClient instance.
bool LogReader::onDataAvailable(SocketClient* cli) {
static bool name_set;
if (!name_set) {
@@ -57,6 +58,18 @@
}
buffer[len] = '\0';
+ // Clients are only allowed to send one command, disconnect them if they
+ // send another.
+ LogTimeEntry::wrlock();
+ for (const auto& entry : mLogbuf.mTimes) {
+ if (entry->mClient == cli) {
+ entry->release_Locked();
+ LogTimeEntry::unlock();
+ return false;
+ }
+ }
+ LogTimeEntry::unlock();
+
unsigned long tail = 0;
static const char _tail[] = " tail=";
char* cp = strstr(buffer, _tail);
@@ -199,14 +212,25 @@
cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
logMask, (int)pid, sequence.nsec(), timeout);
- FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
+ LogTimeEntry::wrlock();
+ auto entry = std::make_unique<LogTimeEntry>(
+ *this, cli, nonBlock, tail, logMask, pid, sequence, timeout);
+ if (!entry->startReader_Locked()) {
+ LogTimeEntry::unlock();
+ return false;
+ }
+
+ // release client and entry reference counts once done
+ cli->incRef();
+ mLogbuf.mTimes.emplace_front(std::move(entry));
// Set acceptable upper limit to wait for slow reader processing b/27242723
struct timeval t = { LOGD_SNDTIMEO, 0 };
setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
sizeof(t));
- command.runSocketCommand(cli);
+ LogTimeEntry::unlock();
+
return true;
}
@@ -215,9 +239,8 @@
LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
- LogTimeEntry* entry = (*it);
+ LogTimeEntry* entry = it->get();
if (entry->mClient == cli) {
- times.erase(it);
entry->release_Locked();
break;
}
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 7a6f84b..1715501 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -30,11 +30,7 @@
LogTimeEntry::LogTimeEntry(LogReader& reader, SocketClient* client,
bool nonBlock, unsigned long tail, log_mask_t logMask,
pid_t pid, log_time start, uint64_t timeout)
- : mRefCount(1),
- mRelease(false),
- mError(false),
- threadRunning(false),
- leadingDropped(false),
+ : leadingDropped(false),
mReader(reader),
mLogMask(logMask),
mPid(pid),
@@ -52,65 +48,21 @@
cleanSkip_Locked();
}
-void LogTimeEntry::startReader_Locked(void) {
+bool LogTimeEntry::startReader_Locked() {
pthread_attr_t attr;
- threadRunning = true;
-
if (!pthread_attr_init(&attr)) {
if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
this)) {
pthread_attr_destroy(&attr);
- return;
+ return true;
}
}
pthread_attr_destroy(&attr);
}
- threadRunning = false;
- if (mClient) {
- mClient->decRef();
- }
- decRef_Locked();
-}
-void LogTimeEntry::threadStop(void* obj) {
- LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
-
- wrlock();
-
- if (me->mNonBlock) {
- me->error_Locked();
- }
-
- SocketClient* client = me->mClient;
-
- if (me->isError_Locked()) {
- LogReader& reader = me->mReader;
- LastLogTimes& times = reader.logbuf().mTimes;
-
- LastLogTimes::iterator it = times.begin();
- while (it != times.end()) {
- if (*it == me) {
- times.erase(it);
- me->release_nodelete_Locked();
- break;
- }
- it++;
- }
-
- me->mClient = nullptr;
- reader.release(client);
- }
-
- if (client) {
- client->decRef();
- }
-
- me->threadRunning = false;
- me->decRef_Locked();
-
- unlock();
+ return false;
}
void* LogTimeEntry::threadStart(void* obj) {
@@ -118,13 +70,7 @@
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
- pthread_cleanup_push(threadStop, obj);
-
SocketClient* client = me->mClient;
- if (!client) {
- me->error();
- return nullptr;
- }
LogBuffer& logbuf = me->mReader.logbuf();
@@ -137,14 +83,14 @@
log_time start = me->mStart;
- while (me->threadRunning && !me->isError_Locked()) {
+ while (!me->mRelease) {
if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
if (pthread_cond_timedwait(&me->threadTriggeredCondition,
×Lock, &me->mTimeout) == ETIMEDOUT) {
me->mTimeout.tv_sec = 0;
me->mTimeout.tv_nsec = 0;
}
- if (!me->threadRunning || me->isError_Locked()) {
+ if (me->mRelease) {
break;
}
}
@@ -162,13 +108,12 @@
wrlock();
if (start == LogBufferElement::FLUSH_ERROR) {
- me->error_Locked();
break;
}
me->mStart = start + log_time(0, 1);
- if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
+ if (me->mNonBlock || me->mRelease) {
break;
}
@@ -179,9 +124,21 @@
}
}
- unlock();
+ LogReader& reader = me->mReader;
+ reader.release(client);
- pthread_cleanup_pop(true);
+ client->decRef();
+
+ LastLogTimes& times = reader.logbuf().mTimes;
+ auto it =
+ std::find_if(times.begin(), times.end(),
+ [&me](const auto& other) { return other.get() == me; });
+
+ if (it != times.end()) {
+ times.erase(it);
+ }
+
+ unlock();
return nullptr;
}
@@ -247,10 +204,6 @@
goto skip;
}
- if (me->isError_Locked()) {
- goto stop;
- }
-
if (!me->mTail) {
goto ok;
}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 76d016c..f4e165f 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -22,6 +22,7 @@
#include <time.h>
#include <list>
+#include <memory>
#include <log/log.h>
#include <sysutils/SocketClient.h>
@@ -33,16 +34,12 @@
class LogTimeEntry {
static pthread_mutex_t timesLock;
- unsigned int mRefCount;
- bool mRelease;
- bool mError;
- bool threadRunning;
+ bool mRelease = false;
bool leadingDropped;
pthread_cond_t threadTriggeredCondition;
pthread_t mThread;
LogReader& mReader;
static void* threadStart(void* me);
- static void threadStop(void* me);
const log_mask_t mLogMask;
const pid_t mPid;
unsigned int skipAhead[LOG_ID_MAX];
@@ -73,11 +70,8 @@
pthread_mutex_unlock(×Lock);
}
- void startReader_Locked(void);
+ bool startReader_Locked();
- bool runningReader_Locked(void) const {
- return threadRunning || mRelease || mError || mNonBlock;
- }
void triggerReader_Locked(void) {
pthread_cond_signal(&threadTriggeredCondition);
}
@@ -87,54 +81,11 @@
}
void cleanSkip_Locked(void);
- // These called after LogTimeEntry removed from list, lock implicitly held
- void release_nodelete_Locked(void) {
- mRelease = true;
- pthread_cond_signal(&threadTriggeredCondition);
- // assumes caller code path will call decRef_Locked()
- }
-
void release_Locked(void) {
mRelease = true;
pthread_cond_signal(&threadTriggeredCondition);
- if (mRefCount || threadRunning) {
- return;
- }
- // No one else is holding a reference to this
- delete this;
}
- // Called to mark socket in jeopardy
- void error_Locked(void) {
- mError = true;
- }
- void error(void) {
- wrlock();
- error_Locked();
- unlock();
- }
-
- bool isError_Locked(void) const {
- return mRelease || mError;
- }
-
- // Mark Used
- // Locking implied, grabbed when protection around loop iteration
- void incRef_Locked(void) {
- ++mRefCount;
- }
-
- bool owned_Locked(void) const {
- return mRefCount != 0;
- }
-
- void decRef_Locked(void) {
- if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
- return;
- }
- // No one else is holding a reference to this
- delete this;
- }
bool isWatching(log_id_t id) const {
return mLogMask & (1 << id);
}
@@ -146,6 +97,6 @@
static int FilterSecondPass(const LogBufferElement* element, void* me);
};
-typedef std::list<LogTimeEntry*> LastLogTimes;
+typedef std::list<std::unique_ptr<LogTimeEntry>> LastLogTimes;
#endif // _LOGD_LOG_TIMES_H__
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index a4c3955..e4e1650 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -67,6 +67,13 @@
LOCAL_REQUIRED_MODULES := asan.options $(ASAN_OPTIONS_FILES) $(ASAN_EXTRACT_FILES)
endif
+EXPORT_GLOBAL_HWASAN_OPTIONS :=
+ifneq ($(filter hwaddress,$(SANITIZE_TARGET)),)
+ ifneq ($(HWADDRESS_SANITIZER_GLOBAL_OPTIONS),)
+ EXPORT_GLOBAL_HWASAN_OPTIONS := export HWASAN_OPTIONS $(HWADDRESS_SANITIZER_GLOBAL_OPTIONS)
+ endif
+endif
+
EXPORT_GLOBAL_GCOV_OPTIONS :=
ifeq ($(NATIVE_COVERAGE),true)
EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/gcov
@@ -151,6 +158,7 @@
$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
+ $(hide) sed -i -e 's?%EXPORT_GLOBAL_HWASAN_OPTIONS%?$(EXPORT_GLOBAL_HWASAN_OPTIONS)?g' $@
bcp_md5 :=
bcp_dep :=
diff --git a/rootdir/OWNERS b/rootdir/OWNERS
index 6029ae7..ca22eb8 100644
--- a/rootdir/OWNERS
+++ b/rootdir/OWNERS
@@ -1,3 +1,4 @@
+ccross@google.com
jeffv@google.com
jiyong@google.com
smoreland@google.com
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 2e2ab74..4576776 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -11,3 +11,4 @@
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
%EXPORT_GLOBAL_ASAN_OPTIONS%
%EXPORT_GLOBAL_GCOV_OPTIONS%
+ %EXPORT_GLOBAL_HWASAN_OPTIONS%