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相关的内容
1 include $(CLEAR_VARS)
2 LOCAL_MODULE := update_engine
3 LOCAL_MODULE_CLASS := EXECUTABLES
4 LOCAL_REQUIRED_MODULES := \
5 cacerts_google
6 LOCAL_CPP_EXTENSION := .cc
7 LOCAL_CLANG := true
8 LOCAL_CFLAGS := $(ue_common_cflags)
9 LOCAL_CPPFLAGS := $(ue_common_cppflags)
10 LOCAL_LDFLAGS := $(ue_common_ldflags)
11 LOCAL_C_INCLUDES := \
12 $(ue_common_c_includes)
13 LOCAL_SHARED_LIBRARIES := \
14 $(ue_common_shared_libraries)
15 LOCAL_STATIC_LIBRARIES := \
16 $(ue_common_static_libraries)
17 LOCAL_SRC_FILES := \
18 main.cc
19
20 ifeq ($(local_use_omaha),1)
21 LOCAL_C_INCLUDES += \
22 $(ue_libupdate_engine_exported_c_includes)
23 LOCAL_STATIC_LIBRARIES += \
24 libupdate_engine \
25 $(ue_libupdate_engine_exported_static_libraries:-host=)
26 LOCAL_SHARED_LIBRARIES += \
27 $(ue_libupdate_engine_exported_shared_libraries:-host=)
28 else # local_use_omaha == 1
29 LOCAL_STATIC_LIBRARIES += \
30 libupdate_engine_android \
31 $(ue_libupdate_engine_android_exported_static_libraries:-host=)
32 LOCAL_SHARED_LIBRARIES += \
33 $(ue_libupdate_engine_android_exported_shared_libraries:-host=)
34 endif # local_use_omaha == 1
35
36 LOCAL_INIT_RC := update_engine.rc
37 include $(BUILD_EXECUTABLE)
从中首先可以获取到的信息就是该模块是个可执行的模块,并且入口函数在main.cc中。接下来再看它一定依赖的文件。
1 ue_common_c_includes := \ #依赖的c文件
2 $(LOCAL_PATH)/client_library/include \
3 system
4
5 ue_common_shared_libraries := \ #依赖的动态库
6 libbrillo-stream \
7 libbrillo \ #在源码下的external中
8 libchrome #在源码下的external中
9
10 ue_common_static_libraries := \ #依赖的静态库
11 libgtest_prod \
由于local_use_omaha := $(if $(filter true,$(PRODUCT_IOT)),1,0) 意思为该设备是否是IOT设备,如果是则值为1否则为0,在这里我们分析的状况是非IOT设备。所以local_use_omaha := 0。所以该模块还依赖如下
1 LOCAL_STATIC_LIBRARIES += \ #静态依赖
2 libupdate_engine_android \
3 $(ue_libupdate_engine_android_exported_static_libraries:-host=)
4 -------------------------------------------------------------------------
5 ue_libupdate_engine_android_exported_static_libraries := \
6 libpayload_consumer \
7 libfs_mgr \
8 libbase \
9 liblog \
10 $(ue_libpayload_consumer_exported_static_libraries) \
11 libupdate_engine_boot_control \
12 $(ue_libupdate_engine_boot_control_exported_static_libraries)
13 ue_libupdate_engine_android_exported_shared_libraries := \
14 $(ue_libpayload_consumer_exported_shared_libraries) \
15 $(ue_libupdate_engine_boot_control_exported_shared_libraries) \
16 libandroid_net \
17 libbinder \
18 libbinderwrapper \
19 libbrillo-binder \
20 libcutils \
21 libcurl \
22 libssl \
23 libutils
24
25 LOCAL_SHARED_LIBRARIES += \ #动态依赖
26 $(ue_libupdate_engine_android_exported_shared_libraries:-host=)
27 -------------------------------------------------------------------------
28 ue_libupdate_engine_android_exported_shared_libraries := \
29 $(ue_libpayload_consumer_exported_shared_libraries) \
30 $(ue_libupdate_engine_boot_control_exported_shared_libraries) \
31 libandroid_net \
32 libbinder \
33 libbinderwrapper \
34 libbrillo-binder \
35 libcutils \
36 libcurl \
37 libssl \
38 libutils
可以看到其中还有很多依赖的源文件是以变量赋值的形式出现的。这里就不一一列出了,但是方法已经知道了,那就是当遇到一个方法存在于两个文件中时就可以通过Android.mk来确定我们所需要的文件。
从main.cc开始分析
src/system/update_engine/main.cc
1 int main(int argc, char** argv) {
2 DEFINE_bool(logtostderr, false,
3 "Write logs to stderr instead of to a file in log_dir.");
4 DEFINE_bool(foreground, false,
5 "Don't daemon()ize; run in foreground.");
6
7 chromeos_update_engine::Terminator::Init();
8 brillo::FlagHelper::Init(argc, argv, "Chromium OS Update Engine");
9 chromeos_update_engine::SetupLogging(FLAGS_logtostderr);
10 if (!FLAGS_foreground)
11 PLOG_IF(FATAL, daemon(0, 0) == 1) << "daemon() failed";
12
13 LOG(INFO) << "Chrome OS Update Engine starting";
14
15 // xz-embedded requires to initialize its CRC-32 table once on startup.
16 xz_crc32_init();
17
18 // Ensure that all written files have safe permissions.
19 // This is a mask, so we _block_ all permissions for the group owner and other
20 // users but allow all permissions for the user owner. We allow execution
21 // for the owner so we can create directories.
22 // Done _after_ log file creation.
23 umask(S_IRWXG | S_IRWXO);
24
25 chromeos_update_engine::UpdateEngineDaemon update_engine_daemon;
26 int exit_code = update_engine_daemon.Run();
27
28 LOG(INFO) << "Chrome OS Update Engine terminating with exit code "
29 << exit_code;
30 return exit_code;
31 }
可以看到首先进行了初始化工作,这些初始化并不影响对程序主干的分析,所以可以暂时略过。直接看最重要的UpdateEngineDaemon以及其Run()方法。UpdateEngineDaemon继承了brillo::Daemon,UpdateEngineDaemon的内容为
src/system/update_engine/daemon.h
1 namespace chromeos_update_engine {
2
3 class UpdateEngineDaemon : public brillo::Daemon {
4 public:
5 UpdateEngineDaemon() = default;
6
7 protected:
8 int OnInit() override;
9
10 private:
11 #if USE_DBUS
12 // Run from the main loop when the |dbus_adaptor_| object is registered. At
13 // this point we can request ownership of the DBus service name and continue
14 // initialization.
15 void OnDBusRegistered(bool succeeded);
16
17 // Main D-Bus service adaptor.
18 std::unique_ptr<UpdateEngineAdaptor> dbus_adaptor_;
19 #endif // USE_DBUS
20
21 // The Subprocess singleton class requires a brillo::MessageLoop in the
22 // current thread, so we need to initialize it from this class instead of
23 // the main() function.
24 Subprocess subprocess_;
25
26 #if USE_BINDER
27 brillo::BinderWatcher binder_watcher_;
28 #endif // USE_BINDER
29
30 #if USE_BINDER
31 #if USE_OMAHA
32 android::sp<BinderUpdateEngineBrilloService> binder_service_;
33 #else // !USE_OMAHA
34 android::sp<BinderUpdateEngineAndroidService> binder_service_;
35 #endif // USE_OMAHA
36 #endif // USE_BINDER
37
38 // The daemon state with all the required daemon classes for the configured
39 // platform.
40 std::unique_ptr<DaemonStateInterface> daemon_state_;
41
42 DISALLOW_COPY_AND_ASSIGN(UpdateEngineDaemon);
43 };
44
45 } // namespace chromeos_update_engine
46
47 #endif // UPDATE_ENGINE_DAEMON_H_
从中可以看到它并没有对Run()进行重写,所以必须要看看daemon类的内容了:
src/external/librillo/brillo/daemons/daemon.cc
1 namespace brillo {
2 ........
3 int Daemon::Run() {
4 int exit_code = OnInit(); //会调用子类的OnInit()方法
5 if (exit_code != EX_OK)
6 return exit_code;
7
8 message_loop_.Run();
9
10 OnShutdown(&exit_code_);
11
12 // base::RunLoop::QuitClosure() causes the message loop to quit
13 // immediately, even if pending tasks are still queued.
14 // Run a secondary loop to make sure all those are processed.
15 // This becomes important when working with D-Bus since dbus::Bus does
16 // a bunch of clean-up tasks asynchronously when shutting down.
17 while (message_loop_.RunOnce(false /* may_block */)) {}
18
19 return exit_code_;
20 }
21
22 int Daemon::OnInit() {
23 async_signal_handler_.Init();
24 for (int signal : {SIGTERM, SIGINT}) {
25 async_signal_handler_.RegisterHandler(
26 signal, base::Bind(&Daemon::Shutdown, base::Unretained(this)));
27 }
28 async_signal_handler_.RegisterHandler(
29 SIGHUP, base::Bind(&Daemon::Restart, base::Unretained(this)));
30 return EX_OK;
31 }
32 ........
33 }
可以看到在Run()方法中主要就是调用了OnInit()方法,子类一旦对其进行了重写那么就会调用子类的OnInit()方法.UpdateEngineDaemon的Oninit()方法体如下:
src/system/update_engine/daemon.cc
1 namespace chromeos_update_engine {
2
3 int UpdateEngineDaemon::OnInit() {
4 // Register the |subprocess_| singleton with this Daemon as the signal
5 // handler.
6 subprocess_.Init(this); //初始化子进程,用来处理信号
7
8 int exit_code = Daemon::OnInit(); //调用父类的OnInit()方法
9 if (exit_code != EX_OK)
10 return exit_code;
11
12 #if USE_BINDER //USE_BINDER=1
13 android::BinderWrapper::Create(); //创建BinderWrapper
14 binder_watcher_.Init();
15 #endif // USE_BINDER
16
17 #if USE_OMAHA //USE_OMAHA=0
18 // Initialize update engine global state but continue if something fails.
19 // TODO(deymo): Move the daemon_state_ initialization to a factory method
20 // avoiding the explicit re-usage of the |bus| instance, shared between
21 // D-Bus service and D-Bus client calls.
22 RealSystemState* real_system_state = new RealSystemState();
23 daemon_state_.reset(real_system_state);
24 LOG_IF(ERROR, !real_system_state->Initialize())
25 << "Failed to initialize system state.";
26 #else // !USE_OMAHA
27 DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
28 daemon_state_.reset(daemon_state_android);
29 LOG_IF(ERROR, !daemon_state_android->Initialize())
30 << "Failed to initialize system state.";
31 #endif // USE_OMAHA
32
33 #if USE_BINDER
34 // Create the Binder Service.
35 #if USE_OMAHA
36 binder_service_ = new BinderUpdateEngineBrilloService{real_system_state};
37 #else // !USE_OMAHA
38 binder_service_ = new BinderUpdateEngineAndroidService{
39 daemon_state_android->service_delegate()}; //创建binder_service
40 #endif // USE_OMAHA
41 auto binder_wrapper = android::BinderWrapper::Get();
42 if (!binder_wrapper->RegisterService(binder_service_->ServiceName(), //向ServiceManager注册binder_service
43 binder_service_)) {
44 LOG(ERROR) << "Failed to register binder service.";
45 }
46
47 daemon_state_->AddObserver(binder_service_.get()); //将binder_service添加到观察者队列中
48 #endif // USE_BINDER
49
50 #if USE_DBUS //USE_DBUS=0
51 // Create the DBus service.
52 dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state));
53 daemon_state_->AddObserver(dbus_adaptor_.get());
54
55 dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
56 base::Unretained(this)));
57 LOG(INFO) << "Waiting for DBus object to be registered.";
58 #else // !USE_DBUS
59 daemon_state_->StartUpdater(); //开始服务的核心流程
60 #endif // USE_DBUS
61 return EX_OK;
62 }
在Oninit()中其实主要就是做了两件事,首先是对Binder进行了初始化,包括创建,注册,添加到观察者队列中。其次就是创建了DaemonStateAndroid,并将其赋给daemon_state_,最后调用daemon_state_->StartUpdater()。