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