android AB升级

概述:

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 <android/hardware/boot/1.0/IBootControl.h>
#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<void(bool)> 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 <string>
#include <hardware/boot_control.h>
#include <hardware/hardware.h>
#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<void(bool)> 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<BootControlInterface> CreateBootControl();
}  // namespace boot_control
}  // namespace chromeos_update_engine

两个实现如下:

boot_control_android.cc

// Factory defined in boot_control.h.
std::unique_ptr<BootControlInterface> CreateBootControl() {
  std::unique_ptr<BootControlAndroid> 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<BootControlInterface> CreateBootControl() {
  std::unique_ptr<BootControlRecovery> 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<ServiceObserverInterface*>& service_observers() = 0;
 protected:
  DaemonStateInterface() = default;
};
}  // namespace chromeos_update_engine

DaemonStateAndroid继承自DaemonStateInterface,部分定义如下,升级相关的主要操作都已经包含在内了。

bool StartUpdater() override;
ServiceDelegateAndroidInterface* service_delegate();
std::set<ServiceObserverInterface*> service_observers_;
std::unique_ptr<BootControlInterface> boot_control_;
std::unique_ptr<HardwareInterface> hardware_;
std::unique_ptr<PrefsInterface> prefs_;
std::unique_ptr<UpdateAttempterAndroid> update_attempter_;
OpenSSLWrapper openssl_wrapper_;
std::unique_ptr<CertificateChecker> 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<android::String16>& header_kv_pairs) {
  const std::string payload_url{android::String8{url}.string()};
  std::vector<std::string> 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<IBinder>& binder) {
  sp<IServiceManager> 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;
}

猜你喜欢

转载自blog.csdn.net/thh159/article/details/88377184
今日推荐