Merge "Load libbacktrace_test.so explicitly."
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 6e143c1..e38e305 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -841,14 +841,19 @@
         return -1;
     }
 
-    std::string service = android::base::StringPrintf(
-        "sideload-host:%d:%d", static_cast<int>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
+    std::string service =
+            android::base::StringPrintf("sideload-host:%" PRId64 ":%d",
+                                        static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
     std::string error;
     unique_fd device_fd(adb_connect(service, &error));
     if (device_fd < 0) {
-        // Try falling back to the older (<= K) sideload method. Maybe this
-        // is an older device that doesn't support sideload-host.
         fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str());
+
+        // If this is a small enough package, maybe this is an older device that doesn't
+        // support sideload-host. Try falling back to the older (<= K) sideload method.
+        if (sb.st_size > INT_MAX) {
+            return -1;
+        }
         fprintf(stderr, "adb: trying pre-KitKat sideload method...\n");
         return adb_sideload_legacy(filename, package_fd, static_cast<int>(sb.st_size));
     }
@@ -858,7 +863,7 @@
 
     char buf[SIDELOAD_HOST_BLOCK_SIZE];
 
-    size_t xfer = 0;
+    int64_t xfer = 0;
     int last_percent = -1;
     while (true) {
         if (!ReadFdExactly(device_fd, buf, 8)) {
@@ -874,20 +879,22 @@
             return 0;
         }
 
-        int block = strtol(buf, nullptr, 10);
-
-        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
-        if (offset >= static_cast<size_t>(sb.st_size)) {
-            fprintf(stderr, "adb: failed to read block %d past end\n", block);
+        int64_t block = strtoll(buf, nullptr, 10);
+        int64_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset >= static_cast<int64_t>(sb.st_size)) {
+            fprintf(stderr,
+                    "adb: failed to read block %" PRId64 " at offset %" PRId64 ", past end %" PRId64
+                    "\n",
+                    block, offset, static_cast<int64_t>(sb.st_size));
             return -1;
         }
 
         size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
-        if ((offset + SIDELOAD_HOST_BLOCK_SIZE) > static_cast<size_t>(sb.st_size)) {
+        if ((offset + SIDELOAD_HOST_BLOCK_SIZE) > static_cast<int64_t>(sb.st_size)) {
             to_write = sb.st_size - offset;
         }
 
-        if (adb_lseek(package_fd, offset, SEEK_SET) != static_cast<int>(offset)) {
+        if (adb_lseek(package_fd, offset, SEEK_SET) != offset) {
             fprintf(stderr, "adb: failed to seek to package block: %s\n", strerror(errno));
             return -1;
         }
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index be0bdd0..b8d7e06 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -52,10 +52,11 @@
 #include <fcntl.h>
 #include <io.h>
 #include <process.h>
+#include <stdint.h>
 #include <sys/stat.h>
 #include <utime.h>
-#include <winsock2.h>
 #include <windows.h>
+#include <winsock2.h>
 #include <ws2tcpip.h>
 
 #include <memory>   // unique_ptr
@@ -92,7 +93,7 @@
 extern int adb_creat(const char* path, int mode);
 extern int adb_read(int fd, void* buf, int len);
 extern int adb_write(int fd, const void* buf, int len);
-extern int adb_lseek(int fd, int pos, int where);
+extern int64_t adb_lseek(int fd, int64_t pos, int where);
 extern int adb_shutdown(int fd, int direction = SHUT_RDWR);
 extern int adb_close(int fd);
 extern int adb_register_socket(SOCKET s);
@@ -315,25 +316,24 @@
 
 #else /* !_WIN32 a.k.a. Unix */
 
-#include <cutils/sockets.h>
 #include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
+#include <poll.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include <string>
 
+#include <cutils/sockets.h>
+
 #define OS_PATH_SEPARATORS "/"
 #define OS_PATH_SEPARATOR '/'
 #define OS_PATH_SEPARATOR_STR "/"
@@ -443,12 +443,15 @@
 #undef   write
 #define  write  ___xxx_write
 
-static __inline__ int   adb_lseek(int  fd, int  pos, int  where)
-{
+static __inline__ int64_t adb_lseek(int fd, int64_t pos, int where) {
+#if defined(__APPLE__)
     return lseek(fd, pos, where);
+#else
+    return lseek64(fd, pos, where);
+#endif
 }
-#undef   lseek
-#define  lseek   ___xxx_lseek
+#undef lseek
+#define lseek ___xxx_lseek
 
 static __inline__  int    adb_unlink(const char*  path)
 {
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 026dd1c..8784757 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -52,12 +52,11 @@
 
 typedef const struct FHClassRec_* FHClass;
 typedef struct FHRec_* FH;
-typedef struct EventHookRec_* EventHook;
 
 typedef struct FHClassRec_ {
     void (*_fh_init)(FH);
     int (*_fh_close)(FH);
-    int (*_fh_lseek)(FH, int, int);
+    int64_t (*_fh_lseek)(FH, int64_t, int);
     int (*_fh_read)(FH, void*, int);
     int (*_fh_write)(FH, const void*, int);
     int (*_fh_writev)(FH, const adb_iovec*, int);
@@ -65,7 +64,7 @@
 
 static void _fh_file_init(FH);
 static int _fh_file_close(FH);
-static int _fh_file_lseek(FH, int, int);
+static int64_t _fh_file_lseek(FH, int64_t, int);
 static int _fh_file_read(FH, void*, int);
 static int _fh_file_write(FH, const void*, int);
 static int _fh_file_writev(FH, const adb_iovec*, int);
@@ -81,7 +80,7 @@
 
 static void _fh_socket_init(FH);
 static int _fh_socket_close(FH);
-static int _fh_socket_lseek(FH, int, int);
+static int64_t _fh_socket_lseek(FH, int64_t, int);
 static int _fh_socket_read(FH, void*, int);
 static int _fh_socket_write(FH, const void*, int);
 static int _fh_socket_writev(FH, const adb_iovec*, int);
@@ -318,10 +317,8 @@
     return wrote_bytes;
 }
 
-static int _fh_file_lseek(FH f, int pos, int origin) {
+static int64_t _fh_file_lseek(FH f, int64_t pos, int origin) {
     DWORD method;
-    DWORD result;
-
     switch (origin) {
         case SEEK_SET:
             method = FILE_BEGIN;
@@ -337,14 +334,13 @@
             return -1;
     }
 
-    result = SetFilePointer(f->fh_handle, pos, nullptr, method);
-    if (result == INVALID_SET_FILE_POINTER) {
+    LARGE_INTEGER li = {.QuadPart = pos};
+    if (!SetFilePointerEx(f->fh_handle, li, &li, method)) {
         errno = EIO;
         return -1;
-    } else {
-        f->eof = 0;
     }
-    return (int)result;
+    f->eof = 0;
+    return li.QuadPart;
 }
 
 /**************************************************************************/
@@ -491,14 +487,12 @@
     return f->clazz->_fh_writev(f, iov, iovcnt);
 }
 
-int adb_lseek(int fd, int pos, int where) {
+int64_t adb_lseek(int fd, int64_t pos, int where) {
     FH f = _fh_from_int(fd, __func__);
-
     if (!f) {
         errno = EBADF;
         return -1;
     }
-
     return f->clazz->_fh_lseek(f, pos, where);
 }
 
@@ -644,7 +638,7 @@
     return 0;
 }
 
-static int _fh_socket_lseek(FH f, int pos, int origin) {
+static int64_t _fh_socket_lseek(FH f, int64_t pos, int origin) {
     errno = EPIPE;
     return -1;
 }
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index d29ccf4..1598a5c 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -529,8 +529,18 @@
     errno = 0;
     ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
     save_errno = errno;
-    PINFO << __FUNCTION__ << "(source=" << source << ",target=" << target
-          << ",type=" << rec->fs_type << ")=" << ret;
+    const char* target_missing = "";
+    const char* source_missing = "";
+    if (save_errno == ENOENT) {
+        if (access(target, F_OK)) {
+            target_missing = "(missing)";
+        } else if (access(source, F_OK)) {
+            source_missing = "(missing)";
+        }
+        errno = save_errno;
+    }
+    PINFO << __FUNCTION__ << "(source=" << source << source_missing << ",target=" << target
+          << target_missing << ",type=" << rec->fs_type << ")=" << ret;
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_mgr_set_blk_ro(source);
     }
@@ -840,7 +850,7 @@
 }
 
 bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
-    if (fs_mgr_is_checkpoint(rec)) {
+    if (fs_mgr_is_checkpoint_fs(rec)) {
         if (!strcmp(rec->fs_type, "f2fs")) {
             std::string opts(rec->fs_options);
 
@@ -850,9 +860,42 @@
         } else {
             LERROR << rec->fs_type << " does not implement checkpoints.";
         }
-    } else if (rec->fs_mgr_flags & MF_CHECKPOINT_BLK) {
-        LERROR << "Block based checkpoint not implemented.";
-        return false;
+    } else if (fs_mgr_is_checkpoint_blk(rec)) {
+        call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+
+        android::base::unique_fd fd(
+                TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+        if (!fd) {
+            PERROR << "Cannot open device " << rec->blk_device;
+            return false;
+        }
+
+        uint64_t size = get_block_device_size(fd) / 512;
+        if (!size) {
+            PERROR << "Cannot get device size";
+            return false;
+        }
+
+        android::dm::DmTable table;
+        if (!table.AddTarget(
+                    std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+            LERROR << "Failed to add Bow target";
+            return false;
+        }
+
+        DeviceMapper& dm = DeviceMapper::Instance();
+        if (!dm.CreateDevice("bow", table)) {
+            PERROR << "Failed to create bow device";
+            return false;
+        }
+
+        std::string name;
+        if (!dm.GetDmDevicePathByName("bow", &name)) {
+            PERROR << "Failed to get bow device name";
+            return false;
+        }
+
+        rec->blk_device = strdup(name.c_str());
     }
     return true;
 }
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index aab89e5..175b0f0 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -156,6 +156,20 @@
     std::string target_string_;
 };
 
+// dm-bow is the backup on write target that can provide checkpoint capability
+// for file systems that do not support checkpoints natively
+class DmTargetBow final : public DmTarget {
+  public:
+    DmTargetBow(uint64_t start, uint64_t length, const std::string& target_string)
+        : DmTarget(start, length), target_string_(target_string) {}
+
+    std::string name() const override { return "bow"; }
+    std::string GetParameterString() const override { return target_string_; }
+
+  private:
+    std::string target_string_;
+};
+
 }  // namespace dm
 }  // namespace android
 
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 352647b..d9a0e9c 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -79,8 +79,9 @@
     out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0});
 }
 
-Partition::Partition(const std::string& name, const std::string& guid, uint32_t attributes)
-    : name_(name), guid_(guid), attributes_(attributes), size_(0) {}
+Partition::Partition(const std::string& name, const std::string& group_name,
+                     const std::string& guid, uint32_t attributes)
+    : name_(name), group_name_(group_name), guid_(guid), attributes_(attributes), size_(0) {}
 
 void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
     size_ += extent->num_sectors() * LP_SECTOR_SIZE;
@@ -128,6 +129,17 @@
     DCHECK(size_ == aligned_size);
 }
 
+uint64_t Partition::BytesOnDisk() const {
+    uint64_t sectors = 0;
+    for (const auto& extent : extents_) {
+        if (!extent->AsLinearExtent()) {
+            continue;
+        }
+        sectors += extent->num_sectors();
+    }
+    return sectors * LP_SECTOR_SIZE;
+}
+
 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_device,
                                                       uint32_t slot_number) {
     std::unique_ptr<LpMetadata> metadata = ReadMetadata(block_device.c_str(), slot_number);
@@ -175,14 +187,23 @@
     header_.header_size = sizeof(header_);
     header_.partitions.entry_size = sizeof(LpMetadataPartition);
     header_.extents.entry_size = sizeof(LpMetadataExtent);
+    header_.groups.entry_size = sizeof(LpMetadataPartitionGroup);
 }
 
 bool MetadataBuilder::Init(const LpMetadata& metadata) {
     geometry_ = metadata.geometry;
 
+    for (const auto& group : metadata.groups) {
+        std::string group_name = GetPartitionGroupName(group);
+        if (!AddGroup(group_name, group.maximum_size)) {
+            return false;
+        }
+    }
+
     for (const auto& partition : metadata.partitions) {
-        Partition* builder = AddPartition(GetPartitionName(partition), GetPartitionGuid(partition),
-                                          partition.attributes);
+        std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
+        Partition* builder = AddPartition(GetPartitionName(partition), group_name,
+                                          GetPartitionGuid(partition), partition.attributes);
         if (!builder) {
             return false;
         }
@@ -292,11 +313,29 @@
     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)) {
+        return false;
+    }
+    return true;
+}
+
+bool MetadataBuilder::AddGroup(const std::string& group_name, uint64_t maximum_size) {
+    if (FindGroup(group_name)) {
+        LERROR << "Group already exists: " << group_name;
+        return false;
+    }
+    groups_.push_back(std::make_unique<PartitionGroup>(group_name, maximum_size));
     return true;
 }
 
 Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& guid,
                                          uint32_t attributes) {
+    return AddPartition(name, "default", guid, attributes);
+}
+
+Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& group_name,
+                                         const std::string& guid, uint32_t attributes) {
     if (name.empty()) {
         LERROR << "Partition must have a non-empty name.";
         return nullptr;
@@ -305,7 +344,11 @@
         LERROR << "Attempting to create duplication partition with name: " << name;
         return nullptr;
     }
-    partitions_.push_back(std::make_unique<Partition>(name, guid, attributes));
+    if (!FindGroup(group_name)) {
+        LERROR << "Could not find partition group: " << group_name;
+        return nullptr;
+    }
+    partitions_.push_back(std::make_unique<Partition>(name, group_name, guid, attributes));
     return partitions_.back().get();
 }
 
