Skip to content

Revert caching fid & disk read on caller thread. #1767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ public class FirebaseInstallations implements FirebaseInstallationsApi {
private final Object lock = new Object();
private final ExecutorService backgroundExecutor;
private final ExecutorService networkExecutor;
/* FID of this Firebase Installations instance. Cached after successfully registering and
persisting the FID locally. NOTE: cachedFid resets if FID is deleted.*/
@GuardedBy("this")
private String cachedFid;

@GuardedBy("lock")
private final List<StateListener> listeners = new ArrayList<>();
Expand Down Expand Up @@ -225,7 +221,9 @@ String getName() {
@Override
public Task<String> getId() {
preConditionChecks();
return Tasks.forResult(doGetId());
Task<String> task = addGetIdListener();
backgroundExecutor.execute(this::doGetId);
return task;
}

/**
Expand All @@ -241,7 +239,11 @@ public Task<String> getId() {
public Task<InstallationTokenResult> getToken(boolean forceRefresh) {
preConditionChecks();
Task<InstallationTokenResult> task = addGetAuthTokenListener();
backgroundExecutor.execute(() -> doGetAuthToken(forceRefresh));
if (forceRefresh) {
backgroundExecutor.execute(this::doGetAuthTokenForceRefresh);
} else {
backgroundExecutor.execute(this::doGetAuthTokenWithoutForceRefresh);
}
return task;
}

Expand All @@ -256,6 +258,15 @@ public Task<Void> delete() {
return Tasks.call(backgroundExecutor, this::deleteFirebaseInstallationId);
}

private Task<String> addGetIdListener() {
TaskCompletionSource<String> taskCompletionSource = new TaskCompletionSource<>();
StateListener l = new GetIdListener(taskCompletionSource);
synchronized (lock) {
listeners.add(l);
}
return taskCompletionSource.getTask();
}

private Task<InstallationTokenResult> addGetAuthTokenListener() {
TaskCompletionSource<InstallationTokenResult> taskCompletionSource =
new TaskCompletionSource<>();
Expand Down Expand Up @@ -292,25 +303,16 @@ private void triggerOnException(PersistedInstallationEntry prefs, Exception exce
}
}

private synchronized void updateCacheFid(String cachedFid) {
this.cachedFid = cachedFid;
private final void doGetId() {
doRegistrationInternal(false);
}

private synchronized String getCacheFid() {
return cachedFid;
private final void doGetAuthTokenWithoutForceRefresh() {
doRegistrationInternal(false);
}

private String doGetId() {

String fid = getCacheFid();
if (fid != null) {
return fid;
}
PersistedInstallationEntry prefs = getPrefsWithGeneratedIdMultiProcessSafe();
// Execute network calls (CreateInstallations) to the FIS Servers on a separate executor
// i.e networkExecutor
networkExecutor.execute(() -> doNetworkCallIfNecessary(false));
return prefs.getFirebaseInstallationId();
private final void doGetAuthTokenForceRefresh() {
doRegistrationInternal(true);
}

/**
Expand All @@ -322,7 +324,7 @@ private String doGetId() {
* @param forceRefresh true if this is for a getAuthToken call and if the caller wants to fetch a
* new auth token from the server even if an unexpired auth token exists on the client.
*/
private void doGetAuthToken(boolean forceRefresh) {
private final void doRegistrationInternal(boolean forceRefresh) {
PersistedInstallationEntry prefs = getPrefsWithGeneratedIdMultiProcessSafe();

// Since the caller wants to force an authtoken refresh remove the authtoken from the
Expand Down Expand Up @@ -359,11 +361,6 @@ private void doNetworkCallIfNecessary(boolean forceRefresh) {
// Store the prefs to persist the result of the previous step.
insertOrUpdatePrefs(prefs);

// Update cachedFID, if FID is successfully REGISTERED and persisted.
if (prefs.isRegistered()) {
updateCacheFid(prefs.getFirebaseInstallationId());
}

// Let the caller know about the result.
if (prefs.isErrored()) {
triggerOnException(prefs, new FirebaseInstallationsException(Status.BAD_CONFIG));
Expand Down Expand Up @@ -523,7 +520,6 @@ private PersistedInstallationEntry fetchAuthTokenFromServer(
case AUTH_ERROR:
// The the server refused to generate a new auth token due to bad credentials, clear the
// FID to force the generation of a new one.
updateCacheFid(null);
return prefs.withNoGeneratedFid();
default:
throw new FirebaseInstallationsException(
Expand All @@ -537,7 +533,6 @@ private PersistedInstallationEntry fetchAuthTokenFromServer(
* storage.
*/
private Void deleteFirebaseInstallationId() throws FirebaseInstallationsException {
updateCacheFid(null);
PersistedInstallationEntry entry = getMultiProcessSafePrefs();
if (entry.isRegistered()) {
// Call the FIS servers to delete this Firebase Installation Id.
Expand All @@ -547,6 +542,7 @@ private Void deleteFirebaseInstallationId() throws FirebaseInstallationsExceptio
/*projectID= */ getProjectIdentifier(),
/*refreshToken= */ entry.getRefreshToken());
}

insertOrUpdatePrefs(entry.withNoGeneratedFid());
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.firebase.installations;

import com.google.android.gms.tasks.TaskCompletionSource;
import com.google.firebase.installations.local.PersistedInstallationEntry;

class GetIdListener implements StateListener {
final TaskCompletionSource<String> taskCompletionSource;

public GetIdListener(TaskCompletionSource<String> taskCompletionSource) {
this.taskCompletionSource = taskCompletionSource;
}

@Override
public boolean onStateReached(PersistedInstallationEntry persistedInstallationEntry) {
if (persistedInstallationEntry.isUnregistered()
|| persistedInstallationEntry.isRegistered()
|| persistedInstallationEntry.isErrored()) {
taskCompletionSource.trySetResult(persistedInstallationEntry.getFirebaseInstallationId());
return true;
}
return false;
}

@Override
public boolean onException(
PersistedInstallationEntry persistedInstallationEntry, Exception exception) {
return false;
}
}