Skip to content

Commit 2d99340

Browse files
noahpgminn
authored andcommitted
nrf_cloud: fix memory leak in nrf_cloud_fota_poll
A memory leak in the nrf_cloud_fota_poll module occurs during FOTA job checks mid-FOTA that return successfully. This commit fixes the leak and also adds a new Kconfig options to control the mid-FOTA job check interval. This allows for two main benefits: - Users can have more granular control over the check interval, especially if they want to reduce the number of requests due to impact on battery life - Projects that use the Memfault FOTA backend can disable the mid-FOTA job check entirely by setting the interval to 0, since the Memfault FOTA backend does not have a job status to check (therefore FOTAs are treated as atomic operations). This is the default behavior for those projects. Signed-off-by: Noah Pendleton <noah.pendleton@nordicsemi.no> Signed-off-by: Gillian Minnehan <gillian.minnehan@nordicsemi.no> Jira: CLOUDMCU-390
1 parent 3212220 commit 2d99340

3 files changed

Lines changed: 40 additions & 5 deletions

File tree

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,8 +834,14 @@ AVSystem integration
834834
nRF Cloud integration
835835
---------------------
836836

837-
* Added a ``memfaultModemKey`` control key in the Device Shadow, enabling the Memfault modem FOTA project key to be provisioned at runtime through Device Shadow updates.
838-
This is applied using the :c:func:`memfault_zephyr_fota_modem_project_key_set()` function and requires the :kconfig:option:`CONFIG_MEMFAULT_FOTA_MODEM_UPDATE` Kconfig option to be enabled.
837+
* Added:
838+
839+
* A ``memfaultModemKey`` control key in the Device Shadow, enabling the Memfault modem FOTA project key to be provisioned at runtime through Device Shadow updates.
840+
This is applied using the :c:func:`memfault_zephyr_fota_modem_project_key_set()` function and requires the :kconfig:option:`CONFIG_MEMFAULT_FOTA_MODEM_UPDATE` Kconfig option to be enabled.
841+
842+
* The :kconfig:option:`CONFIG_NRF_CLOUD_FOTA_POLL_JOB_CHECK_PROGRESS_THRESHOLD` Kconfig option to the :ref:`lib_nrf_cloud` FOTA polling helpers, allowing the progress-based FOTA job re-check to be configured or disabled.
843+
844+
* Fixed a memory leak in the :ref:`lib_nrf_cloud` FOTA polling helpers where the temporary job info returned by each FOTA job check was not released on all code paths.
839845

840846
CoreMark integration
841847
--------------------

subsys/net/lib/nrf_cloud/Kconfig.nrf_cloud_fota

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ config FOTA_DL_TIMEOUT_MIN
8585
the download will be cancelled and the job status will be
8686
set as failed.
8787

88+
config NRF_CLOUD_FOTA_POLL_JOB_CHECK_PROGRESS_THRESHOLD
89+
int "Progress percentage interval at which the FOTA job is re-checked"
90+
range 0 100
91+
default 0 if MEMFAULT_USE_NRF_CLOUD_COAP
92+
default 10
93+
help
94+
During a FOTA download, the current FOTA job is re-checked with
95+
nRF Cloud at every multiple of this progress percentage, to allow
96+
the download to be canceled if the job is no longer valid.
97+
0 disables these checks, for backends that do not provide
98+
cancellation information.
99+
88100
module = NRF_CLOUD_FOTA_POLL
89101
module-str = nRF Cloud FOTA Poll
90102
source "subsys/logging/Kconfig.template.log_config"

subsys/net/lib/nrf_cloud/common/src/nrf_cloud_fota_poll.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static void on_download_evt_finished(struct nrf_cloud_fota_poll_ctx *ctx,
122122
nrf_cloud_download_cancel();
123123
}
124124

125+
nrf_cloud_coap_fota_job_free(&job);
125126
return;
126127
}
127128

