Merge "Do not construct std::function with Allocator argument"
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index dee87bd..98a73eb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -147,24 +147,34 @@
     return fde;
 }
 
-void fdevent_destroy(fdevent* fde) {
+unique_fd fdevent_release(fdevent* fde) {
     check_main_thread();
-    if (fde == nullptr) return;
+    if (!fde) {
+        return {};
+    }
+
     if (!(fde->state & FDE_CREATED)) {
         LOG(FATAL) << "destroying fde not created by fdevent_create(): " << dump_fde(fde);
     }
 
+    unique_fd result = std::move(fde->fd);
     if (fde->state & FDE_ACTIVE) {
-        g_poll_node_map.erase(fde->fd.get());
+        g_poll_node_map.erase(result.get());
+
         if (fde->state & FDE_PENDING) {
             g_pending_list.remove(fde);
         }
-        fde->fd.reset();
         fde->state = 0;
         fde->events = 0;
     }
 
     delete fde;
+    return result;
+}
+
+void fdevent_destroy(fdevent* fde) {
+    // Release, and then let unique_fd's destructor cleanup.
+    fdevent_release(fde);
 }
 
 static void fdevent_update(fdevent* fde, unsigned events) {
diff --git a/adb/fdevent.h b/adb/fdevent.h
index d501b86..df2339a 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -50,11 +50,12 @@
 */
 fdevent *fdevent_create(int fd, fd_func func, void *arg);
 
-/* Uninitialize and deallocate an fdevent object that was
-** created by fdevent_create()
-*/
+// Deallocate an fdevent object that was created by fdevent_create.
 void fdevent_destroy(fdevent *fde);
 
+// fdevent_destroy, except releasing the file descriptor previously owned by the fdevent.
+unique_fd fdevent_release(fdevent* fde);
+
 /* Change which events should cause notifications
 */
 void fdevent_set(fdevent *fde, unsigned events);
diff --git a/adb/test_device.py b/adb/test_device.py
old mode 100644
new mode 100755
index 9f45115..c3166ff
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -751,7 +751,7 @@
                 shutil.rmtree(host_dir)
 
     def test_push_empty(self):
-        """Push a directory containing an empty directory to the device."""
+        """Push an empty directory to the device."""
         self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
         self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
 
@@ -767,9 +767,10 @@
 
             self.device.push(empty_dir_path, self.DEVICE_TEMP_DIR)
 
-            test_empty_cmd = ['[', '-d',
-                              os.path.join(self.DEVICE_TEMP_DIR, 'empty')]
+            remote_path = os.path.join(self.DEVICE_TEMP_DIR, "empty")
+            test_empty_cmd = ["[", "-d", remote_path, "]"]
             rc, _, _ = self.device.shell_nocheck(test_empty_cmd)
+
             self.assertEqual(rc, 0)
             self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
         finally:
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 57e25fc..2a68a2b 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -32,6 +32,7 @@
 #define FB_CMD_DELETE_PARTITION "delete-logical-partition"
 #define FB_CMD_RESIZE_PARTITION "resize-logical-partition"
 #define FB_CMD_UPDATE_SUPER "update-super"
+#define FB_CMD_OEM "oem"
 
 #define RESPONSE_OKAY "OKAY"
 #define RESPONSE_FAIL "FAIL"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 0ec0994..b7cafac 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -40,6 +40,9 @@
 using ::android::hardware::boot::V1_0::BoolResult;
 using ::android::hardware::boot::V1_0::CommandResult;
 using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
+
 using namespace android::fs_mgr;
 
 struct VariableHandlers {
@@ -133,6 +136,24 @@
     return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
 }
 
+bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+    auto fastboot_hal = device->fastboot_hal();
+    if (!fastboot_hal) {
+        return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
+    }
+
+    Result ret;
+    auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; });
+    if (!ret_val.isOk()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command");
+    }
+    if (ret.status != Status::SUCCESS) {
+        return device->WriteStatus(FastbootResult::FAIL, ret.message);
+    }
+
+    return device->WriteStatus(FastbootResult::OKAY, ret.message);
+}
+
 bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
@@ -159,6 +180,12 @@
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
     }
+
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL,
+                                   "Flashing is not allowed on locked devices");
+    }
+
     int ret = Flash(device, args[1]);
     if (ret < 0) {
         return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
@@ -304,6 +331,10 @@
         return device->WriteFail("Invalid partition name and size");
     }
 
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+    }
+
     uint64_t partition_size;
     std::string partition_name = args[1];
     if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
@@ -344,6 +375,10 @@
         return device->WriteFail("Invalid partition name and size");
     }
 
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+    }
+
     PartitionBuilder builder(device);
     if (!builder.Valid()) {
         return device->WriteFail("Could not open super partition");
@@ -360,6 +395,10 @@
         return device->WriteFail("Invalid partition name and size");
     }
 
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+    }
+
     uint64_t partition_size;
     std::string partition_name = args[1];
     if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
@@ -388,6 +427,11 @@
     if (args.size() < 2) {
         return device->WriteFail("Invalid arguments");
     }
