diff --git a/firebase-crashlytics/firebase-crashlytics.gradle b/firebase-crashlytics/firebase-crashlytics.gradle index 4376a85a1ed..29f049c96ce 100644 --- a/firebase-crashlytics/firebase-crashlytics.gradle +++ b/firebase-crashlytics/firebase-crashlytics.gradle @@ -62,11 +62,8 @@ dependencies { implementation project(':transport:transport-api') implementation project(':transport:transport-runtime') implementation project(':transport:transport-backend-cct') - implementation ('com.google.firebase:firebase-iid:20.1.5') { - exclude group: "com.google.firebase", module: "firebase-common" - exclude group: "com.google.firebase", module: "firebase-components" - } - implementation 'com.google.firebase:firebase-iid-interop:17.0.0' + implementation project(':firebase-installations-interop') + runtimeOnly project(':firebase-installations') implementation 'com.google.firebase:firebase-measurement-connector:18.0.0' implementation "com.google.android.gms:play-services-tasks:17.0.0" diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CLSUUIDTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CLSUUIDTest.java index de0731774fa..bb9ff8c6ee9 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CLSUUIDTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CLSUUIDTest.java @@ -15,9 +15,11 @@ package com.google.firebase.crashlytics.internal.common; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import com.google.android.gms.tasks.Tasks; import com.google.firebase.crashlytics.internal.CrashlyticsTestCase; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; public class CLSUUIDTest extends CrashlyticsTestCase { @@ -26,8 +28,9 @@ public class CLSUUIDTest extends CrashlyticsTestCase { protected void setUp() throws Exception { super.setUp(); - FirebaseInstanceIdInternal instanceIdMock = mock(FirebaseInstanceIdInternal.class); - idManager = new IdManager(getContext(), getContext().getPackageName(), instanceIdMock); + FirebaseInstallationsApi installationsApiMock = mock(FirebaseInstallationsApi.class); + when(installationsApiMock.getId()).thenReturn(Tasks.forResult("instanceId")); + idManager = new IdManager(getContext(), getContext().getPackageName(), installationsApiMock); uuid = new CLSUUID(idManager); } diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CommonUtilsTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CommonUtilsTest.java index df66f8117db..9193eafe4ae 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CommonUtilsTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CommonUtilsTest.java @@ -25,9 +25,10 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.util.Log; +import com.google.android.gms.tasks.Tasks; import com.google.firebase.crashlytics.internal.CrashlyticsTestCase; import com.google.firebase.crashlytics.internal.Logger; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; @@ -352,9 +353,10 @@ public void testCapFileCount() throws Exception { private File createEmptyClsFile(File dir) throws IOException { final Context context = getContext(); - FirebaseInstanceIdInternal instanceIdMock = mock(FirebaseInstanceIdInternal.class); + FirebaseInstallationsApi installationsApiMock = mock(FirebaseInstallationsApi.class); + when(installationsApiMock.getId()).thenReturn(Tasks.forResult("instanceId")); final CLSUUID id = - new CLSUUID(new IdManager(context, context.getPackageName(), instanceIdMock)); + new CLSUUID(new IdManager(context, context.getPackageName(), installationsApiMock)); final File f = new File(dir, id.toString() + ".cls"); f.createNewFile(); return f; diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java index 9227fd171b4..28221a1cac8 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java @@ -58,7 +58,7 @@ import com.google.firebase.crashlytics.internal.settings.model.SessionSettingsData; import com.google.firebase.crashlytics.internal.settings.model.SettingsData; import com.google.firebase.crashlytics.internal.unity.UnityVersionProvider; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -99,8 +99,9 @@ protected void setUp() throws Exception { testContext = getContext(); - FirebaseInstanceIdInternal instanceIdMock = mock(FirebaseInstanceIdInternal.class); - idManager = new IdManager(testContext, testContext.getPackageName(), instanceIdMock); + FirebaseInstallationsApi installationsApiMock = mock(FirebaseInstallationsApi.class); + when(installationsApiMock.getId()).thenReturn(Tasks.forResult("instanceId")); + idManager = new IdManager(testContext, testContext.getPackageName(), installationsApiMock); BatteryIntentProvider.returnNull = false; diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreInitializationTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreInitializationTest.java index d04cee8f2c2..d7deec7eb39 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreInitializationTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreInitializationTest.java @@ -36,7 +36,7 @@ import com.google.firebase.crashlytics.internal.settings.SettingsController; import com.google.firebase.crashlytics.internal.settings.TestSettingsData; import com.google.firebase.crashlytics.internal.settings.model.SettingsData; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.io.File; import java.io.IOException; import java.util.concurrent.ExecutorService; @@ -94,8 +94,9 @@ public CoreBuilder(Context context, FirebaseOptions firebaseOptions) { when(app.getApplicationContext()).thenReturn(context); when(app.getOptions()).thenReturn(firebaseOptions); - FirebaseInstanceIdInternal instanceIdMock = mock(FirebaseInstanceIdInternal.class); - idManager = new IdManager(context, context.getPackageName(), instanceIdMock); + FirebaseInstallationsApi installationsApiMock = mock(FirebaseInstallationsApi.class); + when(installationsApiMock.getId()).thenReturn(Tasks.forResult("instanceId")); + idManager = new IdManager(context, context.getPackageName(), installationsApiMock); nativeComponent = new MissingNativeComponent(); diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreTest.java index 25b6efa17cc..b2a7b81c018 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsCoreTest.java @@ -38,7 +38,7 @@ import com.google.firebase.crashlytics.internal.settings.SettingsController; import com.google.firebase.crashlytics.internal.settings.TestSettingsData; import com.google.firebase.crashlytics.internal.settings.model.SettingsData; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.io.File; import java.io.FileFilter; import java.io.IOException; @@ -681,13 +681,14 @@ CrashlyticsCore build(Context context) { FirebaseApp app = mock(FirebaseApp.class); when(app.getApplicationContext()).thenReturn(context); when(app.getOptions()).thenReturn(testFirebaseOptions); - FirebaseInstanceIdInternal instanceIdMock = mock(FirebaseInstanceIdInternal.class); + FirebaseInstallationsApi installationsApiMock = mock(FirebaseInstallationsApi.class); + when(installationsApiMock.getId()).thenReturn(Tasks.forResult("instanceId")); BreadcrumbSource breadcrumbSource = this.breadcrumbSource == null ? new DisabledBreadcrumbSource() : this.breadcrumbSource; final CrashlyticsCore crashlyticsCore = new CrashlyticsCore( app, - new IdManager(context, "unused", instanceIdMock), + new IdManager(context, "unused", installationsApiMock), nativeComponent, arbiter, breadcrumbSource, diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java index 98c794a376a..5436220584a 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java @@ -21,10 +21,11 @@ import android.content.Context; import androidx.test.core.app.ApplicationProvider; import androidx.test.runner.AndroidJUnit4; +import com.google.android.gms.tasks.Tasks; import com.google.firebase.crashlytics.internal.model.CrashlyticsReport; import com.google.firebase.crashlytics.internal.model.CrashlyticsReport.Session.Event.Application.Execution; import com.google.firebase.crashlytics.internal.stacktrace.StackTraceTrimmingStrategy; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.util.List; import org.junit.Before; import org.junit.Test; @@ -43,16 +44,17 @@ public class CrashlyticsReportDataCaptureTest { @Mock private StackTraceTrimmingStrategy stackTraceTrimmingStrategy; - @Mock private FirebaseInstanceIdInternal instanceIdMock; + @Mock private FirebaseInstallationsApi installationsApiMock; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - when(instanceIdMock.getId()).thenReturn("installId"); + when(installationsApiMock.getId()).thenReturn(Tasks.forResult("installId")); when(stackTraceTrimmingStrategy.getTrimmedStackTrace(any(StackTraceElement[].class))) .thenAnswer(i -> i.getArguments()[0]); final Context context = ApplicationProvider.getApplicationContext(); - final IdManager idManager = new IdManager(context, context.getPackageName(), instanceIdMock); + final IdManager idManager = + new IdManager(context, context.getPackageName(), installationsApiMock); final AppData appData = AppData.create(context, idManager, "googleAppId", "buildId"); dataCapture = new CrashlyticsReportDataCapture(context, idManager, appData, stackTraceTrimmingStrategy); diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/IdManagerTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/IdManagerTest.java index f8ae7c6d48e..b582ef3c813 100644 --- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/IdManagerTest.java +++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/IdManagerTest.java @@ -18,8 +18,10 @@ import static org.mockito.Mockito.when; import android.content.SharedPreferences; +import com.google.android.gms.tasks.Tasks; import com.google.firebase.crashlytics.internal.CrashlyticsTestCase; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; +import java.util.concurrent.TimeoutException; public class IdManagerTest extends CrashlyticsTestCase { @@ -56,8 +58,8 @@ private void clearPrefs() { } private IdManager createIdManager(String instanceId) { - FirebaseInstanceIdInternal iid = mock(FirebaseInstanceIdInternal.class); - when(iid.getId()).thenReturn(instanceId); + FirebaseInstallationsApi iid = mock(FirebaseInstallationsApi.class); + when(iid.getId()).thenReturn(Tasks.forResult(instanceId)); return new IdManager(getContext(), getContext().getPackageName(), iid); } @@ -75,6 +77,23 @@ public void testCreateUUID() { assertEquals(installId, idManager.getCrashlyticsInstallId()); } + public void testGetIdExceptionalCase_doesNotRotateInstallId() { + FirebaseInstallationsApi fis = mock(FirebaseInstallationsApi.class); + final String expectedInstallId = "expectedInstallId"; + when(fis.getId()) + .thenReturn(Tasks.forException(new TimeoutException("Fetching id timed out."))); + prefs + .edit() + .putString(IdManager.PREFKEY_INSTALLATION_UUID, expectedInstallId) + .putString(IdManager.PREFKEY_FIREBASE_IID, "firebase-iid") + .apply(); + + final IdManager idManager = new IdManager(getContext(), getContext().getPackageName(), fis); + final String actualInstallId = idManager.getCrashlyticsInstallId(); + assertNotNull(actualInstallId); + assertEquals(expectedInstallId, actualInstallId); + } + public void testInstanceIdChanges() { // Set up the initial state with a valid iid and uuid. final String oldUuid = "old_uuid"; diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java index 4713a9cd6e0..6f4b679af49 100644 --- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java +++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/CrashlyticsRegistrar.java @@ -21,7 +21,7 @@ import com.google.firebase.components.ComponentRegistrar; import com.google.firebase.components.Dependency; import com.google.firebase.crashlytics.internal.CrashlyticsNativeComponent; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import com.google.firebase.platforminfo.LibraryVersionComponent; import java.util.Arrays; import java.util.List; @@ -33,7 +33,7 @@ public List> getComponents() { return Arrays.asList( Component.builder(FirebaseCrashlytics.class) .add(Dependency.required(FirebaseApp.class)) - .add(Dependency.requiredProvider(FirebaseInstanceIdInternal.class)) + .add(Dependency.required(FirebaseInstallationsApi.class)) .add(Dependency.optional(AnalyticsConnector.class)) .add(Dependency.optional(CrashlyticsNativeComponent.class)) .factory(this::buildCrashlytics) @@ -49,9 +49,9 @@ private FirebaseCrashlytics buildCrashlytics(ComponentContainer container) { AnalyticsConnector analyticsConnector = container.get(AnalyticsConnector.class); - FirebaseInstanceIdInternal instanceId = - container.getProvider(FirebaseInstanceIdInternal.class).get(); + FirebaseInstallationsApi firebaseInstallations = container.get(FirebaseInstallationsApi.class); - return FirebaseCrashlytics.init(app, instanceId, nativeComponent, analyticsConnector); + return FirebaseCrashlytics.init( + app, firebaseInstallations, nativeComponent, analyticsConnector); } } diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/FirebaseCrashlytics.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/FirebaseCrashlytics.java index a64877348e1..653ac3f31da 100644 --- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/FirebaseCrashlytics.java +++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/FirebaseCrashlytics.java @@ -38,7 +38,7 @@ import com.google.firebase.crashlytics.internal.common.ExecutorUtils; import com.google.firebase.crashlytics.internal.common.IdManager; import com.google.firebase.crashlytics.internal.settings.SettingsController; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; @@ -60,13 +60,13 @@ public class FirebaseCrashlytics { static @Nullable FirebaseCrashlytics init( @NonNull FirebaseApp app, - @NonNull FirebaseInstanceIdInternal instanceId, + @NonNull FirebaseInstallationsApi firebaseInstallationsApi, @Nullable CrashlyticsNativeComponent nativeComponent, @Nullable AnalyticsConnector analyticsConnector) { Context context = app.getApplicationContext(); // Set up the IdManager. final String appIdentifier = context.getPackageName(); - final IdManager idManager = new IdManager(context, appIdentifier, instanceId); + final IdManager idManager = new IdManager(context, appIdentifier, firebaseInstallationsApi); final DataCollectionArbiter arbiter = new DataCollectionArbiter(app); diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/IdManager.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/IdManager.java index dbb737e8836..aeded9ba32c 100644 --- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/IdManager.java +++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/IdManager.java @@ -18,13 +18,15 @@ import android.content.SharedPreferences; import android.os.Build; import androidx.annotation.NonNull; +import com.google.android.gms.tasks.Task; import com.google.firebase.crashlytics.internal.Logger; -import com.google.firebase.iid.internal.FirebaseInstanceIdInternal; +import com.google.firebase.installations.FirebaseInstallationsApi; import java.util.Locale; import java.util.UUID; import java.util.regex.Pattern; public class IdManager implements InstallIdProvider { + public static final String DEFAULT_VERSION_NAME = "0.0"; static final String PREFKEY_ADVERTISING_ID = "crashlytics.advertising.id"; @@ -41,8 +43,8 @@ public class IdManager implements InstallIdProvider { private final Context appContext; private final String appIdentifier; - // The FirebaseInstanceIdInternal encapsulates a Firebase-wide install id - private final FirebaseInstanceIdInternal firebaseInstallId; + // The FirebaseInstallationsApi encapsulates a Firebase-wide install id + private final FirebaseInstallationsApi firebaseInstallationsApi; // Crashlytics maintains a Crashlytics-specific install id, used in the crash processing backend private String crashlyticsInstallId; @@ -54,7 +56,7 @@ public class IdManager implements InstallIdProvider { * null */ public IdManager( - Context appContext, String appIdentifier, FirebaseInstanceIdInternal firebaseInstallId) { + Context appContext, String appIdentifier, FirebaseInstallationsApi firebaseInstallationsApi) { if (appContext == null) { throw new IllegalArgumentException("appContext must not be null"); } @@ -63,7 +65,7 @@ public IdManager( } this.appContext = appContext; this.appIdentifier = appIdentifier; - this.firebaseInstallId = firebaseInstallId; + this.firebaseInstallationsApi = firebaseInstallationsApi; installerPackageNameProvider = new InstallerPackageNameProvider(); } @@ -99,11 +101,25 @@ public synchronized String getCrashlyticsInstallId() { // Crashlytics rotates the Crashlytics-specific IID if the Firebase IID ("FID") is reset. // This way, Crashlytics privacy controls are consistent with the rest of Firebase. - final String currentFid = firebaseInstallId.getId(); + Task currentFidTask = firebaseInstallationsApi.getId(); + String currentFid = null; final String cachedFid = prefs.getString(PREFKEY_FIREBASE_IID, null); + try { + currentFid = Utils.awaitEvenIfOnMainThread(currentFidTask); + } catch (Exception e) { + Logger.getLogger().d("Failed to retrieve installation id", e); + + // this avoids rotating the identifier in the case that there was an exception which is likely + // to succeed in a future invocation + if (cachedFid != null) { + currentFid = cachedFid; + } + } + if (cachedFid == null) { - // This must be either 1) a new installation or 2) an upgrade from the legacy Crashlytics SDK. + // This must be either 1) a new installation or 2) an upgrade from the legacy + // Crashlytics SDK. // If it is a legacy upgrade, we'll migrate the legacy ID to the new pref store. final SharedPreferences legacyPrefs = CommonUtils.getLegacySharedPrefs(appContext); final String legacyId = legacyPrefs.getString(PREFKEY_LEGACY_INSTALLATION_UUID, null);