Skip to content

Patch caching fid in memory on successful registration. #1764

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 6 commits into from
Jul 9, 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,6 +66,10 @@ 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 @@ -221,8 +225,15 @@ String getName() {
@Override
public Task<String> getId() {
preConditionChecks();

// Return cached fid if available.
String fid = getCacheFid();
if (fid != null) {
return Tasks.forResult(fid);
}

Task<String> task = addGetIdListener();
backgroundExecutor.execute(this::doGetId);
backgroundExecutor.execute(() -> doRegistrationOrRefresh(false));
return task;
}

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

Expand All @@ -261,20 +268,22 @@ public Task<Void> delete() {
private Task<String> addGetIdListener() {
TaskCompletionSource<String> taskCompletionSource = new TaskCompletionSource<>();
StateListener l = new GetIdListener(taskCompletionSource);
synchronized (lock) {
listeners.add(l);
}
addStateListeners(l);
return taskCompletionSource.getTask();
}

private Task<InstallationTokenResult> addGetAuthTokenListener() {
TaskCompletionSource<InstallationTokenResult> taskCompletionSource =
new TaskCompletionSource<>();
StateListener l = new GetAuthTokenListener(utils, taskCompletionSource);
addStateListeners(l);
return taskCompletionSource.getTask();
}

private void addStateListeners(StateListener l) {
synchronized (lock) {
listeners.add(l);
}
return taskCompletionSource.getTask();
}

private void triggerOnStateReached(PersistedInstallationEntry persistedInstallationEntry) {
Expand Down Expand Up @@ -303,16 +312,12 @@ private void triggerOnException(PersistedInstallationEntry prefs, Exception exce
}
}

private final void doGetId() {
doRegistrationInternal(false);
}

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

private final void doGetAuthTokenForceRefresh() {
doRegistrationInternal(true);
private synchronized String getCacheFid() {
return cachedFid;
}

/**
Expand All @@ -324,7 +329,8 @@ private final void doGetAuthTokenForceRefresh() {
* @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 final void doRegistrationInternal(boolean forceRefresh) {
private final void doRegistrationOrRefresh(boolean forceRefresh) {

PersistedInstallationEntry prefs = getPrefsWithGeneratedIdMultiProcessSafe();

// Since the caller wants to force an authtoken refresh remove the authtoken from the
Expand Down Expand Up @@ -361,6 +367,11 @@ 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 @@ -520,6 +531,7 @@ 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 @@ -533,6 +545,7 @@ 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 @@ -542,7 +555,6 @@ 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
Expand Up @@ -17,6 +17,10 @@
import com.google.android.gms.tasks.TaskCompletionSource;
import com.google.firebase.installations.local.PersistedInstallationEntry;

/**
* This class manages {@link PersistedInstallationEntry} state transitions valid for getId() and
* updates the caller once the id is generated.
*/
class GetIdListener implements StateListener {
final TaskCompletionSource<String> taskCompletionSource;

Expand All @@ -32,6 +36,8 @@ public boolean onStateReached(PersistedInstallationEntry persistedInstallationEn
taskCompletionSource.trySetResult(persistedInstallationEntry.getFirebaseInstallationId());
return true;
}
// Don't update the caller if the PersistedInstallationEntry registration status is
// ATTEMPT_MIGRATION or NOT_GENERATED.
return false;
}

Expand Down