Android Fastboot源码分析情景一情景二情景三情景四:情景五总结

在Android的SDK中自带了fastboot,路径为

${SDK_HOME}/platform-tools/fastboot

查看help:

usage: fastboot [ <option> ] <command>

commands:
  update <filename>                        Reflash device from update.zip.
                                           Sets the flashed slot as active.
  flashall                                 Flash boot, system, vendor, and --
                                           if found -- recovery. If the device
                                           supports slots, the slot that has
                                           been flashed to is set as active.
                                           Secondary images may be flashed to
                                           an inactive slot.
  flash <partition> [ <filename> ]         Write a file to a flash partition.
  flashing lock                            Locks the device. Prevents flashing.
  flashing unlock                          Unlocks the device. Allows flashing
                                           any partition except
                                           bootloader-related partitions.
  flashing lock_critical                   Prevents flashing bootloader-related
                                           partitions.
  flashing unlock_critical                 Enables flashing bootloader-related
                                           partitions.
  flashing get_unlock_ability              Queries bootloader to see if the
                                           device is unlocked.
  flashing get_unlock_bootloader_nonce     Queries the bootloader to get the
                                           unlock nonce.
  flashing unlock_bootloader <request>     Issue unlock bootloader using request.
  flashing lock_bootloader                 Locks the bootloader to prevent
                                           bootloader version rollback.
  erase <partition>                        Erase a flash partition.
  format[:[<fs type>][:[<size>]] <partition>
                                           Format a flash partition. Can
                                           override the fs type and/or size
                                           the bootloader reports.
  getvar <variable>                        Display a bootloader variable.
  set_active <slot>                        Sets the active slot. If slots are
                                           not supported, this does nothing.
  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.
  flash:raw <bootable-partition> <kernel> [ <ramdisk> [ <second> ] ]
                                           Create bootimage and flash it.
  devices [-l]                             List all connected devices [with
                                           device paths].
  continue                                 Continue with autoboot.
  reboot [bootloader|emergency]            Reboot device [into bootloader or emergency mode].
  reboot-bootloader                        Reboot device into bootloader.
  oem <parameter1> ... <parameterN>        Executes oem specific command.
  stage <infile>                           Sends contents of <infile> to stage for
                                           the next command. Supported only on
                                           Android Things devices.
  get_staged <outfile>                     Receives data to <outfile> staged by the
                                           last command. Supported only on Android
                                           Things devices.
  help                                     Show this help message.

options:
  -w                                       Erase userdata and cache (and format
                                           if supported by partition type).
  -u                                       Do not erase partition before
                                           formatting.
  -s <specific device>                     Specify a device. For USB, provide either
                                           a serial number or path to device port.
                                           For ethernet, provide an address in the
                                           form <protocol>:<hostname>[:port] where
                                           <protocol> is either tcp or udp.
  -c <cmdline>                             Override kernel commandline.
  -i <vendor id>                           Specify a custom USB vendor id.
  -b, --base <base_addr>                   Specify a custom kernel base
                                           address (default: 0x10000000).
  --kernel-offset                          Specify a custom kernel offset.
                                           (default: 0x00008000)
  --ramdisk-offset                         Specify a custom ramdisk offset.
                                           (default: 0x01000000)
  --tags-offset                            Specify a custom tags offset.
                                           (default: 0x00000100)
  -n, --page-size <page size>              Specify the nand page size
                                           (default: 2048).
  -S <size>[K|M|G]                         Automatically sparse files greater
                                           than 'size'. 0 to disable.
  --slot <slot>                            Specify slot name to be used if the
                                           device supports slots. All operations
                                           on partitions that support slots will
                                           be done on the slot specified.
                                           'all' can be given to refer to all slots.
                                           'other' can be given to refer to a
                                           non-current slot. If this flag is not
                                           used, slotted partitions will default
                                           to the current active slot.
  -a, --set-active[=<slot>]                Sets the active slot. If no slot is
                                           provided, this will default to the value
                                           given by --slot. If slots are not
                                           supported, this does nothing. This will
                                           run after all non-reboot commands.
  --skip-secondary                         Will not flash secondary slots when
                                           performing a flashall or update. This
                                           will preserve data on other slots.
  --skip-reboot                            Will not reboot the device when
                                           performing commands that normally
                                           trigger a reboot.
  --disable-verity                         Set the disable-verity flag in the
                                           the vbmeta image being flashed.
  --disable-verification                   Set the disable-verification flag in                                           the vbmeta image being flashed.
  --wipe-and-use-fbe                       On devices which support it,
                                           erase userdata and cache, and
                                           enable file-based encryption
  --unbuffered                             Do not buffer input or output.
  --version                                Display version.
  -h, --help                               show this message.

够长的,好多参数解释看得也不是很懂。

自己编译Android源码也会产生fastboot,路径为:

${OUT}/host/darwin-x86/bin/fastboot //Mac的编译结果在darwin-x86下

查看help:

usage: fastboot [ <option> ] <command>

commands:
  update <filename>                        reflash device from update.zip
  flashall                                 flash boot + recovery + system
  flash <partition> [ <filename> ]         write a file to a flash partition
  erase <partition>                        erase a flash partition
  format <partition>                       format a flash partition
  getvar <variable>                        display a bootloader variable
  boot <kernel> [ <ramdisk> ]              download and boot kernel
  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it
  devices                                  list all connected devices
  continue                                 continue with autoboot
  reboot                                   reboot device normally
  reboot-bootloader                        reboot device into bootloader
  help                                     show this help message

options:
  -w                                       erase userdata and cache (and format
                                           if supported by partition type)
  -u                                       do not first erase partition before
                                           formatting
  -s <specific device>                     specify device serial number
                                           or path to device port
  -l                                       with "devices", lists device paths
  -p <product>                             specify product name
  -c <cmdline>                             override kernel commandline
  -i <vendor id>                           specify a custom USB vendor id
  -b <base_addr>                           specify a custom kernel base address. default: 0x10000000
  -n <page size>                           specify the nand page size. default: 2048
  -S <size>[K|M|G]                         automatically sparse files greater than
                                           size.  0 to disable

两者还不太一样,好像自己编译的在功能上是SDK自带的子集。在源码中有fastboot相关的代码,正好研究一下。

情景一

我们使用fastboot的第一个有效命令(不算 fastboot -h)通常是fastboot devices,我们来跟踪一下:

 if (argc > 0 && !strcmp(*argv, "devices")) {
        skip(1);
        list_devices();
        return 0;
    }

list_devices:

void list_devices(void) {
    // We don't actually open a USB device here,
    // just getting our callback called so we can
    // list all the connected devices.
    usb_open(list_devices_callback);
}

usb_open,不同操作系统有不同的实现,为了方便理解,我们分析Linux版本的实现(system/core/fastboot/usb_linux.c):

usb_handle *usb_open(ifc_match_func callback)
{
    return find_usb_device("/dev/bus/usb", callback);
}

find_usb_device:

static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
{
    usb_handle *usb = 0;
    char busname[64], devname[64];
    char desc[1024];
    int n, in, out, ifc;

    DIR *busdir, *devdir;
    struct dirent *de;
    int fd;
    int writable;

    busdir = opendir(base);
    if(busdir == 0) return 0;

    while((de = readdir(busdir)) && (usb == 0)) {
        if(badname(de->d_name)) continue;

        sprintf(busname, "%s/%s", base, de->d_name);
        devdir = opendir(busname);
        if(devdir == 0) continue;

//        DBG("[ scanning %s ]\n", busname);
        while((de = readdir(devdir)) && (usb == 0)) {

            if(badname(de->d_name)) continue;
            sprintf(devname, "%s/%s", busname, de->d_name);

//            DBG("[ scanning %s ]\n", devname);
            writable = 1;
            if((fd = open(devname, O_RDWR)) < 0) {
                // Check if we have read-only access, so we can give a helpful
                // diagnostic like "adb devices" does.
                writable = 0;
                if((fd = open(devname, O_RDONLY)) < 0) {
                    continue;
                }
            }

            n = read(fd, desc, sizeof(desc));

            if(filter_usb_device(fd, desc, n, writable, callback,
                                 &in, &out, &ifc) == 0) {
                usb = calloc(1, sizeof(usb_handle));
                strcpy(usb->fname, devname);
                usb->ep_in = in;
                usb->ep_out = out;
                usb->desc = fd;

                n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
                if(n != 0) {
                    close(fd);
                    free(usb);
                    usb = 0;
                    continue;
                }
            } else {
                close(fd);
            }
        }
        closedir(devdir);
    }
    closedir(busdir);

    return usb;
}

循环读取/dev/bus/usb目录下及子目录中的信息,解析并使用filter_usb_device过滤,然后对fastboot模式的usb进行callback调用,至于如何过滤fastboot模式的usb,这里面涉及到usb相关的知识,我也不是很了解,应该是通过usb信息中的某个标识来识别的,屌大的同学可以给我讲讲。

对callback的调用:

if(callback(&info) == 0) {
            *ept_in_id = in;
            *ept_out_id = out;
            *ifc_id = ifc->bInterfaceNumber;
            return 0;
        }

回到list_devices_callback:

int list_devices_callback(usb_ifc_info *info)
{
    if (match_fastboot_with_serial(info, NULL) == 0) {
        char* serial = info->serial_number;
        if (!info->writable) {
            serial = "no permissions"; // like "adb devices"
        }
        if (!serial[0]) {
            serial = "????????????";
        }
        // output compatible with "adb devices"
        if (!long_listing) {
            printf("%s\tfastboot\n", serial);
        } else if (!info->device_path) {
            printf("%-22s fastboot\n", serial);
        } else {
            printf("%-22s fastboot %s\n", serial, info->device_path);
        }
    }

    return -1;
}

其实就是输出连接的设备信息,假如是long_listing,会把device_path也输出来,long_listing通过 -l指定:

$ fastboot devices -l
01d977445292ca8c       fastboot usb:337838080X

情景二

在刷机的时候,通常使用fastboot -w flashall,先看看-w:

case 'w':
            wants_wipe = 1;
            break;

...

if (wants_wipe) {
        fb_queue_erase("userdata");
        fb_queue_format("userdata", 1);
        fb_queue_erase("cache");
        fb_queue_format("cache", 1);
    }

带上这个选项,会清除userdatacache中的内容。 再看看flashall:

else if(!strcmp(*argv, "flashall")) {
            skip(1);
            do_flashall(usb, erase_first);
            wants_reboot = 1;
        } 

do_flashall:

void do_flashall(usb_handle *usb, int erase_first)
{
    char *fname;
    void *data;
    unsigned sz;
    struct fastboot_buffer buf;
    int i;

    queue_info_dump();

    fb_queue_query_save("product", cur_product, sizeof(cur_product));

    fname = find_item("info", product);
    if (fname == 0) die("cannot find android-info.txt");
    data = load_file(fname, &sz);
    if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
    setup_requirements(data, sz);

    for (i = 0; i < ARRAY_SIZE(images); i++) {
        fname = find_item(images[i].part_name, product);
        if (load_buf(usb, fname, &buf)) {
            if (images[i].is_optional)
                continue;
            die("could not load %s\n", images[i].img_name);
        }
        do_send_signature(fname);
        if (erase_first && needs_erase(images[i].part_name)) {
            fb_queue_erase(images[i].part_name);
        }
        flash_buf(images[i].part_name, &buf);
    }
}

find_item:

char *find_item(const char *item, const char *product)
{
    char *dir;
    char *fn;
    char path[PATH_MAX + 128];

    if(!strcmp(item,"boot")) {
        fn = "boot.img";
    } else if(!strcmp(item,"recovery")) {
        fn = "recovery.img";
    } else if(!strcmp(item,"system")) {
        fn = "system.img";
    } else if(!strcmp(item,"userdata")) {
        fn = "userdata.img";
    } else if(!strcmp(item,"cache")) {
        fn = "cache.img";
    } else if(!strcmp(item,"info")) {
        fn = "android-info.txt";
    } else {
        fprintf(stderr,"unknown partition '%s'\n", item);
        return 0;
    }

    if(product) {
        get_my_path(path);
        sprintf(path + strlen(path),
                "../../../target/product/%s/%s", product, fn);
        return strdup(path);
    }

    dir = getenv("ANDROID_PRODUCT_OUT");
    if((dir == 0) || (dir[0] == 0)) {
        die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
        return 0;
    }

    sprintf(path, "%s/%s", dir, fn);
    return strdup(path);
}

会根据环境变量ANDROID_PRODUCT_OUT指定的目录下去找相关的文件,这里是android-info.txt。我们在刷机的时候,如果报找不到img文件时,需要设置ANDROID_PRODUCT_OUT就是这个原因。

接下来就是找相关的img文件,然后刷:

static struct {
    char img_name[13];
    char sig_name[13];
    char part_name[9];
    bool is_optional;
} images[3] = {
    {"boot.img", "boot.sig", "boot", false},
    {"recovery.img", "recovery.sig", "recovery", true},
    {"system.img", "system.sig", "system", false},
};

...

for (i = 0; i < ARRAY_SIZE(images); i++) {
        fd = unzip_to_file(zip, images[i].img_name);
        if (fd < 0) {
            if (images[i].is_optional)
                continue;
            die("update package missing %s", images[i].img_name);
        }
        rc = load_buf_fd(usb, fd, &buf);
        if (rc) die("cannot load %s from flash", images[i].img_name);
        do_update_signature(zip, images[i].sig_name);
        if (erase_first && needs_erase(images[i].part_name)) {
            fb_queue_erase(images[i].part_name);
        }
        flash_buf(images[i].part_name, &buf);
        /* not closing the fd here since the sparse code keeps the fd around
         * but hasn't mmaped data yet. The tmpfile will get cleaned up when the
         * program exits.
         */
    }

可以看到,flashall的时候,会批量刷入boot.img、recovery.img、system.img,其中recovery.img是可选刷入的。

其中load_buf_fd将解压的文件load到buf中。 flash_buf:

static void flash_buf(const char *pname, struct fastboot_buffer *buf)
{
    struct sparse_file **s;

    switch (buf->type) {
        case FB_BUFFER_SPARSE:
            s = buf->data;
            while (*s) {
                int64_t sz64 = sparse_file_len(*s, true, false);
                fb_queue_flash_sparse(pname, *s++, sz64);
            }
            break;
        case FB_BUFFER:
            fb_queue_flash(pname, buf->data, buf->sz);
            break;
        default:
            die("unknown buffer type: %d", buf->type);
    }
}

fb_queue_flash和fb_queue_flash_sparse:

void fb_queue_flash(const char *ptn, void *data, unsigned sz)
{
    Action *a;

    a = queue_action(OP_DOWNLOAD, "");
    a->data = data;
    a->size = sz;
    a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);

    a = queue_action(OP_COMMAND, "flash:%s", ptn);
    a->msg = mkmsg("writing '%s'", ptn);
}

