Skip to content

Commit cdf06e2

Browse files
authored
Added FirebaseMlException and Logging round 1. (#2259)
* Added FirebaseMlException and Logging round 1. * Updating files per failed tests. * Fixing to single junit. * Updates FirebaseMlLogEvent ModelOption name to Options to make internal proto. This allows for proper json to proto conversion and in local tests messages now reach the spanner queue. * Add ability to get download id for file progress tracking. * removing androidTestImplementation - these are not used.
1 parent cdc8e88 commit cdf06e2

22 files changed

+1668
-64
lines changed

firebase-ml-modeldownloader/api.txt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.google.firebase.ml.modeldownloader {
33

44
public class CustomModel {
55
method public long getDownloadId();
6-
method @Nullable public java.io.File getFile() throws java.lang.Exception;
6+
method @Nullable public java.io.File getFile() throws com.google.firebase.ml.modeldownloader.FirebaseMlException;
77
method @NonNull public String getModelHash();
88
method @NonNull public String getName();
99
method public long getSize();
@@ -29,12 +29,36 @@ package com.google.firebase.ml.modeldownloader {
2929
enum_constant public static final com.google.firebase.ml.modeldownloader.DownloadType LOCAL_MODEL_UPDATE_IN_BACKGROUND;
3030
}
3131

32+
public class FirebaseMlException extends com.google.firebase.FirebaseException {
33+
method @com.google.firebase.ml.modeldownloader.FirebaseMlException.Code public int getCode();
34+
field public static final int ABORTED = 10; // 0xa
35+
field public static final int ALREADY_EXISTS = 6; // 0x6
36+
field public static final int CANCELLED = 1; // 0x1
37+
field public static final int DEADLINE_EXCEEDED = 4; // 0x4
38+
field public static final int FAILED_PRECONDITION = 9; // 0x9
39+
field public static final int INTERNAL = 13; // 0xd
40+
field public static final int INVALID_ARGUMENT = 3; // 0x3
41+
field public static final int NOT_ENOUGH_SPACE = 101; // 0x65
42+
field public static final int NOT_FOUND = 5; // 0x5
43+
field public static final int OUT_OF_RANGE = 11; // 0xb
44+
field public static final int PERMISSION_DENIED = 7; // 0x7
45+
field public static final int RESOURCE_EXHAUSTED = 8; // 0x8
46+
field public static final int UNAUTHENTICATED = 16; // 0x10
47+
field public static final int UNAVAILABLE = 14; // 0xe
48+
field public static final int UNIMPLEMENTED = 12; // 0xc
49+
field public static final int UNKNOWN = 2; // 0x2
50+
}
51+
52+
@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 {
53+
}
54+
3255
public class FirebaseModelDownloader {
3356
method @NonNull public com.google.android.gms.tasks.Task<java.lang.Void> deleteDownloadedModel(@NonNull String);
3457
method @NonNull public static com.google.firebase.ml.modeldownloader.FirebaseModelDownloader getInstance();
3558
method @NonNull public static com.google.firebase.ml.modeldownloader.FirebaseModelDownloader getInstance(@NonNull com.google.firebase.FirebaseApp);
3659
method @NonNull public com.google.android.gms.tasks.Task<com.google.firebase.ml.modeldownloader.CustomModel> getModel(@NonNull String, @NonNull com.google.firebase.ml.modeldownloader.DownloadType, @Nullable com.google.firebase.ml.modeldownloader.CustomModelDownloadConditions) throws java.lang.Exception;
3760
method @NonNull public com.google.android.gms.tasks.Task<java.util.Set<com.google.firebase.ml.modeldownloader.CustomModel>> listDownloadedModels();
61+
method public void setStatsCollectionEnabled(boolean);
3862
}
3963

4064
}

firebase-ml-modeldownloader/firebase-ml-modeldownloader.gradle

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,29 @@
1414

1515
plugins {
1616
id 'firebase-library'
17+
id 'com.google.protobuf'
1718
}
1819

1920
firebaseLibrary {
2021
testLab.enabled = false
2122
publishJavadoc = false
2223
}
2324

25+
protobuf {
26+
// Configure the protoc executable
27+
protoc {
28+
// Download from repositories
29+
artifact = "com.google.protobuf:protoc:$protocVersion"
30+
}
31+
generateProtoTasks {
32+
all().each { task ->
33+
task.builtins {
34+
java { }
35+
}
36+
}
37+
}
38+
}
39+
2440
android {
2541
compileSdkVersion project.targetSdkVersion
2642

@@ -43,25 +59,34 @@ android {
4359
}
4460

4561
dependencies {
62+
implementation project(':encoders:firebase-encoders')
63+
implementation project(':encoders:firebase-encoders-json')
4664
implementation project(':firebase-common')
4765
implementation project(':firebase-components')
66+
implementation project(':firebase-datatransport')
4867
implementation project(':firebase-installations-interop')
68+
implementation project(':transport:transport-api')
69+
implementation project(':transport:transport-runtime')
4970
runtimeOnly project(':firebase-installations')
5071

72+
implementation 'androidx.annotation:annotation:1.1.0'
5173
implementation 'com.google.android.gms:play-services-tasks:17.2.0'
5274
implementation 'com.google.auto.service:auto-service-annotations:1.0-rc6'
5375
implementation 'javax.inject:javax.inject:1'
5476

5577
compileOnly "com.google.auto.value:auto-value-annotations:1.6.6"
5678
annotationProcessor "com.google.auto.value:auto-value:1.6.5"
79+
annotationProcessor project(":encoders:firebase-encoders-processor")
5780

5881
testImplementation 'androidx.test:core:1.3.0'
5982
testImplementation 'com.github.tomakehurst:wiremock-standalone:2.26.3'
6083
testImplementation "com.google.truth:truth:$googleTruthVersion"
61-
testImplementation 'junit:junit:4.13.1'
84+
testImplementation "org.robolectric:robolectric:$robolectricVersion"
85+
testImplementation 'com.google.truth.extensions:truth-proto-extension:1.0'
86+
testImplementation 'com.google.protobuf:protobuf-java-util:3.11.0'
87+
testImplementation 'junit:junit:4.13-beta-2'
88+
6289
//Android compatible version of Apache httpclient.
6390
testImplementation 'org.apache.httpcomponents:httpclient-android:4.3.5.1'
6491
testImplementation 'org.mockito:mockito-core:3.3.3'
65-
testImplementation "org.robolectric:robolectric:$robolectricVersion"
66-
testImplementation 'com.google.truth.extensions:truth-proto-extension:1.0'
6792
}

firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/CustomModel.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public String getName() {
129129
* progress, returns null, if file update is in progress returns last fully uploaded model.
130130
*/
131131
@Nullable
132-
public File getFile() throws Exception {
132+
public File getFile() throws FirebaseMlException {
133133
return getFile(ModelFileDownloadService.getInstance());
134134
}
135135

@@ -142,7 +142,7 @@ public File getFile() throws Exception {
142142
*/
143143
@Nullable
144144
@VisibleForTesting
145-
File getFile(ModelFileDownloadService fileDownloadService) throws Exception {
145+
File getFile(ModelFileDownloadService fileDownloadService) throws FirebaseMlException {
146146
// check for completed download
147147
File newDownloadFile = fileDownloadService.loadNewlyDownloadedModelFile(this);
148148
if (newDownloadFile != null) {
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.ml.modeldownloader;
16+
17+
import androidx.annotation.IntDef;
18+
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
20+
import com.google.android.gms.common.internal.Preconditions;
21+
import com.google.firebase.FirebaseException;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
25+
/**
26+
* Represents an Exception resulting from an operation on a {@link FirebaseModelDownloader}. Error
27+
* mappings should remain consistent with the original firebase_ml_sdk whenever possible.
28+
*/
29+
public class FirebaseMlException extends FirebaseException {
30+
/** The operation was cancelled (typically by the caller). */
31+
public static final int CANCELLED = 1;
32+
33+
/** Unknown error or an error from a different error domain. */
34+
public static final int UNKNOWN = 2;
35+
36+
/**
37+
* Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION.
38+
* INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the system
39+
* (e.g., an invalid field name).
40+
*/
41+
public static final int INVALID_ARGUMENT = 3;
42+
43+
/**
44+
* Deadline expired before operation could complete. For operations that change the state of the
45+
* system, this error may be returned even if the operation has completed successfully. For
46+
* example, a successful response from a server could have been delayed long enough for the
47+
* deadline to expire.
48+
*/
49+
public static final int DEADLINE_EXCEEDED = 4;
50+
51+
/** Some requested resource was not found. */
52+
public static final int NOT_FOUND = 5;
53+
54+
/** Some resource that we attempted to create already exists. */
55+
public static final int ALREADY_EXISTS = 6;
56+
57+
/** The caller does not have permission to execute the specified operation. */
58+
public static final int PERMISSION_DENIED = 7;
59+
60+
/**
61+
* Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system
62+
* is out of space.
63+
*/
64+
public static final int RESOURCE_EXHAUSTED = 8;
65+
66+
/**
67+
* Operation was rejected because the system is not in a state required for the operation's
68+
* execution.
69+
*/
70+
public static final int FAILED_PRECONDITION = 9;
71+
72+
/**
73+
* The operation was aborted, typically due to a concurrency issue like transaction aborts, etc.
74+
*/
75+
public static final int ABORTED = 10;
76+
77+
/** Operation was attempted past the valid range. */
78+
public static final int OUT_OF_RANGE = 11;
79+
80+
/** Operation is not implemented or not supported/enabled. */
81+
public static final int UNIMPLEMENTED = 12;
82+
83+
/**
84+
* Internal errors. Means some invariants expected by underlying system has been broken. If you
85+
* see one of these errors, something is very broken.
86+
*/
87+
// annz used
88+
public static final int INTERNAL = 13;
89+
90+
/**
91+
* The service is currently unavailable. This is a most likely a transient condition and may be
92+
* corrected by retrying with a backoff.
93+
*
94+
* <p>In ML Kit, this error is mostly about the models being not available yet.
95+
*/
96+
public static final int UNAVAILABLE = 14;
97+
98+
/** The request does not have valid authentication credentials for the operation. */
99+
public static final int UNAUTHENTICATED = 16;
100+
101+
// ===============================================================================================
102+
// Error codes: 100 to 149 reserved for errors during model downloading/loading.
103+
/** There is not enough space left on the device. */
104+
// annz used
105+
public static final int NOT_ENOUGH_SPACE = 101;
106+
107+
/**
108+
* The set of Firebase ML status codes. The codes are based on <a
109+
* href="https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto">Canonical
110+
* error codes for Google APIs</a>
111+
*/
112+
@IntDef({
113+
CANCELLED,
114+
UNKNOWN,
115+
INVALID_ARGUMENT,
116+
DEADLINE_EXCEEDED,
117+
NOT_FOUND,
118+
ALREADY_EXISTS,
119+
PERMISSION_DENIED,
120+
RESOURCE_EXHAUSTED,
121+
FAILED_PRECONDITION,
122+
ABORTED,
123+
OUT_OF_RANGE,
124+
UNIMPLEMENTED,
125+
INTERNAL,
126+
UNAVAILABLE,
127+
UNAUTHENTICATED,
128+
NOT_ENOUGH_SPACE
129+
})
130+
@Retention(RetentionPolicy.CLASS)
131+
public @interface Code {}
132+
133+
@Code private final int code;
134+
135+
/** @hide */
136+
public FirebaseMlException(@NonNull String detailMessage, @Code int code) {
137+
super(Preconditions.checkNotEmpty(detailMessage, "Provided message must not be empty."));
138+
this.code = code;
139+
}
140+
141+
/** @hide */
142+
public FirebaseMlException(
143+
@NonNull String detailMessage, @Code int code, @Nullable Throwable cause) {
144+
super(Preconditions.checkNotEmpty(detailMessage, "Provided message must not be empty."), cause);
145+
this.code = code;
146+
}
147+
148+
/** Gets the error code for the Firebase ML operation that failed. */
149+
@Code
150+
public int getCode() {
151+
return code;
152+
}
153+
}

firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloader.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import androidx.annotation.Nullable;
1919
import androidx.annotation.RequiresApi;
2020
import androidx.annotation.VisibleForTesting;
21+
import com.google.android.datatransport.TransportFactory;
2122
import com.google.android.gms.common.internal.Preconditions;
2223
import com.google.android.gms.tasks.Task;
2324
import com.google.android.gms.tasks.TaskCompletionSource;
@@ -45,9 +46,11 @@ public class FirebaseModelDownloader {
4546

4647
@RequiresApi(api = VERSION_CODES.KITKAT)
4748
FirebaseModelDownloader(
48-
FirebaseApp firebaseApp, FirebaseInstallationsApi firebaseInstallationsApi) {
49+
FirebaseApp firebaseApp,
50+
FirebaseInstallationsApi firebaseInstallationsApi,
51+
TransportFactory transportFactory) {
4952
this.firebaseOptions = firebaseApp.getOptions();
50-
this.fileDownloadService = new ModelFileDownloadService(firebaseApp);
53+
this.fileDownloadService = new ModelFileDownloadService(firebaseApp, transportFactory);
5154
this.sharedPreferencesUtil = new SharedPreferencesUtil(firebaseApp);
5255
this.modelDownloadService =
5356
new CustomModelDownloadService(firebaseOptions, firebaseInstallationsApi);
@@ -318,6 +321,15 @@ public Task<Void> deleteDownloadedModel(@NonNull String modelName) {
318321
return taskCompletionSource.getTask();
319322
}
320323

324+
/**
325+
* Update the settings which allow logging to firelog.
326+
*
327+
* @param enabled - is statistics logging enabled
328+
*/
329+
public void setStatsCollectionEnabled(boolean enabled) {
330+
sharedPreferencesUtil.setCustomModelStatsCollectionEnabled(enabled);
331+
}
332+
321333
/** Returns the nick name of the {@link FirebaseApp} of this {@link FirebaseModelDownloader} */
322334
@VisibleForTesting
323335
String getApplicationId() {

firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloaderRegistrar.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import android.os.Build.VERSION_CODES;
1818
import androidx.annotation.NonNull;
1919
import androidx.annotation.RequiresApi;
20+
import com.google.android.datatransport.TransportFactory;
2021
import com.google.firebase.FirebaseApp;
2122
import com.google.firebase.FirebaseOptions;
2223
import com.google.firebase.components.Component;
@@ -46,11 +47,14 @@ public List<Component<?>> getComponents() {
4647
return Arrays.asList(
4748
Component.builder(FirebaseModelDownloader.class)
4849
.add(Dependency.required(FirebaseApp.class))
50+
.add(Dependency.required(TransportFactory.class))
4951
.add(Dependency.required(FirebaseInstallationsApi.class))
5052
.factory(
5153
c ->
5254
new FirebaseModelDownloader(
53-
c.get(FirebaseApp.class), c.get(FirebaseInstallationsApi.class)))
55+
c.get(FirebaseApp.class),
56+
c.get(FirebaseInstallationsApi.class),
57+
c.get(TransportFactory.class)))
5458
.build(),
5559
Component.builder(SharedPreferencesUtil.class)
5660
.add(Dependency.required(FirebaseApp.class))
@@ -62,7 +66,11 @@ public List<Component<?>> getComponents() {
6266
.build(),
6367
Component.builder(ModelFileDownloadService.class)
6468
.add(Dependency.required(FirebaseApp.class))
65-
.factory(c -> new ModelFileDownloadService(c.get(FirebaseApp.class)))
69+
.add(Dependency.required(TransportFactory.class))
70+
.factory(
71+
c ->
72+
new ModelFileDownloadService(
73+
c.get(FirebaseApp.class), c.get(TransportFactory.class)))
6674
.build(),
6775
Component.builder(CustomModelDownloadService.class)
6876
.add(Dependency.required(FirebaseOptions.class))

firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/internal/CustomModelDownloadService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ private CustomModel readCustomModelResponse(
232232
expireTime = parseTokenExpirationTimestamp(reader.nextString());
233233
} else if (name.equals("sizeBytes")) {
234234
fileSize = reader.nextLong();
235+
} else if (name.equals("modelFormat")) {
236+
String modelFormat = reader.nextString();
237+
if (modelFormat.equals("MODEL_FORMAT_UNSPECIFIED")) {
238+
// log error but continue... this shouldn't happen
239+
Log.w(TAG, "Ignoring unexpected model type: " + modelFormat);
240+
}
235241
} else {
236242
reader.skipValue();
237243
}

0 commit comments

Comments
 (0)