@@ -318,6 +361,26 @@
     return nullptr;
 }
 
+PartitionGroup* MetadataBuilder::FindGroup(const std::string& group_name) const {
+    for (const auto& group : groups_) {
+        if (group->name() == group_name) {
+            return group.get();
+        }
+    }
+    return nullptr;
+}
+
+uint64_t MetadataBuilder::TotalSizeOfGroup(PartitionGroup* group) const {
+    uint64_t total = 0;
+    for (const auto& partition : partitions_) {
+        if (partition->group_name() != group->name()) {
+            continue;
+        }
+        total += partition->BytesOnDisk();
+    }
+    return total;
+}
+
 void MetadataBuilder::RemovePartition(const std::string& name) {
     for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
         if ((*iter)->name() == name) {
@@ -328,8 +391,23 @@
 }
 
 bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
-    // Figure out how much we need to allocate.
+    PartitionGroup* group = FindGroup(partition->group_name());
+    CHECK(group);
+
+    // Figure out how much we need to allocate, and whether our group has
+    // enough space remaining.
     uint64_t space_needed = aligned_size - partition->size();
+    if (group->maximum_size() > 0) {
+        uint64_t group_size = TotalSizeOfGroup(group);
+        if (group_size >= group->maximum_size() ||
+            group->maximum_size() - group_size < space_needed) {
+            LERROR << "Partition " << partition->name() << " is part of group " << group->name()
+                   << " which does not have enough space free (" << space_needed << "requested, "
+                   << group_size << " used out of " << group->maximum_size();
+            return false;
+        }
+    }
+
     uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
     DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
 
@@ -441,6 +519,20 @@
     metadata->header = header_;
     metadata->geometry = geometry_;
 
+    std::map<std::string, size_t> group_indices;
+    for (const auto& group : groups_) {
+        LpMetadataPartitionGroup out = {};
+
+        if (group->name().size() > sizeof(out.name)) {
+            LERROR << "Partition group name is too long: " << group->name();
+            return nullptr;
+        }
+        strncpy(out.name, group->name().c_str(), sizeof(out.name));
+        out.maximum_size = group->maximum_size();
+
+        metadata->groups.push_back(out);
+    }
+
     // Flatten the partition and extent structures into an LpMetadata, which
     // makes it very easy to validate, serialize, or pass on to device-mapper.
     for (const auto& partition : partitions_) {
@@ -475,6 +567,7 @@
 
     metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
     metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
+    metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size());
     return metadata;
 }
 
