update_engine简介

update_engine是A/B升级的核心逻辑。理解了update_engine就理解了在Android系统中A/B升级是如何运行的。它的代码放在源码目录下system/update_engine/下。那么接下来对update_engine进行分析,首先会分析它的结构,之后分析它的核心操作。

update_engine结构分析

Android.mk分析

一个源码工程中包含的源文件会有很多,但是不代表所有的文件都和我们的目标相关。而通过Android.mk文件可以找到和分析目标update_engine相关的源文件。我们只需要关注这些文件便可。Android.mk中直接和update_engine相关的内容

 include $(CLEAR_VARS)
LOCAL_MODULE := update_engine
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_REQUIRED_MODULES := \
cacerts_google
LOCAL_CPP_EXTENSION := .cc
LOCAL_CLANG := true
LOCAL_CFLAGS := $(ue_common_cflags)
LOCAL_CPPFLAGS := $(ue_common_cppflags)
LOCAL_LDFLAGS := $(ue_common_ldflags)
LOCAL_C_INCLUDES := \
$(ue_common_c_includes)
LOCAL_SHARED_LIBRARIES := \
$(ue_common_shared_libraries)
LOCAL_STATIC_LIBRARIES := \
$(ue_common_static_libraries)
LOCAL_SRC_FILES := \
main.cc ifeq ($(local_use_omaha),)
LOCAL_C_INCLUDES += \
$(ue_libupdate_engine_exported_c_includes)
LOCAL_STATIC_LIBRARIES += \
libupdate_engine \
$(ue_libupdate_engine_exported_static_libraries:-host=)
LOCAL_SHARED_LIBRARIES += \
$(ue_libupdate_engine_exported_shared_libraries:-host=)
else # local_use_omaha ==
LOCAL_STATIC_LIBRARIES += \
libupdate_engine_android \
$(ue_libupdate_engine_android_exported_static_libraries:-host=)
LOCAL_SHARED_LIBRARIES += \
$(ue_libupdate_engine_android_exported_shared_libraries:-host=)
endif # local_use_omaha == LOCAL_INIT_RC := update_engine.rc
include $(BUILD_EXECUTABLE)

从中首先可以获取到的信息就是该模块是个可执行的模块,并且入口函数在main.cc中。接下来再看它一定依赖的文件。

 ue_common_c_includes := \                    #依赖的c文件
$(LOCAL_PATH)/client_library/include \
system ue_common_shared_libraries := \ #依赖的动态库
libbrillo-stream \
libbrillo \ #在源码下的external中
libchrome #在源码下的external中 ue_common_static_libraries := \ #依赖的静态库
libgtest_prod \

由于local_use_omaha := $(if $(filter true,$(PRODUCT_IOT)),1,0) 意思为该设备是否是IOT设备,如果是则值为1否则为0,在这里我们分析的状况是非IOT设备。所以local_use_omaha := 0。所以该模块还依赖如下

 LOCAL_STATIC_LIBRARIES += \                                                      #静态依赖
libupdate_engine_android \
$(ue_libupdate_engine_android_exported_static_libraries:-host=)
-------------------------------------------------------------------------
ue_libupdate_engine_android_exported_static_libraries := \
libpayload_consumer \
libfs_mgr \
libbase \
liblog \
$(ue_libpayload_consumer_exported_static_libraries) \
libupdate_engine_boot_control \
$(ue_libupdate_engine_boot_control_exported_static_libraries)
ue_libupdate_engine_android_exported_shared_libraries := \
$(ue_libpayload_consumer_exported_shared_libraries) \
$(ue_libupdate_engine_boot_control_exported_shared_libraries) \
libandroid_net \
libbinder \
libbinderwrapper \
libbrillo-binder \
libcutils \
libcurl \
libssl \
libutils LOCAL_SHARED_LIBRARIES += \ #动态依赖
$(ue_libupdate_engine_android_exported_shared_libraries:-host=)
-------------------------------------------------------------------------
ue_libupdate_engine_android_exported_shared_libraries := \
$(ue_libpayload_consumer_exported_shared_libraries) \
$(ue_libupdate_engine_boot_control_exported_shared_libraries) \
libandroid_net \
libbinder \
libbinderwrapper \
libbrillo-binder \
libcutils \
libcurl \
libssl \
libutils

可以看到其中还有很多依赖的源文件是以变量赋值的形式出现的。这里就不一一列出了,但是方法已经知道了,那就是当遇到一个方法存在于两个文件中时就可以通过Android.mk来确定我们所需要的文件。

从main.cc开始分析

src/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(, ) == ) << "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 "
<< exit_code;
return exit_code;
}

