in firebase-ml-modeldownloader/src/main/java/com/google/firebase/ml/modeldownloader/FirebaseModelDownloader.java [258:369]
private Task<CustomModel> getCustomModelTask(
@NonNull String modelName,
@Nullable CustomModelDownloadConditions conditions,
@Nullable String modelHash) {
CustomModel currentModel = sharedPreferencesUtil.getCustomModelDetails(modelName);
if (currentModel == null && modelHash != null) {
Log.d(TAG, "Model hash provided but no current model; triggering fresh download.");
modelHash = null;
}
Task<CustomModel> incomingModelDetails =
modelDownloadService.getCustomModelDetails(
firebaseOptions.getProjectId(), modelName, modelHash);
return incomingModelDetails.continueWithTask(
executor,
incomingModelDetailTask -> {
if (incomingModelDetailTask.isSuccessful()) {
// null means we have the latest model or we failed to connect.
if (incomingModelDetailTask.getResult() == null) {
if (currentModel != null) {
return getCompletedLocalCustomModelTask(currentModel);
}
// double check due to timing.
CustomModel updatedModel = sharedPreferencesUtil.getCustomModelDetails(modelName);
if (updatedModel != null) {
return getCompletedLocalCustomModelTask(updatedModel);
}
// clean up model internally
deleteModelDetails(modelName);
return Tasks.forException(
new FirebaseMlException(
"Possible caching issues: no model associated with " + modelName + ".",
FirebaseMlException.INTERNAL));
}
// if modelHash matches current local model just return local model.
// Should be handled by above case but just in case.
if (currentModel != null) {
// is this the same model?
if (currentModel
.getModelHash()
.equals(incomingModelDetails.getResult().getModelHash())
&& currentModel.getLocalFilePath() != null
&& !currentModel.getLocalFilePath().isEmpty()
&& new File(currentModel.getLocalFilePath()).exists()) {
return getCompletedLocalCustomModelTask(currentModel);
}
// update is available
if (!currentModel
.getModelHash()
.equals(incomingModelDetails.getResult().getModelHash())) {
eventLogger.logDownloadEventWithErrorCode(
incomingModelDetails.getResult(),
false,
DownloadStatus.UPDATE_AVAILABLE,
ErrorCode.NO_ERROR);
}
// is download already in progress for this hash?
if (currentModel.getDownloadId() != 0) {
CustomModel downloadingModel =
sharedPreferencesUtil.getDownloadingCustomModelDetails(modelName);
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));
}
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));
}
}
// start download
return fileDownloadService
.download(incomingModelDetailTask.getResult(), conditions)
.continueWithTask(
executor,
downloadTask -> {
if (downloadTask.isSuccessful()) {
return finishModelDownload(modelName);
} else {
return retryExpiredUrlDownload(modelName, conditions, downloadTask, 2);
}
});
}
return Tasks.forException(incomingModelDetailTask.getException());
});
}