在update_engine-整體結構(一)中分析UpdateEngineDaemon::OnInit()的整體情況。下面先分析在該方法中涉及的DaemonStateAndroid和BinderUpdateEngineAndroidService。
DaemonStateAndroid
它的繼承關系為
aemonStateInterface中的成員函數都是純虛函數,在這種情況中可以認為和java中的接口一樣,所以在這里使用的是實現的關系,同時也只列出了較為重要的方法。UpdateEngineDaemon的OnInit()方法中調用了DaemonStateAndroid的Initialize()方法,那么這個方法都干了些什么呢?
src/system/update_engine/daemon_state_android.cc
1 bool DaemonStateAndroid::Initialize() { 2 boot_control_ = boot_control::CreateBootControl(); //創建BootControl
3 if (!boot_control_) { 4 LOG(WARNING) << "Unable to create BootControl instance, using stub "
5 << "instead. All update attempts will fail."; 6 boot_control_.reset(new BootControlStub()); 7 } 8
9 hardware_ = hardware::CreateHardware(); //創建hardware
10 if (!hardware_) { 11 LOG(ERROR) << "Error intializing the HardwareInterface."; 12 return false; 13 } 14
15 LOG_IF(INFO, !hardware_->IsNormalBootMode()) << "Booted in dev mode."; 16 LOG_IF(INFO, !hardware_->IsOfficialBuild()) << "Booted non-official build."; 17
18 // Initialize prefs.
19 base::FilePath non_volatile_path; 20 // TODO(deymo): Fall back to in-memory prefs if there's no physical directory 21 // available.
22 if (!hardware_->GetNonVolatileDirectory(&non_volatile_path)) { 23 LOG(ERROR) << "Failed to get a non-volatile directory."; 24 return false; 25 } 26 Prefs* prefs = new Prefs(); //創建Prefs
27 prefs_.reset(prefs); 28 if (!prefs->Init(non_volatile_path.Append(kPrefsSubDirectory))) { 29 LOG(ERROR) << "Failed to initialize preferences."; 30 return false; 31 } 32
33 // The CertificateChecker singleton is used by the update attempter.
34 certificate_checker_.reset( 35 new CertificateChecker(prefs_.get(), &openssl_wrapper_)); //設置certificateChecker
36 certificate_checker_->Init(); 37
38 // Initialize the UpdateAttempter before the UpdateManager.
39 update_attempter_.reset(new UpdateAttempterAndroid( //設置UpdateAttempterAndroid
40 this, prefs_.get(), boot_control_.get(), hardware_.get())); 41
42 return true; 43 }
可以看到初始化了boot_control_,hardware_,ceritficate_checker_,update_attempter_。boot_control_,hardware_,主要實現對slot等底層的操作(在A/B升級中,會存在雙系統A和B,可以將A和B稱為slot)而update_attempter_其實是A/B升級的核心操作。在UpdateEngineDaemon的OnInit()中的daemon_state->StartUpdater(),最終調用的其實是update_attempter_->Init()
1 bool DaemonStateAndroid::StartUpdater() { 2 // The DaemonState in Android is a passive daemon. It will only start applying 3 // an update when instructed to do so from the exposed binder API.
4 update_attempter_->Init(); 5 return true; 6 }
其實DaemonStateAndroid只進行了一個初始化的工作后,就把其他的工作交給了UpdateAttempterAndroid。DaemonStateAndroid到此就算分析完成了。下面認識UpdateAttempterAndroid。
UpdateAttempterAndroid
它的繼承關系為
從它的結構就可以看出這個類的重要性了,在畫類圖的時候省略了函數的參數,已經成員函數只是部分出現。這個類圖只是為了幫助理清類的結構。其實這幾個接口都是回調接口,他們的函數都是在程序的運行過程中充當回調的角色。UpdateAttempterAndroid通過Init()來開始接管升級的主要流程,內容為:
src/system/update_engine/update_attempter_android.cc
1 void UpdateAttempterAndroid::Init() { 2 // In case of update_engine restart without a reboot we need to restore the
3 // reboot needed state.
4 if (UpdateCompletedOnThisBoot()) 5 SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT); 6 else
7 SetStatusAndNotify(UpdateStatus::IDLE); 8 }
在這個方法中首先判斷是否已經升級完成了但是沒有重啟,如果是那么就會發出重啟的消息,否則就會發出空閑的請求。在來看SetStatusAndNotify這個方法
SetStatusAndNotify
1 void UpdateAttempterAndroid::SetStatusAndNotify(UpdateStatus status) { 2 status_ = status; 3 size_t payload_size =
4 install_plan_.payloads.empty() ? 0 : install_plan_.payloads[0].size; 5 for (auto observer : daemon_state_->service_observers()) { 6 observer->SendStatusUpdate( 7 0, download_progress_, status_, "", payload_size); 8 } 9 last_notify_time_ = TimeTicks::Now(); 10 }
在這個方法中首先會獲取payload(升級包中的payload.bin文件)的大小,之后遍歷binder觀察者的集合,將更新的情況發送出去,從而通知客戶端(使用update_engine服務的)。最后更新通知時間。關於install_plan是一個比較重要的結構體,在后面的敘述中會對其進行描述,現在只需知道它是代表升級包的一個數據結構便可。再看來BinderUpdateEngineAndroidService。
BinderUpdateEngineAndroidService
它的繼承結構為
BinderUpdateEngineAndroidService代表了服務端的binder(BnBinder)可以和客戶端的(BpBinder)進行通信。關於Binder的通信原理就不多做說明了。下面是BinderUpdateEngineAndroidService中部分方法的說明。
src/system/update_engine/binder_service_brillo.cc
1 Status BinderUpdateEngineAndroidService::bind( 2 const android::sp<IUpdateEngineCallback>& callback, bool* return_value) { 3 callbacks_.emplace_back(callback); 4
5 const android::sp<IBinder>& callback_binder =
6 IUpdateEngineCallback::asBinder(callback); 7 auto binder_wrapper = android::BinderWrapper::Get(); 8 binder_wrapper->RegisterForDeathNotifications( 9 callback_binder, 10 base::Bind( 11 base::IgnoreResult(&BinderUpdateEngineAndroidService::UnbindCallback), 12 base::Unretained(this), 13 base::Unretained(callback_binder.get()))); 14
15 // Send an status update on connection (except when no update sent so far),
16 // since the status update is oneway and we don't need to wait for the
17 // response.
18 if (last_status_ != -1) 19 callback->onStatusUpdate(last_status_, last_progress_); 20
21 *return_value = true; 22 return Status::ok(); 23 } 24
25 void BinderUpdateEngineAndroidService::SendStatusUpdate( 26 int64_t /* last_checked_time */, 27 double progress, 28 update_engine::UpdateStatus status, 29 const std::string& /* new_version */, 30 int64_t /* new_size */) { 31 last_status_ = static_cast<int>(status); 32 last_progress_ = progress; 33 for (auto& callback : callbacks_) { 34 callback->onStatusUpdate(last_status_, last_progress_); 35 } 36 } 37
38 Status BinderUpdateEngineAndroidService::unbind( 39 const android::sp<IUpdateEngineCallback>& callback, bool* return_value) { 40 const android::sp<IBinder>& callback_binder =
41 IUpdateEngineCallback::asBinder(callback); 42 auto binder_wrapper = android::BinderWrapper::Get(); 43 binder_wrapper->UnregisterForDeathNotifications(callback_binder); 44
45 *return_value = UnbindCallback(callback_binder.get()); 46 return Status::ok(); 47 } 48
49 Status BinderUpdateEngineAndroidService::applyPayload( 50 const android::String16& url, 51 int64_t payload_offset, 52 int64_t payload_size, 53 const std::vector<android::String16>& header_kv_pairs) { 54 const std::string payload_url{android::String8{url}.string()}; 55 std::vector<std::string> str_headers; 56 str_headers.reserve(header_kv_pairs.size()); 57 for (const auto& header : header_kv_pairs) { 58 str_headers.emplace_back(android::String8{header}.string()); 59 } 60
61 brillo::ErrorPtr error; 62 if (!service_delegate_->ApplyPayload( 63 payload_url, payload_offset, payload_size, str_headers, &error)) { 64 return ErrorPtrToStatus(error); 65 } 66 return Status::ok(); 67 }
當某一個客戶端要使用update_engine提供的服務時,首先會通過bind(...)來獲取到客戶端傳過來的IUpdateEngineCallback回調接口,之后獲取代表客戶端的callback_binder_。之后就可以根據IUpdateEngineCallback,來通知客戶端更新的狀態和更新是否完成。applyPayload(..)是A/B更新的入口,在這個方法中最終會調用service_delegate_->ApplyPayload(...),service_delegate_其實就是DaemonAttempterAndroid,在這個時候就把更新的工作移交給了DaemonStateAndroid。在上面的分析中涉及到了IUpdateEngine和IUpdateEngineCallback,下面是他們的源碼
out/target/product/xxx/obj/STATIC_LIBRARIES/libupdate_engine_android_intermediates/aidl-generated/include/android/os/IUpdateEngine.h

