• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "sandboxed_api/transaction.h"
16 
17 #include <functional>
18 #include <memory>
19 
20 #include "absl/cleanup/cleanup.h"
21 #include "absl/log/log.h"
22 #include "absl/status/status.h"
23 #include "absl/time/time.h"
24 #include "sandboxed_api/util/status_macros.h"
25 
26 namespace sapi {
27 
28 constexpr absl::Duration TransactionBase::kDefaultTimeLimit;
29 
RunTransactionFunctionInSandbox(const std::function<absl::Status ()> & f)30 absl::Status TransactionBase::RunTransactionFunctionInSandbox(
31     const std::function<absl::Status()>& f) {
32   // Run Main(), invoking Init() if this hasn't been yet done.
33   SAPI_RETURN_IF_ERROR(sandbox_->Init());
34 
35   // Set the wall-time limit for this transaction run, and clean it up
36   // afterwards, no matter what the result.
37   SAPI_RETURN_IF_ERROR(sandbox_->SetWallTimeLimit(time_limit_));
38   absl::Cleanup time_cleanup = [this] {
39     sandbox_->SetWallTimeLimit(absl::ZeroDuration()).IgnoreError();
40   };
41 
42   if (!initialized_) {
43     SAPI_RETURN_IF_ERROR(Init());
44     initialized_ = true;
45   }
46 
47   return f();
48 }
49 
RunTransactionLoop(const std::function<absl::Status ()> & f)50 absl::Status TransactionBase::RunTransactionLoop(
51     const std::function<absl::Status()>& f) {
52   // Try to run Main() for a few times, return error if none of the tries
53   // succeeded.
54   absl::Status status;
55   for (int i = 0; i <= retry_count_; ++i) {
56     status = RunTransactionFunctionInSandbox(f);
57     if (status.ok()) {
58       return status;
59     }
60     sandbox_->Terminate();
61     initialized_ = false;
62   }
63 
64   LOG(ERROR) << "Tried " << (retry_count_ + 1) << " times to run the "
65              << "transaction, but it failed. SAPI error: '" << status
66              << "'. Latest sandbox error: '"
67              << sandbox_->AwaitResult().ToString() << "'";
68   return status;
69 }
70 
~TransactionBase()71 TransactionBase::~TransactionBase() {
72   if (!initialized_) {
73     return;
74   }
75   if (absl::Status status = Finish(); !status.ok()) {
76     LOG(ERROR) << "Transaction finalizer returned an error: " << status;
77   }
78 }
79 
80 }  // namespace sapi
81