Android5.0 Recovery源代码分析与定制(一)

简介: Android5.0 Recovery源代码分析与定制(一)

   Android的系统升级,Android的线刷,卡刷,格式化究竟有什么奇妙的地方呢?它又是怎么实现的呢?今天我将为大家揭开它的面纱!我们以Tiny4412的Recovery源代码为例,虽然4412并没有支持Recovery系统,但弄明白它的原理,我们也可以开发或者移植一个出来。其实,在recovery.cpp中开头就已经做了详细的说明,我们来看看。

 1/*
 2 * The recovery tool communicates with the main system through /cache files.
 3 *   /cache/recovery/command - INPUT - command line for tool, one arg per line
 4 *   /cache/recovery/log - OUTPUT - combined log file from recovery run(s)
 5 *   /cache/recovery/intent - OUTPUT - intent that was passed in
 6 *
 7 * The arguments which may be supplied in the recovery.command file:
 8 *   --send_intent=anystring - write the text out to recovery.intent
 9 *   --update_package=path - verify install an OTA package file
10 *   --wipe_data - erase user data (and cache), then reboot
11 *   --wipe_cache - wipe cache (but not user data), then reboot
12 *   --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
13 *   --just_exit - do nothing; exit and reboot
14 *
15 * After completing, we remove /cache/recovery/command and reboot.
16 * Arguments may also be supplied in the bootloader control block (BCB).
17 * These important scenarios must be safely restartable at any point:
18 *
19 * FACTORY RESET
20 * 1. user selects "factory reset"
21 * 2. main system writes "--wipe_data" to /cache/recovery/command
22 * 3. main system reboots into recovery
23 * 4. get_args() writes BCB with "boot-recovery" and "--wipe_data"
24 *    -- after this, rebooting will restart the erase --
25 * 5. erase_volume() reformats /data
26 * 6. erase_volume() reformats /cache
27 * 7. finish_recovery() erases BCB
28 *    -- after this, rebooting will restart the main system --
29 * 8. main() calls reboot() to boot main system
30 *
31 * OTA INSTALL
32 * 1. main system downloads OTA package to /cache/some-filename.zip
33 * 2. main system writes "--update_package=/cache/some-filename.zip"
34 * 3. main system reboots into recovery
35 * 4. get_args() writes BCB with "boot-recovery" and "--update_package=..."
36 *    -- after this, rebooting will attempt to reinstall the update --
37 * 5. install_package() attempts to install the update
38 *    NOTE: the package install must itself be restartable from any point
39 * 6. finish_recovery() erases BCB
40 *    -- after this, rebooting will (try to) restart the main system --
41 * 7. ** if install failed **
42 *    7a. prompt_and_wait() shows an error icon and waits for the user
43 *    7b; the user reboots (pulling the battery, etc) into the main system
44 * 8. main() calls maybe_install_firmware_update()
45 *    ** if the update contained radio/hboot firmware **:
46 *    8a. m_i_f_u() writes BCB with "boot-recovery" and "--wipe_cache"
47 *        -- after this, rebooting will reformat cache & restart main system --
48 *    8b. m_i_f_u() writes firmware image into raw cache partition
49 *    8c. m_i_f_u() writes BCB with "update-radio/hboot" and "--wipe_cache"
50 *        -- after this, rebooting will attempt to reinstall firmware --
51 *    8d. bootloader tries to flash firmware
52 *    8e. bootloader writes BCB with "boot-recovery" (keeping "--wipe_cache")
53 *        -- after this, rebooting will reformat cache & restart main system --
54 *    8f. erase_volume() reformats /cache
55 *    8g. finish_recovery() erases BCB
56 *        -- after this, rebooting will (try to) restart the main system --
57 * 9. main() calls reboot() to boot main system
58 */

  在这段英文注释里,详细的说明了factory_reset(Android的恢复出厂设置功能)的流程以及OTA系统更新的流程。在这段注释得最前面说得很明白,我们只要往/cache/recovery/command中写入相应的命令即可完成对应的功能。