可以看到首先进行了初始化工作,这些初始化并不影响对程序主干的分析,所以可以暂时略过。直接看最重要的UpdateEngineDaemon以及其Run()方法。UpdateEngineDaemon继承了brillo::Daemon,UpdateEngineDaemon的内容为

src/system/update_engine/daemon.h

 namespace chromeos_update_engine {

 class UpdateEngineDaemon : public brillo::Daemon {
public:
UpdateEngineDaemon() = default; protected:
int OnInit() override; private:
#if USE_DBUS
// Run from the main loop when the |dbus_adaptor_| object is registered. At
// this point we can request ownership of the DBus service name and continue
// initialization.
void OnDBusRegistered(bool succeeded); // Main D-Bus service adaptor.
std::unique_ptr<UpdateEngineAdaptor> dbus_adaptor_;
#endif // USE_DBUS // The Subprocess singleton class requires a brillo::MessageLoop in the
// current thread, so we need to initialize it from this class instead of
// the main() function.
Subprocess subprocess_; #if USE_BINDER
brillo::BinderWatcher binder_watcher_;
#endif // USE_BINDER #if USE_BINDER
#if USE_OMAHA
android::sp<BinderUpdateEngineBrilloService> binder_service_;
#else // !USE_OMAHA
android::sp<BinderUpdateEngineAndroidService> binder_service_;
#endif // USE_OMAHA
#endif // USE_BINDER // The daemon state with all the required daemon classes for the configured
// platform.
std::unique_ptr<DaemonStateInterface> daemon_state_; DISALLOW_COPY_AND_ASSIGN(UpdateEngineDaemon);
}; } // namespace chromeos_update_engine #endif // UPDATE_ENGINE_DAEMON_H_

从中可以看到它并没有对Run()进行重写,所以必须要看看daemon类的内容了:

src/external/librillo/brillo/daemons/daemon.cc

 namespace brillo {
........
int Daemon::Run() {
int exit_code = OnInit(); //会调用子类的OnInit()方法
if (exit_code != EX_OK)
return exit_code; message_loop_.Run(); OnShutdown(&exit_code_); // 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 (message_loop_.RunOnce(false /* may_block */)) {} return exit_code_;
} int Daemon::OnInit() {
async_signal_handler_.Init();
for (int signal : {SIGTERM, SIGINT}) {
async_signal_handler_.RegisterHandler(
signal, base::Bind(&Daemon::Shutdown, base::Unretained(this)));
}
async_signal_handler_.RegisterHandler(
SIGHUP, base::Bind(&Daemon::Restart, base::Unretained(this)));
return EX_OK;
}
........
}

可以看到在Run()方法中主要就是调用了OnInit()方法,子类一旦对其进行了重写那么就会调用子类的OnInit()方法.UpdateEngineDaemon的Oninit()方法体如下:

src/system/update_engine/daemon.cc

 namespace chromeos_update_engine {

 int UpdateEngineDaemon::OnInit() {
// Register the |subprocess_| singleton with this Daemon as the signal
// handler.
subprocess_.Init(this); //初始化子进程,用来处理信号 int exit_code = Daemon::OnInit(); //调用父类的OnInit()方法
if (exit_code != EX_OK)
return exit_code; #if USE_BINDER //USE_BINDER=1
android::BinderWrapper::Create(); //创建BinderWrapper
binder_watcher_.Init();
#endif // USE_BINDER #if USE_OMAHA //USE_OMAHA=0
// 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();
daemon_state_.reset(real_system_state);
LOG_IF(ERROR, !real_system_state->Initialize())
<< "Failed to initialize system state.";
#else // !USE_OMAHA
DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
daemon_state_.reset(daemon_state_android);
LOG_IF(ERROR, !daemon_state_android->Initialize())
<< "Failed to initialize system state.";
#endif // USE_OMAHA #if USE_BINDER
// Create the Binder Service.
#if USE_OMAHA
binder_service_ = new BinderUpdateEngineBrilloService{real_system_state};
#else // !USE_OMAHA
binder_service_ = new BinderUpdateEngineAndroidService{
daemon_state_android->service_delegate()}; //创建binder_service
#endif // USE_OMAHA
auto binder_wrapper = android::BinderWrapper::Get();
if (!binder_wrapper->RegisterService(binder_service_->ServiceName(), //向ServiceManager注册binder_service
binder_service_)) {
LOG(ERROR) << "Failed to register binder service.";
} daemon_state_->AddObserver(binder_service_.get()); //将binder_service添加到观察者队列中
#endif // USE_BINDER #if USE_DBUS //USE_DBUS=0
// Create the DBus service.
dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state));
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
daemon_state_->StartUpdater(); //开始服务的核心流程
#endif // USE_DBUS
return EX_OK;
}

