1094332d3Sopenharmony_ci/* 2094332d3Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 3094332d3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4094332d3Sopenharmony_ci * you may not use this file except in compliance with the License. 5094332d3Sopenharmony_ci * You may obtain a copy of the License at 6094332d3Sopenharmony_ci * 7094332d3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8094332d3Sopenharmony_ci * 9094332d3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10094332d3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11094332d3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12094332d3Sopenharmony_ci * See the License for the specific language governing permissions and 13094332d3Sopenharmony_ci * limitations under the License. 14094332d3Sopenharmony_ci */ 15094332d3Sopenharmony_ci 16094332d3Sopenharmony_ci#include "hibernate.h" 17094332d3Sopenharmony_ci 18094332d3Sopenharmony_ci#include <fstream> 19094332d3Sopenharmony_ci#include <sstream> 20094332d3Sopenharmony_ci#include <string> 21094332d3Sopenharmony_ci#include <vector> 22094332d3Sopenharmony_ci#include <cinttypes> 23094332d3Sopenharmony_ci#include <cstdio> 24094332d3Sopenharmony_ci#include <thread> 25094332d3Sopenharmony_ci#include <fcntl.h> 26094332d3Sopenharmony_ci#include <securec.h> 27094332d3Sopenharmony_ci#include <sys/stat.h> 28094332d3Sopenharmony_ci#include <sys/random.h> 29094332d3Sopenharmony_ci#include <sys/swap.h> 30094332d3Sopenharmony_ci#include <sys/sysinfo.h> 31094332d3Sopenharmony_ci#include <linux/fs.h> 32094332d3Sopenharmony_ci#include <linux/fiemap.h> 33094332d3Sopenharmony_ci#include <unistd.h> 34094332d3Sopenharmony_ci#include <sys/ioctl.h> 35094332d3Sopenharmony_ci#include <mntent.h> 36094332d3Sopenharmony_ci 37094332d3Sopenharmony_ci#include <unique_fd.h> 38094332d3Sopenharmony_ci#include <hdf_base.h> 39094332d3Sopenharmony_ci#include <hdf_log.h> 40094332d3Sopenharmony_ci#include <file_ex.h> 41094332d3Sopenharmony_ci 42094332d3Sopenharmony_ci 43094332d3Sopenharmony_cinamespace OHOS { 44094332d3Sopenharmony_cinamespace HDI { 45094332d3Sopenharmony_cinamespace Power { 46094332d3Sopenharmony_cinamespace V1_2 { 47094332d3Sopenharmony_ci 48094332d3Sopenharmony_ci#ifndef HMFS_IOCTL_MAGIC 49094332d3Sopenharmony_ci#define HMFS_IOCTL_MAGIC 0xf5 50094332d3Sopenharmony_ci#endif 51094332d3Sopenharmony_ci 52094332d3Sopenharmony_ci#define HMFS_IOC_SWAPFILE_PREALLOC _IOWR(HMFS_IOCTL_MAGIC, 32, uint32_t) 53094332d3Sopenharmony_ci 54094332d3Sopenharmony_ciconstexpr int32_t SWAP_HEADER_INFO_VERSION = 1; 55094332d3Sopenharmony_ciconstexpr int32_t SWAP_HEADER_INFO_UUID_OFFSET = 3; 56094332d3Sopenharmony_ciconstexpr int32_t SWAP_HEADER_MAGIC_SIZE = 10; 57094332d3Sopenharmony_ciconstexpr int32_t SWAP_HEADER_SIZE = 129; 58094332d3Sopenharmony_ciconstexpr int32_t SWAP_HEADER_INFO_BOOTBITS_SIZE = 1024; 59094332d3Sopenharmony_ciconstexpr int32_t SWAP_HEADER_BUF_LEN = 1024; 60094332d3Sopenharmony_ciconstexpr int32_t FILE_MAP_BUF_LEN = 2048; 61094332d3Sopenharmony_ci// The swap file size, which can be configured in subsequent version. 62094332d3Sopenharmony_ciconstexpr uint64_t SWAP_FILE_SIZE = 17179869184; // 16G 63094332d3Sopenharmony_ciconstexpr uint32_t SWAP_FILE_MODE = 0600; 64094332d3Sopenharmony_ci 65094332d3Sopenharmony_ciconstexpr int32_t UUID_VERSION_OFFSET = 6; 66094332d3Sopenharmony_ciconstexpr int32_t UUID_CLOCK_OFFSET = 8; 67094332d3Sopenharmony_ciconstexpr int32_t UUID_BUF_LEN = 16; 68094332d3Sopenharmony_ciconstexpr unsigned char UUID_VERSION_OPERAND1 = 0x0F; 69094332d3Sopenharmony_ciconstexpr unsigned char UUID_VERSION_OPERAND2 = 0x40; 70094332d3Sopenharmony_ciconstexpr unsigned char UUID_CLOCK_OPERAND1 = 0x3F; 71094332d3Sopenharmony_ciconstexpr unsigned char UUID_CLOCK_OPERAND2 = 0x80; 72094332d3Sopenharmony_ci 73094332d3Sopenharmony_ciconstexpr const char * const SWAP_FILE_PATH = "/data/power/swapfile"; 74094332d3Sopenharmony_ciconstexpr const char * const SWAP_DIR_PATH = "/data/power"; 75094332d3Sopenharmony_ciconstexpr const char * const HIBERNATE_RESUME = "/sys/hibernate/resume"; 76094332d3Sopenharmony_ciconstexpr const char * const SYS_POWER_RESUME = "/sys/power/resume"; 77094332d3Sopenharmony_ciconstexpr const char * const SYS_POWER_RESUME_OFFSET = "/sys/power/resume_offset"; 78094332d3Sopenharmony_ciconstexpr const char * const HIBERNATE_STATE_PATH = "/sys/power/state"; 79094332d3Sopenharmony_ciconstexpr const char * const HIBERNATE_STATE = "disk"; 80094332d3Sopenharmony_ci 81094332d3Sopenharmony_cistruct SwapfileCfg { 82094332d3Sopenharmony_ci unsigned long long len; 83094332d3Sopenharmony_ci}; 84094332d3Sopenharmony_ci 85094332d3Sopenharmony_cistatic int UlongLen(unsigned long arg) 86094332d3Sopenharmony_ci{ 87094332d3Sopenharmony_ci int l = 0; 88094332d3Sopenharmony_ci arg >>= 1; 89094332d3Sopenharmony_ci while (arg) { 90094332d3Sopenharmony_ci l++; 91094332d3Sopenharmony_ci arg >>= 1; 92094332d3Sopenharmony_ci } 93094332d3Sopenharmony_ci return l; 94094332d3Sopenharmony_ci} 95094332d3Sopenharmony_ci 96094332d3Sopenharmony_civoid Hibernate::Init() 97094332d3Sopenharmony_ci{ 98094332d3Sopenharmony_ci HDF_LOGI("hibernate init begin."); 99094332d3Sopenharmony_ci auto myThread = std::thread([this] { this->InitSwap(); }); 100094332d3Sopenharmony_ci myThread.detach(); 101094332d3Sopenharmony_ci} 102094332d3Sopenharmony_ci 103094332d3Sopenharmony_ciint32_t Hibernate::GetResumeInfo(std::string &resumeInfo) 104094332d3Sopenharmony_ci{ 105094332d3Sopenharmony_ci FILE *fp; 106094332d3Sopenharmony_ci struct mntent *me; 107094332d3Sopenharmony_ci int32_t ret = HDF_FAILURE; 108094332d3Sopenharmony_ci if (!(fp = setmntent("/proc/mounts", "r"))) { 109094332d3Sopenharmony_ci HDF_LOGE("open file failed, errno = %{public}d", errno); 110094332d3Sopenharmony_ci return ret; 111094332d3Sopenharmony_ci } 112094332d3Sopenharmony_ci while ((me = getmntent(fp))) { 113094332d3Sopenharmony_ci if (strcmp(me->mnt_dir, "/data") == 0) { 114094332d3Sopenharmony_ci char resolvedPath[PATH_MAX] = {0}; 115094332d3Sopenharmony_ci if (realpath(me->mnt_fsname, resolvedPath) == nullptr) { 116094332d3Sopenharmony_ci HDF_LOGE("realpath error, errno = %{public}d", errno); 117094332d3Sopenharmony_ci break; 118094332d3Sopenharmony_ci } 119094332d3Sopenharmony_ci std::string fileSystemInfo = resolvedPath; 120094332d3Sopenharmony_ci auto index = fileSystemInfo.find_last_of('/'); 121094332d3Sopenharmony_ci if (index == std::string::npos) { 122094332d3Sopenharmony_ci HDF_LOGE("file system info error"); 123094332d3Sopenharmony_ci break; 124094332d3Sopenharmony_ci } 125094332d3Sopenharmony_ci auto partitionNum = fileSystemInfo.substr(index + 1); 126094332d3Sopenharmony_ci HDF_LOGI("partition num: %{public}s", partitionNum.c_str()); 127094332d3Sopenharmony_ci resumeInfo = "/dev/" + partitionNum; 128094332d3Sopenharmony_ci ret = HDF_SUCCESS; 129094332d3Sopenharmony_ci break; 130094332d3Sopenharmony_ci } 131094332d3Sopenharmony_ci } 132094332d3Sopenharmony_ci endmntent(fp); 133094332d3Sopenharmony_ci return ret; 134094332d3Sopenharmony_ci} 135094332d3Sopenharmony_ci 136094332d3Sopenharmony_civoid Hibernate::InitSwap() 137094332d3Sopenharmony_ci{ 138094332d3Sopenharmony_ci std::lock_guard<std::mutex> lock(initMutex_); 139094332d3Sopenharmony_ci if (swapFileReady_) { 140094332d3Sopenharmony_ci HDF_LOGI("swap file is ready, do nothing."); 141094332d3Sopenharmony_ci return; 142094332d3Sopenharmony_ci } 143094332d3Sopenharmony_ci bool needToCreateSwapFile; 144094332d3Sopenharmony_ci auto ret = CheckSwapFile(needToCreateSwapFile); 145094332d3Sopenharmony_ci if (ret != HDF_SUCCESS) { 146094332d3Sopenharmony_ci return; 147094332d3Sopenharmony_ci } 148094332d3Sopenharmony_ci 149094332d3Sopenharmony_ci if (needToCreateSwapFile) { 150094332d3Sopenharmony_ci ret = CreateSwapFile(); 151094332d3Sopenharmony_ci if (ret != HDF_SUCCESS) { 152094332d3Sopenharmony_ci return; 153094332d3Sopenharmony_ci } 154094332d3Sopenharmony_ci ret = MkSwap(); 155094332d3Sopenharmony_ci if (ret != HDF_SUCCESS) { 156094332d3Sopenharmony_ci HDF_LOGI("init swap failed"); 157094332d3Sopenharmony_ci RemoveSwapFile(); 158094332d3Sopenharmony_ci return; 159094332d3Sopenharmony_ci } 160094332d3Sopenharmony_ci } 161094332d3Sopenharmony_ci 162094332d3Sopenharmony_ci ret = WriteOffsetAndResume(); 163094332d3Sopenharmony_ci if (ret != HDF_SUCCESS) { 164094332d3Sopenharmony_ci return; 165094332d3Sopenharmony_ci } 166094332d3Sopenharmony_ci swapFileReady_ = true; 167094332d3Sopenharmony_ci} 168094332d3Sopenharmony_ci 169094332d3Sopenharmony_ciint32_t Hibernate::MkSwap() 170094332d3Sopenharmony_ci{ 171094332d3Sopenharmony_ci int fd = open(SWAP_FILE_PATH, O_RDWR); 172094332d3Sopenharmony_ci if (fd < 0) { 173094332d3Sopenharmony_ci HDF_LOGE("open swap file failed when mkswap"); 174094332d3Sopenharmony_ci return HDF_FAILURE; 175094332d3Sopenharmony_ci } 176094332d3Sopenharmony_ci int32_t retvalue = HDF_FAILURE; 177094332d3Sopenharmony_ci do { 178094332d3Sopenharmony_ci int pagesize = sysconf(_SC_PAGE_SIZE); 179094332d3Sopenharmony_ci if (pagesize == 0) { 180094332d3Sopenharmony_ci break; 181094332d3Sopenharmony_ci } 182094332d3Sopenharmony_ci unsigned int pages = (SWAP_FILE_SIZE / static_cast<unsigned int>(pagesize)) - 1; 183094332d3Sopenharmony_ci char buff[SWAP_HEADER_BUF_LEN]; 184094332d3Sopenharmony_ci uint32_t *swap = reinterpret_cast<uint32_t *>(buff); 185094332d3Sopenharmony_ci 186094332d3Sopenharmony_ci swap[0] = SWAP_HEADER_INFO_VERSION; 187094332d3Sopenharmony_ci swap[1] = pages; 188094332d3Sopenharmony_ci if (lseek(fd, SWAP_HEADER_INFO_BOOTBITS_SIZE, SEEK_SET) < 0) { 189094332d3Sopenharmony_ci HDF_LOGE("skip bootbits failed when mkswap."); 190094332d3Sopenharmony_ci break; 191094332d3Sopenharmony_ci } 192094332d3Sopenharmony_ci 193094332d3Sopenharmony_ci char *uuid = reinterpret_cast<char *>(swap + SWAP_HEADER_INFO_UUID_OFFSET); 194094332d3Sopenharmony_ci if (getrandom(uuid, UUID_BUF_LEN, GRND_RANDOM) != UUID_BUF_LEN) { 195094332d3Sopenharmony_ci HDF_LOGE("create uuid failed when mkswap."); 196094332d3Sopenharmony_ci break; 197094332d3Sopenharmony_ci } 198094332d3Sopenharmony_ci uuid[UUID_VERSION_OFFSET] = (uuid[UUID_VERSION_OFFSET] & UUID_VERSION_OPERAND1) | UUID_VERSION_OPERAND2; 199094332d3Sopenharmony_ci uuid[UUID_CLOCK_OFFSET] = (uuid[UUID_CLOCK_OFFSET] & UUID_CLOCK_OPERAND1) | UUID_CLOCK_OPERAND2; 200094332d3Sopenharmony_ci size_t len = SWAP_HEADER_SIZE * sizeof(uint32_t); 201094332d3Sopenharmony_ci auto ret = write(fd, swap, len); 202094332d3Sopenharmony_ci if (ret < 0 || static_cast<size_t>(ret) != len) { 203094332d3Sopenharmony_ci HDF_LOGE("write swap header info failed when mkswap."); 204094332d3Sopenharmony_ci break; 205094332d3Sopenharmony_ci } 206094332d3Sopenharmony_ci if (lseek(fd, pagesize - SWAP_HEADER_MAGIC_SIZE, SEEK_SET) < 0) { 207094332d3Sopenharmony_ci HDF_LOGE("seek magic of swap failed when mkswap"); 208094332d3Sopenharmony_ci break; 209094332d3Sopenharmony_ci } 210094332d3Sopenharmony_ci if (write(fd, "SWAPSPACE2", SWAP_HEADER_MAGIC_SIZE) != SWAP_HEADER_MAGIC_SIZE) { 211094332d3Sopenharmony_ci HDF_LOGE("write magic of swap failed when mkswap"); 212094332d3Sopenharmony_ci break; 213094332d3Sopenharmony_ci } 214094332d3Sopenharmony_ci fsync(fd); 215094332d3Sopenharmony_ci retvalue = HDF_SUCCESS; 216094332d3Sopenharmony_ci HDF_LOGI("mkswap success"); 217094332d3Sopenharmony_ci } while (0); 218094332d3Sopenharmony_ci close(fd); 219094332d3Sopenharmony_ci return retvalue; 220094332d3Sopenharmony_ci} 221094332d3Sopenharmony_ci 222094332d3Sopenharmony_ciint32_t Hibernate::CheckSwapFile(bool &needToCreateSwapFile) 223094332d3Sopenharmony_ci{ 224094332d3Sopenharmony_ci needToCreateSwapFile = false; 225094332d3Sopenharmony_ci if (!IsSwapFileExist()) { 226094332d3Sopenharmony_ci needToCreateSwapFile = true; 227094332d3Sopenharmony_ci HDF_LOGI("CheckSwapFile, need to create swap file."); 228094332d3Sopenharmony_ci return HDF_SUCCESS; 229094332d3Sopenharmony_ci } 230094332d3Sopenharmony_ci bool isRightSize; 231094332d3Sopenharmony_ci if (CheckSwapFileSize(isRightSize) != HDF_SUCCESS) { 232094332d3Sopenharmony_ci return HDF_FAILURE; 233094332d3Sopenharmony_ci } 234094332d3Sopenharmony_ci if (!isRightSize) { 235094332d3Sopenharmony_ci needToCreateSwapFile = true; 236094332d3Sopenharmony_ci HDF_LOGI("swapfile size was changed, will remove old swapfile."); 237094332d3Sopenharmony_ci if (RemoveSwapFile() != HDF_SUCCESS) { 238094332d3Sopenharmony_ci return HDF_FAILURE; 239094332d3Sopenharmony_ci } 240094332d3Sopenharmony_ci } 241094332d3Sopenharmony_ci HDF_LOGI("CheckSwapFile end."); 242094332d3Sopenharmony_ci return HDF_SUCCESS; 243094332d3Sopenharmony_ci} 244094332d3Sopenharmony_ci 245094332d3Sopenharmony_cibool Hibernate::IsSwapFileExist() 246094332d3Sopenharmony_ci{ 247094332d3Sopenharmony_ci return access(SWAP_FILE_PATH, F_OK) == 0; 248094332d3Sopenharmony_ci} 249094332d3Sopenharmony_ci 250094332d3Sopenharmony_ciint32_t Hibernate::CheckSwapFileSize(bool &isRightSize) 251094332d3Sopenharmony_ci{ 252094332d3Sopenharmony_ci HDF_LOGI("CheckSwapFileSize begin."); 253094332d3Sopenharmony_ci struct stat swapFileStat; 254094332d3Sopenharmony_ci auto ret = stat(SWAP_FILE_PATH, &swapFileStat); 255094332d3Sopenharmony_ci if (ret != 0) { 256094332d3Sopenharmony_ci HDF_LOGE("stat swap file failed, errno=%{public}d", errno); 257094332d3Sopenharmony_ci return HDF_FAILURE; 258094332d3Sopenharmony_ci } 259094332d3Sopenharmony_ci 260094332d3Sopenharmony_ci isRightSize = true; 261094332d3Sopenharmony_ci if (swapFileStat.st_size != SWAP_FILE_SIZE) { 262094332d3Sopenharmony_ci HDF_LOGE("swap file size error, actual_size=%{public}lld expected_size=%{public}lld", 263094332d3Sopenharmony_ci static_cast<long long>(swapFileStat.st_size), static_cast<long long>(SWAP_FILE_SIZE)); 264094332d3Sopenharmony_ci isRightSize = false; 265094332d3Sopenharmony_ci } 266094332d3Sopenharmony_ci HDF_LOGI("CheckSwapFileSize end."); 267094332d3Sopenharmony_ci return HDF_SUCCESS; 268094332d3Sopenharmony_ci} 269094332d3Sopenharmony_ci 270094332d3Sopenharmony_ciint32_t Hibernate::CreateSwapFile() 271094332d3Sopenharmony_ci{ 272094332d3Sopenharmony_ci HDF_LOGI("CreateSwapFile begin."); 273094332d3Sopenharmony_ci if (access(SWAP_DIR_PATH, F_OK) != 0) { 274094332d3Sopenharmony_ci HDF_LOGE("the swap dir not exist."); 275094332d3Sopenharmony_ci return HDF_FAILURE; 276094332d3Sopenharmony_ci } 277094332d3Sopenharmony_ci 278094332d3Sopenharmony_ci struct SwapfileCfg cfg; 279094332d3Sopenharmony_ci cfg.len = SWAP_FILE_SIZE; 280094332d3Sopenharmony_ci 281094332d3Sopenharmony_ci int fd = open(SWAP_FILE_PATH, O_RDONLY | O_LARGEFILE | O_EXCL | O_CREAT, SWAP_FILE_MODE); 282094332d3Sopenharmony_ci if (fd == -1) { 283094332d3Sopenharmony_ci HDF_LOGE("open swap file failed, errno=%{public}d", errno); 284094332d3Sopenharmony_ci return HDF_FAILURE; 285094332d3Sopenharmony_ci } 286094332d3Sopenharmony_ci int ret = ioctl(fd, HMFS_IOC_SWAPFILE_PREALLOC, &cfg); 287094332d3Sopenharmony_ci if (ret != 0) { 288094332d3Sopenharmony_ci HDF_LOGE("ioctl failed, ret=%{public}d", ret); 289094332d3Sopenharmony_ci close(fd); 290094332d3Sopenharmony_ci return HDF_FAILURE; 291094332d3Sopenharmony_ci } 292094332d3Sopenharmony_ci close(fd); 293094332d3Sopenharmony_ci HDF_LOGI("CreateSwapFile success."); 294094332d3Sopenharmony_ci return HDF_SUCCESS; 295094332d3Sopenharmony_ci} 296094332d3Sopenharmony_ci 297094332d3Sopenharmony_ciint32_t Hibernate::RemoveSwapFile() 298094332d3Sopenharmony_ci{ 299094332d3Sopenharmony_ci if (swapoff(SWAP_FILE_PATH) != 0) { 300094332d3Sopenharmony_ci HDF_LOGE("swap off failed when remove swap file, errno=%{public}d", errno); 301094332d3Sopenharmony_ci } 302094332d3Sopenharmony_ci 303094332d3Sopenharmony_ci if (remove(SWAP_FILE_PATH) != 0) { 304094332d3Sopenharmony_ci HDF_LOGE("remove swap file failed, errno=%{public}d", errno); 305094332d3Sopenharmony_ci return HDF_FAILURE; 306094332d3Sopenharmony_ci } 307094332d3Sopenharmony_ci 308094332d3Sopenharmony_ci HDF_LOGI("remove swap file success."); 309094332d3Sopenharmony_ci return HDF_SUCCESS; 310094332d3Sopenharmony_ci} 311094332d3Sopenharmony_ci 312094332d3Sopenharmony_ciint32_t Hibernate::EnableSwap() 313094332d3Sopenharmony_ci{ 314094332d3Sopenharmony_ci HDF_LOGI("swapon begin."); 315094332d3Sopenharmony_ci int ret = swapon(SWAP_FILE_PATH, 0); 316094332d3Sopenharmony_ci if (ret < 0) { 317094332d3Sopenharmony_ci HDF_LOGE("swapon failed, errno=%{public}d", errno); 318094332d3Sopenharmony_ci return HDF_FAILURE; 319094332d3Sopenharmony_ci } 320094332d3Sopenharmony_ci HDF_LOGI("swapon success."); 321094332d3Sopenharmony_ci return HDF_SUCCESS; 322094332d3Sopenharmony_ci} 323094332d3Sopenharmony_ci 324094332d3Sopenharmony_ciint32_t Hibernate::WriteOffsetAndResume() 325094332d3Sopenharmony_ci{ 326094332d3Sopenharmony_ci uint64_t resumeOffset; 327094332d3Sopenharmony_ci auto status = GetResumeOffset(resumeOffset); 328094332d3Sopenharmony_ci if (status != HDF_SUCCESS) { 329094332d3Sopenharmony_ci return HDF_FAILURE; 330094332d3Sopenharmony_ci } 331094332d3Sopenharmony_ci UniqueFd fd(TEMP_FAILURE_RETRY(open(HIBERNATE_RESUME, O_RDWR | O_CLOEXEC))); 332094332d3Sopenharmony_ci if (fd < 0) { 333094332d3Sopenharmony_ci HDF_LOGE("write offset and resume error, fd < 0, errno=%{public}d", errno); 334094332d3Sopenharmony_ci return HDF_FAILURE; 335094332d3Sopenharmony_ci } 336094332d3Sopenharmony_ci std::string resumeInfo; 337094332d3Sopenharmony_ci if (GetResumeInfo(resumeInfo) != HDF_SUCCESS) { 338094332d3Sopenharmony_ci return HDF_FAILURE; 339094332d3Sopenharmony_ci } 340094332d3Sopenharmony_ci std::string offsetResume = std::to_string(resumeOffset) + ":" + resumeInfo; 341094332d3Sopenharmony_ci 342094332d3Sopenharmony_ci bool ret = SaveStringToFd(fd, offsetResume.c_str()); 343094332d3Sopenharmony_ci if (!ret) { 344094332d3Sopenharmony_ci HDF_LOGE("WriteOffsetAndResume fail"); 345094332d3Sopenharmony_ci return HDF_FAILURE; 346094332d3Sopenharmony_ci } 347094332d3Sopenharmony_ci HDF_LOGI("WriteOffsetAndResume end"); 348094332d3Sopenharmony_ci return HDF_SUCCESS; 349094332d3Sopenharmony_ci} 350094332d3Sopenharmony_ci 351094332d3Sopenharmony_ciint32_t Hibernate::WriteOffset() 352094332d3Sopenharmony_ci{ 353094332d3Sopenharmony_ci uint64_t resumeOffset; 354094332d3Sopenharmony_ci auto status = GetResumeOffset(resumeOffset); 355094332d3Sopenharmony_ci if (status != HDF_SUCCESS) { 356094332d3Sopenharmony_ci return HDF_FAILURE; 357094332d3Sopenharmony_ci } 358094332d3Sopenharmony_ci UniqueFd fd(TEMP_FAILURE_RETRY(open(SYS_POWER_RESUME_OFFSET, O_RDWR | O_CLOEXEC))); 359094332d3Sopenharmony_ci if (fd < 0) { 360094332d3Sopenharmony_ci HDF_LOGE("write offset error, fd < 0, errno=%{public}d", errno); 361094332d3Sopenharmony_ci return HDF_FAILURE; 362094332d3Sopenharmony_ci } 363094332d3Sopenharmony_ci 364094332d3Sopenharmony_ci std::string offset = std::to_string(resumeOffset); 365094332d3Sopenharmony_ci 366094332d3Sopenharmony_ci bool ret = SaveStringToFd(fd, offset.c_str()); 367094332d3Sopenharmony_ci if (!ret) { 368094332d3Sopenharmony_ci HDF_LOGE("WriteOffset fail"); 369094332d3Sopenharmony_ci return HDF_FAILURE; 370094332d3Sopenharmony_ci } 371094332d3Sopenharmony_ci HDF_LOGI("WriteOffset end"); 372094332d3Sopenharmony_ci return HDF_SUCCESS; 373094332d3Sopenharmony_ci} 374094332d3Sopenharmony_ci 375094332d3Sopenharmony_ciint32_t Hibernate::WriteResume() 376094332d3Sopenharmony_ci{ 377094332d3Sopenharmony_ci UniqueFd fd(TEMP_FAILURE_RETRY(open(SYS_POWER_RESUME, O_RDWR | O_CLOEXEC))); 378094332d3Sopenharmony_ci if (fd < 0) { 379094332d3Sopenharmony_ci HDF_LOGE("write resume error, fd < 0, errno=%{public}d", errno); 380094332d3Sopenharmony_ci return HDF_FAILURE; 381094332d3Sopenharmony_ci } 382094332d3Sopenharmony_ci 383094332d3Sopenharmony_ci std::string resumeInfo; 384094332d3Sopenharmony_ci if (GetResumeInfo(resumeInfo) != HDF_SUCCESS) { 385094332d3Sopenharmony_ci return HDF_FAILURE; 386094332d3Sopenharmony_ci } 387094332d3Sopenharmony_ci 388094332d3Sopenharmony_ci bool ret = SaveStringToFd(fd, resumeInfo); 389094332d3Sopenharmony_ci if (!ret) { 390094332d3Sopenharmony_ci HDF_LOGE("WriteResume fail"); 391094332d3Sopenharmony_ci return HDF_FAILURE; 392094332d3Sopenharmony_ci } 393094332d3Sopenharmony_ci 394094332d3Sopenharmony_ci HDF_LOGI("WriteResume end"); 395094332d3Sopenharmony_ci return HDF_SUCCESS; 396094332d3Sopenharmony_ci} 397094332d3Sopenharmony_ci 398094332d3Sopenharmony_ciint32_t Hibernate::WritePowerState() 399094332d3Sopenharmony_ci{ 400094332d3Sopenharmony_ci UniqueFd fd(TEMP_FAILURE_RETRY(open(HIBERNATE_STATE_PATH, O_RDWR | O_CLOEXEC))); 401094332d3Sopenharmony_ci if (fd < 0) { 402094332d3Sopenharmony_ci HDF_LOGE("WritePowerState error, fd < 0, errno=%{public}d", errno); 403094332d3Sopenharmony_ci return HDF_FAILURE; 404094332d3Sopenharmony_ci } 405094332d3Sopenharmony_ci 406094332d3Sopenharmony_ci bool ret = SaveStringToFd(fd, HIBERNATE_STATE); 407094332d3Sopenharmony_ci if (!ret) { 408094332d3Sopenharmony_ci HDF_LOGE("WritePowerState fail"); 409094332d3Sopenharmony_ci return HDF_FAILURE; 410094332d3Sopenharmony_ci } 411094332d3Sopenharmony_ci 412094332d3Sopenharmony_ci HDF_LOGE("WritePowerState end"); 413094332d3Sopenharmony_ci return HDF_SUCCESS; 414094332d3Sopenharmony_ci} 415094332d3Sopenharmony_ci 416094332d3Sopenharmony_ciint32_t Hibernate::DoHibernate() 417094332d3Sopenharmony_ci{ 418094332d3Sopenharmony_ci InitSwap(); 419094332d3Sopenharmony_ci if (EnableSwap() != HDF_SUCCESS) { 420094332d3Sopenharmony_ci return HDF_FAILURE; 421094332d3Sopenharmony_ci } 422094332d3Sopenharmony_ci int32_t ret = HDF_SUCCESS; 423094332d3Sopenharmony_ci do { 424094332d3Sopenharmony_ci if (WriteResume() != HDF_SUCCESS) { 425094332d3Sopenharmony_ci ret = HDF_FAILURE; 426094332d3Sopenharmony_ci break; 427094332d3Sopenharmony_ci } 428094332d3Sopenharmony_ci if (WriteOffset() != HDF_SUCCESS) { 429094332d3Sopenharmony_ci ret = HDF_FAILURE; 430094332d3Sopenharmony_ci break; 431094332d3Sopenharmony_ci } 432094332d3Sopenharmony_ci if (WritePowerState() != HDF_SUCCESS) { 433094332d3Sopenharmony_ci ret = HDF_FAILURE; 434094332d3Sopenharmony_ci break; 435094332d3Sopenharmony_ci } 436094332d3Sopenharmony_ci } while (0); 437094332d3Sopenharmony_ci if (swapoff(SWAP_FILE_PATH) != 0) { 438094332d3Sopenharmony_ci HDF_LOGE("swap off failed, errno=%{public}d", errno); 439094332d3Sopenharmony_ci } 440094332d3Sopenharmony_ci return ret; 441094332d3Sopenharmony_ci} 442094332d3Sopenharmony_ci 443094332d3Sopenharmony_ciint32_t Hibernate::GetResumeOffset(uint64_t &resumeOffset) 444094332d3Sopenharmony_ci{ 445094332d3Sopenharmony_ci int fd = open(SWAP_FILE_PATH, O_RDONLY); 446094332d3Sopenharmony_ci if (fd < 0) { 447094332d3Sopenharmony_ci HDF_LOGE("open swap file failed, errno=%{public}d", errno); 448094332d3Sopenharmony_ci return HDF_FAILURE; 449094332d3Sopenharmony_ci } 450094332d3Sopenharmony_ci 451094332d3Sopenharmony_ci struct stat fileStat; 452094332d3Sopenharmony_ci int rc = stat(SWAP_FILE_PATH, &fileStat); 453094332d3Sopenharmony_ci if (rc != 0) { 454094332d3Sopenharmony_ci HDF_LOGE("stat swap file failed, errno=%{public}d", errno); 455094332d3Sopenharmony_ci close(fd); 456094332d3Sopenharmony_ci return HDF_FAILURE; 457094332d3Sopenharmony_ci } 458094332d3Sopenharmony_ci 459094332d3Sopenharmony_ci __u64 buf[FILE_MAP_BUF_LEN]; 460094332d3Sopenharmony_ci unsigned long flags = 0; 461094332d3Sopenharmony_ci struct fiemap *swapFileFiemap = reinterpret_cast<struct fiemap *>(buf); 462094332d3Sopenharmony_ci struct fiemap_extent *swapFileFmExt = &swapFileFiemap->fm_extents[0]; 463094332d3Sopenharmony_ci unsigned int count = (sizeof(buf) - sizeof(*swapFileFiemap)) / sizeof(struct fiemap_extent); 464094332d3Sopenharmony_ci 465094332d3Sopenharmony_ci if (memset_s(swapFileFiemap, sizeof(buf), 0, sizeof(struct fiemap)) != EOK) { 466094332d3Sopenharmony_ci close(fd); 467094332d3Sopenharmony_ci return HDF_FAILURE; 468094332d3Sopenharmony_ci } 469094332d3Sopenharmony_ci 470094332d3Sopenharmony_ci swapFileFiemap->fm_length = ~0ULL; 471094332d3Sopenharmony_ci swapFileFiemap->fm_flags = flags; 472094332d3Sopenharmony_ci swapFileFiemap->fm_extent_count = count; 473094332d3Sopenharmony_ci 474094332d3Sopenharmony_ci rc = ioctl(fd, FS_IOC_FIEMAP, reinterpret_cast<unsigned long>(swapFileFiemap)); 475094332d3Sopenharmony_ci if (rc != 0) { 476094332d3Sopenharmony_ci HDF_LOGE("get swap file physical blk fail, rc=%{public}d", rc); 477094332d3Sopenharmony_ci close(fd); 478094332d3Sopenharmony_ci return HDF_FAILURE; 479094332d3Sopenharmony_ci } 480094332d3Sopenharmony_ci 481094332d3Sopenharmony_ci resumeOffset = swapFileFmExt[0].fe_physical >> UlongLen(fileStat.st_blksize); 482094332d3Sopenharmony_ci HDF_LOGI("resume offset size: %{public}lld", static_cast<long long>(resumeOffset)); 483094332d3Sopenharmony_ci close(fd); 484094332d3Sopenharmony_ci return HDF_SUCCESS; 485094332d3Sopenharmony_ci} 486094332d3Sopenharmony_ci} // namespace V1_2 487094332d3Sopenharmony_ci} // namespace Power 488094332d3Sopenharmony_ci} // namespace HDI 489094332d3Sopenharmony_ci} // namespace OHOS 490