+
+    if (GetDeviceLockStatus()) {
+        return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
+    }
+
     bool wipe = (args.size() >= 3 && args[2] == "wipe");
     return UpdateSuper(device, args[1], wipe);
 }
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index 4778d23..9df43a9 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -45,3 +45,4 @@
 bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
 bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args);
 bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index ae2e7a6..6862741 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -48,6 +48,7 @@
               {FB_CMD_DELETE_PARTITION, DeletePartitionHandler},
               {FB_CMD_RESIZE_PARTITION, ResizePartitionHandler},
               {FB_CMD_UPDATE_SUPER, UpdateSuperHandler},
+              {FB_CMD_OEM, OemCmdHandler},
       }),
       transport_(std::make_unique<ClientUsbTransport>()),
       boot_control_hal_(IBootControl::getService()),
@@ -120,10 +121,20 @@
         command[bytes_read] = '\0';
 
         LOG(INFO) << "Fastboot command: " << command;
-        auto args = android::base::Split(command, ":");
-        auto found_command = kCommandMap.find(args[0]);
+
+        std::vector<std::string> args;
+        std::string cmd_name;
+        if (android::base::StartsWith(command, "oem ")) {
+            args = {command};
+            cmd_name = "oem";
+        } else {
+            args = android::base::Split(command, ":");
+            cmd_name = args[0];
+        }
+
+        auto found_command = kCommandMap.find(cmd_name);
         if (found_command == kCommandMap.end()) {
-            WriteStatus(FastbootResult::FAIL, "Unrecognized command");
+            WriteStatus(FastbootResult::FAIL, "Unrecognized command " + args[0]);
             continue;
         }
         if (!found_command->second(this, args)) {
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 261a202..02f6f2c 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <fs_mgr_dm_linear.h>
 #include <liblp/liblp.h>
@@ -159,3 +160,9 @@
     }
     return partitions;
 }
+
+bool GetDeviceLockStatus() {
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+    return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index 4f0d079..bb08f72 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -58,3 +58,4 @@
 bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle);
 bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
 std::vector<std::string> ListPartitions(FastbootDevice* device);
+bool GetDeviceLockStatus();
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 7535248..002e043 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -148,7 +148,7 @@
 
 bool GetUnlocked(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
                  std::string* message) {
-    *message = "yes";
+    *message = GetDeviceLockStatus() ? "no" : "yes";
     return true;
 }
 
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 018c280..352647b 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -482,6 +482,14 @@
     return (geometry_.last_logical_sector - geometry_.first_logical_sector + 1) * LP_SECTOR_SIZE;
 }
 
+uint64_t MetadataBuilder::UsedSpace() const {
+    uint64_t size = 0;
+    for (const auto& partition : partitions_) {
+        size += partition->size();
+    }
+    return size;
+}
+
 uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
     // 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.
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index da9c8f3..0c7e43d 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -202,14 +202,28 @@
 }
 
 TEST(liblp, UseAllDiskSpace) {
-    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
-    EXPECT_EQ(builder->AllocatableSpace(), 1036288);
+    static constexpr uint64_t total = 1024 * 1024;
+    static constexpr uint64_t metadata = 1024;
+    static constexpr uint64_t slots = 2;
+    unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(total, metadata, slots);
+    // We reserve a geometry block (4KB) plus space for each copy of the
+    // maximum size of a metadata blob. Then, we double that space since
+    // we store a backup copy of everything.
+    static constexpr uint64_t geometry = 4 * 1024;
+    static constexpr uint64_t allocatable = total - (metadata * slots + geometry) * 2;
+    EXPECT_EQ(builder->AllocatableSpace(), allocatable);
+    EXPECT_EQ(builder->UsedSpace(), 0);
 
     Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
     ASSERT_NE(system, nullptr);
-    EXPECT_EQ(builder->ResizePartition(system, 1036288), true);
-    EXPECT_EQ(system->size(), 1036288);
-    EXPECT_EQ(builder->ResizePartition(system, 1036289), false);
+    EXPECT_EQ(builder->ResizePartition(system, allocatable), true);
+    EXPECT_EQ(system->size(), allocatable);
+    EXPECT_EQ(builder->UsedSpace(), allocatable);
+    EXPECT_EQ(builder->AllocatableSpace(), allocatable);
+    EXPECT_EQ(builder->ResizePartition(system, allocatable + 1), false);
+    EXPECT_EQ(system->size(), allocatable);
+    EXPECT_EQ(builder->UsedSpace(), allocatable);
+    EXPECT_EQ(builder->AllocatableSpace(), allocatable);
 }
 
 TEST(liblp, BuildComplex) {
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 38842a4..2780825 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -184,6 +184,7 @@
 
     // Amount of space that can be allocated to logical partitions.
     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.
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 1f4bec1..71a8e0d 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -120,14 +120,18 @@
     return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
 }
 