@@ -530,8 +623,10 @@
         ShrinkPartition(partition, aligned_size);
     }
 
-    LINFO << "Partition " << partition->name() << " will resize from " << old_size << " bytes to "
-          << aligned_size << " bytes";
+    if (partition->size() != old_size) {
+        LINFO << "Partition " << partition->name() << " will resize from " << old_size
+              << " bytes to " << aligned_size << " bytes";
+    }
     return true;
 }
 
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 0c7e43d..711cc64 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -495,3 +495,28 @@
     unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
     ASSERT_EQ(builder, nullptr);
 }
+
+TEST(liblp, HasDefaultGroup) {
+    BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+    ASSERT_NE(builder, nullptr);
+
+    EXPECT_FALSE(builder->AddGroup("default", 0));
+}
+
+TEST(liblp, GroupSizeLimits) {
+    BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+    ASSERT_NE(builder, nullptr);
+
+    ASSERT_TRUE(builder->AddGroup("google", 16384));
+
+    Partition* partition = builder->AddPartition("system", "google", TEST_GUID, 0);
+    ASSERT_NE(partition, nullptr);
+    EXPECT_TRUE(builder->ResizePartition(partition, 8192));
+    EXPECT_EQ(partition->size(), 8192);
+    EXPECT_TRUE(builder->ResizePartition(partition, 16384));
+    EXPECT_EQ(partition->size(), 16384);
+    EXPECT_FALSE(builder->ResizePartition(partition, 32768));
+    EXPECT_EQ(partition->size(), 16384);
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 2780825..f1edee7 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -95,11 +95,25 @@
     void AddTo(LpMetadata* out) const override;
 };
 
