Skip to content

Ml logging #2355

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 14 commits into from
Jan 28, 2021
Merged
6 changes: 4 additions & 2 deletions firebase-ml-modeldownloader/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.google.firebase.ml.modeldownloader {

public class CustomModel {
method public long getDownloadId();
method @Nullable public java.io.File getFile() throws com.google.firebase.ml.modeldownloader.FirebaseMlException;
method @Nullable public java.io.File getFile();
method @NonNull public String getModelHash();
method @NonNull public String getName();
method public long getSize();
Expand Down Expand Up @@ -35,9 +35,11 @@ package com.google.firebase.ml.modeldownloader {
field public static final int ALREADY_EXISTS = 6; // 0x6
field public static final int CANCELLED = 1; // 0x1
field public static final int DEADLINE_EXCEEDED = 4; // 0x4
field public static final int DOWNLOAD_URL_EXPIRED = 121; // 0x79
field public static final int FAILED_PRECONDITION = 9; // 0x9
field public static final int INTERNAL = 13; // 0xd
field public static final int INVALID_ARGUMENT = 3; // 0x3
field public static final int MODEL_HASH_MISMATCH = 102; // 0x66
field public static final int NOT_ENOUGH_SPACE = 101; // 0x65
field public static final int NOT_FOUND = 5; // 0x5
field public static final int OUT_OF_RANGE = 11; // 0xb
Expand All @@ -49,7 +51,7 @@ package com.google.firebase.ml.modeldownloader {
field public static final int UNKNOWN = 2; // 0x2
}

@IntDef({com.google.firebase.ml.modeldownloader.FirebaseMlException.CANCELLED, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNKNOWN, com.google.firebase.ml.modeldownloader.FirebaseMlException.INVALID_ARGUMENT, com.google.firebase.ml.modeldownloader.FirebaseMlException.DEADLINE_EXCEEDED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_FOUND, com.google.firebase.ml.modeldownloader.FirebaseMlException.ALREADY_EXISTS, com.google.firebase.ml.modeldownloader.FirebaseMlException.PERMISSION_DENIED, com.google.firebase.ml.modeldownloader.FirebaseMlException.RESOURCE_EXHAUSTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.FAILED_PRECONDITION, com.google.firebase.ml.modeldownloader.FirebaseMlException.ABORTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.OUT_OF_RANGE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNIMPLEMENTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.INTERNAL, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAVAILABLE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAUTHENTICATED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_ENOUGH_SPACE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FirebaseMlException.Code {
@IntDef({com.google.firebase.ml.modeldownloader.FirebaseMlException.CANCELLED, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNKNOWN, com.google.firebase.ml.modeldownloader.FirebaseMlException.INVALID_ARGUMENT, com.google.firebase.ml.modeldownloader.FirebaseMlException.DEADLINE_EXCEEDED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_FOUND, com.google.firebase.ml.modeldownloader.FirebaseMlException.ALREADY_EXISTS, com.google.firebase.ml.modeldownloader.FirebaseMlException.PERMISSION_DENIED, com.google.firebase.ml.modeldownloader.FirebaseMlException.RESOURCE_EXHAUSTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.FAILED_PRECONDITION, com.google.firebase.ml.modeldownloader.FirebaseMlException.ABORTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.OUT_OF_RANGE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNIMPLEMENTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.INTERNAL, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAVAILABLE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAUTHENTICATED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_ENOUGH_SPACE, com.google.firebase.ml.modeldownloader.FirebaseMlException.MODEL_HASH_MISMATCH, com.google.firebase.ml.modeldownloader.FirebaseMlException.DOWNLOAD_URL_EXPIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FirebaseMlException.Code {
}

public class FirebaseModelDownloader {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
*/
@RunWith(AndroidJUnit4.class)
public class TestGetModelLocal {
private FirebaseModelDownloader firebaseModelDownloader;

private static final String MODEL_NAME_LOCAL = "getLocalModel";
private static final String MODEL_NAME_LOCAL_2 = "getLocalModel2";
private static final String MODEL_HASH = "origHash324";
Expand All @@ -51,14 +51,13 @@ public class TestGetModelLocal {
private FirebaseApp app;
private File firstDeviceModelFile;
private File firstLoadTempModelFile;
private SharedPreferencesUtil sharedPreferencesUtil;

@Before
public void before() {
app = FirebaseApp.initializeApp(ApplicationProvider.getApplicationContext());
firebaseModelDownloader = FirebaseModelDownloader.getInstance(app);
FirebaseModelDownloader firebaseModelDownloader = FirebaseModelDownloader.getInstance(app);

sharedPreferencesUtil = new SharedPreferencesUtil(app);
SharedPreferencesUtil sharedPreferencesUtil = new SharedPreferencesUtil(app);
// reset shared preferences and downloads for models used by this test.
firebaseModelDownloader.deleteDownloadedModel(MODEL_NAME_LOCAL);
firebaseModelDownloader.deleteDownloadedModel(MODEL_NAME_LOCAL_2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public String getName() {
* progress, returns null, if file update is in progress returns last fully downloaded model.
*/
@Nullable
public File getFile() throws FirebaseMlException {
public File getFile() {
return getFile(ModelFileDownloadService.getInstance());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.common.internal.Preconditions;
import com.google.firebase.FirebaseException;
import java.lang.annotation.Retention;
Expand Down Expand Up @@ -84,7 +83,6 @@ public class FirebaseMlException extends FirebaseException {
* Internal errors. Means some invariants expected by underlying system has been broken. If you
* see one of these errors, something is very broken.
*/
// annz used
public static final int INTERNAL = 13;

/**
Expand All @@ -101,9 +99,17 @@ public class FirebaseMlException extends FirebaseException {
// ===============================================================================================
// Error codes: 100 to 149 reserved for errors during model downloading/loading.
/** There is not enough space left on the device. */
// annz used
public static final int NOT_ENOUGH_SPACE = 101;

/** The downloaded model's hash doesn't match the expected value. */
public static final int MODEL_HASH_MISMATCH = 102;

/**
* These download url expired before download could complete. Usually, multiple download attempt
* will be performed before this is returned.
*/
public static final int DOWNLOAD_URL_EXPIRED = 121;

/**
* The set of Firebase ML status codes. The codes are based on <a
* href="https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto">Canonical
Expand All @@ -125,7 +131,9 @@ public class FirebaseMlException extends FirebaseException {
INTERNAL,
UNAVAILABLE,
UNAUTHENTICATED,
NOT_ENOUGH_SPACE
NOT_ENOUGH_SPACE,
MODEL_HASH_MISMATCH,
DOWNLOAD_URL_EXPIRED
})
@Retention(RetentionPolicy.CLASS)
public @interface Code {}
Expand All @@ -138,13 +146,6 @@ public FirebaseMlException(@NonNull String detailMessage, @Code int code) {
this.code = code;
}

/** @hide */
public FirebaseMlException(
@NonNull String detailMessage, @Code int code, @Nullable Throwable cause) {
super(Preconditions.checkNotEmpty(detailMessage, "Provided message must not be empty."), cause);
this.code = code;
}

/** Gets the error code for the Firebase ML operation that failed. */
@Code
public int getCode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
package com.google.firebase.ml.modeldownloader;

import android.os.Build.VERSION_CODES;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import com.google.android.datatransport.TransportFactory;
import com.google.android.gms.common.internal.Preconditions;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
Expand All @@ -40,6 +40,7 @@

public class FirebaseModelDownloader {

private static final String TAG = "FirebaseModelDownld";
private final FirebaseOptions firebaseOptions;
private final SharedPreferencesUtil sharedPreferencesUtil;
private final ModelFileDownloadService fileDownloadService;
Expand All @@ -51,15 +52,13 @@ public class FirebaseModelDownloader {

@RequiresApi(api = VERSION_CODES.KITKAT)
FirebaseModelDownloader(
FirebaseApp firebaseApp,
FirebaseInstallationsApi firebaseInstallationsApi,
TransportFactory transportFactory) {
FirebaseApp firebaseApp, FirebaseInstallationsApi firebaseInstallationsApi) {
this.firebaseOptions = firebaseApp.getOptions();
this.sharedPreferencesUtil = new SharedPreferencesUtil(firebaseApp);
this.eventLogger = FirebaseMlLogger.getInstance();
this.fileDownloadService = new ModelFileDownloadService(firebaseApp, transportFactory);
this.fileDownloadService = new ModelFileDownloadService(firebaseApp);
this.modelDownloadService =
new CustomModelDownloadService(firebaseApp, firebaseInstallationsApi, transportFactory);
new CustomModelDownloadService(firebaseApp, firebaseInstallationsApi);

this.executor = Executors.newSingleThreadExecutor();
fileManager = ModelFileManager.getInstance();
Expand Down Expand Up @@ -250,7 +249,7 @@ private Task<CustomModel> getCustomModelTask(
CustomModel currentModel = sharedPreferencesUtil.getCustomModelDetails(modelName);

if (currentModel == null && modelHash != null) {
// todo(annzimmer) log something about mismatched state and use hash = null
Log.d(TAG, "Model hash provided but no current model; triggering fresh download.");
modelHash = null;
}

Expand All @@ -273,7 +272,7 @@ private Task<CustomModel> getCustomModelTask(
return getCompletedLocalCustomModelTask(updatedModel);
}
// clean up model internally
deleteModelDetails(currentModel.getName());
deleteModelDetails(modelName);
return Tasks.forException(
new FirebaseMlException(
"Possible caching issues: no model associated with " + modelName + ".",
Expand Down Expand Up @@ -308,16 +307,34 @@ && new File(currentModel.getLocalFilePath()).exists()) {
if (currentModel.getDownloadId() != 0) {
CustomModel downloadingModel =
sharedPreferencesUtil.getDownloadingCustomModelDetails(modelName);
if (downloadingModel != null
&& downloadingModel
.getModelHash()
.equals(incomingModelDetails.getResult().getModelHash())) {
return Tasks.forResult(downloadingModel);
if (downloadingModel != null) {
if (downloadingModel
.getModelHash()
.equals(incomingModelDetails.getResult().getModelHash())) {
return Tasks.forResult(downloadingModel);
}
Log.d(
TAG, "Hash does not match with expected: " + downloadingModel.getModelHash());
// Note we log "DownloadStatus.SUCCEEDED" because the model file's download itself
// succeeded. Just the hash validation failed.
eventLogger.logDownloadEventWithErrorCode(
downloadingModel,
true,
DownloadStatus.SUCCEEDED,
ErrorCode.MODEL_HASH_MISMATCH);
return Tasks.forException(
new FirebaseMlException(
"Hash does not match with expected",
FirebaseMlException.MODEL_HASH_MISMATCH));
}
// todo(annzimmer) this shouldn't happen unless they are calling the sdk with
// multiple
// sets of download types/conditions.
// this should be a download in progress - add appropriate handling.
Log.d(TAG, "Download details missing for model");
// Note we log "DownloadStatus.SUCCEEDED" because the model file's download itself
// succeeded. Just the file copy failed.
eventLogger.logDownloadEventWithErrorCode(
downloadingModel, true, DownloadStatus.SUCCEEDED, ErrorCode.DOWNLOAD_FAILED);
return Tasks.forException(
new FirebaseMlException(
"Download details missing for model", FirebaseMlException.INTERNAL));
}
}

Expand All @@ -343,7 +360,9 @@ private Task<CustomModel> retryExpiredUrlDownload(
@Nullable CustomModelDownloadConditions conditions,
Task<Void> downloadTask,
int retryCounter) {
if (downloadTask.getException().getMessage().contains("Retry: Expired URL")) {
if (downloadTask.getException() instanceof FirebaseMlException
&& ((FirebaseMlException) downloadTask.getException()).getCode()
== FirebaseMlException.DOWNLOAD_URL_EXPIRED) {
// this is likely an expired url - retry.
Task<CustomModel> retryModelDetails =
modelDownloadService.getNewDownloadUrlWithExpiry(
Expand All @@ -367,13 +386,18 @@ private Task<CustomModel> retryExpiredUrlDownload(
modelName, conditions, downloadTask, retryCounter - 1);
}
return Tasks.forException(
new Exception("File download failed. Too many attempts."));
new FirebaseMlException(
"File download failed after multiple attempts, possible expired url.",
FirebaseMlException.DOWNLOAD_URL_EXPIRED));
});
}
return Tasks.forException(retryModelDetailTask.getException());
});
} else if (downloadTask.getException() instanceof FirebaseMlException) {
return Tasks.forException(downloadTask.getException());
}
return Tasks.forException(new Exception("File download failed."));
return Tasks.forException(
new FirebaseMlException("File download failed.", FirebaseMlException.INTERNAL));
}

private Task<CustomModel> finishModelDownload(@NonNull String modelName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,11 @@ public List<Component<?>> getComponents() {
return Arrays.asList(
Component.builder(FirebaseModelDownloader.class)
.add(Dependency.required(FirebaseApp.class))
.add(Dependency.required(TransportFactory.class))
.add(Dependency.required(FirebaseInstallationsApi.class))
.factory(
c ->
new FirebaseModelDownloader(
c.get(FirebaseApp.class),
c.get(FirebaseInstallationsApi.class),
c.get(TransportFactory.class)))
c.get(FirebaseApp.class), c.get(FirebaseInstallationsApi.class)))
.build(),
Component.builder(SharedPreferencesUtil.class)
.add(Dependency.required(FirebaseApp.class))
Expand All @@ -77,22 +74,15 @@ public List<Component<?>> getComponents() {
.build(),
Component.builder(ModelFileDownloadService.class)
.add(Dependency.required(FirebaseApp.class))
.add(Dependency.required(TransportFactory.class))
.factory(
c ->
new ModelFileDownloadService(
c.get(FirebaseApp.class), c.get(TransportFactory.class)))
.factory(c -> new ModelFileDownloadService(c.get(FirebaseApp.class)))
.build(),
Component.builder(CustomModelDownloadService.class)
.add(Dependency.required(FirebaseApp.class))
.add(Dependency.required(TransportFactory.class))
.add(Dependency.required(FirebaseInstallationsApi.class))
.factory(
c ->
new CustomModelDownloadService(
c.get(FirebaseApp.class),
c.get(FirebaseInstallationsApi.class),
c.get(TransportFactory.class)))
c.get(FirebaseApp.class), c.get(FirebaseInstallationsApi.class)))
.build(),
LibraryVersionComponent.create("firebase-ml-modeldownloader", BuildConfig.VERSION_NAME));
}
Expand Down
Loading