19
19
20
20
#include " app/src/embedded_file.h"
21
21
#include " app/src/include/firebase/future.h"
22
+ #include " app/src/include/firebase/internal/mutex.h"
22
23
#include " app/src/reference_counted_future_impl.h"
23
24
#include " app/src/util_android.h"
24
25
#include " app_check/app_check_resources.h"
@@ -100,6 +101,27 @@ static const JNINativeMethod kNativeJniAppCheckProviderMethods[] = {
100
101
reinterpret_cast <void *>(JniAppCheckProvider_nativeGetToken)},
101
102
};
102
103
104
+ // clang-format off
105
+ #define JNI_APP_CHECK_LISTENER_METHODS (X ) \
106
+ X (Constructor, " <init>" , " (J)V" )
107
+ // clang-format on
108
+
109
+ METHOD_LOOKUP_DECLARATION (jni_app_check_listener,
110
+ JNI_APP_CHECK_LISTENER_METHODS)
111
+ METHOD_LOOKUP_DEFINITION (
112
+ jni_app_check_listener,
113
+ " com/google/firebase/appcheck/internal/cpp/JniAppCheckListener" ,
114
+ JNI_APP_CHECK_LISTENER_METHODS)
115
+
116
+ JNIEXPORT void JNICALL JniAppCheckListener_nativeOnAppCheckTokenChanged (
117
+ JNIEnv* env, jobject clazz, jlong c_app_check, jobject token);
118
+
119
+ static const JNINativeMethod kNativeJniAppCheckListenerMethods [] = {
120
+ {" nativeOnAppCheckTokenChanged" ,
121
+ " (JLcom/google/firebase/appcheck/AppCheckToken;)V" ,
122
+ reinterpret_cast <void *>(JniAppCheckListener_nativeOnAppCheckTokenChanged)},
123
+ };
124
+
103
125
static const char * kApiIdentifier = " AppCheck" ;
104
126
105
127
static AppCheckProviderFactory* g_provider_factory = nullptr ;
@@ -127,13 +149,24 @@ bool CacheAppCheckMethodIds(
127
149
FIREBASE_ARRAYSIZE (kNativeJniAppCheckProviderMethods )))) {
128
150
return false ;
129
151
}
152
+ // Cache the JniAppCheckListener class and register the native callback
153
+ // methods.
154
+ if (!(jni_app_check_listener::CacheClassFromFiles (env, activity,
155
+ &embedded_files) &&
156
+ jni_app_check_listener::CacheMethodIds (env, activity) &&
157
+ jni_app_check_listener::RegisterNatives (
158
+ env, kNativeJniAppCheckListenerMethods ,
159
+ FIREBASE_ARRAYSIZE (kNativeJniAppCheckListenerMethods )))) {
160
+ return false ;
161
+ }
130
162
return app_check::CacheMethodIds (env, activity);
131
163
}
132
164
133
165
void ReleaseAppCheckClasses (JNIEnv* env) {
134
166
app_check::ReleaseClass (env);
135
167
jni_provider_factory::ReleaseClass (env);
136
168
jni_provider::ReleaseClass (env);
169
+ jni_app_check_listener::ReleaseClass (env);
137
170
}
138
171
139
172
// Release cached Java classes.
@@ -195,7 +228,7 @@ JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetToken(
195
228
jobject task_completion_source_global =
196
229
env->NewGlobalRef (task_completion_source);
197
230
198
- // Defines a c ++ callback method to call
231
+ // Defines a C ++ callback method to call
199
232
// JniAppCheckProvider.HandleGetTokenResult with the resulting token
200
233
auto token_callback{[j_provider_global, task_completion_source_global](
201
234
firebase::app_check::AppCheckToken token,
@@ -219,6 +252,13 @@ JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetToken(
219
252
provider->GetToken (token_callback);
220
253
}
221
254
255
+ JNIEXPORT void JNICALL JniAppCheckListener_nativeOnAppCheckTokenChanged (
256
+ JNIEnv* env, jobject clazz, jlong c_app_check, jobject token) {
257
+ auto app_check_internal = reinterpret_cast <AppCheckInternal*>(c_app_check);
258
+ AppCheckToken cpp_token = CppTokenFromAndroidToken (env, token);
259
+ app_check_internal->NotifyTokenChanged (cpp_token);
260
+ }
261
+
222
262
AppCheckInternal::AppCheckInternal (App* app) : app_(app) {
223
263
future_manager ().AllocFutureApi (this , kAppCheckFnCount );
224
264
@@ -284,16 +324,40 @@ AppCheckInternal::AppCheckInternal(App* app) : app_(app) {
284
324
FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
285
325
env->DeleteLocalRef (j_factory);
286
326
}
327
+
328
+ // Add a token-changed listener and give it a pointer to the C++ listeners.
329
+ jobject j_listener =
330
+ env->NewObject (jni_app_check_listener::GetClass (),
331
+ jni_app_check_listener::GetMethodId (
332
+ jni_app_check_listener::kConstructor ),
333
+ reinterpret_cast <jlong>(this ));
334
+ FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
335
+ env->CallVoidMethod (app_check_impl_,
336
+ app_check::GetMethodId (app_check::kAddAppCheckListener ),
337
+ j_listener);
338
+ FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
339
+ j_app_check_listener_ = env->NewGlobalRef (j_listener);
340
+ env->DeleteLocalRef (j_listener);
287
341
} else {
288
342
app_check_impl_ = nullptr ;
343
+ j_app_check_listener_ = nullptr ;
289
344
}
290
345
}
291
346
292
347
AppCheckInternal::~AppCheckInternal () {
293
348
future_manager ().ReleaseFutureApi (this );
294
349
JNIEnv* env = app_->GetJNIEnv ();
295
350
app_ = nullptr ;
351
+ listeners_.clear ();
296
352
353
+ if (j_app_check_listener_ != nullptr ) {
354
+ env->CallVoidMethod (
355
+ app_check_impl_,
356
+ app_check::GetMethodId (app_check::kRemoveAppCheckListener ),
357
+ j_app_check_listener_);
358
+ FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
359
+ env->DeleteGlobalRef (j_app_check_listener_);
360
+ }
297
361
if (app_check_impl_ != nullptr ) {
298
362
env->DeleteGlobalRef (app_check_impl_);
299
363
}
@@ -314,7 +378,7 @@ ReferenceCountedFutureImpl* AppCheckInternal::future() {
314
378
315
379
void AppCheckInternal::SetAppCheckProviderFactory (
316
380
AppCheckProviderFactory* factory) {
317
- // Store the c ++ factory in a static variable.
381
+ // Store the C ++ factory in a static variable.
318
382
// Whenever an instance of AppCheck is created, it will read this variable
319
383
// and install the factory as it is initialized.
320
384
g_provider_factory = factory;
@@ -357,9 +421,28 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckTokenLastResult() {
357
421
future ()->LastResult (kAppCheckFnGetAppCheckToken ));
358
422
}
359
423
360
- void AppCheckInternal::AddAppCheckListener (AppCheckListener* listener) {}
424
+ void AppCheckInternal::AddAppCheckListener (AppCheckListener* listener) {
425
+ MutexLock lock (listeners_mutex_);
426
+ auto it = std::find (listeners_.begin (), listeners_.end (), listener);
427
+ if (it == listeners_.end ()) {
428
+ listeners_.push_back (listener);
429
+ }
430
+ }
431
+
432
+ void AppCheckInternal::RemoveAppCheckListener (AppCheckListener* listener) {
433
+ MutexLock lock (listeners_mutex_);
434
+ auto it = std::find (listeners_.begin (), listeners_.end (), listener);
435
+ if (it != listeners_.end ()) {
436
+ listeners_.erase (it);
437
+ }
438
+ }
361
439
362
- void AppCheckInternal::RemoveAppCheckListener (AppCheckListener* listener) {}
440
+ void AppCheckInternal::NotifyTokenChanged (AppCheckToken token) {
441
+ MutexLock lock (listeners_mutex_);
442
+ for (AppCheckListener* listener : listeners_) {
443
+ listener->OnAppCheckTokenChanged (token);
444
+ }
445
+ }
363
446
364
447
} // namespace internal
365
448
} // namespace app_check
0 commit comments