1 // Copyright (C) 2019 The Android Open Source Project
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 //      http://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 "utility.h"
16 
17 #include <errno.h>
18 #include <unistd.h>
19 
20 #include <thread>
21 
22 #include <android-base/logging.h>
23 
24 using namespace std::literals;
25 
26 namespace android {
27 namespace dm {
28 
WaitForCondition(const std::function<WaitResult ()> & condition,const std::chrono::milliseconds & timeout_ms)29 bool WaitForCondition(const std::function<WaitResult()>& condition,
30                       const std::chrono::milliseconds& timeout_ms) {
31     auto start_time = std::chrono::steady_clock::now();
32     while (true) {
33         auto result = condition();
34         if (result == WaitResult::Done) return true;
35         if (result == WaitResult::Fail) return false;
36 
37         std::this_thread::sleep_for(20ms);
38 
39         auto now = std::chrono::steady_clock::now();
40         auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
41         if (time_elapsed > timeout_ms) return false;
42     }
43 }
44 
WaitForFile(const std::string & path,const std::chrono::milliseconds & timeout_ms)45 bool WaitForFile(const std::string& path, const std::chrono::milliseconds& timeout_ms) {
46     auto condition = [&]() -> WaitResult {
47         // If the file exists but returns EPERM or something, we consider the
48         // condition met.
49         if (access(path.c_str(), F_OK) != 0) {
50             if (errno == ENOENT) {
51                 return WaitResult::Wait;
52             }
53             PLOG(ERROR) << "access failed: " << path;
54             return WaitResult::Fail;
55         }
56         return WaitResult::Done;
57     };
58     return WaitForCondition(condition, timeout_ms);
59 }
60 
WaitForFileDeleted(const std::string & path,const std::chrono::milliseconds & timeout_ms)61 bool WaitForFileDeleted(const std::string& path, const std::chrono::milliseconds& timeout_ms) {
62     auto condition = [&]() -> WaitResult {
63         if (access(path.c_str(), F_OK) == 0) {
64             return WaitResult::Wait;
65         }
66         if (errno != ENOENT) {
67             PLOG(ERROR) << "access failed: " << path;
68             return WaitResult::Fail;
69         }
70         return WaitResult::Done;
71     };
72     return WaitForCondition(condition, timeout_ms);
73 }
74 
75 }  // namespace dm
76 }  // namespace android
77