• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.libraries.mobiledatadownload;
17 
18 import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
19 
20 import com.google.android.libraries.mobiledatadownload.tracing.PropagatedFutures;
21 import com.google.common.base.Preconditions;
22 import com.google.common.util.concurrent.ListenableFuture;
23 import com.google.common.util.concurrent.MoreExecutors;
24 import com.google.errorprone.annotations.CanIgnoreReturnValue;
25 
26 /** Thrown when there is a download failure. */
27 public final class DownloadException extends Exception {
28   /** This error code is a representation of {@code MddDownloadResult.Code}. */
29   private final DownloadResultCode downloadResultCode;
30 
31   /**
32    * This is the result of calling download, which should be identical to {@code
33    * MddDownloadResult.Code}.
34    */
35   // LINT.IfChange
36   public enum DownloadResultCode {
37     UNSPECIFIED(0), // unset value
38 
39     // File downloaded successfully.
40     // This is just a placeholder, we currently don't log for success case.
41     SUCCESS(1),
42 
43     // The error we don't know.
44     UNKNOWN_ERROR(2),
45 
46     // The errors from the android downloader outside MDD, which comes from:
47     // <internal>
48     ANDROID_DOWNLOADER_UNKNOWN(100),
49     ANDROID_DOWNLOADER_CANCELED(101),
50     ANDROID_DOWNLOADER_INVALID_REQUEST(102),
51     ANDROID_DOWNLOADER_HTTP_ERROR(103),
52     ANDROID_DOWNLOADER_REQUEST_ERROR(104),
53     ANDROID_DOWNLOADER_RESPONSE_OPEN_ERROR(105),
54     ANDROID_DOWNLOADER_RESPONSE_CLOSE_ERROR(106),
55     ANDROID_DOWNLOADER_NETWORK_IO_ERROR(107),
56     ANDROID_DOWNLOADER_DISK_IO_ERROR(108),
57     ANDROID_DOWNLOADER_FILE_SYSTEM_ERROR(109),
58     ANDROID_DOWNLOADER_UNKNOWN_IO_ERROR(110),
59     ANDROID_DOWNLOADER_OAUTH_ERROR(111),
60 
61     // The errors from the android downloader v2 outside MDD, which comes from:
62     // <internal>
63     ANDROID_DOWNLOADER2_ERROR(200),
64 
65     // The data file group has not been added to MDD by the time the caller
66     // makes download API call.
67     GROUP_NOT_FOUND_ERROR(300),
68 
69     // The DownloadListener is present but the DownloadMonitor is not provided.
70     DOWNLOAD_MONITOR_NOT_PROVIDED_ERROR(301),
71 
72     // Errors from unsatisfied download preconditions.
73     INSECURE_URL_ERROR(302),
74     LOW_DISK_ERROR(303),
75 
76     // Errors from download preparation.
77     UNABLE_TO_CREATE_FILE_URI_ERROR(304),
78     SHARED_FILE_NOT_FOUND_ERROR(305),
79     MALFORMED_FILE_URI_ERROR(306),
80     UNABLE_TO_CREATE_MOBSTORE_RESPONSE_WRITER_ERROR(307),
81 
82     // Errors from file validation.
83     UNABLE_TO_VALIDATE_DOWNLOAD_FILE_ERROR(308),
84     DOWNLOADED_FILE_NOT_FOUND_ERROR(309),
85     DOWNLOADED_FILE_CHECKSUM_MISMATCH_ERROR(310),
86     CUSTOM_FILEGROUP_VALIDATION_FAILED(330),
87 
88     // Errors from download transforms.
89     UNABLE_TO_SERIALIZE_DOWNLOAD_TRANSFORM_ERROR(311),
90     DOWNLOAD_TRANSFORM_IO_ERROR(312),
91     FINAL_FILE_CHECKSUM_MISMATCH_ERROR(313),
92 
93     // Errors from delta download.
94     DELTA_DOWNLOAD_BASE_FILE_NOT_FOUND_ERROR(314),
95     DELTA_DOWNLOAD_DECODE_IO_ERROR(315),
96 
97     // The error occurs after the file is ready.
98     UNABLE_TO_UPDATE_FILE_STATE_ERROR(316),
99 
100     // Fail to update the file group metadata.
101     UNABLE_TO_UPDATE_GROUP_METADATA_ERROR(317),
102 
103     // Errors from sharing files with the blob storage.
104     // Failed to update the metadata max_expiration_date.
105     UNABLE_TO_UPDATE_FILE_MAX_EXPIRATION_DATE(318),
106     // Failed to share the file before SharedFileManager.startDownload is called.
107     UNABLE_SHARE_FILE_BEFORE_DOWNLOAD_ERROR(319),
108     // Failed to share the file after SharedFileManager.startDownload is called.
109     UNABLE_SHARE_FILE_AFTER_DOWNLOAD_ERROR(320),
110 
111     // Download errors related to isolated file structure
112     UNABLE_TO_REMOVE_SYMLINK_STRUCTURE(321),
113     UNABLE_TO_CREATE_SYMLINK_STRUCTURE(322),
114 
115     // Download errors related to importing inline files
116     // Failed to reserve file entries
117     UNABLE_TO_RESERVE_FILE_ENTRY(323),
118     // Invalid use of inlinefile url scheme
119     INVALID_INLINE_FILE_URL_SCHEME(324),
120     // Error performing inline file download
121     INLINE_FILE_IO_ERROR(327),
122     // Missing required inline download parms in FileDownloader's DownloadRequest
123     MISSING_INLINE_DOWNLOAD_PARAMS(328),
124     // Missing required inline file source in ImportFilesRequest
125     MISSING_INLINE_FILE_SOURCE(329),
126 
127     // Download errors related to URL parsing
128     MALFORMED_DOWNLOAD_URL(325),
129     UNSUPPORTED_DOWNLOAD_URL_SCHEME(326),
130 
131     // Download errors for manifest file group populator.
132     MANIFEST_FILE_GROUP_POPULATOR_INVALID_FLAG_ERROR(400),
133     MANIFEST_FILE_GROUP_POPULATOR_CONTENT_CHANGED_DURING_DOWNLOAD_ERROR(401),
134     MANIFEST_FILE_GROUP_POPULATOR_PARSE_MANIFEST_FILE_ERROR(402),
135     MANIFEST_FILE_GROUP_POPULATOR_DELETE_MANIFEST_FILE_ERROR(403),
136     MANIFEST_FILE_GROUP_POPULATOR_METADATA_IO_ERROR(404),
137 
138     // GDD specific download errors, reserved from 2000-2999.
139     GDD_INVALID_ACCOUNT(2000),
140     GDD_INVALID_AUTH_TOKEN(2001),
141     GDD_FAIL_IN_SYNC_RUNNER(2002),
142     GDD_INVALID_ELEMENT_COMBINATION_RECEIVED(2003),
143     GDD_INVALID_INLINE_PAYLOAD_ELEMENT_DATA(2004),
144     GDD_INVALID_CURRENT_ACTIVE_ELEMENT_DATA(2005),
145     GDD_INVALID_NEXT_PENDING_ELEMENT_DATA(2006),
146     GDD_CURRENT_ACTIVE_GROUP_HAS_NO_INLINE_FILE(2007),
147     GDD_FAIL_TO_ADD_NEXT_PENDING_GROUP(2008),
148     GDD_MISSING_ACCOUNT_FOR_PRIVATE_SYNC(2009),
149     GDD_FAIL_IN_SYNC_RUNNER_PUBLIC(2010),
150     GDD_FAIL_IN_SYNC_RUNNER_PRIVATE(2011),
151     GDD_PUBLIC_SYNC_SUCCESS(2012),
152     GDD_PRIVATE_SYNC_SUCCESS(2013),
153     GDD_FAIL_TO_RETRIEVE_ZWIEBACK_TOKEN(2014);
154 
155     private final int code;
156 
DownloadResultCode(int code)157     DownloadResultCode(int code) {
158       this.code = code;
159     }
160 
161     /** Returns the int code corresponding to this enum value. */
getCode()162     public int getCode() {
163       return code;
164     }
165   }
166   // LINT.ThenChange(<internal>)
167 
168   /** Builder for {@link DownloadException}. */
169   public static final class Builder {
170     private DownloadResultCode downloadResultCode;
171     private String message;
172     private Throwable cause;
173 
174     /** Sets the {@link DownloadResultCode}. */
175     @CanIgnoreReturnValue
setDownloadResultCode(DownloadResultCode downloadResultCode)176     public Builder setDownloadResultCode(DownloadResultCode downloadResultCode) {
177       this.downloadResultCode = downloadResultCode;
178       return this;
179     }
180 
181     /** Sets the error message. */
182     @CanIgnoreReturnValue
setMessage(String message)183     public Builder setMessage(String message) {
184       this.message = message;
185       return this;
186     }
187 
188     /** Sets the cause of the exception. */
189     @CanIgnoreReturnValue
setCause(Throwable cause)190     public Builder setCause(Throwable cause) {
191       this.cause = cause;
192       return this;
193     }
194 
195     /** Returns a {@link DownloadException} instance. */
build()196     public DownloadException build() {
197       Preconditions.checkNotNull(downloadResultCode);
198       if (message == null) {
199         message = "Download result code: " + downloadResultCode.name();
200       }
201       return new DownloadException(this);
202     }
203   }
204 
205   /** Returns a Builder for {@link DownloadException}. */
builder()206   public static Builder builder() {
207     return new Builder();
208   }
209 
getDownloadResultCode()210   public DownloadResultCode getDownloadResultCode() {
211     return downloadResultCode;
212   }
213 
214   /**
215    * Wraps the throwable with {@link DownloadException} and returns a failed future only if the
216    * input future fails.
217    */
wrapIfFailed( ListenableFuture<T> future, DownloadResultCode code, String message)218   public static <T> ListenableFuture<T> wrapIfFailed(
219       ListenableFuture<T> future, DownloadResultCode code, String message) {
220     return PropagatedFutures.catchingAsync(
221         future,
222         Throwable.class,
223         (Throwable t) -> immediateFailedFuture(wrap(t, code, message)),
224         MoreExecutors.directExecutor());
225   }
226 
227   /** Wraps the throwable with {@link DownloadException}. */
wrap( Throwable throwable, DownloadResultCode code, String message)228   private static DownloadException wrap(
229       Throwable throwable, DownloadResultCode code, String message) {
230     return DownloadException.builder()
231         .setDownloadResultCode(code)
232         .setMessage(message)
233         .setCause(throwable)
234         .build();
235   }
236 
DownloadException(Builder builder)237   private DownloadException(Builder builder) {
238     super(builder.message, builder.cause);
239     this.downloadResultCode = builder.downloadResultCode;
240   }
241 }
242