1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "Storage.h"
18
19 #include <sstream>
20
21 #include <android-base/chrono_utils.h>
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/strings.h>
25 #include <fstab/fstab.h>
26
27 namespace android {
28 namespace hardware {
29 namespace health {
30 namespace storage {
31 namespace V1_0 {
32 namespace implementation {
33
34 using base::ReadFileToString;
35 using base::Timer;
36 using base::Trim;
37 using base::WriteStringToFd;
38 using base::WriteStringToFile;
39 using fs_mgr::Fstab;
40 using fs_mgr::ReadDefaultFstab;
41
getGarbageCollectPath()42 std::string getGarbageCollectPath() {
43 Fstab fstab;
44 ReadDefaultFstab(&fstab);
45
46 for (const auto& entry : fstab) {
47 if (!entry.sysfs_path.empty()) {
48 return entry.sysfs_path + "/manual_gc";
49 }
50 }
51
52 return "";
53 }
54
garbageCollect(uint64_t timeoutSeconds,const sp<IGarbageCollectCallback> & cb)55 Return<void> Storage::garbageCollect(uint64_t timeoutSeconds,
56 const sp<IGarbageCollectCallback>& cb) {
57 Result result = Result::SUCCESS;
58 std::string path = getGarbageCollectPath();
59
60 if (path.empty()) {
61 LOG(WARNING) << "Cannot find Dev GC path";
62 result = Result::UNKNOWN_ERROR;
63 } else {
64 Timer timer;
65 LOG(INFO) << "Start Dev GC on " << path;
66 while (1) {
67 std::string require;
68 if (!ReadFileToString(path, &require)) {
69 PLOG(WARNING) << "Reading manual_gc failed in " << path;
70 result = Result::IO_ERROR;
71 break;
72 }
73 require = Trim(require);
74 if (require == "" || require == "off" || require == "disabled") {
75 LOG(DEBUG) << "No more to do Dev GC";
76 break;
77 }
78 LOG(DEBUG) << "Trigger Dev GC on " << path;
79 if (!WriteStringToFile("1", path)) {
80 PLOG(WARNING) << "Start Dev GC failed on " << path;
81 result = Result::IO_ERROR;
82 break;
83 }
84 if (timer.duration() >= std::chrono::seconds(timeoutSeconds)) {
85 LOG(WARNING) << "Dev GC timeout";
86 // Timeout is not treated as an error. Try next time.
87 break;
88 }
89 sleep(2);
90 }
91 LOG(INFO) << "Stop Dev GC on " << path;
92 if (!WriteStringToFile("0", path)) {
93 PLOG(WARNING) << "Stop Dev GC failed on " << path;
94 result = Result::IO_ERROR;
95 }
96 }
97
98 if (cb != nullptr) {
99 auto ret = cb->onFinish(result);
100 if (!ret.isOk()) {
101 LOG(WARNING) << "Cannot return result to callback: " << ret.description();
102 }
103 }
104 return Void();
105 }
106
debug(const hidl_handle & handle,const hidl_vec<hidl_string> &)107 Return<void> Storage::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
108 if (handle == nullptr || handle->numFds < 1) {
109 return Void();
110 }
111
112 int fd = handle->data[0];
113 std::stringstream output;
114
115 std::string path = getGarbageCollectPath();
116 if (path.empty()) {
117 output << "Cannot find Dev GC path";
118 } else {
119 std::string require;
120
121 if (ReadFileToString(path, &require)) {
122 output << path << ":" << require << std::endl;
123 }
124
125 if (WriteStringToFile("0", path)) {
126 output << "stop success" << std::endl;
127 }
128 }
129
130 if (!WriteStringToFd(output.str(), fd)) {
131 PLOG(WARNING) << "debug: cannot write to fd";
132 }
133
134 fsync(fd);
135
136 return Void();
137 }
138
139 } // namespace implementation
140 } // namespace V1_0
141 } // namespace storage
142 } // namespace health
143 } // namespace hardware
144 } // namespace android
145