1 namespace android { 2 3 namespace os { 4 5 class IUpdateEngine : public ::android::IInterface { 6 public: 7 DECLARE_META_INTERFACE(UpdateEngine) 8 virtual ::android::binder::Status applyPayload(const ::android::String16& url, int64_t payload_offset, int64_t payload_size, const ::std::vector<::android::String16>& headerKeyValuePairs) = 0; 9 virtual ::android::binder::Status bind(const ::android::sp<::android::os::IUpdateEngineCallback>& callback, bool* _aidl_return) = 0; 10 virtual ::android::binder::Status unbind(const ::android::sp<::android::os::IUpdateEngineCallback>& callback, bool* _aidl_return) = 0; 11 virtual ::android::binder::Status suspend() = 0; 12 virtual ::android::binder::Status resume() = 0; 13 virtual ::android::binder::Status cancel() = 0; 14 virtual ::android::binder::Status resetStatus() = 0; 15 enum Call { 16 APPLYPAYLOAD = ::android::IBinder::FIRST_CALL_TRANSACTION + 0, 17 BIND = ::android::IBinder::FIRST_CALL_TRANSACTION + 1, 18 UNBIND = ::android::IBinder::FIRST_CALL_TRANSACTION + 2, 19 SUSPEND = ::android::IBinder::FIRST_CALL_TRANSACTION + 3, 20 RESUME = ::android::IBinder::FIRST_CALL_TRANSACTION + 4, 21 CANCEL = ::android::IBinder::FIRST_CALL_TRANSACTION + 5, 22 RESETSTATUS = ::android::IBinder::FIRST_CALL_TRANSACTION + 6, 23 }; 24 }; // class IUpdateEngine 25 26 } // namespace os 27 28 } // namespace android 29 30 #endif // AIDL_GENERATED_ANDROID_OS_I_UPDATE_ENGINE_H_
out/target/product/qcs605/obj/STATIC_LIBRARIES/libupdate_engine_android_intermediates/aidl-generated/include/android/os/IUpdateEngineCallback.h

1 namespace android { 2 3 namespace os { 4 5 class IUpdateEngineCallback : public ::android::IInterface { 6 public: 7 DECLARE_META_INTERFACE(UpdateEngineCallback) 8 virtual ::android::binder::Status onStatusUpdate(int32_t status_code, float percentage) = 0; 9 virtual ::android::binder::Status onPayloadApplicationComplete(int32_t error_code) = 0; 10 enum Call { 11 ONSTATUSUPDATE = ::android::IBinder::FIRST_CALL_TRANSACTION + 0, 12 ONPAYLOADAPPLICATIONCOMPLETE = ::android::IBinder::FIRST_CALL_TRANSACTION + 1, 13 }; 14 }; // class IUpdateEngineCallback 15 16 } // namespace os 17 18 }
接下來接着看service_delegate_->ApplyPayload(...)
src/update_engine/update_attempter_android.cc
1 bool UpdateAttempterAndroid::ApplyPayload( 2 const string& payload_url, 3 int64_t payload_offset, 4 int64_t payload_size, 5 const vector<string>& key_value_pair_headers, 6 brillo::ErrorPtr* error) { 7 if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) { //檢查是否已經更新完成,需要重新啟動
8 return LogAndSetError( 9 error, FROM_HERE, "An update already applied, waiting for reboot"); 10 } 11 if (ongoing_update_) { //檢查是否正在更新
12 return LogAndSetError( 13 error, FROM_HERE, "Already processing an update, cancel it first."); 14 } 15 DCHECK(status_ == UpdateStatus::IDLE); //檢查當前是否為空閑狀態
16
17 std::map<string, string> headers; 18 for (const string& key_value_pair : key_value_pair_headers) { 19 string key; 20 string value; 21 if (!brillo::string_utils::SplitAtFirst( 22 key_value_pair, "=", &key, &value, false)) { 23 return LogAndSetError( 24 error, FROM_HERE, "Passed invalid header: " + key_value_pair); 25 } 26 if (!headers.emplace(key, value).second) 27 return LogAndSetError(error, FROM_HERE, "Passed repeated key: " + key); //將傳遞進來的key-value保存到headers中
28 } 29
30 // Unique identifier for the payload. An empty string means that the payload
31 // can't be resumed.
32 string payload_id = (headers[kPayloadPropertyFileHash] +
33 headers[kPayloadPropertyMetadataHash]); //根據Payload的hash和元數據的hash計算一個payload_id
34
35 // Setup the InstallPlan based on the request.
36 install_plan_ = InstallPlan(); //創建一個InstallPlan
37
38 install_plan_.download_url = payload_url; 39 install_plan_.version = ""; 40 base_offset_ = payload_offset; 41 InstallPlan::Payload payload; 42 payload.size = payload_size; 43 if (!payload.size) { 44 if (!base::StringToUint64(headers[kPayloadPropertyFileSize], 45 &payload.size)) { 46 payload.size = 0; 47 } 48 } 49 if (!brillo::data_encoding::Base64Decode(headers[kPayloadPropertyFileHash], 50 &payload.hash)) { 51 LOG(WARNING) << "Unable to decode base64 file hash: "
52 << headers[kPayloadPropertyFileHash]; 53 } 54 if (!base::StringToUint64(headers[kPayloadPropertyMetadataSize], 55 &payload.metadata_size)) { 56 payload.metadata_size = 0; 57 } 58 // The |payload.type| is not used anymore since minor_version 3.
59 payload.type = InstallPayloadType::kUnknown; 60 install_plan_.payloads.push_back(payload); //為payload賦值完成后,將其放入到集合中,因為ApplyPayload可能被多次調用,會有多個payload
61
62 // The |public_key_rsa| key would override the public key stored on disk.
63 install_plan_.public_key_rsa = ""; 64
65 install_plan_.hash_checks_mandatory = hardware_->IsOfficialBuild(); //是否進行強制性的hash驗證,如果為user版則為true,如果為userdebug則為false
66 install_plan_.is_resume = !payload_id.empty() &&
67 DeltaPerformer::CanResumeUpdate(prefs_, payload_id); //是否接着上次未更新完的繼續更新
68 if (!install_plan_.is_resume) { //如果從頭開始更新
69 if (!DeltaPerformer::ResetUpdateProgress(prefs_, false)) { //重置更新進度
70 LOG(WARNING) << "Unable to reset the update progress."; 71 } 72 if (!prefs_->SetString(kPrefsUpdateCheckResponseHash, payload_id)) { //保存payload_id
73 LOG(WARNING) << "Unable to save the update check response hash."; 74 } 75 } 76 install_plan_.source_slot = boot_control_->GetCurrentSlot(); //當前正在運行的slot
77 install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0; //備用的也就是將要升級的slot
78
79 int data_wipe = 0; //是否進行數據擦除,也就是恢復出廠設置,在做升級包時可以指定該值 -w
80 install_plan_.powerwash_required =
81 base::StringToInt(headers[kPayloadPropertyPowerwash], &data_wipe) &&
82 data_wipe != 0; 83
84 NetworkId network_id = kDefaultNetworkId; //NetworkId沒有使用過,估計和流式更新相關。
85 if (!headers[kPayloadPropertyNetworkId].empty()) { 86 if (!base::StringToUint64(headers[kPayloadPropertyNetworkId], 87 &network_id)) { 88 return LogAndSetError( 89 error, 90 FROM_HERE, 91 "Invalid network_id: " + headers[kPayloadPropertyNetworkId]); 92 } 93 if (!network_selector_->SetProcessNetwork(network_id)) { 94 return LogAndSetError( 95 error, 96 FROM_HERE, 97 "Unable to set network_id: " + headers[kPayloadPropertyNetworkId]); 98 } 99 } 100
101 LOG(INFO) << "Using this install plan:"; 102 install_plan_.Dump(); 103
104 BuildUpdateActions(payload_url); //創建Action,這一架構可以說是更新的主要架構
105 // Setup extra headers.
106 HttpFetcher* fetcher = download_action_->http_fetcher(); 107 if (!headers[kPayloadPropertyAuthorization].empty()) 108 fetcher->SetHeader("Authorization", headers[kPayloadPropertyAuthorization]); 109 if (!headers[kPayloadPropertyUserAgent].empty()) 110 fetcher->SetHeader("User-Agent", headers[kPayloadPropertyUserAgent]); 111
112 SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE); 113 ongoing_update_ = true; //表式正在更新
114
115 // Just in case we didn't update boot flags yet, make sure they're updated
116 // before any update processing starts. This will start the update process.
117 UpdateBootFlags(); //修改bootFlags並且開始執行Action
118 return true; 119 }
從整體上看ApplyPayload主要進行了兩個工作首先是初始化payload,之后將具體的升級流程交給了一系列的Action。先看第一部分,要想了解初始化的一些細節,首先應該知道,一個升級包中都包含了些什么。下面以差分包為例,將一個差分包解壓后會得到下面的幾個文件。
升級包的基本結構
├── care_map.txt #基本上用不到
├── compatibility.zip #基本上用不到
├── META-INF
│ └── com
│ └── android
│ ├── metadata #基本上用不到
│ └── otacert #基本上用不到
├── payload.bin #主要的升級文件
└── payload_properties.txt #升級文件附帶的屬性
payload_properties.txt文件的內容大致為:
1 FILE_HASH=4kYpprUJyMwW8NNV25v0ovMWV11PPijNANQwHy0oZwc=
2 FILE_SIZE=42897969
3 METADATA_HASH=l2ih2Xam7jqAQYhr9SRdVddG9NPeenaWzTEd+DHct+o=
4 METADATA_SIZE=300902
接下來再看一下InstallPlan這個數據結構
InstallPlan數據結構
1 namespace chromeos_update_engine { 2
3 enum class InstallPayloadType { //升級包的類型
4 kUnknown, //未知
5 kFull, //全包
6 kDelta, //差分包
7 }; 8
9 std::string InstallPayloadTypeToString(InstallPayloadType type); 10
11 struct InstallPlan { 12 InstallPlan() = default; 13
14 bool operator==(const InstallPlan& that) const; 15 bool operator!=(const InstallPlan& that) const; 16
17 void Dump() const; 18
19 // Load the |source_path| and |target_path| of all |partitions| based on the
20 // |source_slot| and |target_slot| if available. Returns whether it succeeded
21 // to load all the partitions for the valid slots.
22 bool LoadPartitionsFromSlots(BootControlInterface* boot_control); //獲取source_slot和target_slot中的分區path
23
24 bool is_resume{false}; // 是否未更新完成需要恢復更新
25 std::string download_url; // url to download from 升級文件的url
26 std::string version; // version we are installing. 版本號
27
28 struct Payload { 29 uint64_t size = 0; // size of the payload payload.bin的大小
30 uint64_t metadata_size = 0; // size of the metadata 元數據的大小
31 std::string metadata_signature; // signature of the metadata in base64 元數據的簽名
32 brillo::Blob hash; // SHA256 hash of the payload payload.bin的hash
33 InstallPayloadType type{InstallPayloadType::kUnknown}; //升級包的類型
34 // Only download manifest and fill in partitions in install plan without
35 // apply the payload if true. Will be set by DownloadAction when resuming
36 // multi-payload.
37 bool already_applied = false; //升級包是否已經被應用
38
39 bool operator==(const Payload& that) const { 40 return size == that.size && metadata_size == that.metadata_size &&
41 metadata_signature == that.metadata_signature &&
42 hash == that.hash && type == that.type &&
43 already_applied == that.already_applied; 44 } 45 }; 46 std::vector<Payload> payloads; 47
48 // The partition slots used for the update.
49 BootControlInterface::Slot source_slot{BootControlInterface::kInvalidSlot}; //定義source_slot
50 BootControlInterface::Slot target_slot{BootControlInterface::kInvalidSlot}; //定義target_slot
51
52 // The vector below is used for partition verification. The flow is:
53 // 54 // 1. DownloadAction fills in the expected source and target partition sizes
55 // and hashes based on the manifest.
56 // 57 // 2. FilesystemVerifierAction computes and verifies the partition sizes and
58 // hashes against the expected values.
59 struct Partition { //一個分區在source_slot和target_slot都存在
60 bool operator==(const Partition& that) const; 61
62 // The name of the partition.
63 std::string name; 64
65 std::string source_path; //在source_slot中的位置
66 uint64_t source_size{0}; //大小
67 brillo::Blob source_hash; //hash
68
69 std::string target_path; //在target_slot中的位置
70 uint64_t target_size{0}; 71 brillo::Blob target_hash; 72
73 // Whether we should run the postinstall script from this partition and the
74 // postinstall parameters.
75 bool run_postinstall{false}; 76 std::string postinstall_path; 77 std::string filesystem_type; //文件系統的類型
78 bool postinstall_optional{false}; 79 }; 80 std::vector<Partition> partitions; 81
82 // True if payload hash checks are mandatory based on the system state and
83 // the Omaha response.
84 bool hash_checks_mandatory{false}; //是否強制進行hash檢查
85
86 // True if Powerwash is required on reboot after applying the payload.
87 // False otherwise.
88 bool powerwash_required{false}; //是否在升級時進行數據的擦除
89
90 // If not blank, a base-64 encoded representation of the PEM-encoded
91 // public key in the response.
92 std::string public_key_rsa; //public_key 一般為null,這個秘鑰常常是已經被內置到了系統中了
93 }; 94 }
把這個數據結構弄明白后,也就對ApplyPayload(..)中對InstallPlan的賦值有一個大體的意思了。在這里出現了source和target的概念,source代表的是現在正在運行的系統,target代表此時此刻備用的系統。也可以把source系統做為一個舊的系統,因為在升級檢測新版本的時候,會根據source系統檢測新的版本,而在升級的時候,先會把source系統拷貝到target中,之后再利用升級包對target進行差分升級。回到ApplyPayload(),對InstallPlan初始化完成后,就會建立Action。這個時候我們就需要明白Action是什么,又是如何運行的。