ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 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 | |
| 17 | #define LOG_TAG "storaged" |
| 18 | |
| 19 | #include <stdlib.h> |
| 20 | #include <time.h> |
| 21 | #include <unistd.h> |
| 22 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 23 | #include <android-base/logging.h> |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 24 | #include <batteryservice/BatteryServiceConstants.h> |
| 25 | #include <batteryservice/IBatteryPropertiesRegistrar.h> |
Jin Qian | 26b2be0 | 2017-04-03 18:10:38 -0700 | [diff] [blame] | 26 | #include <binder/IPCThreadState.h> |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 27 | #include <binder/IServiceManager.h> |
Jin Qian | 3790f5b | 2017-01-23 14:38:47 -0800 | [diff] [blame] | 28 | #include <cutils/properties.h> |
Jin Qian | f42d7c8 | 2017-01-26 11:20:26 -0800 | [diff] [blame] | 29 | #include <log/log.h> |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 30 | |
| 31 | #include <storaged.h> |
| 32 | #include <storaged_utils.h> |
| 33 | |
| 34 | /* disk_stats_publisher */ |
| 35 | void disk_stats_publisher::publish(void) { |
| 36 | // Logging |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 37 | struct disk_perf perf = get_disk_perf(&mAccumulate); |
Jin Qian | 27506fa | 2017-01-17 11:51:51 -0800 | [diff] [blame] | 38 | log_debug_disk_perf(&perf, "regular"); |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 39 | log_event_disk_stats(&mAccumulate, "regular"); |
| 40 | // Reset global structures |
| 41 | memset(&mAccumulate, 0, sizeof(struct disk_stats)); |
| 42 | } |
| 43 | |
| 44 | void disk_stats_publisher::update(void) { |
| 45 | struct disk_stats curr; |
| 46 | if (parse_disk_stats(DISK_STATS_PATH, &curr)) { |
| 47 | struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr); |
| 48 | add_disk_stats(&inc, &mAccumulate); |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 49 | #ifdef DEBUG |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 50 | // log_kernel_disk_stats(&mPrevious, "prev stats"); |
| 51 | // log_kernel_disk_stats(&curr, "curr stats"); |
| 52 | // log_kernel_disk_stats(&inc, "inc stats"); |
| 53 | // log_kernel_disk_stats(&mAccumulate, "accumulated stats"); |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 54 | #endif |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 55 | mPrevious = curr; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | /* disk_stats_monitor */ |
| 60 | void disk_stats_monitor::update_mean() { |
| 61 | CHECK(mValid); |
| 62 | mMean.read_perf = (uint32_t)mStats.read_perf.get_mean(); |
| 63 | mMean.read_ios = (uint32_t)mStats.read_ios.get_mean(); |
| 64 | mMean.write_perf = (uint32_t)mStats.write_perf.get_mean(); |
| 65 | mMean.write_ios = (uint32_t)mStats.write_ios.get_mean(); |
| 66 | mMean.queue = (uint32_t)mStats.queue.get_mean(); |
| 67 | } |
| 68 | |
| 69 | void disk_stats_monitor::update_std() { |
| 70 | CHECK(mValid); |
| 71 | mStd.read_perf = (uint32_t)mStats.read_perf.get_std(); |
| 72 | mStd.read_ios = (uint32_t)mStats.read_ios.get_std(); |
| 73 | mStd.write_perf = (uint32_t)mStats.write_perf.get_std(); |
| 74 | mStd.write_ios = (uint32_t)mStats.write_ios.get_std(); |
| 75 | mStd.queue = (uint32_t)mStats.queue.get_std(); |
| 76 | } |
| 77 | |
| 78 | void disk_stats_monitor::add(struct disk_perf* perf) { |
| 79 | mStats.read_perf.add(perf->read_perf); |
| 80 | mStats.read_ios.add(perf->read_ios); |
| 81 | mStats.write_perf.add(perf->write_perf); |
| 82 | mStats.write_ios.add(perf->write_ios); |
| 83 | mStats.queue.add(perf->queue); |
| 84 | } |
| 85 | |
| 86 | void disk_stats_monitor::evict(struct disk_perf* perf) { |
| 87 | mStats.read_perf.evict(perf->read_perf); |
| 88 | mStats.read_ios.evict(perf->read_ios); |
| 89 | mStats.write_perf.evict(perf->write_perf); |
| 90 | mStats.write_ios.evict(perf->write_ios); |
| 91 | mStats.queue.evict(perf->queue); |
| 92 | } |
| 93 | |
| 94 | bool disk_stats_monitor::detect(struct disk_perf* perf) { |
| 95 | return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) && |
| 96 | ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) && |
| 97 | ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf); |
| 98 | } |
| 99 | |
| 100 | void disk_stats_monitor::update(struct disk_stats* stats) { |
| 101 | struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats); |
| 102 | struct disk_perf perf = get_disk_perf(&inc); |
| 103 | // Update internal data structures |
| 104 | if (LIKELY(mValid)) { |
| 105 | CHECK_EQ(mBuffer.size(), mWindow); |
| 106 | |
| 107 | if (UNLIKELY(detect(&perf))) { |
| 108 | mStall = true; |
| 109 | add_disk_stats(&inc, &mAccumulate); |
Jin Qian | 27506fa | 2017-01-17 11:51:51 -0800 | [diff] [blame] | 110 | log_debug_disk_perf(&mMean, "stalled_mean"); |
| 111 | log_debug_disk_perf(&mStd, "stalled_std"); |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 112 | } else { |
| 113 | if (mStall) { |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 114 | struct disk_perf acc_perf = get_disk_perf(&mAccumulate); |
Jin Qian | 27506fa | 2017-01-17 11:51:51 -0800 | [diff] [blame] | 115 | log_debug_disk_perf(&acc_perf, "stalled"); |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 116 | log_event_disk_stats(&mAccumulate, "stalled"); |
| 117 | mStall = false; |
| 118 | memset(&mAccumulate, 0, sizeof(mAccumulate)); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | evict(&mBuffer.front()); |
| 123 | mBuffer.pop(); |
| 124 | add(&perf); |
| 125 | mBuffer.push(perf); |
| 126 | |
| 127 | update_mean(); |
| 128 | update_std(); |
| 129 | |
| 130 | } else { /* mValid == false */ |
| 131 | CHECK_LT(mBuffer.size(), mWindow); |
| 132 | add(&perf); |
| 133 | mBuffer.push(perf); |
| 134 | if (mBuffer.size() == mWindow) { |
| 135 | mValid = true; |
| 136 | update_mean(); |
| 137 | update_std(); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | mPrevious = *stats; |
| 142 | } |
| 143 | |
| 144 | void disk_stats_monitor::update(void) { |
| 145 | struct disk_stats curr; |
| 146 | if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) { |
| 147 | update(&curr); |
| 148 | } |
| 149 | } |
| 150 | |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 151 | static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() { |
| 152 | sp<IServiceManager> sm = defaultServiceManager(); |
| 153 | if (sm == NULL) return NULL; |
| 154 | |
| 155 | sp<IBinder> binder = sm->getService(String16("batteryproperties")); |
| 156 | if (binder == NULL) return NULL; |
| 157 | |
| 158 | sp<IBatteryPropertiesRegistrar> battery_properties = |
| 159 | interface_cast<IBatteryPropertiesRegistrar>(binder); |
| 160 | |
| 161 | return battery_properties; |
| 162 | } |
| 163 | |
| 164 | static inline charger_stat_t is_charger_on(int64_t prop) { |
| 165 | return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ? |
| 166 | CHARGER_ON : CHARGER_OFF; |
| 167 | } |
| 168 | |
| 169 | void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) { |
| 170 | mUidm.set_charger_state(is_charger_on(props.batteryStatus)); |
| 171 | } |
| 172 | |
| 173 | void storaged_t::init_battery_service() { |
Jin Qian | ba27df4 | 2017-03-28 15:21:20 -0700 | [diff] [blame] | 174 | if (!mConfig.proc_uid_io_available) |
| 175 | return; |
| 176 | |
Jin Qian | 566e63d | 2017-03-31 14:26:23 -0700 | [diff] [blame] | 177 | battery_properties = get_battery_properties_service(); |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 178 | if (battery_properties == NULL) { |
| 179 | LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service"; |
| 180 | return; |
| 181 | } |
| 182 | |
| 183 | struct BatteryProperty val; |
| 184 | battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val); |
| 185 | mUidm.init(is_charger_on(val.valueInt64)); |
| 186 | |
| 187 | // register listener after init uid_monitor |
| 188 | battery_properties->registerListener(this); |
Jin Qian | 566e63d | 2017-03-31 14:26:23 -0700 | [diff] [blame] | 189 | IInterface::asBinder(battery_properties)->linkToDeath(this); |
| 190 | } |
| 191 | |
| 192 | void storaged_t::binderDied(const wp<IBinder>& who) { |
| 193 | if (battery_properties != NULL && |
| 194 | IInterface::asBinder(battery_properties) == who) { |
| 195 | LOG_TO(SYSTEM, ERROR) << "batteryproperties service died, exiting"; |
Jin Qian | 26b2be0 | 2017-04-03 18:10:38 -0700 | [diff] [blame] | 196 | IPCThreadState::self()->stopProcess(); |
Jin Qian | 566e63d | 2017-03-31 14:26:23 -0700 | [diff] [blame] | 197 | exit(1); |
| 198 | } else { |
| 199 | LOG_TO(SYSTEM, ERROR) << "unknown service died"; |
| 200 | } |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 201 | } |
| 202 | |
Jin Qian | 8847c62 | 2017-07-17 15:06:11 -0700 | [diff] [blame] | 203 | void storaged_t::report_storage_info() { |
| 204 | storage_info->report(); |
| 205 | } |
| 206 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 207 | /* storaged_t */ |
| 208 | storaged_t::storaged_t(void) { |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 209 | if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) { |
| 210 | mConfig.diskstats_available = false; |
| 211 | } else { |
| 212 | mConfig.diskstats_available = true; |
| 213 | } |
| 214 | |
Jin Qian | bcd6e3b | 2016-12-28 15:43:51 -0800 | [diff] [blame] | 215 | mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); |
| 216 | |
Jin Qian | 3790f5b | 2017-01-23 14:38:47 -0800 | [diff] [blame] | 217 | mConfig.periodic_chores_interval_unit = |
| 218 | property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); |
| 219 | |
| 220 | mConfig.event_time_check_usec = |
| 221 | property_get_int32("ro.storaged.event.perf_check", 0); |
| 222 | |
| 223 | mConfig.periodic_chores_interval_disk_stats_publish = |
| 224 | property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); |
| 225 | |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 226 | mConfig.periodic_chores_interval_uid_io = |
| 227 | property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 228 | |
Jin Qian | 8847c62 | 2017-07-17 15:06:11 -0700 | [diff] [blame] | 229 | storage_info.reset(storage_info_t::get_storage_info()); |
| 230 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 231 | mStarttime = time(NULL); |
| 232 | } |
| 233 | |
| 234 | void storaged_t::event(void) { |
| 235 | if (mConfig.diskstats_available) { |
| 236 | mDiskStats.update(); |
| 237 | mDsm.update(); |
Jin Qian | 8847c62 | 2017-07-17 15:06:11 -0700 | [diff] [blame] | 238 | storage_info->refresh(); |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 239 | if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) { |
| 240 | mDiskStats.publish(); |
| 241 | } |
| 242 | } |
| 243 | |
Jin Qian | bcd6e3b | 2016-12-28 15:43:51 -0800 | [diff] [blame] | 244 | if (mConfig.proc_uid_io_available && mTimer && |
Jin Qian | 5b962c6 | 2017-01-30 14:48:38 -0800 | [diff] [blame] | 245 | (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { |
Jin Qian | bcd6e3b | 2016-12-28 15:43:51 -0800 | [diff] [blame] | 246 | mUidm.report(); |
| 247 | } |
| 248 | |
ynwang | 62cb372 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 249 | mTimer += mConfig.periodic_chores_interval_unit; |
ynwang | af49d97 | 2016-06-17 14:30:48 -0700 | [diff] [blame] | 250 | } |
Jin Qian | 3790f5b | 2017-01-23 14:38:47 -0800 | [diff] [blame] | 251 | |
| 252 | void storaged_t::event_checked(void) { |
| 253 | struct timespec start_ts, end_ts; |
| 254 | bool check_time = true; |
| 255 | |
| 256 | if (mConfig.event_time_check_usec && |
| 257 | clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) { |
| 258 | check_time = false; |
Jin Qian | f42d7c8 | 2017-01-26 11:20:26 -0800 | [diff] [blame] | 259 | static time_t state_a; |
| 260 | IF_ALOG_RATELIMIT_LOCAL(300, &state_a) { |
| 261 | PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; |
| 262 | } |
Jin Qian | 3790f5b | 2017-01-23 14:38:47 -0800 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | event(); |
| 266 | |
Jin Qian | f42d7c8 | 2017-01-26 11:20:26 -0800 | [diff] [blame] | 267 | if (mConfig.event_time_check_usec && check_time) { |
Jin Qian | 3790f5b | 2017-01-23 14:38:47 -0800 | [diff] [blame] | 268 | if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) { |
Jin Qian | f42d7c8 | 2017-01-26 11:20:26 -0800 | [diff] [blame] | 269 | static time_t state_b; |
| 270 | IF_ALOG_RATELIMIT_LOCAL(300, &state_b) { |
| 271 | PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; |
| 272 | } |
Jin Qian | 3790f5b | 2017-01-23 14:38:47 -0800 | [diff] [blame] | 273 | return; |
| 274 | } |
| 275 | int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC + |
| 276 | (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC; |
| 277 | if (cost > mConfig.event_time_check_usec) { |
| 278 | LOG_TO(SYSTEM, ERROR) |
| 279 | << "event loop spent " << cost << " usec, threshold " |
| 280 | << mConfig.event_time_check_usec << " usec"; |
| 281 | } |
| 282 | } |
| 283 | } |