void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz)
{
    Action *a;

    a = queue_action(OP_DOWNLOAD_SPARSE, "");
    a->data = s;
    a->size = 0;
    a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024);

    a = queue_action(OP_COMMAND, "flash:%s", ptn);
    a->msg = mkmsg("writing '%s'", ptn);
}

queue_action:

static Action *queue_action(unsigned op, const char *fmt, ...)
{
    Action *a;
    va_list ap;
    size_t cmdsize;

    a = calloc(1, sizeof(Action));
    if (a == 0) die("out of memory");

    va_start(ap, fmt);
    cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
    va_end(ap);

    if (cmdsize >= sizeof(a->cmd)) {
        free(a);
        die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
    }

    if (action_last) {
        action_last->next = a;
    } else {
        action_list = a;
    }
    action_last = a;
    a->op = op;
    a->func = cb_default;

    a->start = -1;

    return a;
}

其实就是将对应命令和数据放入到action_last链表中。那肯定有另外一个地方对这个链表进行真正的操作。 fb_execute_queue:

int fb_execute_queue(usb_handle *usb)
{
    Action *a;
    char resp[FB_RESPONSE_SZ+1];
    int status = 0;

    a = action_list;
    if (!a)
        return status;
    resp[FB_RESPONSE_SZ] = 0;

    double start = -1;
    for (a = action_list; a; a = a->next) {
        a->start = now();
        if (start < 0) start = a->start;
        if (a->msg) {
            // fprintf(stderr,"%30s... ",a->msg);
            fprintf(stderr,"%s...\n",a->msg);
        }
        if (a->op == OP_DOWNLOAD) {
            status = fb_download_data(usb, a->data, a->size);
            status = a->func(a, status, status ? fb_get_error() : "");
            if (status) break;
        } else if (a->op == OP_COMMAND) {
            status = fb_command(usb, a->cmd);
            status = a->func(a, status, status ? fb_get_error() : "");
            if (status) break;
        } else if (a->op == OP_QUERY) {
            status = fb_command_response(usb, a->cmd, resp);
            status = a->func(a, status, status ? fb_get_error() : resp);
            if (status) break;
        } else if (a->op == OP_NOTICE) {
            fprintf(stderr,"%s\n",(char*)a->data);
        } else if (a->op == OP_FORMAT) {
            status = fb_format(a, usb, (int)a->data);
            status = a->func(a, status, status ? fb_get_error() : "");
            if (status) break;
        } else if (a->op == OP_DOWNLOAD_SPARSE) {
            status = fb_download_data_sparse(usb, a->data);
            status = a->func(a, status, status ? fb_get_error() : "");
            if (status) break;
        } else {
            die("bogus action");
        }
    }

    fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
    return status;
}

