xref: /aosp_15_r20/external/pigweed/pw_system/system.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 #define PW_LOG_MODULE_NAME "pw_system"
16 
17 #include "pw_system/system.h"
18 
19 #include <utility>
20 
21 #include "pw_allocator/best_fit.h"
22 #include "pw_allocator/synchronized_allocator.h"
23 #include "pw_assert/check.h"
24 #include "pw_async2/allocate_task.h"
25 #include "pw_async2/pend_func_task.h"
26 #include "pw_log/log.h"
27 #include "pw_rpc/echo_service_pwpb.h"
28 #include "pw_sync/interrupt_spin_lock.h"
29 #include "pw_system/config.h"
30 #include "pw_system/device_service.h"
31 #include "pw_system/file_service.h"
32 #include "pw_system/internal/async_packet_io.h"
33 #include "pw_system/log.h"
34 #include "pw_system/thread_snapshot_service.h"
35 #include "pw_system/transfer_service.h"
36 #include "pw_system/work_queue.h"
37 #include "pw_system_private/threads.h"
38 #include "pw_thread/detached_thread.h"
39 
40 #if PW_SYSTEM_ENABLE_CRASH_HANDLER
41 #include "pw_system/crash_handler.h"
42 #include "pw_system/crash_snapshot.h"
43 #endif  // PW_SYSTEM_ENABLE_CRASH_HANDLER
44 
45 namespace pw {
46 
SystemStart(channel::ByteReaderWriter & io_channel)47 void SystemStart(channel::ByteReaderWriter& io_channel) {
48   System().Init(io_channel);
49 
50   system::StartScheduler();
51 }
52 
53 namespace system {
54 namespace {
55 
56 using pw::allocator::BestFitAllocator;
57 using pw::allocator::SynchronizedAllocator;
58 
59 // TODO: b/349654108 - Standardize component declaration and initialization.
60 alignas(internal::PacketIO) std::byte packet_io_[sizeof(internal::PacketIO)];
61 
InitializePacketIoGlobal(channel::ByteReaderWriter & io_channel)62 internal::PacketIO& InitializePacketIoGlobal(
63     channel::ByteReaderWriter& io_channel) {
64   static std::byte buffer[256];
65   internal::PacketIO* packet_io = new (packet_io_) internal::PacketIO(
66       io_channel, buffer, System().allocator(), System().rpc_server());
67   return *packet_io;
68 }
69 
70 // Functions for quickly creating a task from a function. This functions could
71 // be moved to `pw::system::AsyncCore`.
72 template <typename Func>
PostTaskFunction(Func && func)73 [[nodiscard]] bool PostTaskFunction(Func&& func) {
74   async2::Task* task = async2::AllocateTask<async2::PendFuncTask<Func>>(
75       System().allocator(), std::forward<Func>(func));
76   if (task == nullptr) {
77     return false;
78   }
79   System().dispatcher().Post(*task);
80   return true;
81 }
82 
83 template <typename Func>
PostTaskFunctionOrCrash(Func && func)84 void PostTaskFunctionOrCrash(Func&& func) {
85   PW_CHECK(PostTaskFunction(std::forward<Func>(func)));
86 }
87 
88 }  // namespace
89 
dispatcher()90 async2::Dispatcher& AsyncCore::dispatcher() {
91   static async2::Dispatcher dispatcher;
92   return dispatcher;
93 }
94 
allocator()95 Allocator& AsyncCore::allocator() {
96   alignas(uintptr_t) static std::byte buffer[8192];
97   static BestFitAllocator<> block_allocator(buffer);
98   static SynchronizedAllocator<::pw::sync::InterruptSpinLock> sync_allocator(
99       block_allocator);
100   return sync_allocator;
101 }
102 
RunOnce(Function<void ()> && function)103 bool AsyncCore::RunOnce(Function<void()>&& function) {
104   return GetWorkQueue().PushWork(std::move(function)).ok();
105 }
106 
Init(channel::ByteReaderWriter & io_channel)107 void AsyncCore::Init(channel::ByteReaderWriter& io_channel) {
108 #if PW_SYSTEM_ENABLE_CRASH_HANDLER
109   RegisterCrashHandler();
110 #endif  // PW_SYSTEM_ENABLE_CRASH_HANDLER
111 
112   PW_LOG_INFO("Initializing pw_system");
113 
114 #if PW_SYSTEM_ENABLE_CRASH_HANDLER
115   if (HasCrashSnapshot()) {
116     PW_LOG_ERROR("==========================");
117     PW_LOG_ERROR("======CRASH DETECTED======");
118     PW_LOG_ERROR("==========================");
119     PW_LOG_ERROR("Crash snapshots available.");
120     PW_LOG_ERROR(
121         "Run `device.get_crash_snapshots()` to download and clear the "
122         "snapshots.");
123   } else {
124     PW_LOG_DEBUG("No crash snapshot");
125   }
126 #endif  // PW_SYSTEM_ENABLE_CRASH_HANDLER
127 
128   PostTaskFunctionOrCrash(InitTask);
129 
130   // Initialize the packet_io subsystem
131   internal::PacketIO& packet_io = InitializePacketIoGlobal(io_channel);
132   packet_io.Start(System().dispatcher(), RpcThreadOptions());
133 
134   thread::DetachedThread(DispatcherThreadOptions(),
135                          [] { System().dispatcher().RunToCompletion(); });
136 
137   thread::DetachedThread(WorkQueueThreadOptions(), GetWorkQueue());
138 }
139 
InitTask(async2::Context &)140 async2::Poll<> AsyncCore::InitTask(async2::Context&) {
141   PW_LOG_INFO("Initializing pw_system");
142 
143   const Status status = GetLogThread().OpenUnrequestedLogStream(
144       kLoggingRpcChannelId, System().rpc_server(), GetLogService());
145   if (!status.ok()) {
146     PW_LOG_ERROR("Error opening unrequested log streams %d",
147                  static_cast<int>(status.code()));
148   }
149 
150   System().rpc_server().RegisterService(GetLogService());
151   thread::DetachedThread(system::LogThreadOptions(), GetLogThread());
152 
153   static rpc::EchoService echo_service;
154   System().rpc_server().RegisterService(echo_service);
155 
156   RegisterDeviceService(System().rpc_server());
157 
158   if (PW_SYSTEM_ENABLE_THREAD_SNAPSHOT_SERVICE != 0) {
159     RegisterThreadSnapshotService(System().rpc_server());
160   }
161 
162   if (PW_SYSTEM_ENABLE_TRANSFER_SERVICE != 0) {
163     RegisterTransferService(System().rpc_server());
164     RegisterFileService(System().rpc_server());
165     thread::DetachedThread(system::TransferThreadOptions(),
166                            GetTransferThread());
167     InitTransferService();
168   }
169 
170   PW_LOG_INFO("pw_system initialization complete");
171   return async2::Ready();
172 }
173 
174 }  // namespace system
175 }  // namespace pw
176