• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 
17 #include <string_view>
18 
19 #include "pw_result/result.h"
20 #include "pw_software_update/manifest_accessor.h"
21 #include "pw_software_update/update_bundle_accessor.h"
22 #include "pw_status/status.h"
23 #include "pw_stream/interval_reader.h"
24 #include "pw_stream/stream.h"
25 
26 namespace pw::software_update {
27 
28 // TODO(b/235273688): update documentation for backend api contract
29 class BundledUpdateBackend {
30  public:
31   virtual ~BundledUpdateBackend() = default;
32 
33   // Perform optional, product-specific validations to the specified target
34   // file, using whatever metadata available in manifest.
35   //
36   // This is called for each target file after the standard verification has
37   // passed.
VerifyTargetFile(ManifestAccessor manifest,std::string_view target_file_name)38   virtual Status VerifyTargetFile(
39       [[maybe_unused]] ManifestAccessor manifest,
40       [[maybe_unused]] std::string_view target_file_name) {
41     // TODO(backend): Perform any additional product-specific validations.
42     // It is safe to assume the target's payload has passed standard
43     // verification.
44     return OkStatus();
45   }
46 
47   // Perform any product-specific tasks needed before starting update sequence.
BeforeUpdateStart()48   virtual Status BeforeUpdateStart() { return OkStatus(); }
49 
50   // Attempts to enable the transfer service transfer handler, returning the
51   // transfer_id if successful. This is invoked after BeforeUpdateStart();
52   virtual Result<uint32_t> EnableBundleTransferHandler(
53       std::string_view bundle_filename) = 0;
54 
55   // Disables the transfer service transfer handler. This is invoked after
56   // either BeforeUpdateAbort() or BeforeBundleVerify().
57   virtual void DisableBundleTransferHandler() = 0;
58 
59   // Perform any product-specific abort tasks before marking the update as
60   // aborted in bundled updater.  This should set any downstream state to a
61   // default no-update-pending state.
62   // TODO(keir): Revisit invariants; should this instead be "Abort()"? This is
63   // called for all error paths in the service and needs to reset. Furthermore,
64   // should this be async?
BeforeUpdateAbort()65   virtual Status BeforeUpdateAbort() { return OkStatus(); }
66 
67   // Perform any product-specific tasks needed before starting verification.
BeforeBundleVerify()68   virtual Status BeforeBundleVerify() { return OkStatus(); }
69 
70   // Perform any product-specific bundle verification tasks (e.g. hw version
71   // match check), done after TUF bundle verification process.
VerifyManifest(ManifestAccessor manifest_accessor)72   virtual Status VerifyManifest(
73       [[maybe_unused]] ManifestAccessor manifest_accessor) {
74     return OkStatus();
75   }
76 
77   // Perform product-specific tasks after all bundle verifications are complete.
AfterBundleVerified()78   virtual Status AfterBundleVerified() { return OkStatus(); }
79 
80   // Perform any product-specific tasks before apply sequence started
BeforeApply()81   virtual Status BeforeApply() { return OkStatus(); }
82 
83   // Get status information from update backend. This will not be called when
84   // BundledUpdater is in a step where it has entire control with no operation
85   // handed over to update backend.
GetStatus()86   virtual int64_t GetStatus() { return 0; }
87 
88   // Update the specific target file on the device.
89   virtual Status ApplyTargetFile(std::string_view target_file_name,
90                                  stream::Reader& target_payload,
91                                  size_t update_bundle_offset) = 0;
92 
93   // Backend to probe the device manifest and prepare a ready-to-go reader
94   // for it. See the comments to `GetCurrentManfestReader()` for more context.
BeforeManifestRead()95   virtual Status BeforeManifestRead() {
96     // Todo(backend):
97     // 1. Probe device to see if a well-formed manifest already exists.
98     // 2. If not, return `Status::NotFound()`. Note this will cause
99     //    anti-rollback to skip. So please don't always return
100     //    `Status::NotFound()`!
101     // 3. If yes, instantiate and activate a reader for the manifest!
102     // 4. Return any unexpected condition as errors but note this will cause
103     //    the current software update session to abort.
104     return OkStatus();
105   }
106 
107   // Backend to provide a ready-to-go reader for the on-device manifest blob.
108   // This function is called after a successful `BeforeManifestRead()`,
109   // potentially more than once.
110   //
111   // This manifest blob is a serialized `message Manifest{...}` as defined in
112   // update_bundle.proto.
113   //
114   // This manifest blob is ALWAYS and EXCLUSIVELY persisted by a successful
115   // software update. Thus it may not available before the first software
116   // update, in which case `BeforeManifestRead()` should've returned
117   // `Status::NotFound()`.
118   //
119   // This manifest contains trusted metadata of all software currently running
120   // on the device and used for anti-rollback checks. It MUST NOT be tampered
121   // by factory resets, flashing, or any other means other than software
122   // updates.
GetCurrentManifestReader()123   virtual Result<stream::SeekableReader*> GetCurrentManifestReader() {
124     // Todo(backend):
125     // 1. Double check if a ready-to-go reader has been prepared by
126     //    `BeforeManifestRead()`.
127     // 2. If yes (expected), return the reader.
128     // 3. If not (unexpected), return `Status::FailedPrecondition()`.
129     return Status::Unimplemented();
130   }
131 
132   // TODO(alizhang): Deprecate GetCurrentManifestReader in favor of
133   // `GetManifestReader()`.
GetManifestReader()134   virtual Result<stream::SeekableReader*> GetManifestReader() {
135     return GetCurrentManifestReader();
136   }
137 
138   // Backend to prepare for on-device manifest update, e.g. make necessary
139   // efforts to ready the manifest writer. The manifest writer is used to
140   // persist a new manifest on-device following a successful software update.
141   // Manifest writing is never mixed with reading (i.e. reader and writer are
142   // used sequentially).
BeforeManifestWrite()143   virtual Status BeforeManifestWrite() {
144     // Todo(backend):
145     // 1. Instantiate and activate a manifest writer pointing at a persistent
146     //    storage that at least could survive a factory data reset (FDR), if not
147     //    tamper-resistant.
148     return OkStatus();
149   }
150 
151   // Backend to provide a ready-to-go writer for the on-device manifest blob.
152   // This function is called after a successful `BeforeManifestWrite()`,
153   // potentially more than once.
154   //
155   // This manifest blob is a serialized `message Manifest{...}` as defined in
156   // update_bundle.proto.
157   //
158   // This manifest blob is ALWAYS and EXCLUSIVELY persisted by a successful
159   // software update.
160   //
161   // This manifest contains trusted metadata of all software currently running
162   // on the device and used for anti-rollback checks. It MUST NOT be tampered
163   // by factory resets, flashing, or any other means other than software
164   // updates.
GetManifestWriter()165   virtual Result<stream::Writer*> GetManifestWriter() {
166     // Todo(backend):
167     // 1. Double check a writer is ready to go as result of
168     //    `BeforeManifestWrite()`.
169     // 2. If yes (expected), simply return the writer.
170     // 3. If not (unexpected), return `Status::FailedPrecondition()`.
171     return Status::Unimplemented();
172   }
173 
174   // Backend to finish up manifest writing.
AfterManifestWrite()175   virtual Status AfterManifestWrite() {
176     // Todo(backend):
177     // Protect the newly persisted manifest blob. This is to make manifest
178     // probing / reading easier and more reliable. This could involve taking
179     // a measurement (e.g. checksum) and storing that measurement in a
180     // FDR-safe tag, replicating the manifest in a backup location if the
181     // backing media is unreliable (e.g. raw NAND) etc.
182     //
183     // It is safe to assume the writing has been successful in this function.
184     return OkStatus();
185   }
186 
187   // Do any work needed to finish the apply of the update and do a required
188   // reboot of the device!
189   //
190   // NOTE: If successful this method does not return and reboots the device, it
191   // only returns on failure to finalize.
192   //
193   // NOTE: ApplyReboot shall be configured such to allow pending RPC or logs to
194   // send out the reply before the device reboots.
195   virtual Status ApplyReboot() = 0;
196 
197   // Do any work needed to finalize the update including optionally doing a
198   // reboot of the device! The software update state and breadcrumbs are not
199   // cleaned up until this method returns OK.
200   //
201   // This method is called after the reboot done as part of ApplyReboot().
202   //
203   // If this method does an optional reboot, it will be called again after the
204   // reboot.
205   //
206   // NOTE: PostRebootFinalize shall be configured such to allow pending RPC or
207   // logs to send out the reply before the device reboots.
PostRebootFinalize()208   virtual Status PostRebootFinalize() { return OkStatus(); }
209 
210   // Get reader of the device's root metadata.
211   //
212   // This method MUST return a valid root metadata once verified OTA is enabled.
213   // An invalid or corrupted root metadata will result in permanent OTA
214   // failures.
GetRootMetadataReader()215   virtual Result<stream::SeekableReader*> GetRootMetadataReader() {
216     return Status::Unimplemented();
217   }
218 
219   // Write a given root metadata to persistent storage in a failsafe manner.
220   //
221   // The updating must be atomic/fail-safe. An invalid or corrupted root
222   // metadata will result in permanent OTA failures.
SafelyPersistRootMetadata(stream::IntervalReader root_metadata)223   virtual Status SafelyPersistRootMetadata(
224       [[maybe_unused]] stream::IntervalReader root_metadata) {
225     return Status::Unimplemented();
226   }
227 };
228 
229 }  // namespace pw::software_update
230