updater_sample: add http header demo

Added demo passing http headers to UpdateEngine#applyPayload.

Bug: 79483768
Test: manually
Change-Id: I3e9c812dba2066acadbcea8d07c933368806e20c
Signed-off-by: Zhomart Mukhamejanov <zhomart@google.com>
This commit is contained in:
Zhomart Mukhamejanov 2018-05-09 14:28:49 -07:00
parent daa86e9024
commit 6aa5fb0bbe
4 changed files with 51 additions and 13 deletions

View file

@ -61,6 +61,17 @@ purpose only.
6. Push OTA packages to the device. 6. Push OTA packages to the device.
## Sending HTTP headers from UpdateEngine
Sometimes OTA package server might require some HTTP headers to be present,
e.g. `Authorization` header to contain valid auth token. While performing
streaming update, `UpdateEngine` allows passing on certain HTTP headers;
as of writing this sample app, these headers are `Authorization` and `User-Agent`.
`android.os.UpdateEngine#applyPayload` contains information on
which HTTP headers are supported.
## Development ## Development
- [x] Create a UI with list of configs, current version, - [x] Create a UI with list of configs, current version,
@ -72,12 +83,12 @@ purpose only.
- [x] Prepare streaming update (partially downloading package) - [x] Prepare streaming update (partially downloading package)
- [x] Add applying streaming update - [x] Add applying streaming update
- [x] Add stop/reset the update - [x] Add stop/reset the update
- [x] Add demo for passing HTTP headers to `UpdateEngine#applyPayload`
- [ ] Add tests for `MainActivity` - [ ] Add tests for `MainActivity`
- [ ] Verify system partition checksum for package
- [ ] HAL compatibility check - [ ] HAL compatibility check
- [ ] Change partition demo - [ ] Change partition demo
- [ ] Verify system partition checksum for package
- [ ] Add non-A/B updates demo - [ ] Add non-A/B updates demo
- [ ] Add docs for passing HTTP headers to `UpdateEngine#applyPayload`
## Running tests ## Running tests

View file

@ -8,6 +8,7 @@
"ab_streaming_metadata": { "ab_streaming_metadata": {
"__": "streaming_metadata is required only for streaming update", "__": "streaming_metadata is required only for streaming update",
"__property_files": "name, offset and size of files", "__property_files": "name, offset and size of files",
"__authorization": "it will be sent to OTA package server as value of HTTP header - Authorization",
"property_files": [ "property_files": [
{ {
"__filename": "name of the file in package", "__filename": "name of the file in package",
@ -17,6 +18,7 @@
"offset": 531, "offset": 531,
"size": 5012323 "size": 5012323
} }
] ],
"authorization": "Basic my-secret-token"
} }
} }

View file

