Skip to content
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

FirebaseModelDownloader instance creation fails when using FirebaseModelDownloader.getInstance(app: FirebaseApp) when there is no default FirebaseApp while using a separate FirebaseApp #3321

Closed
dev-gloomyfox opened this issue Jan 17, 2022 · 6 comments
Labels
api: mlkit type: bug Something isn't working

Comments

@dev-gloomyfox
Copy link

dev-gloomyfox commented Jan 17, 2022

[READ] Step 1: Are you in the right place?

Issues filed here should be about bugs in the code in this repository.
If you have a general question, need help debugging, or fall into some
other category use one of these other channels:

  • For general technical questions, post a question on StackOverflow
    with the firebase tag.
  • For general Firebase discussion, use the firebase-talk
    google group.
  • For help troubleshooting your application that does not fall under one
    of the above categories, reach out to the personalized
    Firebase support channel.

[REQUIRED] Step 2: Describe your environment

  • Android Studio version: Android Studio 4.1.1
  • Firebase Component: ml-modeldownloader
  • Component version: gradle 6.5
    ** build.gradle(app)
...
dependencies {
    implementation platform('com.google.firebase:firebase-bom:29.0.3')
    implementation 'com.google.firebase:firebase-installations'
    implementation 'com.google.firebase:firebase-ml-modeldownloader-ktx'
...
}

[REQUIRED] Step 3: Describe the problem

FirebaseModelDownloader instance creation fails when using FirebaseModelDownloader.getInstance(app: FirebaseApp) when there is no default FirebaseApp while using a separate FirebaseApp

Steps to reproduce:

FirebaseModelDownloader instance creation fails when using FirebaseModelDownloader.getInstance(app: FirebaseApp) when there is no default FirebaseApp while using a separate FirebaseApp

E/AndroidRuntime: FATAL EXCEPTION: main
Process: dev.gloomyfox.firebase.test, PID: 10576
java.lang.RuntimeException: Unable to start activity ComponentInfo{dev.gloomyfox.firebase.test/dev.gloomyfox.firebase.test.MainActivity}: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process dev.gloomyfox.firebase.test. Make sure to call FirebaseApp.initializeApp(Context) first.

...

at com.google.firebase.ml.modeldownloader.internal.FirebaseMlLogger.getInstance(FirebaseMlLogger.java:93)
at com.google.firebase.ml.modeldownloader.FirebaseModelDownloader.<init>(FirebaseModelDownloader.java:58)

...

Relevant Code:

The reason is that there are objects that use the default FirebaseApp among the properties inside FirebaseModelDownloader.
FirebaseMlLogger (https://github.com/firebase/firebase-android-sdk/blob/master/firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/internal/FirebaseMlLogger.java#L93) and ModelFileManager (https://github.com/firebase/firebase-android-sdk/blob/master/firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/internal/ModelFileManager.java#L62) uses the default FirebaseApp internally, so if there is no default FirebaseApp, it will not work even if a specific FirebaseApp is specified in getInstance.

In most cases there will be a Default FirebaseApp, and apart from the logger and file manager, downloading the model itself works well for the specified firebase project, so I don't think it's a big problem.
However, unless there is a special reason, it is more intuitive for the logger and file manager to use the FirebaseApp specified in the app parameter, and I think it is better because it is not tied to the default FirebaseApp state.

// TODO

// FirebaseMlLogger.java
@NonNull
public static FirebaseMlLogger getInstance(FirebaseApp app) {
    Preconditions.checkArgument(app != null, "Null is not a valid value of FirebaseApp.");
    return (FirebaseMlLogger)FirebaseApp.getInstance(app).get(FirebaseMlLogger.class);
}

// ModelFileManager.java
@NonNull
public static ModelFileManager getInstance(FirebaseApp app) {
    Preconditions.checkArgument(app != null, "Null is not a valid value of FirebaseApp.");
    return (ModelFileManager)FirebaseApp.getInstance(app).get(ModelFileManager.class);
}

// And use the above method in the constructor that receives the FirebaseApp parameter.
@google-oss-bot
Copy link
Contributor

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.

@argzdev
Copy link
Contributor

argzdev commented Jan 17, 2022

Hi @dev-gloomyfox, thanks for the detailed explanation and report. Any chance you could share us a minimal repro of the issue? It'll greatly help us in our investigation, thanks!

@dev-gloomyfox
Copy link
Author

dev-gloomyfox commented Jan 17, 2022

Hi @argzdev,
Provides a simple repro, please let me know if there is anything missing

Create android app project template(on android studio)

  • New → Empty Activity → Create Project
  • Although it is not common, due to the main project situation, the google-service.json file is not used.

build.gradle(root)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.4.32"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.1.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.10'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

build.gradle(app)

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'com.google.gms.google-services'
}

