Skip to content

Commit 87175a4

Browse files
committed
refactoring FirebaseCredentialsProvider to fix the issue w.r.t. auth global dispatch queue
1 parent 9b222e2 commit 87175a4

File tree

6 files changed

+61
-18
lines changed

6 files changed

+61
-18
lines changed

Firestore/core/src/firebase/firestore/auth/credentials_provider.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace auth {
2323
CredentialsProvider::CredentialsProvider() : user_change_listener_(nullptr) {
2424
}
2525

26+
CredentialsProvider::~CredentialsProvider() {
27+
}
28+
2629
} // namespace auth
2730
} // namespace firestore
2831
} // namespace firebase

Firestore/core/src/firebase/firestore/auth/credentials_provider.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class CredentialsProvider {
4545
public:
4646
CredentialsProvider();
4747

48+
virtual ~CredentialsProvider();
49+
4850
/**
4951
* Requests token for the current user, optionally forcing a refreshed token
5052
* to be fetched.

Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,30 @@ namespace auth {
4949
* from the thread backing our internal worker queue and the callbacks from
5050
* FIRAuth will be executed on an arbitrary different thread.
5151
*
52-
* For non-Apple desktop build, this is right now just a stub.
52+
* Any instance that has GetToken() calls has to be destructed in
53+
* FIRAuthGlobalWorkQueue i.e through another call to GetToken. This prevents
54+
* the object being destructed before the callback. For example, use the
55+
* following pattern:
56+
*
57+
* class Bar {
58+
* Bar(): provider_(new FirebaseCredentialsProvider([FIRApp defaultApp])) {}
59+
*
60+
* ~Bar() {
61+
* credentials_provider->GetToken(
62+
* false, [provider_](const Token& token, const absl::string_view error)
63+
* { delete provider_;
64+
* });
65+
* }
66+
*
67+
* Foo() {
68+
* credentials_provider->GetToken(
69+
* true, [](const Token& token, const absl::string_view error) {
70+
* ... ...
71+
* });
72+
* }
73+
*
74+
* FirebaseCredentialsProvider* provider_;
75+
* };
5376
*/
5477
class FirebaseCredentialsProvider : public CredentialsProvider {
5578
public:
@@ -62,20 +85,12 @@ class FirebaseCredentialsProvider : public CredentialsProvider {
6285
*/
6386
explicit FirebaseCredentialsProvider(FIRApp* app);
6487

88+
~FirebaseCredentialsProvider() override;
89+
6590
void GetToken(bool force_refresh, TokenListener completion) override;
6691

6792
void SetUserChangeListener(UserChangeListener listener) override;
6893

69-
friend class FirebaseCredentialsProviderTest_GetToken_Test;
70-
friend class FirebaseCredentialsProviderTest_SetListener_Test;
71-
friend class DISABLED_FirebaseCredentialsProviderTest_GetToken_Test;
72-
friend class DISABLED_FirebaseCredentialsProviderTest_SetListener_Test;
73-
74-
friend class FirebaseCredentialsProviderTest_GetToken_Test;
75-
friend class FirebaseCredentialsProviderTest_SetListener_Test;
76-
friend class DISABLED_FirebaseCredentialsProviderTest_GetToken_Test;
77-
friend class DISABLED_FirebaseCredentialsProviderTest_SetListener_Test;
78-
7994
private:
8095
const FIRApp* app_;
8196

@@ -96,7 +111,7 @@ class FirebaseCredentialsProvider : public CredentialsProvider {
96111

97112
// Make it static as as it is used in some of the callbacks. Otherwise, we saw
98113
// mutex lock failed: Invalid argument.
99-
static std::mutex mutex_;
114+
std::mutex mutex_;
100115
};
101116

102117
} // namespace auth

Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.mm

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@
2727
namespace firestore {
2828
namespace auth {
2929

30-
std::mutex FirebaseCredentialsProvider::mutex_;
31-
3230
FirebaseCredentialsProvider::FirebaseCredentialsProvider(FIRApp* app)
3331
: app_(app),
3432
auth_listener_handle_(nil),
3533
current_user_(firebase::firestore::util::MakeStringView([app getUID])),
36-
user_counter_(0) {
34+
user_counter_(0),
35+
mutex_() {
3736
auth_listener_handle_ = [[NSNotificationCenter defaultCenter]
3837
addObserverForName:FIRAuthStateDidChangeInternalNotification
3938
object:nil
@@ -64,6 +63,15 @@ User new_user(
6463
}];
6564
}
6665

66+
FirebaseCredentialsProvider::~FirebaseCredentialsProvider() {
67+
if (auth_listener_handle_) {
68+
// For iOS 9.0 and later or macOS 10.11 and later, it is not required to
69+
// unregister an observer in dealloc. Nothing is said for C++ destruction
70+
// and thus we do it here just to be sure.
71+
[[NSNotificationCenter defaultCenter] removeObserver:auth_listener_handle_];
72+
}
73+
}
74+
6775
void FirebaseCredentialsProvider::GetToken(bool force_refresh,
6876
TokenListener completion) {
6977
FIREBASE_ASSERT_MESSAGE(auth_listener_handle_,

Firestore/core/src/firebase/firestore/auth/user.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace firebase {
2222
namespace firestore {
2323
namespace auth {
2424

25-
User::User() : is_authenticated_(false) {
25+
User::User() : uid_(), is_authenticated_(false) {
2626
}
2727

2828
User::User(const absl::string_view uid) : uid_(uid), is_authenticated_(true) {

Firestore/core/test/firebase/firestore/auth/firebase_credentials_provider_test.mm

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
#include "gtest/gtest.h"
2626

27+
#define UNUSED(x) (void)(x)
28+
2729
namespace firebase {
2830
namespace firestore {
2931
namespace auth {
@@ -63,15 +65,28 @@ void SetUp() override {
6365
return;
6466
}
6567

66-
FirebaseCredentialsProvider credentials_provider([FIRApp defaultApp]);
67-
credentials_provider.GetToken(
68+
// GetToken() registers callback and thus we do not allocate it in stack.
69+
FirebaseCredentialsProvider* credentials_provider =
70+
new FirebaseCredentialsProvider([FIRApp defaultApp]);
71+
72+
credentials_provider->GetToken(
6873
true, [](const Token& token, const absl::string_view error) {
6974
EXPECT_EQ("", token.token());
7075
const User& user = token.user();
7176
EXPECT_EQ("I'm a fake uid.", user.uid());
7277
EXPECT_TRUE(user.is_authenticated());
7378
EXPECT_EQ("", error) << error;
7479
});
80+
81+
// Destruct credentials_provider via the FIRAuthGlobalWorkQueue, which is
82+
// serial.
83+
credentials_provider->GetToken(
84+
false, [credentials_provider](const Token& token,
85+
const absl::string_view error) {
86+
UNUSED(token);
87+
UNUSED(error);
88+
delete credentials_provider;
89+
});
7590
}
7691

7792
// Set kPlist above before enable.

0 commit comments

Comments
 (0)