寫在前面:

首先當我們執行升級腳本updater-script的時候,就表示我們已經進入了升級安裝狀態。那么在我們就從實際的安裝作為入口開始分析。也就是說我們從install.cpp中的install_package函數開始一步步來分析。

這里主要分析與腳本相關的部分,其他的請參考這位朋友的博文http://blog.chinaunix.net/uid-22028566-id-3533856.html,我也很受啟發。這里也借用一張圖來幫助流程上的分析。

下面是調用的流程:install_package()-->really_install_package(),那么在really_install_package()函數中真正開始安裝的邏輯如下:

/* Verify and install the contents of the package.

*/

ui->Print("Installing update...\n");

err = try_update_binary(path, &zip, wipe_cache);

if(err != INSTALL_SUCCESS)

return err;    try_update_binary是真正實現讀取升級包中的腳本文件並執行相應的函數。在此函數中,通過調用fork函數創建出一個子進程,在子進程中開始讀取並執行升級腳本文件。在此需要注意的是函數fork的用法,fork被調用一次,將做兩次返回,在父進程中返回的是子進程的進程ID,為正數;而在子進程中,則返回0。子進程中所進行的操作,即execv(binary, args)。子進程創建成功后,開始執行升級代碼,並通過管道與父進程交互(創建管道,並將pipefd[1]作為參數傳遞給子進程,子進程則將相關信息寫入到此管道描述符中);而父進程則通過讀取子進程傳遞過來的信息更新UI。

那么下面我們來具體來分析一下這個方法具體的邏輯。

static int

try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {

//定義一個常量用來封裝查找相zip關信息的結果如“META-INF/com/google/android/update-binary”,便於后面進行解壓,因為之前mzOpenZipArchive函數並沒有對更新包進行解壓操作,*zip是之前mzOpenZipArchive方法返回的一個ZipArchive對象。mzOpenZipArchive是打開升級包,並將相關的信息拷貝到一個臨時的ZipArchinve變量中。

//ASSUMED_UPDATE_BINARY_NAME="META-INF/com/google/android/update-binary"

const ZipEntry* binary_entry =

mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);

if (binary_entry == NULL) {

mzCloseZipArchive(zip);

return INSTALL_CORRUPT;

}

const char* binary = "/tmp/update_binary";

unlink(binary);

//創建“/tmp/update_binary”文件

int fd = creat(binary, 0755);

if (fd < 0) {

mzCloseZipArchive(zip);

LOGE("Can't make %s\n", binary);

return INSTALL_ERROR;

}

//將META-INF/com/google/android/update-binary中的內容解壓縮到"/tmp/update_binary"下面。其實這個方法中主要是對update_binary操作的,如解壓和執行等。

bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);

close(fd);

mzCloseZipArchive(zip);

if (!ok) {

LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);

return INSTALL_ERROR;

}

int pipefd[2];

//創建管道,用於下面的子進程和父進程之間的通信

pipe(pipefd);

// When executing the update binary contained in the package, the

// arguments passed are:

//

// - the version number for this interface

//

// - an fd to which the program can write in order to update the

// progress bar. The program can write single-line commands:

//

// progress

// fill up the next part of of the progress bar

// over seconds. If is zero, use

// set_progress commands to manually control the

// progress of this segment of the bar

//

// set_progress

// should be between 0.0 and 1.0; sets the

// progress bar within the segment defined by the most

// recent progress command.

//

// firmware

// arrange to install the contents of in the

// given partition on reboot.

//

// (API v2: may start with "PACKAGE:" to

// indicate taking a file from the OTA package.)

//

// (API v3: this command no longer exists.)

//

// ui_print

// display on the screen.

//

// - the name of the package zip file.

//

const char** args = (const char**)malloc(sizeof(char*) * 5);

args[0] = binary;

args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk

char* temp = (char*)malloc(10);

sprintf(temp, "%d", pipefd[1]);

args[2] = temp;

args[3] = (char*)path;

args[4] = NULL;

//創建子進程。其中的子進程主要負責執行binary(execv(binary,args),即執行我們的安裝命令腳本),父進程負責接受子進程發送的命令去更新ui顯示(顯示當前的進度)。子父進程間通信依靠管道。