+class PartitionGroup final {
+  public:
+    explicit PartitionGroup(const std::string& name, uint64_t maximum_size)
+        : name_(name), maximum_size_(maximum_size) {}
+
+    const std::string& name() const { return name_; }
+    uint64_t maximum_size() const { return maximum_size_; }
+
+  private:
+    std::string name_;
+    uint64_t maximum_size_;
+};
+
 class Partition final {
     friend class MetadataBuilder;
 
   public:
-    Partition(const std::string& name, const std::string& guid, uint32_t attributes);
+    Partition(const std::string& name, const std::string& group_name, const std::string& guid,
+              uint32_t attributes);
 
     // Add a raw extent.
     void AddExtent(std::unique_ptr<Extent>&& extent);
@@ -107,7 +121,12 @@
     // Remove all extents from this partition.
     void RemoveExtents();
 
+    // Compute the size used by linear extents. This is the same as size(),
+    // but does not factor in extents which do not take up space.
+    uint64_t BytesOnDisk() const;
+
     const std::string& name() const { return name_; }
+    const std::string& group_name() const { return group_name_; }
     uint32_t attributes() const { return attributes_; }
     const std::string& guid() const { return guid_; }
     const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; }
@@ -117,6 +136,7 @@
     void ShrinkTo(uint64_t aligned_size);
 
     std::string name_;
