xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/transaction.h (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of 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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SANDBOXED_API_TRANSACTION_H_
16 #define SANDBOXED_API_TRANSACTION_H_
17 
18 #include <ctime>
19 #include <functional>
20 #include <memory>
21 #include <utility>
22 
23 #include "absl/base/attributes.h"
24 #include "absl/log/check.h"
25 #include "absl/log/log.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/time/time.h"
29 #include "sandboxed_api/sandbox.h"
30 
31 #define TRANSACTION_FAIL_IF_NOT(x, y)        \
32   if (!(x)) {                                \
33     return absl::FailedPreconditionError(y); \
34   }
35 
36 namespace sapi {
37 
38 // The Transaction class allows to perform operations in the sandboxee,
39 // repeating them if necessary (if the sandboxing, or IPC failed).
40 //
41 // We provide two different implementations of transactions:
42 //  1) Single function transactions - They consist out of a single function
43 //     Main() that will be invoked as body of the transaction. For this,
44 //     inherit from the Transaction class and implement Main().
45 //  2) Function pointer based transactions - The BasicTransaction class accepts
46 //     functions that take a sandbox object (along with arbitrary other
47 //     parameters) and return a status. This way no custom implementation of a
48 //     Transaction class is required.
49 //
50 // Additionally both methods support Init() and Finish() functions.
51 // Init() will be called after the sandbox has been set up.
52 // Finish() will be called when the transaction object goes out of scope.
53 class TransactionBase {
54  public:
55   TransactionBase(const TransactionBase&) = delete;
56   TransactionBase& operator=(const TransactionBase&) = delete;
57 
58   virtual ~TransactionBase();
59 
60   // Getter/Setter for retry_count_.
retry_count()61   int retry_count() const { return retry_count_; }
set_retry_count(int value)62   void set_retry_count(int value) {
63     CHECK_GE(value, 0);
64     retry_count_ = value;
65   }
66 
67   // Getter/Setter for time_limit_.
GetTimeLimit()68   time_t GetTimeLimit() const { return time_limit_; }
SetTimeLimit(time_t time_limit)69   void SetTimeLimit(time_t time_limit) { time_limit_ = time_limit; }
SetTimeLimit(absl::Duration time_limit)70   void SetTimeLimit(absl::Duration time_limit) {
71     time_limit_ = absl::ToTimeT(absl::UnixEpoch() + time_limit);
72   }
73 
IsInitialized()74   bool IsInitialized() const { return initialized_; }
75 
76   // Getter for the sandbox_.
sandbox()77   Sandbox* sandbox() const { return sandbox_.get(); }
78 
79   // Restarts the sandbox.
80   // WARNING: This will invalidate any references to the remote process, make
81   //          sure you don't keep any vars or FDs to the remote process when
82   //          calling this.
Restart()83   absl::Status Restart() {
84     if (initialized_) {
85       Finish().IgnoreError();
86       initialized_ = false;
87     }
88     return sandbox_->Restart(true);
89   }
90 
91  protected:
TransactionBase(std::unique_ptr<Sandbox> sandbox)92   explicit TransactionBase(std::unique_ptr<Sandbox> sandbox)
93       : time_limit_(absl::ToTimeT(absl::UnixEpoch() + kDefaultTimeLimit)),
94         sandbox_(std::move(sandbox)) {}
95 
96   // Runs the main (retrying) transaction loop.
97   absl::Status RunTransactionLoop(const std::function<absl::Status()>& f);
98 
99  private:
100   // Number of default transaction execution re-tries, in case of failures.
101   static constexpr int kDefaultRetryCount = 1;
102 
103   // Wall-time limit for a single transaction execution (60 s.).
104   static constexpr absl::Duration kDefaultTimeLimit = absl::Seconds(60);
105 
106   // Executes a single function in the sandbox, used in the main transaction
107   // loop. Asserts that the sandbox has been set up and Init() was called.
108   absl::Status RunTransactionFunctionInSandbox(
109       const std::function<absl::Status()>& f);
110 
111   // Initialization routine of the sandboxed process that will be called only
112   // once upon sandboxee startup.
Init()113   virtual absl::Status Init() { return absl::OkStatus(); }
114 
115   // End routine for the sandboxee that gets calls when the transaction is
116   // destroyed/restarted to clean up resources.
Finish()117   virtual absl::Status Finish() { return absl::OkStatus(); }
118 
119   // Number of tries this transaction will be re-executed until it succeeds.
120   int retry_count_ = kDefaultRetryCount;
121 
122   // Time (wall-time) limit for a single Run() call (in seconds). 0 means: no
123   // wall-time limit.
124   time_t time_limit_;
125 
126   // Has Init() finished with success?
127   bool initialized_ = false;
128 
129   // The main sapi::Sandbox object.
130   std::unique_ptr<Sandbox> sandbox_;
131 };
132 
133 // Regular style transactions, based on inheriting.
134 class Transaction : public TransactionBase {
135  public:
136   Transaction(const Transaction&) = delete;
137   Transaction& operator=(const Transaction&) = delete;
138   using TransactionBase::TransactionBase;
139 
140   // Run the transaction.
Run()141   absl::Status Run() {
142     return RunTransactionLoop([this] { return Main(); });
143   }
144 
145  protected:
146   // The main sandboxee routine: Can be called multiple times.
Main()147   virtual absl::Status Main() { return absl::OkStatus(); }
148 };
149 
150 // Callback style transactions:
151 class BasicTransaction final : public TransactionBase {
152  private:
153   using InitFunction = std::function<absl::Status(Sandbox*)>;
154   using FinishFunction = std::function<absl::Status(Sandbox*)>;
155 
156  public:
BasicTransaction(std::unique_ptr<Sandbox> sandbox)157   explicit BasicTransaction(std::unique_ptr<Sandbox> sandbox)
158       : TransactionBase(std::move(sandbox)),
159         init_function_(nullptr),
160         finish_function_(nullptr) {}
161 
162   template <typename F>
BasicTransaction(std::unique_ptr<Sandbox> sandbox,F init_function)163   BasicTransaction(std::unique_ptr<Sandbox> sandbox, F init_function)
164       : TransactionBase(std::move(sandbox)),
165         init_function_(static_cast<InitFunction>(init_function)),
166         finish_function_(nullptr) {}
167 
168   template <typename F, typename G>
BasicTransaction(std::unique_ptr<Sandbox> sandbox,F init_function,G fini_function)169   BasicTransaction(std::unique_ptr<Sandbox> sandbox, F init_function,
170                    G fini_function)
171       : TransactionBase(std::move(sandbox)),
172         init_function_(static_cast<InitFunction>(init_function)),
173         finish_function_(static_cast<FinishFunction>(fini_function)) {}
174 
175   // Run any function as body of the transaction that matches our expectations
176   // (that is: Returning a Status and accepting a Sandbox object as first
177   // parameter).
178   template <typename T, typename... Args>
Run(T func,Args &&...args)179   absl::Status Run(T func, Args&&... args) {
180     return RunTransactionLoop(
181         [&] { return func(sandbox(), std::forward<Args>(args)...); });
182   }
183 
184  private:
185   InitFunction init_function_;
186   FinishFunction finish_function_;
187 
Init()188   absl::Status Init() final {
189     return init_function_ ? init_function_(sandbox()) : absl::OkStatus();
190   }
191 
Finish()192   absl::Status Finish() final {
193     return finish_function_ ? finish_function_(sandbox()) : absl::OkStatus();
194   }
195 };
196 
197 }  // namespace sapi
198 
199 #endif  // SANDBOXED_API_TRANSACTION_H_
200