概述:
ab升级方式区别于之前的文件升级file-to-file和块升级block-to-block,由于系统中同时存在两套boot和system分区,可以做到用户无感知升级,整个升级过程只需要一次正常重启,告别了recovery升级的耗时和危险性。
传统升级方式与ab升级方式是采用的设备分区如下:
ab升级方式中boot和system均保留了两份,所以对设备的存储容量要求会比传统升级方式要大的多。
典型应用场景如下,假定当前从slot B中启动
JAVA层调用相关:
涉及文件主要有:frameworks\base\core\java\android\os\UpdateEngine.java
frameworks\base\core\java\android\os\UpdateEngineCallback.java
frameworks\base\core\java\android\os\SystemUpdateManager.java
UpdateEngine是UpdateEngineService服务提供的jave层调用接口,包含了各个状态值,和错误码,错误码:
public static final class ErrorCodeConstants {
public static final int SUCCESS = 0;
public static final int ERROR = 1;
public static final int FILESYSTEM_COPIER_ERROR = 4;
public static final int POST_INSTALL_RUNNER_ERROR = 5;
public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
public static final int DOWNLOAD_TRANSFER_ERROR = 9;
public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
}
updateEngineService服务返回的状态值:
public static final class UpdateStatusConstants {
public static final int IDLE = 0;
public static final int CHECKING_FOR_UPDATE = 1;
public static final int UPDATE_AVAILABLE = 2;
public static final int DOWNLOADING = 3;
public static final int VERIFYING = 4;
public static final int FINALIZING = 5;
public static final int UPDATED_NEED_REBOOT = 6;
public static final int REPORTING_ERROR_EVENT = 7;
public static final int ATTEMPTING_ROLLBACK = 8;
public static final int DISABLED = 9;
}
主要方法如下:
接收服务返回的错误码已经当前运行的状态值给用户,方便客户端进程更新ui显示。
@SystemApi
public boolean bind(final UpdateEngineCallback callback, final Handler handler) {
synchronized (mUpdateEngineCallbackLock) {
mUpdateEngineCallback = new IUpdateEngineCallback.Stub() {
@Override
public void onStatusUpdate(final int status, final float percent) {
if (handler != null) {
handler.post(new Runnable() {
@Override
public void run() {
callback.onStatusUpdate(status, percent);
}
});
} else {
callback.onStatusUpdate(status, percent);
}
}
@Override
public void onPayloadApplicationComplete(final int errorCode) {
if (handler != null) {
handler.post(new Runnable() {
@Override
public void run() {
callback.onPayloadApplicationComplete(errorCode);
}
});
} else {
callback.onPayloadApplicationComplete(errorCode);
}
}
};
try {
return mUpdateEngine.bind(mUpdateEngineCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
开始升级:url可以试下载链接,或者本地文件,如果是本地文件,以file://格式表示
@SystemApi
public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs)
{
try {
mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
除此之外还有取消升级、暂停升级、恢复升级、重置状态、解除绑定,校验升级包。
NATIVE层相关:
来自谷歌官网有如下描述:
想要实现 A/B 系统更新的原始设备制造商 (OEM) 和 SoC 供应商必须确保其引导加载程序实现 boot_control HAL,并将正确的参数传递到内核。
支持 A/B 更新的引导加载程序必须在hardware/libhardware/include/hardware/boot_control.h 中实现 boot_control HAL。您可以使用 system/extras/bootctl 实用工具和 system/extras/tests/bootloader/ 来测试此类实现。
\hardware\libhardware\include\hardware\boot_control.h中定义了boot_control_module结构体:
typedef struct boot_control_module {
struct hw_module_t common;
/*
* (*init)() perform any initialization tasks needed for the HAL.
* This is called only once.
*/
void (*init)(struct boot_control_module *module);
/*
* (*getNumberSlots)() returns the number of available slots.
* For instance, a system with a single set of partitions would return
* 1, a system with A/B would return 2, A/B/C -> 3...
*/
unsigned (*getNumberSlots)(struct boot_control_module *module);
/*
* (*getCurrentSlot)() returns the value letting the system know
* whether the current slot is A or B. The meaning of A and B is
* left up to the implementer. It is assumed that if the current slot
* is A, then the block devices underlying B can be accessed directly
* without any risk of corruption.
* The returned value is always guaranteed to be strictly less than the
* value returned by getNumberSlots. Slots start at 0 and
* finish at getNumberSlots() - 1
*/
unsigned (*getCurrentSlot)(struct boot_control_module *module);
/*
* (*markBootSuccessful)() marks the current slot
* as having booted successfully
*
* Returns 0 on success, -errno on error.
*/
int (*markBootSuccessful)(struct boot_control_module *module);
/*
* (*setActiveBootSlot)() marks the slot passed in parameter as
* the active boot slot (see getCurrentSlot for an explanation
* of the "slot" parameter). This overrides any previous call to
* setSlotAsUnbootable.
* Returns 0 on success, -errno on error.
*/
int (*setActiveBootSlot)(struct boot_control_module *module, unsigned slot);
/*
* (*setSlotAsUnbootable)() marks the slot passed in parameter as
* an unbootable. This can be used while updating the contents of the slot's
* partitions, so that the system will not attempt to boot a known bad set up.
* Returns 0 on success, -errno on error.
*/
int (*setSlotAsUnbootable)(struct boot_control_module *module, unsigned slot);
/*
* (*isSlotBootable)() returns if the slot passed in parameter is
* bootable. Note that slots can be made unbootable by both the
* bootloader and by the OS using setSlotAsUnbootable.
* Returns 1 if the slot is bootable, 0 if it's not, and -errno on
* error.
*/
int (*isSlotBootable)(struct boot_control_module *module, unsigned slot);
/*
* (*getSuffix)() returns the string suffix used by partitions that
* correspond to the slot number passed in parameter. The returned string
* is expected to be statically allocated and not need to be freed.
* Returns NULL if slot does not match an existing slot.
*/
const char* (*getSuffix)(struct boot_control_module *module, unsigned slot);
/*
* (*isSlotMarkedSucessful)() returns if the slot passed in parameter has
* been marked as successful using markBootSuccessful.
* Returns 1 if the slot has been marked as successful, 0 if it's
* not the case, and -errno on error.
*/
int (*isSlotMarkedSuccessful)(struct boot_control_module *module, unsigned slot);
void* reserved[31];
} boot_control_module_t;
实现boot_control接口需要厂商自己实现用于读取和设置启动槽位信息,在system/updateEngine中有如下类:
\system\update_engine\boot_control_android.h
\system\update_engine\boot_control_recovery.h
#include
#include "update_engine/common/boot_control.h"
namespace chromeos_update_engine {
// The Android implementation of the BootControlInterface. This implementation
// uses the libhardware's boot_control HAL to access the bootloader.
class BootControlAndroid : public BootControlInterface {
public:
BootControlAndroid() = default;
~BootControlAndroid() = default;
// Load boot_control HAL implementation using libhardware and
// initializes it. Returns false if an error occurred.
bool Init();
// BootControlInterface overrides.
unsigned int GetNumSlots() const override;
BootControlInterface::Slot GetCurrentSlot() const override;
bool GetPartitionDevice(const std::string& partition_name,
BootControlInterface::Slot slot,
std::string* device) const override;
bool IsSlotBootable(BootControlInterface::Slot slot) const override;
bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
bool MarkBootSuccessfulAsync(base::Callback callback) override;
private:
::android::sp<::android::hardware::boot::V1_0::IBootControl> module_;
DISALLOW_COPY_AND_ASSIGN(BootControlAndroid);
};
} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_BOOT_CONTROL_ANDROID_H_
#include
#include
#include
#include "update_engine/common/boot_control.h"
namespace chromeos_update_engine {
// The Android recovery implementation of the BootControlInterface. This
// implementation uses the legacy libhardware's boot_control HAL to access the
// bootloader by linking against it statically. This should only be used in
// recovery.
class BootControlRecovery : public BootControlInterface {
public:
BootControlRecovery() = default;
~BootControlRecovery() = default;
// Load boot_control HAL implementation using libhardware and
// initializes it. Returns false if an error occurred.
bool Init();
// BootControlInterface overrides.
unsigned int GetNumSlots() const override;
BootControlInterface::Slot GetCurrentSlot() const override;
bool GetPartitionDevice(const std::string& partition_name,
BootControlInterface::Slot slot,
std::string* device) const override;
bool IsSlotBootable(BootControlInterface::Slot slot) const override;
bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
bool MarkBootSuccessfulAsync(base::Callback callback) override;
private:
// NOTE: There is no way to release/unload HAL implementations so
// this is essentially leaked on object destruction.
boot_control_module_t* module_;
DISALLOW_COPY_AND_ASSIGN(BootControlRecovery);
};
} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_BOOT_CONTROL_RECOVERY_H_
\system\update_engine\common\boot_control.h定义了获取得到boot_control接口实体的方法:
namespace chromeos_update_engine {
namespace boot_control {
// The real BootControlInterface is platform-specific. This factory function
// creates a new BootControlInterface instance for the current platform. If
// this fails nullptr is returned.
std::unique_ptr CreateBootControl();
} // namespace boot_control
} // namespace chromeos_update_engine
两个实现如下:
boot_control_android.cc
// Factory defined in boot_control.h.
std::unique_ptr CreateBootControl() {
std::unique_ptr boot_control(new BootControlAndroid());
if (!boot_control->Init()) {
return nullptr;
}
return std::move(boot_control);
}
boot_control_recovery.cc
// Factory defined in boot_control.h.
std::unique_ptr CreateBootControl() {
std::unique_ptr boot_control(new BootControlRecovery());
if (!boot_control->Init()) {
return nullptr;
}
return std::move(boot_control);
}
update_engine进程分析:
从system/update_engine根目录下的android.mk中
部分截取如下:
include $(CLEAR_VARS)
LOCAL_MODULE := update_engine
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := \
main.cc
ifeq ($(local_use_omaha),1)
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 == 1
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 == 1
可知:update_engine进程的入口是main.cc类,该进程有两个重要依赖库:libupdate_engine和libupdate_engine_android。
int main(int argc, char** argv) {
省略部分初始化日志设置
得到update_engine_daemon后调用其run方法
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;
}
chromeos_update_engine命名空间下的UpdateEngineDaemon类如下所示:
system\update_engine\daemon.h
namespace chromeos_update_engine {
class UpdateEngineDaemon : public brillo::Daemon {
brillo::Daemon如下:
\external\libbrillo\brillo\daemons\daemon.h
Daemon是一个简单的基础系统守护进程,提供了许多有用的功能,比如消息循环,信号处理,信号挂起等,您可以直接使用此类来实现您的守护程序,或者您可以通过创建自己的类并从brillo :: Daemon派生它来专门化它。 覆盖一些提供的虚拟方法,以微调其行为以满足您的守护程序的需要。
class BRILLO_EXPORT Daemon : public AsynchronousSignalHandlerInterface {
public:
Daemon();
virtual ~Daemon();
// Performs proper initialization of the daemon and runs the message loop.
// Blocks until the daemon is finished. The return value is the error
// code that should be returned from daemon's main(). Returns EX_OK (0) on
// success.
virtual int Run();
// Can be used by call-backs to trigger shut-down of a running message loop.
// Calls QuiteWithExitCode(EX_OK);
// WARNING: This method (as well as QuitWithExitCode) can only be called when
// the message loop is running (that is, during Daemon::Run() call). Calling
// these methods before (e.g. during OnInit()) or after (e.g in OnShutdown())
// will lead to abnormal process termination.
void Quit();
// |exit_code| is the status code to be returned when the daemon process
// quits. See the warning for Quit() above regarding the allowed scope for
// this method.
void QuitWithExitCode(int exit_code);
// AsynchronousSignalHandlerInterface overrides.
// Register/unregister custom signal handlers for the daemon. The semantics
// are identical to AsynchronousSignalHandler::RegisterHandler and
// AsynchronousSignalHandler::UnregisterHandler, except that handlers for
// SIGTERM, SIGINT, and SIGHUP cannot be modified.
void RegisterHandler(
int signal, const
AsynchronousSignalHandlerInterface::SignalHandler& callback) override;
void UnregisterHandler(int signal) override;
protected:
// Overload to provide your own initialization code that should happen just
// before running the message loop. Return EX_OK (0) on success or any other
// non-zero error codes. If an error is returned, the message loop execution
// is aborted and Daemon::Run() exits early.
// When overloading, make sure you call the base implementation of OnInit().
virtual int OnInit();
// Called when the message loops exits and before Daemon::Run() returns.
// Overload to clean up the data that was set up during OnInit().
// |return_code| contains the current error code that will be returned from
// Run(). You can override this value with your own error code if needed.
// When overloading, make sure you call the base implementation of
// OnShutdown().
virtual void OnShutdown(int* exit_code);
// Called when the SIGHUP signal is received. In response to this call, your
// daemon could reset/reload the configuration and re-initialize its state
// as if the process has been reloaded.
// Return true if the signal was processed successfully and the daemon
// reset its configuration. Returning false will force the daemon to
// quit (and subsequently relaunched by an upstart job, if one is configured).
// The default implementation just returns false (unhandled), which terminates
// the daemon, so do not call the base implementation of OnRestart() from
// your overload.
virtual bool OnRestart();
// Returns a delegate to Quit() method in the base::RunLoop instance.
base::Closure QuitClosure() const {
return message_loop_.QuitClosure();
}
private:
// Called when SIGTERM/SIGINT signals are received.
bool Shutdown(const signalfd_siginfo& info);
// Called when SIGHUP signal is received.
bool Restart(const signalfd_siginfo& info);
// |at_exit_manager_| must be first to make sure it is initialized before
// other members, especially the |message_loop_|.
base::AtExitManager at_exit_manager_;
// The brillo wrapper for the base message loop.
BaseMessageLoop message_loop_;
// A helper to dispatch signal handlers asynchronously, so that the main
// system signal handler returns as soon as possible.
AsynchronousSignalHandler async_signal_handler_;
// Process exit code specified in QuitWithExitCode() method call.
int exit_code_;
DISALLOW_COPY_AND_ASSIGN(Daemon);
};
} // namespace brillo
run方法如下:进入了循环消息读取中。
int Daemon::Run() {
int exit_code = 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_;
}
在run之前调用了OnInit,在子类\system\update_engine\daemon.cc中的OnInit中,主要操作有:
初始化全局update engine状态:
DaemonStateAndroid* daemon_state_android = new DaemonStateAndroid();
daemon_state_.reset(daemon_state_android);
生成bindservice
binder_service_ = new BinderUpdateEngineAndroidService{
daemon_state_android->service_delegate()};
将该binderservice加入到bind服务管理中
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();
\system\update_engine\daemon_state_interface.h如下:
namespace chromeos_update_engine {
class DaemonStateInterface {
public:
virtual ~DaemonStateInterface() = default;
// Start the daemon loop. Should be called only once to start the daemon's
// main functionality.
virtual bool StartUpdater() = 0;
// Add and remove an observer. All the registered observers will be called
// whenever there's a new status to update.
virtual void AddObserver(ServiceObserverInterface* observer) = 0;
virtual void RemoveObserver(ServiceObserverInterface* observer) = 0;
// Return the set of current observers.
virtual const std::set& service_observers() = 0;
protected:
DaemonStateInterface() = default;
};
} // namespace chromeos_update_engine
DaemonStateAndroid继承自DaemonStateInterface,部分定义如下,升级相关的主要操作都已经包含在内了。
bool StartUpdater() override;
ServiceDelegateAndroidInterface* service_delegate();
std::set service_observers_;
std::unique_ptr boot_control_;
std::unique_ptr hardware_;
std::unique_ptr prefs_;
std::unique_ptr update_attempter_;
OpenSSLWrapper openssl_wrapper_;
std::unique_ptr certificate_checker_;
\system\update_engine\update_attempter_android.h
UpdateAttempterAndroid类包含了升级相关的所有方法,升级操作最终通过UpdateAttempterAndroid该类来实现。
java层调用updateEngine的apply后,通过binder调用到BinderUpdateEngineAndroidService类的apply中,升级的具体开始没有在该方法中实现,而是调用了ServiceDelegateAndroidInterface的ApplyPayload方法,UpdateAttempterAndroid继承自ServiceDelegateAndroidInterface,所以最终升级是在\system\update_engine\update_attempter_android.cc中实现。
\system\update_engine\binder_service_android.h如下:
ServiceDelegateAndroidInterface* service_delegate_;
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();
}
system\core\libbinderwrapper\binder_wrapper.cc中
BinderWrapper* BinderWrapper::Get() {
CHECK(instance_) << "Not initialized; missing call to Create()?";
return instance_;
}
void BinderWrapper::Create() {
CHECK(!instance_) << "Already initialized; missing call to Destroy()?";
instance_ = new RealBinderWrapper();
}
E:\source\AndroidP_r3\system\core\libbinderwrapper\real_binder_wrapper.cc中通过RegisterService方法将该服务加入到service_manager中。
bool RealBinderWrapper::RegisterService(const std::string& service_name,
const sp& binder) {
sp service_manager = defaultServiceManager();
if (!service_manager.get()) {
LOG(ERROR) << "Unable to get service manager";
return false;
}
status_t status = defaultServiceManager()->addService(
String16(service_name.c_str()), binder);
if (status != OK) {
LOG(ERROR) << "Failed to register \"" << service_name << "\" with service "
<< "manager";
return false;
}
return true;
}