1/* 2 * Copyright (c) 2021-2022 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#include "param_persist.h" 16 17#include <time.h> 18 19#include "init_param.h" 20#include "init_utils.h" 21#include "param_manager.h" 22#include "param_trie.h" 23#include "param_osadp.h" 24#include "securec.h" 25 26static ParamPersistWorkSpace g_persistWorkSpace = {0, 0, NULL, {0}, {0}}; 27static int IsNeedToSave(const char *name) 28{ 29#if defined(__LITEOS_M__) || defined(__LITEOS_A__) 30 return IS_READY_ONLY(name) ? 0 : 1; 31#else 32 return (strncmp(name, PARAM_PERSIST_PREFIX, strlen(PARAM_PERSIST_PREFIX)) == 0) ? 1 : 0; 33#endif 34} 35 36static long long GetPersistCommitId(void) 37{ 38 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 39 PARAM_CHECK(paramSpace != NULL, return 0, "Invalid paramSpace"); 40 PARAM_WORKSPACE_CHECK(paramSpace, return 0, "Invalid space"); 41 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 42 if (space == NULL) { 43 return 0; 44 } 45 PARAMSPACE_AREA_RD_LOCK(space); 46 long long globalCommitId = ATOMIC_UINT64_LOAD_EXPLICIT(&space->area->commitPersistId, MEMORY_ORDER_ACQUIRE); 47 PARAMSPACE_AREA_RW_UNLOCK(space); 48 return globalCommitId; 49} 50 51static void UpdatePersistCommitId(void) 52{ 53 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 54 PARAM_CHECK(paramSpace != NULL, return, "Invalid paramSpace"); 55 PARAM_WORKSPACE_CHECK(paramSpace, return, "Invalid space"); 56 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 57 if (space == NULL) { 58 return; 59 } 60 PARAMSPACE_AREA_RW_LOCK(space); 61 ATOMIC_SYNC_ADD_AND_FETCH(&space->area->commitPersistId, 1, MEMORY_ORDER_RELEASE); 62 PARAMSPACE_AREA_RW_UNLOCK(space); 63} 64 65static int SavePersistParam(const WorkSpace *workSpace, const ParamTrieNode *node, const void *cookie) 66{ 67 ParamTrieNode *current = (ParamTrieNode *)node; 68 if (current == NULL || current->dataIndex == 0) { 69 return 0; 70 } 71 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex); 72 if (entry == NULL) { 73 return 0; 74 } 75 76 if (!IsNeedToSave(entry->data)) { 77 return 0; 78 } 79 80 if ((entry->commitId & PARAM_FLAGS_PERSIST) == 0) { 81 return 0; 82 } 83 static char name[PARAM_NAME_LEN_MAX] = {0}; 84 int ret = memcpy_s(name, PARAM_NAME_LEN_MAX - 1, entry->data, entry->keyLength); 85 PARAM_CHECK(ret == EOK, return -1, "Failed to read param name %s", entry->data); 86 name[entry->keyLength] = '\0'; 87 ret = g_persistWorkSpace.persistParamOps.batchSave( 88 (PERSIST_SAVE_HANDLE)cookie, name, entry->data + entry->keyLength + 1); 89 PARAM_CHECK(ret == 0, return -1, "Failed to write param %s", current->key); 90 return ret; 91} 92 93static int BatchSavePersistParam(void) 94{ 95 PARAM_LOGV("BatchSavePersistParam"); 96 if (g_persistWorkSpace.persistParamOps.batchSaveBegin == NULL || 97 g_persistWorkSpace.persistParamOps.batchSave == NULL || 98 g_persistWorkSpace.persistParamOps.batchSaveEnd == NULL) { 99 return 0; 100 } 101#if defined(__LITEOS_M__) || defined(__LITEOS_A__) || defined(__LINUX__) 102 PERSIST_SAVE_HANDLE handle; 103 int ret = g_persistWorkSpace.persistParamOps.batchSaveBegin(&handle); 104#if defined(__LITEOS_M__) || defined(__LITEOS_A__) 105 const char *prefix = ""; 106#else 107 const char *prefix = PARAM_PERSIST_PREFIX; 108#endif 109#else 110 PERSIST_SAVE_HANDLE handle[PERSIST_HANDLE_MAX] = { NULL, NULL }; 111 int ret = g_persistWorkSpace.persistParamOps.batchSaveBegin(handle); 112 const char *prefix = PARAM_PERSIST_PREFIX; 113#endif 114 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to save persist"); 115 // walk and save persist param 116 WorkSpace *workSpace = GetNextWorkSpace(NULL); 117 while (workSpace != NULL) { 118 WorkSpace *next = GetNextWorkSpace(workSpace); 119 ParamTrieNode *root = FindTrieNode(workSpace, prefix, strlen(prefix), NULL); 120 PARAMSPACE_AREA_RD_LOCK(workSpace); 121 TraversalTrieNode(workSpace, root, SavePersistParam, (void *)handle); 122 PARAMSPACE_AREA_RW_UNLOCK(workSpace); 123 workSpace = next; 124 } 125 g_persistWorkSpace.persistParamOps.batchSaveEnd(handle); 126 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Save persist param fail"); 127 128 PARAM_CLEAR_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE); 129 (void)clock_gettime(CLOCK_MONOTONIC, &g_persistWorkSpace.lastSaveTimer); 130 return ret; 131} 132 133INIT_LOCAL_API int InitPersistParamWorkSpace(void) 134{ 135 if (PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_INIT)) { 136 return 0; 137 } 138 (void)clock_gettime(CLOCK_MONOTONIC, &g_persistWorkSpace.lastSaveTimer); 139 RegisterPersistParamOps(&g_persistWorkSpace.persistParamOps); 140 PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_INIT); 141 return 0; 142} 143 144INIT_LOCAL_API void ClosePersistParamWorkSpace(void) 145{ 146 if (g_persistWorkSpace.saveTimer != NULL) { 147 ParamTimerClose(g_persistWorkSpace.saveTimer); 148 } 149 g_persistWorkSpace.flags = 0; 150} 151 152void CheckAndSavePersistParam(void) 153{ 154 // check commit 155 long long commit = GetPersistCommitId(); 156 PARAM_LOGV("CheckAndSavePersistParam commit %lld %lld", commit, g_persistWorkSpace.commitId); 157 if (g_persistWorkSpace.commitId == commit) { 158 return; 159 } 160 g_persistWorkSpace.commitId = commit; 161 (void)BatchSavePersistParam(); 162} 163 164PARAM_STATIC void TimerCallbackForSave(const ParamTaskPtr timer, void *context) 165{ 166 UNUSED(context); 167 UNUSED(timer); 168 PARAM_LOGV("TimerCallbackForSave "); 169 // for liteos-a must cycle check 170#if (!defined(PARAM_SUPPORT_CYCLE_CHECK) || defined(PARAM_SUPPORT_REAL_CHECK)) 171 ParamTimerClose(g_persistWorkSpace.saveTimer); 172 g_persistWorkSpace.saveTimer = NULL; 173 if (!PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE)) { 174 return; 175 } 176#endif 177 CheckAndSavePersistParam(); 178} 179 180INIT_LOCAL_API int WritePersistParam(const char *name, const char *value) 181{ 182 PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); 183 if (!IsNeedToSave(name)) { 184 return 0; 185 } 186 PARAM_LOGV("WritePersistParam name %s ", name); 187 if (g_persistWorkSpace.persistParamOps.save != NULL) { 188 g_persistWorkSpace.persistParamOps.save(name, value); 189 } 190 // update commit for check 191 UpdatePersistCommitId(); 192 // for liteos-m, start task to check and save parameter 193 // for linux, start timer after set persist parameter 194 // for liteos-a, start timer in init to check and save parameter 195#ifdef PARAM_SUPPORT_REAL_CHECK 196 if (!PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED)) { 197 PARAM_LOGE("Can not save persist param before load %s ", name); 198 return 0; 199 } 200 if (g_persistWorkSpace.persistParamOps.batchSave == NULL) { 201 return 0; 202 } 203 204 // check timer for save all 205 struct timespec currTimer = {0}; 206 (void)clock_gettime(CLOCK_MONOTONIC, &currTimer); 207 uint32_t diff = IntervalTime(&g_persistWorkSpace.lastSaveTimer, &currTimer); 208 if (diff > PARAM_MUST_SAVE_PARAM_DIFF) { 209 if (g_persistWorkSpace.saveTimer != NULL) { 210 ParamTimerClose(g_persistWorkSpace.saveTimer); 211 g_persistWorkSpace.saveTimer = NULL; 212 } 213 return BatchSavePersistParam(); 214 } 215 216 PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_UPDATE); 217 if (g_persistWorkSpace.saveTimer == NULL) { 218 ParamTimerCreate(&g_persistWorkSpace.saveTimer, TimerCallbackForSave, NULL); 219 ParamTimerStart(g_persistWorkSpace.saveTimer, PARAM_MUST_SAVE_PARAM_DIFF * MS_UNIT, MS_UNIT); 220 } 221#endif 222 return 0; 223} 224 225int LoadPersistParams(void) 226{ 227 // get persist parameter 228 int ret = InitPersistParamWorkSpace(); 229 PARAM_CHECK(ret == 0, return ret, "Failed to init persist param"); 230#ifndef STARTUP_INIT_TEST 231 if (PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED)) { 232 PARAM_LOGE("Persist param has been loaded"); 233 return 0; 234 } 235#endif 236#if defined(__LITEOS_M__) || defined(__LITEOS_A__) || defined(__LINUX__) 237 if (g_persistWorkSpace.persistParamOps.load != NULL) { 238 (void)g_persistWorkSpace.persistParamOps.load(); 239 PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED); 240 } 241 // save new persist param 242 ret = BatchSavePersistParam(); 243 PARAM_CHECK(ret == 0, return ret, "Failed to load persist param"); 244 // for liteos-a, start time to check in init 245#ifdef PARAM_SUPPORT_CYCLE_CHECK 246 PARAM_LOGV("LoadPersistParams start check time "); 247 if (g_persistWorkSpace.saveTimer == NULL) { 248 ParamTimerCreate(&g_persistWorkSpace.saveTimer, TimerCallbackForSave, NULL); 249 ParamTimerStart(g_persistWorkSpace.saveTimer, PARAM_MUST_SAVE_PARAM_DIFF * MS_UNIT, MS_UNIT); 250 } 251#endif 252#else 253 if (g_persistWorkSpace.persistParamOps.load != NULL) { 254 (void)g_persistWorkSpace.persistParamOps.load(PUBLIC_PERSIST_FILE); 255 } 256#endif 257 return 0; 258} 259 260int LoadPrivatePersistParams(void) 261{ 262#if !(defined(__LITEOS_M__) || defined(__LITEOS_A__) || defined(__LINUX__)) 263#ifndef STARTUP_INIT_TEST 264 if (PARAM_TEST_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED)) { 265 PARAM_LOGE("Persist param has been loaded"); 266 return 0; 267 } 268#endif 269 if (g_persistWorkSpace.persistParamOps.load != NULL) { 270 (void)g_persistWorkSpace.persistParamOps.load(PRIVATE_PERSIST_FILE); 271 PARAM_SET_FLAG(g_persistWorkSpace.flags, WORKSPACE_FLAGS_LOADED); 272 } 273 // save new persist param 274 int ret = BatchSavePersistParam(); 275 PARAM_CHECK(ret == 0, return ret, "Failed to load persist param"); 276 // for liteos-a, start time to check in init 277#ifdef PARAM_SUPPORT_CYCLE_CHECK 278 PARAM_LOGV("LoadPersistParams start check time "); 279 if (g_persistWorkSpace.saveTimer == NULL) { 280 ParamTimerCreate(&g_persistWorkSpace.saveTimer, TimerCallbackForSave, NULL); 281 ParamTimerStart(g_persistWorkSpace.saveTimer, PARAM_MUST_SAVE_PARAM_DIFF * MS_UNIT, MS_UNIT); 282 } 283#endif 284#endif 285 return 0; 286}