Installer::ProceedState RomInstaller::on_checked_device()
{
    // /sbin is not going to be populated with anything useful in a normal boot
    // image. We can almost guarantee that a recovery image is going to be
    // installed though, so we'll open the recovery partition with libmbp and
    // extract its /sbin with libarchive into the chroot's /sbin.

    std::string block_dev(_recovery_block_dev);
    mbp::BootImage bi;
    mbp::CpioFile innerCpio;
    const unsigned char *ramdisk_data;
    std::size_t ramdisk_size;
    bool using_boot = false;

    // Check if the device has a combined boot/recovery partition. If the
    // FOTAKernel partition is listed, it will be used instead of the combined
    // ramdisk from the boot image
    bool combined = mb_device_flags(_device)
            & FLAG_HAS_COMBINED_BOOT_AND_RECOVERY;
    if (combined && block_dev.empty()) {
        block_dev = _boot_block_dev;
        using_boot = true;
    }

    if (block_dev.empty()) {
        display_msg("Could not determine the recovery block device");
        return ProceedState::Fail;
    }

    if (!bi.loadFile(block_dev)) {
        display_msg("Failed to load recovery partition image");
        return ProceedState::Fail;
    }

    // Load ramdisk
    bi.ramdiskImageC(&ramdisk_data, &ramdisk_size);

    if (using_boot) {
        if (!innerCpio.load(ramdisk_data, ramdisk_size)) {
            display_msg("Failed to load ramdisk from combined boot image");
            return ProceedState::Fail;
        }

        if (!innerCpio.contentsC("sbin/ramdisk-recovery.cpio",
                                 &ramdisk_data, &ramdisk_size)) {
            display_msg("Could not find recovery ramdisk in combined boot image");
            return ProceedState::Fail;
        }
    }

    autoclose::archive in(archive_read_new(), archive_read_free);
    autoclose::archive out(archive_write_disk_new(), archive_write_free);

    if (!in || !out) {
        LOGE("Out of memory");
        return ProceedState::Fail;
    }

    archive_entry *entry;

    // Set up input
    archive_read_support_filter_gzip(in.get());
    archive_read_support_filter_lzop(in.get());
    archive_read_support_filter_lz4(in.get());
    archive_read_support_filter_lzma(in.get());
    archive_read_support_filter_xz(in.get());
    archive_read_support_format_cpio(in.get());

    int ret = archive_read_open_memory(in.get(),
            const_cast<unsigned char *>(ramdisk_data), ramdisk_size);
    if (ret != ARCHIVE_OK) {
        LOGW("Failed to open recovery ramdisk: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Set up output
    archive_write_disk_set_options(out.get(),
                                   ARCHIVE_EXTRACT_ACL |
                                   ARCHIVE_EXTRACT_FFLAGS |
                                   ARCHIVE_EXTRACT_PERM |
                                   ARCHIVE_EXTRACT_SECURE_NODOTDOT |
                                   ARCHIVE_EXTRACT_SECURE_SYMLINKS |
                                   ARCHIVE_EXTRACT_TIME |
                                   ARCHIVE_EXTRACT_UNLINK |
                                   ARCHIVE_EXTRACT_XATTR);

    while ((ret = archive_read_next_header(in.get(), &entry)) == ARCHIVE_OK) {
        std::string path = archive_entry_pathname(entry);

        if (path == "default.prop") {
            path = "default.recovery.prop";
        } else if (!util::starts_with(path, "sbin/")) {
            continue;
        }

        LOGE("Copying from recovery: %s", path.c_str());

        archive_entry_set_pathname(entry, in_chroot(path).c_str());

        if (util::libarchive_copy_header_and_data(
                in.get(), out.get(), entry) != ARCHIVE_OK) {
            return ProceedState::Fail;
        }

        archive_entry_set_pathname(entry, path.c_str());
    }

    if (ret != ARCHIVE_EOF) {
        LOGE("Archive extraction ended without reaching EOF: %s",
             archive_error_string(in.get()));
        return ProceedState::Fail;
    }

    // Create fake /etc/fstab file to please installers that read the file
    std::string etc_fstab(in_chroot("/etc/fstab"));
    if (access(etc_fstab.c_str(), R_OK) < 0 && errno == ENOENT) {
        autoclose::file fp(autoclose::fopen(etc_fstab.c_str(), "w"));
        if (fp) {
            auto system_devs = mb_device_system_block_devs(_device);
            auto cache_devs = mb_device_cache_block_devs(_device);
            auto data_devs = mb_device_data_block_devs(_device);

            // Set block device if it's provided and non-empty
            const char *system_dev =
                    system_devs && system_devs[0] && system_devs[0][0]
                    ? system_devs[0] : "dummy";
            const char *cache_dev =
                    cache_devs && cache_devs[0] && cache_devs[0][0]
                    ? cache_devs[0] : "dummy";
            const char *data_dev =
                    data_devs && data_devs[0] && data_devs[0][0]
                    ? data_devs[0] : "dummy";

            fprintf(fp.get(), "%s /system ext4 rw 0 0\n", system_dev);
            fprintf(fp.get(), "%s /cache ext4 rw 0 0\n", cache_dev);
            fprintf(fp.get(), "%s /data ext4 rw 0 0\n", data_dev);
        }
    }

    // Load recovery properties
    util::file_get_all_properties(
            in_chroot("/default.recovery.prop"), &_recovery_props);

    return ProceedState::Continue;
}
Esempio n. 2
0
TEST(JsonTest, LoadCompleteDefinition)
{
    ScopedDevice sd(sample_complete);

    ASSERT_NE(sd.device, nullptr);

    ASSERT_STREQ(mb_device_id(sd.device), "test");

    const char *codenames[] = { "test1", "test2", "test3", "test4", nullptr };
    ASSERT_TRUE(string_array_eq(mb_device_codenames(sd.device), codenames));

    ASSERT_STREQ(mb_device_name(sd.device), "Test Device");
    ASSERT_STREQ(mb_device_architecture(sd.device), "arm64-v8a");

    uint64_t device_flags = FLAG_HAS_COMBINED_BOOT_AND_RECOVERY;
    ASSERT_EQ(mb_device_flags(sd.device), device_flags);

    const char *base_dirs[] = { "/dev/block/bootdevice/by-name", nullptr };
    ASSERT_TRUE(string_array_eq(mb_device_block_dev_base_dirs(sd.device), base_dirs));

    const char *system_devs[] = {
        "/dev/block/bootdevice/by-name/system",
        "/dev/block/sda1",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_system_block_devs(sd.device), system_devs));

    const char *cache_devs[] = {
        "/dev/block/bootdevice/by-name/cache",
        "/dev/block/sda2",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_cache_block_devs(sd.device), cache_devs));

    const char *data_devs[] = {
        "/dev/block/bootdevice/by-name/userdata",
        "/dev/block/sda3",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_data_block_devs(sd.device), data_devs));

    const char *boot_devs[] = {
        "/dev/block/bootdevice/by-name/boot",
        "/dev/block/sda4",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_boot_block_devs(sd.device), boot_devs));

    const char *recovery_devs[] = {
        "/dev/block/bootdevice/by-name/recovery",
        "/dev/block/sda5",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_recovery_block_devs(sd.device), recovery_devs));

    const char *extra_devs[] = {
        "/dev/block/bootdevice/by-name/modem",
        "/dev/block/sda6",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_extra_block_devs(sd.device), extra_devs));

    /* Boot UI */

    ASSERT_EQ(mb_device_tw_supported(sd.device), true);

    uint64_t flags =
            FLAG_TW_TOUCHSCREEN_SWAP_XY
            | FLAG_TW_TOUCHSCREEN_FLIP_X
            | FLAG_TW_TOUCHSCREEN_FLIP_Y
            | FLAG_TW_GRAPHICS_FORCE_USE_LINELENGTH
            | FLAG_TW_SCREEN_BLANK_ON_BOOT
            | FLAG_TW_BOARD_HAS_FLIPPED_SCREEN
            | FLAG_TW_IGNORE_MAJOR_AXIS_0
            | FLAG_TW_IGNORE_MT_POSITION_0
            | FLAG_TW_IGNORE_ABS_MT_TRACKING_ID
            | FLAG_TW_NEW_ION_HEAP
            | FLAG_TW_NO_SCREEN_BLANK
            | FLAG_TW_NO_SCREEN_TIMEOUT
            | FLAG_TW_ROUND_SCREEN
            | FLAG_TW_NO_CPU_TEMP
            | FLAG_TW_QCOM_RTC_FIX
            | FLAG_TW_HAS_DOWNLOAD_MODE
            | FLAG_TW_PREFER_LCD_BACKLIGHT;
    ASSERT_EQ(mb_device_tw_flags(sd.device), flags);

    ASSERT_EQ(mb_device_tw_pixel_format(sd.device), TW_PIXEL_FORMAT_RGBA_8888);
    ASSERT_EQ(mb_device_tw_force_pixel_format(sd.device), TW_FORCE_PIXEL_FORMAT_RGB_565);
    ASSERT_EQ(mb_device_tw_overscan_percent(sd.device), 10);
    ASSERT_EQ(mb_device_tw_default_x_offset(sd.device), 20);
    ASSERT_EQ(mb_device_tw_default_y_offset(sd.device), 30);
    ASSERT_STREQ(mb_device_tw_brightness_path(sd.device), "/sys/class/backlight");
    ASSERT_STREQ(mb_device_tw_secondary_brightness_path(sd.device), "/sys/class/lcd-backlight");
    ASSERT_EQ(mb_device_tw_max_brightness(sd.device), 255);
    ASSERT_EQ(mb_device_tw_default_brightness(sd.device), 100);
    ASSERT_STREQ(mb_device_tw_battery_path(sd.device), "/sys/class/battery");
    ASSERT_STREQ(mb_device_tw_cpu_temp_path(sd.device), "/sys/class/cputemp");
    ASSERT_STREQ(mb_device_tw_input_blacklist(sd.device), "foo");
    ASSERT_STREQ(mb_device_tw_input_whitelist(sd.device), "bar");

    const char *graphics_backends[] = {
        "overlay_msm_old",
        "fbdev",
        nullptr
    };
    ASSERT_TRUE(string_array_eq(mb_device_tw_graphics_backends(sd.device), graphics_backends));

    ASSERT_STREQ(mb_device_tw_theme(sd.device), "portrait_hdpi");
}