热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidUpdateEngine分析(四)服务端进程

AndroidUpdateEngine分析(四)服务端进程前面三篇分别分析了Makefile,Protobuf和AIDL相关文件以及UpdateEngine的客户端进程update
Android Update Engine分析(四)服务端进程

前面三篇分别分析了Makefile,Protobuf和AIDL相关文件以及Update Engine的客户端进程update_engine_client

相关文章:

A/B System系列

  • Android A/B System OTA分析(一)概览
  • Android A/B System OTA分析(二)系统image的生成
  • Android A/B System OTA分析(三)主系统和bootloader的通信
  • Android A/B System OTA分析(四)系统的启动和升级

Update Engine系列

  • Android Update Engine分析(一)Makefile
  • Android Update Engine分析(二)Protobuf和AIDL文件
  • Android Update Engine分析(三)客户端进程
  • Android Update Engine分析(四)服务端进程
  • Android Update Engine分析(五)服务端核心之Action机制
  • Android Update Engine分析(六)服务端核心之Action详解
  • Android Update Engine分析(七) DownloadAction之FileWriter
  • Android Update Engine分析(八)升级包制作脚本分析

本篇开始分析Update Engine的服务端进程update_engine

本文涉及的Android代码版本:android‐7.1.1_r23 (NMF27D)

1. update_engine的文件依赖关系

老规矩,在开始代码之前,先看看文件的依赖关系。

有人或许会问,分析代码就分析代码,干嘛还在先去列举依赖的文件?岂不多此一举?

当你尝试阅读代码就会明白,代码中涉及多个分支的条件编译时,有些函数在多个分支实现中都会存在,这时到底应该分析哪个文件就是个问题。如果将这些文件的依赖都列举出来,很容易就知道哪些文件有参与编译,哪些文件没有被使用。如果不确定,那就回头来看看代码的文件依赖关系就知道了。

例如名为update_engine_client.cc的文件,里面有main函数,有各种实现代码,看起来像是客户端的入口,那这个文件真的是客户端update_engine_client的入口吗?

又例如,名为update_attempter.cc的文件,里面也实现了一套Update Engine的核心逻辑,那应该分析这个文件吗?

单从文件命名上来看,根本无法确定上面提到的这两个文件是否有参与编译。如果你有文件依赖列表,你就知道客户端进程的代码是update_engine_client_android.cc;而Android上Update Engine中使用的是update_attempter_android.cc而不是update_attempter.cc

Android Update Engine的服务端守护进程自身的代码文件只有一个,那就是main.cc,其余是对各种库的依赖,以下列举服务端守护进程update_engine和Update Engine相关库和文件的依赖关系。

服务端守护进程update_engine

update_engine
--> files (
main.cc
)
--> static libraries (
libupdate_engine_android
libpayload_consumer
libfs_mgr
update_metadata-protos
libxz-host
libbz
)
--> shared libraries (
libcrypto-host
libprotobuf-cpp-lite
libandroid
libbinder
libbinderwrapper
libcutils
libcurl
libhardware
libssl
libssl
)

服务端守护进程update_engine除去依赖Android的公共静态和动态库之外,跟Update Engine相关的库主要有三个:

  • libupdate_engine_android
  • libpayload_consumer
  • update_metadata-protos

我们的目标是分析Update Engine相关内容,因此这里对公共的静态和动态库不做展开说明。

下面是Update Engine三个主要的库文件依赖关系:

libupdate_engine_android (STATIC_LIBRARIES)
--> binder_bindings/android/os/IUpdateEngine.aidl
binder_bindings/android/os/IUpdateEngineCallback.aidl
binder_service_android.cc
boot_control_android.cc
certificate_checker.cc
daemon.cc
daemon_state_android.cc
hardware_android.cc
libcurl_http_fetcher.cc
network_selector_android.cc
proxy_resolver.cc
update_attempter_android.cc
update_status_utils.cc
utils_android.cc
libpayload_consumer (STATIC_LIBRARIES)
--> common/action_processor.cc
common/boot_control_stub.cc
common/clock.cc
common/constants.cc
common/cpu_limiter.cc
common/error_code_utils.cc
common/hash_calculator.cc
common/http_common.cc
common/http_fetcher.cc
common/file_fetcher.cc
common/hwid_override.cc
common/multi_range_http_fetcher.cc
common/platform_constants_android.cc
common/prefs.cc
common/subprocess.cc
common/terminator.cc
common/utils.cc
payload_consumer/bzip_extent_writer.cc
payload_consumer/delta_performer.cc
payload_consumer/download_action.cc
payload_consumer/extent_writer.cc
payload_consumer/file_descriptor.cc
payload_consumer/file_writer.cc
payload_consumer/filesystem_verifier_action.cc
payload_consumer/install_plan.cc
payload_consumer/payload_constants.cc
payload_consumer/payload_verifier.cc
payload_consumer/postinstall_runner_action.cc
payload_consumer/xz_extent_writer.cc
update_metadata-protos (STATIC_LIBRARIES)
--> update_metadata.proto

如果阅读代码时不清楚文件是否有用,回头来看看这个列表吧。

闲话到此位置,以下对代码展开分析。

2. update_engine代码分析

2.1 main.cc

服务端进程update_engine的入口在main.cc文件中,因此这里从main函数入手。

