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. mac安装破解的Navicat

    原文:https://www.jianshu.com/p/f42785e55b6b 原始文档没操作成功,折腾了一下午,后来在如下地址看的简洁版的,突然发现一句重要的话,豁然开朗. 原文链接:https ...

  2. mybatics 与jpa

    mybatics,dao层接口,mapper: public interface UserMapper { @Select("SELECT * FROM T_ROLE WHERE ROLE_ ...

  3. vmware10.0.1安装redhat linux6.2每次启动vm崩溃问题解决!

    最近在学习linux技术,安装了一套redhat linux6.2的环境,里面有软件若干,wmare用的是10.0.1的,最近每次出现登陆界面,输入root登陆后,wm就报错vmui不可恢复错误MEM ...

  4. vgcreate语法

    vgcreate 用于创建LVM卷组 补充说明 vgcreate命令 用于创建LVM卷组.卷组(Volume Group)将多个物理卷组织成一个整体,屏蔽了底层物理卷细节.在卷组上创建逻辑卷时不用考虑 ...

  5. anaconda3下64位python和32位python共存

    查看当前工作平台:conda info 切换64位和32位: set CONDA_FORCE_32BIT=1是切换到32位 set CONDA_FORCE_32BIT= 是切换到64位 注意=号前后不 ...

  6. vue项目中如何使用less

    首先你的vue-cli下载完成 第一步   安装less-loader  依赖 npm  install  less less-loader  --save-dev 直接自动就配置上了,不用手动配置 ...

  7. 深度学习(pytorch)-1.基于简单神经网络的图片自动分类

    这是pytorch官方的一个例子 官方教程地址:http://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-b ...

  8. centOS6.0虚拟机ip配置

    1.首先使用虚拟机安装好centOS6.0系统 2.虚拟机网络配置:(选择桥接模式) 3. 第一步:首先关闭防火墙 1.将防火服务从启动列表移除 #chkconfig --del iptables # ...

  9. JS里浮点数的运算

    //浮点数加法运算 function FloatAdd(arg1,arg2){ var r1,r2,m; try{r1=arg1.toString().split(".")[1]. ...

  10. sqlite当天时间的23:59:59

    select strftime('%Y-%m-%d %H:%M:%S','now','+1 day','localtime','start of day','-1 seconds')