fb_download_data:

int fb_download_data(usb_handle *usb, const void *data, unsigned size)
{
    char cmd[64];
    int r;

    sprintf(cmd, "download:%08x", size);
    r = _command_send(usb, cmd, data, size, 0);

    if(r < 0) {
        return -1;
    } else {
        return 0;
    }
}

_command_send:

static int _command_send(usb_handle *usb, const char *cmd,
                         const void *data, unsigned size,
                         char *response)
{
    int r;
    if (size == 0) {
        return -1;
    }

    r = _command_start(usb, cmd, size, response);
    if (r < 0) {
        return -1;
    }

    r = _command_data(usb, data, size);
    if (r < 0) {
        return -1;
    }

    r = _command_end(usb);
    if(r < 0) {
        return -1;
    }

    return size;
}

_command_start:

static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
                          char *response)
{
    int cmdsize = strlen(cmd);
    int r;

    if(response) {
        response[0] = 0;
    }

    if(cmdsize > 64) {
        sprintf(ERROR,"command too large");
        return -1;
    }

    if(usb_write(usb, cmd, cmdsize) != cmdsize) {
        sprintf(ERROR,"command write failed (%s)", strerror(errno));
        usb_close(usb);
        return -1;
    }

    return check_response(usb, size, response);
}

usb_write(system/core/fastboot/usb_linux.c):

