2 * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "include/cache-agent-interface.h"
19 static pthread_mutex_t mutex_ca_block_request = PTHREAD_MUTEX_INITIALIZER;
20 static pthread_mutex_t mutex_ca_capa_handling = PTHREAD_MUTEX_INITIALIZER;
21 static ca_bool_t block_request = CA_TRUE;
22 static pthread_t g_capa_tid = 0;
24 static void __set_block_request(ca_bool_t update)
26 CA_MUTEX_LOCK(&mutex_ca_block_request);
27 block_request = update;
28 CA_MUTEX_UNLOCK(&mutex_ca_block_request);
31 static int __cancel_cache_download(int req_id, ca_bool_t update)
33 int ret = CA_RESULT_OK;
34 ca_info_t *ca_info = CA_NULL;
36 CA_LOGV("cache_id[%d]", req_id);
37 ret = ca_get_info_with_ca_id(req_id, &ca_info);
38 if (ret != CA_RESULT_OK)
41 ca_info->is_cb_update = update;
43 ret = ca_request_to_cancel_cache_download(ca_info);
44 if (ret != CA_RESULT_OK)
47 CA_LOGI("Cache-download is canceled for cache id[%d]", req_id);
50 CA_LOGI("Return:id[%d], ret[%d]", req_id, ret);
54 static int __suspend_cache_download(int req_id, ca_bool_t update)
56 int ret = CA_RESULT_OK;
57 ca_info_t *ca_info = CA_NULL;
59 CA_LOGV("cache_id[%d]", req_id);
60 ret = ca_get_info_with_ca_id(req_id, &ca_info);
61 if (ret != CA_RESULT_OK)
64 ca_info->is_cb_update = update;
66 ret = ca_request_to_suspend_cache_download(ca_info);
67 if (ret != CA_RESULT_OK)
70 CA_LOGI("Cache-download is paused for cache id[%d]", req_id);
73 CA_LOGI("Return:id[%d], ret[%d]", req_id, ret);
77 static int __check_capacity_exceeded(const char *file_path, ca_bool_t *is_allowed)
79 int ret = CA_RESULT_OK;
80 ca_size_t cache_size = 0;
81 unsigned int max_cache_size = 0;
82 ca_size_t src_file_size = 0;
83 *is_allowed = CA_FALSE;
86 ca_storage_get_file_size(file_path, &src_file_size);
88 if (src_file_size < 0) {
89 CA_LOGE("Unable to get the file size!");
90 return CA_ERR_FAIL_TO_ACCESS_FILE;
93 ca_config_get_cache_size(&cache_size);
94 ca_config_get_max_cache_size(&max_cache_size);
95 cache_size /= CA_MB_BYTE;
96 src_file_size /= CA_MB_BYTE;
98 if (cache_size + src_file_size >= max_cache_size * CA_CAPA_THRESHOLD_RATIO) {
99 CA_LOGD("Capacity is exceeded!, cache_size: %lld, src_file_size: %lld, max_cache_size * %f: %f",
100 cache_size, src_file_size, CA_CAPA_THRESHOLD_RATIO,
101 max_cache_size * CA_CAPA_THRESHOLD_RATIO);
102 ret = CA_ERR_DISK_FULL;
105 if (cache_size + src_file_size < max_cache_size)
106 *is_allowed = CA_TRUE;
111 static ca_bool_t __check_lifecycle_exceeded(void)
113 ca_time_t oldest_time;
114 unsigned int max_lifecycle;
116 ca_config_get_oldest_time(&oldest_time);
117 if (oldest_time == 0) {
118 ca_config_set_oldest_time(time(CA_NULL));
122 ca_config_get_max_lifecycle(&max_lifecycle);
124 if (difftime(time(CA_NULL), oldest_time) >= max_lifecycle * CA_CAPA_THRESHOLD_RATIO) {
125 CA_LOGD("Lifecycle expired!, oldest_time: %ld, max_lifecycle: %u, difftime: %f, max_lifecycle * %f: %f",
126 oldest_time, max_lifecycle, difftime(time(CA_NULL), oldest_time),
127 CA_CAPA_THRESHOLD_RATIO, max_lifecycle * CA_CAPA_THRESHOLD_RATIO);
134 static char **__convert_gslist_to_array(GSList *file_list, unsigned int *file_count)
136 char **file_array = CA_NULL;
139 *file_count = g_slist_length(file_list);
140 if (*file_count == 0)
143 file_array = (char **)calloc(*file_count, sizeof(char *));
147 for (GSList* node = file_list; node != NULL; node = node->next) {
148 file_array[index] = (char *)node->data;
155 static void *__thread_clear_exceeded_files(void *data)
157 GSList *file_list = CA_NULL;
158 char **file_array = CA_NULL;
159 unsigned int file_count = 0;
160 ca_capacity_event_type type = (ca_capacity_event_type)data;
162 if (type != CA_CAPACITY_MAX_SIZE && type != CA_CAPACITY_LIFECYCLE)
165 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, CA_NULL);
167 __set_block_request(CA_TRUE);
169 file_list = ca_config_call_capacity_cb(type);
173 file_array = __convert_gslist_to_array(file_list, &file_count);
175 g_slist_free_full(file_list, g_free);
179 ca_storage_remove_files((int)file_count, (const char **) file_array);
181 g_slist_free_full(file_list, g_free);
185 __set_block_request(CA_FALSE);
187 CA_LOGI("=====EXIT thread : ca_id[%lu]=====", g_capa_tid);
189 CA_MUTEX_LOCK(&(mutex_ca_capa_handling));
191 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
193 pthread_exit((void *)CA_NULL);
197 static void __create_capacity_thread(ca_capacity_event_type type)
199 pthread_attr_t thread_attr;
201 if (pthread_attr_init(&thread_attr) != 0)
204 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0)
207 if (pthread_create(&g_capa_tid, &thread_attr, __thread_clear_exceeded_files, (void *)type) != 0) {
208 CA_LOGE("Fail to make thread capacity managing: type[%d]", type);
212 CA_LOGI("Thread is created:thread id[%lu]", g_capa_tid);
215 int ca_init(ca_capacity_event_cb capa_cb)
217 int ret = CA_RESULT_OK;
220 ret = ca_storage_init();
221 if (ret != CA_RESULT_OK)
224 ret = ca_config_init();
225 if (ret != CA_RESULT_OK) {
230 ca_config_set_capacity_cb(capa_cb);
231 __set_block_request(CA_FALSE);
238 int ret = CA_RESULT_OK;
239 CA_LOGI("====== ca_deint EXIT =====");
241 __set_block_request(CA_TRUE);
249 char *ca_store_file(const char *file_path)
251 int ret = CA_RESULT_OK;
252 ca_bool_t is_allowed = CA_TRUE;
254 REQ_BLOCK_RET_PTR(&mutex_ca_block_request, block_request);
259 CA_MUTEX_LOCK(&(mutex_ca_capa_handling));
261 if (g_capa_tid != 0) {
262 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
266 ret = __check_capacity_exceeded(file_path, &is_allowed);
267 if (ret == CA_ERR_DISK_FULL)
268 __create_capacity_thread(CA_CAPACITY_MAX_SIZE);
271 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
275 if (g_capa_tid == 0 && __check_lifecycle_exceeded())
276 __create_capacity_thread(CA_CAPACITY_LIFECYCLE);
278 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
280 return ca_storage_store_file(file_path);
283 int ca_remove_files(int file_count, const char *cache_files[])
285 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
288 return CA_ERR_INVALID_ARGUMENT;
290 return ca_storage_remove_files(file_count, cache_files);
293 int ca_is_file_available(const char *cache_file)
295 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
298 return CA_ERR_INVALID_ARGUMENT;
300 return ca_storage_is_file_available(cache_file);
303 int ca_get_used_cache_size(ca_size_t *size)
306 return CA_ERR_INVALID_ARGUMENT;
308 return ca_storage_get_used_cache_size(size);
311 int ca_start_cache_download(const char *cache_file,
312 ca_req_data_t *ext_data, ca_cb_t *ca_cb_data, int *cache_id)
314 int ret = CA_RESULT_OK;
315 int ca_id = CA_INVALID_ID;
316 ca_info_t *ca_info = CA_NULL;
318 if (!cache_file || !ext_data || !ca_cb_data || !cache_id) {
319 CA_LOGE("Null Check: cache_file, ext_data, ca_cb_data, cache_id");
320 return CA_ERR_INVALID_ARGUMENT;
323 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
325 ret = ca_get_available_ca_id(&ca_id);
326 if (ret != CA_RESULT_OK) {
327 CA_LOGE("No available cache id");
328 return CA_ERR_ALREADY_MAX_COPY;
331 ca_info = ca_get_ca_info(ca_id);
332 if (ca_info == CA_NULL) {
333 CA_LOGE("No available cache info, ca_id[%d]", ca_id);
334 return CA_ERR_INVALID_STATE;
337 ca_info->ca_id = ca_id;
339 if (ext_data->install_path)
340 CA_SECURE_LOGI("install path[%s]", ext_data->install_path);
341 if (ext_data->file_name)
342 CA_SECURE_LOGI("file_name[%s]", ext_data->file_name);
343 if (ext_data->pkg_name)
344 CA_SECURE_LOGI("pkg_name[%s]", ext_data->pkg_name);
345 if (ext_data->user_req_data)
346 CA_LOGI("user_req_data[%p]", ext_data->user_req_data);
347 if (ext_data->user_client_data)
348 CA_LOGI("user_client_data[%p]", ext_data->user_client_data);
350 ret = ca_init_cache_download_data(ca_info, cache_file, ext_data);
351 if (ret != CA_RESULT_OK) {
352 ca_destroy_ca_info(ca_info->ca_id);
353 CA_LOGE("Unable to init cache download info");
354 return CA_ERR_INVALID_STATE;
357 ca_info->is_cb_update = CA_TRUE;
358 memcpy(&(ca_info->cb_info), ca_cb_data, sizeof(ca_cb_t));
360 ret = ca_storage_copy_file(ca_info);
362 if (ret != CA_RESULT_OK) {
363 if (ca_info->dst_fp && ca_info->dst_file) {
364 fclose(ca_info->dst_fp);
365 unlink(ca_info->dst_file);
366 ca_info->dst_fp = CA_NULL;
369 ca_destroy_ca_info(ca_info->ca_id);
373 CA_LOGI("Return:id[%d], ret[%d]", *cache_id, ret);
378 int ca_pause_cache_download(int req_id)
380 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
381 return __suspend_cache_download(req_id, CA_TRUE);
384 int ca_resume_cache_download(int req_id)
386 int ret = CA_RESULT_OK;
387 ca_info_t *ca_info = CA_NULL;
389 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
391 CA_LOGV("cache_id[%d]", req_id);
392 ret = ca_get_info_with_ca_id(req_id, &ca_info);
393 if (ret != CA_RESULT_OK)
396 ca_info->is_cb_update = CA_TRUE;
398 ret = ca_request_to_resume_cache_download(ca_info);
399 if (ret != CA_RESULT_OK)
402 CA_LOGI("Cache-download is resumed for cache id[%d]", req_id);
405 CA_LOGI("Return:id[%d], ret[%d]", req_id, ret);
409 int ca_cancel_cache_download(int req_id)
411 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
412 return __cancel_cache_download(req_id, CA_TRUE);
415 int ca_pause_cache_download_without_update(int req_id)
417 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
418 return __suspend_cache_download(req_id, CA_FALSE);
421 int ca_cancel_cache_download_without_update(int req_id)
423 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
424 return __cancel_cache_download(req_id, CA_FALSE);
427 int ca_is_alive_cache_download(int req_id)
429 int ret = CA_RESULT_OK;
430 ca_info_t *ca_info = CA_NULL;
432 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
434 ca_info = ca_get_ca_info(req_id);
435 if (ca_info == CA_NULL) {
436 CA_LOGE("No available cache info, ca_id[%d]", req_id);
437 ret = CA_ERR_INVALID_ARGUMENT;
441 if (CA_RESULT_OK != ca_check_ca_id(ca_info, req_id)) {
442 CA_LOGE("Invalid ca_id[%d]", ca_info->ca_id);
443 ret = CA_ERR_INVALID_ARGUMENT;
447 CA_LOGI("Return:id[%d], ret[%d]", req_id, ret);
451 int ca_get_max_cache_size(unsigned int *size)
453 return ca_config_get_max_cache_size(size);
456 int ca_set_max_cache_size(unsigned int size)
458 int ret = CA_RESULT_OK;
459 ca_bool_t is_allowed;
461 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
463 ret = ca_config_set_max_cache_size(size);
464 if (ret != CA_RESULT_OK)
467 CA_MUTEX_LOCK(&(mutex_ca_capa_handling));
469 if (g_capa_tid != 0) {
470 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
474 ret = __check_capacity_exceeded(CA_NULL, &is_allowed);
475 if (ret == CA_ERR_DISK_FULL)
476 __create_capacity_thread(CA_CAPACITY_MAX_SIZE);
478 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
483 int ca_get_cache_path(char **path)
485 int ret = CA_RESULT_OK;
487 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
489 *path = (char *)ca_config_get_cache_path();
491 ret = CA_ERR_INVALID_STATE;
496 int ca_set_cache_path(const char *path)
498 int ret = CA_RESULT_OK;
500 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
502 __set_block_request(CA_TRUE);
504 ca_cancel_all_cache_operations();
506 ret = ca_clear_all_cache_files();
507 if (ret != CA_RESULT_OK) {
508 __set_block_request(CA_FALSE);
512 ca_config_set_cache_path(path);
514 __set_block_request(CA_FALSE);
519 int ca_get_cache_lifecycle(unsigned int *time)
521 return ca_config_get_max_lifecycle(time);
524 int ca_set_cache_lifecycle(unsigned int time)
526 int ret = CA_RESULT_OK;
528 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
530 ret = ca_config_set_max_lifecycle(time);
531 if (ret != CA_RESULT_OK)
534 CA_MUTEX_LOCK(&(mutex_ca_capa_handling));
536 if (g_capa_tid == 0 && __check_lifecycle_exceeded())
537 __create_capacity_thread(CA_CAPACITY_LIFECYCLE);
539 CA_MUTEX_UNLOCK(&(mutex_ca_capa_handling));
544 int ca_clear_all_files(void)
546 int ret = CA_RESULT_OK;
548 REQ_BLOCK_RET(&mutex_ca_block_request, block_request);
550 __set_block_request(CA_TRUE);
552 ca_cancel_all_cache_operations();
553 ret = ca_clear_all_cache_files();
555 ca_config_set_cache_size(0);
556 ca_config_set_oldest_time(time(CA_NULL));
558 __set_block_request(CA_FALSE);
563 int ca_set_oldest_file_time(ca_time_t oldest_time)
565 return ca_config_set_oldest_time(oldest_time);