// 文件: system\update_engine\main.cc
int main(int argc, char** argv) {
DEFINE_bool(logtostderr, false,
"Write logs to stderr instead of to a file in log_dir.");
DEFINE_bool(foreground, false,
"Don't daemon()ize; run in foreground.");
chromeos_update_engine::Terminator::Init();
brillo::FlagHelper::Init(argc, argv, "Chromium OS Update Engine");
chromeos_update_engine::SetupLogging(FLAGS_logtostderr);
if (!FLAGS_foreground)
PLOG_IF(FATAL, daemon(0, 0) == 1) <<"daemon() failed";
LOG(INFO) <<"Chrome OS Update Engine starting";
// xz-embedded requires to initialize its CRC-32 table once on startup.
xz_crc32_init();
// Ensure that all written files have safe permissions.
// This is a mask, so we _block_ all permissions for the group owner and other
// users but allow all permissions for the user owner. We allow execution
// for the owner so we can create directories.
// Done _after_ log file creation.
umask(S_IRWXG | S_IRWXO);
chromeos_update_engine::UpdateEngineDaemon update_engine_daemon;
int exit_code = update_engine_daemon.Run();
LOG(INFO) <<"Chrome OS Update Engine terminating with exit code "
< return exit_code;
}

整个main函数看起来比较简单:

  1. 定义入口参数并进行初始化;
  2. 初始化CRC-32 table;
  3. 生成update_engine_daemon,并调用其Run()方法;
  • 定义入口参数并进行初始化

# 定义参数logtostderr
DEFINE_bool(logtostderr, false,
"Write logs to stderr instead of to a file in log_dir.");
# 定义参数foreground
DEFINE_bool(foreground, false,
"Don't daemon()ize; run in foreground.");
# 初始化Terminator
chromeos_update_engine::Terminator::Init();
# 解析参数
brillo::FlagHelper::Init(argc, argv, "Chromium OS Update Engine");
chromeos_update_engine::SetupLogging(FLAGS_logtostderr);
if (!FLAGS_foreground)
PLOG_IF(FATAL, daemon(0, 0) == 1) <<"daemon() failed";
LOG(INFO) <<"Chrome OS Update Engine starting";

通过DEFINE_bool宏定义了两个参数logtostderr, foreground,展开后得到两个变量FLAGS_logtostderrFLAGS_foreground。前者用于设置日志输出重定向,后者用于指定 update_engine进程是否以forground方式运行。

  • 初始化CRC-32 table

// xz-embedded requires to initialize its CRC-32 table once on startup.
xz_crc32_init();
// Ensure that all written files have safe permissions.
// This is a mask, so we _block_ all permissions for the group owner and other
// users but allow all permissions for the user owner. We allow execution
// for the owner so we can create directories.
// Done _after_ log file creation.
umask(S_IRWXG | S_IRWXO);

这段代码目前不清楚后面哪里会用到,看起来像是创建一个查找表,用于解压缩时提高性能。不是分析重点,不解释。

umask操作设置当前进程的文件操作权限。

  • 生成update_engine_daemon对象,并调用其Run()方法

Update Engine服务端守护进程的核心update_engine_daemon对象。

chromeos_update_engine::UpdateEngineDaemon update_engine_daemon;
int exit_code = update_engine_daemon.Run();
LOG(INFO) <<"Chrome OS Update Engine terminating with exit code "
< return exit_code;

update_engine跟客户端进程update_engine_client一样,都是派生于brillo::Daemon类,所以这里会执行父类brillo::DaemonRun()方法:

// 文件: external\libbrillo\brillo\daemons\daemon.cc
int Daemon::Run() {
// 1. 执行OnInit函数进行初始化
int exit_code = OnInit();
if (exit_code != EX_OK)
return exit_code;
// 2. 初始化完成后调用brillo_message_loop_.Run()进入消息循环处理模式
brillo_message_loop_.Run();
// 3. 调用OnShutdown
OnShutdown(&exit_code_);
// 4. 等待退出消息
// base::RunLoop::QuitClosure() causes the message loop to quit
// immediately, even if pending tasks are still queued.
// Run a secondary loop to make sure all those are processed.
// This becomes important when working with D-Bus since dbus::Bus does
// a bunch of clean-up tasks asynchronously when shutting down.
while (brillo_message_loop_.RunOnce(false /* may_block */)) {}
return exit_code_;
}

这里先后有4个操作:

  1. 执行OnInit()函数进行初始化
  2. 初始化完成后调用brillo_message_loop_.Run()进入消息循环处理模式
  3. Run()退出则调用OnShutdown(),其实OnShutdown()操作里面什么都没做。
  4. 等待退出消息

总体上,整个进程的结构比较简单,就是基于brillo::Daemon类的结构,进行初始化,启动brilllo::MessageLoop机制进行消息循环处理直到退出。这4个操作中,重点是文件system\update_engine\daemon.cc中的OnInit()函数。

2.2 UpdateEngineDaemon

文件system\update_engine\daemon.cc提供了类UpdateEngineDaemon的实现。

留意跟Update Engine相关的daemon.cc文件有两个,分别是:

  • external\libbrillo\brillo\daemons\daemon.cc
  • system\update_engine\daemon.cc

前者定义了brillo::Daemon类,作为update_engine系统的消息处理框架。后者定义了UpdateEngineDaemon类, 继承自前者,在update_engine守护进程中实例化生成业务对象update_engine_daemon

update_engine_daemon.Run()会执行父类的Daemon::Run()方法,在该方法中调用OnInit()函数进行初始化时,由于int Daemon::OnInit()定义为虚函数,所以这里执行的是其子类UpdateEngineDaemonOnInit()函数,这是整个Update Engine初始化最重要的部分:

// 文件: system\update_engine\daemon.cc
int UpdateEngineDaemon::OnInit() {
// Register the |subprocess_| singleton with this Daemon as the signal
// handler.
subprocess_.Init(this);
// 调用父类brillo::Daemon的OnInit()方法,注册SIGTERM, SIGINT, SIGHUP的处理函数
int exit_code = Daemon::OnInit();
if (exit_code != EX_OK)
return exit_code;
// Android.mk中分析过USE_WEAVE=0, USE_BINDER=1,以下代码会被编译
#if USE_WEAVE || USE_BINDER
android::BinderWrapper::Create();
binder_watcher_.Init();
#endif // USE_WEAVE || USE_BINDER
// Android.mk中分析过,这里USE_DBUS=0, 不会编译以下代码,略过
#if USE_DBUS
// We wait for the D-Bus connection for up two minutes to avoid re-spawning
// the daemon too fast causing thrashing if dbus-daemon is not running.
scoped_refptr bus = dbus_connection_.ConnectWithTimeout(
base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds));
if (!bus) {
// TODO(deymo): Make it possible to run update_engine even if dbus-daemon
// is not running or constantly crashing.
LOG(ERROR) <<"Failed to initialize DBus, aborting.";
return 1;
}
CHECK(bus->SetUpAsyncOperations());
#endif // USE_DBUS
// 由于没有定义__BRILLO__和__CHROMEOS__,所以这里应该走else路径
#if defined(__BRILLO__) || defined(__CHROMEOS__)
// Initialize update engine global state but continue if something fails.
// TODO(deymo): Move the daemon_state_ initialization to a factory method
// avoiding the explicit re-usage of the |bus| instance, shared between
// D-Bus service and D-Bus client calls.
RealSystemState* real_system_state = new RealSystemState(bus);
daemon_state_.reset(real_system_state);
LOG_IF(ERROR, !real_system_state->Initialize())
<<"Failed to initialize system state.";
#else // !(defined(__BRILLO__) || defined(__CHROMEOS__))
// 针对非__BRILLO__和__CHROMEOS__的路径
// 初始化一个类DaemonStateAndroid的实例,赋值到daemon_state_android
// 对于DaemonStateAndroid,其构造函数DaemonStateAndroid()为空,没有任何操作:
// DaemonStateAndroid() = default;
DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
// 用指针daemon_state_android设置daemon_state_成员
daemon_state_.reset(daemon_state_android);
// 接下来调用DaemonStateAndroid类的方法Initialize()进行初始化
// update_engine进程真正的初始化开始啦……
LOG_IF(ERROR, !daemon_state_android->Initialize())
<<"Failed to initialize system state.";
#endif // defined(__BRILLO__) || defined(__CHROMEOS__)
// USE_BINDER=1,以下代码会被编译
#if USE_BINDER
// Create the Binder Service.
#if defined(__BRILLO__) || defined(__CHROMEOS__) // 由于没有定义__BRILLO__和__CHROMEOS__,所以这里应该走else路径
binder_service_ = new BinderUpdateEngineBrilloService{real_system_state};
#else // !(defined(__BRILLO__) || defined(__CHROMEOS__))
// 生成Binder服务对象`binder_service_`
binder_service_ = new BinderUpdateEngineAndroidService{
daemon_state_android->service_delegate()};
#endif // defined(__BRILLO__) || defined(__CHROMEOS__)
// 使用`binder_service_`向系统注册名为`"android.os.UpdateEngineService"`的服务
auto binder_wrapper = android::BinderWrapper::Get();
if (!binder_wrapper->RegisterService(binder_service_->ServiceName(),
binder_service_)) {
LOG(ERROR) <<"Failed to register binder service.";
}
// 以观察者模式将`binder_service`添加到`daemon_state_`的观察者集合中
// 观察者设计模式中,被观察对象以广播方式向注册的观察者发送消息,降低各对象的耦合度
daemon_state_->AddObserver(binder_service_.get());
#endif // USE_BINDER
// Android.mk中分析过,这里USE_DBUS=0, 不会编译以下代码,略过
#if USE_DBUS
// Create the DBus service.
dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state, bus));
daemon_state_->AddObserver(dbus_adaptor_.get());
dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
base::Unretained(this)));
LOG(INFO) <<"Waiting for DBus object to be registered.";
#else // !USE_DBUS
// 从字面`StartUpdater`看,这里开始Update Engine的核心工作
daemon_state_->StartUpdater();
#endif // USE_DBUS
return EX_OK;
}

这段代码使用的宏特别多,看起来很凌乱,整理一下,主要有以下几件事:

  • 创建一个DaemonStateAndroid类的对象daemon_state_android,并对其进行初始化

    DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
    daemon_state_.reset(daemon_state_android);
    LOG_IF(ERROR, !daemon_state_android->Initialize())
    <<"Failed to initialize system state.";

    UpdateEngineDaemon中通过unique_ptr指针daemon_state_访问daemon_state_android

  • 类对象daemon_state_android调用service_delegate()返回一个委托对象,用于构造提供Binder服务的私有私有智能指针binder_service_

    binder_service_ = new BinderUpdateEngineAndroidService{
    daemon_state_android->service_delegate()};

    其实binder_service_也是通过daemon_state_实现的。从代码可见,通过调用daemon_state_androidservice_delegate()接口:

    ServiceDelegateAndroidInterface* DaemonStateAndroid::service_delegate() {
    return update_attempter_.get();
    }

    将其私有成员update_attempter_传递给BinderUpdateEngineAndroidService类的构造函数:

    BinderUpdateEngineAndroidService::BinderUpdateEngineAndroidService(
    ServiceDelegateAndroidInterface* service_delegate)
    : service_delegate_(service_delegate) {
    }

    所以这里就是将daemon_state_的私有成员update_attempter_委托给binder_service_的私有成员service_delegate_

    BinderUpdateEngineAndroidService的实现中,applyPayload/suspend/resume/cancel/resetStatus操作都会转发给成员service_delegate_,所以这些操作最终由update_attempter_来执行。可以这么理解,binder_service_也是通过daemon_state_来实现。

    实际上,如果机械的理解&#8221;binder_service_是通过daemon_state_来实现&#8221;是有问题的,因为除了上面提到的&#8221;applyPayload / suspend / resume / cancel / resetStatus&#8220;部分,binder_service_在运行中还有调用callback进行的状态更新操作,这些callback操作接口是使用bind调用的传入参数设置的,并非来自daemon_state_,所以不是由daemon_state_实现。

    所以这里只是粗略的将binder_service_想象为是通过daemon_state_来实现而已。

  • 使用私有的binder_service_对象向系统注册名为"android.brillo.UpdateEngineService"的系统服务

    auto binder_wrapper = android::BinderWrapper::Get();
    if (!binder_wrapper->RegisterService(binder_service_->ServiceName(),
    binder_service_)) {
    LOG(ERROR) <<"Failed to register binder service.";
    }

  • binder_service添加为daemon_state_的观察对象,并通过StartUpdater()调用升级的主类UpdateAttempterAndroid进行各种处理

    daemon_state_->AddObserver(binder_service_.get());
    ...
    daemon_state_->StartUpdater();

    进行完上面的设置,整个Update Engine服务端的业务基本上也就交由daemon_state_的私有成员update_attempter_来处理了。所以daemon_state_对象对应的类DaemonStateAndroid,是真正的Update Engine业务实现者,而其私有成员update_attempter_所在的类才是整个Update Engine服务端的核心类。