+    std::string group_name_;
     std::string guid_;
     std::vector<std::unique_ptr<Extent>> extents_;
     uint32_t attributes_;
@@ -156,12 +176,24 @@
         return New(device_info, metadata_max_size, metadata_slot_count);
     }
 
+    // Define a new partition group. By default there is one group called
+    // "default", with an unrestricted size. A non-zero size will restrict the
+    // total space used by all partitions in the group.
+    //
+    // This can fail and return false if the group already exists.
+    bool AddGroup(const std::string& group_name, uint64_t maximum_size);
+
     // Export metadata so it can be serialized to an image, to disk, or mounted
     // via device-mapper.
     std::unique_ptr<LpMetadata> Export();
 
     // Add a partition, returning a handle so it can be sized as needed. If a
     // partition with the given name already exists, nullptr is returned.
+    Partition* AddPartition(const std::string& name, const std::string& group_name,
+                            const std::string& guid, uint32_t attributes);
+
+    // Same as AddPartition above, but uses the default partition group which
+    // has no size restrictions.
     Partition* AddPartition(const std::string& name, const std::string& guid, uint32_t attributes);
 
     // Delete a partition by name if it exists.
@@ -202,10 +234,13 @@
     bool GrowPartition(Partition* partition, uint64_t aligned_size);
     void ShrinkPartition(Partition* partition, uint64_t aligned_size);
     uint64_t AlignSector(uint64_t sector);
+    PartitionGroup* FindGroup(const std::string& group_name) const;
+    uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
 
     LpMetadataGeometry geometry_;
     LpMetadataHeader header_;
     std::vector<std::unique_ptr<Partition>> partitions_;
+    std::vector<std::unique_ptr<PartitionGroup>> groups_;
     BlockDeviceInfo device_info_;
 };
 
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 6da24f6..51d262b 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -36,6 +36,7 @@
     LpMetadataHeader header;
     std::vector<LpMetadataPartition> partitions;
     std::vector<LpMetadataExtent> extents;
+    std::vector<LpMetadataPartitionGroup> groups;
 };
 
 // Place an initial partition table on the device. This will overwrite the
@@ -68,6 +69,7 @@
 // Helper to extract safe C++ strings from partition info.
 std::string GetPartitionName(const LpMetadataPartition& partition);
 std::string GetPartitionGuid(const LpMetadataPartition& partition);
