updated: only fetch on metered connection when necessary (#31041)

* updated: only fetch on metered connection when necessary

* button always fetches
This commit is contained in:
Adeeb Shihadeh 2024-01-17 16:30:08 -08:00 committed by GitHub
parent d36103791c
commit 4c2bb9f380
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 16 deletions

View File

@ -161,6 +161,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"NavPastDestinations", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT},
{"NavSettingTime24h", PERSISTENT},
{"NetworkMetered", PERSISTENT},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
@ -201,6 +202,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterState", CLEAR_ON_MANAGER_START},
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
{"UpdaterLastFetchTime", PERSISTENT},
{"Version", PERSISTENT},
{"VisionRadarToggle", PERSISTENT},
{"WheeledBody", PERSISTENT},

View File

@ -447,6 +447,8 @@ def thermald_thread(end_event, hw_queue) -> None:
except Exception:
cloudlog.exception("failed to save offroad status")
params.put_bool_nonblocking("NetworkMetered", (msg.deviceState.networkType != NetworkType.wifi))
count += 1
should_start_prev = should_start

View File

@ -35,26 +35,42 @@ OVERLAY_INIT = Path(os.path.join(BASEDIR, ".overlay_init"))
DAYS_NO_CONNECTIVITY_MAX = 14 # do not allow to engage after this many days
DAYS_NO_CONNECTIVITY_PROMPT = 10 # send an offroad prompt after this many days
class UserRequest:
NONE = 0
CHECK = 1
FETCH = 2
class WaitTimeHelper:
def __init__(self):
self.ready_event = threading.Event()
self.only_check_for_update = False
self.user_request = UserRequest.NONE
signal.signal(signal.SIGHUP, self.update_now)
signal.signal(signal.SIGUSR1, self.check_now)
def update_now(self, signum: int, frame) -> None:
cloudlog.info("caught SIGHUP, attempting to downloading update")
self.only_check_for_update = False
self.user_request = UserRequest.FETCH
self.ready_event.set()
def check_now(self, signum: int, frame) -> None:
cloudlog.info("caught SIGUSR1, checking for updates")
self.only_check_for_update = True
self.user_request = UserRequest.CHECK
self.ready_event.set()
def sleep(self, t: float) -> None:
self.ready_event.wait(timeout=t)
def write_time_to_param(params, param) -> None:
t = datetime.datetime.utcnow()
params.put(param, t.isoformat().encode('utf8'))
def read_time_from_param(params, param) -> Optional[datetime.datetime]:
t = params.get(param, encoding='utf8')
try:
return datetime.datetime.fromisoformat(t)
except (TypeError, ValueError):
pass
return None
def run(cmd: List[str], cwd: Optional[str] = None) -> str:
return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8')
@ -266,14 +282,11 @@ class Updater:
last_update = datetime.datetime.utcnow()
if update_success:
t = last_update.isoformat()
self.params.put("LastUpdateTime", t.encode('utf8'))
write_time_to_param(self.params, "LastUpdateTime")
else:
try:
t = self.params.get("LastUpdateTime", encoding='utf8')
last_update = datetime.datetime.fromisoformat(t)
except (TypeError, ValueError):
pass
t = read_time_from_param(self.params, "LastUpdateTime")
if t is not None:
last_update = t
if exception is None:
self.params.remove("LastUpdateException")
@ -421,10 +434,7 @@ def main() -> None:
updater = Updater()
update_failed_count = 0 # TODO: Load from param?
# no fetch on the first time
wait_helper = WaitTimeHelper()
wait_helper.only_check_for_update = True
# invalidate old finalized update
set_consistent_flag(False)
@ -458,10 +468,16 @@ def main() -> None:
updater.check_for_update()
# download update
if wait_helper.only_check_for_update:
cloudlog.info("skipping fetch this cycle")
last_fetch = read_time_from_param(params, "UpdaterLastFetchTime")
timed_out = last_fetch is None or (datetime.datetime.utcnow() - last_fetch > datetime.timedelta(days=3))
user_requested_fetch = wait_helper.user_request == UserRequest.FETCH
if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch:
cloudlog.info("skipping fetch, connection metered")
elif wait_helper.user_request == UserRequest.CHECK:
cloudlog.info("skipping fetch, only checking")
else:
updater.fetch_update()
write_time_to_param(params, "UpdaterLastFetchTime")
update_failed_count = 0
except subprocess.CalledProcessError as e:
cloudlog.event(
@ -485,7 +501,7 @@ def main() -> None:
cloudlog.exception("uncaught updated exception while setting params, shouldn't happen")
# infrequent attempts if we successfully updated recently
wait_helper.only_check_for_update = False
wait_helper.user_request = UserRequest.NONE
wait_helper.sleep(5*60 if update_failed_count > 0 else 1.5*60*60)