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 "pw_software_update/bundled_update.rpc.pb.h"
18 #include "pw_software_update/bundled_update_backend.h"
19 #include "pw_software_update/update_bundle_accessor.h"
20 #include "pw_status/status.h"
21 #include "pw_sync/borrow.h"
22 #include "pw_sync/lock_annotations.h"
23 #include "pw_sync/mutex.h"
24 #include "pw_work_queue/work_queue.h"
25 
26 namespace pw::software_update {
27 
28 // Implementation class for pw.software_update.BundledUpdate.
29 // See bundled_update.proto for RPC method documentation.
30 class BundledUpdateService
31     : public pw_rpc::nanopb::BundledUpdate::Service<BundledUpdateService> {
32  public:
33   PW_MODIFY_DIAGNOSTICS_PUSH();
34   PW_MODIFY_DIAGNOSTIC(ignored, "-Wmissing-field-initializers");
BundledUpdateService(UpdateBundleAccessor & bundle,BundledUpdateBackend & backend,work_queue::WorkQueue & work_queue)35   BundledUpdateService(UpdateBundleAccessor& bundle,
36                        BundledUpdateBackend& backend,
37                        work_queue::WorkQueue& work_queue)
38       : unsafe_status_{.state =
39                            pw_software_update_BundledUpdateState_Enum_INACTIVE},
40         status_(unsafe_status_, status_mutex_),
41         backend_(backend),
42         bundle_(bundle),
43         bundle_open_(false),
44         work_queue_(work_queue),
45         work_enqueued_(false) {}
46   PW_MODIFY_DIAGNOSTICS_POP();
47 
48   Status GetStatus(const pw_protobuf_Empty& request,
49                    pw_software_update_BundledUpdateStatus& response);
50 
51   // Sync
52   Status Start(const pw_software_update_StartRequest& request,
53                pw_software_update_BundledUpdateStatus& response);
54 
55   // Sync
56   Status SetTransferred(const pw_protobuf_Empty& request,
57                         pw_software_update_BundledUpdateStatus& response);
58 
59   // Async
60   Status Verify(const pw_protobuf_Empty& request,
61                 pw_software_update_BundledUpdateStatus& response);
62 
63   // Async
64   Status Apply(const pw_protobuf_Empty& request,
65                pw_software_update_BundledUpdateStatus& response);
66 
67   // Currently sync, should be async.
68   // TODO(keir): Make this async to support aborting verify/apply.
69   Status Abort(const pw_protobuf_Empty& request,
70                pw_software_update_BundledUpdateStatus& response);
71 
72   // Sync
73   Status Reset(const pw_protobuf_Empty& request,
74                pw_software_update_BundledUpdateStatus& response);
75 
76   // Notify the service that the bundle transfer has completed. The service has
77   // no way to know when the bundle transfer completes, so users must invoke
78   // this method in their transfer completion handler.
79   //
80   // After this call, the service will be in TRANSFERRED state if and only if
81   // it was in the TRANSFERRING state.
82   void NotifyTransferSucceeded();
83 
84   // TODO(davidrogers) Add a MaybeFinishApply() method that is called after
85   // reboot to finish any need apply and verify work.
86 
87   // TODO(keir): VerifyProgress - to update % complete.
88   // TODO(keir): ApplyProgress - to update % complete.
89 
90  private:
91   // Top-level lock for OTA state coherency. May be held for extended periods.
92   sync::Mutex mutex_;
93   // Nested lock for safe status updates and queries.
94   sync::Mutex status_mutex_ PW_ACQUIRED_AFTER(mutex_);
95   pw_software_update_BundledUpdateStatus unsafe_status_
96       PW_GUARDED_BY(status_mutex_);
97   sync::Borrowable<pw_software_update_BundledUpdateStatus, sync::Mutex> status_;
98   BundledUpdateBackend& backend_ PW_GUARDED_BY(mutex_);
99   UpdateBundleAccessor& bundle_ PW_GUARDED_BY(mutex_);
100   bool bundle_open_ PW_GUARDED_BY(mutex_);
101   work_queue::WorkQueue& work_queue_ PW_GUARDED_BY(mutex_);
102   bool work_enqueued_ PW_GUARDED_BY(mutex_);
103 
104   void DoVerify() PW_LOCKS_EXCLUDED(status_mutex_);
105   void DoApply() PW_LOCKS_EXCLUDED(status_mutex_);
106   void Finish(_pw_software_update_BundledUpdateResult_Enum result)
107       PW_EXCLUSIVE_LOCKS_REQUIRED(mutex_) PW_LOCKS_EXCLUDED(status_mutex_);
IsFinished()108   bool IsFinished() PW_EXCLUSIVE_LOCKS_REQUIRED(mutex_)
109       PW_LOCKS_EXCLUDED(status_mutex_) {
110     return status_.acquire()->state ==
111            pw_software_update_BundledUpdateState_Enum_FINISHED;
112   }
113 };
114 
115 }  // namespace pw::software_update
116