int usb_write(usb_handle *h, const void *_data, int len)
{
    unsigned char *data = (unsigned char*) _data;
    unsigned count = 0;
    struct usbdevfs_bulktransfer bulk;
    int n;

    if(h->ep_out == 0) {
        return -1;
    }

    if(len == 0) {
        bulk.ep = h->ep_out;
        bulk.len = 0;
        bulk.data = data;
        bulk.timeout = 0;

        n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
        if(n != 0) {
            fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
                    n, errno, strerror(errno));
            return -1;
        }
        return 0;
    }

    while(len > 0) {
        int xfer;
        xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;

        bulk.ep = h->ep_out;
        bulk.len = xfer;
        bulk.data = data;
        bulk.timeout = 0;

        n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
        if(n != xfer) {
            DBG("ERROR: n = %d, errno = %d (%s)\n",
                n, errno, strerror(errno));
            return -1;
        }

        count += xfer;
        len -= xfer;
        data += xfer;
    }

    return count;
}

这里就是将内容写入到usb_handle对应的usb设备中。这样我们的数据就通过usb写入到设备中了,而在设备中,有对应的usb驱动程序来处理写过去的数据。对于设备如何处理写过去的数据,我并没有搜索到相关的代码,也许在厂商的驱动程序里面,同样,屌大的同学可以给我讲讲。

