1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <errno.h>
17#include <time.h>
18#include <unistd.h>
19
20#include "init_utils.h"
21#include "param_manager.h"
22#include "param_persist.h"
23#include "param_utils.h"
24#if !(defined __LITEOFS_A__ || defined __LITEOS_M__)
25#include "trigger_manager.h"
26#endif
27
28// for linux, no mutex
29static ParamMutex g_saveMutex = {};
30
31static int LoadOnePersistParam_(const uint32_t *context, const char *name, const char *value)
32{
33    if (strncmp(name, "persist", strlen("persist")) != 0) {
34        PARAM_LOGE("%s is not persist param, do not load", name);
35        return 0;
36    }
37    bool clearFactoryPersistParams = *(bool*)context;
38    uint32_t dataIndex = 0;
39    unsigned int mode = 0;
40    int result = 0;
41    do {
42        if (!clearFactoryPersistParams) {
43            mode |= LOAD_PARAM_PERSIST;
44            result = WriteParam(name, value, &dataIndex, mode);
45            break;
46        }
47
48        char persetValue[PARAM_VALUE_LEN_MAX] = {0};
49        uint32_t len = PARAM_VALUE_LEN_MAX;
50        int ret = SystemReadParam(name, persetValue, &len);
51        if (ret != 0) {
52            mode |= LOAD_PARAM_PERSIST;
53            result = WriteParam(name, value, &dataIndex, mode);
54            break;
55        }
56
57        if ((strcmp(persetValue, value) != 0)) {
58            PARAM_LOGI("%s value is different, preset value is:%s, persist value is:%s", name, persetValue, value);
59            mode |= LOAD_PARAM_PERSIST;
60            result = WriteParam(name, value, &dataIndex, mode);
61        }
62    } while (0);
63#if !(defined __LITEOFS_A__ || defined __LITEOS_M__)
64    if (result == 0) {
65        PostParamTrigger(EVENT_TRIGGER_PARAM_WATCH, name, value);
66    }
67#endif
68    return result;
69}
70
71static bool IsPublicParam(const char *param)
72{
73    const char *publicPersistParams[] = {
74        "persist.arkui.libace.og", "persist.ddgr.opinctype",
75        "persist.dfx.leak.threshold", "persist.rosen.animationtrace.enabled",
76        "persist.rosen.ddgr.opinctype.debugtype", "persist.sys.graphic.blurEnabled",
77        "persist.sys.graphic.drawing.test", "persist.sys.graphic.filterCacheEnabled",
78        "persist.sys.graphic.foregroundFilterEnabled", "persist.sys.graphic.GpuApitype",
79        "persist.sys.graphic.hmsymbolcfg.enable", "persist.sys.graphic.hmsymboltxt.enable",
80        "persist.sys.graphic.HpsBlurEnable", "persist.sys.graphic.kawaseEnable",
81        "persist.sys.graphic.openDebugTrace", "persist.sys.graphic.subSurface",
82        "persist.sys.text.autospacing.enable", "persist.sys.hilog.binary.forhota.on",
83        "persist.sys.hilog.fuse.on", "persist.sys.xlog.debug",
84        "persist.sys.hiview.testtype", "persist.security.jitfort.disabled",
85        "persist.sys.prefork.enable", "persist.time.timezone",
86        "persist.global.tz_override", "persist.dupdate_engine.update_type",
87        "persist.update.hmos_to_next_flag", "persist.hiview.leak_detector",
88        "persist.hiviewdfx.debugenv", "persist.swing.switch_enable",
89        "persist.hiviewdfx.priv.diagnosis.time.deadline", "persist.hmos_fusion_mgr.ctl.support_hmos",
90        "persist.init.debug.dump.trigger", "persist.init.bootchart.enabled",
91        "persist.init.debug.loglevel", "persist.samgr.cache.sa",
92        "persist.sys.hilog.binary.on", "persist.sys.hilog.debug.on",
93        "persist.bluetooth.collaboration_service", "persist.bluetooth.switch_enable",
94        "persist.edc.proxy_ap_startup", "persist.edm.edm_enable",
95        "persist.moduleupdate.bms.scan", "persist.nearlink.switch_enable",
96        "persist.parentcontrol.enable", "persist.samgr.moduleupdate.start",
97    };
98    int size = sizeof(publicPersistParams) / sizeof(char*);
99    for (int i = 0; i < size; i++) {
100        if (strncmp(param, publicPersistParams[i], strlen(publicPersistParams[i])) == 0) {
101            return true;
102        }
103    }
104    return false;
105}
106
107static int LoadOnePublicPersistParam_(const uint32_t *context, const char *name, const char *value)
108{
109    if (IsPublicParam(name)) {
110        return LoadOnePersistParam_(context, name, value);
111    }
112    PARAM_LOGI("%s is private, ignore", name);
113    return 0;
114}
115
116static void LoadPersistParam_(const bool clearFactoryPersistParams, const char *fileName,
117    char *buffer, uint32_t buffSize, bool isFullLoad)
118{
119    FILE *fp = fopen(fileName, "r");
120    PARAM_WARNING_CHECK(fp != NULL, return, "No valid persist parameter file %s", fileName);
121    int ret = 0;
122    uint32_t paramNum = 0;
123    while (fgets(buffer, buffSize, fp) != NULL) {
124        buffer[buffSize - 1] = '\0';
125        if (isFullLoad) {
126            ret = SplitParamString(buffer, NULL, 0, LoadOnePersistParam_, (uint32_t*)&clearFactoryPersistParams);
127        } else {
128            ret = SplitParamString(buffer, NULL, 0, LoadOnePublicPersistParam_, (uint32_t*)&clearFactoryPersistParams);
129        }
130        PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buffer);
131        paramNum++;
132    }
133    (void)fclose(fp);
134    PARAM_LOGI("LoadPersistParam from file %s paramNum %d", fileName, paramNum);
135}
136
137static bool GetPersistFilePath(char **path, char **tmpPath, int fileType)
138{
139    bool isFullLoad = true;
140    if (InUpdaterMode() == 1) {
141        *path = "/param/persist_parameters";
142        *tmpPath = "/param/tmp_persist_paramters";
143        return isFullLoad;
144    }
145    if (fileType == PUBLIC_PERSIST_FILE) {
146        isFullLoad = false;
147        if (access(PARAM_PERSIST_SAVE_PATH, F_OK) == 0 && access(PARAM_PUBLIC_PERSIST_SAVE_PATH, F_OK) != 0) {
148            int ret = rename(PARAM_PERSIST_SAVE_PATH, PARAM_PUBLIC_PERSIST_SAVE_PATH);
149            if (ret != 0) {
150                PARAM_LOGE("rename failed %s", PARAM_PERSIST_SAVE_PATH);
151            }
152        } else {
153            CheckAndCreateDir(PARAM_PUBLIC_PERSIST_SAVE_PATH);
154        }
155        *path = PARAM_PUBLIC_PERSIST_SAVE_PATH;
156        *tmpPath = PARAM_PUBLIC_PERSIST_SAVE_TMP_PATH;
157        return isFullLoad;
158    }
159    if (access(PARAM_OLD_PERSIST_SAVE_PATH, F_OK) == 0 && access(PARAM_PRIVATE_PERSIST_SAVE_PATH, F_OK) != 0) {
160        int ret = rename(PARAM_OLD_PERSIST_SAVE_PATH, PARAM_PRIVATE_PERSIST_SAVE_PATH);
161        if (ret != 0) {
162            PARAM_LOGE("rename failed %s", PARAM_OLD_PERSIST_SAVE_PATH);
163        }
164    } else {
165        CheckAndCreateDir(PARAM_PRIVATE_PERSIST_SAVE_PATH);
166    }
167    *path = PARAM_PRIVATE_PERSIST_SAVE_PATH;
168    *tmpPath = PARAM_PRIVATE_PERSIST_SAVE_TMP_PATH;
169    return isFullLoad;
170}
171
172static int LoadPersistParam(int fileType)
173{
174    bool clearFactoryPersistParams = false;
175    char value[PARAM_VALUE_LEN_MAX] = {0};
176    uint32_t len = PARAM_VALUE_LEN_MAX;
177    int ret = SystemReadParam("const.startup.param.version", value, &len);
178    if ((ret != 0 || strcmp(value, "1") != 0) &&
179        (access(PERSIST_PARAM_FIXED_FLAGS, F_OK) != 0)) {
180        clearFactoryPersistParams = true;
181    }
182    const uint32_t buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 max len
183    char *buffer = calloc(1, buffSize);
184    PARAM_CHECK(buffer != NULL, return -1, "Failed to alloc");
185
186    char *tmpPath = "";
187    char *path = "";
188    bool isFullLoad = GetPersistFilePath(&path, &tmpPath, fileType);
189    LoadPersistParam_(clearFactoryPersistParams, path, buffer, buffSize, isFullLoad);
190    LoadPersistParam_(clearFactoryPersistParams, tmpPath, buffer, buffSize, isFullLoad);
191    free(buffer);
192    if (clearFactoryPersistParams) {
193        FILE *fp = fopen(PERSIST_PARAM_FIXED_FLAGS, "w");
194        PARAM_CHECK(fp != NULL, return -1, "create file %s fail error %d", PERSIST_PARAM_FIXED_FLAGS, errno);
195        (void)fclose(fp);
196    }
197    return 0;
198}
199
200static int SavePersistParam(const char *name, const char *value)
201{
202    ParamMutexPend(&g_saveMutex);
203    int ret = -1;
204    if (InUpdaterMode() == 1) {
205        char *path = "/param/persist_parameters";
206        FILE *fp = fopen(path, "a+");
207        if (fp != NULL) {
208            ret = fprintf(fp, "%s=%s\n", name, value);
209            (void)fclose(fp);
210        }
211        ParamMutexPost(&g_saveMutex);
212        return ret;
213    }
214    const char *path[PERSIST_HANDLE_MAX] = { PARAM_PUBLIC_PERSIST_SAVE_PATH, PARAM_PRIVATE_PERSIST_SAVE_PATH };
215    for (int i = 0; i < PERSIST_HANDLE_MAX; i++) {
216        FILE *fp = fopen(path[i], "a+");
217        if (fp != NULL) {
218            ret = fprintf(fp, "%s=%s\n", name, value);
219            (void)fclose(fp);
220        }
221    }
222    ParamMutexPost(&g_saveMutex);
223    if (ret <= 0) {
224        PARAM_LOGE("Failed to save persist param %s", name);
225    }
226    return ret;
227}
228
229static int BatchSavePersistParamBegin(PERSIST_SAVE_HANDLE *handle)
230{
231    ParamMutexPend(&g_saveMutex);
232    if (InUpdaterMode() == 1) {
233        char *path = "/param/tmp_persist_parameters";
234        unlink(path);
235        FILE *fp = fopen(path, "w");
236        if (fp == NULL) {
237            ParamMutexPost(&g_saveMutex);
238            PARAM_LOGE("Open file %s fail error %d", path, errno);
239            return -1;
240        }
241        handle[0] = (PERSIST_SAVE_HANDLE)fp;
242        return 0;
243    }
244    const char *path[PERSIST_HANDLE_MAX] = {
245        PARAM_PUBLIC_PERSIST_SAVE_TMP_PATH,
246        PARAM_PRIVATE_PERSIST_SAVE_TMP_PATH
247    };
248    for (int i = 0; i < PERSIST_HANDLE_MAX; i++) {
249        unlink(path[i]);
250        FILE *fp = fopen(path[i], "w");
251        if (fp == NULL) {
252            PARAM_LOGE("Open file %s fail error %d", path[i], errno);
253        } else {
254            handle[i] = (PERSIST_SAVE_HANDLE)fp;
255        }
256    }
257    return 0;
258}
259
260static int BatchSavePersistParam(PERSIST_SAVE_HANDLE handle[], const char *name, const char *value)
261{
262    int ret = 0;
263    for (int i = 0; i < PERSIST_HANDLE_MAX; i++) {
264        FILE *fp = (FILE*)handle[i];
265        if (fp != NULL) {
266            ret = fprintf(fp, "%s=%s\n", name, value);
267            PARAM_CHECK(ret > 0, return -1, "Batchsavepersistparam fail, error %d", errno);
268        }
269    }
270    return (ret > 0) ? 0 : -1;
271}
272
273static void BatchSavePersistParamEnd(PERSIST_SAVE_HANDLE handle[])
274{
275    int ret = 0;
276    if (InUpdaterMode() == 1) {
277        FILE *fp = (FILE *)handle[0];
278        (void)fflush(fp);
279        (void)fsync(fileno(fp));
280        (void)fclose(fp);
281        unlink("/param/persist_parameters");
282        ret = rename("/param/tmp_persist_parameters", "/param/persist_parameters");
283        ParamMutexPost(&g_saveMutex);
284        return;
285    }
286    const char *tmpPath[PERSIST_HANDLE_MAX] = {
287        PARAM_PUBLIC_PERSIST_SAVE_TMP_PATH,
288        PARAM_PRIVATE_PERSIST_SAVE_TMP_PATH
289    };
290    const char *path[PERSIST_HANDLE_MAX] = {
291        PARAM_PUBLIC_PERSIST_SAVE_PATH,
292        PARAM_PRIVATE_PERSIST_SAVE_PATH
293    };
294    for (int i = 0; i < PERSIST_HANDLE_MAX; i++) {
295        if (handle[i] != NULL) {
296            FILE *fp = (FILE *)handle[i];
297            (void)fflush(fp);
298            (void)fsync(fileno(fp));
299            (void)fclose(fp);
300        }
301        unlink(path[i]);
302        ret = rename(tmpPath[i], path[i]);
303    }
304    ParamMutexPost(&g_saveMutex);
305}
306
307int RegisterPersistParamOps(PersistParamOps *ops)
308{
309    ParamMutexCreate(&g_saveMutex);
310    PARAM_CHECK(ops != NULL, return -1, "Invalid ops");
311    ops->save = SavePersistParam;
312    ops->load = LoadPersistParam;
313    ops->batchSaveBegin = BatchSavePersistParamBegin;
314    ops->batchSave = BatchSavePersistParam;
315    ops->batchSaveEnd = BatchSavePersistParamEnd;
316    return 0;
317}