@@ -134,7 +135,14 @@ static void cancel_if_job_is_not_valid(struct nrf_cloud_fota_poll_ctx *ctx, uint
134135
int err;
135136
struct nrf_cloud_fota_job_info job_current = {0};
136137
static uint32_t last_progress_threshold;
137-
uint32_t current_progress_threshold = ROUND_DOWN(progress, threshold);
138+
uint32_t current_progress_threshold;
139+
140+
if (threshold == 0) {
141+
/* Progress checks are disabled */
142+
return;
143+
}
144+
145+
current_progress_threshold = ROUND_DOWN(progress, threshold);
138146

139147
if ((current_progress_threshold != last_progress_threshold) &&
140148
(current_progress_threshold != 0)) {
@@ -145,9 +153,10 @@ static void cancel_if_job_is_not_valid(struct nrf_cloud_fota_poll_ctx *ctx, uint
145153
if (err == 1) {
146154
LOG_ERR("No job available, canceling...");
147155

148-
nrf_cloud_coap_fota_job_free(&job_current);
149156
k_work_schedule(&ctx->cancel_work, K_SECONDS(1));
150157
}
158+
159+
nrf_cloud_coap_fota_job_free(&job_current);
151160
}
152161
}
153162

@@ -200,6 +209,7 @@ static void fota_dl_handler(const struct fota_download_evt *evt)
200209
ctx_ptr->status_fn(fota_status, fota_status_details);
201210

202211
(void)update_job_status(ctx_ptr);
212+
nrf_cloud_coap_fota_job_free(&job);
203213
} else {
204214
k_sem_give(&fota_download_sem);
205215
}
@@ -221,12 +231,14 @@ static void fota_dl_handler(const struct fota_download_evt *evt)
221231
ctx_ptr->status_fn(fota_status, fota_status_details);
222232

223233
(void)update_job_status(ctx_ptr);
234+
nrf_cloud_coap_fota_job_free(&job);
224235
}
225236
break;
226237
case FOTA_DOWNLOAD_EVT_PROGRESS:
227238
LOG_DBG("FOTA download percent: %d%%", evt->progress);
228239

229-
cancel_if_job_is_not_valid(ctx_ptr, evt->progress, 10);
240+
cancel_if_job_is_not_valid(ctx_ptr, evt->progress,
241+
CONFIG_NRF_CLOUD_FOTA_POLL_JOB_CHECK_PROGRESS_THRESHOLD);
230242
break;
231243
default:
232244
break;
@@ -605,6 +617,8 @@ int nrf_cloud_fota_poll_update_apply(struct nrf_cloud_fota_poll_ctx *ctx)
605617
{
606618
int err = handle_downloaded_image(ctx, false);
607619

620+
nrf_cloud_coap_fota_job_free(&job);
621+
608622
if (err) {
609623
LOG_ERR("handle_downloaded_image, error: %d", err);
610624
return err;
@@ -642,6 +656,7 @@ int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx)
642656
return err;
643657
} else if (err < 0) {
644658
LOG_ERR("Failed to check for FOTA job, error: %d", err);
659+
nrf_cloud_coap_fota_job_free(&job);
645660
return IS_RECOVERABLE_NETWORK_ERR(err) ? err : -ENOTRECOVERABLE;
646661
} else if (err > 0) {
647662
/* No job. */
@@ -655,6 +670,7 @@ int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx)
655670
err = start_download();
656671
if (err) {
657672
LOG_ERR("Failed to start FOTA download");
673+
nrf_cloud_coap_fota_job_free(&job);
658674
return -ENOTRECOVERABLE;
659675
}
660676

@@ -680,6 +696,7 @@ int nrf_cloud_fota_poll_process(struct nrf_cloud_fota_poll_ctx *ctx)
680696
*/
681697
if (fota_status == NRF_CLOUD_FOTA_SUCCEEDED) {
682698
handle_downloaded_image(ctx, true);
699+
nrf_cloud_coap_fota_job_free(&job);
683700
/* Application was expected to reboot... */
684701
return -EBUSY;
685702
}

0 commit comments

Comments
 (0)