情景三

有时候我们只刷单个的img,使用的命令是fastboot flash xxx xxx.img,也来看看吧:

else if(!strcmp(*argv, "flash")) {
            char *pname = argv[1];
            char *fname = 0;
            require(2);
            if (argc > 2) {
                fname = argv[2];
                skip(3);
            } else {
                fname = find_item(pname, product);
                skip(2);
            }
            if (fname == 0) die("cannot determine image filename for '%s'", pname);
            if (erase_first && needs_erase(pname)) {
                fb_queue_erase(pname);
            }
            do_flash(usb, pname, fname);
        }

do_flash:

void do_flash(usb_handle *usb, const char *pname, const char *fname)
{
    struct fastboot_buffer buf;

    if (load_buf(usb, fname, &buf)) {
        die("cannot load '%s'", fname);
    }
    flash_buf(pname, &buf);
}

同样的是将数据load到buf,然后调用flash_bufflash_buf前面已经分析过了,就不再复述。

情景四:

在help中,我们看到这个:

 boot <kernel> [ <ramdisk> ]              download and boot kernel

貌似对boot镜像有特别的处理,跟踪一下:

else if(!strcmp(*argv, "boot")) {
            char *kname = 0;
            char *rname = 0;
            skip(1);
            if (argc > 0) {
                kname = argv[0];
                skip(1);
            }
            if (argc > 0) {
                rname = argv[0];
                skip(1);
            }
            data = load_bootable_image(kname, rname, &sz, cmdline);
            if (data == 0) return 1;
            fb_queue_download("boot.img", data, sz);
            fb_queue_command("boot", "booting");
        } 

