storaged.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * Copyright (C) 2016 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. #define LOG_TAG "storaged"
  17. #include <dirent.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <time.h>
  21. #include <unistd.h>
  22. #include <zlib.h>
  23. #include <chrono>
  24. #include <fstream>
  25. #include <sstream>
  26. #include <string>
  27. #include <android-base/file.h>
  28. #include <android-base/logging.h>
  29. #include <android-base/unique_fd.h>
  30. #include <android/hidl/manager/1.0/IServiceManager.h>
  31. #include <batteryservice/BatteryServiceConstants.h>
  32. #include <cutils/properties.h>
  33. #include <healthhalutils/HealthHalUtils.h>
  34. #include <hidl/HidlTransportSupport.h>
  35. #include <hwbinder/IPCThreadState.h>
  36. #include <log/log.h>
  37. #include <storaged.h>
  38. #include <storaged_utils.h>
  39. using namespace android::base;
  40. using namespace chrono;
  41. using namespace google::protobuf::io;
  42. using namespace storaged_proto;
  43. namespace {
  44. /*
  45. * The system user is the initial user that is implicitly created on first boot
  46. * and hosts most of the system services. Keep this in sync with
  47. * frameworks/base/core/java/android/os/UserManager.java
  48. */
  49. constexpr int USER_SYSTEM = 0;
  50. constexpr ssize_t benchmark_unit_size = 16 * 1024; // 16KB
  51. constexpr ssize_t min_benchmark_size = 128 * 1024; // 128KB
  52. } // namespace
  53. const uint32_t storaged_t::current_version = 4;
  54. using android::hardware::interfacesEqual;
  55. using android::hardware::Return;
  56. using android::hardware::health::V1_0::BatteryStatus;
  57. using android::hardware::health::V1_0::toString;
  58. using android::hardware::health::V2_0::get_health_service;
  59. using android::hardware::health::V2_0::HealthInfo;
  60. using android::hardware::health::V2_0::IHealth;
  61. using android::hardware::health::V2_0::Result;
  62. using android::hidl::manager::V1_0::IServiceManager;
  63. inline charger_stat_t is_charger_on(BatteryStatus prop) {
  64. return (prop == BatteryStatus::CHARGING || prop == BatteryStatus::FULL) ?
  65. CHARGER_ON : CHARGER_OFF;
  66. }
  67. Return<void> storaged_t::healthInfoChanged(const HealthInfo& props) {
  68. mUidm.set_charger_state(is_charger_on(props.legacy.batteryStatus));
  69. return android::hardware::Void();
  70. }
  71. void storaged_t::init() {
  72. init_health_service();
  73. mDsm = std::make_unique<disk_stats_monitor>(health);
  74. storage_info.reset(storage_info_t::get_storage_info(health));
  75. }
  76. void storaged_t::init_health_service() {
  77. if (!mUidm.enabled())
  78. return;
  79. health = get_health_service();
  80. if (health == NULL) {
  81. LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service";
  82. return;
  83. }
  84. BatteryStatus status = BatteryStatus::UNKNOWN;
  85. auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) {
  86. if (r != Result::SUCCESS) {
  87. LOG_TO(SYSTEM, WARNING)
  88. << "health: cannot get battery status " << toString(r);
  89. return;
  90. }
  91. if (v == BatteryStatus::UNKNOWN) {
  92. LOG_TO(SYSTEM, WARNING) << "health: invalid battery status";
  93. }
  94. status = v;
  95. });
  96. if (!ret.isOk()) {
  97. LOG_TO(SYSTEM, WARNING) << "health: get charge status transaction error "
  98. << ret.description();
  99. }
  100. mUidm.init(is_charger_on(status));
  101. // register listener after init uid_monitor
  102. health->registerCallback(this);
  103. health->linkToDeath(this, 0 /* cookie */);
  104. }
  105. void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) {
  106. if (health != NULL && interfacesEqual(health, who.promote())) {
  107. LOG_TO(SYSTEM, ERROR) << "health service died, exiting";
  108. android::hardware::IPCThreadState::self()->stopProcess();
  109. exit(1);
  110. } else {
  111. LOG_TO(SYSTEM, ERROR) << "unknown service died";
  112. }
  113. }
  114. void storaged_t::report_storage_info() {
  115. storage_info->report();
  116. }
  117. /* storaged_t */
  118. storaged_t::storaged_t(void) {
  119. mConfig.periodic_chores_interval_unit =
  120. property_get_int32("ro.storaged.event.interval",
  121. DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
  122. mConfig.event_time_check_usec =
  123. property_get_int32("ro.storaged.event.perf_check", 0);
  124. mConfig.periodic_chores_interval_disk_stats_publish =
  125. property_get_int32("ro.storaged.disk_stats_pub",
  126. DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
  127. mConfig.periodic_chores_interval_uid_io =
  128. property_get_int32("ro.storaged.uid_io.interval",
  129. DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
  130. mConfig.periodic_chores_interval_flush_proto =
  131. property_get_int32("ro.storaged.flush_proto.interval",
  132. DEFAULT_PERIODIC_CHORES_INTERVAL_FLUSH_PROTO);
  133. mStarttime = time(NULL);
  134. mTimer = 0;
  135. }
  136. void storaged_t::add_user_ce(userid_t user_id) {
  137. load_proto(user_id);
  138. proto_loaded[user_id] = true;
  139. }
  140. void storaged_t::remove_user_ce(userid_t user_id) {
  141. proto_loaded[user_id] = false;
  142. mUidm.clear_user_history(user_id);
  143. RemoveFileIfExists(proto_path(user_id), nullptr);
  144. }
  145. void storaged_t::load_proto(userid_t user_id) {
  146. string proto_file = proto_path(user_id);
  147. ifstream in(proto_file, ofstream::in | ofstream::binary);
  148. if (!in.good()) return;
  149. stringstream ss;
  150. ss << in.rdbuf();
  151. StoragedProto proto;
  152. proto.ParseFromString(ss.str());
  153. const UidIOUsage& uid_io_usage = proto.uid_io_usage();
  154. uint32_t computed_crc = crc32(current_version,
  155. reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
  156. uid_io_usage.ByteSize());
  157. if (proto.crc() != computed_crc) {
  158. LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
  159. return;
  160. }
  161. mUidm.load_uid_io_proto(user_id, proto.uid_io_usage());
  162. if (user_id == USER_SYSTEM) {
  163. storage_info->load_perf_history_proto(proto.perf_history());
  164. }
  165. }
  166. char* storaged_t:: prepare_proto(userid_t user_id, StoragedProto* proto) {
  167. proto->set_version(current_version);
  168. const UidIOUsage& uid_io_usage = proto->uid_io_usage();
  169. proto->set_crc(crc32(current_version,
  170. reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
  171. uid_io_usage.ByteSize()));
  172. uint32_t pagesize = sysconf(_SC_PAGESIZE);
  173. if (user_id == USER_SYSTEM) {
  174. proto->set_padding("", 1);
  175. vector<char> padding;
  176. ssize_t size = ROUND_UP(MAX(min_benchmark_size, proto->ByteSize()),
  177. pagesize);
  178. padding = vector<char>(size - proto->ByteSize(), 0xFD);
  179. proto->set_padding(padding.data(), padding.size());
  180. while (!IS_ALIGNED(proto->ByteSize(), pagesize)) {
  181. padding.push_back(0xFD);
  182. proto->set_padding(padding.data(), padding.size());
  183. }
  184. }
  185. char* data = nullptr;
  186. if (posix_memalign(reinterpret_cast<void**>(&data),
  187. pagesize, proto->ByteSize())) {
  188. PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: "
  189. << proto->ByteSize() << ")";
  190. return data;
  191. }
  192. proto->SerializeToArray(data, proto->ByteSize());
  193. return data;
  194. }
  195. void storaged_t::flush_proto_data(userid_t user_id,
  196. const char* data, ssize_t size) {
  197. string proto_file = proto_path(user_id);
  198. string tmp_file = proto_file + "_tmp";
  199. unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_file.c_str(),
  200. O_SYNC | O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC |
  201. (user_id == USER_SYSTEM ? O_DIRECT : 0),
  202. S_IRUSR | S_IWUSR)));
  203. if (fd == -1) {
  204. PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
  205. return;
  206. }
  207. if (user_id == USER_SYSTEM) {
  208. time_point<steady_clock> start, end;
  209. uint32_t benchmark_size = 0;
  210. uint64_t benchmark_time_ns = 0;
  211. ssize_t ret;
  212. bool first_write = true;
  213. while (size > 0) {
  214. start = steady_clock::now();
  215. ret = write(fd, data, MIN(benchmark_unit_size, size));
  216. if (ret <= 0) {
  217. PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
  218. return;
  219. }
  220. end = steady_clock::now();
  221. /*
  222. * compute bandwidth after the first write and if write returns
  223. * exactly unit size.
  224. */
  225. if (!first_write && ret == benchmark_unit_size) {
  226. benchmark_size += benchmark_unit_size;
  227. benchmark_time_ns += duration_cast<nanoseconds>(end - start).count();
  228. }
  229. size -= ret;
  230. data += ret;
  231. first_write = false;
  232. }
  233. if (benchmark_size) {
  234. int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
  235. storage_info->update_perf_history(perf, system_clock::now());
  236. }
  237. } else {
  238. if (!WriteFully(fd, data, size)) {
  239. PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
  240. return;
  241. }
  242. }
  243. fd.reset(-1);
  244. rename(tmp_file.c_str(), proto_file.c_str());
  245. }
  246. void storaged_t::flush_proto(userid_t user_id, StoragedProto* proto) {
  247. unique_ptr<char> proto_data(prepare_proto(user_id, proto));
  248. if (proto_data == nullptr) return;
  249. flush_proto_data(user_id, proto_data.get(), proto->ByteSize());
  250. }
  251. void storaged_t::flush_protos(unordered_map<int, StoragedProto>* protos) {
  252. for (auto& it : *protos) {
  253. /*
  254. * Don't flush proto if we haven't attempted to load it from file.
  255. */
  256. if (proto_loaded[it.first]) {
  257. flush_proto(it.first, &it.second);
  258. }
  259. }
  260. }
  261. void storaged_t::event(void) {
  262. unordered_map<int, StoragedProto> protos;
  263. if (mDsm->enabled()) {
  264. mDsm->update();
  265. if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) {
  266. mDsm->publish();
  267. }
  268. }
  269. if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) {
  270. mUidm.report(&protos);
  271. }
  272. if (storage_info) {
  273. storage_info->refresh(protos[USER_SYSTEM].mutable_perf_history());
  274. }
  275. if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) {
  276. flush_protos(&protos);
  277. }
  278. mTimer += mConfig.periodic_chores_interval_unit;
  279. }
  280. void storaged_t::event_checked(void) {
  281. struct timespec start_ts, end_ts;
  282. bool check_time = true;
  283. if (mConfig.event_time_check_usec &&
  284. clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) {
  285. check_time = false;
  286. PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
  287. }
  288. event();
  289. if (mConfig.event_time_check_usec && check_time) {
  290. if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) {
  291. PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
  292. return;
  293. }
  294. int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC +
  295. (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC;
  296. if (cost > mConfig.event_time_check_usec) {
  297. LOG_TO(SYSTEM, ERROR)
  298. << "event loop spent " << cost << " usec, threshold "
  299. << mConfig.event_time_check_usec << " usec";
  300. }
  301. }
  302. }