1* The arguments which may be supplied in the recovery.command file:
2 *   --send_intent=anystring - write the text out to recovery.intent
3 *   --update_package=path - verify install an OTA package file
4 *   --wipe_data - erase user data (and cache), then reboot
5 *   --wipe_cache - wipe cache (but not user data), then reboot
6 *   --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
7 *   --just_exit - do nothing; exit and reboot

比如写入:

--update_package=path(对应的OTA更新的路径)

例如:

--update_package=/mnt/external_sd/xxx.zip

   将这条命令写入后,再重启Android系统,recovery检测到有这个命令存在,就会去搜索这个路径,然后将这个路径做路径转换,接下来获取转换后的路径后,就挂载这个路径,然后挂载这个路径,获取OTA包,解包,校验,然后最后实现真正的更新。    

   如果我们往这个文件写入: --wipe_data那么就会做出厂设置,格式化/data分区的内容。接下来,我们来看看代码,从main函数开始分析:进入main函数后,会将recovery产生的log信息重定向到/tmp/recovery.log这个文件里,具体代码实现如下:

1//重定向标准输出和标准出错到/tmp/recovery.log 这个文件里
2//static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
3redirect_stdio(TEMPORARY_LOG_FILE);

redirect_stdio函数源代码实现:

1static void redirect_stdio(const char* filename) {
2    // If these fail, there's not really anywhere to complain...
3    freopen(filename, "a", stdout); setbuf(stdout, NULL);
4    freopen(filename, "a", stderr); setbuf(stderr, NULL);
5}

   我们看到,所有产生来自stdout和stderr的信息会使用freopen这个函数重定向到/tmp/recovery.log这个文件里。stdout就是标准输出,stdout就是标准出错。标准输出就是我们平时使用的printf输出的信息。    

   当然也可以使用fprintf(stdout,"hello world\n");也是一样的标准出错就是fprintf(stderr,"hello world!\n");类似的代码。接下下来,将会判断是否使用adb的sideload来传入,通过参数--adbd来判断:

 1    // If this binary is started with the single argument "--adbd",
 2    // instead of being the normal recovery binary, it turns into kind
 3    // of a stripped-down version of adbd that only supports the
 4    // 'sideload' command.  Note this must be a real argument, not
 5    // anything in the command file or bootloader control block; the
 6    // only way recovery should be run with this argument is when it
 7    // starts a copy of itself from the apply_from_adb() function.
 8    if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
 9        adb_main();
10        return 0;
11    }

   做完这些步骤以后,会初始化并装载recovery的分区表recovery.fstab,然后挂载/cache/recovery/last_log这个文件,用来输出log。

1    printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
2    //装载recovery的分区表recovery.fstab
3    load_volume_table();
4    //在recovery中挂载/cache/recovery/last_log这个文件
5    //#define LAST_LOG_FILE "/cache/recovery/last_log"
6    ensure_path_mounted(LAST_LOG_FILE);
7    rotate_last_logs(KEEP_LOG_COUNT);

这里主要看如何装载分区表的流程,先来看看recovery.fstab