其中,第一个参数为kernel文件名,第二个参数为ramdisk文件名(可选的)。

load_bootable_image:

void *load_bootable_image(const char *kernel, const char *ramdisk,
                          unsigned *sz, const char *cmdline)
{
    void *kdata = 0, *rdata = 0;
    unsigned ksize = 0, rsize = 0;
    void *bdata;
    unsigned bsize;

    if(kernel == 0) {
        fprintf(stderr, "no image specified\n");
        return 0;
    }

    kdata = load_file(kernel, &ksize);
    if(kdata == 0) {
        fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno));
        return 0;
    }

        /* is this actually a boot image? */
    if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
        if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);

        if(ramdisk) {
            fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
            return 0;
        }

        *sz = ksize;
        return kdata;
    }

    if(ramdisk) {
        rdata = load_file(ramdisk, &rsize);
        if(rdata == 0) {
            fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno));
            return  0;
        }
    }

    fprintf(stderr,"creating boot image...\n");
    bdata = mkbootimg(kdata, ksize, kernel_offset,
                      rdata, rsize, ramdisk_offset,
                      0, 0, second_offset,
                      page_size, base_addr, tags_offset, &bsize);
    if(bdata == 0) {
        fprintf(stderr,"failed to create boot.img\n");
        return 0;
    }
    if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
    fprintf(stderr,"creating boot image - %d bytes\n", bsize);
    *sz = bsize;

    return bdata;
}

