diff --git a/auth/src/desktop/auth_desktop.cc b/auth/src/desktop/auth_desktop.cc index 99ae3419bf..fe4764de63 100644 --- a/auth/src/desktop/auth_desktop.cc +++ b/auth/src/desktop/auth_desktop.cc @@ -14,6 +14,7 @@ #include "auth/src/desktop/auth_desktop.h" +#include #include #include #include @@ -92,6 +93,19 @@ void* CreatePlatformAuth(App* const app) { AuthImpl* const auth = new AuthImpl(); auth->api_key = app->options().api_key(); auth->app_name = app->name(); + + // Check environment variables for emulator if set. + if (std::getenv("USE_AUTH_EMULATOR") != nullptr) { + auth->assigned_emulator_url.append(kEmulatorLocalHost); + auth->assigned_emulator_url.append(":"); + if (std::getenv("AUTH_EMULATOR_PORT") == nullptr) { + auth->assigned_emulator_url.append(kEmulatorPort); + } else { + auth->assigned_emulator_url.append(std::getenv("AUTH_EMULATOR_PORT")); + } + LogInfo("Using Auth Emulator: %s", auth->assigned_emulator_url.c_str()); + } + return auth; } @@ -576,6 +590,7 @@ void Auth::UseEmulator(std::string host, uint32_t port) { auth_impl->assigned_emulator_url.append(host); auth_impl->assigned_emulator_url.append(":"); auth_impl->assigned_emulator_url.append(std::to_string(port)); + LogInfo("Using Auth Emulator: %s", auth_impl->assigned_emulator_url.c_str()); } void InitializeTokenRefresher(AuthData* auth_data) { @@ -667,6 +682,8 @@ void IdTokenRefreshThread::Initialize(AuthData* auth_data) { thread_ = firebase::Thread( [](IdTokenRefreshThread* refresh_thread) { Auth* auth = refresh_thread->auth; + int retry_backoff_ms = kMinRetryBackoffMs; + while (!refresh_thread->is_shutting_down()) { // Note: Make sure to always make future_impl.mutex the innermost // lock, to prevent deadlocks! @@ -700,8 +717,21 @@ void IdTokenRefreshThread::Initialize(AuthData* auth_data) { // is completed. future_sem.Wait(); - // (We don't actually care about the results of the token request. - // The token listener will handle that.) + if (future.error() != 0) { + // Token refresh failed (e.g. network outage). Wait with + // exponential backoff to prevent tight retry loops and avoid + // overloading backend servers upon reconnect. Matches Android + // DefaultTokenRefresher (30s initial, doubling up to 16m max). + if (!refresh_thread->is_shutting_down()) { + refresh_thread->wakeup_sem_.TimedWait(retry_backoff_ms); + retry_backoff_ms = + std::min(kMaxRetryBackoffMs, retry_backoff_ms * 2); + } + continue; + } else { + // Refresh succeeded! Reset backoff to minimum interval. + retry_backoff_ms = kMinRetryBackoffMs; + } } else { auth->auth_data_->future_impl.mutex().Release(); refresh_thread->ref_count_mutex_.Release(); diff --git a/auth/src/desktop/auth_desktop.h b/auth/src/desktop/auth_desktop.h index 42309ee0cb..7aa5e8a0bb 100644 --- a/auth/src/desktop/auth_desktop.h +++ b/auth/src/desktop/auth_desktop.h @@ -179,6 +179,9 @@ struct AuthImpl { const int kMinutesPerTokenRefresh = 58; const int kMsPerTokenRefresh = kMinutesPerTokenRefresh * internal::kMillisecondsPerMinute; +// Exponential backoff parameters when token refresh fails (e.g. network outage), matching Android DefaultTokenRefresher. +const int kMinRetryBackoffMs = 30 * 1000; // 30 seconds base delay +const int kMaxRetryBackoffMs = 16 * 60 * 1000; // 16 minutes max delay void InitializeUserDataPersist(AuthData* auth_data); void DestroyUserDataPersist(AuthData* auth_data); diff --git a/auth/src/desktop/rpcs/auth_request.cc b/auth/src/desktop/rpcs/auth_request.cc index 4d50cf0ddc..a59fbb6927 100644 --- a/auth/src/desktop/rpcs/auth_request.cc +++ b/auth/src/desktop/rpcs/auth_request.cc @@ -42,8 +42,6 @@ const char* kHeaderFirebaseLocale = "X-Firebase-Locale"; AuthRequest::AuthRequest(::firebase::App& app, const char* schema, bool deliver_heartbeat) : RequestJson(schema), app(app) { - CheckEnvEmulator(); - if (deliver_heartbeat) { std::shared_ptr heartbeat_controller = app.GetHeartbeatController(); @@ -76,52 +74,23 @@ AuthRequest::AuthRequest(::firebase::App& app, const char* schema, } std::string AuthRequest::GetUrl() { - std::string emulator_url; Auth* auth_ptr = Auth::GetAuth(&app); std::string assigned_emulator_url = static_cast(auth_ptr->auth_data_->auth_impl) ->assigned_emulator_url; - if (assigned_emulator_url.empty()) { - emulator_url = env_emulator_url; - } else { - emulator_url = assigned_emulator_url; - } - if (emulator_url.empty()) { + if (assigned_emulator_url.empty()) { std::string url(kHttps); url += kServerURL; return url; } else { std::string url(kHttp); - url += emulator_url; + url += assigned_emulator_url; url += "/"; url += kServerURL; return url; } } -void AuthRequest::CheckEnvEmulator() { - if (!env_emulator_url.empty()) { - LogInfo("Environment Emulator Url already set: %s", - env_emulator_url.c_str()); - return; - } - - // Use emulator as long as this env variable is set, regardless its value. - if (std::getenv("USE_AUTH_EMULATOR") == nullptr) { - LogInfo("USE_AUTH_EMULATOR not set."); - return; - } - env_emulator_url.append(kEmulatorLocalHost); - env_emulator_url.append(":"); - // Use AUTH_EMULATOR_PORT if it is set to non empty string, - // otherwise use the default port. - if (std::getenv("AUTH_EMULATOR_PORT") == nullptr) { - env_emulator_url.append(kEmulatorPort); - } else { - env_emulator_url.append(std::getenv("AUTH_EMULATOR_PORT")); - } -} - } // namespace auth } // namespace firebase diff --git a/auth/src/desktop/rpcs/auth_request.h b/auth/src/desktop/rpcs/auth_request.h index 889e04aea7..fe14e1c96b 100644 --- a/auth/src/desktop/rpcs/auth_request.h +++ b/auth/src/desktop/rpcs/auth_request.h @@ -55,8 +55,6 @@ class AuthRequest std::string GetUrl(); private: - void CheckEnvEmulator(); - std::string env_emulator_url; ::firebase::App& app; }; diff --git a/release_build_files/readme.md b/release_build_files/readme.md index 22bbebc02e..e199de85cc 100644 --- a/release_build_files/readme.md +++ b/release_build_files/readme.md @@ -615,6 +615,7 @@ code. ## Release Notes ### Upcoming - Changes + - Auth (Desktop): Fixed log spam and high CPU utilization when offline by moving `USE_AUTH_EMULATOR` environment variable check to initialization and eliminating per-request logging (#1629). - Realtime Database (Desktop): Fixed an intermittent use-after-free crash (`ACCESS_VIOLATION`) when detaching a listener while a WebSocket listen response is pending. ### 13.10.0