1/dev/block/by-name/boot         /boot         emmc     defaults                                                                defaults
2/dev/block/by-name/recovery     /recovery     emmc     defaults                                                                defaults
3/dev/block/by-name/splashscreen /splashscreen emmc     defaults                                                                defaults
4/dev/block/by-name/fastboot     /fastboot     emmc     defaults                                                                defaults
5/dev/block/by-name/misc         /misc         emmc     defaults                                                                defaults
6/dev/block/by-name/system       /system       ext4     ro,noatime                                                              wait
7/dev/block/by-name/cache        /cache        ext4     nosuid,nodev,noatime,barrier=1,data=ordered                             wait,check
8/dev/block/by-name/userdata     /data         ext4     nosuid,nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc     wait,check
9/dev/block/by-name/factory      /factory      ext4     nosuid,nodev,noatime,barrier=1,data=ordered                             wait
1void load_volume_table()
 2{
 3    int i;
 4    int ret;
 5    //读recovery.fstab 这个分区表
 6    fstab = fs_mgr_read_fstab("/etc/recovery.fstab");
 7    if (!fstab) {
 8        LOGE("failed to read /etc/recovery.fstab\n");
 9        return;
10    }
11    //将对应的信息加入到一条链表中
12    ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk");
13    //如果load到的分区表为空,后面做释放操作
14    if (ret < 0 ) {
15        LOGE("failed to add /tmp entry to fstab\n");
16        fs_mgr_free_fstab(fstab);
17        fstab = NULL;
18        return;
19    }
20
21    printf("recovery filesystem table\n");
22    printf("=========================\n");
23    //到这一步,打印分区表信息,这类信息在
24    //recovery启动的时候的log可以看到
25    //分别是以下
26    //编号|   挂载节点|  文件系统类型|  块设备|   长度
27    for (i = 0; i < fstab->num_entries; ++i) {
28        Volume* v = &fstab->recs[i];
29        printf("  %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
30               v->blk_device, v->length);
31    }
32    printf("\n");
33}


   挂载完相应的分区以后,就需要获取命令参数,因为只有挂载了对应的分区,才能访问到前面要写入command的这个文件,这样我们才能正确的打开文件,如果分区都没找到,那么当然就找不到分区上的文件,上面这个步骤是至关重要的。

 1//获取参数
 2    //这个参数也可能是从/cache/recovery/command文件中得到相应的命令
 3    //也就是可以往command这个文件写入对应的格式的命令即可
 4    get_args(&argc, &argv);
 5
 6    const char *send_intent = NULL;
 7    const char *update_package = NULL;
 8    int wipe_data = 0, wipe_cache = 0, show_text = 0;
 9    bool just_exit = false;
10    bool shutdown_after = false;
11
12    int arg;
13    //参数有擦除分区,OTA更新等
14    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
15        switch (arg) {
16        case 's': send_intent = optarg; break;
17        case 'u': update_package = optarg; break;
18        case 'w': wipe_data = wipe_cache = 1; break;
19        case 'c': wipe_cache = 1; break;
20        case 't': show_text = 1; break;
21        case 'x': just_exit = true; break;
22        case 'l': locale = optarg; break;
23        case 'g': {
24            if (stage == NULL || *stage == '\0') {
25                char buffer[20] = "1/";
26                strncat(buffer, optarg, sizeof(buffer)-3);
27                stage = strdup(buffer);
28            }
29            break;
30        }
31        case 'p': shutdown_after = true; break;
32        case 'r': reason = optarg; break;
33        case '?':
34            LOGE("Invalid command argument\n");
35            continue;
36        }
37    }

  获取到对应的命令,就会执行对应的标志,后面会根据标志来执行对应的操作。

   做完以上的流程后,下面就是创建设备,设置语言信息,初始化recovery的UI界面,设置Selinux权限,代码如下:

 1//设置语言
 2    if (locale == NULL) {
 3        load_locale_from_cache();
 4    }
 5    printf("locale is [%s]\n", locale);
 6    printf("stage is [%s]\n", stage);
 7    printf("reason is [%s]\n", reason);
 8    //创建设备
 9    Device* device = make_device();