-static bool IsRecoveryMode() {
+static bool ForceNormalBoot() {
     static bool force_normal_boot = []() {
         std::string cmdline;
         android::base::ReadFileToString("/proc/cmdline", &cmdline);
         return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
     }();
 
-    return !force_normal_boot && access("/system/bin/recovery", F_OK) == 0;
+    return force_normal_boot;
+}
+
+static bool IsRecoveryMode() {
+    return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
 }
 
 static inline bool IsDmLinearEnabled() {
@@ -368,11 +372,15 @@
     // this case, we mount system first then pivot to it.  From that point on,
     // we are effectively identical to a system-as-root device.
     auto system_partition =
-            std::find_if(mount_fstab_recs_.begin(), mount_fstab_recs_.end(), [](const auto& rec) {
-                return rec->mount_point == "/system"s ||
-                       rec->mount_point == "/system_recovery_mount"s;
-            });
+            std::find_if(mount_fstab_recs_.begin(), mount_fstab_recs_.end(),
+                         [](const auto& rec) { return rec->mount_point == "/system"s; });
+
     if (system_partition != mount_fstab_recs_.end()) {
+        if (ForceNormalBoot()) {
+            free((*system_partition)->mount_point);
+            (*system_partition)->mount_point = strdup("/system_recovery_mount");
+        }
+
         if (!MountPartition(*system_partition)) {
             return false;
         }
diff --git a/init/init.cpp b/init/init.cpp
index e5c1548..47cfe32 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -346,12 +346,12 @@
     if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
         return;
     }
-
-    std::string value = GetProperty("ro.boot.verifiedbootstate", "");
-
-    if (!value.empty()) {
-        property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
-    }
+    import_kernel_cmdline(
+            false, [](const std::string& key, const std::string& value, bool in_qemu) {
+                if (key == "androidboot.verifiedbootstate") {
+                    property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
+                }
+            });
 }
 
 static void export_kernel_boot_props() {
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index bcc0616..d27feb9 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_static {
+cc_library {
     name: "libgrallocusage",
     vendor_available: true,
     cflags: [
diff --git a/libgrallocusage/OWNERS b/libgrallocusage/OWNERS
new file mode 100644
index 0000000..154dc6d
--- /dev/null
+++ b/libgrallocusage/OWNERS
@@ -0,0 +1,3 @@
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index bce308b..4432f9e 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -110,25 +110,25 @@
  */
 
 struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
-    uint32_t recovery_dtbo_size;   /* size in bytes for recovery DTBO image */
-    uint64_t recovery_dtbo_offset; /* offset to recovery dtbo in boot image */
+    uint32_t recovery_dtbo_size;   /* size in bytes for recovery DTBO/ACPIO image */
+    uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
     uint32_t header_size;
 } __attribute__((packed));
 
 /* When the boot image header has a version of 1, the structure of the boot
  * image is as follows:
  *
- * +-----------------+
- * | boot header     | 1 page
- * +-----------------+
- * | kernel          | n pages
- * +-----------------+
- * | ramdisk         | m pages
- * +-----------------+
- * | second stage    | o pages
- * +-----------------+
- * | recovery dtbo   | p pages
- * +-----------------+
+ * +---------------------+
+ * | boot header         | 1 page
+ * +---------------------+
+ * | kernel              | n pages
+ * +---------------------+
+ * | ramdisk             | m pages
+ * +---------------------+
+ * | second stage        | o pages
+ * +---------------------+
+ * | recovery dtbo/acpio | p pages
+ * +---------------------+
  * n = (kernel_size + page_size - 1) / page_size
  * m = (ramdisk_size + page_size - 1) / page_size
  * o = (second_size + page_size - 1) / page_size
@@ -136,13 +136,14 @@
  *
  * 0. all entities are page_size aligned in flash
  * 1. kernel and ramdisk are required (size != 0)
- * 2. recovery_dtbo is required for recovery.img in non-A/B devices(recovery_dtbo_size != 0)
+ * 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
+ *    devices(recovery_dtbo_size != 0)
  * 3. second is optional (second_size == 0 -> no second)
  * 4. load each element (kernel, ramdisk, second) at
  *    the specified physical address (kernel_addr, etc)
- * 5. If booting to recovery mode in a non-A/B device, extract recovery dtbo and
- *    apply the correct set of overlays on the base device tree depending on the
- *    hardware/product revision.
+ * 5. If booting to recovery mode in a non-A/B device, extract recovery
+ *    dtbo/acpio and apply the correct set of overlays on the base device tree
+ *    depending on the hardware/product revision.
  * 6. prepare tags at tag_addr.  kernel_args[] is
  *    appended to the kernel commandline in the tags.
  * 7. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index fda9af0..2eb2bab 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -161,7 +161,10 @@
                         required=True)
     parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
     parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
-    parser.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb'))
+    recovery_dtbo_group = parser.add_mutually_exclusive_group()
+    recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb'))
+    recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
+                                     type=FileType('rb'), metavar='RECOVERY_ACPIO', dest='recovery_dtbo')
     parser.add_argument('--cmdline', help='extra arguments to be passed on the '
                         'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
     parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 915540e..f39ea7c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -407,6 +407,9 @@
     mkdir /data/bootchart 0755 shell shell
     bootchart start
 
+    # Start apexd as soon as we can
+    start apexd
+
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
     copy /data/system/entropy.dat /dev/urandom