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