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