android {
    compileSdkVersion 31
    buildToolsVersion "30.0.2"

    defaultConfig {
        applicationId "{appicationId}"
        minSdkVersion 21
        targetSdkVersion 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.2'

    implementation platform('com.google.firebase:firebase-bom:29.0.3')

    implementation 'com.google.firebase:firebase-installations'
    implementation 'com.google.firebase:firebase-ml-modeldownloader-ktx'

    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

// Although not common, for several reasons, the google-service.json file is not used.
tasks.all { task ->
    if(task.name.contains("processDebugGoogleServices") || task.name.contains("processReleaseGoogleServices")) {
        task.enabled = false
    }
}

MainActivity.kt

package com.kakaopay.data.inference.remote

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.google.firebase.FirebaseOptions
import com.google.firebase.ktx.Firebase
import com.google.firebase.ktx.initialize
import com.google.firebase.ml.modeldownloader.CustomModelDownloadConditions
import com.google.firebase.ml.modeldownloader.DownloadType
import com.google.firebase.ml.modeldownloader.ktx.modelDownloader

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        FirebaseOptions.Builder()
                .setProjectId("{firebase_project_id}")
                .setApplicationId("{firebase_project's_application_id}")
                .setApiKey("{project_api_key}")
                .build()
                .run {
                    Firebase.initialize(this@MainActivity, this, "model-downloader")
                }
                .run {
                    Firebase.modelDownloader(this)
                }
                .getModel(
                        "{model_name}",
                        DownloadType.LATEST_MODEL,
                        CustomModelDownloadConditions.Builder().build()
                )
                .addOnSuccessListener {
                    Log.i("MainActivity", "Success, name: ${it.name}")
                }
                .addOnFailureListener {
                    Log.i("MainActivity", "Failure, stacktrace: ${it.stackTraceToString()}")
                }
    }
}

If you configure the code as above and start the app, the exception described above will occur.

E/AndroidRuntime: FATAL EXCEPTION: main
Process: dev.gloomyfox.firebase.test, PID: 10576
java.lang.RuntimeException: Unable to start activity ComponentInfo{dev.gloomyfox.firebase.test/dev.gloomyfox.firebase.test.MainActivity}: java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process dev.gloomyfox.firebase.test. Make sure to call FirebaseApp.initializeApp(Context) first.

...

at com.google.firebase.ml.modeldownloader.internal.FirebaseMlLogger.getInstance(FirebaseMlLogger.java:93)
at com.google.firebase.ml.modeldownloader.FirebaseModelDownloader.<init>(FirebaseModelDownloader.java:58)

...

@argzdev
Copy link
Contributor

argzdev commented Jan 19, 2022

Thanks for the code snippet, @dev-gloomyfox. I was able to repro the issue, with that said, I'll notify an engineer and see what we can do here.

@argzdev argzdev added the type: bug Something isn't working label Jan 19, 2022
@argzdev
Copy link
Contributor

argzdev commented Jan 19, 2022

In the meantime, I'll try to create a PR and ask our engineers if this is good to merge or if updates are needed.

@argzdev
Copy link
Contributor

argzdev commented Jan 27, 2022

Hi @dev-gloomyfox, the fix has been merged. With that said, I can't provide any specific timeline when this fix will be available, but you may keep an eye out on our release notes from time to time to check out the latest features and bug fixes. I'll be closing this issue now. Thanks!

@argzdev argzdev closed this as completed Jan 27, 2022
@firebase firebase locked and limited conversation to collaborators Feb 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api: mlkit type: bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants