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 23 #include <android-base/logging.h> 24 #include <batteryservice/BatteryServiceConstants.h> 25 #include <batteryservice/IBatteryPropertiesRegistrar.h> 26 #include <binder/IPCThreadState.h> 27 #include <binder/IServiceManager.h> 28 #include <cutils/properties.h> 29 #include <log/log.h> 30 31 #include <storaged.h> 32 #include <storaged_utils.h> 33 34 /* disk_stats_publisher */ 35 void disk_stats_publisher::publish(void) { 36 // Logging 37 struct disk_perf perf = get_disk_perf(&mAccumulate); 38 log_debug_disk_perf(&perf, "regular"); 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); 49 #ifdef DEBUG 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"); 54 #endif 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); 110 log_debug_disk_perf(&mMean, "stalled_mean"); 111 log_debug_disk_perf(&mStd, "stalled_std"); 112 } else { 113 if (mStall) { 114 struct disk_perf acc_perf = get_disk_perf(&mAccumulate); 115 log_debug_disk_perf(&acc_perf, "stalled"); 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 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() { 174 if (!mConfig.proc_uid_io_available) 175 return; 176 177 battery_properties = get_battery_properties_service(); 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); 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"; 196 IPCThreadState::self()->stopProcess(); 197 exit(1); 198 } else { 199 LOG_TO(SYSTEM, ERROR) << "unknown service died"; 200 } 201 } 202 203 void storaged_t::report_storage_info() { 204 storage_info->report(); 205 } 206 207 /* storaged_t */ 208 storaged_t::storaged_t(void) { 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 215 mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); 216 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 226 mConfig.periodic_chores_interval_uid_io = 227 property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); 228 229 storage_info.reset(storage_info_t::get_storage_info()); 230 231 mStarttime = time(NULL); 232 } 233 234 void storaged_t::event(void) { 235 if (mConfig.diskstats_available) { 236 mDiskStats.update(); 237 mDsm.update(); 238 storage_info->refresh(); 239 if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) { 240 mDiskStats.publish(); 241 } 242 } 243 244 if (mConfig.proc_uid_io_available && mTimer && 245 (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { 246 mUidm.report(); 247 } 248 249 mTimer += mConfig.periodic_chores_interval_unit; 250 } 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; 259 static time_t state_a; 260 IF_ALOG_RATELIMIT_LOCAL(300, &state_a) { 261 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 262 } 263 } 264 265 event(); 266 267 if (mConfig.event_time_check_usec && check_time) { 268 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) { 269 static time_t state_b; 270 IF_ALOG_RATELIMIT_LOCAL(300, &state_b) { 271 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 272 } 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 } 284