前言
前面分析了 UpdateEngine 模塊的編譯和啟動(dòng)流程,對(duì)于 UpdateEngine 模塊已經(jīng)有了初步的了解,接下來我們從升級(jí)的功能出發(fā),分析 UpdateEngine 的升級(jí)過程,升級(jí)過程的內(nèi)容非常的多,準(zhǔn)備從 UpdateEngine 的 Action 機(jī)制開始分析,UpdateEngine 的升級(jí)過程有很多步驟,每一個(gè)步驟由一個(gè) Action 去控制。因此,我們先說明 UpdateEngine 模塊的 Action 機(jī)制,并從升級(jí)的觸發(fā)方式以及實(shí)現(xiàn)流程展開描述。
上一篇:Android UpdateEngine 模塊分析(二)UpdateEngine 服務(wù)啟動(dòng)
下一篇:Android UpdateEngine 模塊分析(四)UpdateEngine 升級(jí)邏輯
正文
關(guān)于 UpdateEngine 的升級(jí)有兩種方式觸發(fā):
第一種是采用命令行客戶端的形式觸發(fā),此種觸發(fā)方式在命令行中通過 update_engine_client 工具觸發(fā);
第二種是采用 Android 提供的原生接口觸發(fā),此處觸發(fā)方式基于 Aidl 接口與 UpdateEngine 進(jìn)行通信,按流程觸發(fā);
1、update_engine_client 命令行
在使用 update_engine_client 命令行的方式觸發(fā)升級(jí)時(shí),需要先將 SOC 的 zip 升級(jí)包解壓,得到如下格式文件:
├── META-INF
│ └── com
│ └── android
│ ├── metadata
│ └── otacert
├── payload.bin
└── payload_properties.txt
update_engine_client 命令格式為:
update_engine_client --payload=file://payload.bin路徑 --update --headers="文件hash、文件大小、metadata hash、metadata大小"
然后在 cmd 命令行中進(jìn)入 adb shell。輸入升級(jí)命令:
update_engine_client --payload=file:///storage/5F49-FB9D/socupdate/payload.bin --update --headers="FILE_HASH=PLo9cSeCeECAhKHlk06drRFHCyd1BGHE/fliEd0F3uQ=
FILE_SIZE=2447066254
METADATA_HASH=H+gFeOLUWil1LyX4VOJIhGvHHv+MrFu1RBdxXzhorHQ=
METADATA_SIZE=179338"
升級(jí)完成后可以通過 cat proc/cmdline 查看升級(jí)前后的 AB 分區(qū)切換情況,判斷升級(jí)是否成功,“androidboot.slot_suffix” 代表著當(dāng)前運(yùn)行分區(qū),如下所示:
:/ # cat proc/cmdline
root=/dev/ram0 rootfstype=ramfs highres=1 earlycon loglevel=4 console=ttyS0,115200n8 fbcon=map:1 androidboot.mode=normal androidboot.debuggable=1 androidboot.dm_verity=disable androidboot.vdsp=disable init=/init init=/init androidboot.console=ttyS0 consoleblank=0 androidboot.hardware=x9m_ref androidboot.boot_devices=soc/34180000.sdhci,soc/341a0000.sdhci firmware_class.path=/vendor/firmware hardware.platform=x9m_ref androidboot.wificountrycode=CN buildvariant=userdebug androidboot.slot_suffix=_b androidboot.storage_type=emmc androidboot.verifiedbootstate=orange androidboot.force_normal_boot=1
2、Android 接口
在 Android 源碼中,Google 提供了一個(gè)名為 SystemUpdater 的 apk 用以本地 U盤升級(jí) SOC 的 Demo,可以理解為描述 update_engine 接口調(diào)用流程的 Demo 應(yīng)用。我們接下來將從這個(gè)應(yīng)用入手,從接口調(diào)用流程上出發(fā),按流程分析使用原生接口升級(jí)的流程。
2.1 應(yīng)用 SystemUpdater
2.1.1 SystemUpdater 介紹
SystemUpdater 應(yīng)用的代碼目錄為:android/packages/apps/Car/SystemUpdater
應(yīng)用啟動(dòng)命令:adb shell am start -n com.android.car.systemupdater.SystemUpdaterActivity
主要功能有:
? 讀取 U盤 中的升級(jí)文件,用戶點(diǎn)擊目標(biāo)升級(jí)文件
? 注冊(cè) UpdateEngine 升級(jí)進(jìn)度、結(jié)果回調(diào),調(diào)用 UpdateEngine 升級(jí)接口傳遞升級(jí)參數(shù)觸發(fā)升級(jí)
? 在升級(jí)結(jié)束之后通知 powermanager 重啟機(jī)器
代碼文件有:
├── DeviceListFragment.java
├── SystemUpdaterActivity.java
├── UpdateLayoutFragment.java
├── UpdateParser.java
└── UpFragment.java
2.2.2 SystemUpdater 關(guān)鍵流程
下面為 SystemUpdater 調(diào)用的時(shí)序圖:
對(duì)于升級(jí)來說,有兩個(gè)步驟是必須的,第一個(gè)是注冊(cè)升級(jí)進(jìn)度、結(jié)果的回調(diào);第二個(gè)是觸發(fā)升級(jí)。
下面是 SystemUpdater 有關(guān)升級(jí)的部分代碼:
/** Show the install now button. */
private void showInstallNow(UpdateParser.ParsedUpdate update) {
mContentTitle.setText(R.string.install_ready);
mContentInfo.append(getString(R.string.update_file_name, mUpdateFile.getName()));
mContentInfo.append(System.getProperty("line.separator"));
mContentInfo.append(getString(R.string.update_file_size));
mContentInfo.append(Formatter.formatFileSize(getContext(), mUpdateFile.length()));
mContentDetails.setText(null);
mSystemUpdateToolbarAction.setOnClickListener(v -> installUpdate(update)); // 準(zhǔn)備升級(jí)
mSystemUpdateToolbarAction.setText(R.string.install_now);
mSystemUpdateToolbarAction.setVisibility(View.VISIBLE);
}
/** Attempt to install the update that is copied to the device. */
private void installUpdate(UpdateParser.ParsedUpdate parsedUpdate) {
showInstallationInProgress(); // 注冊(cè)升級(jí)信息回調(diào)并顯示升級(jí)進(jìn)度
mUpdateEngine.applyPayload(
parsedUpdate.mUrl, parsedUpdate.mOffset, parsedUpdate.mSize, parsedUpdate.mProps); // 調(diào)用升級(jí)接口觸發(fā)升級(jí)
}
/** Set the layout to show installation progress. */
private void showInstallationInProgress() {
mInstallationInProgress = true;
mProgressBar.setIndeterminate(false);
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setMax(PERCENT_MAX);
mSystemUpdateToolbarAction.setVisibility(View.GONE);
showStatus(R.string.install_in_progress);
mUpdateEngine.bind(mCarUpdateEngineCallback, new Handler(getContext().getMainLooper())); // 綁定升級(jí)信息回調(diào)
}
/** Handles events from the UpdateEngine. */
// 升級(jí)信息回調(diào)實(shí)現(xiàn)
public class CarUpdateEngineCallback extends UpdateEngineCallback {
// 升級(jí)狀態(tài)、進(jìn)度回調(diào)
@Override
public void onStatusUpdate(int status, float percent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, String.format("onStatusUpdate %d, Percent %.2f", status, percent));
}
switch (status) {
case UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT:
rebootNow();
break;
case UpdateEngine.UpdateStatusConstants.DOWNLOADING:
mProgressBar.setProgress((int) (percent * 100));
break;
default:
// noop
}
}
// 升級(jí)結(jié)果回調(diào)
@Override
public void onPayloadApplicationComplete(int errorCode) {
Log.w(TAG, String.format("onPayloadApplicationComplete %d", errorCode));
mInstallationInProgress = false;
showStatus(errorCode == UpdateEngine.ErrorCodeConstants.SUCCESS
? R.string.install_success
: R.string.install_failed);
mProgressBar.setVisibility(View.GONE);
mSystemUpdateToolbarAction.setVisibility(View.GONE);
}
}
/** Build a notification to show the installation status. */
private static Notification createNotification(Context context, @StringRes int contents) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(context, SystemUpdaterActivity.class));
intent.putExtra(EXTRA_RESUME_UPDATE, true);
PendingIntent pendingIntent =
PendingIntent.getActivity(
context,
/* requestCode= */ 0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentTitle(context.getString(contents))
.setSmallIcon(R.drawable.ic_system_update_alt_black_48dp)
.setContentIntent(pendingIntent)
.setShowWhen(false)
.setOngoing(true)
.setAutoCancel(false)
.build();
}
2.2 UpdateEngine 架構(gòu)
下圖為 UpdateEngine 架構(gòu)圖
UpdateEngine模塊結(jié)構(gòu)描述:
(1) Framework Java模塊
系統(tǒng)編譯生成framework.jar包,向Application提供升級(jí)調(diào)用接口;和底層Hal層進(jìn)行交互回調(diào)
(2) AIDL接口
描述上層和HAL層的接口定義,進(jìn)行進(jìn)程間通信
(3) HAL層模塊
update_engine業(yè)務(wù)處理的主要模塊,實(shí)現(xiàn)AIDL接口提供服務(wù)。將SOC升級(jí)過程通過5個(gè)Action實(shí)現(xiàn),通過ActionProcessor管理按序分步線性執(zhí)行。
下圖為 Framework 層 UpdateEngine.java 類圖,主要描述給應(yīng)用提供的接口
下圖為 Framework 層 UpdateEngineCallback.java 類圖,主要描述應(yīng)用需要實(shí)現(xiàn)的接口
下表為 UpdateEngine aidl 接口定義
update_engine aidl接口定義 | 功能描述 |
---|---|
void applyPayload (String url, in long payload_offset, in long payload_size, in String[] headerKeyValuePairs); | 調(diào)用applyPayload接口,傳入升級(jí)參數(shù),開始升級(jí) 【url:升級(jí)包路徑 Payload_offset:payload在update.zip中的偏移量 Payload_size:payload文件的大小 headerKeyValuePairs:metadata中的數(shù)據(jù)】 |
boolean bind (IUpdateEngineCallback callback) | 綁定回調(diào),底層會(huì)將升級(jí)狀態(tài),升級(jí)進(jìn)度結(jié)果等信息通過此回調(diào)告訴上層 【callback:實(shí)現(xiàn)IUpdateEngineCallback的對(duì)象】 |
boolean unbind (IUpdateEngineCallback callback) | 解綁回調(diào),與上述綁定回調(diào)對(duì)應(yīng),解除綁定 【callback:實(shí)現(xiàn)IUpdateEngineCallback的對(duì)象】 |
void suspend() | 暫停升級(jí),上層可以通過此接口將升級(jí)流程暫停 |
void resume() | 恢復(fù)升級(jí),上層可以通過此接口將升級(jí)狀態(tài)由暫停切換恢復(fù) |
void cancel() | 取消升級(jí),上層可以通過此接口取消升級(jí) |
void resetStatus() | 重設(shè)升級(jí)狀態(tài)。上層通過此接口重設(shè)升級(jí)狀態(tài) |
boolean verifyPayloadApplicable (in String metadataFilename) | 驗(yàn)證此metadata數(shù)據(jù)是否能夠應(yīng)用在此設(shè)備中 【metadata的路徑】 |
下表為 UpdateEngine 回調(diào)接口定義
update_engine callback aidl接口定義 | 功能描述 |
---|---|
void onStatusUpdate (int status_code, float percentage) | 升級(jí)狀態(tài)回調(diào)、進(jìn)度回調(diào) |
void onPayloadApplicationComplete (int error_code) | 升級(jí)結(jié)果回調(diào) |
UpdateEngine 模塊功能流轉(zhuǎn)流程圖:
UpdateEngine 注冊(cè)-升級(jí)-回調(diào)流程序列圖如下:
2.3 系統(tǒng) UpdateEngine 升級(jí)流程
整體概述:關(guān)于 UpdateEngine 升級(jí)流程,準(zhǔn)備從上述兩個(gè)關(guān)鍵接口 bind 和 applyPayload 出發(fā),從升級(jí)流程 applyPayload 以及 升級(jí)回調(diào)流程 bind 兩大塊展開描述;
2.3.1 升級(jí)流程
2.3.1.1 Action 機(jī)制
在開始講解升級(jí)流程之前,我們有必要先來概述一下 UpdateEngine 對(duì)于升級(jí)的步驟是怎么管理的,先從整體去了解升級(jí)的步驟。
2.3.1.1.1 Action
在 UpdateEngine 升級(jí)流程中,將整個(gè)刷新過程按邏輯分為了 5 個(gè)步驟,每個(gè)步驟用一個(gè) Action 來表示,分別為 update_boot_flags_action、install_plan_action、download_action、filesystem_verifier_action、postinstall_runner_action。
Action | 定義 | 功能簡(jiǎn)述 |
---|---|---|
update_boot_flags_action | update_boot_flags_action.h | 完成一些標(biāo)志變量的初始化 |
install_plan_action | install_plan.h | 構(gòu)建一個(gè) InstallPlan 結(jié)構(gòu)體變量,并關(guān)聯(lián) OutputPipe |
download_action | download_action.h | 構(gòu)建 http_fetcher 完成升級(jí)數(shù)據(jù)下載,DeltaPerformer 的 writer_ 對(duì)象用于數(shù)據(jù)的解析更新 |
filesystem_verifier_action | filesystem_verifier_action.h | 逐個(gè)校驗(yàn)需要升級(jí)分區(qū)的 HASH 值 |
postinstall_runner_action | postinstall_runner_action.h | 對(duì)升級(jí)后的分區(qū)執(zhí)行 postinstall 腳本,并將升級(jí)成功后的分區(qū)設(shè)置為可啟動(dòng) active 狀態(tài) |
關(guān)于 Action 的定義,涉及兩個(gè)類:AbstractAction、Action。定義均在 /android/system/update_engine/common/action.h 路徑下。下面是兩個(gè)類的類圖:
AbstractAction 類圖:
Action 類圖:
AbstractAction 類可以理解為是 Action 基類,其中定義的虛函數(shù),每個(gè)具體的 action 都會(huì)重寫該類中的虛函數(shù)方法,定義了 Action 不同階段的邏輯功能,例如開始、暫停、恢復(fù)、停止、完成等場(chǎng)景功能邏輯;Action 類繼承了 AbstractAction 類,引入了 ActionPipe 的功能,定義的則是 Action 的輸入對(duì)象和輸出對(duì)象,關(guān)于 ActionPipe 會(huì)在下面介紹。
那么在 UpdateEngine 中定義的 Action 應(yīng)該都具備以上里兩個(gè)類的功能:功能邏輯和 ActionPipe 輸入輸出對(duì)象。UpdateEngine 中定義的 Action 是繼承自 InstallPlanAction,InstallPlanAction 是繼承自 Action。
文件:android/system/update_engine/common/action.h
// It is handy to have a non-templated base class of all Actions.
// 擁有所有 Actions 的非模板基類
class AbstractAction {
public:
AbstractAction() : processor_(nullptr) {}
virtual ~AbstractAction() = default;
// Begin performing the action. Since this code is asynchronous, when this
// method returns, it means only that the action has started, not necessarily
// completed. However, it's acceptable for this method to perform the
// action synchronously; Action authors should understand the implications
// of synchronously performing, though, because this is a single-threaded
// app, the entire process will be blocked while the action performs.
//
// When the action is complete, it must call
// ActionProcessor::ActionComplete(this); to notify the processor that it's
// done.
/*
* 開始執(zhí)行操作。
* 此代碼是異步的,當(dāng)方法返回時(shí),僅以為這該動(dòng)作已經(jīng)開始,并不一定完成。
* 不過方法可以同步執(zhí)行操作,需要了解同步執(zhí)行的含義,因?yàn)檫@是一個(gè)單線程應(yīng)用程序,所以動(dòng)作執(zhí)行時(shí)會(huì)阻塞整個(gè)過程。
* 操作完成后,必須調(diào)用 ActionProcessor::ActionComplete(this);通知處理器已完成。
*/
virtual void PerformAction() = 0;
// Called on ActionProcess::ActionComplete() by ActionProcessor.
// 執(zhí)行 ActionProcess::ActionComplete()
virtual void ActionCompleted(ErrorCode code) {}
// Called by the ActionProcessor to tell this Action which processor
// it belongs to.
// 由 ActionProcessor 調(diào)用以說明這個(gè) Action 數(shù)據(jù)哪個(gè) processor
void SetProcessor(ActionProcessor* processor) {
if (processor)
CHECK(!processor_);
else
CHECK(processor_);
processor_ = processor;
}
// Returns true iff the action is the current action of its ActionProcessor.
// 當(dāng)這個(gè) action 是 ActionPorcessor 當(dāng)前正在運(yùn)行的 action 時(shí)返回 true。
bool IsRunning() const {
if (!processor_)
return false;
return processor_->current_action() == this;
}
// Called on asynchronous actions if canceled. Actions may implement if
// there's any cleanup to do. There is no need to call
// ActionProcessor::ActionComplete() because the processor knows this
// action is terminating.
// Only the ActionProcessor should call this.
// 如果要執(zhí)行任何清理操作,可以實(shí)施此操作。
virtual void TerminateProcessing() {}
// Called on asynchronous actions if the processing is suspended and resumed,
// respectively. These methods are called by the ActionProcessor and should
// not be explicitly called.
// The action may still call ActionCompleted() once the action is completed
// while the processing is suspended, for example if suspend/resume is not
// implemented for the given action.
// 暫停當(dāng)前 action 的執(zhí)行。
virtual void SuspendAction() {}
// 恢復(fù)當(dāng)前暫停的 action 為執(zhí)行。
virtual void ResumeAction() {}
// These methods are useful for debugging. TODO(adlr): consider using
// std::type_info for this?
// Type() returns a string of the Action type. I.e., for DownloadAction,
// Type() would return "DownloadAction".
virtual std::string Type() const = 0;
protected:
// A weak pointer to the processor that owns this Action.
// 一個(gè)指向擁有這些 action 操作的 ActionProcessor 對(duì)象的弱指針。
ActionProcessor* processor_;
};
// Action 類繼承自 AbstractAction,是對(duì) Action 輸入對(duì)象、輸出對(duì)象定義的延申。
class Action : public AbstractAction {
public:
~Action() override {}
// Attaches an input pipe to this Action. This is optional; an Action
// doesn't need to have an input pipe. The input pipe must be of the type
// of object that this class expects.
// This is generally called by ActionPipe::Bond()
/*
* 將輸入管道對(duì)象附加到此動(dòng)作,此動(dòng)作是可選的,第一個(gè) Action 不需要輸入管道。
* 輸入管道必須為該類期望的對(duì)象,通常由 ActionPipe::Bond() 調(diào)用。
*/
void set_in_pipe(
// this type is a fancy way of saying: a shared_ptr to an
// ActionPipe<InputObjectType>.
const std::shared_ptr<
ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>&
in_pipe) {
in_pipe_ = in_pipe;
}
// Attaches an output pipe to this Action. This is optional; an Action
// doesn't need to have an output pipe. The output pipe must be of the type
// of object that this class expects.
// This is generally called by ActionPipe::Bond()
/*
* 將輸出管道附加到此操作。這是可選的,最后一個(gè) Action 不需要輸出管道。
* 輸出管道必須是此類所需要的對(duì)象類型。通常由 ActionPipe::Bond() 調(diào)用。
*/
void set_out_pipe(
// this type is a fancy way of saying: a shared_ptr to an
// ActionPipe<OutputObjectType>.
const std::shared_ptr<
ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>&
out_pipe) {
out_pipe_ = out_pipe;
}
// Returns true iff there is an associated input pipe. If there's an input
// pipe, there's an input object, but it may have been constructed with the
// default ctor if the previous action didn't call SetOutputObject().
/*
* 如果存在關(guān)聯(lián)的輸入管道,則返回 true。
* 如果存在輸入管道,有一個(gè)輸入對(duì)象,但是之前沒有調(diào)用 SetOutputObject() 方法,那么對(duì)象有可能是默認(rèn)構(gòu)造函數(shù)創(chuàng)建的。
*/
bool HasInputObject() const { return in_pipe_.get(); }
// returns a const reference to the object in the input pipe.
// 返回輸入管道中對(duì)象的 const 引用。
const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
const {
CHECK(HasInputObject());
return in_pipe_->contents();
}
// Returns true iff there's an output pipe.
// 如果有輸出管道,則返回 true。
bool HasOutputPipe() const { return out_pipe_.get(); }
// Copies the object passed into the output pipe. It will be accessible to
// the next Action via that action's input pipe (which is the same as this
// Action's output pipe).
// 復(fù)制傳遞到輸出管道中的對(duì)象。下一個(gè)操作可以通過該操作輸入管道訪問此操作。
// 也就是說 上一個(gè)Action 的輸出管道對(duì)象 就是 下一個(gè)Action 的輸入管道對(duì)象。
void SetOutputObject(
const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
CHECK(HasOutputPipe());
out_pipe_->set_contents(out_obj);
}
// Returns a reference to the object sitting in the output pipe.
// 返回輸出管道中對(duì)象的 const 引用。
const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
CHECK(HasOutputPipe());
return out_pipe_->contents();
}
protected:
// We use a shared_ptr to the pipe. shared_ptr objects destroy what they
// point to when the last such shared_ptr object dies. We consider the
// Actions on either end of a pipe to "own" the pipe. When the last Action
// of the two dies, the ActionPipe will die, too.
/*
* 定義兩個(gè)管道 輸入管道 in_pipe_ 和 輸出管道 out_pipe_。
* 管道對(duì)象使用 shared_ptr 修飾,shared_ptr 對(duì)象會(huì)在最后一個(gè)這樣的 shared_ptr 對(duì)象銷毀同時(shí)銷毀指向的對(duì)象。
* 我們將管道兩端的操作視為擁有管道。當(dāng)兩者的最后一個(gè)動(dòng)作結(jié)束銷毀時(shí),管道也會(huì)銷毀。
*
* shared_ptr:
* shared_ptr 的主要功能是管理動(dòng)態(tài)創(chuàng)建的對(duì)象的銷毀。
* 它的基本原理就是記錄對(duì)象被引用的次數(shù),當(dāng)引用次數(shù)為0的時(shí)候,也就是最后一個(gè)指向某對(duì)象的 共享指針析構(gòu) 的時(shí)候,共享指針的析構(gòu)函數(shù)就把 指向的內(nèi)存區(qū)域 釋放掉
*/
std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
in_pipe_;
std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
out_pipe_;
};
2.3.1.1.2 ActionProcessor
Action 表示 UpdateEngine 的升級(jí)步驟,那么就需要控制管理 Action 的一套機(jī)制,ActionProcessor 則是控制管理 Action 入隊(duì)、開始、暫停、恢復(fù)、停止、狀態(tài)判斷、Action 獲取、運(yùn)行結(jié)束邏輯等流程。
ActionProcessor 定義在 “android/system/update_engine/common/action_processor.h” 中。
ActionProcessor 類圖如下:
ActionProcessorDelegate 類圖如下:
文件:android/system/update_engine/common/action_processor.h
// ActionProcessor 類
class ActionProcessor {
public:
ActionProcessor() = default;
virtual ~ActionProcessor();
// Starts processing the first Action in the queue. If there's a delegate,
// when all processing is complete, ProcessingDone() will be called on the
// delegate.
// 開始處理隊(duì)列中的第一個(gè) Action 動(dòng)作。
virtual void StartProcessing();
// Aborts processing. If an Action is running, it will have
// TerminateProcessing() called on it. The Action that was running and all the
// remaining actions will be lost and must be re-enqueued if this Processor is
// to use it.
/*
* 中止處理。
* 如果某個(gè) Action 正在運(yùn)行,它將調(diào)用 TerminateProcessing(),如果此處理器要使用它,則正在運(yùn)行的動(dòng)作以及所有其他剩余動(dòng)作將丟失,必須重新排隊(duì)。
*/
void StopProcessing();
// Suspend the processing. If an Action is running, it will have the
// SuspendProcessing() called on it, and it should suspend operations until
// ResumeProcessing() is called on this class to continue. While suspended,
// no new actions will be started. Calling SuspendProcessing while the
// processing is suspended or not running this method performs no action.
/*
* 暫停處理。
* 如果某個(gè) Action 正在運(yùn)行,它將調(diào)用 SuspendProcessing(),并且它應(yīng)該暫停操作,直到在此類上調(diào)用 ResumeProcessing() 以繼續(xù)。
* 掛起期間,不會(huì)啟動(dòng)任何新操作,在處理掛起或未運(yùn)行此方法時(shí)調(diào)用掛起處理不執(zhí)行任何操作。
*/
void SuspendProcessing();
// Resume the suspended processing. If the ActionProcessor is not suspended
// or not running in the first place this method performs no action.
// 恢復(fù)掛起的處理。如果操作處理器未掛起或未首先運(yùn)行,則此方法不執(zhí)行任何操作。
void ResumeProcessing();
// Returns true iff the processing was started but not yet completed nor
// stopped.
// 定義一個(gè)方法用于判斷當(dāng)前 Action 的運(yùn)行狀態(tài),運(yùn)行或者暫停
bool IsRunning() const;
// Adds another Action to the end of the queue.
// 將 Action 操作放入隊(duì)列中
virtual void EnqueueAction(std::unique_ptr<AbstractAction> action);
// Sets/gets the current delegate. Set to null to remove a delegate.
/*
* 設(shè)置一個(gè)代理委托對(duì)象 ActionProcessorDelegate。
* ActionProcessorDelegate 在下面定義,此類的作用是用于控制整體的 Action 操作的狀態(tài)交互的。
*/
ActionProcessorDelegate* delegate() const { return delegate_; }
void set_delegate(ActionProcessorDelegate* delegate) { delegate_ = delegate; }
// Returns a pointer to the current Action that's processing.
// 返回當(dāng)前正在運(yùn)行的 Action 對(duì)象。
AbstractAction* current_action() const { return current_action_.get(); }
// Called by an action to notify processor that it's done. Caller passes self.
// But this call deletes the action if there no other object has a reference
// to it, so in that case, the caller should not try to access any of its
// member variables after this call.
// 當(dāng) Action 完成后通知 ActionProcessor 已完成。
void ActionComplete(AbstractAction* actionptr, ErrorCode code);
private:
FRIEND_TEST(ActionProcessorTest, ChainActionsTest);
// Continue processing actions (if any) after the last action terminated with
// the passed error code. If there are no more actions to process, the
// processing will terminate.
// 當(dāng) Action 執(zhí)行結(jié)束后調(diào)用,判斷是執(zhí)行隊(duì)列中下一個(gè) Action 還是結(jié)束整個(gè)過程。當(dāng) Action 因傳遞的錯(cuò)誤碼而終止后繼續(xù)處理操作。
void StartNextActionOrFinish(ErrorCode code);
// Actions that have not yet begun processing, in the order in which
// they'll be processed.
// Action 隊(duì)列
std::deque<std::unique_ptr<AbstractAction>> actions_;
// A pointer to the currently processing Action, if any.
// 一個(gè)指向當(dāng)前正在運(yùn)行的 Action 指針。
std::unique_ptr<AbstractAction> current_action_;
// The ErrorCode reported by an action that was suspended but finished while
// being suspended. This error code is stored here to be reported back to the
// delegate once the processor is resumed.
// 當(dāng)調(diào)用 suspend 暫停 Action 過程中出現(xiàn)的 錯(cuò)誤碼 會(huì)存放在此處,以便于處理器恢復(fù)后報(bào)告給委托對(duì)象。
ErrorCode suspended_error_code_{ErrorCode::kSuccess};
// Whether the action processor is or should be suspended.
// 定義一個(gè)標(biāo)志位,判斷是否未 暫停狀態(tài)。
bool suspended_{false};
// A pointer to the delegate, or null if none.
// 定義委托對(duì)象的指針。
ActionProcessorDelegate* delegate_{nullptr};
DISALLOW_COPY_AND_ASSIGN(ActionProcessor);
};
// ActionProcessorDelegate 類
// A delegate object can be used to be notified of events that happen
// in an ActionProcessor. An instance of this class can be passed to an
// ActionProcessor to register itself.
/*
* ActionProcessorDelegate 委托對(duì)象可用于通知操作處理器中發(fā)生的事件。
* 可以將此類的示例傳遞給 ActionProcessor 以注冊(cè)自身。
* 這個(gè)委托類,在 ActionProcessor 中進(jìn)行注冊(cè),這樣用委托調(diào)用 ActionProcessor 的方法,這樣可以調(diào)用到 processor 的方法,也可以定義一些與外部交互的方法
* 例如,Action 完成或停止時(shí)給客戶端返回狀態(tài)
*/
class ActionProcessorDelegate {
public:
virtual ~ActionProcessorDelegate() = default;
// Called when all processing in an ActionProcessor has completed. A pointer
// to the ActionProcessor is passed. |code| is set to the exit code of the
// last completed action.
/*
* 當(dāng)操作處理器中的所有處理都已完成時(shí)調(diào)用。
* 參數(shù):processor 指向 ActionProcessor 的指針;code 表示未上次完成的操作時(shí)退出的代碼
*/
virtual void ProcessingDone(const ActionProcessor* processor,
ErrorCode code) {}
// Called when processing has stopped. Does not mean that all Actions have
// completed. If/when all Actions complete, ProcessingDone() will be called.
/*
* 當(dāng)處理停止時(shí)調(diào)用。
* 并不代表著所有動(dòng)作均已完成。如果當(dāng)所有動(dòng)作均已完成,將調(diào)用 ProcessingDone()。
*/
virtual void ProcessingStopped(const ActionProcessor* processor) {}
// Called whenever an action has finished processing, either successfully
// or otherwise.
/*
* 每當(dāng)操作完成處理時(shí)調(diào)用,無論成功與否。
*/
virtual void ActionCompleted(ActionProcessor* processor,
AbstractAction* action,
ErrorCode code) {}
};
ActionProcessor 作為一個(gè) Action 管理類,其功能如下:
Action 入隊(duì):EnqueueAction
Action 啟動(dòng)與停止:StartProcessing StopProcessing
Action 暫停與恢復(fù):SuspendProcessing ResumeProcessing
Action 完成與切換:ActionComplete StartNextActionOrFinish
設(shè)置委托類:set_delegate
判斷 Action 是否正在運(yùn)行:IsRunning()
判斷 Action 是否暫停狀態(tài):suspended_
ActionProcessorDelegate 作為一個(gè)委托類,主要用于通知 ActionProcess 處理過程中的狀態(tài)和發(fā)生的事件,其功能如下:
當(dāng)某個(gè) Action 完成其功能的處理時(shí),通知 ActionProcessor 調(diào)用 ActionCompleted()
當(dāng)調(diào)用停止處理函數(shù)時(shí),調(diào)用 ProcessingStopped()
當(dāng)操作處理器中所有的 Action 都完成時(shí),調(diào)用 ProcessingDone()
2.3.1.1.3 ActionPipe
類似于 Unix 系統(tǒng)的管道,Action 機(jī)制中,也會(huì)通過管道 ActionPipe 將這些 Action 鏈接在一起。上一個(gè) Action 的輸出會(huì)作為下一個(gè) Action 的輸入。
因此在 Update Engine 中,所有的 Action 之間有一個(gè)先后關(guān)系。例如,只有 DownloadAction 完成操作了,才能開始 FilesystemVerifierAction 操作;也只有 FilesystemVerifierAction 結(jié)束了,才會(huì)開始 PostinstallRunnerAction 操作。
ActionPipe 類的功能是 。類定義在 “android/system/update_engine/common/action_pipe.h”。
ActionPipe 類圖如下:
// 文件:android/system/update_engine/common/action_pipe.h
class ActionPipe {
public:
virtual ~ActionPipe() {}
// This should be called by an Action on its input pipe.
// Returns a reference to the stored object.
/*
* 此函數(shù)應(yīng)該由 Action 的輸入管道調(diào)用,用于獲取 輸入對(duì)象 的引用。
*/
const ObjectType& contents() const { return contents_; }
// This should be called by an Action on its output pipe.
// Stores a copy of the passed object in this pipe.
/*
* 此函數(shù)應(yīng)該由 Action 的輸出管道調(diào)用,用于存儲(chǔ)一個(gè)輸出對(duì)象的副本。
*/
void set_contents(const ObjectType& contents) { contents_ = contents; }
// Bonds two Actions together with a new ActionPipe. The ActionPipe is
// jointly owned by the two Actions and will be automatically destroyed
// when the last Action is destroyed.
/*
* 將兩個(gè)操作與新的操作管道綁定在一起,操作管道有兩個(gè)操作共同擁有,并且在最后一個(gè)操作銷毀時(shí)自動(dòng)銷毀
* FromAction 表示上一個(gè) Action; ToAction 表示下一個(gè) Action。
* 上一個(gè) Action 的輸出對(duì)象跟下一個(gè) Action 的輸入對(duì)象是同一個(gè)。
*/
template <typename FromAction, typename ToAction>
static void Bond(FromAction* from, ToAction* to) {
std::shared_ptr<ActionPipe<ObjectType>> pipe(new ActionPipe<ObjectType>);
from->set_out_pipe(pipe);
to->set_in_pipe(pipe); // If you get an error on this line, then
// it most likely means that the From object's OutputObjectType is
// different from the To object's InputObjectType.
// 如果此行收到錯(cuò)誤,則很可能意味著 From 對(duì)象的 OutputObjectType 與 To 對(duì)象的 InputObjectType 不同。
}
private:
ObjectType contents_;
// The ctor is private. This is because this class should construct itself
// via the static Bond() method.
// 這個(gè)構(gòu)造函數(shù)是私有的,這是因?yàn)檫@個(gè)類應(yīng)該通過靜態(tài)函數(shù) Bond() 方法實(shí)現(xiàn)構(gòu)造。
ActionPipe() {}
DISALLOW_COPY_AND_ASSIGN(ActionPipe);
};
Action 中的輸入輸出對(duì)象是什么時(shí)候完成的?
Action 會(huì)有 InputObject 和 OutputObject,那這些對(duì)象是什么時(shí)候完成的,并且是怎么完成的呢?
先說答案:InputObject 是本 Action 的管道輸入對(duì)象,那么就應(yīng)該在本 Action 功能執(zhí)行之前獲取,而 Action 執(zhí)行的第一個(gè)函數(shù)應(yīng)該是 PerformAction() 函數(shù),因此一般獲取 InputObject 是在此方法中進(jìn)行的;OutputObject 是本 Action 的管道輸出對(duì)象,也是下一個(gè) Action 的輸入對(duì)象,那么就應(yīng)該在本 Action 功能執(zhí)行結(jié)束之后設(shè)置,而 Action 執(zhí)行的最后一個(gè)函數(shù)應(yīng)該是 ActionComplete() 函數(shù),因此一般設(shè)置 OutputObject 是在此方法調(diào)用之前進(jìn)行的。
2.3.1.1.4 總結(jié)圖示
關(guān)于 Action 機(jī)制總的來說如下圖所示,UpdateEngine 模塊的升級(jí)步驟用 Action 來表示,Action 的輸入輸出對(duì)象由 ActionPipe 來控制,所有的 Action 動(dòng)作會(huì)存儲(chǔ)在 ActionPorcessor 管理類中,ActionProcessor 管理類會(huì)使用 ActionProcessorDelegate 委托類來控制整體 Action 運(yùn)行的節(jié)奏。
2.3.1.2 applyPayload 流程
本節(jié)將會(huì)從 applyPayload 函數(shù)的流程出發(fā),展開描述由類結(jié)構(gòu)到函數(shù)實(shí)現(xiàn)的細(xì)節(jié)。
2.3.1.2.1 BinderUpdateEngineAndroidService 類
從上一篇 UpdateEngine 啟動(dòng)的流程分析 中,UpdateEngine 的 AIDL 服務(wù)端對(duì)象是 BinderUpdateEngineAndroidService 類,上層獲取的 UpdateEngine aidl 服務(wù)端對(duì)象實(shí)際就是 BinderUpdateEngineAndroidService 類對(duì)象。我們來看下這個(gè)類的定義:
BinderUpdateEngineAndroidService 類結(jié)構(gòu)圖:
從類定義中可以發(fā)現(xiàn),BinderUpdateEngineAndroidService 繼承了 android::os::BnUpdateEngine、ServiceObserverInterface;android::os::BnUpdateEngine 是 AIDL 對(duì)象,ServiceObserverInterface 是封裝了回調(diào)接口類。就是說 BinderUpdateEngineAndroidService 是接收上層調(diào)用以及回調(diào)信息給上層的對(duì)象。
// 文件:android/system/update_engine/binder_service_android.h
class BinderUpdateEngineAndroidService : public android::os::BnUpdateEngine,
public ServiceObserverInterface {
public:
explicit BinderUpdateEngineAndroidService(
ServiceDelegateAndroidInterface* service_delegate);
~BinderUpdateEngineAndroidService() override = default;
const char* ServiceName() const { return "android.os.UpdateEngineService"; }
--------------------------------------------------------------------------------------------------------------------------------
// ServiceObserverInterface overrides.下面兩個(gè)函數(shù)是來自 ServiceObserverInterface 類,封裝了反饋信息給上層的接口
void SendStatusUpdate(
const update_engine::UpdateEngineStatus& update_engine_status) override;
void SendPayloadApplicationComplete(ErrorCode error_code) override;
--------------------------------------------------------------------------------------------------------------------------------
// android::os::BnUpdateEngine overrides.下面的函數(shù)是來自 android::os::BnUpdateEngine 類,AIDL類接口的實(shí)現(xiàn)。
android::binder::Status applyPayload(
const android::String16& url,
int64_t payload_offset,
int64_t payload_size,
const std::vector<android::String16>& header_kv_pairs) override;
android::binder::Status bind(
const android::sp<android::os::IUpdateEngineCallback>& callback,
bool* return_value) override;
android::binder::Status unbind(
const android::sp<android::os::IUpdateEngineCallback>& callback,
bool* return_value) override;
android::binder::Status suspend() override;
android::binder::Status resume() override;
android::binder::Status cancel() override;
android::binder::Status resetStatus() override;
android::binder::Status verifyPayloadApplicable(
const android::String16& metadata_filename, bool* return_value) override;
--------------------------------------------------------------------------------------------------------------------------------
private:
// Remove the passed |callback| from the list of registered callbacks. Called
// on unbind() or whenever the callback object is destroyed.
// Returns true on success.
// 此函數(shù)作用是從注冊(cè)回調(diào)列表中刪除傳遞的回調(diào)對(duì)象,在上層調(diào)用 unbind() 或?qū)ο蟊讳N毀時(shí)調(diào)用
bool UnbindCallback(const IBinder* callback);
// List of currently bound callbacks. 回調(diào)對(duì)象列表,用于保存上層 bind() 傳下來的回調(diào)對(duì)象
std::vector<android::sp<android::os::IUpdateEngineCallback>> callbacks_;
// Cached copy of the last status update sent. Used to send an initial
// notification when bind() is called from the client.
// 發(fā)送的最后一次狀態(tài)更新的緩存副本。用于在從客戶端調(diào)用 bind() 時(shí)發(fā)送初始通知。
int last_status_{-1};
double last_progress_{0.0};
// DaemonStateAndroid 類型實(shí)例,繼承自 ServiceDelegateAndroidInterface,封裝了 AIDI 接口,當(dāng)上層調(diào)用 AIDL 接口時(shí),會(huì)調(diào)用到
// DaemonStateAndroid 類中
ServiceDelegateAndroidInterface* service_delegate_;
};
BinderUpdateEngineAndroidService 類實(shí)現(xiàn)中實(shí)際上并沒有 AIDL 接口的具體實(shí)現(xiàn),具體實(shí)現(xiàn)是調(diào)用了 ServiceDelegateAndroidInterface 類的 ApplyPayload 接口。
2.3.1.2.2 UpdateAttempterAndroid 類
ServiceDelegateAndroidInterface 相當(dāng)于是一個(gè)接口文件,此類基于 AIDL 接口定義了功能實(shí)現(xiàn)接口,后續(xù)的功能類繼承此接口,實(shí)現(xiàn)此類的方法以提供具體的功能,子類 UpdateAttempterAndroid 繼承自 ServiceDelegateAndroidInterface、ActionProcessorDelegate、DownloadActionDelegate、PostinstallRunnerAction::DelegateInterface;是 UpdateEngine 功能的具體實(shí)現(xiàn)類。
UpdateAttempterAndroid 類結(jié)構(gòu)圖:
從 UpdateAttempterAndroid 結(jié)構(gòu)中可以發(fā)現(xiàn)其重要性,ServiceDelegateAndroidInterface 是實(shí)現(xiàn) AIDL 接口功能類;DownloadActionDelegate 是升級(jí)步驟中 Download 部分的功能類;PostinstallRunnerAction::DelegateInterface 是升級(jí)步驟中 PostInstall 部分的功能類;ActionProcessorDelegate 是 UpdateEngine 的 Action 機(jī)制的功能類;
文件:android/system/update_engine/update_attempter_android.h
class UpdateAttempterAndroid
: public ServiceDelegateAndroidInterface,
public ActionProcessorDelegate,
public DownloadActionDelegate,
public PostinstallRunnerAction::DelegateInterface {
public:
using UpdateStatus = update_engine::UpdateStatus;
UpdateAttempterAndroid(DaemonStateInterface* daemon_state,
PrefsInterface* prefs,
BootControlInterface* boot_control_,
HardwareInterface* hardware_);
~UpdateAttempterAndroid() override;
// Further initialization to be done post construction.
void Init();
--------------------------------------------------------------------------------------------------------------------------------
下面是 ServiceDelegateAndroidInterface 的接口實(shí)現(xiàn)
// ServiceDelegateAndroidInterface overrides.
/*
* 觸發(fā)升級(jí)接口
*/
bool ApplyPayload(const std::string& payload_url,
int64_t payload_offset,
int64_t payload_size,
const std::vector<std::string>& key_value_pair_headers,
brillo::ErrorPtr* error) override;
/*
* 暫停升級(jí)
* 函數(shù)實(shí)現(xiàn)中會(huì)調(diào)用 ActionProcessor->SuspendProcessing() 方法暫停處理。
*/
bool SuspendUpdate(brillo::ErrorPtr* error) override;
/*
* 繼續(xù)升級(jí)
* 函數(shù)實(shí)現(xiàn)中會(huì)調(diào)用 ActionProcessor->ResumeProcessing() 方法恢復(fù)處理。
*/
bool ResumeUpdate(brillo::ErrorPtr* error) override;
/*
* 取消升級(jí)
* 函數(shù)實(shí)現(xiàn)中會(huì)調(diào)用 ActionProcessor->StopProcessing() 方法停止升級(jí)。
*/
bool CancelUpdate(brillo::ErrorPtr* error) override;
/*
* 重置升級(jí)狀態(tài)
* 函數(shù)實(shí)現(xiàn)中會(huì)根據(jù)當(dāng)前的狀態(tài)做出重置
* 當(dāng)前如果是 IDLE 狀態(tài),那么不用處理,直接 return;
* 當(dāng)前如果是升級(jí)完成,需要重啟的狀態(tài),那么此時(shí)現(xiàn)清除 kPrefsUpdateCompletedOnBootId 標(biāo)記,更新 boot 標(biāo)記,將當(dāng)前分區(qū)設(shè)置為正常啟動(dòng)分區(qū),重置當(dāng)前狀
* 態(tài)為 IDLE 并通知客戶端重置成功。
* 當(dāng)前如果是其他狀態(tài),不允許重置的操作,需要先取消正在進(jìn)行的升級(jí),會(huì)返回一個(gè) Error。
*/
bool ResetStatus(brillo::ErrorPtr* error) override;
/*
* 判斷此升級(jí)包是否可以應(yīng)用與本機(jī)升級(jí)
* 函數(shù)實(shí)現(xiàn)中會(huì)根據(jù)升級(jí)包的參數(shù),解析升級(jí)包并校驗(yàn),判斷是否能夠進(jìn)行升級(jí)。
*/
bool VerifyPayloadApplicable(const std::string& metadata_filename,
brillo::ErrorPtr* error) override;
--------------------------------------------------------------------------------------------------------------------------------
下面是 ActionProcessorDelegate 接口實(shí)現(xiàn)
// ActionProcessorDelegate methods:
/*
* 當(dāng) Action 隊(duì)列中的 Action 均執(zhí)行結(jié)束后 或者 Action 執(zhí)行過程中有報(bào)錯(cuò)退出時(shí)觸發(fā)。
* 此函數(shù)由 ActionProcessor::StartNextActionOrFinish() 調(diào)用。
* 函數(shù)實(shí)現(xiàn)
* 1、根據(jù)傳入的 ErrorCode 判斷
* 2、如果是升級(jí)成功,寫入升級(jí)成功的標(biāo)記
* 3、如果是升級(jí)失敗,重置升級(jí)
* 4、如果是 payload 時(shí)間戳錯(cuò)誤,寫入錯(cuò)誤并停止
* 5、最后結(jié)束升級(jí)并通知
*/
void ProcessingDone(const ActionProcessor* processor,
ErrorCode code) override;
/*
* 停止升級(jí)接口
* 此函數(shù)由 ActionProcessor::StopProcessing() 調(diào)用
* 函數(shù)實(shí)現(xiàn)
* 終止升級(jí)并進(jìn)行通知,使用的 ErrorCode 為用戶取消升級(jí)
*/
void ProcessingStopped(const ActionProcessor* processor) override;
/*
* Action 動(dòng)作執(zhí)行結(jié)束函數(shù)
* 此函數(shù)由 ActionProcessor::ActionComplete() 調(diào)用
* 函數(shù)實(shí)現(xiàn)
* 1、首先獲取當(dāng)前 Action 是哪個(gè) Action
* 2、對(duì)于不同的 Action 做出對(duì)應(yīng)的結(jié)束成功的判斷
* 3、如果當(dāng)前 Action 的執(zhí)行結(jié)果不是成功狀態(tài),表明此 Action 的執(zhí)行是失敗的,直接 return
* 4、在當(dāng)前狀態(tài)成功的情況下,通知客戶端升級(jí)狀態(tài)
*/
void ActionCompleted(ActionProcessor* processor,
AbstractAction* action,
ErrorCode code) override;
--------------------------------------------------------------------------------------------------------------------------------
下面是 DownloadActionDelegate 接口的實(shí)現(xiàn)
// DownloadActionDelegate overrides.
/*
* 下載數(shù)據(jù)接收接口
* 此函數(shù)在下載過程中會(huì)頻繁的被調(diào)用,下載的數(shù)據(jù)是分包下載的,此函數(shù)會(huì)計(jì)算下載的進(jìn)度、寫入當(dāng)前已下載的數(shù)據(jù)量和總數(shù)據(jù)量,并且判斷是否下載完成,下載完成就調(diào)用
* SetStatusAndNotify() 函數(shù)通知下載完成狀態(tài);如果沒有下載完成,就持續(xù)調(diào)用 ProgressUpdate() 函數(shù)報(bào)告進(jìn)度。
*/
void BytesReceived(uint64_t bytes_progressed,
uint64_t bytes_received,
uint64_t total) override;
/*
* 取消下載接口
* 此函數(shù)是空實(shí)現(xiàn)
*/
bool ShouldCancel(ErrorCode* cancel_reason) override;
/*
* 下載完成接口
* 此函數(shù)是空實(shí)現(xiàn)
*/
void DownloadComplete() override;
--------------------------------------------------------------------------------------------------------------------------------
下面是 PostInstallRunnerAction::DelegateInterface 接口實(shí)現(xiàn)
// PostinstallRunnerAction::DelegateInterface
/*
* 下載進(jìn)度更新接口
* 函數(shù)實(shí)現(xiàn)會(huì)基于進(jìn)度進(jìn)行判斷,如果進(jìn)度太慢,會(huì)發(fā)送通知。
*/
void ProgressUpdate(double progress) override;
--------------------------------------------------------------------------------------------------------------------------------
private:
friend class UpdateAttempterAndroidTest;
// Schedules an event loop callback to start the action processor. This is
// scheduled asynchronously to unblock the event loop.
void ScheduleProcessingStart();
// Notifies an update request completed with the given error |code| to all
// observers.
void TerminateUpdateAndNotify(ErrorCode error_code);
// Sets the status to the given |status| and notifies a status update to
// all observers.
void SetStatusAndNotify(UpdateStatus status);
// Helper method to construct the sequence of actions to be performed for
// applying an update using a given HttpFetcher. The ownership of |fetcher| is
// passed to this function.
void BuildUpdateActions(HttpFetcher* fetcher);
// Writes to the processing completed marker. Does nothing if
// |update_completed_marker_| is empty.
bool WriteUpdateCompletedMarker();
// Returns whether an update was completed in the current boot.
bool UpdateCompletedOnThisBoot();
// Prefs to use for metrics report
// |kPrefsPayloadAttemptNumber|: number of update attempts for the current
// payload_id.
// |KprefsNumReboots|: number of reboots when applying the current update.
// |kPrefsSystemUpdatedMarker|: end timestamp of the last successful update.
// |kPrefsUpdateTimestampStart|: start timestamp in monotonic time of the
// current update.
// |kPrefsUpdateBootTimestampStart|: start timestamp in boot time of
// the current update.
// |kPrefsCurrentBytesDownloaded|: number of bytes downloaded for the current
// payload_id.
// |kPrefsTotalBytesDownloaded|: number of bytes downloaded in total since
// the last successful update.
// Metrics report function to call:
// |ReportUpdateAttemptMetrics|
// |ReportSuccessfulUpdateMetrics|
// Prefs to update:
// |kPrefsSystemUpdatedMarker|
void CollectAndReportUpdateMetricsOnUpdateFinished(ErrorCode error_code);
// Metrics report function to call:
// |ReportAbnormallyTerminatedUpdateAttemptMetrics|
// |ReportTimeToRebootMetrics|
// Prefs to update:
// |kPrefsBootId|, |kPrefsPreviousVersion|
void UpdatePrefsAndReportUpdateMetricsOnReboot();
// Prefs to update:
// |kPrefsPayloadAttemptNumber|, |kPrefsUpdateTimestampStart|,
// |kPrefsUpdateBootTimestampStart|
void UpdatePrefsOnUpdateStart(bool is_resume);
// Prefs to delete:
// |kPrefsNumReboots|, |kPrefsCurrentBytesDownloaded|
// |kPrefsSystemUpdatedMarker|, |kPrefsUpdateTimestampStart|,
// |kPrefsUpdateBootTimestampStart|
void ClearMetricsPrefs();
DaemonStateInterface* daemon_state_;
// DaemonStateAndroid pointers.
PrefsInterface* prefs_;
BootControlInterface* boot_control_;
HardwareInterface* hardware_;
// Last status notification timestamp used for throttling. Use monotonic
// TimeTicks to ensure that notifications are sent even if the system clock is
// set back in the middle of an update.
base::TimeTicks last_notify_time_;
// Only direct proxy supported.
DirectProxyResolver proxy_resolver_;
// The processor for running Actions.
std::unique_ptr<ActionProcessor> processor_;
// The InstallPlan used during the ongoing update.
InstallPlan install_plan_;
// For status:
UpdateStatus status_{UpdateStatus::IDLE};
double download_progress_{0.0};
// The offset in the payload file where the CrAU part starts.
int64_t base_offset_{0};
// Helper class to select the network to use during the update.
std::unique_ptr<NetworkSelectorInterface> network_selector_;
std::unique_ptr<ClockInterface> clock_;
std::unique_ptr<MetricsReporterInterface> metrics_reporter_;
DISALLOW_COPY_AND_ASSIGN(UpdateAttempterAndroid);
};
2.3.1.2.3 ApplyPayload 函數(shù)實(shí)現(xiàn)
下面我們進(jìn)入 UpdateAttempterAndroid 的 ApplyPayload() 的實(shí)現(xiàn),開始分析升級(jí)流程
文件:android/system/update_engine/update_attempter_android.cc
/*
* 從 ApplyPayload 接口實(shí)現(xiàn)代碼中,整個(gè)過程做的事情有很多,我們得把具體實(shí)現(xiàn)進(jìn)行分步分析,以免繞暈...
*/
bool UpdateAttempterAndroid::ApplyPayload(
const string& payload_url,
int64_t payload_offset,
int64_t payload_size,
const vector<string>& key_value_pair_headers,
brillo::ErrorPtr* error) {
--------------------------------------------------------------------------------------------------------------------------------
關(guān)于入?yún)?string payload_url:內(nèi)容舉例 “file:///storage/798A-ECED/usb_ota_update.zip”,是升級(jí)包的路徑
int payload_offset:內(nèi)容舉例 offset=659 表示的數(shù)據(jù)的偏移量,下載的時(shí)候會(huì)從這個(gè)偏移量之后開始下載,是數(shù)據(jù)的開始
int payload_size:內(nèi)容舉例 size=2447066254 表示數(shù)據(jù)的長(zhǎng)度
vector<string> key_value_pair_headers:此內(nèi)容是一個(gè) String 格式的數(shù)據(jù)集合,內(nèi)容如下:
[
FILE_HASH=PLo9cSeCeECAhKHlk06drRFHCyd1BGHE/fliEd0F3uQ=,
FILE_SIZE=2447066254,
METADATA_HASH=H+gFeOLUWil1LyX4VOJIhGvHHv+MrFu1RBdxXzhorHQ=,
METADATA_SIZE=179338
]
可以發(fā)現(xiàn)是 payload_properties.txt 中的內(nèi)容
billlo::ErrorPtr error: error 信息
--------------------------------------------------------------------------------------------------------------------------------
下面兩個(gè)條件判斷是先對(duì)升級(jí)的狀態(tài)進(jìn)行判斷,在升級(jí)前,根據(jù)狀態(tài)判斷是否已經(jīng)升級(jí)完畢需要重啟;判斷是否已經(jīng)有一個(gè)升級(jí)正在進(jìn)行中。
當(dāng)上述兩種場(chǎng)景時(shí),上層觸發(fā)升級(jí)的話,會(huì)直接上報(bào)一個(gè) Error 返回給應(yīng)用。并不會(huì)觸發(fā)升級(jí)。
if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
return LogAndSetError(
error, FROM_HERE, "An update already applied, waiting for reboot");
}
if (processor_->IsRunning()) {
return LogAndSetError(
error, FROM_HERE, "Already processing an update, cancel it first.");
}
DCHECK(status_ == UpdateStatus::IDLE);
--------------------------------------------------------------------------------------------------------------------------------
下面步驟是對(duì)于 入?yún)?key_value_pair_headers 內(nèi)容拆分存儲(chǔ)到 headers 集合中。
std::map<string, string> headers;
for (const string& key_value_pair : key_value_pair_headers) {
string key;
string value;
if (!brillo::string_utils::SplitAtFirst(
key_value_pair, "=", &key, &value, false)) {
return LogAndSetError(
error, FROM_HERE, "Passed invalid header: " + key_value_pair);
}
if (!headers.emplace(key, value).second)
return LogAndSetError(error, FROM_HERE, "Passed repeated key: " + key);
}
--------------------------------------------------------------------------------------------------------------------------------
創(chuàng)建一個(gè) payload_id,這個(gè) payload_id 的內(nèi)容是 headers 集合中兩個(gè)數(shù)據(jù)的組合,表示的是這個(gè)升級(jí)數(shù)據(jù)包的唯一標(biāo)識(shí)
headers[kPayloadPropertyFileHash] = headers[FILE_HASH]
headers[kPayloadPropertyMetadataHash] = headers[METADATA_HASH]
那么 payload_id 的內(nèi)容就是:PLo9cSeCeECAhKHlk06drRFHCyd1BGHE/fliEd0F3uQ=H+gFeOLUWil1LyX4VOJIhGvHHv+MrFu1RBdxXzhorHQ=
由于兩個(gè)數(shù)據(jù)是 Hash 值,可以標(biāo)識(shí)此數(shù)據(jù)包
// Unique identifier for the payload. An empty string means that the payload
// can't be resumed.
string payload_id = (headers[kPayloadPropertyFileHash] +
headers[kPayloadPropertyMetadataHash]);
--------------------------------------------------------------------------------------------------------------------------------
下面是根據(jù)升級(jí)請(qǐng)求創(chuàng)建 InstallPlan
關(guān)于 InstallPlan 結(jié)構(gòu)體的描述在下面會(huì)分析。
此結(jié)構(gòu)體從流程上看還是比較重要的,描述了升級(jí)過程中的安裝計(jì)劃,也是作為 Action 的輸入輸出對(duì)象一直出現(xiàn)在 Action 的執(zhí)行過程中的。
// Setup the InstallPlan based on the request.
install_plan_ = InstallPlan();
install_plan_.download_url = payload_url;
install_plan_.version = "";
base_offset_ = payload_offset;
// 創(chuàng)建 InstallPlan 結(jié)構(gòu)體中的 Payload 結(jié)構(gòu)體
InstallPlan::Payload payload;
payload.size = payload_size;
if (!payload.size) {
if (!base::StringToUint64(headers[kPayloadPropertyFileSize],
&payload.size)) {
payload.size = 0;
}
}
if (!brillo::data_encoding::Base64Decode(headers[kPayloadPropertyFileHash],
&payload.hash)) {
LOG(WARNING) << "Unable to decode base64 file hash: "
<< headers[kPayloadPropertyFileHash];
}
if (!base::StringToUint64(headers[kPayloadPropertyMetadataSize],
&payload.metadata_size)) {
payload.metadata_size = 0;
}
// The |payload.type| is not used anymore since minor_version 3.
payload.type = InstallPayloadType::kUnknown;
// 為 Payload 結(jié)構(gòu)體賦值后,將對(duì)象放入到 install_plan_.payloads 容器中。
install_plan_.payloads.push_back(payload);
// The |public_key_rsa| key would override the public key stored on disk.
install_plan_.public_key_rsa = "";
install_plan_.hash_checks_mandatory = hardware_->IsOfficialBuild();
// 判斷是否進(jìn)行未完成的升級(jí)。是一次 全新升級(jí)(new update) 還是 恢復(fù)上一次升級(jí)(resume)。
install_plan_.is_resume = !payload_id.empty() &&
DeltaPerformer::CanResumeUpdate(prefs_, payload_id);
if (!install_plan_.is_resume) {
if (!DeltaPerformer::ResetUpdateProgress(prefs_, false)) {
LOG(WARNING) << "Unable to reset the update progress.";
}
if (!prefs_->SetString(kPrefsUpdateCheckResponseHash, payload_id)) {
LOG(WARNING) << "Unable to save the update check response hash.";
}
}
// source_slot 表示當(dāng)前正在運(yùn)行的分區(qū)
install_plan_.source_slot = boot_control_->GetCurrentSlot();
// target_slot 表示需要升級(jí)的分區(qū)
install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0;
install_plan_.powerwash_required =
GetHeaderAsBool(headers[kPayloadPropertyPowerwash], false);
// 選擇哪個(gè)分區(qū)進(jìn)行重啟。
install_plan_.switch_slot_on_reboot =
GetHeaderAsBool(headers[kPayloadPropertySwitchSlotOnReboot], true);
// 需要執(zhí)行 run_post_install 步驟。
install_plan_.run_post_install = true;
// Optionally skip post install if and only if:
// a) we're resuming
// b) post install has already succeeded before
// c) RUN_POST_INSTALL is set to 0.
/*
*(可選)在以下情況下跳過 run_post_install 步驟:
* a) 我們正在恢復(fù)
* b) 安裝后在之前已經(jīng)成功
* c) RUN_POST_INSTALL設(shè)置為 0。
*/
if (install_plan_.is_resume && prefs_->Exists(kPrefsPostInstallSucceeded)) {
bool post_install_succeeded = false;
if (prefs_->GetBoolean(kPrefsPostInstallSucceeded,
&post_install_succeeded) &&
post_install_succeeded) {
install_plan_.run_post_install =
GetHeaderAsBool(headers[kPayloadPropertyRunPostInstall], true);
}
}
// Skip writing verity if we're resuming and verity has already been written.
install_plan_.write_verity = true;
if (install_plan_.is_resume && prefs_->Exists(kPrefsVerityWritten)) {
bool verity_written = false;
if (prefs_->GetBoolean(kPrefsVerityWritten, &verity_written) &&
verity_written) {
install_plan_.write_verity = false;
}
}
NetworkId network_id = kDefaultNetworkId;
if (!headers[kPayloadPropertyNetworkId].empty()) {
if (!base::StringToUint64(headers[kPayloadPropertyNetworkId],
&network_id)) {
return LogAndSetError(
error,
FROM_HERE,
"Invalid network_id: " + headers[kPayloadPropertyNetworkId]);
}
if (!network_selector_->SetProcessNetwork(network_id)) {
return LogAndSetError(
error,
FROM_HERE,
"Unable to set network_id: " + headers[kPayloadPropertyNetworkId]);
}
}
LOG(INFO) << "Using this install plan:";
// 一直到這里,InstallPlan 結(jié)構(gòu)體參數(shù)設(shè)置完成了。這里會(huì)輸出 InstallPlan 中的參數(shù),其實(shí)現(xiàn)在 install_plan.cc 中。
install_plan_.Dump();
--------------------------------------------------------------------------------------------------------------------------------
下面是對(duì) HttpFetcher 類做 URL升級(jí)文件路徑判斷與 headers Map集合的額外配置
判斷:判斷當(dāng)前傳過來的路徑是否支持下載,僅支持的 url 路徑必須以 "file:///" 開始
配置:如果 headers[AUTHORIZATION] 和 headers[USER_AGENT] 配置項(xiàng)為空,那么進(jìn)行默認(rèn)配置
headers[AUTHORIZATION] = "Authorization"
headers[USER_AGENT] = "User-Agent"
HttpFetcher* fetcher = nullptr;
if (FileFetcher::SupportedUrl(payload_url)) {
DLOG(INFO) << "Using FileFetcher for file URL.";
fetcher = new FileFetcher();
} else {
#ifdef _UE_SIDELOAD
LOG(FATAL) << "Unsupported sideload URI: " << payload_url;
#else
LibcurlHttpFetcher* libcurl_fetcher =
new LibcurlHttpFetcher(&proxy_resolver_, hardware_);
libcurl_fetcher->set_server_to_check(ServerToCheck::kDownload);
fetcher = libcurl_fetcher;
#endif // _UE_SIDELOAD
}
// Setup extra headers.
if (!headers[kPayloadPropertyAuthorization].empty())
fetcher->SetHeader("Authorization", headers[kPayloadPropertyAuthorization]);
if (!headers[kPayloadPropertyUserAgent].empty())
fetcher->SetHeader("User-Agent", headers[kPayloadPropertyUserAgent]);
--------------------------------------------------------------------------------------------------------------------------------
到這里一些準(zhǔn)備工作就已經(jīng)差不多結(jié)束了,要開始準(zhǔn)備升級(jí)的動(dòng)作了。
// 創(chuàng)建升級(jí)的各種 Action。前面提到的 UpdateEngine 模塊的 Action 就是這里完成的。
BuildUpdateActions(fetcher);
// 回調(diào)給客戶端當(dāng)前升級(jí)狀態(tài)為 UPDATE_AVAILABLE
SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
// 保存更新開始時(shí)間。如果更新不是恢復(fù),則重置重新啟動(dòng)計(jì)數(shù)和嘗試次數(shù);否則遞增嘗試次數(shù)。
UpdatePrefsOnUpdateStart(install_plan_.is_resume);
// TODO(xunchang) report the metrics for unresumable updates
// 這里是開啟了 ActionProcessor 中的 Action 調(diào)度,開始執(zhí)行 Action。
/*
* 問題:是否開啟了新的線程
* 參考鏈接:
* https://keyou.github.io/blog/2019/06/11/Chromium-MessageLoop-and-TaskScheduler/
* https://blog.csdn.net/Mirage520/article/details/41699347
*
* 我們先來看下這里的實(shí)現(xiàn),這里調(diào)用了 PostTask() 函數(shù)去調(diào)用 ActionProcessor->StartProcessing() 函數(shù)
* brillo::MessageLoop::current()->PostTask(
FROM_HERE,
Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
base::Unretained(processor_.get())));
*
* 關(guān)于 PostTask() 函數(shù),搜索到的理解是向當(dāng)前線程調(diào)用 PostTask() 函數(shù)向 線程池 里創(chuàng)建任務(wù),那么這里的執(zhí)行是否會(huì)在新的線程里執(zhí)行呢?
* 從日志上看,升級(jí)的動(dòng)作是在主進(jìn)程中完成的。
*/
ScheduleProcessingStart();
return true;
}
總結(jié)一下 ApplyPayload 方法的內(nèi)容:
1、判斷升級(jí)狀態(tài)
2、解析傳入的參數(shù)
3、將傳入的參數(shù)設(shè)定到 install_plan_ 結(jié)構(gòu)體中
4、創(chuàng)建升級(jí)的各種 action
5、回調(diào)給客戶端當(dāng)前的升級(jí)狀態(tài)
6、開啟 ActionProcessor 中 Action 的運(yùn)行
2.3.1.2.4 BuildUpdateActions 函數(shù)實(shí)現(xiàn)
在 ApplyPayload() 升級(jí)觸發(fā)接口中,創(chuàng)建 Action 動(dòng)作的過程由 BuildUpdateActions 完成。下面我們來分析下創(chuàng)建 Action 的實(shí)現(xiàn)過程。
文件:android/system/update_engine/update_attempter_android.cc
// 創(chuàng)建升級(jí)過程中的 Action。
void UpdateAttempterAndroid::BuildUpdateActions(HttpFetcher* fetcher) {
CHECK(!processor_->IsRunning());
// 設(shè)置 ActionProcessor 管理類的委托對(duì)象,UpdateAttempterAndroid 類繼承自 ActionProcessorDelegate 類。
processor_->set_delegate(this);
// Actions:
/*
* 下面是創(chuàng)建 Action。
* Action 依次是:
* UpdateBootFlagsAction
* InstallPlanAction
* DownloadAction
* FilesystemVerifierAction
* PostinstallRunnerAction
*
*/
auto update_boot_flags_action =
std::make_unique<UpdateBootFlagsAction>(boot_control_);
auto install_plan_action = std::make_unique<InstallPlanAction>(install_plan_);
auto download_action =
std::make_unique<DownloadAction>(prefs_,
boot_control_,
hardware_,
nullptr, // system_state, not used.
fetcher, // passes ownership
true /* interactive */);
// 設(shè)置 DownloadAction 類的委托對(duì)象,UpdateAttempterAndroid 類繼承自 DownloadActionDelegate 類。
download_action->set_delegate(this);
download_action->set_base_offset(base_offset_);
auto filesystem_verifier_action =
std::make_unique<FilesystemVerifierAction>();
auto postinstall_runner_action =
std::make_unique<PostinstallRunnerAction>(boot_control_, hardware_);
// 設(shè)置 PostinstallRunnerAction 類的委托對(duì)象,UpdateAttempterAndroid 類繼承自 PostinstallRunnerAction::DelegateInterface 類。
postinstall_runner_action->set_delegate(this);
// Bond them together. We have to use the leaf-types when calling
// BondActions().
// 通過調(diào)用 BondActions() 函數(shù)將 Action 之間通過 ActionPipe 連接起來。
BondActions(install_plan_action.get(), download_action.get());
BondActions(download_action.get(), filesystem_verifier_action.get());
BondActions(filesystem_verifier_action.get(),
postinstall_runner_action.get());
// 將創(chuàng)建的 Action 依次放入 ActionProcessor 的隊(duì)列中。
processor_->EnqueueAction(std::move(update_boot_flags_action));
processor_->EnqueueAction(std::move(install_plan_action));
processor_->EnqueueAction(std::move(download_action));
processor_->EnqueueAction(std::move(filesystem_verifier_action));
processor_->EnqueueAction(std::move(postinstall_runner_action));
processor_->printActions();
}
2.3.1.2.5 ScheduleProcessingStart 函數(shù)實(shí)現(xiàn)
在 ApplyPayload 接口實(shí)現(xiàn)中,調(diào)用了 ScheduleProcessingStart() 函數(shù)去開啟 ActionProcessor 中的 Action 執(zhí)行。
文件:android/system/update_engine/update_attempter_android.cc
/*
* 調(diào)用 PostTask() 函數(shù)執(zhí)行 ActionProcessor->StartProcessing() 方法開啟 Action 動(dòng)作執(zhí)行。
*/
void UpdateAttempterAndroid::ScheduleProcessingStart() {
LOG(INFO) << "Scheduling an action processor start.";
brillo::MessageLoop::current()->PostTask(
FROM_HERE,
Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
base::Unretained(processor_.get())));
}
我們來跟蹤下是如何進(jìn)行 Action 執(zhí)行的。
文件:android/system/update_engine/common/action_processor.cc
/*
* 開啟 ActionProcessor 中 Action 的執(zhí)行。
*/
void ActionProcessor::StartProcessing() {
CHECK(!IsRunning());
// 如果當(dāng)前 Action 隊(duì)列中有 Action,則進(jìn)行處理,否則無處理。
if (!actions_.empty()) {
// 獲取 actions_ 隊(duì)列中的第一個(gè) Action 賦值給 current_action。
current_action_ = std::move(actions_.front());
// 將 actions_ 隊(duì)列中的第一個(gè) Action 移出隊(duì)列。
actions_.pop_front();
LOG(INFO) << "ActionProcessor: starting " << current_action_->Type();
// 調(diào)用 Action 的 performAction() 函數(shù)執(zhí)行 Action 的功能。
current_action_->PerformAction();
}
}
2.3.1.3 InstallPlan 結(jié)構(gòu)分析
前面提到 InstallPlan 結(jié)構(gòu)體是在整個(gè)升級(jí)中都參與的,是大多 Action 動(dòng)作的輸入對(duì)象和輸出對(duì)象。
InstallPlan 結(jié)構(gòu)體中的數(shù)據(jù)是從升級(jí)包中解析出來的,升級(jí)過程中會(huì)不斷填充此結(jié)構(gòu)體,最終升級(jí)完成。
InstallPlan的結(jié)構(gòu)如下圖所示:
struct InstallPlan {
InstallPlan() = default;
bool operator==(const InstallPlan& that) const;
bool operator!=(const InstallPlan& that) const;
void Dump() const;
// Loads the |source_path| and |target_path| of all |partitions| based on the
// |source_slot| and |target_slot| if available. Returns whether it succeeded
// to load all the partitions for the valid slots.
bool LoadPartitionsFromSlots(BootControlInterface* boot_control); // 獲取 source_slot 和 target_slot 中的分區(qū)路徑
bool is_resume{false}; // 是否未更新完成,需要恢復(fù)更新
std::string download_url; // url to download from 升級(jí)文件的 url
std::string version; // version we are installing. 版本號(hào)
// system version, if present and separate from version
std::string system_version; // 系統(tǒng)版本號(hào)
struct Payload {
uint64_t size = 0; // size of the payload 升級(jí)包 payload.bin 的大小
uint64_t metadata_size = 0; // size of the metadata 元數(shù)據(jù) metadata 的大小
std::string metadata_signature; // signature of the metadata in base64 元數(shù)據(jù)的簽名 base64 格式
brillo::Blob hash; // SHA256 hash of the payload 升級(jí)包 payload.bin 的 hash 值
InstallPayloadType type{InstallPayloadType::kUnknown}; // 升級(jí)包的類型{kUnknown:未知 kFull:整包升級(jí) kDelta:差分升級(jí)}
// Only download manifest and fill in partitions in install plan without
// apply the payload if true. Will be set by DownloadAction when resuming
// multi-payload.
bool already_applied = false; // 升級(jí)包是否已經(jīng)被應(yīng)用,如果為 true,則僅下載清單并填寫安裝計(jì)劃中的密碼,而不應(yīng)用有效負(fù)載。將在 DownloadAction 階段恢復(fù)多有效負(fù)載時(shí)由下載操作設(shè)置。
bool operator==(const Payload& that) const {
return size == that.size && metadata_size == that.metadata_size &&
metadata_signature == that.metadata_signature &&
hash == that.hash && type == that.type &&
already_applied == that.already_applied;
}
};
std::vector<Payload> payloads;
// The partition slots used for the update.
BootControlInterface::Slot source_slot{BootControlInterface::kInvalidSlot}; // 定義 source_slot
BootControlInterface::Slot target_slot{BootControlInterface::kInvalidSlot}; // 定義 target_slot
// The vector below is used for partition verification. The flow is:
//
// 1. DownloadAction fills in the expected source and target partition sizes
// and hashes based on the manifest.
//
// 2. FilesystemVerifierAction computes and verifies the partition sizes and
// hashes against the expected values.
struct Partition {
bool operator==(const Partition& that) const;
// The name of the partition.
std::string name; // 分區(qū)名
std::string source_path; // 在 source_slot 中的位置
uint64_t source_size{0}; // 在 source_slot 大小
brillo::Blob source_hash; // 在 source_slot 中的 hash 值
std::string target_path; // 在 target_slot 中的位置
uint64_t target_size{0}; // 在 target_slot 中大小
brillo::Blob target_hash; // 在 target_slot 中的 hash 值
uint32_t block_size{0};
// Whether we should run the postinstall script from this partition and the
// postinstall parameters.
bool run_postinstall{false};
std::string postinstall_path;
std::string filesystem_type; // 文件系統(tǒng)類型
bool postinstall_optional{false};
// Verity hash tree and FEC config. See update_metadata.proto for details.
// All offsets and sizes are in bytes.
uint64_t hash_tree_data_offset{0};
uint64_t hash_tree_data_size{0};
uint64_t hash_tree_offset{0};
uint64_t hash_tree_size{0};
std::string hash_tree_algorithm;
brillo::Blob hash_tree_salt;
uint64_t fec_data_offset{0};
uint64_t fec_data_size{0};
uint64_t fec_offset{0};
uint64_t fec_size{0};
uint32_t fec_roots{0};
};
std::vector<Partition> partitions;
// True if payload hash checks are mandatory based on the system state and
// the Omaha response.
bool hash_checks_mandatory{false}; // 是否進(jìn)行強(qiáng)制 HASH 檢測(cè)
// True if Powerwash is required on reboot after applying the payload.
// False otherwise.
bool powerwash_required{false}; // 是否在升級(jí)后進(jìn)行數(shù)據(jù)擦除
// True if the updated slot should be marked active on success.
// False otherwise.
bool switch_slot_on_reboot{true}; // 是否在升級(jí)成功后標(biāo)記分區(qū)啟動(dòng)狀態(tài)
// True if the update should run its post-install step.
// False otherwise.
bool run_post_install{true};
// True if this update is a rollback.
bool is_rollback{false};
// True if the update should write verity.
// False otherwise.
bool write_verity{true};
// If not blank, a base-64 encoded representation of the PEM-encoded
// public key in the response.
std::string public_key_rsa; // 公鑰,此密鑰已經(jīng)內(nèi)置到系統(tǒng)中
};
source 代表的是現(xiàn)在正在運(yùn)行的系統(tǒng),target 代表此時(shí)備用的系統(tǒng)。
也可以把 source 系統(tǒng)作為一個(gè)舊的系統(tǒng),因?yàn)樵谏?jí)檢測(cè)新版本的時(shí)候,會(huì)根據(jù) source 系統(tǒng)檢測(cè)新的版本,而在升級(jí)的時(shí)候,先會(huì)把 source 系統(tǒng)拷貝到 target 中,之后再利用升級(jí)包對(duì) target 系統(tǒng)進(jìn)行升級(jí)。
2.3.2 回調(diào)流程
前面提到 BinderUpdateEngineAndroidService 封裝了 aidl 接口以及回調(diào)的實(shí)現(xiàn),BinderUpdateEngineAndroidService 繼承 android::os::BnUpdateEngine、ServiceObserverInterface;android::os::BnUpdateEngine 是 AIDL 對(duì)象,ServiceObserverInterface 是封裝了回調(diào)接口類。這里先看下 ServiceObserverInterface 類中的回調(diào)方法定義。
文件:android/system/update_engine/service_observer_interface.h
class ServiceObserverInterface {
public:
virtual ~ServiceObserverInterface() = default;
// Called whenever the value of these parameters changes. For |progress|
// value changes, this method will be called only if it changes significantly.
// 回調(diào)升級(jí)狀態(tài)和升級(jí)進(jìn)度給上層
virtual void SendStatusUpdate(
const update_engine::UpdateEngineStatus& update_engine_status) = 0;
// Called whenever an update attempt is completed.
// 回調(diào)升級(jí)結(jié)果給上層
virtual void SendPayloadApplicationComplete(ErrorCode error_code) = 0;
protected:
ServiceObserverInterface() = default;
};
ServiceObserverInterface 定義了回調(diào)的接口,BinderUpdateEngineAndroidService 繼承了 ServiceObserverInterface 類,提供了回調(diào)的實(shí)現(xiàn),我們來跟蹤下功能實(shí)現(xiàn)。文章來源:http://www.zghlxwxcb.cn/news/detail-744591.html
文件:android/system/update_engine/binder_service_android.cc
--------------------------------------------------------------------------------------------------------------------------------
這里在描述回調(diào)流程之前,我們先分析下綁定回調(diào)的流程,以便于對(duì)整個(gè)回調(diào)有清晰的了解
// 綁定回調(diào)流程
// 上層通過 bind 接口將 callback 對(duì)象傳遞到底層。
Status BinderUpdateEngineAndroidService::bind(
const android::sp<IUpdateEngineCallback>& callback, bool* return_value) {
// 將上層傳遞下來的 callback 對(duì)象放入到 callbacks_ 集合中保存。
// callbacks_ 集合是專門來保存上層傳遞的 Callback 對(duì)象的。
// 那么回調(diào)對(duì)象的綁定也就是將 callback 對(duì)象保存起來。
callbacks_.emplace_back(callback);
// 調(diào)用 RegisterForDeathNotifications 函數(shù)確保傳遞下來的 callback 對(duì)象是存在的。
const android::sp<IBinder>& callback_binder =
IUpdateEngineCallback::asBinder(callback);
auto binder_wrapper = android::BinderWrapper::Get();
binder_wrapper->RegisterForDeathNotifications(
callback_binder,
base::Bind(
base::IgnoreResult(&BinderUpdateEngineAndroidService::UnbindCallback),
base::Unretained(this),
base::Unretained(callback_binder.get())));
// Send an status update on connection (except when no update sent so far),
// since the status update is oneway and we don't need to wait for the
// response.
// 對(duì)于進(jìn)度的判斷,如果存在進(jìn)度的話,則將進(jìn)度同步回調(diào)上層告知此時(shí)的升級(jí)進(jìn)度。
if (last_status_ != -1)
callback->onStatusUpdate(last_status_, last_progress_);
*return_value = true;
return Status::ok();
}
--------------------------------------------------------------------------------------------------------------------------------
回調(diào)接口實(shí)現(xiàn)
// 回調(diào)升級(jí)狀態(tài)和升級(jí)進(jìn)度
void BinderUpdateEngineAndroidService::SendStatusUpdate(
const UpdateEngineStatus& update_engine_status) {
// 獲取升級(jí)的狀態(tài)
last_status_ = static_cast<int>(update_engine_status.status);
// 通過 update_engine_status 獲取升級(jí)的進(jìn)度
last_progress_ = update_engine_status.progress;
// 遍歷 callbacks_ 集合,調(diào)用對(duì)象的 onStatusUpdate 方法將升級(jí)的狀態(tài)和升級(jí)的進(jìn)度回調(diào)給上層
for (auto& callback : callbacks_) {
callback->onStatusUpdate(last_status_, last_progress_);
}
}
// 回調(diào)升級(jí)結(jié)果
void BinderUpdateEngineAndroidService::SendPayloadApplicationComplete(
ErrorCode error_code) {
// 遍歷 callbacks_ 集合,調(diào)用對(duì)象的 onPayloadApplicationComplete 方法將升級(jí)的結(jié)果回調(diào)給上層
for (auto& callback : callbacks_) {
callback->onPayloadApplicationComplete(static_cast<int>(error_code));
}
}
下一篇:Android UpdateEngine 模塊分析(四)UpdateEngine 升級(jí)邏輯文章來源地址http://www.zghlxwxcb.cn/news/detail-744591.html
到了這里,關(guān)于Android UpdateEngine 模塊分析(三)升級(jí)觸發(fā)以及Action機(jī)制介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!