void command_loop(Socket *client) {
    char buffer[64];

    while (true) {
        if (client->Receive(buffer, 8, 0) != 8) {
            return;
        }

        uint64_t length = ExtractMessageLength(buffer);
        if (length > 64) {
            ALOGE("Wrong message length: %" PRId64, length);
            return;
        }

        ssize_t read = client->Receive(buffer, length, 0);
        if (read != (ssize_t)length) {
            ALOGE("Failed to retrive command.");
            return;
        }

        std::vector<std::string> cmd = android::base::Split(std::string(buffer, read), ":");
        if (handle_command(client, cmd[0], std::vector<std::string>(cmd.begin() + 1, cmd.end())) != true) {
            return;
        }
    }
}
Beispiel #2
0
ssize_t TcpTransport::Read(void* data, size_t length) {
    if (socket_ == nullptr) {
        return -1;
    }

    // Unless we're mid-message, read the next 8-byte message length.
    if (message_bytes_left_ == 0) {
        char buffer[8];
        if (socket_->ReceiveAll(buffer, 8, 0) != 8) {
            Close();
            return -1;
        }
        message_bytes_left_ = ExtractMessageLength(buffer);
    }

    // Now read the message (up to |length| bytes).
    if (length > message_bytes_left_) {
        length = message_bytes_left_;
    }
    ssize_t bytes_read = socket_->ReceiveAll(data, length, 0);
    if (bytes_read == -1) {
        Close();
    } else {
        message_bytes_left_ -= bytes_read;
    }
    return bytes_read;
}
bool handle_command(Socket *client, std::string cmd, std::vector<std::string> args) {
    const char *trampfile = "/data/misc/fastbootd/mid.bin";

    if (cmd == "getvar") {
        if (args[0] == "max-download-size") {
            return send_reply(client, "OKAY", "%d", kMaxDownloadSize);
        } else if (args[0] == "partition-type") {
            for (size_t i = 0; i < sizeof(part_info) / sizeof(part_info[0]); i++) {
                if (args[1] == part_info[i].name) {
                    return send_reply(client, "OKAY", part_info[i].type);
                }
            }
        } else if (args[0] == "product") {
            char property[PROPERTY_VALUE_MAX];
            property_get("ro.product.board", property, "");
            return send_reply(client, "OKAY", property);
        } else if (args[0] == "serialno") {
            char property[PROPERTY_VALUE_MAX];
            property_get("ro.serialno", property, "");
            return send_reply(client, "OKAY", property);
        } else if (args[0] == "version-bootloader") {
            return send_reply(client, "OKAY", "0.1");
        }
        return send_reply(client, "OKAY", "");
    } else if (cmd == "download") {
        uint32_t size = strtol(args[0].c_str(), 0, 16);
        send_reply(client, "DATA", "%08x", size);

        int fd = open(trampfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
        if (fd < 0) {
            send_reply(client, "FAIL", "fail to create trampoline file to store data!");
            return false;
        }

        while (size > 0) {
            char buffer[4096];
            ssize_t read = client->Receive(buffer, 8, 0);
            if (read != 8) {
                send_reply(client, "FAIL", "fail to receive data!");
                close(fd);
                return false;
            }
            size_t length = ExtractMessageLength(buffer);
            do {
                read = client->Receive(buffer, std::min(length, sizeof(buffer)), 0);
                if (read < 0) {
                    close(fd);
                    return false;
                }

                write(fd, buffer, read);

                length -= read;
                size -= read;
            } while (length > 0);
        }

        close(fd);

        return send_reply(client, "OKAY", "");
    } else if (cmd == "flash") {
        std::unique_ptr<char, int (*)(const char *)> tmpfile((char *)trampfile, unlink);
        int fd = open(tmpfile.get(), O_RDONLY);
        if (fd < 0) {
            send_reply(client, "FAIL", "please run download command first!");
            return false;
        }

        const char *devname = NULL;
        const char *partname = NULL;
        for (size_t i = 0; i < sizeof(part_info) / sizeof(part_info[0]); i++) {
            if (args[0] == part_info[i].name) {
                devname = part_info[i].device;
                partname = part_info[i].name;
                break;
            }
        }

        if (devname == NULL) {
            close(fd);
            send_reply(client, "FAIL", "partition: %s does not exist!", args[0].c_str());
            return false;
        }

        if (!strcmp("boot", partname)) {
            close(fd);
            return handle_command_flash_boot_partition(client, tmpfile.get(), devname);
        }

        int fddev = open(devname, O_WRONLY | O_CREAT, 0600);
        if (fddev < 0) {
            close(fd);
            send_reply(client, "FAIL", "failed to open partition: %s", args[0].c_str());
            return false;
        }

        struct sparse_file *s = sparse_file_import(fd, true, false);
        if (!s) {
            close(fd);
            close(fddev);

            send_reply(client, "FAIL", "failed to read sparse file!");
            return false;
        }

        sparse_file_write(s, fddev, false, false, false);
        sparse_file_destroy(s);

        close(fd);
        close(fddev);

        sync();

        return send_reply(client, "OKAY", "");
    } else if (cmd == "erase") {
        const char *devname = NULL;
        for (size_t i = 0; i < sizeof(part_info) / sizeof(part_info[0]); i++) {
            if (args[0] == part_info[i].name) {
                devname = part_info[i].device;
                break;
            }
        }

        if (devname == NULL) {
            send_reply(client, "FAIL", "partition: %s does not exist!", args[0].c_str());
            return false;
        }

        uint64_t devsize = 0;
        int fd = open(devname, O_RDONLY);
        ioctl(fd, BLKGETSIZE64, &devsize);

        const uint64_t blksize = 64 * 1024;
        const uint64_t numblk = (devsize + blksize - 1) / blksize;
        const uint64_t updsize = (numblk / 10) * blksize;
        for (uint64_t offset = 0; offset < devsize; offset += updsize) {
            uint64_t realsize = std::min(updsize, devsize - offset);
            const char *argv[] = {
                "/system/bin/dd",
                "if=/dev/zero",
                android::base::StringPrintf("of=%s", devname).c_str(),
                android::base::StringPrintf("seek=%lld", offset).c_str(),
                android::base::StringPrintf("bs=%lld", realsize).c_str(),
                "count=1",
            };
            int status;

            android_fork_execvp(sizeof(argv) / sizeof(argv[0]), (char **)argv, &status, true, true);
            send_reply(client, "INFO", android::base::StringPrintf("erase %s: %3lld/100",
                    devname, (offset + realsize) * 100 / devsize).c_str());
        }

        return send_reply(client, "OKAY", "");
    } else if (cmd == "continue") {
        android::base::WriteStringToFile("5", "/sys/module/bcm2709/parameters/reboot_part");
        android_reboot(ANDROID_RB_RESTART, 0, NULL);
//        while (true) { pause(); }
        return send_reply(client, "OKAY", "");
    } else if (cmd == "reboot" || cmd == "reboot-bootloader") {
        android::base::WriteStringToFile("0", "/sys/module/bcm2709/parameters/reboot_part");
        android_reboot(ANDROID_RB_RESTART, 0, NULL);
//        while (true) { pause(); }
        return send_reply(client, "OKAY", "");
    }

    return send_reply(client, "FAIL", "unknown command: %s", cmd.c_str());
}