diff --git a/app/src/util.cc b/app/src/util.cc index 1504c3f2fe..a9bf03651a 100644 --- a/app/src/util.cc +++ b/app/src/util.cc @@ -342,5 +342,21 @@ std::vector SplitString(const std::string& s, return split_parts; } +// Id used as part of the logic to make unique api identifiers. +static int g_api_identifier_count = 0; + +std::string CreateApiIdentifier(const char* api_id, void* object) { + std::string created; + const char* format = "%s0x%016llx_%d"; + unsigned long long object_ptr = // NOLINT + static_cast( // NOLINT + reinterpret_cast(object)); + int extra_id = g_api_identifier_count++; + int size = snprintf(nullptr, 0, format, api_id, object_ptr, extra_id) + 1; + created.reserve(size); + snprintf(&(created[0]), size, format, api_id, object_ptr, extra_id); + return created; +} + // NOLINTNEXTLINE - allow namespace overridden } // namespace firebase diff --git a/app/src/util.h b/app/src/util.h index 54e9f48798..f25817a209 100644 --- a/app/src/util.h +++ b/app/src/util.h @@ -238,7 +238,11 @@ class StaticFutureData { // delimiter. Returns a vector of constituent parts. std::vector SplitString(const std::string& s, char delimiter); -// NOLINTNEXTLINE - allow namespace overridden +// Helper function to combine a string and other object into a unique +// identifier. Primarily used to manage listening to JNI Tasks on Android. +// Note that repeated calls are expected to return different values. +std::string CreateApiIdentifier(const char* api_id, void* object); + } // namespace firebase #endif // FIREBASE_APP_SRC_UTIL_H_ diff --git a/app/tests/util_test.cc b/app/tests/util_test.cc index 90bca1ba20..c0fc858942 100644 --- a/app/tests/util_test.cc +++ b/app/tests/util_test.cc @@ -54,5 +54,17 @@ TEST(UtilTest, SplitStringDelimetersOnly) { EXPECT_THAT(SplitString("///", '/'), IsEmpty()); } +TEST(UtilTest, CreateApiIdentifierUnique) { + int v1, v2; + EXPECT_STRNE(CreateApiIdentifier("Test", &v1).c_str(), + CreateApiIdentifier("Test", &v2).c_str()); +} + +TEST(UtilTest, CreateApiIdentifierReallyUnique) { + int v1; + EXPECT_STRNE(CreateApiIdentifier("Test", &v1).c_str(), + CreateApiIdentifier("Test", &v1).c_str()); +} + } // namespace } // namespace firebase diff --git a/app_check/src/android/app_check_android.cc b/app_check/src/android/app_check_android.cc index a565fb8e28..f7295d525a 100644 --- a/app_check/src/android/app_check_android.cc +++ b/app_check/src/android/app_check_android.cc @@ -21,6 +21,7 @@ #include "app/src/include/firebase/future.h" #include "app/src/include/firebase/internal/mutex.h" #include "app/src/reference_counted_future_impl.h" +#include "app/src/util.h" #include "app/src/util_android.h" #include "app_check/app_check_resources.h" #include "app_check/src/android/common_android.h" @@ -135,8 +136,6 @@ static const JNINativeMethod kNativeJniAppCheckListenerMethods[] = { reinterpret_cast(JniAppCheckListener_nativeOnAppCheckTokenChanged)}, }; -static const char* kApiIdentifier = "AppCheck"; - static AppCheckProviderFactory* g_provider_factory = nullptr; static int g_initialized_count = 0; @@ -306,6 +305,9 @@ AppCheckInternal::AppCheckInternal(App* app) : app_(app) { g_initialized_count++; } + static const char* kApiIdentifier = "AppCheck"; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); + // Create the FirebaseAppCheck class in Java. jobject platform_app = app->GetPlatformApp(); jobject j_app_check_local = env->CallStaticObjectMethod( @@ -364,6 +366,7 @@ AppCheckInternal::~AppCheckInternal() { JNIEnv* env = app_->GetJNIEnv(); app_ = nullptr; listeners_.clear(); + util::CancelCallbacks(env, jni_task_id_.c_str()); if (j_app_check_listener_ != nullptr) { env->CallVoidMethod( @@ -393,7 +396,6 @@ AppCheckInternal::~AppCheckInternal() { FIREBASE_ASSERT(g_initialized_count); g_initialized_count--; if (g_initialized_count == 0) { - util::CancelCallbacks(env, kApiIdentifier); ReleaseClasses(env); util::Terminate(env); } @@ -435,7 +437,7 @@ Future AppCheckInternal::GetAppCheckToken(bool force_refresh) { auto data_handle = new FutureDataHandle(future(), handle); util::RegisterCallbackOnTask(env, j_task, TokenResultCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } else { AppCheckToken empty_token; future()->CompleteWithResult(handle, kAppCheckErrorUnknown, error.c_str(), diff --git a/app_check/src/android/app_check_android.h b/app_check/src/android/app_check_android.h index b0ef767e2b..22c30259a1 100644 --- a/app_check/src/android/app_check_android.h +++ b/app_check/src/android/app_check_android.h @@ -15,6 +15,7 @@ #ifndef FIREBASE_APP_CHECK_SRC_ANDROID_APP_CHECK_ANDROID_H_ #define FIREBASE_APP_CHECK_SRC_ANDROID_APP_CHECK_ANDROID_H_ +#include #include #include "app/src/future_manager.h" @@ -70,6 +71,9 @@ class AppCheckInternal { Mutex listeners_mutex_; FutureManager future_manager_; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/app_check/src/android/common_android.cc b/app_check/src/android/common_android.cc index 4dbafb62c1..2bae6cf878 100644 --- a/app_check/src/android/common_android.cc +++ b/app_check/src/android/common_android.cc @@ -17,6 +17,7 @@ #include #include "app/src/app_common.h" +#include "app/src/util.h" #include "app/src/util_android.h" #include "app_check/src/include/firebase/app_check.h" @@ -45,8 +46,6 @@ METHOD_LOOKUP_DEFINITION(app_check_token, "com/google/firebase/appcheck/AppCheckToken", APP_CHECK_TOKEN_METHODS) -static const char* kApiIdentifier = "AppCheckProvider"; - bool CacheCommonAndroidMethodIds(JNIEnv* env, jobject activity) { // Cache the token and provider classes. if (!(app_check_token::CacheMethodIds(env, activity) && @@ -124,12 +123,15 @@ void TokenResultCallback(JNIEnv* env, jobject result, AndroidAppCheckProvider::AndroidAppCheckProvider(jobject local_provider) : android_provider_(nullptr) { + static const char* kApiIdentifier = "AppCheckProvider"; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); JNIEnv* env = GetJniEnv(); android_provider_ = env->NewGlobalRef(local_provider); } AndroidAppCheckProvider::~AndroidAppCheckProvider() { JNIEnv* env = GetJniEnv(); + util::CancelCallbacks(env, jni_task_id_.c_str()); if (env != nullptr && android_provider_ != nullptr) { env->DeleteGlobalRef(android_provider_); } @@ -150,7 +152,8 @@ void AndroidAppCheckProvider::GetToken( new TokenResultCallbackData(completion_callback); util::RegisterCallbackOnTask( env, j_task, TokenResultCallback, - reinterpret_cast(completion_callback_data), kApiIdentifier); + reinterpret_cast(completion_callback_data), + jni_task_id_.c_str()); } else { AppCheckToken empty_token; completion_callback(empty_token, kAppCheckErrorUnknown, error.c_str()); diff --git a/app_check/src/android/common_android.h b/app_check/src/android/common_android.h index 0ae65a9176..bd8ca8ec4a 100644 --- a/app_check/src/android/common_android.h +++ b/app_check/src/android/common_android.h @@ -61,6 +61,9 @@ class AndroidAppCheckProvider : public AppCheckProvider { private: jobject android_provider_; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/auth/src/auth.cc b/auth/src/auth.cc index 979d5a6fd2..88aae1a37f 100644 --- a/auth/src/auth.cc +++ b/auth/src/auth.cc @@ -111,15 +111,8 @@ Auth::Auth(App* app, void* auth_impl) : auth_data_(new AuthData) { auth_data_->user_impl = nullptr; InitPlatformAuth(auth_data_); - std::string* future_id = &auth_data_->future_api_id; static const char* kApiIdentifier = "Auth"; - future_id->reserve(strlen(kApiIdentifier) + - 16 /* hex characters in the pointer */ + - 1 /* null terminator */); - snprintf(&((*future_id)[0]), future_id->capacity(), "%s0x%016llx", - kApiIdentifier, - static_cast( // NOLINT - reinterpret_cast(this))); + auth_data_->future_api_id = CreateApiIdentifier(kApiIdentifier, this); // Cleanup this object if app is destroyed. CleanupNotifier* notifier = CleanupNotifier::FindByOwner(app); diff --git a/database/src/android/database_android.cc b/database/src/android/database_android.cc index 2b67134930..ee5d72051a 100644 --- a/database/src/android/database_android.cc +++ b/database/src/android/database_android.cc @@ -24,6 +24,7 @@ #include "app/src/include/firebase/internal/common.h" #include "app/src/include/firebase/log.h" #include "app/src/reference_counted_future_impl.h" +#include "app/src/util.h" #include "app/src/util_android.h" #include "database/database_resources.h" #include "database/src/android/data_snapshot_android.h" @@ -172,6 +173,7 @@ DatabaseInternal::DatabaseInternal(App* app) app_ = nullptr; if (!Initialize(app)) return; app_ = app; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); JNIEnv* env = app_->GetJNIEnv(); jobject platform_app = app->GetPlatformApp(); @@ -198,6 +200,7 @@ DatabaseInternal::DatabaseInternal(App* app, const char* url) app_ = nullptr; if (!Initialize(app)) return; app_ = app; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); JNIEnv* env = app_->GetJNIEnv(); jobject url_string = env->NewStringUTF(url); @@ -399,6 +402,7 @@ DatabaseInternal::~DatabaseInternal() { cleanup_.CleanupAll(); JNIEnv* env = app_->GetJNIEnv(); + util::CancelCallbacks(env, jni_task_id_.c_str()); { // If there are any pending listeners, delete their pointers. MutexLock lock(listener_mutex_); diff --git a/database/src/android/database_android.h b/database/src/android/database_android.h index 7747d3b4a2..5056e41ed4 100644 --- a/database/src/android/database_android.h +++ b/database/src/android/database_android.h @@ -19,6 +19,7 @@ #include #include +#include #include #include "app/src/cleanup_notifier.h" @@ -42,10 +43,6 @@ namespace internal { // For constructing, copying or moving DatabaseReferences atomically. extern Mutex g_database_reference_constructor_mutex; -// Used for registering global callbacks. See -// firebase::util::RegisterCallbackOnTask for context. -extern const char kApiIdentifier[]; - // This is the Android implementation of Database. class DatabaseInternal { public: @@ -183,6 +180,10 @@ class DatabaseInternal { Logger* logger() { return &logger_; } + // Used for registering global callbacks. See + // firebase::util::RegisterCallbackOnTask for context. + const char* jni_task_id() { return jni_task_id_.c_str(); } + private: static bool Initialize(App* app); static void ReleaseClasses(App* app); @@ -222,6 +223,9 @@ class DatabaseInternal { std::string constructor_url_; Logger logger_; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/database/src/android/database_reference_android.cc b/database/src/android/database_reference_android.cc index dafa606dc4..d3d3947068 100644 --- a/database/src/android/database_reference_android.cc +++ b/database/src/android/database_reference_android.cc @@ -329,7 +329,7 @@ Future DatabaseReferenceInternal::RemoveValue() { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast( new FutureCallbackData(handle, ref_future(), db_)), - kApiIdentifier); + db_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); return MakeFuture(ref_future(), handle); @@ -358,7 +358,7 @@ Future DatabaseReferenceInternal::SetValue(Variant value) { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast( new FutureCallbackData(handle, ref_future(), db_)), - kApiIdentifier); + db_->jni_task_id()); env->DeleteLocalRef(task); if (value_obj) env->DeleteLocalRef(value_obj); } @@ -391,7 +391,7 @@ Future DatabaseReferenceInternal::SetPriority(Variant priority) { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast( new FutureCallbackData(handle, ref_future(), db_)), - kApiIdentifier); + db_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); if (priority_obj) env->DeleteLocalRef(priority_obj); @@ -432,7 +432,7 @@ Future DatabaseReferenceInternal::SetValueAndPriority(Variant value, // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast( new FutureCallbackData(handle, ref_future(), db_)), - kApiIdentifier); + db_->jni_task_id()); env->DeleteLocalRef(task); if (value_obj) env->DeleteLocalRef(value_obj); if (priority_obj) env->DeleteLocalRef(priority_obj); @@ -464,7 +464,7 @@ Future DatabaseReferenceInternal::UpdateChildren(Variant values) { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast( new FutureCallbackData(handle, ref_future(), db_)), - kApiIdentifier); + db_->jni_task_id()); env->DeleteLocalRef(task); if (values_obj) env->DeleteLocalRef(values_obj); } diff --git a/database/src/android/disconnection_android.cc b/database/src/android/disconnection_android.cc index 4ef5a75e6a..af59c1e2b6 100644 --- a/database/src/android/disconnection_android.cc +++ b/database/src/android/disconnection_android.cc @@ -120,7 +120,7 @@ Future DisconnectionHandlerInternal::Cancel() { env, task, FutureCallback, // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData(handle, future(), db_)), - kApiIdentifier); + db_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); return MakeFuture(future(), handle); @@ -141,7 +141,7 @@ Future DisconnectionHandlerInternal::RemoveValue() { env, task, FutureCallback, // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData(handle, future(), db_)), - kApiIdentifier); + db_->jni_task_id()); util::CheckAndClearJniExceptions(env); return MakeFuture(future(), handle); } @@ -166,7 +166,7 @@ Future DisconnectionHandlerInternal::SetValue(Variant value) { env, task, FutureCallback, // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData(handle, future(), db_)), - kApiIdentifier); + db_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); if (value_obj) env->DeleteLocalRef(value_obj); @@ -211,7 +211,7 @@ Future DisconnectionHandlerInternal::SetValueAndPriority( env, task, FutureCallback, // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData(handle, future(), db_)), - kApiIdentifier); + db_->jni_task_id()); env->DeleteLocalRef(task); if (value_obj) env->DeleteLocalRef(value_obj); } @@ -240,7 +240,7 @@ Future DisconnectionHandlerInternal::UpdateChildren(Variant values) { env, task, FutureCallback, // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData(handle, future(), db_)), - kApiIdentifier); + db_->jni_task_id()); env->DeleteLocalRef(task); if (values_obj) env->DeleteLocalRef(values_obj); } diff --git a/functions/src/android/callable_reference_android.cc b/functions/src/android/callable_reference_android.cc index 75618f41ac..18c31f7225 100644 --- a/functions/src/android/callable_reference_android.cc +++ b/functions/src/android/callable_reference_android.cc @@ -188,7 +188,7 @@ Future HttpsCallableReferenceInternal::Call() { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData( handle, future(), functions_, kCallableReferenceFnCall)), - kApiIdentifier); + functions_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); @@ -219,7 +219,7 @@ Future HttpsCallableReferenceInternal::Call( // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData( handle, future(), functions_, kCallableReferenceFnCall)), - kApiIdentifier); + functions_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); diff --git a/functions/src/android/functions_android.cc b/functions/src/android/functions_android.cc index 7bdc6fe244..619cd7d02d 100644 --- a/functions/src/android/functions_android.cc +++ b/functions/src/android/functions_android.cc @@ -17,6 +17,7 @@ #include #include "app/src/include/firebase/app.h" +#include "app/src/util.h" #include "app/src/util_android.h" #include "functions/src/android/callable_reference_android.h" @@ -24,8 +25,6 @@ namespace firebase { namespace functions { namespace internal { -const char kApiIdentifier[] = "Functions"; - // clang-format off #define FIREBASE_FUNCTIONS_METHODS(X) \ X(GetInstance, "getInstance", \ @@ -86,6 +85,8 @@ FunctionsInternal::FunctionsInternal(App* app, const char* region) app_ = nullptr; if (!Initialize(app)) return; app_ = app; + const char kApiIdentifier[] = "Functions"; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); JNIEnv* env = app_->GetJNIEnv(); jstring region_str = env->NewStringUTF(region); jobject platform_app = app_->GetPlatformApp(); @@ -106,6 +107,7 @@ FunctionsInternal::~FunctionsInternal() { if (app_ == nullptr) return; JNIEnv* env = app_->GetJNIEnv(); + util::CancelCallbacks(env, jni_task_id_.c_str()); env->DeleteGlobalRef(obj_); obj_ = nullptr; Terminate(app_); diff --git a/functions/src/android/functions_android.h b/functions/src/android/functions_android.h index 416a404798..3c57248c02 100644 --- a/functions/src/android/functions_android.h +++ b/functions/src/android/functions_android.h @@ -19,6 +19,7 @@ #include #include +#include #include "app/src/cleanup_notifier.h" #include "app/src/future_manager.h" @@ -34,10 +35,6 @@ namespace firebase { namespace functions { namespace internal { -// Used for registering global callbacks. See -// firebase::util::RegisterCallbackOnTask for context. -extern const char kApiIdentifier[]; - class FunctionsInternal { public: // Build a Functions. @@ -77,6 +74,10 @@ class FunctionsInternal { // objects. CleanupNotifier& cleanup() { return cleanup_; } + // Used for registering global callbacks. See + // firebase::util::RegisterCallbackOnTask for context. + const char* jni_task_id() { return jni_task_id_.c_str(); } + private: // Initialize JNI for all classes. static bool Initialize(App* app); @@ -97,6 +98,9 @@ class FunctionsInternal { FutureManager future_manager_; CleanupNotifier cleanup_; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/installations/src/android/installations_android.cc b/installations/src/android/installations_android.cc index 1a7dd0b9ae..73344b19ce 100644 --- a/installations/src/android/installations_android.cc +++ b/installations/src/android/installations_android.cc @@ -57,8 +57,6 @@ using firebase::internal::ReferenceCountLock; ReferenceCount internal::InstallationsInternal::initializer_; // NOLINT -static const char* kApiIdentifier = "Installations"; - template struct FISDataHandle { FISDataHandle(ReferenceCountedFutureImpl* _future_api, @@ -138,6 +136,7 @@ void TokenResultCallback(JNIEnv* env, jobject result, InstallationsInternal::InstallationsInternal(const firebase::App& app) : app_(app), future_impl_(kInstallationsFnCount) { ReferenceCountLock lock(&initializer_); + static const char* kApiIdentifier = "Installations"; LogDebug("%s API Initializing", kApiIdentifier); JNIEnv* env = app_.GetJNIEnv(); @@ -158,7 +157,9 @@ InstallationsInternal::InstallationsInternal(const firebase::App& app) } } - // Create the remote config class. + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); + + // Create the underlying Installations java object. jobject platform_app = app_.GetPlatformApp(); jclass installations_class = installations::GetClass(); @@ -172,7 +173,10 @@ InstallationsInternal::InstallationsInternal(const firebase::App& app) LogDebug("%s API Initialized", kApiIdentifier); } -InstallationsInternal::~InstallationsInternal() {} +InstallationsInternal::~InstallationsInternal() { + JNIEnv* env = app_.GetJNIEnv(); + util::CancelCallbacks(env, jni_task_id_.c_str()); +} bool InstallationsInternal::Initialized() const { return internal_obj_ != nullptr; @@ -212,7 +216,7 @@ Future InstallationsInternal::GetId() { util::RegisterCallbackOnTask(env, task, StringResultCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); env->DeleteLocalRef(task); @@ -237,7 +241,7 @@ Future InstallationsInternal::GetToken(bool forceRefresh) { util::RegisterCallbackOnTask(env, task, TokenResultCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); env->DeleteLocalRef(task); @@ -259,7 +263,7 @@ Future InstallationsInternal::Delete() { util::RegisterCallbackOnTask(env, task, CompleteVoidCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); env->DeleteLocalRef(task); diff --git a/installations/src/android/installations_android.h b/installations/src/android/installations_android.h index 46d0c17c65..d709d378ea 100644 --- a/installations/src/android/installations_android.h +++ b/installations/src/android/installations_android.h @@ -15,6 +15,8 @@ #ifndef FIREBASE_INSTALLATIONS_SRC_ANDROID_INSTALLATIONS_ANDROID_H_ #define FIREBASE_INSTALLATIONS_SRC_ANDROID_INSTALLATIONS_ANDROID_H_ +#include + #include "app/src/reference_count.h" #include "app/src/reference_counted_future_impl.h" #include "app/src/util_android.h" @@ -60,6 +62,9 @@ class InstallationsInternal { ReferenceCountedFutureImpl future_impl_; jobject internal_obj_; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/remote_config/src/android/remote_config_android.cc b/remote_config/src/android/remote_config_android.cc index 4615e7bbe6..75cf4e208f 100644 --- a/remote_config/src/android/remote_config_android.cc +++ b/remote_config/src/android/remote_config_android.cc @@ -225,8 +225,6 @@ static const ValueSource kFirebaseRemoteConfigSourceToValueSourceMap[] = { kValueSourceRemoteValue, // FirebaseRemoteConfig.VALUE_SOURCE_REMOTE (2) }; -static const char* kApiIdentifier = "Remote Config"; - ReferenceCount RemoteConfigInternal::initializer_; // NOLINT static bool CacheJNIMethodIds( @@ -557,6 +555,8 @@ RemoteConfigInternal::RemoteConfigInternal(const firebase::App& app) : app_(app), future_impl_(kRemoteConfigFnCount) { ReferenceCountLock lock(&initializer_); LogDebug("Firebase RemoteConfig API Initializing"); + static const char* kApiIdentifier = "Remote Config"; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); JNIEnv* env = app_.GetJNIEnv(); if (lock.AddReference() == 0) { // Initialize @@ -602,6 +602,8 @@ RemoteConfigInternal::~RemoteConfigInternal() { // ConfigUpdateListenerRegistration instances to no longer point to the // corresponding internal objects. cleanup_notifier().CleanupAll(); + JNIEnv* env = app_.GetJNIEnv(); + util::CancelCallbacks(env, jni_task_id_.c_str()); } bool RemoteConfigInternal::Initialized() const { @@ -712,7 +714,7 @@ Future RemoteConfigInternal::EnsureInitialized() { util::RegisterCallbackOnTask(env, task, EnsureInitializedCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); return MakeFuture(&future_impl_, handle); @@ -736,7 +738,7 @@ Future RemoteConfigInternal::Activate() { auto data_handle = new RCDataHandle(&future_impl_, handle, this); util::RegisterCallbackOnTask(env, task, BoolResultCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); @@ -762,7 +764,7 @@ Future RemoteConfigInternal::FetchAndActivate() { auto data_handle = new RCDataHandle(&future_impl_, handle, this); util::RegisterCallbackOnTask(env, task, BoolResultCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); @@ -789,7 +791,7 @@ Future RemoteConfigInternal::Fetch(uint64_t cache_expiration_in_seconds) { util::RegisterCallbackOnTask(env, task, FetchCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); return MakeFuture(&future_impl_, handle); @@ -815,7 +817,7 @@ Future RemoteConfigInternal::SetDefaults(int defaults_resource_id) { auto data_handle = new RCDataHandle(&future_impl_, handle, this); util::RegisterCallbackOnTask(env, task, SetDefaultsCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); return MakeFuture(&future_impl_, handle); @@ -842,7 +844,7 @@ Future RemoteConfigInternal::SetDefaults( util::RegisterCallbackOnTask(env, task, SetDefaultsCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); env->DeleteLocalRef(hash_map); @@ -870,7 +872,7 @@ Future RemoteConfigInternal::SetDefaults(const ConfigKeyValue* defaults, util::RegisterCallbackOnTask(env, task, SetDefaultsCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); env->DeleteLocalRef(hash_map); @@ -933,7 +935,7 @@ Future RemoteConfigInternal::SetConfigSettings(ConfigSettings settings) { util::RegisterCallbackOnTask(env, task, CompleteVoidCallback, reinterpret_cast(data_handle), - kApiIdentifier); + jni_task_id_.c_str()); } env->DeleteLocalRef(task); } diff --git a/remote_config/src/android/remote_config_android.h b/remote_config/src/android/remote_config_android.h index fbf1f40754..c286002af4 100644 --- a/remote_config/src/android/remote_config_android.h +++ b/remote_config/src/android/remote_config_android.h @@ -15,6 +15,8 @@ #ifndef FIREBASE_REMOTE_CONFIG_SRC_ANDROID_REMOTE_CONFIG_ANDROID_H_ #define FIREBASE_REMOTE_CONFIG_SRC_ANDROID_REMOTE_CONFIG_ANDROID_H_ +#include + #include "app/meta/move.h" #include "app/src/cleanup_notifier.h" #include "app/src/include/firebase/internal/common.h" @@ -124,6 +126,9 @@ class RemoteConfigInternal { // If a fetch was throttled, this is set to the time when throttling is // finished, in milliseconds since epoch. int64_t throttled_end_time_ = 0; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/storage/src/android/storage_android.cc b/storage/src/android/storage_android.cc index 04d5123f72..c4d2c953cb 100644 --- a/storage/src/android/storage_android.cc +++ b/storage/src/android/storage_android.cc @@ -20,6 +20,7 @@ #include "app/src/embedded_file.h" #include "app/src/include/firebase/app.h" #include "app/src/include/firebase/internal/common.h" +#include "app/src/util.h" #include "app/src/util_android.h" #include "storage/src/android/controller_android.h" #include "storage/src/android/metadata_android.h" @@ -30,8 +31,6 @@ namespace firebase { namespace storage { namespace internal { -const char kApiIdentifier[] = "Storage"; - // clang-format off #define FIREBASE_STORAGE_METHODS(X) \ X(GetInstance, "getInstance", \ @@ -142,6 +141,8 @@ StorageInternal::StorageInternal(App* app, const char* url) { if (!Initialize(app)) return; app_ = app; url_ = url ? url : ""; + const char kApiIdentifier[] = "Storage"; + jni_task_id_ = CreateApiIdentifier(kApiIdentifier, this); JNIEnv* env = app_->GetJNIEnv(); jobject url_jstring = env->NewStringUTF(url_.c_str()); @@ -173,6 +174,7 @@ StorageInternal::~StorageInternal() { if (app_ == nullptr) return; JNIEnv* env = app_->GetJNIEnv(); + util::CancelCallbacks(env, jni_task_id_.c_str()); env->DeleteGlobalRef(obj_); obj_ = nullptr; Terminate(app_); diff --git a/storage/src/android/storage_android.h b/storage/src/android/storage_android.h index 94fe7d5c7d..4ed8774a47 100644 --- a/storage/src/android/storage_android.h +++ b/storage/src/android/storage_android.h @@ -19,6 +19,7 @@ #include #include +#include #include "app/src/cleanup_notifier.h" #include "app/src/future_manager.h" @@ -55,10 +56,6 @@ METHOD_LOOKUP_DECLARATION(cpp_byte_downloader, CPP_BYTE_DOWNLOADER_METHODS) // clang-format on METHOD_LOOKUP_DECLARATION(cpp_byte_uploader, CPP_BYTE_UPLOADER_METHODS) -// Used for registering global callbacks. See -// firebase::util::RegisterCallbackOnTask for context. -extern const char kApiIdentifier[]; - class StorageInternal { public: // Build a Storage. A nullptr or empty url uses the default getInstance. @@ -114,6 +111,10 @@ class StorageInternal { // objects. CleanupNotifier& cleanup() { return cleanup_; } + // Used for registering global callbacks. See + // firebase::util::RegisterCallbackOnTask for context. + const char* jni_task_id() { return jni_task_id_.c_str(); } + private: // Initialize JNI for all classes. static bool Initialize(App* app); @@ -135,6 +136,9 @@ class StorageInternal { std::string url_; CleanupNotifier cleanup_; + + // String to be used when registering for JNI task callbacks. + std::string jni_task_id_; }; } // namespace internal diff --git a/storage/src/android/storage_reference_android.cc b/storage/src/android/storage_reference_android.cc index 1ccbcd2c1c..99b9d40280 100644 --- a/storage/src/android/storage_reference_android.cc +++ b/storage/src/android/storage_reference_android.cc @@ -349,7 +349,7 @@ Future StorageReferenceInternal::Delete() { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData( handle, future(), storage_, kStorageReferenceFnDelete)), - kApiIdentifier); + storage_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); return DeleteLastResult(); @@ -391,7 +391,7 @@ Future StorageReferenceInternal::GetFile(const char* path, reinterpret_cast(new FutureCallbackData(handle, future(), storage_, kStorageReferenceFnGetFile, java_listener)), - kApiIdentifier); + storage_->jni_task_id()); if (controller_out) { controller_out->internal_->AssignTask(storage_, task); } @@ -454,7 +454,7 @@ Future StorageReferenceInternal::GetBytes(void* buffer, reinterpret_cast(new FutureCallbackData( handle, future(), storage_, kStorageReferenceFnGetBytes, java_listener, buffer, buffer_size, byte_downloader)), - kApiIdentifier); + storage_->jni_task_id()); if (controller_out) { controller_out->internal_->AssignTask(storage_, task); } @@ -480,7 +480,7 @@ Future StorageReferenceInternal::GetDownloadUrl() { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData( handle, future(), storage_, kStorageReferenceFnGetDownloadUrl)), - kApiIdentifier); + storage_->jni_task_id()); env->DeleteLocalRef(task); util::CheckAndClearJniExceptions(env); @@ -504,7 +504,7 @@ Future StorageReferenceInternal::GetMetadata() { // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData( handle, future(), storage_, kStorageReferenceFnGetMetadata)), - kApiIdentifier); + storage_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); return GetMetadataLastResult(); @@ -530,7 +530,7 @@ Future StorageReferenceInternal::UpdateMetadata( // FutureCallback will delete the newed FutureCallbackData. reinterpret_cast(new FutureCallbackData( handle, future(), storage_, kStorageReferenceFnUpdateMetadata)), - kApiIdentifier); + storage_->jni_task_id()); util::CheckAndClearJniExceptions(env); env->DeleteLocalRef(task); return UpdateMetadataLastResult(); @@ -607,7 +607,7 @@ Future StorageReferenceInternal::PutBytes( reinterpret_cast(new FutureCallbackData( handle, future_impl, storage_, kStorageReferenceFnPutBytes, java_listener, nullptr, 0, nullptr, env->NewGlobalRef(uploader))), - kApiIdentifier); + storage_->jni_task_id()); if (controller_out) controller_out->internal_->AssignTask(storage_, task); env->DeleteLocalRef(task); } @@ -641,7 +641,7 @@ Future StorageReferenceInternal::PutFile(const char* path, reinterpret_cast(new FutureCallbackData(handle, future(), storage_, kStorageReferenceFnPutFile, java_listener)), - kApiIdentifier); + storage_->jni_task_id()); if (controller_out) { controller_out->internal_->AssignTask(storage_, task); } @@ -672,7 +672,7 @@ Future StorageReferenceInternal::PutFile(const char* path, reinterpret_cast(new FutureCallbackData(handle, future(), storage_, kStorageReferenceFnPutFile, java_listener)), - kApiIdentifier); + storage_->jni_task_id()); if (controller_out) { controller_out->internal_->AssignTask(storage_, task); }