在Oninit()中其实主要就是做了两件事,首先是对Binder进行了初始化,包括创建,注册,添加到观察者队列中。其次就是创建了DaemonStateAndroid,并将其赋给daemon_state_,最后调用daemon_state_->StartUpdater()。

update_engine-整体结构(一)的更多相关文章

  1. Abot 爬虫分析-整体结构

    1. 引言 在Github 上搜索下Web Crawler 有上千个开源的项目,但是C#的仅仅只有168 个,相比于Java 或者Python 确实少的可怜.如果按照Stars 排名.可以看到 排在第 ...

  2. html规范整体结构

    <!DOCTYPE html><html lang="zh"><head> <meta charset="utf-8" ...

  3. NFC规范学习之一 ---整体结构

    1.NFC 采用两个感应线圈进行数据交互,其中至少必须有一个设备产生13.56MHZ的磁场,该场被调制以方便数据传输.通讯中,一个设备处于initiator模式(就是发起通讯)另外一个设备则工作在ta ...

  4. LIRe 源代码分析 1:整体结构

    ===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...

  5. Media Player Classic - HC 源代码分析 1:整体结构

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  6. HTML(二)HTML元素(整体结构,块级元素,内联元素,结构元素,交互元素,元素嵌套规则)

    HTML整体结构解释 <!DOCTYPE html> // 文件应以"<!DOCTYPE ......>"首行顶格开始,推荐使用"<!DOC ...

  7. HTML 初识 HTML【 整体结构 文字 图片 表格 超链接】

    HTML        超文本标记语言,页面内可以包含图片.链接,甚至音乐.程序等非文字元素.       网页的本质就是超级文本标记语言,万维网是建立在超文本基础之上的.TML 通过标记符号来标记要 ...

  8. Android4.0 Launcher 源码分析1——Launcher整体结构

    1.Launcher整体结构 桌面程序其实并不包含桌面壁纸,桌面壁纸其实是由 WallpaperManagerService来提供,整个桌面其实是叠加在整个桌面壁纸上的另外一个层. 1.1 WorkS ...

  9. Hyperledger Fabric1.0 整体结构

    整体结构 Hyperledger Fabric 在 1.0 中,架构已经解耦为三部分: fabric-peer:主要起到 peer 作用,包括 endorser.committer 两种角色: fab ...

  10. Spring IOC源代码具体解释之整体结构

    Spring ICO具体解释之整体结构 IOC介绍 IOC, spring的核心.贯穿Spring始终.直观的来说.就是由spring来负责控制对象的生命周期和对象间的关系,将对象之间的关系抽象出来. ...

随机推荐

  1. 棋盘(noip2017普及组)

    题目描述 有一个m \times mm×m的棋盘,棋盘上每一个格子可能是红色.黄色或没有任何颜色的.你现在要从棋盘的最左上角走到棋盘的最右下角. 任何一个时刻,你所站在的位置必须是有颜色的(不能是无色 ...

  2. 从零搭建Vue开发环境

    参考: 1.node安装和环境配置:https://www.cnblogs.com/zhouyu2017/p/6485265.html: 2.babel的安装:https://www.cnblogs. ...

  3. ORM-Model操作

    django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM). django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成 ...

  4. Python基础学习---位运算符

    <<   左移,每移动1位,相当于乘以2      例如:32<<2    等价于:32*4 ==128 >>   右移,每移动1位,相当于除以2      例如: ...

  5. .net实现扫描二维码登录webqq群抓取qq群信息

    一.流程 1. //获得二维码的qrsig,cookie标志 2. //登录二维码获得二维码的状态,及最新的url 3. //登录此网址,获得Cookies 4.//cookies,筛选出skey信息 ...

  6. 编译原理子cygwin的使用

    目的:熟悉cygwin环境的使用,学习使用lex写简单的词法分析程序,会在cygwin环境下使用flex调试lex写的程序 内容:使用cygwin下的flex工具将exam1.l和exam2.l编译并 ...

  7. Python实现12306自动查票程序

    这是在网上扒拉过来的,原文链接: http://blog.csdn.net/An_Feng_z/article/details/78631290 目前时间2018/01/04 文中各种接口均为可用,亲 ...

  8. 刷新浏览器 protractor

    //refresh browser.ignoreSynchronization = true; browser.refresh(); browser.sleep(3000); browser.swit ...

  9. Windows 下Redis的部署 及key 过期事件

    window下Redis部署,下载安装完成之后,进入到redis目录: 1.修改配置文件redis.windows.service.conf配置密码 requirepass myRedis (注意在R ...

  10. HD ACM 水题顺序

    原文传送门:http://acm.hdu.edu.cn/ 第一阶段:开始入门吧!(15天,53题) 一.输入输出练习(2天,10题) 1000.1089-1096.1001 二.简单操作:(2-4天, ...