综述一下,代码看起来很复杂,但简化理解起来也还算简单。为什么这么说呢?

服务端进程的业务对象update_engine_daemonUpdateEngineDaemon类的实例,通过继承brillo::Daemon类构建了daemon进程的基本功能,包含了3个重要的私有指针成员:

  • binder_watcher_
  • binder_service_
  • daemon_state_

这里binder_watcher_是构建Binder服务的公共基础设施。binder_service_通过binder_watcher_RegisterService接口进行注册,从而向外界提供名为android.brillo.UpdateEngineService的Binder服务。

因此客户端对IUpdateEngine接口的调用会转化为对binder_service_调用,这些操作会进一步被转发为daemon_state_私有成员update_attempter_的相应操作。

以下是省略掉binder_watcher后服务端进程对象update_engine_daemon简单的示意图。所以daemon_state_对象对应的的类DaemonStateAndroid,是真正的Update Engine业务实现者。

《Android Update Engine分析(四)服务端进程》

daemon_state_调用AddObserver()binder_service_添加到私有的service_observers_集合中去:

daemon_state_->AddObserver(binder_service_.get())

因为每个service在bind时会注册相应的callback接口,所以服务端可以通过调用每个观察者的callback接口向每个使用服务的客户端广播消息,例如升级进度。

daemon_state_调用StartUpdater()开始Update Engine的正式工作了。

daemon_state_->StartUpdater()

阅读代码就会发现,StartUpdater()是其私有成员update_attempter_调用Init()操作,这之后的工作就基本上交给update_attempter_了。

bool DaemonStateAndroid::StartUpdater() {
// The DaemonState in Android is a passive daemon. It will only start applying
// an update when instructed to do so from the exposed binder API.
update_attempter_->Init();
return true;
}

好了,工作转到update_attempter_以后我们就不需要再关心外层的update_engine_daemon是干什么的了。余下的重点就是对象binder_service_对应的类BinderUpdateEngineAndroidService和对象daemon_state_对应的类DaemonStateAndroid进行分析。

2.3 BinderUpdateEngineAndroidService

update_engine_daemon的私有指针binder_service_对应的类为BinderUpdateEngineAndroidService,该类提供了IUpdateEngine操作和IUpdateEngineCallback回调接口的实现。其对应的代码位于文件system\update_engine\binder_service_android.cc中。