@ -25,6 +25,7 @@ import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.io.Serializable; import java.io.Serializable;
import java.util.Optional;
/** /**
* An update description. It will be parsed from JSON, which is intended to * An update description. It will be parsed from JSON, which is intended to
@ -78,7 +79,9 @@ public class UpdateConfig implements Parcelable {
p.getLong("offset"), p.getLong("offset"),
p.getLong("size")); p.getLong("size"));
} }
c.mAbStreamingMetadata = new StreamingMetadata(propertyFiles); c.mAbStreamingMetadata = new StreamingMetadata(
propertyFiles,
meta.getString("authorization_token"));
} }
c.mRawJson = json; c.mRawJson = json;
return c; return c;
@ -178,17 +181,23 @@ public class UpdateConfig implements Parcelable {
/** defines beginning of update data in archive */ /** defines beginning of update data in archive */
private PackageFile[] mPropertyFiles; private PackageFile[] mPropertyFiles;
public StreamingMetadata() { /** SystemUpdaterSample receives the authorization token from the OTA server, in addition
mPropertyFiles = new PackageFile[0]; * to the package URL. It passes on the info to update_engine, so that the latter can
} * fetch the data from the package server directly with the token. */
private String mAuthorization;
public StreamingMetadata(PackageFile[] propertyFiles) { public StreamingMetadata(PackageFile[] propertyFiles, String authorization) {
this.mPropertyFiles = propertyFiles; this.mPropertyFiles = propertyFiles;
this.mAuthorization = authorization;
} }
public PackageFile[] getPropertyFiles() { public PackageFile[] getPropertyFiles() {
return mPropertyFiles; return mPropertyFiles;
} }
public Optional<String> getAuthorization() {
return Optional.of(mAuthorization);
}
} }
/** /**
@ -224,7 +233,6 @@ public class UpdateConfig implements Parcelable {
public long getSize() { public long getSize() {
return mSize; return mSize;
} }
} }
} }

View file

@ -41,6 +41,7 @@ import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
import com.example.android.systemupdatersample.util.UpdateEngineStatuses; import com.example.android.systemupdatersample.util.UpdateEngineStatuses;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -51,6 +52,10 @@ public class MainActivity extends Activity {
private static final String TAG = "MainActivity"; private static final String TAG = "MainActivity";
/** HTTP Header: User-Agent; it will be sent to the server when streaming the payload. */
private static final String HTTP_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";
private TextView mTextViewBuild; private TextView mTextViewBuild;
private Spinner mSpinnerConfigs; private Spinner mSpinnerConfigs;
private TextView mTextViewConfigsDirHint; private TextView mTextViewConfigsDirHint;
@ -295,12 +300,17 @@ public class MainActivity extends Activity {
.show(); .show();
return; return;
} }
updateEngineApplyPayload(payload); updateEngineApplyPayload(payload, null);
} else { } else {
Log.d(TAG, "Starting PrepareStreamingService"); Log.d(TAG, "Starting PrepareStreamingService");
PrepareStreamingService.startService(this, config, (code, payloadSpec) -> { PrepareStreamingService.startService(this, config, (code, payloadSpec) -> {
if (code == PrepareStreamingService.RESULT_CODE_SUCCESS) { if (code == PrepareStreamingService.RESULT_CODE_SUCCESS) {
updateEngineApplyPayload(payloadSpec); List<String> extraProperties = new ArrayList<>();
extraProperties.add("USER_AGENT=" + HTTP_USER_AGENT);
config.getStreamingMetadata()
.getAuthorization()
.ifPresent(s -> extraProperties.add("AUTHORIZATION=" + s));
updateEngineApplyPayload(payloadSpec, extraProperties);
} else { } else {
Log.e(TAG, "PrepareStreamingService failed, result code is " + code); Log.e(TAG, "PrepareStreamingService failed, result code is " + code);
Toast.makeText( Toast.makeText(
@ -317,14 +327,21 @@ public class MainActivity extends Activity {
* *
* UpdateEngine works asynchronously. This method doesn't wait until * UpdateEngine works asynchronously. This method doesn't wait until
* end of the update. * end of the update.
*
* @param payloadSpec contains url, offset and size to {@code PAYLOAD_BINARY_FILE_NAME}
* @param extraProperties additional properties to pass to {@link UpdateEngine#applyPayload}
*/ */
private void updateEngineApplyPayload(PayloadSpec payloadSpec) { private void updateEngineApplyPayload(PayloadSpec payloadSpec, List<String> extraProperties) {
ArrayList<String> properties = new ArrayList<>(payloadSpec.getProperties());
if (extraProperties != null) {
properties.addAll(extraProperties);
}
try { try {
mUpdateEngine.applyPayload( mUpdateEngine.applyPayload(
payloadSpec.getUrl(), payloadSpec.getUrl(),
payloadSpec.getOffset(), payloadSpec.getOffset(),
payloadSpec.getSize(), payloadSpec.getSize(),
payloadSpec.getProperties().toArray(new String[0])); properties.toArray(new String[0]));
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "UpdateEngine failed to apply the update", e); Log.e(TAG, "UpdateEngine failed to apply the update", e);
Toast.makeText( Toast.makeText(