10    //获取UI
11    ui = device->GetUI();
12    //设置当前的UI
13    gCurrentUI = ui;
14    //设置UI的语言信息
15    ui->SetLocale(locale);
16    //UI初始化
17    ui->Init();
18
19    int st_cur, st_max;
20    if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) {
21        ui->SetStage(st_cur, st_max);
22    }
23    //设置recovery的背景图
24    ui->SetBackground(RecoveryUI::NONE);
25    //设置界面上是否能够显示字符,使能ui->print函数开关
26    if (show_text) ui->ShowText(true);
27    //设置selinux权限,一般我会把selinux 给disabled
28    struct selinux_opt seopts[] = {
29      { SELABEL_OPT_PATH, "/file_contexts" }
30    };
31
32    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
33
34    if (!sehandle) {
35        ui->Print("Warning: No file_contexts\n");
36    }
37    //虚函数,没有做什么流程
38    device->StartRecovery();
39
40    printf("Command:");
41    for (arg = 0; arg < argc; arg++) {
42        printf(" \"%s\"", argv[arg]);
43    }
44    printf("\n"); 

   接下来是重要的环节,这个环节将会根据上面命令参数来做真正的事情了,比如恢复出厂设置,OTA更新等。

 1//如果update_package(也就是要升级的OTA包)不为空的情况下
  2    //这里要对升级包的路径做一下路径转换,这里可以自由定制自己升级包的路径
  3    if (update_package) {
  4        // For backwards compatibility on the cache partition only, if
  5        // we're given an old 'root' path "CACHE:foo", change it to
  6        // "/cache/foo".
  7
  8    //这里就是做转换的方法
  9    //先比较传进来的recovery参数的前6个byte是否是CACHE
 10    //如果是将其路径转化为/cache/CACHE: ......
 11        if (strncmp(update_package, "CACHE:", 6) == 0) {
 12            int len = strlen(update_package) + 10;
 13            char* modified_path = (char*)malloc(len);
 14            strlcpy(modified_path, "/cache/", len);
 15            strlcat(modified_path, update_package+6, len);
 16            printf("(replacing path \"%s\" with \"%s\")\n",
 17                   update_package, modified_path);
 18            //这个update_package就是转换后的路径
 19            update_package = modified_path;
 20        }
 21    }
 22    printf("\n");
 23    property_list(print_property, NULL);
 24    //获取属性,这里应该是从一个文件中找到ro.build.display.id
 25    //获取recovery的版本信息
 26    property_get("ro.build.display.id", recovery_version, "");
 27    printf("\n");
 28
 29    //定义一个安装成功的标志位INSTALL_SUCCESS  ----> 其实是个枚举,值为0
 30    int status = INSTALL_SUCCESS;
 31    //判断转换后的OTA升级包的路径是否不为空,如果不为空
 32    //执行install_package 函数进行升级
 33    if (update_package != NULL) {
 34        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE, true);
 35        //判断是否升级成功
 36        if (status == INSTALL_SUCCESS && wipe_cache) {
 37            //擦除这个路径,相当于删除了这个路径下的OTA升级包
 38            if (erase_volume("/cache")) {
 39                LOGE("Cache wipe (requested by package) failed.");
 40            }
 41        }
 42        //如果安装不成功
 43        if (status != INSTALL_SUCCESS) {
 44            ui->Print("Installation aborted.\n");
 45
 46            // If this is an eng or userdebug build, then automatically
 47            // turn the text display on if the script fails so the error
 48            // message is visible.
 49            char buffer[PROPERTY_VALUE_MAX+1];
 50            property_get("ro.build.fingerprint", buffer, "");
 51            if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) {
 52                ui->ShowText(true);
 53            }
 54        }
 55    }
 56    //如果跑的是格式化数据区,那么就走这个流程
 57    else if (wipe_data) {
 58        if (device->WipeData()) status = INSTALL_ERROR;
 59        //格式化/data分区
 60        if (erase_volume("/data")) status = INSTALL_ERROR;
 61        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
 62        if (erase_persistent_partition() == -1 ) status = INSTALL_ERROR;
 63        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
 64    } 
 65    //格式化cache分区
 66    else if (wipe_cache) {
 67        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
 68        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
 69    } 
 70    else if (!just_exit) {
 71        status = INSTALL_NONE;  // No command specified
 72        ui->SetBackground(RecoveryUI::NO_COMMAND);
 73    }
 74    //如果安装失败或者。。。
 75    if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
 76        copy_logs();
 77        //显示错误的LOGO
 78        ui->SetBackground(RecoveryUI::ERROR);
 79    }
 80    Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT;
 81    if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
 82        Device::BuiltinAction temp = prompt_and_wait(device, status);
 83        if (temp != Device::NO_ACTION) after = temp;
 84    }
 85
 86    // Save logs and clean up before rebooting or shutting down.
 87    //完成recovery升级
 88    finish_recovery(send_intent);
 89
 90    switch (after) {
 91        case Device::SHUTDOWN:
 92            ui->Print("Shutting down...\n");
 93            property_set(ANDROID_RB_PROPERTY, "shutdown,");
 94            break;
 95
 96        case Device::REBOOT_BOOTLOADER:
 97            ui->Print("Rebooting to bootloader...\n");
 98            property_set(ANDROID_RB_PROPERTY, "reboot,bootloader");
 99            break;
100
101        default:
102            ui->Print("Rebooting...\n");
103            property_set(ANDROID_RB_PROPERTY, "reboot,");
104            break;
105    }
106    sleep(5); // should reboot before this finishes
107    return EXIT_SUCCESS;

   在这里面,我们最常用的即是OTA更新和恢复出厂设置,先来说说恢复出厂设置,这个功能就是所谓的手机双清,众所周知,Android手机在使用很久后,由于垃圾数据,以及其它的因素会导致手机的反应越来越慢,这让人烦恼不已,所以就需要双清,双清一般就是清除/data分区和/cache分区,代码流程很详细,有兴趣可以自己去分析。


   接下来看看OTA是如何实现更新的,我们看到install_ota_package这个函数,执行到这个函数,看到源码:

 1//安装更新包
 2int
 3install_package(const char* path, int* wipe_cache, const char* install_file,
 4                bool needs_mount)
 5{
 6    FILE* install_log = fopen_path(install_file, "w");
 7    if (install_log) {
 8        fputs(path, install_log);
 9        fputc('\n', install_log);
10    } else {
11        LOGE("failed to open last_install: %s\n", strerror(errno));
12    }
13    int result;
14    //设置安装挂载对应的节点
15    //这一步是关键
16    if (setup_install_mounts() != 0) {
17        LOGE("failed to set up expected mounts for install; aborting\n");
18        result = INSTALL_ERROR;
19    } else {
20        //到这里才是真正的去安装OTA包
21        result = really_install_package(path, wipe_cache, needs_mount);
22    }
23    //如果返回结果为0,那么安装就成功了
24    if (install_log) {
25        fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
26        fputc('\n', install_log);
27        fclose(install_log);
28    }
29    return result;
30}

   其实到了really_install_package这一步,才是真正做到OTA更新,但是在OTA更新之前至关重要的一步就是设置安装挂载对应的节点了,我曾经掉入此坑,现在拿出来分析一下,我们来看看setup_install_mounts这个函数:

 1//设置安装挂载的节点
 2int setup_install_mounts() {
 3    if (fstab == NULL) {
 4        LOGE("can't set up install mounts: no fstab loaded\n");
 5        return -1;
 6    }
 7    for (int i = 0; i < fstab->num_entries; ++i) {
 8        Volume* v = fstab->recs + i;
 9    //如果判断挂载的路径是/tmp 或者/cache
10    //那么就挂载对应的节点,而其它的节点都不会去挂载
11        if (strcmp(v->mount_point, "/tmp") == 0 ||
12            strcmp(v->mount_point, "/cache") == 0) {
13            if (ensure_path_mounted(v->mount_point) != 0) {
14                LOGE("failed to mount %s\n", v->mount_point);
15                return -1;
16            }
17
18        }
19        //如果不是/tmp或者/cache这两个节点,则默认就会卸载所有的挂载节点
20        else {
21            //卸载所有的挂载节点
22            if (ensure_path_unmounted(v->mount_point) != 0) {
23                LOGE("failed to unmount %s\n", v->mount_point);
24                return -1;
25            }
26        }
27    }
28    return 0;
29} 

   如果在安装更新的时候,OTA包经过路径转换后不是放在/tmp和/cache这个路径下的时候,那么就会走else分支,从而卸载所有的挂载节点,这样就会导致,传的路径正确,却OTA更新不成功,如果是做自己定制的路径,这一步一定要小心,我们可以在这里继续添加定制的挂载点。那么,执行完设置挂载节点的函数后,接下来就是执行真正的OTA更新了,我们来看看:

 1static int
 2really_install_package(const char *path, int* wipe_cache, bool needs_mount)
 3{
 4    //设置更新时的背景
 5    ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
 6    ui->Print("Finding update package...\n");
 7    // Give verification half the progress bar...
 8    //设置进度条的类型
 9    ui->SetProgressType(RecoveryUI::DETERMINATE);
10    //显示进度条
11    ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
12    LOGI("Update location: %s\n", path);
13    //在屏幕上打印 Opening update package..
14    // Map the update package into memory.
15    ui->Print("Opening update package...\n");
16    //patch是OTA的路径,need_mount参数表示是否需要挂载,1挂载,0,不挂载
17    if (path && needs_mount) {
18        if (path[0] == '@') {
19            ensure_path_mounted(path+1);
20        } else {
21            //挂载OTA升级包的路径------> 一般是执行这个流程
22            ensure_path_mounted(path);
23        }
24    }
25
26    MemMapping map;
27    if (sysMapFile(path, &map) != 0) {
28        LOGE("failed to map file\n");
29        return INSTALL_CORRUPT;
30    }
31
32    int numKeys;
33    //获取校验公钥文件
34    Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
35    if (loadedKeys == NULL) {
36        LOGE("Failed to load keys\n");
37        return INSTALL_CORRUPT;
38    }
39    LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
40
41    ui->Print("Verifying update package...\n");
42
43    int err;
44    //校验文件
45    err = verify_file(map.addr, map.length, loadedKeys, numKeys);
46    free(loadedKeys);
47    LOGI("verify_file returned %d\n", err);
48    //如果校验不成功
49    if (err != VERIFY_SUCCESS) {
50        //打印签名失败
51        LOGE("signature verification failed\n");
52        sysReleaseMap(&map);
53        return INSTALL_CORRUPT;
54    }
55
56    /* Try to open the package.
57     */
58    //尝试去打开ota压缩包
59    ZipArchive zip;
60    err = mzOpenZipArchive(map.addr, map.length, &zip);
61    if (err != 0) {
62        LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
63        sysReleaseMap(&map);
64        return INSTALL_CORRUPT;
65    }
66
67    /* Verify and install the contents of the package.
68     */
69    //开始安装升级包
70    ui->Print("Installing update...\n");
71    ui->SetEnableReboot(false);
72    int result = try_update_binary(path, &zip, wipe_cache);
73    //安装成功后自动重启
74    ui->SetEnableReboot(true);
75    ui->Print("\n");
76
77    sysReleaseMap(&map);
78    //返回结果
79    return result;
80}

   关于recovery的大致流程,我们分析至此,关于如何像MTK平台一样,定制recovery,这就需要读者能够读懂recovery的流程,然后加入自己的代码进行定制,当然我们也会看到,一些recovery花样百出,很多UI做了自己的,而不是用安卓系统原生态的,安卓系统recovery原生态的UI如下:

640.jpg

   如何定制相应的UI,后续我们会对recovery源代码中的UI显示做进一步的分析。。。。

目录
相关文章
|
17天前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
2月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
51 2
|
25天前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
49 15
Android 系统缓存扫描与清理方法分析
|
1月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
2月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
139 3
|
1月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。
|
2月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。
|
3月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
【8月更文挑战第20天】在移动应用开发的广阔天地中,Android和iOS两大平台各自占据着重要的位置。本文将深入探讨这两种操作系统的开发环境,从编程语言到开发工具,从用户界面设计到性能优化,以及市场趋势对开发者选择的影响。我们旨在为读者提供一个全面的比较视角,帮助理解不同平台的优势与挑战,并为那些站在选择十字路口的开发者提供有价值的参考信息。
|
2月前
|
IDE 开发工具 Android开发
安卓与iOS开发环境对比分析
本文将探讨安卓和iOS这两大移动操作系统在开发环境上的差异,从工具、语言、框架到生态系统等多个角度进行比较。我们将深入了解各自的优势和劣势,并尝试为开发者提供一些实用的建议,以帮助他们根据自己的需求选择最适合的开发平台。
49 1
|
3月前
|
搜索推荐 Android开发
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
本文分享了不同价位电脑配置对于编译AOSP安卓系统源代码的影响,提供了从6000元到更高价位的电脑配置实例,并比较了它们的编译时间,以供学习AOSP源代码时电脑配置选择的参考。
250 0
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
下一篇
无影云桌面