@@ -178,17 +178,24 @@ class JavaFirestoreMap {
178178 jni::Global<jni::HashMap> firestores_;
179179};
180180
181- // Governed by init_mutex_below as well.
182- JavaFirestoreMap* java_firestores_ = nullptr ;
181+ // init_mutex protects all the globals below.
182+ Mutex init_mutex; // NOLINT
183+ int initialize_count = 0 ;
184+ Loader* global_loader = nullptr ;
185+
186+ JavaFirestoreMap* java_firestores = nullptr ;
187+
188+ // The initial value for setLoggingEnabled.
189+ enum class InitialLogState {
190+ kUnset ,
191+ kSetEnabled ,
192+ kSetDisabled ,
193+ } initial_log_state = InitialLogState::kUnset ;
183194
184195} // namespace
185196
186197const char kApiIdentifier [] = " Firestore" ;
187198
188- Mutex FirestoreInternal::init_mutex_; // NOLINT
189- int FirestoreInternal::initialize_count_ = 0 ;
190- Loader* FirestoreInternal::loader_ = nullptr ;
191-
192199FirestoreInternal::FirestoreInternal (App* app) {
193200 FIREBASE_ASSERT (app != nullptr );
194201 if (!Initialize (app)) return ;
@@ -200,7 +207,7 @@ FirestoreInternal::FirestoreInternal(App* app) {
200207 FIREBASE_ASSERT (java_firestore.get () != nullptr );
201208 obj_ = java_firestore;
202209
203- java_firestores_ ->Put (env, java_firestore, this );
210+ java_firestores ->Put (env, java_firestore, this );
204211
205212 // Mainly for enabling TimestampsInSnapshotsEnabled. The rest comes from the
206213 // default in native SDK. The C++ implementation relies on that for reading
@@ -218,21 +225,22 @@ FirestoreInternal::FirestoreInternal(App* app) {
218225
219226/* static */
220227bool FirestoreInternal::Initialize (App* app) {
221- MutexLock init_lock (init_mutex_ );
222- if (initialize_count_ == 0 ) {
228+ MutexLock init_lock (init_mutex );
229+ if (initialize_count == 0 ) {
223230 jni::Initialize (app->java_vm ());
224231
225- FIREBASE_DEV_ASSERT (java_firestores_ == nullptr );
226- java_firestores_ = new JavaFirestoreMap ();
232+ FIREBASE_DEV_ASSERT (java_firestores == nullptr );
233+ java_firestores = new JavaFirestoreMap ();
227234
235+ Env env = GetEnv ();
228236 Loader loader (app);
229237 loader.AddEmbeddedFile (::firebase_firestore::firestore_resources_filename,
230238 ::firebase_firestore::firestore_resources_data,
231239 ::firebase_firestore::firestore_resources_size);
232240 loader.CacheEmbeddedFiles ();
233241
234242 jni::Object::Initialize (loader);
235-
243+ jni::String::Initialize (env, loader);
236244 jni::ArrayList::Initialize (loader);
237245 jni::Boolean::Initialize (loader);
238246 jni::Collection::Initialize (loader);
@@ -272,32 +280,42 @@ bool FirestoreInternal::Initialize(App* app) {
272280 TransactionInternal::Initialize (loader);
273281 WriteBatchInternal::Initialize (loader);
274282 if (!loader.ok ()) {
275- ReleaseClasses (app );
283+ ReleaseClassesLocked (env );
276284 return false ;
277285 }
278286
279- FIREBASE_DEV_ASSERT (loader_ == nullptr );
280- loader_ = new Loader (Move (loader));
287+ FIREBASE_DEV_ASSERT (global_loader == nullptr );
288+ global_loader = new Loader (Move (loader));
289+
290+ if (initial_log_state != InitialLogState::kUnset ) {
291+ bool enabled = initial_log_state == InitialLogState::kSetEnabled ;
292+ env.Call (kSetLoggingEnabled , enabled);
293+ }
281294 }
282- initialize_count_ ++;
295+ initialize_count ++;
283296 return true ;
284297}
285298
286299/* static */
287- void FirestoreInternal::ReleaseClasses (App* app) {
288- delete loader_;
289- loader_ = nullptr ;
300+ void FirestoreInternal::ReleaseClassesLocked (Env& env) {
301+ // Assumes `init_mutex` is held.
302+ String::Terminate (env);
303+
304+ delete global_loader;
305+ global_loader = nullptr ;
290306}
291307
292308/* static */
293309void FirestoreInternal::Terminate (App* app) {
294- MutexLock init_lock (init_mutex_);
295- FIREBASE_ASSERT (initialize_count_ > 0 );
296- initialize_count_--;
297- if (initialize_count_ == 0 ) {
298- ReleaseClasses (app);
299- delete java_firestores_;
300- java_firestores_ = nullptr ;
310+ MutexLock init_lock (init_mutex);
311+ FIREBASE_ASSERT (initialize_count > 0 );
312+ initialize_count--;
313+ if (initialize_count == 0 ) {
314+ Env env (app->GetJNIEnv ());
315+ ReleaseClassesLocked (env);
316+
317+ delete java_firestores;
318+ java_firestores = nullptr ;
301319 }
302320}
303321
@@ -316,7 +334,7 @@ FirestoreInternal::~FirestoreInternal() {
316334
317335 future_manager_.ReleaseFutureApi (this );
318336
319- java_firestores_ ->Remove (env, obj_);
337+ java_firestores ->Remove (env, obj_);
320338
321339 Terminate (app_);
322340 app_ = nullptr ;
@@ -512,13 +530,28 @@ void Firestore::set_log_level(LogLevel log_level) {
512530 // "Info", "warning", "error", and "assert" map to logging disabled.
513531 bool logging_enabled = log_level < LogLevel::kLogLevelInfo ;
514532
533+ {
534+ MutexLock lock (init_mutex);
535+
536+ // Set the initial_log_state on every invocation, just in case Firestore
537+ // is terminated for long enough to unload the Firestore classes within
538+ // the JVM.
539+ initial_log_state = logging_enabled ? InitialLogState::kSetEnabled
540+ : InitialLogState::kSetDisabled ;
541+
542+ if (initialize_count < 1 ) {
543+ // Avoid invoking Java methods before Firestore has been initialized.
544+ return ;
545+ }
546+ }
547+
515548 Env env = FirestoreInternal::GetEnv ();
516549 env.Call (kSetLoggingEnabled , logging_enabled);
517550}
518551
519552FirestoreInternal* FirestoreInternal::RecoverFirestore (
520553 Env& env, const Object& java_firestore) {
521- return java_firestores_ ->Get (env, java_firestore);
554+ return java_firestores ->Get (env, java_firestore);
522555}
523556
524557void FirestoreInternal::SetClientLanguage (const std::string& language_token) {
0 commit comments