先通过load_file将kernel加载到内存中,如果发现其魔数是ANDROID!,代表其已经是打包好的boot.img文件(包含了kernel和ramdisk),这种情况下就忽略对ramdisk的处理。 不然的话,就将ramdisk也加载到内存,并使用mkbootimg将二者打包成boot.img格式的数据。 然后将这个打包好的数据,写入的usb中,指定要刷的目标为boot.img

所以,这个命令可以有两种用法:

1. 
fastboot boot boot.img

2. 
fastboot boot kernel ramdisk //会先打包成boot.img

另外,可以看到,在使用mkbootimg时,用到了很多参数,很多参数是可以通过特定选项指定的,比如kernel_offset-k:

  case 'k':
            kernel_offset = strtoul(optarg, 0, 16);

情景五

类似的flash:raw:

else if(!strcmp(*argv, "flash:raw")) {
            char *pname = argv[1];
            char *kname = argv[2];
            char *rname = 0;
            require(3);
            if(argc > 3) {
                rname = argv[3];
                skip(4);
            } else {
                skip(3);
            }
            data = load_bootable_image(kname, rname, &sz, cmdline);
            if (data == 0) die("cannot load bootable image");
            fb_queue_flash(pname, data, sz);
        } 

fastboot boot类似,先将kernel和ramdisk打包,在刷入,这里的不同是,你需要指定pname,即boot,使用方式如下:

fastboot flash:raw boot kernel ramdisk

总结

至此,重要的几个命令分析清楚了,即通过fastboot协议,将数据写入到usb中。感觉完整的整个过程,需要再分析一下设备上的usb驱动接收到数据后的处理过程。但暂时没有相关的代码可以分析,先到此为止。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏儿童编程

天干地支五行八卦的对应关系

19790
来自专栏儿童编程

儿童创造力教育与编程教育的碰撞——MIT雷斯尼克教授最新理论梗概

儿童编程教育已经在我国各一线二线城市疯狂出现,颇有“烂大街”的趋势。我们不禁要问很多很多问题:

22370
来自专栏儿童编程

《动物魔法学校》儿童学编程Scratch之“外观”部分

导读:本文通过一个案例《动物魔法学校》来学习Scratch语言的“外观”部分。之后通过一系列其他功能的综合运用对作品功能进行了扩展。

19240
来自专栏华章科技

穿越十年后看互联网+:家电行业的金矿在哪里?

现在市场上炒得火热的智能家居未来出路在何方?做智能家居的创业者应该注意哪些机会?传统家电厂商又到底如何借助互联网进行转型?本文以智能空调为例,用故事的形式,提前...

8410
来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.2K20
来自专栏儿童编程

一张图理清《梅花易数》梗概

学《易经》的目的不一定是为了卜卦,但是了解卜卦绝对能够让你更好地了解易学。今天用一张思维导图对《梅花易数》的主要内容进行概括,希望能够给学友们提供帮助。

32440
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

18230
来自专栏儿童编程

我不是算命先生,却对占卜有了疑惑——如何论证“占卜前提”的正确与否

事出有因,我对《周易》感兴趣了很多年。只是觉得特别有趣,断断续续学习了一些皮毛。这几天又偶然接触到了《梅花易数》,觉得很是精彩,将五行八卦天干地支都串联了起来。...

15410
来自专栏儿童编程

声音功能让儿童编程更有创造性

导读:Scratch中声音功能非常强大,除了常规的音效,你甚至可以模拟各种乐器的各个发音、设置节拍、休止……如果你愿意,甚至可以用它创作一个交响乐。我们可以引导...

13840
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

30040

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励