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