pid_t pid = fork();

if (pid == 0) {

close(pipefd[0]);

//執行update-binary,這個程序的實質就是去解析update.zip包中的updater-script腳本中的命令並執行。由此,Recovery服務就進入了實際安裝update.zip包的過程。在執行execv函數時,execv會停止執行當前的進程,並且以progname應用進程替換被停止執行的進程,進程ID沒有改變。這里的progname就是指update-binary,也就是被執行的應用程序。第二個參數argv,是指運行update-binaryt時,傳遞給執行程序的參數列表, 注意,這個數組的第一個參數應該是應用程序名字本身,並且最后一個參數應該為NULL,不參將多個參數合並為一個參數放入數組。

此外,如果應用程序正常執行完畢,那么execv是永遠不會返回的;當execv在調用進程中返回時,那么這個應用程序應該出錯了(可能是程序本身沒找到,權限不夠...),此時它的返回值應該是-1,具體的錯誤代碼可以通過全局變量errno查看,還可以通過stderr得到具體的錯誤描述字符串。

execv(binary, (char* const*)args);//其實我的理解就是update-binary相當一個exe可執行程序,這里就是一個雙擊可執行程序的動作

fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));

_exit(-1);

}

close(pipefd[1]);

*wipe_cache = 0;

char buffer[1024];

FILE* from_child = fdopen(pipefd[0], "r");

while (fgets(buffer, sizeof(buffer), from_child) != NULL) {

char* command = strtok(buffer, " \n");

if (command == NULL) {

continue;

} else if (strcmp(command, "progress") == 0) {

char* fraction_s = strtok(NULL, " \n");

char* seconds_s = strtok(NULL, " \n");

float fraction = strtof(fraction_s, NULL);

int seconds = strtol(seconds_s, NULL, 10);

ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);

} else if (strcmp(command, "set_progress") == 0) {

char* fraction_s = strtok(NULL, " \n");

float fraction = strtof(fraction_s, NULL);

ui->SetProgress(fraction);

} else if (strcmp(command, "ui_print") == 0) {

char* str = strtok(NULL, "\n");

if (str) {

ui->Print("%s", str);

} else {

ui->Print("\n");

}

fflush(stdout);

} else if (strcmp(command, "wipe_cache") == 0) {

*wipe_cache = 1;

#if 1 //wschen 2012-07-25

} else if (strcmp(command, "special_factory_reset") == 0) {

*wipe_cache = 2;

#endif

} else if (strcmp(command, "clear_display") == 0) {

ui->SetBackground(RecoveryUI::NONE);

} else {

LOGE("unknown command [%s]\n", command);

}

}

fclose(from_child);

int status;

waitpid(pid, &status, 0);

if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {

LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));

return INSTALL_ERROR;

}

#ifdef SUPPORT_DATA_BACKUP_RESTORE //wschen 2011-03-09

//Skip userdata restore if updating from /data with no /data layout change

if(!usrdata_changed && update_from_data){

ui->Print("/data offset remains the same no need to restore usrdata\n");

}else{

if (part_size_changed) {

if (ensure_path_mounted("/sdcard") != 0) {

LOGE("Can't mount %s\n", path);

return INSTALL_NO_SDCARD;

}

if (userdata_restore(backup_path, 1)) {

return INSTALL_FILE_SYSTEM_ERROR;

}

}

}

#endif //SUPPORT_DATA_BACKUP_RESTORE

/* ----------------------------- */

/* SECURE BOOT UPDATE */

/* ----------------------------- */

#ifdef SUPPORT_SBOOT_UPDATE

sec_update(false);

#endif

return INSTALL_SUCCESS;

}

