blob: 1e0fadc27166553b78fa32e1a2dfc929b7a9b826 [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 Mukhamejanov6aa5fb02018-05-09 14:28:49 -070028import java.util.Optional;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070029
30/**
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070031 * An update description. It will be parsed from JSON, which is intended to
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070032 * be sent from server to the update app, but in this sample app it will be stored on the device.
33 */
34public class UpdateConfig implements Parcelable {
35
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070036 public static final int AB_INSTALL_TYPE_NON_STREAMING = 0;
37 public static final int AB_INSTALL_TYPE_STREAMING = 1;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070038
39 public static final Parcelable.Creator<UpdateConfig> CREATOR =
40 new Parcelable.Creator<UpdateConfig>() {
41 @Override
42 public UpdateConfig createFromParcel(Parcel source) {
43 return new UpdateConfig(source);
44 }
45
46 @Override
47 public UpdateConfig[] newArray(int size) {
48 return new UpdateConfig[size];
49 }
50 };
51
52 /** parse update config from json */
53 public static UpdateConfig fromJson(String json) throws JSONException {
54 UpdateConfig c = new UpdateConfig();
55
56 JSONObject o = new JSONObject(json);
57 c.mName = o.getString("name");
58 c.mUrl = o.getString("url");
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070059 switch (o.getString("ab_install_type")) {
60 case AB_INSTALL_TYPE_NON_STREAMING_JSON:
61 c.mAbInstallType = AB_INSTALL_TYPE_NON_STREAMING;
62 break;
63 case AB_INSTALL_TYPE_STREAMING_JSON:
64 c.mAbInstallType = AB_INSTALL_TYPE_STREAMING;
65 break;
66 default:
67 throw new JSONException("Invalid type, expected either "
68 + "NON_STREAMING or STREAMING, got " + o.getString("ab_install_type"));
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070069 }
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070070 if (c.mAbInstallType == AB_INSTALL_TYPE_STREAMING) {
71 JSONObject meta = o.getJSONObject("ab_streaming_metadata");
72 JSONArray propertyFilesJson = meta.getJSONArray("property_files");
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -070073 PackageFile[] propertyFiles =
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070074 new PackageFile[propertyFilesJson.length()];
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070075 for (int i = 0; i < propertyFilesJson.length(); i++) {
76 JSONObject p = propertyFilesJson.getJSONObject(i);
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -070077 propertyFiles[i] = new PackageFile(
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -070078 p.getString("filename"),
79 p.getLong("offset"),
80 p.getLong("size"));
81 }
Zhomart Mukhamejanovbb8a2152018-05-10 12:19:16 -070082 String authorization = null;
83 if (meta.has("authorization")) {
84 authorization = meta.getString("authorization");
85 }
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -070086 c.mAbStreamingMetadata = new StreamingMetadata(
87 propertyFiles,
Zhomart Mukhamejanovbb8a2152018-05-10 12:19:16 -070088 authorization);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070089 }
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -070090
91 // TODO: parse only for A/B updates when non-A/B is implemented
92 JSONObject ab = o.getJSONObject("ab_config");
93 boolean forceSwitchSlot = ab.getBoolean("force_switch_slot");
94 c.mAbConfig = new AbConfig(forceSwitchSlot);
95
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -070096 c.mRawJson = json;
97 return c;
98 }
99
100 /**
101 * these strings are represent types in JSON config files
102 */
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700103 private static final String AB_INSTALL_TYPE_NON_STREAMING_JSON = "NON_STREAMING";
104 private static final String AB_INSTALL_TYPE_STREAMING_JSON = "STREAMING";
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700105
106 /** name will be visible on UI */
107 private String mName;
108
109 /** update zip file URI, can be https:// or file:// */
110 private String mUrl;
111
112 /** non-streaming (first saves locally) OR streaming (on the fly) */
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700113 private int mAbInstallType;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700114
115 /** metadata is required only for streaming update */
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700116 private StreamingMetadata mAbStreamingMetadata;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700117
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700118 /** A/B update configurations */
119 private AbConfig mAbConfig;
120
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700121 private String mRawJson;
122
123 protected UpdateConfig() {
124 }
125
126 protected UpdateConfig(Parcel in) {
127 this.mName = in.readString();
128 this.mUrl = in.readString();
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700129 this.mAbInstallType = in.readInt();
130 this.mAbStreamingMetadata = (StreamingMetadata) in.readSerializable();
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700131 this.mAbConfig = (AbConfig) in.readSerializable();
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700132 this.mRawJson = in.readString();
133 }
134
135 public UpdateConfig(String name, String url, int installType) {
136 this.mName = name;
137 this.mUrl = url;
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700138 this.mAbInstallType = installType;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700139 }
140
141 public String getName() {
142 return mName;
143 }
144
145 public String getUrl() {
146 return mUrl;
147 }
148
149 public String getRawJson() {
150 return mRawJson;
151 }
152
153 public int getInstallType() {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700154 return mAbInstallType;
155 }
156
157 public StreamingMetadata getStreamingMetadata() {
158 return mAbStreamingMetadata;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700159 }
160
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700161 public AbConfig getAbConfig() {
162 return mAbConfig;
163 }
164
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700165 /**
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700166 * @return File object for given url
167 */
168 public File getUpdatePackageFile() {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700169 if (mAbInstallType != AB_INSTALL_TYPE_NON_STREAMING) {
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700170 throw new RuntimeException("Expected non-streaming install type");
171 }
172 if (!mUrl.startsWith("file://")) {
173 throw new RuntimeException("url is expected to start with file://");
174 }
175 return new File(mUrl.substring(7, mUrl.length()));
176 }
177
178 @Override
179 public int describeContents() {
180 return 0;
181 }
182
183 @Override
184 public void writeToParcel(Parcel dest, int flags) {
185 dest.writeString(mName);
186 dest.writeString(mUrl);
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700187 dest.writeInt(mAbInstallType);
188 dest.writeSerializable(mAbStreamingMetadata);
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700189 dest.writeSerializable(mAbConfig);
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700190 dest.writeString(mRawJson);
191 }
192
193 /**
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700194 * Metadata for streaming A/B update.
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700195 */
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700196 public static class StreamingMetadata implements Serializable {
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700197
198 private static final long serialVersionUID = 31042L;
199
200 /** defines beginning of update data in archive */
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -0700201 private PackageFile[] mPropertyFiles;
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700202
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700203 /**
204 * SystemUpdaterSample receives the authorization token from the OTA server, in addition
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -0700205 * to the package URL. It passes on the info to update_engine, so that the latter can
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700206 * fetch the data from the package server directly with the token.
207 */
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -0700208 private String mAuthorization;
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700209
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -0700210 public StreamingMetadata(PackageFile[] propertyFiles, String authorization) {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700211 this.mPropertyFiles = propertyFiles;
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -0700212 this.mAuthorization = authorization;
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700213 }
214
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -0700215 public PackageFile[] getPropertyFiles() {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700216 return mPropertyFiles;
217 }
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -0700218
219 public Optional<String> getAuthorization() {
Zhomart Mukhamejanovbb8a2152018-05-10 12:19:16 -0700220 return mAuthorization == null ? Optional.empty() : Optional.of(mAuthorization);
Zhomart Mukhamejanov6aa5fb02018-05-09 14:28:49 -0700221 }
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700222 }
223
224 /**
225 * Description of a file in an OTA package zip file.
226 */
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -0700227 public static class PackageFile implements Serializable {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700228
229 private static final long serialVersionUID = 31043L;
230
231 /** filename in an archive */
232 private String mFilename;
233
234 /** defines beginning of update data in archive */
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700235 private long mOffset;
236
237 /** size of the update data in archive */
238 private long mSize;
239
Zhomart Mukhamejanov0dd5a832018-04-23 11:38:54 -0700240 public PackageFile(String filename, long offset, long size) {
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700241 this.mFilename = filename;
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700242 this.mOffset = offset;
243 this.mSize = size;
244 }
245
Zhomart Mukhamejanov963e3ee2018-04-26 21:07:05 -0700246 public String getFilename() {
247 return mFilename;
248 }
249
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700250 public long getOffset() {
251 return mOffset;
252 }
253
254 public long getSize() {
255 return mSize;
256 }
Zhomart Mukhamejanovf4d280c2018-04-17 13:20:22 -0700257 }
258
Zhomart Mukhamejanov238beb72018-05-09 16:25:40 -0700259 /**
260 * A/B (seamless) update configurations.
261 */
262 public static class AbConfig implements Serializable {
263
264 private static final long serialVersionUID = 31044L;
265
266 /**
267 * if set true device will boot to new slot, otherwise user manually
268 * switches slot on the screen.
269 */
270 private boolean mForceSwitchSlot;
271
272 public AbConfig(boolean forceSwitchSlot) {
273 this.mForceSwitchSlot = forceSwitchSlot;
274 }
275
276 public boolean getForceSwitchSlot() {
277 return mForceSwitchSlot;
278 }
279
280 }
281
Zhomart Mukhamejanov6f26e712018-05-18 10:15:31 -0700282}