+std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
 
 // Helper to return a slot number for a slot suffix.
 uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 52c80f7..79ef2ab 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 1
+#define LP_METADATA_MAJOR_VERSION 2
 #define LP_METADATA_MINOR_VERSION 0
 
 /* Attributes for the LpMetadataPartition::attributes field.
@@ -216,6 +216,8 @@
     LpMetadataTableDescriptor partitions;
     /* 92: Extent table descriptor. */
     LpMetadataTableDescriptor extents;
+    /* 104: Updateable group descriptor. */
+    LpMetadataTableDescriptor groups;
 } __attribute__((packed)) LpMetadataHeader;
 
 /* This struct defines a logical partition entry, similar to what would be
@@ -245,6 +247,9 @@
      * least one extent.
      */
     uint32_t num_extents;
+
+    /* 64: Group this partition belongs to. */
+    uint32_t group_index;
 } __attribute__((packed)) LpMetadataPartition;
 
 /* This extent is a dm-linear target, and the index is an index into the
@@ -271,6 +276,19 @@
     uint64_t target_data;
 } __attribute__((packed)) LpMetadataExtent;
 
+/* This struct defines an entry in the groups table. Each group has a maximum
+ * size, and partitions in a group must not exceed that size. There is always
+ * a "default" group of unlimited size, which is used when not using update
+ * groups or when using overlayfs or fastbootd.
+ */
+typedef struct LpMetadataPartitionGroup {
+    /*  0: Name of this group. Any unused characters must be 0. */
+    char name[36];
+
+    /* 36: Maximum size in bytes. If 0, the group has no maximum size. */
+    uint64_t maximum_size;
+} LpMetadataPartitionGroup;
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index eda68fd..f93852b 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -343,9 +343,6 @@
         ASSERT_NE(partition, nullptr);
     }
     ASSERT_NE(partition, nullptr);
-    // Add one extent to any partition to fill up more space - we're at 508
-    // bytes after this, out of 512.
-    ASSERT_TRUE(builder->ResizePartition(partition, 1024));
 
     unique_ptr<LpMetadata> exported = builder->Export();
     ASSERT_NE(exported, nullptr);
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 190c650..005d493 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -188,7 +188,8 @@
         return false;
     }
     if (!ValidateTableBounds(header, header.partitions) ||
-        !ValidateTableBounds(header, header.extents)) {
+        !ValidateTableBounds(header, header.extents) ||
+        !ValidateTableBounds(header, header.groups)) {
         LERROR << "Logical partition metadata has invalid table bounds.";
         return false;
     }
@@ -202,6 +203,10 @@
         LERROR << "Logical partition metadata has invalid extent table entry size.";
         return false;
     }
+    if (header.groups.entry_size != sizeof(LpMetadataPartitionGroup)) {
+        LERROR << "Logical partition metadata has invalid group table entry size.";
+        return false;
+    }
     return true;
 }
 
@@ -257,6 +262,10 @@
             LERROR << "Logical partition has invalid extent list.";
             return nullptr;
         }
+        if (partition.group_index >= header.groups.num_entries) {
+            LERROR << "Logical partition has invalid group index.";
+            return nullptr;
+        }
 
         metadata->partitions.push_back(partition);
     }
@@ -269,6 +278,16 @@
 
         metadata->extents.push_back(extent);
     }
+
+    cursor = buffer.get() + header.groups.offset;
+    for (size_t i = 0; i < header.groups.num_entries; i++) {
+        LpMetadataPartitionGroup group = {};
+        memcpy(&group, cursor, sizeof(group));
+        cursor += header.groups.entry_size;
+
+        metadata->groups.push_back(group);
+    }
+
     return metadata;
 }
 
@@ -345,5 +364,9 @@
     return NameFromFixedArray(partition.name, sizeof(partition.name));
 }
 
+std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group) {
+    return NameFromFixedArray(group.name, sizeof(group.name));
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 9dd2745..2415629 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -56,14 +56,17 @@
                            metadata.partitions.size() * sizeof(LpMetadataPartition));
     std::string extents(reinterpret_cast<const char*>(metadata.extents.data()),
                         metadata.extents.size() * sizeof(LpMetadataExtent));
+    std::string groups(reinterpret_cast<const char*>(metadata.groups.data()),
+                       metadata.groups.size() * sizeof(LpMetadataPartitionGroup));
 
     // Compute positions of tables.
     header.partitions.offset = 0;
     header.extents.offset = header.partitions.offset + partitions.size();
