From 9660921b9b260bc91525d1745de550fec25ea5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Thu, 9 Jan 2025 15:23:00 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=E5=9B=9E=E6=BB=9A=E7=9A=84boot?= =?UTF-8?q?=E6=8A=95=E7=A5=A8=E6=9C=BA=E5=88=B6=E6=A3=80=E6=B5=8B=E5=92=8C?= =?UTF-8?q?ota=E9=87=8D=E6=96=B0=E6=8C=82=E8=BD=BDdata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 Change-Id: I8b621f3184e0a2d065df6bac1f6ead2629b122d3 --- OAT.xml | 1 + begetd.gni | 2 + interfaces/innerkits/fs_manager/BUILD.gn | 7 + interfaces/innerkits/fs_manager/fstab_mount.c | 72 ++++++++ .../innerkits/include/fs_manager/fs_manager.h | 1 + services/modules/bootevent/BUILD.gn | 19 +- services/modules/bootevent/bootevent.c | 166 ++++++++++++++++++ 7 files changed, 265 insertions(+), 3 deletions(-) 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 c76fa75e9..f5060b7aa 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 = false declare_args() { enable_ohos_startup_init_feature_watcher = true enable_ohos_startup_init_feature_deviceinfo = true diff --git a/interfaces/innerkits/fs_manager/BUILD.gn b/interfaces/innerkits/fs_manager/BUILD.gn index e0ac82cc7..f428ccc0a 100755 --- a/interfaces/innerkits/fs_manager/BUILD.gn +++ b/interfaces/innerkits/fs_manager/BUILD.gn @@ -81,6 +81,9 @@ ohos_static_library("libfsmanager_static") { defines += [ "EROFS_OVERLAY" ] } + if (init_feature_ota_rollback) { + defines += [ "OTA_ROLLBACK_SUPPORT" ] + } } public_configs = [ ":libfsmanager_exported_configs" ] @@ -123,6 +126,10 @@ ohos_static_library("libfsmanager_static_real") { defines = [ "SUPPORT_HVB" ] external_deps += [ "hvb:libhvb_static" ] deps += [ "//base/startup/init/ueventd:libueventd_ramdisk_static_real" ] + + if (init_feature_ota_rollback) { + defines += [ "OTA_ROLLBACK_SUPPORT" ] + } } } diff --git a/interfaces/innerkits/fs_manager/fstab_mount.c b/interfaces/innerkits/fs_manager/fstab_mount.c index 0f3f07fc0..aff8d6ca5 100755 --- a/interfaces/innerkits/fs_manager/fstab_mount.c +++ b/interfaces/innerkits/fs_manager/fstab_mount.c @@ -47,6 +47,8 @@ extern "C" { #define RESIZE_BUFFER_SIZE 1024 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; __attribute__((weak)) void InitPostMount(const char *mountPoint, int rc) { @@ -429,9 +431,46 @@ static int GetSlotInfoFromBootctrl(off_t offset, off_t size) BEGET_INFO_CHECK(read(fd, &slotInfo, sizeof(slotInfo)) == size, close(fd); return -1, "Failed to read current slot from bootctrl, errno %d", errno); close(fd); + BEGET_LOGI("get slotinfo: %d", slotInfo); 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) { return GetSlotInfoFromCmdLine("bootslots"); @@ -448,6 +487,32 @@ int GetCurrentSlot(void) return GetSlotInfoFromBootctrl(PARTITION_ACTIVE_SLOT_OFFSET, PARTITION_ACTIVE_SLOT_SIZE); } +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 static int DoMountOneItem(FstabItem *item) { BEGET_LOGI("Mount device %s to %s", item->deviceName, item->mountPoint); @@ -553,6 +618,13 @@ int MountOneItem(FstabItem *item) if (rc == 0 && (strcmp(item->mountPoint, "/usr") == 0)) { SwitchRoot("/usr"); } +#ifdef OTA_ROLLBACK_SUPPORT + // OTA rollback data + int ret = DoOtaRollBack(item); + if (ret != 0) { + BEGET_LOGW("Failed to rollback data"); + } +#endif #endif InitPostMount(item->mountPoint, rc); if (rc != 0) { diff --git a/interfaces/innerkits/include/fs_manager/fs_manager.h b/interfaces/innerkits/include/fs_manager/fs_manager.h index de7d021bb..8b8250f09 100644 --- a/interfaces/innerkits/include/fs_manager/fs_manager.h +++ b/interfaces/innerkits/include/fs_manager/fs_manager.h @@ -84,6 +84,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/modules/bootevent/BUILD.gn b/services/modules/bootevent/BUILD.gn index 7a11d4632..446cb93df 100755 --- a/services/modules/bootevent/BUILD.gn +++ b/services/modules/bootevent/BUILD.gn @@ -10,7 +10,7 @@ # 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. - +import("//base/startup/init/begetd.gni") import("//build/ohos.gni") config("bootevent_static_config") { @@ -25,18 +25,31 @@ config("bootevent_static_config") { } ohos_source_set("libbootevent_static") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } sources = [ "bootevent.c" ] include_dirs = [ ".." ] public_configs = [ ":bootevent_static_config" ] 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" ] + defines = [] + external_deps = [] if (build_selinux) { include_dirs += [ "//base/startup/init/interfaces/innerkits/include/param" ] - external_deps = [ + external_deps += [ "selinux:libselinux", "selinux_adapter:librestorecon", ] - defines = [ "WITH_SELINUX" ] + defines += [ "WITH_SELINUX" ] + } + if (init_feature_ota_rollback) { + defines += [ "OTA_ROLLBACK_SUPPORT" ] + external_deps += [ "updater:libotainfo" ] } + part_name = "init" + subsystem_name = "startup" } diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index de455563f..ade9cb2a0 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -29,10 +29,32 @@ #include "init_cmds.h" #include "config_policy_utils.h" +#ifdef OTA_ROLLBACK_SUPPORT +#include "ota_event/ota_event.h" +#include +#endif + #ifdef WITH_SELINUX #include #endif +#ifdef OTA_ROLLBACK_SUPPORT +#define BOOTEVENT_LEN 4 +#define MAX_EVENTS 100 +#define EVENT_NAME_LENGTH 256 + +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. +}; + +char* g_bootEventOta[MAX_EVENTS]; +int g_eventCount = 0; +#endif + static int GetBootSwitchEnable(const char *paramName) { char bootEventOpen[6] = ""; // 6 is length of bool value @@ -316,6 +338,141 @@ static void WriteBooteventSysParam(const char *paramName) "snprintf_s name failed"); SystemWriteParam(name, buf); } +#ifdef OTA_ROLLBACK_SUPPORT +void AllocateEventName(char *eventName) +{ + // Remove trailing whitespace (newline) from the event name + char *end = eventName + strlen(eventName) - 1; + while (end > eventName && (*end == ' ' || *end == '\n')) { + end--; + } + *(end + 1) = '\0'; // Null-terminate the string at the end of the trimmed name + + // Allocate memory for the event string and copy it + g_bootEventOta[g_eventCount] = malloc(strlen(eventName) + 1); + if (g_bootEventOta[g_eventCount] == NULL) { + INIT_LOGE("malloc failed."); + return; + } + int ret = strcpy_s(g_bootEventOta[g_eventCount], strlen(eventName) + 1, eventName); + if (ret != EOK) { + INIT_LOGE("strcpy_s failed, ret = %d.", ret); + } + g_eventCount++; +} +void FetchBootevent(void) +{ + INIT_LOGI("Start Fetch Bootevent."); + FILE *fp; + char path[EVENT_NAME_LENGTH]; + + // Execute the command and open a pipe to read its output + fp = popen("param get | grep bootevent", "r"); + if (fp == NULL) { + INIT_LOGE("Failed to run command"); + exit(1); + } + + // Read the output a line at a time + while (fgets(path, sizeof(path), fp) != NULL && g_eventCount < MAX_EVENTS) { + // Find the '=' character + char *EqualSign = strchr(path, '='); + if (EqualSign != NULL) { + // Replace the '=' with a null terminator to isolate the event name + *EqualSign = '\0'; + + // Remove leading whiteEspace from the event name + char *eventName = path; + while (*eventName == ' ') { + eventName++; + } + AllocateEventName(eventName); + } + } + // Close the pipe + pclose(fp); +} +void FreeBootEvents(void) +{ + for (int i = 0; i < g_eventCount; i++) { + free(g_bootEventOta[i]); + } +} +static void RebootSystem(void) +{ + // Accessing address 0, creating an exception, causing the system to restart + *((volatile int *)0) = 0; +} +static int BootEventJudgeBootComplete(void) +{ + INIT_LOGI("Start Judge Boot Complete."); + FetchBootevent(); + char value[6] = ""; // 6 is length of bool value + uint32_t len = sizeof(value); + INIT_LOGI("booteventLength = %d.", g_eventCount); + for (int i = 0; i < g_eventCount; i++) { + SystemReadParam(g_bootEventOta[i], value, &len); + INIT_LOGI("bootevent %s is %s.", g_bootEventOta[i], value); + if (strncmp(value, "true", BOOTEVENT_LEN) != 0) { + INIT_LOGI("bootevent %s is not ready.", g_bootEventOta[i]); + return 0; + } + } + FreeBootEvents(); + return 1; +} + +static int OTARollback(void) +{ + // Determine if the system is starting up abnormally + int retOta = SET_OTA_STATUS_FAILED; + int bootStatus = BootEventJudgeBootComplete(); + + 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 + RebootSystem(); + 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 static int BootEventParaFireByName(const char *paramName) { @@ -345,6 +502,15 @@ static int BootEventParaFireByName(const char *paramName) if (g_bootEventNum > 0) { return 0; } +#ifdef OTA_ROLLBACK_SUPPORT + // First reboot in ota phase, check if rollback is needed + int retOta = OTARollback(); + if (retOta != 1) { + INIT_LOGI("boot failed, no process."); + return 0; + } +#endif + // All parameters are fired, set boot completed now ... INIT_LOGI("All boot events are fired, boot complete now ..."); SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true"); -- Gitee From d63f9b1600bf958de7a9bebb0baf8dbb2970230a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Thu, 9 Jan 2025 15:23:23 +0800 Subject: [PATCH 2/5] =?UTF-8?q?test:ota=E5=BC=82=E5=B8=B8=E5=9B=9E?= =?UTF-8?q?=E6=BB=9A=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 Change-Id: I07f12a13f3356748582d1a7265fd30f655fe1e5a --- test/unittest/BUILD.gn | 7 +- .../ota_boot_success_unittest.cpp | 218 ++++++++++++++++++ .../ota_rollback/ota_data_mount_unittest.cpp | 77 +++++++ 3 files changed, 301 insertions(+), 1 deletion(-) 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/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 419f01d65..35742bfe5 100755 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -157,7 +157,6 @@ ohos_unittest("init_unittest") { "${FSCRYPT_PATH}/libfscrypt/src/key_control.c", "${FSCRYPT_PATH}/libfscrypt/src/sysparam_static.c", ] - if (defined(build_selinux) && build_selinux) { sources += [ "//base/startup/init/services/param/adapter/param_selinux.c" ] } @@ -441,6 +440,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..c0b758b01 --- /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); +} +} \ No newline at end of file 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..7ced9c816 --- /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); +} + +} \ No newline at end of file -- Gitee From 25a747362435910de39d7de8c39e9d94e6893cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Thu, 6 Mar 2025 17:18:37 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=96=B0=E5=A2=9Ev1=5F1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 Change-Id: I85af328c2a50ffd363d101e74441e92272635c99 --- services/begetctl/BUILD.gn | 2 +- test/unittest/BUILD.gn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 35742bfe5..23501ed2f 100755 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -359,7 +359,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", ] -- Gitee From 6e21e84df458553a5f7cbf49efd5646da8e890d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Fri, 7 Mar 2025 10:29:10 +0800 Subject: [PATCH 4/5] fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- services/begetctl/partitionslot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; -- Gitee From e6454542c7111de31c3834794b1285bc7e49a55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=98=E7=BD=97=E5=AE=87?= Date: Thu, 27 Mar 2025 17:56:09 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=A4=E6=96=ADboot?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 甘罗宇 --- services/modules/bootevent/bootevent.c | 98 ++++---------------------- 1 file changed, 14 insertions(+), 84 deletions(-) diff --git a/services/modules/bootevent/bootevent.c b/services/modules/bootevent/bootevent.c index 229c2c095..cec3929a3 100755 --- a/services/modules/bootevent/bootevent.c +++ b/services/modules/bootevent/bootevent.c @@ -39,10 +39,6 @@ #endif #ifdef OTA_ROLLBACK_SUPPORT -#define BOOTEVENT_LEN 4 -#define MAX_EVENTS 100 -#define EVENT_NAME_LENGTH 256 - 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. @@ -51,8 +47,8 @@ enum ReturnSetOtaStatus { BOOT_FAILD_IN_NORMAL = 3, // In the non-ota stage, startup is failed. }; -char* g_bootEventOta[MAX_EVENTS]; -int g_eventCount = 0; +int g_eventBootcomplete = 0; + #endif static int GetBootSwitchEnable(const char *paramName) @@ -337,94 +333,17 @@ static void WriteBooteventSysParam(const char *paramName) SystemWriteParam(name, buf); } #ifdef OTA_ROLLBACK_SUPPORT -void AllocateEventName(char *eventName) -{ - // Remove trailing whitespace (newline) from the event name - char *end = eventName + strlen(eventName) - 1; - while (end > eventName && (*end == ' ' || *end == '\n')) { - end--; - } - *(end + 1) = '\0'; // Null-terminate the string at the end of the trimmed name - - // Allocate memory for the event string and copy it - g_bootEventOta[g_eventCount] = malloc(strlen(eventName) + 1); - if (g_bootEventOta[g_eventCount] == NULL) { - INIT_LOGE("malloc failed."); - return; - } - int ret = strcpy_s(g_bootEventOta[g_eventCount], strlen(eventName) + 1, eventName); - if (ret != EOK) { - INIT_LOGE("strcpy_s failed, ret = %d.", ret); - } - g_eventCount++; -} -void FetchBootevent(void) -{ - INIT_LOGI("Start Fetch Bootevent."); - FILE *fp; - char path[EVENT_NAME_LENGTH]; - - // Execute the command and open a pipe to read its output - fp = popen("param get | grep bootevent", "r"); - if (fp == NULL) { - INIT_LOGE("Failed to run command"); - exit(1); - } - - // Read the output a line at a time - while (fgets(path, sizeof(path), fp) != NULL && g_eventCount < MAX_EVENTS) { - // Find the '=' character - char *EqualSign = strchr(path, '='); - if (EqualSign != NULL) { - // Replace the '=' with a null terminator to isolate the event name - *EqualSign = '\0'; - - // Remove leading whiteEspace from the event name - char *eventName = path; - while (*eventName == ' ') { - eventName++; - } - AllocateEventName(eventName); - } - } - // Close the pipe - pclose(fp); -} -void FreeBootEvents(void) -{ - for (int i = 0; i < g_eventCount; i++) { - free(g_bootEventOta[i]); - } -} static void RebootSystem(void) { // Accessing address 0, creating an exception, causing the system to restart *((volatile int *)0) = 0; } -static int BootEventJudgeBootComplete(void) -{ - INIT_LOGI("Start Judge Boot Complete."); - FetchBootevent(); - char value[6] = ""; // 6 is length of bool value - uint32_t len = sizeof(value); - INIT_LOGI("booteventLength = %d.", g_eventCount); - for (int i = 0; i < g_eventCount; i++) { - SystemReadParam(g_bootEventOta[i], value, &len); - INIT_LOGI("bootevent %s is %s.", g_bootEventOta[i], value); - if (strncmp(value, "true", BOOTEVENT_LEN) != 0) { - INIT_LOGI("bootevent %s is not ready.", g_bootEventOta[i]); - return 0; - } - } - FreeBootEvents(); - return 1; -} static int OTARollback(void) { // Determine if the system is starting up abnormally int retOta = SET_OTA_STATUS_FAILED; - int bootStatus = BootEventJudgeBootComplete(); + int bootStatus = g_eventBootcomplete; INIT_LOGI("bootStatus = %d.", bootStatus); retOta = SetOTAStatus(bootStatus); @@ -500,7 +419,9 @@ static int BootEventParaFireByName(const char *paramName) if (g_bootEventNum > 0) { return 0; } + #ifdef OTA_ROLLBACK_SUPPORT + g_eventBootcomplete = 1; // First reboot in ota phase, check if rollback is needed int retOta = OTARollback(); if (retOta != 1) { @@ -513,6 +434,7 @@ static int BootEventParaFireByName(const char *paramName) INIT_LOGI("All boot events are fired, boot complete now ..."); SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true"); SetBootCompleted(true); + SaveServiceBootEvent(); // report complete event ReportSysEvent(); @@ -633,6 +555,14 @@ static int DoUnsetBootEventCmd(int id, const char *name, int argc, const char ** SystemWriteParam(argv[0], "false"); if (g_finished != 0) { +#ifdef OTA_ROLLBACK_SUPPORT + // First reboot in ota phase, check if rollback is needed + int retOta = OTARollback(); + if (retOta != 1) { + INIT_LOGI("boot failed, no process."); + return 0; + } +#endif SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "false"); SetBootCompleted(false); g_finished = 0; -- Gitee