Skip to content

Commit 5d29d1a

Browse files
authored
Merge pull request #219 from firebase/feature/js-merge-firestore-changes
Merge Firestore changes
2 parents 38d860c + bc71dbb commit 5d29d1a

File tree

18 files changed

+240
-116
lines changed

18 files changed

+240
-116
lines changed

app/instance_id/instance_id_desktop_impl.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ bool InstanceIdDesktopImpl::FetchServerToken(const char* scope, bool* retry) {
721721
size_t component_start = 0;
722722
size_t component_end;
723723
do {
724-
component_end = error.find(":", component_start);
724+
component_end = error.find(':', component_start);
725725
std::string error_component =
726726
error.substr(component_start, component_end - component_start);
727727
if (error_component == kPhoneRegistrationError) {

app/src/locale.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ std::string GetLocale() {
6969
// Some of the environment variables have a "." after the name to specify the
7070
// terminal encoding, e.g. "en_US.UTF-8", so we want to cut the string on the
7171
// ".".
72-
size_t cut = output.find(".");
72+
size_t cut = output.find('.');
7373
if (cut != std::string::npos) {
7474
output = output.substr(0, cut);
7575
}
7676
// Do the same with a "@" which some locales also have.
77-
cut = output.find("@");
77+
cut = output.find('@');
7878
if (cut != std::string::npos) {
7979
output = output.substr(0, cut);
8080
}

app/tests/locale_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ TEST_F(LocaleTest, TestGetLocale) {
4949
// Make sure this looks like a locale, e.g. has at least 5 characters and
5050
// contains an underscore.
5151
EXPECT_GE(loc.size(), 5);
52-
EXPECT_NE(loc.find("_"), std::string::npos);
52+
EXPECT_NE(loc.find('_'), std::string::npos);
5353
}
5454

5555
} // namespace internal

auth/src/desktop/rpcs/error_codes.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ AuthError GetAuthErrorCode(const std::string& error,
225225
// Couldn't find it, check again with just the first word.
226226
// Sometimes the backend will return the error code along with
227227
// some explanatory text (see kAuthErrorNoSuchProvider above).
228-
size_t space = error.find(" ");
228+
size_t space = error.find(' ');
229229
if (space != std::string::npos) {
230230
std::string first_word = error.substr(0, space);
231231
found = find_error(first_word);

firestore/src/android/firestore_android.cc

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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

186197
const char kApiIdentifier[] = "Firestore";
187198

188-
Mutex FirestoreInternal::init_mutex_; // NOLINT
189-
int FirestoreInternal::initialize_count_ = 0;
190-
Loader* FirestoreInternal::loader_ = nullptr;
191-
192199
FirestoreInternal::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 */
220227
bool 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 */
293309
void 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

519552
FirestoreInternal* 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

524557
void FirestoreInternal::SetClientLanguage(const std::string& language_token) {

firestore/src/android/firestore_android.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,9 @@ class FirestoreInternal {
178178
void ShutdownUserCallbackExecutor(jni::Env& env);
179179

180180
static bool Initialize(App* app);
181-
static void ReleaseClasses(App* app);
181+
static void ReleaseClassesLocked(jni::Env& env);
182182
static void Terminate(App* app);
183183

184-
static Mutex init_mutex_;
185-
static int initialize_count_;
186-
static jni::Loader* loader_;
187-
188184
jni::Global<jni::Object> user_callback_executor_;
189185

190186
App* app_ = nullptr;

firestore/src/jni/env.cc

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#include "firestore/src/jni/env.h"
22

3+
#include <cstring>
4+
35
#include "app/src/assert.h"
46
#include "app/src/log.h"
7+
#include "firestore/src/jni/array.h"
58

69
// Add constant declarations missing from the NDK's jni.h
710
#ifndef JNI_ENOMEM
@@ -144,28 +147,36 @@ jmethodID Env::GetStaticMethodId(const Class& clazz, const char* name,
144147
}
145148

146149
Local<String> Env::NewStringUtf(const char* bytes) {
150+
if (!bytes) return {};
151+
152+
return NewStringUtf(bytes, strlen(bytes));
153+
}
154+
155+
Local<String> Env::NewStringUtf(const char* bytes, size_t size) {
147156
if (!ok()) return {};
148157

149-
jstring result = env_->NewStringUTF(bytes);
150-
RecordException();
151-
return Local<String>(env_, result);
158+
Local<Array<uint8_t>> java_bytes = NewArray<uint8_t>(size);
159+
SetArrayRegion(java_bytes, 0, size, reinterpret_cast<const uint8_t*>(bytes));
160+
if (!ok()) return {};
161+
162+
return String::Create(*this, java_bytes, String::GetUtf8());
152163
}
153164

154-
std::string Env::GetStringUtfRegion(const String& string, size_t start,
155-
size_t len) {
165+
std::string Env::ToStringUtf(const String& string) {
156166
if (!ok()) return "";
157167

168+
Local<Array<uint8_t>> bytes = string.GetBytes(*this, String::GetUtf8());
169+
size_t len = GetArrayLength(bytes);
170+
158171
// Copy directly into the std::string buffer. This is guaranteed to work as
159172
// of C++11, and also happens to work with STLPort.
160173
std::string result;
161174
result.resize(len);
162175

163-
env_->GetStringUTFRegion(string.get(), ToJni(start), ToJni(len), &result[0]);
164-
RecordException();
165-
166-
// Ensure that if there was an exception, the contents of the buffer are
167-
// disregarded.
176+
auto* buffer = reinterpret_cast<uint8_t*>(&result[0]);
177+
GetArrayRegion(bytes, 0, len, buffer);
168178
if (!ok()) return "";
179+
169180
return result;
170181
}
171182

firestore/src/jni/env.h

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -297,29 +297,28 @@ class Env {
297297
// MARK: String Operations
298298

299299
/**
300-
* Creates a new proxy for a Java String from a sequences of modified UTF-8
301-
* bytes.
300+
* Creates a new proxy for a Java String from a sequence of UTF-8 bytes.
301+
*
302+
* Note that unlike the underlying JNI method, these bytes should be encoded
303+
* in standard UTF-8, and *not* in the modified UTF-8 customarily used in the
304+
* JNI API.
305+
*
306+
* @param bytes The UTF-8 bytes from which to create a Java String.
307+
* @param size The number of bytes in the UTF-8 sequence.
302308
*/
303309
Local<String> NewStringUtf(const char* bytes);
310+
Local<String> NewStringUtf(const char* bytes, size_t size);
304311
Local<String> NewStringUtf(const std::string& bytes) {
305-
return NewStringUtf(bytes.c_str());
306-
}
307-
308-
/** Returns the length of the string in modified UTF-8 bytes. */
309-
size_t GetStringUtfLength(const String& string) {
310-
if (!ok()) return 0;
311-
312-
jsize result = env_->GetStringUTFLength(string.get());
313-
RecordException();
314-
return static_cast<size_t>(result);
312+
return NewStringUtf(bytes.c_str(), bytes.size());
315313
}
316314

317315
/**
318-
* Copies the contents of a region of a Java string to a C++ string. The
319-
* resulting string has a modified UTF-8 encoding.
316+
* Converts the given Java String to a C++ string encoded in UTF-8.
317+
*
318+
* Note that this string is encoded in standard UTF-8, and *not* in the
319+
* modified UTF-8 customarily used in the JNI API.
320320
*/
321-
std::string GetStringUtfRegion(const String& string, size_t start,
322-
size_t len);
321+
std::string ToStringUtf(const String& string);
323322

324323
// MARK: Array Operations
325324

firestore/src/jni/loader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class Loader {
4444
* Returns true if the loader has succeeded. If not, any errors have already
4545
* been logged.
4646
*/
47-
bool ok() const { return ok_; }
47+
bool ok() const { return ok_ && !env_->ExceptionCheck(); }
4848

4949
/**
5050
* Adds metadata about embedded class files in the binary distribution.

firestore/src/jni/object.cc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,24 @@ namespace jni {
1111
namespace {
1212

1313
Method<bool> kEquals("equals", "(Ljava/lang/Object;)Z");
14-
jclass g_clazz = nullptr;
14+
Method<String> kToString("toString", "()Ljava/lang/String;");
15+
jclass object_class = nullptr;
1516

1617
} // namespace
1718

1819
void Object::Initialize(Loader& loader) {
19-
g_clazz = util::object::GetClass();
20-
loader.LoadFromExistingClass("java/lang/Object", g_clazz, kEquals);
20+
object_class = util::object::GetClass();
21+
loader.LoadFromExistingClass("java/lang/Object", object_class, kEquals,
22+
kToString);
2123
}
2224

23-
Class Object::GetClass() { return Class(util::object::GetClass()); }
25+
Class Object::GetClass() { return Class(object_class); }
2426

25-
std::string Object::ToString(JNIEnv* env) const {
26-
return util::JniObjectToString(env, object_);
27+
std::string Object::ToString(Env& env) const {
28+
Local<String> java_string = env.Call(*this, kToString);
29+
return java_string.ToString(env);
2730
}
2831

29-
std::string Object::ToString(Env& env) const { return ToString(env.get()); }
30-
3132
bool Object::Equals(Env& env, const Object& other) const {
3233
return env.Call(*this, kEquals, other);
3334
}

0 commit comments

Comments
 (0)