Skip to content
Merged
16 changes: 16 additions & 0 deletions app/src/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -342,5 +342,21 @@ std::vector<std::string> 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<unsigned long long>( // NOLINT
reinterpret_cast<intptr_t>(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
6 changes: 5 additions & 1 deletion app/src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@ class StaticFutureData {
// delimiter. Returns a vector of constituent parts.
std::vector<std::string> 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_
12 changes: 12 additions & 0 deletions app/tests/util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 6 additions & 4 deletions app_check/src/android/app_check_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -135,8 +136,6 @@ static const JNINativeMethod kNativeJniAppCheckListenerMethods[] = {
reinterpret_cast<void*>(JniAppCheckListener_nativeOnAppCheckTokenChanged)},
};

static const char* kApiIdentifier = "AppCheck";

static AppCheckProviderFactory* g_provider_factory = nullptr;
static int g_initialized_count = 0;

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -435,7 +437,7 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckToken(bool force_refresh) {
auto data_handle = new FutureDataHandle(future(), handle);
util::RegisterCallbackOnTask(env, j_task, TokenResultCallback,
reinterpret_cast<void*>(data_handle),
kApiIdentifier);
jni_task_id_.c_str());
} else {
AppCheckToken empty_token;
future()->CompleteWithResult(handle, kAppCheckErrorUnknown, error.c_str(),
Expand Down
4 changes: 4 additions & 0 deletions app_check/src/android/app_check_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <string>
#include <vector>

#include "app/src/future_manager.h"
Expand Down Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions app_check/src/android/common_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <string>

#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"

Expand Down Expand Up @@ -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) &&
Expand Down Expand Up @@ -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_);
}
Expand All @@ -150,7 +152,8 @@ void AndroidAppCheckProvider::GetToken(
new TokenResultCallbackData(completion_callback);
util::RegisterCallbackOnTask(
env, j_task, TokenResultCallback,
reinterpret_cast<void*>(completion_callback_data), kApiIdentifier);
reinterpret_cast<void*>(completion_callback_data),
jni_task_id_.c_str());
} else {
AppCheckToken empty_token;
completion_callback(empty_token, kAppCheckErrorUnknown, error.c_str());
Expand Down
3 changes: 3 additions & 0 deletions app_check/src/android/common_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 1 addition & 8 deletions auth/src/auth.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned long long>( // NOLINT
reinterpret_cast<intptr_t>(this)));
auth_data_->future_api_id = CreateApiIdentifier(kApiIdentifier, this);

// Cleanup this object if app is destroyed.
CleanupNotifier* notifier = CleanupNotifier::FindByOwner(app);
Expand Down
4 changes: 4 additions & 0 deletions database/src/android/database_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand Down Expand Up @@ -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_);
Expand Down
12 changes: 8 additions & 4 deletions database/src/android/database_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <map>
#include <set>
#include <string>
#include <vector>

#include "app/src/cleanup_notifier.h"
Expand All @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions database/src/android/database_reference_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ Future<void> DatabaseReferenceInternal::RemoveValue() {
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(
new FutureCallbackData(handle, ref_future(), db_)),
kApiIdentifier);
db_->jni_task_id());
util::CheckAndClearJniExceptions(env);
env->DeleteLocalRef(task);
return MakeFuture(ref_future(), handle);
Expand Down Expand Up @@ -358,7 +358,7 @@ Future<void> DatabaseReferenceInternal::SetValue(Variant value) {
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(
new FutureCallbackData(handle, ref_future(), db_)),
kApiIdentifier);
db_->jni_task_id());
env->DeleteLocalRef(task);
if (value_obj) env->DeleteLocalRef(value_obj);
}
Expand Down Expand Up @@ -391,7 +391,7 @@ Future<void> DatabaseReferenceInternal::SetPriority(Variant priority) {
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(
new FutureCallbackData(handle, ref_future(), db_)),
kApiIdentifier);
db_->jni_task_id());
util::CheckAndClearJniExceptions(env);
env->DeleteLocalRef(task);
if (priority_obj) env->DeleteLocalRef(priority_obj);
Expand Down Expand Up @@ -432,7 +432,7 @@ Future<void> DatabaseReferenceInternal::SetValueAndPriority(Variant value,
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(
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);
Expand Down Expand Up @@ -464,7 +464,7 @@ Future<void> DatabaseReferenceInternal::UpdateChildren(Variant values) {
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(
new FutureCallbackData(handle, ref_future(), db_)),
kApiIdentifier);
db_->jni_task_id());
env->DeleteLocalRef(task);
if (values_obj) env->DeleteLocalRef(values_obj);
}
Expand Down
10 changes: 5 additions & 5 deletions database/src/android/disconnection_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ Future<void> DisconnectionHandlerInternal::Cancel() {
env, task, FutureCallback,
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(handle, future(), db_)),
kApiIdentifier);
db_->jni_task_id());
util::CheckAndClearJniExceptions(env);
env->DeleteLocalRef(task);
return MakeFuture(future(), handle);
Expand All @@ -141,7 +141,7 @@ Future<void> DisconnectionHandlerInternal::RemoveValue() {
env, task, FutureCallback,
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(handle, future(), db_)),
kApiIdentifier);
db_->jni_task_id());
util::CheckAndClearJniExceptions(env);
return MakeFuture(future(), handle);
}
Expand All @@ -166,7 +166,7 @@ Future<void> DisconnectionHandlerInternal::SetValue(Variant value) {
env, task, FutureCallback,
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(handle, future(), db_)),
kApiIdentifier);
db_->jni_task_id());
util::CheckAndClearJniExceptions(env);
env->DeleteLocalRef(task);
if (value_obj) env->DeleteLocalRef(value_obj);
Expand Down Expand Up @@ -211,7 +211,7 @@ Future<void> DisconnectionHandlerInternal::SetValueAndPriority(
env, task, FutureCallback,
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(handle, future(), db_)),
kApiIdentifier);
db_->jni_task_id());
env->DeleteLocalRef(task);
if (value_obj) env->DeleteLocalRef(value_obj);
}
Expand Down Expand Up @@ -240,7 +240,7 @@ Future<void> DisconnectionHandlerInternal::UpdateChildren(Variant values) {
env, task, FutureCallback,
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(handle, future(), db_)),
kApiIdentifier);
db_->jni_task_id());
env->DeleteLocalRef(task);
if (values_obj) env->DeleteLocalRef(values_obj);
}
Expand Down
4 changes: 2 additions & 2 deletions functions/src/android/callable_reference_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ Future<HttpsCallableResult> HttpsCallableReferenceInternal::Call() {
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(
handle, future(), functions_, kCallableReferenceFnCall)),
kApiIdentifier);
functions_->jni_task_id());

util::CheckAndClearJniExceptions(env);
env->DeleteLocalRef(task);
Expand Down Expand Up @@ -219,7 +219,7 @@ Future<HttpsCallableResult> HttpsCallableReferenceInternal::Call(
// FutureCallback will delete the newed FutureCallbackData.
reinterpret_cast<void*>(new FutureCallbackData(
handle, future(), functions_, kCallableReferenceFnCall)),
kApiIdentifier);
functions_->jni_task_id());

util::CheckAndClearJniExceptions(env);
env->DeleteLocalRef(task);
Expand Down
Loading