-    header.tables_size = header.extents.offset + extents.size();
+    header.groups.offset = header.extents.offset + extents.size();
+    header.tables_size = header.groups.offset + groups.size();
 
     // Compute payload checksum.
-    std::string tables = partitions + extents;
+    std::string tables = partitions + extents + groups;
     SHA256(tables.data(), tables.size(), header.tables_checksum);
 
     // Compute header checksum.
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 879ba21..f78093b 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -42,6 +42,7 @@
 using DmTargetLinear = ::android::dm::DmTargetLinear;
 using DmTargetZero = ::android::dm::DmTargetZero;
 using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
+using DmTargetBow = ::android::dm::DmTargetBow;
 using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
 using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
 
@@ -108,6 +109,13 @@
             std::string block_device = NextArg();
             return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
                                                            block_device);
+        } else if (target_type == "bow") {
+            if (!HasArgs(1)) {
+                std::cerr << "Expected \"bow\" <block_device>" << std::endl;
+                return nullptr;
+            }
+            std::string block_device = NextArg();
+            return std::make_unique<DmTargetBow>(start_sector, num_sectors, block_device);
         } else {
             std::cerr << "Unrecognized target type: " << target_type << std::endl;
             return nullptr;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 71a8e0d..6f97d19 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -68,6 +68,7 @@
     bool CreateLogicalPartitions();
     bool MountPartition(fstab_rec* fstab_rec);
     bool MountPartitions();
+    bool IsDmLinearEnabled();
     bool GetBackingDmLinearDevices();
 
     virtual ListenerAction UeventCallback(const Uevent& uevent);
@@ -134,22 +135,6 @@
     return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
 }
 
-static inline bool IsDmLinearEnabled() {
-    static bool checked = false;
-    static bool enabled = false;
-    if (checked) {
-        return enabled;
-    }
-    import_kernel_cmdline(false,
-                          [](const std::string& key, const std::string& value, bool in_qemu) {
-                              if (key == "androidboot.logical_partitions" && value == "1") {
-                                  enabled = true;
-                              }
-                          });
-    checked = true;
-    return enabled;
-}
-
 // Class Definitions
 // -----------------
 FirstStageMount::FirstStageMount()
@@ -198,6 +183,13 @@
     return GetBackingDmLinearDevices() && GetDmVerityDevices() && InitRequiredDevices();
 }
 
+bool FirstStageMount::IsDmLinearEnabled() {
+    for (auto fstab_rec : mount_fstab_recs_) {
+        if (fs_mgr_is_logical(fstab_rec)) return true;
+    }
+    return false;
+}
+
 bool FirstStageMount::GetBackingDmLinearDevices() {
     // Add any additional devices required for dm-linear mappings.
     if (!IsDmLinearEnabled()) {
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index e7b1728..53653de 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -56,15 +56,24 @@
 /*
  * Use __VA_ARGS__ if running a static analyzer,
  * to avoid warnings of unused variables in __VA_ARGS__.
- * __FAKE_USE_VA_ARGS is undefined at link time,
- * so don't link with __clang_analyzer__ defined.
+ * Use contexpr function in C++ mode, so these macros can be used
+ * in other constexpr functions without warning.
  */
 #ifdef __clang_analyzer__
-extern void __fake_use_va_args(int, ...);
-#define __FAKE_USE_VA_ARGS(...) __fake_use_va_args(0, ##__VA_ARGS__)
+#ifdef __cplusplus
+extern "C++" {
+template <typename... Ts>
+constexpr int __fake_use_va_args(Ts...) {
+  return 0;
+}
+}
+#else
+extern int __fake_use_va_args(int, ...);
+#endif /* __cplusplus */
+#define __FAKE_USE_VA_ARGS(...) ((void)__fake_use_va_args(0, ##__VA_ARGS__))
 #else
 #define __FAKE_USE_VA_ARGS(...) ((void)(0))
-#endif
+#endif /* __clang_analyzer__ */
 
 #ifndef __predict_false
 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index f39ea7c..2a70a4a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -400,6 +400,7 @@
 
     # Make sure we have the device encryption key.
     start vold
+    exec - system system -- /system/bin/vdc checkpoint prepareDriveForCheckpoint /data
     installkey /data
 
     # Start bootcharting as soon as possible after the data partition is