blob: 61872a6342c801f202ca08a97c46ccebaee8be5e [file] [log] [blame]
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
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
17package com.example.android.systemupdatersample;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070022import org.json.JSONArray;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070023import org.json.JSONException;
24import org.json.JSONObject;
25
26import java.io.File;
27import java.io.Serializable;
Zhomart Mukhamejanov88712f72018-08-21 12:19:02 -070028import java.util.ArrayList;
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -070029import java.util.Optional;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070030
31/**
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070032 * An update description. It will be parsed from JSON, which is intended to
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070033 * be sent from server to the update app, but in this sample app it will be stored on the device.
34 */
35public class UpdateConfig implements Parcelable {
36
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070037 public static final int AB_INSTALL_TYPE_NON_STREAMING = 0;
38 public static final int AB_INSTALL_TYPE_STREAMING = 1;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070039
40 public static final Parcelable.Creator<UpdateConfig> CREATOR =
41 new Parcelable.Creator<UpdateConfig>() {
42 @Override
43 public UpdateConfig createFromParcel(Parcel source) {
44 return new UpdateConfig(source);
45 }
46
47 @Override
48 public UpdateConfig[] newArray(int size) {
49 return new UpdateConfig[size];
50 }
51 };
52
53 /** parse update config from json */
54 public static UpdateConfig fromJson(String json) throws JSONException {
55 UpdateConfig c = new UpdateConfig();
56
57 JSONObject o = new JSONObject(json);
58 c.mName = o.getString("name");
59 c.mUrl = o.getString("url");
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070060 switch (o.getString("ab_install_type")) {
61 case AB_INSTALL_TYPE_NON_STREAMING_JSON:
62 c.mAbInstallType = AB_INSTALL_TYPE_NON_STREAMING;
63 break;
64 case AB_INSTALL_TYPE_STREAMING_JSON:
65 c.mAbInstallType = AB_INSTALL_TYPE_STREAMING;
66 break;
67 default:
68 throw new JSONException("Invalid type, expected either "
69 + "NON_STREAMING or STREAMING, got " + o.getString("ab_install_type"));
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070070 }
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070071
72 // TODO: parse only for A/B updates when non-A/B is implemented
73 JSONObject ab = o.getJSONObject("ab_config");
74 boolean forceSwitchSlot = ab.getBoolean("force_switch_slot");
Zhomart Mukhamejanov88712f72018-08-21 12:19:02 -070075 boolean verifyPayloadMetadata = ab.getBoolean("verify_payload_metadata");
76 ArrayList<PackageFile> propertyFiles = new ArrayList<>();
77 if (ab.has("property_files")) {
78 JSONArray propertyFilesJson = ab.getJSONArray("property_files");
79 for (int i = 0; i < propertyFilesJson.length(); i++) {
80 JSONObject p = propertyFilesJson.getJSONObject(i);
81 propertyFiles.add(new PackageFile(
82 p.getString("filename"),
83 p.getLong("offset"),
84 p.getLong("size")));
85 }
86 }
87 String authorization = ab.optString("authorization", null);
88 c.mAbConfig = new AbConfig(
89 forceSwitchSlot,
90 verifyPayloadMetadata,
91 propertyFiles.toArray(new PackageFile[0]),
92 authorization);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070093
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070094 c.mRawJson = json;
95 return c;
96 }
97
98 /**
99 * these strings are represent types in JSON config files
100 */
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700101 private static final String AB_INSTALL_TYPE_NON_STREAMING_JSON = "NON_STREAMING";
102 private static final String AB_INSTALL_TYPE_STREAMING_JSON = "STREAMING";
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700103
104 /** name will be visible on UI */
105 private String mName;
106
107 /** update zip file URI, can be https:// or file:// */
108 private String mUrl;
109
110 /** non-streaming (first saves locally) OR streaming (on the fly) */
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700111 private int mAbInstallType;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700112
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700113 /** A/B update configurations */
114 private AbConfig mAbConfig;
115
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700116 private String mRawJson;
117
118 protected UpdateConfig() {
119 }
120
121 protected UpdateConfig(Parcel in) {
122 this.mName = in.readString();
123 this.mUrl = in.readString();
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700124 this.mAbInstallType = in.readInt();
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700125 this.mAbConfig = (AbConfig) in.readSerializable();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700126 this.mRawJson = in.readString();
127 }
128
129 public UpdateConfig(String name, String url, int installType) {
130 this.mName = name;
131 this.mUrl = url;
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700132 this.mAbInstallType = installType;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700133 }
134
135 public String getName() {
136 return mName;
137 }
138
139 public String getUrl() {
140 return mUrl;
141 }
142
143 public String getRawJson() {
144 return mRawJson;
145 }
146
147 public int getInstallType() {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700148 return mAbInstallType;
149 }
150
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700151 public AbConfig getAbConfig() {
152 return mAbConfig;
153 }
154
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700155 /**
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700156 * @return File object for given url
157 */
158 public File getUpdatePackageFile() {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700159 if (mAbInstallType != AB_INSTALL_TYPE_NON_STREAMING) {
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700160 throw new RuntimeException("Expected non-streaming install type");
161 }
162 if (!mUrl.startsWith("file://")) {
163 throw new RuntimeException("url is expected to start with file://");
164 }
165 return new File(mUrl.substring(7, mUrl.length()));
166 }
167
168 @Override
169 public int describeContents() {
170 return 0;
171 }
172
173 @Override
174 public void writeToParcel(Parcel dest, int flags) {
175 dest.writeString(mName);
176 dest.writeString(mUrl);
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700177 dest.writeInt(mAbInstallType);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700178 dest.writeSerializable(mAbConfig);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700179 dest.writeString(mRawJson);
180 }
181
182 /**
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700183 * Description of a file in an OTA package zip file.
184 */
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -0700185 public static class PackageFile implements Serializable {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700186
187 private static final long serialVersionUID = 31043L;
188
189 /** filename in an archive */
190 private String mFilename;
191
192 /** defines beginning of update data in archive */
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700193 private long mOffset;
194
195 /** size of the update data in archive */
196 private long mSize;
197
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -0700198 public PackageFile(String filename, long offset, long size) {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700199 this.mFilename = filename;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700200 this.mOffset = offset;
201 this.mSize = size;
202 }
203
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700204 public String getFilename() {
205 return mFilename;
206 }
207
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700208 public long getOffset() {
209 return mOffset;
210 }
211
212 public long getSize() {
213 return mSize;
214 }
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700215 }
216
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700217 /**
218 * A/B (seamless) update configurations.
219 */
220 public static class AbConfig implements Serializable {
221
222 private static final long serialVersionUID = 31044L;
223
224 /**
225 * if set true device will boot to new slot, otherwise user manually
226 * switches slot on the screen.
227 */
228 private boolean mForceSwitchSlot;
229
Zhomart Mukhamejanov88712f72018-08-21 12:19:02 -0700230 /**
231 * if set true device will boot to new slot, otherwise user manually
232 * switches slot on the screen.
233 */
234 private boolean mVerifyPayloadMetadata;
235
236 /** defines beginning of update data in archive */
237 private PackageFile[] mPropertyFiles;
238
239 /**
240 * SystemUpdaterSample receives the authorization token from the OTA server, in addition
241 * to the package URL. It passes on the info to update_engine, so that the latter can
242 * fetch the data from the package server directly with the token.
243 */
244 private String mAuthorization;
245
246 public AbConfig(
247 boolean forceSwitchSlot,
248 boolean verifyPayloadMetadata,
249 PackageFile[] propertyFiles,
250 String authorization) {
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700251 this.mForceSwitchSlot = forceSwitchSlot;
Zhomart Mukhamejanov88712f72018-08-21 12:19:02 -0700252 this.mVerifyPayloadMetadata = verifyPayloadMetadata;
253 this.mPropertyFiles = propertyFiles;
254 this.mAuthorization = authorization;
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700255 }
256
257 public boolean getForceSwitchSlot() {
258 return mForceSwitchSlot;
259 }
260
Zhomart Mukhamejanov88712f72018-08-21 12:19:02 -0700261 public boolean getVerifyPayloadMetadata() {
262 return mVerifyPayloadMetadata;
263 }
264
265 public PackageFile[] getPropertyFiles() {
266 return mPropertyFiles;
267 }
268
269 public Optional<String> getAuthorization() {
270 return mAuthorization == null ? Optional.empty() : Optional.of(mAuthorization);
271 }
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700272 }
273
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700274}