# file: system\update_engine\binder_service_android.h
class BinderUpdateEngineAndroidService : public android::os::BnUpdateEngine,
public ServiceObserverInterface {
public:
BinderUpdateEngineAndroidService(
ServiceDelegateAndroidInterface* service_delegate);
~BinderUpdateEngineAndroidService() override = default;
const char* ServiceName() const {
return "android.os.UpdateEngineService";
}
// ServiceObserverInterface overrides.
void SendStatusUpdate(int64_t last_checked_time,
double progress,
update_engine::UpdateStatus status,
const std::string& new_version,
int64_t new_size) override;
void SendPayloadApplicationComplete(ErrorCode error_code) override;
// Channel tracking changes are ignored.
void SendChannelChangeUpdate(const std::string& tracking_channel) override {}
// android::os::BnUpdateEngine overrides.
android::binder::Status applyPayload(
const android::String16& url,
int64_t payload_offset,
int64_t payload_size,
const std::vector& header_kv_pairs) override;
android::binder::Status bind(
const android::sp& 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;
private:
// Remove the passed |callback| from the list of registered callbacks. Called
// whenever the callback object is destroyed.
void UnbindCallback(android::os::IUpdateEngineCallback* callback);
// List of currently bound callbacks.
std::vector> callbacks_;
// Cached copy of the last status update sent. Used to send an initial
// notification when bind() is called from the client.
int last_status_{-1};
double last_progress_{0.0};
ServiceDelegateAndroidInterface* service_delegate_;
};

从定义看,类BinderUpdateEngineAndroidService继承自BnUpdateEngine类和ServiceObserverInterface类,实际上这两个类都属于接口类,主要用于统一定义接口,然后由子类来实现。这方面,C#和Java就比较方便,可以直接定义接口类型实现接口继承。
BinderUpdateEngineAndroidService的父类中:

  • BnUpdateEngine主要是用于实现IUpdateEngine接口;
  • ServiceObserverInterface类用于实现回调通知接口,包括:SendStatusUpdateSendPayloadApplicationCompleteSendChannelChangeUpdate

除去以上的接口,我们可以看到BinderUpdateEngineAndroidService类还有两个重要的私有成员,IUpdateEngineCallback类型的回调对象callbacks_和Binder服务的委托对象service_delegate_

前一节中分析过,BinderUpdateEngineAndroidService的构造函数中,直接将传递进来的参数用于构造binder_service_的委托对象service_delegate_

一句话,BinderUpdateEngineAndroidServiceservice_delegate_就是DaemonStateAndroid类的私有成员update_attempter_。所有对service_delegate_的操作实际上转化为对update_attempter_相应方法的调用,如下:

Status BinderUpdateEngineAndroidService::applyPayload(
const android::String16& url,
int64_t payload_offset,
int64_t payload_size,
const std::vector& header_kv_pairs) {
const std::string payload_url{android::String8{url}.string()};
std::vector str_headers;
str_headers.reserve(header_kv_pairs.size());
for (const auto& header : header_kv_pairs) {
str_headers.emplace_back(android::String8{header}.string());
}
brillo::ErrorPtr error;
if (!service_delegate_->ApplyPayload(
payload_url, payload_offset, payload_size, str_headers, &error)) {
return ErrorPtrToStatus(error);
}
return Status::ok();
}
Status BinderUpdateEngineAndroidService::suspend() {
brillo::ErrorPtr error;
if (!service_delegate_->SuspendUpdate(&error))
return ErrorPtrToStatus(error);
return Status::ok();
}
Status BinderUpdateEngineAndroidService::resume() {
brillo::ErrorPtr error;
if (!service_delegate_->ResumeUpdate(&error))
return ErrorPtrToStatus(error);
return Status::ok();
}
Status BinderUpdateEngineAndroidService::cancel() {
brillo::ErrorPtr error;
if (!service_delegate_->CancelUpdate(&error))
return ErrorPtrToStatus(error);
return Status::ok();
}
Status BinderUpdateEngineAndroidService::resetStatus() {
brillo::ErrorPtr error;
if (!service_delegate_->ResetStatus(&error))
return ErrorPtrToStatus(error);
return Status::ok();
}

另外,在BinderUpdateEngineAndroidServicebind操作时,会使用传入的callback参数设置私有的callbacks_成员:

Status BinderUpdateEngineAndroidService::bind(
const android::sp& callback, bool* return_value) {
callbacks_.emplace_back(callback);
auto binder_wrapper = android::BinderWrapper::Get();
binder_wrapper->RegisterForDeathNotifications(
IUpdateEngineCallback::asBinder(callback),
base::Bind(&BinderUpdateEngineAndroidService::UnbindCallback,
base::Unretained(this),
base::Unretained(callback.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.
if (last_status_ != -1)
callback->onStatusUpdate(last_status_, last_progress_);
*return_value = true;
return Status::ok();
}

另外两个方法SendStatusUpdateSendPayloadApplicationComplete用于实现IUpdateEngineCallback接口,对这两个方法的调用,最后都是对bind操作传入的callback的调用(callback参数被保存到callback_私有成员中了):

void BinderUpdateEngineAndroidService::SendStatusUpdate(
int64_t /* last_checked_time */,
double progress,
update_engine::UpdateStatus status,
const std::string& /* new_version */,
int64_t /* new_size */) {
last_status_ = static_cast(status);
last_progress_ = progress;
for (auto& callback : callbacks_) {
callback->onStatusUpdate(last_status_, last_progress_);
}
}
void BinderUpdateEngineAndroidService::SendPayloadApplicationComplete(
ErrorCode error_code) {
for (auto& callback : callbacks_) {
callback->onPayloadApplicationComplete(static_cast(error_code));
}
}

总结下BinderUpdateEngineAndroidService类,主要是将外部服务接收到的请求发送到DaemonStateAndroid类的update_attempter_对象,如果有状态更新,则调用bind操作时传入的IUpdateEngineCallback类型的回调函数通知外部应用。

2.4 DaemonStateAndroid

UpdateEngineDaemon的私有指针binder_service_对应的类为BinderUpdateEngineAndroidService,该类提供了IUpdateEngine操作和IUpdateEngineCallback回调接口的实现。其对应的代码位于文件system\update_engine\binder_service_android.cc中。

UpdateEngineDaemon的私有指针daemon_state_对应的类为DaemonStateAndroid,是整个Update Engine业务的实现这,看完代码会发现这个实现者还有个核心,那就是update_attempter_

废话少数,先来看看DaemonStateAndroid类的实现文件system\update_engine\daemon_state_android.cc

文件中总共定义了5个函数:

  • Initialize()
  • StartUpdater()
  • AddObserver(* observer) (这里*表示是observer的指针)
  • RemoveObserver(* observer) (这里*表示是observer的指针)
  • service_delegate()

我们看看这几个函数在UpdateEngineDaemon::OnInit()中是如何使用的吧。还记得吗?再啰嗦一下吧:

// file: system\update_engine\daemon.cc
int UpdateEngineDaemon::OnInit() {
...
DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
daemon_state_.reset(daemon_state_android);
LOG_IF(ERROR, !daemon_state_android->Initialize())
<<"Failed to initialize system state.";
...
binder_service_ = new BinderUpdateEngineAndroidService{
daemon_state_android->service_delegate()};
auto binder_wrapper = android::BinderWrapper::Get();
if (!binder_wrapper->RegisterService(binder_service_->ServiceName(),
binder_service_)) {
LOG(ERROR) <<"Failed to register binder service.";
}
daemon_state_->AddObserver(binder_service_.get());
daemon_state_->StartUpdater();
}

以上是经过简化后的UpdateEngineDaemon::OnInit()函数,这里只突出了DaemonStateAndroid类及其对象的活动,下面对这些活动逐个分析。

初始化daemon_state_

DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
daemon_state_.reset(daemon_state_android);

使用new操作构造一个DaemonStateAndroid类的对象daemon_state_android,并用这个对象初始化指针成员daemon_state_
实际上其构造函数是一个空操作,啥也没做:

class DaemonStateAndroid : public DaemonStateInterface {
public:
DaemonStateAndroid() = default;
~DaemonStateAndroid() override = default;
...
}

留意daemon_state_实际上是DaemonStateAndroid父类DaemonStateInterface的指针,这里指向了子类的对象。

调用Initialize()

接下来调用Initialize()进行对daemon_state_android进行初始化:

LOG_IF(ERROR, !daemon_state_android->Initialize())
<<"Failed to initialize system state.";

Initialize函数代码如下:

bool DaemonStateAndroid::Initialize() {
// 调用CreateBootControl创建boot_control_,连接BootControl的HAL模块
boot_control_ = boot_control::CreateBootControl();
if (!boot_control_) {
LOG(WARNING) <<"Unable to create BootControl instance, using stub "
<<"instead. All update attempts will fail.";
boot_control_.reset(new BootControlStub());
}
// 调用CreateHardware创建hardware_,连接Hardware的HAL模块
hardware_ = hardware::CreateHardware();
if (!hardware_) {
LOG(ERROR) <<"Error intializing the HardwareInterface.";
return false;
}
// 检查boot mode和official build
LOG_IF(INFO, !hardware_->IsNormalBootMode()) <<"Booted in dev mode.";
LOG_IF(INFO, !hardware_->IsOfficialBuild()) <<"Booted non-official build.";
// Initialize prefs.
base::FilePath non_volatile_path;
// TODO(deymo): Fall back to in-memory prefs if there's no physical directory
// available.
if (!hardware_->GetNonVolatileDirectory(&non_volatile_path)) {
LOG(ERROR) <<"Failed to get a non-volatile directory.";
return false;
}
Prefs* prefs = new Prefs();
prefs_.reset(prefs);
if (!prefs->Init(non_volatile_path.Append(kPrefsSubDirectory))) {
LOG(ERROR) <<"Failed to initialize preferences.";
return false;
}
// The CertificateChecker singleton is used by the update attempter.
certificate_checker_.reset(
new CertificateChecker(prefs_.get(), &openssl_wrapper_));
certificate_checker_->Init();
// Initialize the UpdateAttempter before the UpdateManager.
update_attempter_.reset(new UpdateAttempterAndroid(
this, prefs_.get(), boot_control_.get(), hardware_.get()));
return true;
}

上面这段代码的思路比较清晰,主要操作包括:

  • 使用BootControlAndroid类的CreateBootControl()方法创建类对象并初始化boot_control_变量
  • 使用HardwareAndroid类的CreateHardware()方法创建类对象并初始化hardware_变量
  • 创建Prefs类的对象并初始化prefs_变量
  • 创建CertificateChecker类的对象,并初始化certificate_checker_变量,然后执行Init()操作
  • 使用当前DaemonStateAndroid类的对象this和前面生成的prefs_boot_control_hardware_变量来构造一个UpdateAttempterAndroid类对象用于设置update_attempter_变量

为了避免陷进代码的细节,这里不再深入下一层代码。最后总结一下,整个Initialize()函数主要就是初始化certificate_checker_update_attempter_

创建binder_service_对象

创建binder_service_对象:

binder_service_ = new BinderUpdateEngineAndroidService{
daemon_state_android->service_delegate()};

这里使用daemon_state_android->service_delegate()操作返回的对象来创建binder_service_对象。

service_deletegate()操作到底做了什么?

ServiceDelegateAndroidInterface* DaemonStateAndroid::service_delegate() {
return update_attempter_.get();
}

我去,这里就是返回私有成员update_attempter_而已。

比较有意思的是,我们来看看BinderUpdateEngineAndroidService的构造函数:

BinderUpdateEngineAndroidService::BinderUpdateEngineAndroidService(
ServiceDelegateAndroidInterface* service_delegate)
: service_delegate_(service_delegate) {
}

这里干嘛了?就是将外部传入的参数service_delegate(这里实际上是update_attempter_)设置给service_delegate_成员。

从名字service_delegate_看,这也是一个委托对象。浏览下BinderUpdateEngineAndroidService代码,关于IUpdateEngine接口(包括applyPayload, suspend, resume, cancel, resetStatus)的调用都是直接将其转发给了service_delegate_对象,这意味这所有这些对象最终都是调用update_attemper_的相应操作!!

注册Update Engine的Binder服务

注册Update Engine的Binder服务,并将binder_service_添加到daemon_state的观察对象中:

if (!binder_wrapper->RegisterService(binder_service_->ServiceName(),
binder_service_)) {
LOG(ERROR) <<"Failed to register binder service.";
}
daemon_state_->AddObserver(binder_service_.get());

这里的AddObserver干了什么呢?不妨看看代码实现:

void DaemonStateAndroid::AddObserver(ServiceObserverInterface* observer) {
service_observers_.insert(observer);
}

真简单,就是把传入的observer参数(这里为binder_service_)添加到service_observers_集合中去。这里的service_observers_有什么用呢?在DaemonStateAndroid的实现代码中没有提到,我开始也是一脸懵逼,直到我看了UpdateAttempterAndroid的代码。

先转到UpdateAttempterAndroid中,构造函数是这样的:

UpdateAttempterAndroid::UpdateAttempterAndroid(
DaemonStateInterface* daemon_state,
PrefsInterface* prefs,
BootControlInterface* boot_control,
HardwareInterface* hardware)
: daemon_state_(daemon_state),
prefs_(prefs),
boot_control_(boot_control),
hardware_(hardware),
processor_(new ActionProcessor()) {
network_selector_ = network::CreateNetworkSelector();
}

仔细留意这里的daemon_state_(daemon_state),这里用传入的daemon_state初始化私有的daemon_state_成员。有两个成员函数会使用到daemon_state_成员,如下:

void UpdateAttempterAndroid::TerminateUpdateAndNotify(ErrorCode error_code) {
if (status_ == UpdateStatus::IDLE) {
LOG(ERROR) <<"No ongoing update, but TerminatedUpdate() called.";
return;
}
// Reset cpu shares back to normal.
cpu_limiter_.StopLimiter();
download_progress_ = 0;
actions_.clear();
UpdateStatus new_status =
(error_code == ErrorCode::kSuccess ? UpdateStatus::UPDATED_NEED_REBOOT
: UpdateStatus::IDLE);
SetStatusAndNotify(new_status);
ongoing_update_ = false;
for (auto observer : daemon_state_->service_observers())
observer->SendPayloadApplicationComplete(error_code);
}
void UpdateAttempterAndroid::SetStatusAndNotify(UpdateStatus status) {
status_ = status;
for (auto observer : daemon_state_->service_observers()) {
observer->SendStatusUpdate(
0, download_progress_, status_, "", install_plan_.payload_size);
}
last_notify_time_ = TimeTicks::Now();
}

这两个函数分别在Update结束和状态更新时对service_observers集合的成员逐个调用SendPayloadApplicationCompleteSendStatusUpdate,目的是向外界发送通知状态更新。

3. Update Engine的回调通知是如何实现的?

前面的第2.4节说道,对daemon_state_service_observers集合成员逐个调用SendPayloadApplicationCompleteSendStatusUpdate,外接就能接收到通知。这是如何实现的呢?

让我们先回到service_observers所属的类BinderUpdateEngineAndroidService中代码实现:

void BinderUpdateEngineAndroidService::SendStatusUpdate(
int64_t /* last_checked_time */,
double progress,
update_engine::UpdateStatus status,
const std::string& /* new_version */,
int64_t /* new_size */) {
last_status_ = static_cast(status);
last_progress_ = progress;
for (auto& callback : callbacks_) {
callback->onStatusUpdate(last_status_, last_progress_);
}
}
void BinderUpdateEngineAndroidService::SendPayloadApplicationComplete(
ErrorCode error_code) {
for (auto& callback : callbacks_) {
callback->onPayloadApplicationComplete(static_cast(error_code));
}
}

这里的两个方法SendStatusUpdateSendPayloadApplicationComplete,实际上是调用callbacks_onStatusUpdateonPayloadApplicationComplete

callbacks_IUpdateEngineCallback的集合,是在bind操作是作为参数传入的:

Status BinderUpdateEngineAndroidService::bind(
const android::sp& callback, bool* return_value) {
// 将传入的参数callback保存到callbacks_中
callbacks_.emplace_back(callback);
auto binder_wrapper = android::BinderWrapper::Get();
binder_wrapper->RegisterForDeathNotifications(
IUpdateEngineCallback::asBinder(callback),
base::Bind(&BinderUpdateEngineAndroidService::UnbindCallback,
base::Unretained(this),
base::Unretained(callback.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.
if (last_status_ != -1)
callback->onStatusUpdate(last_status_, last_progress_);
*return_value = true;
return Status::ok();
}

代码扯得有点远了,云里雾里的,我们以Android自带的demo应用update_engine_client_android看看到底是怎么回事。

在文件update_engine_client_android.cc中,以BnUpdateEngineCallback为基类定义了一个UECallback类,这个类只有两个函数onStatusUpdateonPayloadApplicationComplete

class UECallback : public android::os::BnUpdateEngineCallback {
public:
explicit UECallback(UpdateEngineClientAndroid* client) : client_(client) {}
// android::os::BnUpdateEngineCallback overrides.
Status onStatusUpdate(int status_code, float progress) override;
Status onPayloadApplicationComplete(int error_code) override;
private:
UpdateEngineClientAndroid* client_;
};

函数的详细实现如下:

Status UpdateEngineClientAndroid::UECallback::onStatusUpdate(
int status_code, float progress) {
update_engine::UpdateStatus status =
static_cast(status_code);
LOG(INFO) <<"onStatusUpdate(" < < return Status::ok();
}
Status UpdateEngineClientAndroid::UECallback::onPayloadApplicationComplete(
int error_code) {
ErrorCode code = static_cast(error_code);
LOG(INFO) <<"onPayloadApplicationComplete(" < <<" (" < client_->ExitWhenIdle(code == ErrorCode::kSuccess ? EX_OK : 1);
return Status::ok();
}

这两个函数本身比较简单,通过打印的方式输出状态信息。

然后在OnInit()函数的bind操作时生成回调对象callback_并向服务端注册进行注册,如下:

int UpdateEngineClientAndroid::OnInit() {
...
android::status_t status = android::getService(
android::String16("android.os.UpdateEngineService"), &service_);
if (status != android::OK) {
LOG(ERROR) <<"Failed to get IUpdateEngine binder from service manager: "
< return ExitWhenIdle(1);
}
...
if (FLAGS_follow) {
// 创建包含onStatusUpdate和onPayloadApplicationComplete实现的回调对象callback_
// Register a callback object with the service.
callback_ = new UECallback(this);
bool bound;
// 调用bind,向"android.os.UpdateEngineService"服务注册回调对象callback_
if (!service_->bind(callback_, &bound).isOk() || !bound) {
LOG(ERROR) <<"Failed to bind() the UpdateEngine daemon.";
return 1;
}
keep_running = true;
}
...
return EX_OK;
}

在执行bind操作时,服务端函数BinderUpdateEngineAndroidService::bind(...)会接收到传入的callback_,并被保存在binder_service_callbacks_中。相应地,服务端binder_service_对象中的callbacks_就是这里客户端定义的回调函数类对应的模板对象。

所以服务端callback->onStatusUpdatecallback->onPayloadApplicationComplete分别是客户端实现的UECallback::onStatusUpdateUECallback::onPayloadApplicationComplete函数。

4. 总结

总结一下:

服务端进程(代码main.cc)在main函数中先解析命令行参数并进行简单初始化,随后创建update_engine_daemon对象,并调用对象的Run()方法进入服务等待状态。

Run()中进入主循环前,通过OnInit()初始化生成两个业务对象binder_service_daemon_state_,前者负责binder服务对外的工作,后者则负责后台的实际业务。

binder_service_在客户端调用bind操作时会保存客户端注册的回调函数,从而在适当的时候通过回调函数告知客户端升级的状态信息;同时binder_service_接收到客户端的服务请求后,将其交给daemon_state_的成员update_attempter_去完成,所以update_attempter_才是Update Engine服务端业务的核心。

可以看到,目前基本上所有调用最后都会转到update_attempter_中,代码分析都在涉及到update_attempter_的操作时停止。所以update_attempter_是Update Engine服务端的核心对象,代码比较复杂,我们另外开篇分析。

5. 联系和福利

  • 个人微信公众号“洛奇看世界”,一个大龄码农的救赎之路。

    • 公众号回复关键词“Android电子书”,获取超过150本Android相关的电子书和文档。电子书包含了Android开发相关的方方面面,从此你再也不需要到处找Android开发的电子书了。
    • 公众号回复关键词“个人微信”,获取个人微信联系方式。我组建了一个Android OTA的讨论组,联系我,说明Android OTA,拉你进组一起讨论。

    《Android Update Engine分析(四)服务端进程》


推荐阅读
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • 本课程详细解析了Spring AOP的核心概念及其增强机制,涵盖前置增强、后置增强和环绕增强等类型。通过具体示例,深入探讨了如何在实际开发中有效运用这些增强技术,以提升代码的模块化和可维护性。此外,还介绍了Spring AOP在异常处理和性能监控等场景中的应用,帮助开发者更好地理解和掌握这一强大工具。 ... [详细]
  • 在启用分层编译的情况下,即时编译器(JIT)的触发条件涉及多个因素,包括方法调用频率、代码复杂度和运行时性能数据。本文将详细解析这些条件,并探讨分层编译如何优化JVM的执行效率。 ... [详细]
  • 本文深入探讨了RecyclerView的缓存与视图复用机制,详细解析了不同类型的缓存及其功能。首先,介绍了屏幕内ViewHolder的Scrap缓存,这是一种最轻量级的缓存方式,旨在提高滚动性能并减少不必要的视图创建。通过分析其设计原理,揭示了Scrap缓存为何能有效提升用户体验。此外,还讨论了其他类型的缓存机制,如RecycledViewPool和ViewCacheExtension,进一步优化了视图复用效率。 ... [详细]
  • C++设计模式精华:高效学习与速记指南
    本书《C++设计模式精华:高效学习与速记指南》旨在帮助读者快速掌握C++设计模式的核心概念和应用技巧。书中详细介绍了继承这一重要机制,解释了派生类如何继承基类的属性和方法,并探讨了派生类对象如何存储和使用基类的数据成员。通过实例和代码示例,读者可以更好地理解继承在实际开发中的应用,从而提升编程效率和代码质量。 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • 本文深入探讨了 MXOTDLL.dll 在 C# 环境中的应用与优化策略。针对近期公司从某生物技术供应商采购的指纹识别设备,该设备提供的 DLL 文件是用 C 语言编写的。为了更好地集成到现有的 C# 系统中,我们对原生的 C 语言 DLL 进行了封装,并利用 C# 的互操作性功能实现了高效调用。此外,文章还详细分析了在实际应用中可能遇到的性能瓶颈,并提出了一系列优化措施,以确保系统的稳定性和高效运行。 ... [详细]
  • 本题库精选了Java核心知识点的练习题,旨在帮助学习者巩固和检验对Java理论基础的掌握。其中,选择题部分涵盖了访问控制权限等关键概念,例如,Java语言中仅允许子类或同一包内的类访问的访问权限为protected。此外,题库还包括其他重要知识点,如异常处理、多线程、集合框架等,全面覆盖Java编程的核心内容。 ... [详细]
  • 本文介绍了一种基于最大匹配算法的简易分词程序的设计与实现。该程序通过引入哈希集合存储词典,利用前向最大匹配方法对输入文本进行高效分词处理,具有较高的准确率和较快的处理速度,适用于中文文本的快速分词需求。 ... [详细]
  • BZOJ1034 详细解析与算法优化
    本文深入解析了BZOJ1034问题,并提出了优化算法。通过借鉴广义田忌赛马的贪心策略,当己方当前最弱的马优于对方最弱的马时进行匹配;同样地,若己方当前最强的马优于对方最强的马,也进行匹配。此方法在保证胜率的同时,有效提升了算法效率。 ... [详细]
  • 探讨 `org.openide.windows.TopComponent.componentOpened()` 方法的应用及其代码实例分析 ... [详细]
  • MongoDB Aggregates.group() 方法详解与编程实例 ... [详细]
  • 本文深入探讨了Spring Cloud Eureka在企业级应用中的高级使用场景及优化策略。首先,介绍了Eureka的安全配置,确保服务注册与发现过程的安全性。接着,分析了Eureka的健康检查机制,提高系统的稳定性和可靠性。随后,详细讨论了Eureka的各项参数调优技巧,以提升性能和响应速度。最后,阐述了如何实现Eureka的高可用性部署,保障服务的连续性和可用性。通过这些内容,开发者可以更好地理解和运用Eureka,提升微服务架构的整体效能。 ... [详细]
  • 如何使用 org.geomajas.configuration.FontStyleInfo.getColor() 方法及其代码示例详解 ... [详细]
  • 本文提供了 RabbitMQ 3.7 的快速上手指南,详细介绍了环境搭建、生产者和消费者的配置与使用。通过官方教程的指引,读者可以轻松完成初步测试和实践,快速掌握 RabbitMQ 的核心功能和基本操作。 ... [详细]
author-avatar
千__鱼姐姐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有