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. flask 登录验证码 字母和数字

    captcha.py #!/usr/bin/env python# -*- coding: utf-8 -*- # refer to `https://bitbucket.org/akorn/whee ...

  2. zookeeper 启动 zookeeper_server.pid: Permission denied

    在启动zookeeper的时候 报错 没有权限 以为是 zookeeper 没有权限 然后 chmod -R 777 zookeeper/ 之后还是不行. 后来 才发现 原来是我 /tmp/zooke ...

  3. 安装Python mysqlclient出现“OSError: mysql_config not found”错误

    问题:               使用Python3开发一个管理平台,用MySQL数据库存放元数据.使用pip安装mysqlclient模块时出现“OSError: mysql_config not ...

  4. java版数据结构与算法第二章数组

    数组由一组具有相同类型的数据元素组成,并存储在一组连续存储单元中.一维数组是常量. 二维数组:若一维数组中的数据元素又是一堆数据结构,我们称之为二维数组.二维数组可以看成是n个列向量组成的线性表. 数 ...

  5. loadrunner11浏览器兼容性的问题

    最近项目中遇到了新开发的系统,全是HTML5和一些最新的前端框架技术,由于没有做浏览器兼容处理,所以该系统无法在IE浏览器进行操作,对firefox和google浏览器支持较好.但是又一个问题出现了, ...

  6. freeswitch配置功能二

    <?xml version="1.0" encoding="utf-8"?><include>        <context n ...

  7. Docker 部署应用过程记录

    Kibana直接部署到centos中,老是没有任何征兆退出,今天将他移动到docker中部署,以下是部署的过程,做个记录防止忘记 1.安装Docker # yum install docker 2.启 ...

  8. pyCharm django 中新加app

    1.在manage.py@djangotest中输入命令: 1.startapp   realnameauth   ---新建一个app,名字为realnameauth 2.在 django 项目中的 ...

  9. Altium Designer 10 使用技巧

    一.封装文件.PCB文件编辑时的吸附(Snap)的灵敏度. 像焊盘中心.过孔中心.线段的端点.走线的端点.铺铜的顶点,这样的点有吸附光标的特性,鼠标移动到这些点的附近会被吸附到上面.Snap的灵敏度可 ...

  10. 数字特征值-python

    #Digital eigenvalue.py number = eval(input()) count = 0 Ob = 0 Ox = 0 while number > 0: Ob = numb ...