android ota 升级脚本,Android OTA升級包制作腳本詳解(五,升級腳本updater-script的執行1)...相关推荐

  1. android ota升级服务,android 标准OTA升级流程

    标准的OTA升级流程包括一下几个步骤: 1.Android设备首先会与OTA服务器进行交互,如果有更新会推送给客户.推送的信息常常会包含OTA更新包的下载地址和一些版本信息. 2.Update程序会将 ...

  2. RTOS设备如何快速实现OTA升级--快速接入OTA平台

    目录 一. 创建产品和零件 1.1 登陆平台 1.2 添加产品 1.3 配置产品 1.4 添加升级零件 二. 添加设备 2.1 单个添加 2.2 批量添加 三. 设备注册激活 3.1 发起请求 3.2 ...

  3. ESP32 OTA升级之HTTP OTA

    ESP32 OTA升级之 HTTP OTA 文章目录 ESP32 OTA升级之 HTTP OTA 1. 前言 2. 搭建http本地服务器 2. HTTP OTA 3. 补充学习 1. 前言 在所有电 ...

  4. android.mk 执行脚本,Android.mk的用法

    (1)Android.mk是什么? Android.mk是Android提供的一种makefile文件.Android.mk其实是把真正的Makefile包装起来,做成了一个对使用者来说很简单的东西. ...

  5. 58 ESP32 OTA升级(双OTA分区无factory APP)

    1 引言 产品功能实现后,就要对产品的维护进行考虑.产品出来后,卖了N台出去,如果突然发现自己一行代码写错了,怎么办,肯定不能去现场吧N台设备,免费出差旅游也累啊,所以一般需要有远程升级设备的功能,此 ...

  6. android魅族升级,魅族Android 4.4 Flyme升级教程教学详细介绍

    魅族Android 4.4 Flyme升级教程教学详细介绍 注意事项: 1)已ROOT,或安装安全类软件进行了Android签名漏洞修补的'用户,请务必在升级时清除数据,否则可能会无法开机.清除数据会 ...

  7. android静默升级方案,Android静默更新程序

    先说我的应用场景,android板子嵌在机器里面.因为没有显示器,所以版本更新需要用到静默安装.先root... 静默更新流程: 1.服务里定时去检测是否有新的版本,下载新版本保存在本地 2.静默更新 ...

  8. android fota升级 开发,android fota升级

    1.    简介 fota(Firmware Over The Air),移动终端空中下载软件升级技术.原理是根据算法把新旧版本之间的差别做成一个软件包,手机从服务器上下载到手机里,由手机完成软件版本 ...

  9. android 在线升级apk,Android 在线升级APK

    @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setC ...

最新文章

  1. 【全网之最】最短代码清除数组中的假、空值(0、空、null、undefined、false)
  2. PyInstaller库的使用
  3. js jquery 数组的合并 对象的合并
  4. 关于jasmine里debugElement.query和fixture.detectChanges的依赖关系
  5. 【自己给自己题目做】:如何在Canvas上实现魔方效果
  6. Java基础---方法的重载(overload)+ 优先向上匹配原则
  7. pip安装gluonts
  8. 牛逼!支付宝 App架构
  9. 2021-06-27 方法的调用
  10. win7休眠 计算机管理,Win7休眠功能怎么关闭?
  11. Google 应用与游戏出海 4 月刊: 带您连线 GDC,赢在发布前!
  12. 计算机软件工作室起名'',游戏工作室起名大全
  13. 【JAVA】贪吃蛇的初步实现(三)
  14. ImportError: cannot import name ‘xxx‘ from ‘xxx‘
  15. WooCommerce Product Feed指南 – Google Shopping和Facebook[2022]
  16. 汉服经济迎来“井喷式”发展!vr全景助力汉服数字化蜕变
  17. C++ 计算直线的交点数(动态规划)
  18. 高数上册第七章小结笔记
  19. 2018东华计算机复试,18东华双控初试复试经验
  20. Opencv学习笔记 基于HOG和SVM的行人检测

热门文章

  1. 影像组学视频学习笔记(15)-ROC曲线及其绘制、Li‘s have a solution and plan.
  2. 机器学习-第九章 聚类
  3. R语言 (温度 随时间变化)
  4. C++所提供的类模板应用(堆栈)
  5. tf.keras.activations.softmax 激活函数 示例
  6. photoshop 图片转 pdf
  7. Linux (CentOS)安装VNC+XFCE可视化桌面环境 附安装FireFox浏览器
  8. php t double arrow,关于php:php – 语法错误,意外T_DOUBLE_ARROW
  9. qq说说时间轴php实现,PHP实现时间轴函数
  10. matlab门槛回归,重磅!这可能是最全的门槛回归汇总了