博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

update_engine-整体结构(二)

Posted on 2019-03-19 10:44  不上班行不行  阅读(3936)  评论(0编辑  收藏  举报

在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_
View Code

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 }  
View Code

 接下来接着看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是什么,又是如何运行的。