From e2b0f4c4402748a7e7432c6d8dc6da87e0b256fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Mon, 8 Sep 2025 15:46:58 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E5=9B=9E=E6=BB=9A?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- OAT.xml | 1 + begetd.gni | 2 + bundle.json | 9 + interfaces/innerkits/fs_manager/BUILD.gn | 43 +++- interfaces/innerkits/fs_manager/fstab_mount.c | 73 ++++++ .../fs_manager/ota_event/include/ota_event.h | 31 +++ .../fs_manager/ota_event/ota_event.cpp | 99 ++++++++ .../innerkits/include/fs_manager/fs_manager.h | 1 + services/begetctl/BUILD.gn | 2 +- services/begetctl/partitionslot.cpp | 4 +- services/modules/bootevent/BUILD.gn | 19 +- services/modules/bootevent/bootevent.c | 85 +++++++ test/unittest/BUILD.gn | 8 +- .../ota_boot_success_unittest.cpp | 218 ++++++++++++++++++ .../ota_rollback/ota_data_mount_unittest.cpp | 77 +++++++ 15 files changed, 665 insertions(+), 7 deletions(-) create mode 100755 interfaces/innerkits/fs_manager/ota_event/include/ota_event.h create mode 100755 interfaces/innerkits/fs_manager/ota_event/ota_event.cpp create mode 100755 test/unittest/fs_manager/ota_rollback/ota_boot_success_unittest.cpp create mode 100755 test/unittest/fs_manager/ota_rollback/ota_data_mount_unittest.cpp diff --git a/OAT.xml b/OAT.xml index 0cfc6f859..62bc1e52b 100644 --- a/OAT.xml +++ b/OAT.xml @@ -23,6 +23,7 @@ + diff --git a/begetd.gni b/begetd.gni index 2b18ec65a..985e19997 100644 --- a/begetd.gni +++ b/begetd.gni @@ -13,6 +13,8 @@ init_innerkits_path = "//base/startup/init/interfaces/innerkits" +# init ota rollback +init_feature_ota_rollback = true declare_args() { enable_ohos_startup_init_feature_watcher = true enable_ohos_startup_init_feature_deviceinfo = true diff --git a/bundle.json b/bundle.json index 4ea02f8e9..280a34c69 100755 --- a/bundle.json +++ b/bundle.json @@ -76,6 +76,7 @@ "toybox", "hicollie", "drivers_interface_partitionslot", + "drivers_peripheral_partitionslot", "code_signature", "runtime_core" ], @@ -144,6 +145,14 @@ "name": "//base/startup/init/interfaces/innerkits/fs_manager:libfsmanager_static_real", "visibility": [ "updater" ] }, + { + "header": { + "header_base": "//base/startup/init/interfaces/innerkits/include/fs_manager/", + "header_files": [] + }, + "name": "//base/startup/init/interfaces/innerkits/fs_manager:libotainfo", + "visibility": [ "updater" ] + }, { "header": { "header_base": "//base/startup/init/interfaces/innerkits/include/", diff --git a/interfaces/innerkits/fs_manager/BUILD.gn b/interfaces/innerkits/fs_manager/BUILD.gn index 5989fa3b9..36b4268ed 100755 --- a/interfaces/innerkits/fs_manager/BUILD.gn +++ b/interfaces/innerkits/fs_manager/BUILD.gn @@ -24,6 +24,7 @@ config("libfsmanager_exported_configs") { "//base/startup/init/interfaces/innerkits/fs_manager/erofs_overlay/include", "//base/startup/init/interfaces/innerkits/fs_manager/switch_root/include", "//base/startup/init/interfaces/innerkits/init_module_engine/include", + "//base/startup/init/interfaces/innerkits/fs_manager/ota_event/include", ] } @@ -94,6 +95,10 @@ ohos_static_library("libfsmanager_static") { cflags = [ "-DWITH_SELINUX" ] } } + + if (init_feature_ota_rollback) { + defines += [ "OTA_ROLLBACK_SUPPORT" ] + } } public_configs = [ ":libfsmanager_exported_configs" ] @@ -121,6 +126,7 @@ ohos_static_library("libfsmanager_static_real") { "bounds_checking_function:libsec_static", "cJSON:cjson_static", ] + defines = [] deps = [ "//base/startup/init/services/utils:libinit_utils" ] if ((defined(global_parts_info) && @@ -151,7 +157,7 @@ ohos_static_library("libfsmanager_static_real") { "//base/startup/init/interfaces/innerkits/fs_manager/dm_verity/include", ] - defines = [ "SUPPORT_HVB" ] + defines += [ "SUPPORT_HVB" ] external_deps += [ "hvb:libhvb_static" ] } @@ -165,9 +171,44 @@ ohos_static_library("libfsmanager_static_real") { defines += [ "EROFS_OVERLAY" ] } + + if (init_feature_ota_rollback) { + defines += [ "OTA_ROLLBACK_SUPPORT" ] + } } public_configs = [ ":libfsmanager_exported_configs" ] part_name = "init" subsystem_name = "startup" } + +ohos_static_library("libotainfo") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + sources = [ "ota_event/ota_event.cpp" ] + + include_dirs = [ + "//base/startup/init/interfaces/innerkits/include", + "//base/startup/init/services/log", + "//base/startup/init/services/param/include", + "//base/startup/init/interfaces/innerkits/fs_manager/ota_event/include", + ] + + deps = [ "//base/startup/init/services/utils:libinit_utils" ] + + public_configs = [ ":libfsmanager_exported_configs" ] + if (init_feature_ota_rollback) { + defines = [ "OTA_ROLLBACK_SUPPORT" ] + external_deps = [ + "c_utils:utils", + "drivers_peripheral_partitionslot:libpartition_slot_manager", + "hilog:libhilog_base", + ] + } + + part_name = "init" + subsystem_name = "startup" +} diff --git a/interfaces/innerkits/fs_manager/fstab_mount.c b/interfaces/innerkits/fs_manager/fstab_mount.c index 801cf1c7a..9e44f7c6f 100755 --- a/interfaces/innerkits/fs_manager/fstab_mount.c +++ b/interfaces/innerkits/fs_manager/fstab_mount.c @@ -53,6 +53,8 @@ extern "C" { #define GCALLOWANCE_INCREASE 10 const off_t PARTITION_ACTIVE_SLOT_OFFSET = 1024; const off_t PARTITION_ACTIVE_SLOT_SIZE = 4; +const off_t PARTITION_CHECKPOINT_OFFSET = 1032; +const off_t PARTITION_CHECKPOINT_SIZE = 4; int g_bootSlots = -1; int g_currentSlot = -1; @@ -488,6 +490,42 @@ static int GetSlotInfoFromBootctrl(off_t offset, off_t size) return slotInfo; } +static int GetCheckpointFromBootctrl(off_t offset, off_t size) +{ + char bootctrlDev[MAX_BUFFER_LEN] = {0}; + // default checkpoint not set, normal mode + int checkpoint = 0; + // Get bootctrl device path + if (GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) != 0) { + BEGET_LOGE("Failed to get bootctrl device"); + return -1; + } + char *realPath = GetRealPath(bootctrlDev); + if (realPath == NULL) { + BEGET_LOGE("Failed to get bootctrl device real path"); + return -1; + } + int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + free(realPath); + if (fd < 0) { + BEGET_LOGE("Failed to open bootctrl device, errno %d", errno); + return -1; + } + if (lseek(fd, offset, SEEK_SET) < 0) { + close(fd); + BEGET_LOGE("Failed to lseek bootctrl device fd, errno %d", errno); + return -1; + } + if (read(fd, &checkpoint, sizeof(checkpoint)) != size) { + close(fd); + BEGET_LOGE("Failed to read current checkpoint from bootctrl, errno %d", errno); + return -1; + } + close(fd); + BEGET_LOGI("get checkpoint: %d", checkpoint); + return checkpoint; +} + int GetBootSlots(void) { if (g_bootSlots != -1) { @@ -497,6 +535,33 @@ int GetBootSlots(void) return g_bootSlots; } +int GetCurrentCheckpoint(void) +{ + return GetCheckpointFromBootctrl(PARTITION_CHECKPOINT_OFFSET, PARTITION_CHECKPOINT_SIZE); +} + +#ifdef OTA_ROLLBACK_SUPPORT +static int DoOtaRollBack(FstabItem *item) +{ + // Get the checkpoint of the current bootctrl + if (strcmp(item->mountPoint, "/data") == 0) { + if (GetCurrentCheckpoint() == 1) { + const char *mountPoint = "/data"; + // Remount data, set checkpoint=disable + const char *options = "checkpoint=disable"; + const char *fsType = NULL; + BEGET_LOGI("remount_point = %s.", mountPoint); + int result = mount(mountPoint, mountPoint, fsType, MS_REMOUNT, options); + if (result != 0) { + BEGET_LOGE("Failed to remount /data"); + return -1; + } + } + } + return 0; +} +#endif + int GetCurrentSlot(void) { if (g_currentSlot != -1) { @@ -743,6 +808,14 @@ int MountOneItem(FstabItem *item) } #endif +#ifdef OTA_ROLLBACK_SUPPORT + // OTA rollback data + int ret = DoOtaRollBack(item); + if (ret != 0) { + BEGET_LOGW("Failed to rollback data"); + } +#endif + if (disableCheckpointRet == 0 && rc == 0) { BEGET_LOGI("start health check process"); HookMgrExecute(GetBootStageHookMgr(), INIT_HEALTH_CHECK_ACTIVE, NULL, NULL); diff --git a/interfaces/innerkits/fs_manager/ota_event/include/ota_event.h b/interfaces/innerkits/fs_manager/ota_event/include/ota_event.h new file mode 100755 index 000000000..b82ac8963 --- /dev/null +++ b/interfaces/innerkits/fs_manager/ota_event/include/ota_event.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OTA_EVENT_H +#define OTA_EVENT_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +void SetActiveSlot(void); +int SetOTAStatus(int status); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif /* OTA_EVENT_H */ diff --git a/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp b/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp new file mode 100755 index 000000000..1f5769a62 --- /dev/null +++ b/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ota_event.h" +#include +#include +#include +#include "beget_ext.h" +#ifdef OTA_ROLLBACK_SUPPORT +#include "partitionslot_manager.h" +#endif + +void SetActiveSlot() +{ + OHOS::HDI::Partitionslot::V1_1::PartitionSlotManager psMgr; + int32_t curSlot = -1; + int32_t numOfSlots = 0; + int32_t ret = psMgr.GetCurrentSlot(curSlot, numOfSlots); + BEGET_LOGI("Get slot info, curSlot: %d, numOfSlots: %d", curSlot, numOfSlots); + if (ret != 0 || curSlot <= 0 || curSlot > 2 || numOfSlots != 2) { // 2: max slot num + return; + } + + int32_t activeSlot = curSlot == 1 ? 2 : 1; + ret = psMgr.SetActiveSlot(activeSlot); + if (ret != 0) { + BEGET_LOGE("Set active slot error, slot: %d", activeSlot); + } +} + +#ifdef OTA_ROLLBACK_SUPPORT +enum ReturnSetOtaStatus { + SET_OTA_STATUS_FAILED = -1, // Failed to call SetOTAStatus to set information. + BOOT_SUCCESS_IN_OTA = 0, // In the ota stage, startup is complete. + BOOT_SUCCESS_IN_NORMAL = 1, // In the non-ota stage, startup is complete. + BOOT_FAILD_IN_OTA = 2, // In the ota stage, startup is failed. + BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. +}; +int SetOTAStatus(int status) +{ + OHOS::HDI::Partitionslot::V1_1::PartitionSlotManager psMgr; + int32_t checkpoint = -1; + + int32_t retGetcheckpoint = psMgr.GetCheckpoint(checkpoint); + if (retGetcheckpoint != 0 || checkpoint == -1) { + BEGET_LOGE("Get checkpoint error"); + return SET_OTA_STATUS_FAILED; + } + // In the ota stage, startup is failed + if (status == 0 && checkpoint == 1) { + BEGET_LOGI("OTA upgrade failed, need to reboot and rollback"); + // switch partition + SetActiveSlot(); + // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed + // Upgrade fails, reboot to do userdata rollback + int retSetcheckpoint = psMgr.SetCheckpoint(0); + if (retSetcheckpoint != 0) { + return SET_OTA_STATUS_FAILED; + } + return BOOT_FAILD_IN_OTA; + // In the ota stage, startup is complete. + } else if (status == 1 && checkpoint == 1) { + BEGET_LOGI("OTA upgrade success"); + // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed + int retSetcheckpoint = psMgr.SetCheckpoint(0); + if (retSetcheckpoint != 0) { + return SET_OTA_STATUS_FAILED; + } + return BOOT_SUCCESS_IN_OTA; + // In the non-ota stage, startup is complete + } else if (status == 1 && checkpoint == 0) { + BEGET_LOGI("Normal boot success"); + return BOOT_SUCCESS_IN_NORMAL; + // In the non-ota stage, startup is failed + } else if (status == 0 && checkpoint == 0) { + BEGET_LOGI("Normal boot failed"); + return BOOT_FAILD_IN_NORMAL; + } + return SET_OTA_STATUS_FAILED; +} +#else +int SetOTAStatus(int status) +{ + (void)status; + return -1; +} +#endif \ No newline at end of file diff --git a/interfaces/innerkits/include/fs_manager/fs_manager.h b/interfaces/innerkits/include/fs_manager/fs_manager.h index dd437e657..5ca5a61a2 100644 --- a/interfaces/innerkits/include/fs_manager/fs_manager.h +++ b/interfaces/innerkits/include/fs_manager/fs_manager.h @@ -114,6 +114,7 @@ typedef struct SlotInfo { Fstab* LoadFstabFromCommandLine(void); int GetBootSlots(void); int GetCurrentSlot(void); +int GetCurrentCheckpoint(void); void ReleaseFstab(Fstab *fstab); Fstab *ReadFstabFromFile(const char *file, bool procMounts); FstabItem *FindFstabItemForPath(Fstab fstab, const char *path); diff --git a/services/begetctl/BUILD.gn b/services/begetctl/BUILD.gn index 77f143fc5..82ddef142 100755 --- a/services/begetctl/BUILD.gn +++ b/services/begetctl/BUILD.gn @@ -137,7 +137,7 @@ if (defined(ohos_lite)) { if (init_feature_ab_partition) { sources += [ "partitionslot.cpp" ] external_deps += [ - "drivers_interface_partitionslot:libpartitionslot_proxy_1.0", + "drivers_interface_partitionslot:libpartitionslot_proxy_1.1", "hdf_core:libhdi", "hdf_core:libpub_utils", ] diff --git a/services/begetctl/partitionslot.cpp b/services/begetctl/partitionslot.cpp index 2f8ee450b..99c349218 100644 --- a/services/begetctl/partitionslot.cpp +++ b/services/begetctl/partitionslot.cpp @@ -17,9 +17,9 @@ #include "begetctl.h" #include "idevmgr_hdi.h" -#include "v1_0/ipartition_slot.h" +#include "v1_1/ipartition_slot.h" -using namespace OHOS::HDI::Partitionslot::V1_0; +using namespace OHOS::HDI::Partitionslot::V1_1; using OHOS::HDI::DeviceManager::V1_0::IDeviceManager; static const int32_t PARTITION_ARGC = 2; diff --git a/services/modules/bootevent/BUILD.gn b/services/modules/bootevent/BUILD.gn index 281d4adf9..df527be06 100755 --- a/services/modules/bootevent/BUILD.gn +++ b/services/modules/bootevent/BUILD.gn @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//base/startup/init/begetd.gni") import("//build/ohos.gni") config("bootevent_static_config") { @@ -25,6 +26,11 @@ config("bootevent_static_config") { } ohos_source_set("libbootevent_static") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } sources = [ "bootevent.c" ] include_dirs = [ ".." ] include_dirs += [ @@ -33,7 +39,10 @@ ohos_source_set("libbootevent_static") { ] sources += [ "//base/startup/init/services/utils/init_utils.c" ] public_configs = [ ":bootevent_static_config" ] - external_deps = [ "cJSON:cjson" ] + deps = [ "//base/startup/init/services/utils:libinit_utils" ] + defines = [] + external_deps = [] + external_deps += [ "cJSON:cjson" ] public_external_deps = [ "config_policy:configpolicy_util" ] public_configs += [ "//base/startup/init/interfaces/innerkits/init_module_engine:init_module_engine_exported_config" ] public_external_deps += [ "bounds_checking_function:libsec_static" ] @@ -43,6 +52,12 @@ ohos_source_set("libbootevent_static") { "selinux:libselinux", "selinux_adapter:librestorecon", ] - defines = [ "WITH_SELINUX" ] + defines += [ "WITH_SELINUX" ] + } + if (init_feature_ota_rollback) { + defines += [ "OTA_ROLLBACK_SUPPORT" ] + deps += [ "//base/startup/init/interfaces/innerkits/fs_manager:libotainfo" ] } + part_name = "init" + subsystem_name = "startup" } diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index c896169ba..2934b327c 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -29,6 +29,11 @@ #include "init_cmds.h" #include "config_policy_utils.h" +#ifdef OTA_ROLLBACK_SUPPORT +#include "ota_event.h" +#include +#endif + #ifdef WITH_SELINUX #include #endif @@ -36,6 +41,16 @@ static const int SLEPP_TIME = 100; #endif +#ifdef OTA_ROLLBACK_SUPPORT +enum ReturnSetOtaStatus { + SET_OTA_STATUS_FAILED = -1, // Failed to call SetOTAStatus to set information. + BOOT_SUCCESS_IN_OTA = 0, // In the ota stage, startup is complete. + BOOT_SUCCESS_IN_NORMAL = 1, // In the non-ota stage, startup is complete. + BOOT_FAILD_IN_OTA = 2, // In the ota stage, startup is failed. + BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. +}; +#endif + static int GetBootSwitchEnable(const char *paramName) { char bootEventOpen[6] = ""; // 6 is length of bool value @@ -318,6 +333,60 @@ static void WriteBooteventSysParam(const char *paramName) SystemWriteParam(name, buf); } +#ifdef OTA_ROLLBACK_SUPPORT +static int OTARollback(void) +{ + // Determine if the system is starting up abnormally + int retOta = SET_OTA_STATUS_FAILED; + int bootStatus = IsBootCompleted(); + + INIT_LOGI("bootStatus = %d.", bootStatus); + retOta = SetOTAStatus(bootStatus); + if (retOta == SET_OTA_STATUS_FAILED) { + INIT_LOGI("Set OTA status failed."); + return -1; + } + + INIT_LOGI("retOta = %d.", retOta); + const char *mountPoint = "/data"; + const char *fsType = NULL; + const char *options = "checkpoint=enable"; + int result; + + switch (retOta) { + case BOOT_SUCCESS_IN_OTA: + INIT_LOGI("boot success in OTA, start to remount data."); + // remount data, set checkpoint=enable + BEGET_LOGI("remount_point = %s.", mountPoint); + result = mount(mountPoint, mountPoint, fsType, MS_REMOUNT, options); + if (result != 0) { + BEGET_LOGE("Failed to remount /data"); + return -1; + } + break; + + case BOOT_SUCCESS_IN_NORMAL: + INIT_LOGI("boot success in normal, no process."); + break; + + case BOOT_FAILD_IN_OTA: + INIT_LOGI("boot faild in OTA, start to reboot."); + // reboot system + ExecReboot("reboot"); + break; + + case BOOT_FAILD_IN_NORMAL: + INIT_LOGI("boot faild in normal, no process."); + break; + + default: + INIT_LOGI("boot status is unknown."); + break; + } + return 1; +} +#endif + #ifndef STARTUP_INIT_TEST static void DelayedHookMgrExecute(TimerHandle handler, void *context) { @@ -399,6 +468,14 @@ static int BootEventParaFireByName(const char *paramName) UpdateBootCount(); SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true"); SetBootCompleted(true); +#ifdef OTA_ROLLBACK_SUPPORT + // First reboot in ota phase, check if rollback is needed + int retOta = OTARollback(); + if (retOta != 1) { + INIT_LOGE("boot failed, no process."); + return 0; + } +#endif SaveServiceBootEvent(); // report complete event ReportSysEvent(); @@ -525,6 +602,14 @@ static int DoUnsetBootEventCmd(int id, const char *name, int argc, const char ** SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "false"); SetBootCompleted(false); g_finished = 0; +#ifdef OTA_ROLLBACK_SUPPORT + // First reboot in ota phase, check if rollback is needed + int retOta = OTARollback(); + if (retOta != 1) { + INIT_LOGE("boot failed, no process."); + return INIT_EPARAMETER; + } +#endif } item->timestamp[BOOTEVENT_READY].tv_sec = 0; diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 38c71982e..f8008b1ae 100755 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -381,7 +381,7 @@ ohos_unittest("init_unittest") { if (init_feature_ab_partition) { sources += [ "//base/startup/init/services/begetctl/partitionslot.cpp" ] external_deps += [ - "drivers_interface_partitionslot:libpartitionslot_proxy_1.0", + "drivers_interface_partitionslot:libpartitionslot_proxy_1.1", "hdf_core:libhdi", "hdf_core:libpub_utils", ] @@ -465,6 +465,12 @@ ohos_unittest("init_unittest") { # test atomic operation sources += [ "//base/startup/init/test/unittest/param/atomic_unittest.cpp" ] + # test ota remount data + sources += [ "//base/startup/init/test/unittest/fs_manager/ota_rollback/ota_data_mount_unittest.cpp" ] + + # test ota check boot success + sources += [ "//base/startup/init/test/unittest/fs_manager/ota_rollback/ota_boot_success_unittest.cpp" ] + cflags_cc = [ "-fexceptions" ] } diff --git a/test/unittest/fs_manager/ota_rollback/ota_boot_success_unittest.cpp b/test/unittest/fs_manager/ota_rollback/ota_boot_success_unittest.cpp new file mode 100755 index 000000000..0292294e7 --- /dev/null +++ b/test/unittest/fs_manager/ota_rollback/ota_boot_success_unittest.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "securec.h" +#include "bootevent.h" +#include +#include "init_utils.h" +#include +#include +#include +#include +#include + +#define BOOTEVENT_LEN 4 +using namespace std; +using namespace testing::ext; +namespace init_ut { +const char* g_bootEventOta1[] = {"bootEvent1", "bootEvent3"}; +const char* g_bootEventOta2[] = {"bootEvent1", "bootEvent4"}; +const char* g_bootEventOta3[] = {"bootEvent2", "bootEvent3"}; +const char* g_bootEventOta4[] = {"bootEvent2", "bootEvent4"}; + +// Define the possible return values for OTA status +enum ReturnSetOtaStatus { + SET_OTA_STATUS_FAILED = -1, // Failed to call SetOTAStatus to set information. + BOOT_SUCCESS_IN_OTA = 0, // In the ota stage, startup is complete. + BOOT_SUCCESS_IN_NORMAL = 1, // In the non-ota stage, startup is complete. + BOOT_FAILD_IN_OTA = 2, // In the ota stage, startup is failed. + BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. +}; + +void SystemReadParam(const char* param, char* value, uint32_t* len) +{ + if (strcmp(param, "bootEvent1") == 0 || strcmp(param, "bootEvent3") == 0) { + int ret = strncpy_s(value, *len, "true", strlen("true")); + if (ret != 0) { + printf("strncpy_s failed\n"); + } + } else if (strcmp(param, "bootEvent2") == 0 || strcmp(param, "bootEvent4") == 0) { + int ret = strncpy_s(value, *len, "false", strlen("false")); + if (ret != 0) { + printf("strncpy_s failed\n"); + } + } else { + int ret = strncpy_s(value, *len, "unknown", strlen("unknown")); + if (ret != 0) { + printf("strncpy_s failed\n"); + } + } +} +static int BootEventJudgeBootComplete1(void) +{ + char value[6] = ""; + uint32_t len = sizeof(value); + int booteventLength = sizeof(g_bootEventOta1) / sizeof(g_bootEventOta1[0]); + + for (int i = 0; i < booteventLength; i++) { + SystemReadParam(g_bootEventOta1[i], value, &len); + if (strncmp(value, "true", BOOTEVENT_LEN) != 0) { + return 0; + } + } + return 1; +} +static int BootEventJudgeBootComplete2(void) +{ + char value[6] = ""; + uint32_t len = sizeof(value); + int booteventLength = sizeof(g_bootEventOta2) / sizeof(g_bootEventOta2[0]); + + for (int i = 0; i < booteventLength; i++) { + SystemReadParam(g_bootEventOta2[i], value, &len); + if (strncmp(value, "true", BOOTEVENT_LEN) != 0) { + return 0; + } + } + return 1; +} +static int BootEventJudgeBootComplete3(void) +{ + char value[6] = ""; + uint32_t len = sizeof(value); + int booteventLength = sizeof(g_bootEventOta3) / sizeof(g_bootEventOta3[0]); + + for (int i = 0; i < booteventLength; i++) { + SystemReadParam(g_bootEventOta3[i], value, &len); + if (strncmp(value, "true", BOOTEVENT_LEN) != 0) { + return 0; + } + } + return 1; +} + +static int BootEventJudgeBootComplete4(void) +{ + char value[6] = ""; + uint32_t len = sizeof(value); + int booteventLength = sizeof(g_bootEventOta4) / sizeof(g_bootEventOta4[0]); + + for (int i = 0; i < booteventLength; i++) { + SystemReadParam(g_bootEventOta4[i], value, &len); + if (strncmp(value, "true", BOOTEVENT_LEN) != 0) { + return 0; + } + } + return 1; +} +void RebootSystem() +{ + printf("System is rebooting...\n"); +} +int Mount(const char *source, const char *target, const char *filesystemtype, + unsigned long mountflags, const void *data) +{ + return 0; // Simulate successful mount +} +static int HandleBootStatus(int retOta) +{ + switch (retOta) { + case BOOT_SUCCESS_IN_OTA: + { + const char *mountPoint = "/data"; + const char *fsType = "f2fs"; + const char *options = "checkpoint=enable"; + int result = Mount(mountPoint, mountPoint, fsType, MS_REMOUNT, options); + if (result != 0) { + return -1; + } + printf("boot success in normal, no process.\n"); + break; + } + + case BOOT_SUCCESS_IN_NORMAL: + printf("boot success in normal, no process.\n"); + break; + + case BOOT_FAILD_IN_OTA: + printf("boot faild in OTA, start to reboot.\n"); + RebootSystem(); + break; + + case BOOT_FAILD_IN_NORMAL: + printf("boot faild in normal, no process.\n"); + break; + + case SET_OTA_STATUS_FAILED: + printf("Set OTA status failed, no process.\n"); + break; + + default: + printf("Unknown boot status, no process.\n"); + break; + } + return 1; +} +class OtaRollbackUnitTest : public testing::Test { +public: + static void SetUpTestCase(void) + { + cout << "OTA Rollback Unittest Begin!" << endl; + }; + static void TearDownTestCase(void) + { + cout << "OTA Rollback Unittest End!" << endl; + }; + void SetUp(void) {}; + void TearDown(void) {}; +}; +HWTEST_F(OtaRollbackUnitTest, BootEventJudgeBootComplete_001, TestSize.Level0) +{ + int result1 = BootEventJudgeBootComplete1(); + EXPECT_EQ(result1, 1); + + int result2 = BootEventJudgeBootComplete2(); + EXPECT_EQ(result2, 0); + + int result3 = BootEventJudgeBootComplete3(); + EXPECT_EQ(result3, 0); + + int result4 = BootEventJudgeBootComplete4(); + EXPECT_EQ(result4, 0); +} + +HWTEST_F(OtaRollbackUnitTest, Init_OtaRollback_001, TestSize.Level0) +{ + int result1 = HandleBootStatus(BOOT_SUCCESS_IN_OTA); + EXPECT_EQ(result1, 1); + + int result2 = HandleBootStatus(BOOT_SUCCESS_IN_NORMAL); + EXPECT_EQ(result2, 1); + + int result3 = HandleBootStatus(BOOT_FAILD_IN_OTA); + EXPECT_EQ(result3, 1); + + int result4 = HandleBootStatus(BOOT_FAILD_IN_NORMAL); + EXPECT_EQ(result4, 1); + + int result5 = HandleBootStatus(SET_OTA_STATUS_FAILED); + EXPECT_EQ(result5, 1); + + int result6 = HandleBootStatus(999); + EXPECT_EQ(result6, 1); + + int result7 = HandleBootStatus(-1); + EXPECT_EQ(result7, 1); +} +} diff --git a/test/unittest/fs_manager/ota_rollback/ota_data_mount_unittest.cpp b/test/unittest/fs_manager/ota_rollback/ota_data_mount_unittest.cpp new file mode 100755 index 000000000..8cc111ec1 --- /dev/null +++ b/test/unittest/fs_manager/ota_rollback/ota_data_mount_unittest.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_manager/fs_manager.h" +#include +#include "init_utils.h" +#include +#include +#include +#include +#include + +using namespace std; +using namespace testing::ext; +namespace init_ut { +struct Item { + const char *mountPoint; + const char *fsType; +}; +class OtaDataRemountUnitTest : public testing::Test { +public: + static void SetUpTestCase(void) + { + cout << "OTA Data Remount Unittest Begin!" << endl; + }; + static void TearDownTestCase(void) + { + cout << "OTA Data Remount Unittest End!" << endl; + }; + void SetUp(void) {}; + void TearDown(void) {}; +}; +HWTEST_F(OtaDataRemountUnitTest, Init_OtaDataRemount_001, TestSize.Level0) +{ + Item item = {"/data", "f2fs"}; + const char *options = "checkpoint=disable"; + int result = mount(item.mountPoint, item.mountPoint, item.fsType, MS_REMOUNT, options); + EXPECT_EQ(result, 0); + + Item item1 = {"/data", "ext4"}; + int result1 = mount(item1.mountPoint, item1.mountPoint, item1.fsType, MS_REMOUNT, options); + EXPECT_EQ(result1, 0); + + Item item2 = {"/data", "unknown_fs"}; + int result2 = mount(item2.mountPoint, item2.mountPoint, item2.fsType, MS_REMOUNT, options); + EXPECT_EQ(result2, 0); +} + +HWTEST_F(OtaDataRemountUnitTest, Init_OtaDataRemount_002, TestSize.Level0) +{ + Item item = {"/data", "f2fs"}; + const char *options = "checkpoint=enable"; + int result = mount(item.mountPoint, item.mountPoint, item.fsType, MS_REMOUNT, options); + EXPECT_EQ(result, 0); + + Item item1 = {"/data", "ext4"}; + int result1 = mount(item1.mountPoint, item1.mountPoint, item1.fsType, MS_REMOUNT, options); + EXPECT_EQ(result1, 0); + + Item item2 = {"/data", "unknown_fs"}; + int result2 = mount(item2.mountPoint, item2.mountPoint, item2.fsType, MS_REMOUNT, options); + EXPECT_EQ(result2, 0); +} + +} -- Gitee From 8307980882c9ea32f99c4971cf8d186229d79672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Tue, 9 Sep 2025 09:53:50 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=9B=9E=E6=BB=9A?= =?UTF-8?q?=E5=AE=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- begetd.gni | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/begetd.gni b/begetd.gni index 985e19997..2deccc7de 100644 --- a/begetd.gni +++ b/begetd.gni @@ -14,7 +14,7 @@ init_innerkits_path = "//base/startup/init/interfaces/innerkits" # init ota rollback -init_feature_ota_rollback = true +init_feature_ota_rollback = false declare_args() { enable_ohos_startup_init_feature_watcher = true enable_ohos_startup_init_feature_deviceinfo = true -- Gitee From 01acb86718d3c69826e3418c180dd462ac4d4c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Wed, 10 Sep 2025 15:19:44 +0800 Subject: [PATCH 3/5] fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- bundle.json | 9 -- interfaces/innerkits/fs_manager/BUILD.gn | 32 ----- interfaces/innerkits/fs_manager/fstab_mount.c | 124 ++++++++++++++++++ .../fs_manager/ota_event/ota_event.cpp | 97 ++++++++++---- .../innerkits/include/fs_manager/fs_manager.h | 2 +- services/modules/bootevent/BUILD.gn | 1 - services/modules/bootevent/bootevent.c | 2 +- 7 files changed, 201 insertions(+), 66 deletions(-) diff --git a/bundle.json b/bundle.json index 280a34c69..4ea02f8e9 100755 --- a/bundle.json +++ b/bundle.json @@ -76,7 +76,6 @@ "toybox", "hicollie", "drivers_interface_partitionslot", - "drivers_peripheral_partitionslot", "code_signature", "runtime_core" ], @@ -145,14 +144,6 @@ "name": "//base/startup/init/interfaces/innerkits/fs_manager:libfsmanager_static_real", "visibility": [ "updater" ] }, - { - "header": { - "header_base": "//base/startup/init/interfaces/innerkits/include/fs_manager/", - "header_files": [] - }, - "name": "//base/startup/init/interfaces/innerkits/fs_manager:libotainfo", - "visibility": [ "updater" ] - }, { "header": { "header_base": "//base/startup/init/interfaces/innerkits/include/", diff --git a/interfaces/innerkits/fs_manager/BUILD.gn b/interfaces/innerkits/fs_manager/BUILD.gn index 36b4268ed..930c8b01f 100755 --- a/interfaces/innerkits/fs_manager/BUILD.gn +++ b/interfaces/innerkits/fs_manager/BUILD.gn @@ -24,7 +24,6 @@ config("libfsmanager_exported_configs") { "//base/startup/init/interfaces/innerkits/fs_manager/erofs_overlay/include", "//base/startup/init/interfaces/innerkits/fs_manager/switch_root/include", "//base/startup/init/interfaces/innerkits/init_module_engine/include", - "//base/startup/init/interfaces/innerkits/fs_manager/ota_event/include", ] } @@ -181,34 +180,3 @@ ohos_static_library("libfsmanager_static_real") { part_name = "init" subsystem_name = "startup" } - -ohos_static_library("libotainfo") { - sanitize = { - cfi = true - cfi_cross_dso = true - debug = false - } - sources = [ "ota_event/ota_event.cpp" ] - - include_dirs = [ - "//base/startup/init/interfaces/innerkits/include", - "//base/startup/init/services/log", - "//base/startup/init/services/param/include", - "//base/startup/init/interfaces/innerkits/fs_manager/ota_event/include", - ] - - deps = [ "//base/startup/init/services/utils:libinit_utils" ] - - public_configs = [ ":libfsmanager_exported_configs" ] - if (init_feature_ota_rollback) { - defines = [ "OTA_ROLLBACK_SUPPORT" ] - external_deps = [ - "c_utils:utils", - "drivers_peripheral_partitionslot:libpartition_slot_manager", - "hilog:libhilog_base", - ] - } - - part_name = "init" - subsystem_name = "startup" -} diff --git a/interfaces/innerkits/fs_manager/fstab_mount.c b/interfaces/innerkits/fs_manager/fstab_mount.c index 9e44f7c6f..6d980dfa3 100755 --- a/interfaces/innerkits/fs_manager/fstab_mount.c +++ b/interfaces/innerkits/fs_manager/fstab_mount.c @@ -541,6 +541,130 @@ int GetCurrentCheckpoint(void) } #ifdef OTA_ROLLBACK_SUPPORT +static int SetCheckpointToBootctrl(off_t offset, off_t size, int checkpoint) +{ + char bootctrlDev[MAX_BUFFER_LEN] = {0}; + // Get bootctrl device path + if (GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) != 0) { + BEGET_LOGE("Failed to get bootctrl device"); + return -1; + } + char *realPath = GetRealPath(bootctrlDev); + if (realPath == NULL) { + BEGET_LOGE("Failed to get bootctrl device real path"); + return -1; + } + int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + free(realPath); + if (fd < 0) { + BEGET_LOGE("Failed to open bootctrl device, errno %d", errno); + return -1; + } + if (lseek(fd, offset, SEEK_SET) < 0) { + close(fd); + BEGET_LOGE("Failed to lseek bootctrl device fd, errno %d", errno); + return -1; + } + if (write(fd, &checkpoint, sizeof(checkpoint)) != size) { + close(fd); + BEGET_LOGE("Failed to write current checkpoint to bootctrl, errno %d", errno); + return -1; + } + close(fd); + BEGET_LOGI("set checkpoint: %d", checkpoint); + return 0; +} + +static int SetSlotInfoToBootctrl(off_t offset, off_t size, int slotInfo) +{ + char bootctrlDev[MAX_BUFFER_LEN] = {0}; + BEGET_ERROR_CHECK(GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) == 0, + return -1, "Failed to get bootctrl device"); + char *realPath = GetRealPath(bootctrlDev); + BEGET_ERROR_CHECK(realPath != NULL, return -1, "Failed to get bootctrl device real path"); + int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + free(realPath); + BEGET_ERROR_CHECK(fd >= 0, return -1, "Failed to open bootctrl device, errno %d", errno); + BEGET_ERROR_CHECK(lseek(fd, offset, SEEK_SET) >= 0, close(fd); return -1, + "Failed to lseek bootctrl device fd, errno %d", errno); + BEGET_INFO_CHECK(write(fd, &slotInfo, sizeof(slotInfo)) == size, close(fd); return -1, + "Failed to write slot info to bootctrl, errno %d", errno); + close(fd); + BEGET_LOGI("set slot info: %d", slotInfo); + return 0; +} + +int SetCurrentCheckpoint(int checkpoint) +{ + return SetCheckpointToBootctrl(PARTITION_CHECKPOINT_OFFSET, PARTITION_CHECKPOINT_SIZE, checkpoint); +} + +int SetCurrentSlot(int currentSlot) +{ + return SetSlotInfoToBootctrl(PARTITION_ACTIVE_SLOT_OFFSET, PARTITION_ACTIVE_SLOT_SIZE, currentSlot); +} + +enum ReturnSetOtaStatus { + SET_OTA_STATUS_FAILED = -1, // Failed to call SetOTAStatus to set information. + BOOT_SUCCESS_IN_OTA = 0, // In the ota stage, startup is complete. + BOOT_SUCCESS_IN_NORMAL = 1, // In the non-ota stage, startup is complete. + BOOT_FAILD_IN_OTA = 2, // In the ota stage, startup is failed. + BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. +}; + +int SetActiveSlot(void) +{ + int currentSlot = GetCurrentSlot(); + BEGET_LOGI("Get slot info, curSlot: %d", currentSlot); + if (currentSlot <= 0 || currentSlot > 2) { + return -1; + } + + int32_t activeSlot = currentSlot == 1 ? 2 : 1; + return SetCurrentSlot(activeSlot); +} + +int SetOTAStatus(int status) +{ + int32_t checkpoint = GetCurrentCheckpoint(); + if (checkpoint < 0) { + return SET_OTA_STATUS_FAILED; + } + // In the ota stage, startup is failed + if (status == 0 && checkpoint == 1) { + BEGET_LOGI("OTA upgrade failed, need to reboot and rollback"); + // switch partition + if (SetActiveSlot() != 0) { + return SET_OTA_STATUS_FAILED; + } + // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed + // Upgrade fails, reboot to do userdata rollback + int retSetcheckpoint = SetCurrentCheckpoint(0); + if (retSetcheckpoint != 0) { + return SET_OTA_STATUS_FAILED; + } + return BOOT_FAILD_IN_OTA; + // In the ota stage, startup is complete. + } else if (status == 1 && checkpoint == 1) { + BEGET_LOGI("OTA upgrade success"); + // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed + int retSetcheckpoint = SetCurrentCheckpoint(0); + if (retSetcheckpoint != 0) { + return SET_OTA_STATUS_FAILED; + } + return BOOT_SUCCESS_IN_OTA; + // In the non-ota stage, startup is complete + } else if (status == 1 && checkpoint == 0) { + BEGET_LOGI("Normal boot success"); + return BOOT_SUCCESS_IN_NORMAL; + // In the non-ota stage, startup is failed + } else if (status == 0 && checkpoint == 0) { + BEGET_LOGI("Normal boot failed"); + return BOOT_FAILD_IN_NORMAL; + } + return SET_OTA_STATUS_FAILED; +} + static int DoOtaRollBack(FstabItem *item) { // Get the checkpoint of the current bootctrl diff --git a/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp b/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp index 1f5769a62..2b89eea47 100755 --- a/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp +++ b/interfaces/innerkits/fs_manager/ota_event/ota_event.cpp @@ -17,30 +17,85 @@ #include #include #include +#include +#include +#include #include "beget_ext.h" +#include "init_utils.h" + #ifdef OTA_ROLLBACK_SUPPORT -#include "partitionslot_manager.h" + #endif -void SetActiveSlot() +#ifdef OTA_ROLLBACK_SUPPORT +const off_t PARTITION_ACTIVE_SLOT_OFFSET = 1024; +const off_t PARTITION_ACTIVE_SLOT_SIZE = 4; +const off_t PARTITION_CHECKPOINT_OFFSET = 1032; +const off_t PARTITION_CHECKPOINT_SIZE = 4; + +static int SetCheckpointToBootctrl(off_t offset, off_t size, int checkpoint) { - OHOS::HDI::Partitionslot::V1_1::PartitionSlotManager psMgr; - int32_t curSlot = -1; - int32_t numOfSlots = 0; - int32_t ret = psMgr.GetCurrentSlot(curSlot, numOfSlots); - BEGET_LOGI("Get slot info, curSlot: %d, numOfSlots: %d", curSlot, numOfSlots); - if (ret != 0 || curSlot <= 0 || curSlot > 2 || numOfSlots != 2) { // 2: max slot num - return; + char bootctrlDev[MAX_BUFFER_LEN] = {0}; + // Get bootctrl device path + if (GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) != 0) { + BEGET_LOGE("Failed to get bootctrl device"); + return -1; } - - int32_t activeSlot = curSlot == 1 ? 2 : 1; - ret = psMgr.SetActiveSlot(activeSlot); - if (ret != 0) { - BEGET_LOGE("Set active slot error, slot: %d", activeSlot); + char *realPath = GetRealPath(bootctrlDev); + if (realPath == NULL) { + BEGET_LOGE("Failed to get bootctrl device real path"); + return -1; } + int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + free(realPath); + if (fd < 0) { + BEGET_LOGE("Failed to open bootctrl device, errno %d", errno); + return -1; + } + if (lseek(fd, offset, SEEK_SET) < 0) { + close(fd); + BEGET_LOGE("Failed to lseek bootctrl device fd, errno %d", errno); + return -1; + } + if (write(fd, &checkpoint, sizeof(checkpoint)) != size) { + close(fd); + BEGET_LOGE("Failed to write current checkpoint to bootctrl, errno %d", errno); + return -1; + } + close(fd); + BEGET_LOGI("set checkpoint: %d", checkpoint); + return 0; +} + +static int SetSlotInfoToBootctrl(off_t offset, off_t size, int slotInfo) +{ + char bootctrlDev[MAX_BUFFER_LEN] = {0}; + BEGET_ERROR_CHECK(GetBlockDevicePath("/bootctrl", bootctrlDev, MAX_BUFFER_LEN) == 0, + return -1, "Failed to get bootctrl device"); + char *realPath = GetRealPath(bootctrlDev); + BEGET_ERROR_CHECK(realPath != NULL, return -1, "Failed to get bootctrl device real path"); + int fd = open(realPath, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + free(realPath); + BEGET_ERROR_CHECK(fd >= 0, return -1, "Failed to open bootctrl device, errno %d", errno); + BEGET_ERROR_CHECK(lseek(fd, offset, SEEK_SET) >= 0, close(fd); return -1, + "Failed to lseek bootctrl device fd, errno %d", errno); + BEGET_INFO_CHECK(write(fd, &slotInfo, sizeof(slotInfo)) == size, close(fd); return -1, + "Failed to write slot info to bootctrl, errno %d", errno); + close(fd); + BEGET_LOGI("set slot info: %d", slotInfo); + return 0; +} + +int SetCurrentCheckpoint(int checkpoint) +{ + return SetCheckpointToBootctrl(PARTITION_CHECKPOINT_OFFSET, PARTITION_CHECKPOINT_SIZE, checkpoint); +} + +int SetCurrentSlot(int currentSlot) +{ + return SetSlotInfoToBootctrl(PARTITION_ACTIVE_SLOT_OFFSET, PARTITION_ACTIVE_SLOT_SIZE, currentSlot); } -#ifdef OTA_ROLLBACK_SUPPORT enum ReturnSetOtaStatus { SET_OTA_STATUS_FAILED = -1, // Failed to call SetOTAStatus to set information. BOOT_SUCCESS_IN_OTA = 0, // In the ota stage, startup is complete. @@ -48,13 +103,11 @@ enum ReturnSetOtaStatus { BOOT_FAILD_IN_OTA = 2, // In the ota stage, startup is failed. BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. }; + int SetOTAStatus(int status) { - OHOS::HDI::Partitionslot::V1_1::PartitionSlotManager psMgr; - int32_t checkpoint = -1; - - int32_t retGetcheckpoint = psMgr.GetCheckpoint(checkpoint); - if (retGetcheckpoint != 0 || checkpoint == -1) { + int32_t retGetcheckpoint = GetCurrentCheckpoint(); + if (retGetcheckpoint != 0 || retGetcheckpoint == -1) { BEGET_LOGE("Get checkpoint error"); return SET_OTA_STATUS_FAILED; } @@ -65,7 +118,7 @@ int SetOTAStatus(int status) SetActiveSlot(); // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed // Upgrade fails, reboot to do userdata rollback - int retSetcheckpoint = psMgr.SetCheckpoint(0); + int retSetcheckpoint = SetCurrentCheckpoint(0); if (retSetcheckpoint != 0) { return SET_OTA_STATUS_FAILED; } @@ -74,7 +127,7 @@ int SetOTAStatus(int status) } else if (status == 1 && checkpoint == 1) { BEGET_LOGI("OTA upgrade success"); // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed - int retSetcheckpoint = psMgr.SetCheckpoint(0); + int retSetcheckpoint = SetCurrentCheckpoint(0); if (retSetcheckpoint != 0) { return SET_OTA_STATUS_FAILED; } diff --git a/interfaces/innerkits/include/fs_manager/fs_manager.h b/interfaces/innerkits/include/fs_manager/fs_manager.h index 5ca5a61a2..63377b01e 100644 --- a/interfaces/innerkits/include/fs_manager/fs_manager.h +++ b/interfaces/innerkits/include/fs_manager/fs_manager.h @@ -136,7 +136,7 @@ unsigned long GetMountFlags(char *mountFlag, char *fsSpecificFlags, size_t fsSpe const char *mountPoint); int GetBlockDevicePath(const char *partName, char *path, size_t size); - +int SetOTAStatus(int status); // Get fscrypt policy if exist int LoadFscryptPolicy(char *buf, size_t size); #ifdef __cplusplus diff --git a/services/modules/bootevent/BUILD.gn b/services/modules/bootevent/BUILD.gn index df527be06..42bbefaf4 100755 --- a/services/modules/bootevent/BUILD.gn +++ b/services/modules/bootevent/BUILD.gn @@ -56,7 +56,6 @@ ohos_source_set("libbootevent_static") { } if (init_feature_ota_rollback) { defines += [ "OTA_ROLLBACK_SUPPORT" ] - deps += [ "//base/startup/init/interfaces/innerkits/fs_manager:libotainfo" ] } part_name = "init" subsystem_name = "startup" diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index 2934b327c..697f8dd92 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -30,7 +30,7 @@ #include "config_policy_utils.h" #ifdef OTA_ROLLBACK_SUPPORT -#include "ota_event.h" +#include "fs_manager/fs_manager.h" #include #endif -- Gitee From cab1a0af8b218f4d9dd6afdf878b272a9c95f103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Wed, 10 Sep 2025 16:15:48 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=91=8A=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- begetd.gni | 2 +- interfaces/innerkits/fs_manager/fstab_mount.c | 67 +++++++++++-------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/begetd.gni b/begetd.gni index 2deccc7de..985e19997 100644 --- a/begetd.gni +++ b/begetd.gni @@ -14,7 +14,7 @@ init_innerkits_path = "//base/startup/init/interfaces/innerkits" # init ota rollback -init_feature_ota_rollback = false +init_feature_ota_rollback = true declare_args() { enable_ohos_startup_init_feature_watcher = true enable_ohos_startup_init_feature_deviceinfo = true diff --git a/interfaces/innerkits/fs_manager/fstab_mount.c b/interfaces/innerkits/fs_manager/fstab_mount.c index 6d980dfa3..225e7e29d 100755 --- a/interfaces/innerkits/fs_manager/fstab_mount.c +++ b/interfaces/innerkits/fs_manager/fstab_mount.c @@ -612,15 +612,17 @@ enum ReturnSetOtaStatus { BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. }; +int slotB = 2; +int slotA = 1; int SetActiveSlot(void) { int currentSlot = GetCurrentSlot(); BEGET_LOGI("Get slot info, curSlot: %d", currentSlot); - if (currentSlot <= 0 || currentSlot > 2) { + if (currentSlot < slotA || currentSlot > slotB) { + BEGET_LOGE("Current slot value %d is invalid", currentSlot); return -1; } - - int32_t activeSlot = currentSlot == 1 ? 2 : 1; + int32_t activeSlot = currentSlot == slotA ? slotB : slotA; return SetCurrentSlot(activeSlot); } @@ -628,6 +630,7 @@ int SetOTAStatus(int status) { int32_t checkpoint = GetCurrentCheckpoint(); if (checkpoint < 0) { + BEGET_LOGE("Failed to get current checkpoint"); return SET_OTA_STATUS_FAILED; } // In the ota stage, startup is failed @@ -635,12 +638,14 @@ int SetOTAStatus(int status) BEGET_LOGI("OTA upgrade failed, need to reboot and rollback"); // switch partition if (SetActiveSlot() != 0) { + BEGET_LOGE("Failed to set active slot"); return SET_OTA_STATUS_FAILED; } // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed // Upgrade fails, reboot to do userdata rollback int retSetcheckpoint = SetCurrentCheckpoint(0); if (retSetcheckpoint != 0) { + BEGET_LOGE("Failed to set checkpoint"); return SET_OTA_STATUS_FAILED; } return BOOT_FAILD_IN_OTA; @@ -650,6 +655,7 @@ int SetOTAStatus(int status) // Write checkpoint=0 to prevent remounting the data partition the next time it is accessed int retSetcheckpoint = SetCurrentCheckpoint(0); if (retSetcheckpoint != 0) { + BEGET_LOGE("Failed to set checkpoint"); return SET_OTA_STATUS_FAILED; } return BOOT_SUCCESS_IN_OTA; @@ -887,6 +893,35 @@ static int ExecCheckpointHook(FstabItem *item) return ret; } +static int HandleMountPostProcessing(FstabItem *item, int rc, int disableCheckpointRet) +{ +#ifdef OTA_ROLLBACK_SUPPORT + // OTA rollback data + int ret = DoOtaRollBack(item); + if (ret != 0) { + BEGET_LOGW("Failed to rollback data"); + } +#endif + + if (disableCheckpointRet == 0 && rc == 0) { + BEGET_LOGI("start health check process"); + HookMgrExecute(GetBootStageHookMgr(), INIT_HEALTH_CHECK_ACTIVE, NULL, NULL); + } + UpdataAndCheckVabMountInfo(item, rc); + InitPostMount(rc, item); + if (rc != 0) { + if (FM_MANAGER_NOFAIL_ENABLED(item->fsManagerFlags)) { + BEGET_LOGE("Mount no fail device %s to %s failed, err = %d", item->deviceName, item->mountPoint, errno); + } else { + BEGET_LOGW("Mount %s to %s failed, err = %d. Ignore failure", item->deviceName, item->mountPoint, errno); + rc = 0; + } + } else { + BEGET_LOGI("Mount %s to %s successful", item->deviceName, item->mountPoint); + } + return rc; +} + int MountOneItem(FstabItem *item) { if (item == NULL) { @@ -932,31 +967,7 @@ int MountOneItem(FstabItem *item) } #endif -#ifdef OTA_ROLLBACK_SUPPORT - // OTA rollback data - int ret = DoOtaRollBack(item); - if (ret != 0) { - BEGET_LOGW("Failed to rollback data"); - } -#endif - - if (disableCheckpointRet == 0 && rc == 0) { - BEGET_LOGI("start health check process"); - HookMgrExecute(GetBootStageHookMgr(), INIT_HEALTH_CHECK_ACTIVE, NULL, NULL); - } - UpdataAndCheckVabMountInfo(item, rc); - InitPostMount(rc, item); - if (rc != 0) { - if (FM_MANAGER_NOFAIL_ENABLED(item->fsManagerFlags)) { - BEGET_LOGE("Mount no fail device %s to %s failed, err = %d", item->deviceName, item->mountPoint, errno); - } else { - BEGET_LOGW("Mount %s to %s failed, err = %d. Ignore failure", item->deviceName, item->mountPoint, errno); - rc = 0; - } - } else { - BEGET_LOGI("Mount %s to %s successful", item->deviceName, item->mountPoint); - } - return rc; + return HandleMountPostProcessing(item, rc, disableCheckpointRet); } #if defined EROFS_OVERLAY && defined SUPPORT_HVB -- Gitee From e8d5d70dfa961e0e7d15ecb624bfd587c30266a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Fri, 12 Sep 2025 14:04:57 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B7=BB=E5=8A=A0otarollback=E9=92=A9?= =?UTF-8?q?=E5=AD=90=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- .../init_module_engine/include/bootstage.h | 8 +++++++ services/init/bootstagehooker.c | 17 ++++++++++++++ services/modules/bootevent/bootevent.c | 23 +++++++++++++++---- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/interfaces/innerkits/init_module_engine/include/bootstage.h b/interfaces/innerkits/init_module_engine/include/bootstage.h index 1703df338..ac1bc85b3 100755 --- a/interfaces/innerkits/init_module_engine/include/bootstage.h +++ b/interfaces/innerkits/init_module_engine/include/bootstage.h @@ -44,6 +44,7 @@ enum INIT_BOOTSTAGE { INIT_POST_PERSIST_PARAM_LOAD = 40, INIT_POST_CFG_LOAD = 50, INIT_CMD_RECORD = 51, + INIT_OTA_ROLLBACK = 53, INIT_REBOOT = 55, INIT_SERVICE_CLEAR = 56, INIT_SERVICE_DUMP = 57, @@ -62,6 +63,8 @@ enum INIT_BOOTSTAGE { HOOK_MGR *GetBootStageHookMgr(void); +HOOK_MGR *GetOTArollbackHookMgr(void); + __attribute__((always_inline)) inline int InitAddGlobalInitHook(int prio, OhosHook hook) { return HookMgrAdd(GetBootStageHookMgr(), INIT_GLOBAL_INIT, prio, hook); @@ -77,6 +80,11 @@ __attribute__((always_inline)) inline int InitAddPreParamLoadHook(int prio, Ohos return HookMgrAdd(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, prio, hook); } +__attribute__((always_inline)) inline int InitAddOTARollbackHook(int prio, OhosHook hook) +{ + return HookMgrAdd(GetOTArollbackHookMgr(), INIT_OTA_ROLLBACK, prio, hook); +} + /** * @brief Parameter load filter context */ diff --git a/services/init/bootstagehooker.c b/services/init/bootstagehooker.c index 3cac2bf1d..bf89f0709 100755 --- a/services/init/bootstagehooker.c +++ b/services/init/bootstagehooker.c @@ -30,3 +30,20 @@ __attribute__((noinline)) HOOK_MGR *GetBootStageHookMgr(void) bootStageHookMgr = HookMgrCreate(INIT_BOOTSTAGE_HOOK_NAME); return bootStageHookMgr; } + +#define INIT_OTA_ROLLBACK_HOOK_NAME "otarollback" +static HOOK_MGR *otaRollbackHookMgr = NULL; + +__attribute__((noinline)) HOOK_MGR *GetOTArollbackHookMgr(void) +{ + if (otaRollbackHookMgr != NULL) { + return otaRollbackHookMgr; + } + + /* + * Create ota rollback hook manager for OTA rollback checking. + * This manager will be used to handle OTA exception rollback logic. + */ + otaRollbackHookMgr = HookMgrCreate(INIT_OTA_ROLLBACK_HOOK_NAME); + return otaRollbackHookMgr; +} diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index 697f8dd92..56a4159a0 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -334,7 +334,7 @@ static void WriteBooteventSysParam(const char *paramName) } #ifdef OTA_ROLLBACK_SUPPORT -static int OTARollback(void) +int OTARollback(void) { // Determine if the system is starting up abnormally int retOta = SET_OTA_STATUS_FAILED; @@ -385,6 +385,14 @@ static int OTARollback(void) } return 1; } + +static int OTARollbackAdapter(const HOOK_INFO *hookInfo, void *executionContext) +{ + UNUSED(hookInfo); + UNUSED(executionContext); + return OTARollback(); +} + #endif #ifndef STARTUP_INIT_TEST @@ -470,8 +478,8 @@ static int BootEventParaFireByName(const char *paramName) SetBootCompleted(true); #ifdef OTA_ROLLBACK_SUPPORT // First reboot in ota phase, check if rollback is needed - int retOta = OTARollback(); - if (retOta != 1) { + int retOta = HookMgrExecute(GetOTArollbackHookMgr(), INIT_OTA_ROLLBACK, NULL, NULL); + if (retOta != 0) { INIT_LOGE("boot failed, no process."); return 0; } @@ -604,8 +612,8 @@ static int DoUnsetBootEventCmd(int id, const char *name, int argc, const char ** g_finished = 0; #ifdef OTA_ROLLBACK_SUPPORT // First reboot in ota phase, check if rollback is needed - int retOta = OTARollback(); - if (retOta != 1) { + int retOta = HookMgrExecute(GetOTArollbackHookMgr(), INIT_OTA_ROLLBACK, NULL, NULL); + if (retOta != 0) { INIT_LOGE("boot failed, no process."); return INIT_EPARAMETER; } @@ -698,4 +706,9 @@ MODULE_CONSTRUCTOR(void) InitAddServiceHook(SetServiceBootEventFork, INIT_SERVICE_FORK_AFTER); InitAddGlobalInitHook(0, ParamSetBootEventHook); + +#ifdef OTA_ROLLBACK_SUPPORT + // Add hook for OTA rollback functionality + InitAddOTARollbackHook(0, OTARollbackAdapter); +#endif } -- Gitee