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 /* storaged_t */ 204 storaged_t::storaged_t(void) { 205 if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) { 206 mConfig.diskstats_available = false; 207 } else { 208 mConfig.diskstats_available = true; 209 } 210 211 mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); 212 213 mConfig.periodic_chores_interval_unit = 214 property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT); 215 216 mConfig.event_time_check_usec = 217 property_get_int32("ro.storaged.event.perf_check", 0); 218 219 mConfig.periodic_chores_interval_disk_stats_publish = 220 property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH); 221 222 mConfig.periodic_chores_interval_uid_io = 223 property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO); 224 225 mStarttime = time(NULL); 226 } 227 228 void storaged_t::event(void) { 229 if (mConfig.diskstats_available) { 230 mDiskStats.update(); 231 mDsm.update(); 232 if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) { 233 mDiskStats.publish(); 234 } 235 } 236 237 if (mConfig.proc_uid_io_available && mTimer && 238 (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { 239 mUidm.report(); 240 } 241 242 mTimer += mConfig.periodic_chores_interval_unit; 243 } 244 245 void storaged_t::event_checked(void) { 246 struct timespec start_ts, end_ts; 247 bool check_time = true; 248 249 if (mConfig.event_time_check_usec && 250 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) { 251 check_time = false; 252 static time_t state_a; 253 IF_ALOG_RATELIMIT_LOCAL(300, &state_a) { 254 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 255 } 256 } 257 258 event(); 259 260 if (mConfig.event_time_check_usec && check_time) { 261 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) { 262 static time_t state_b; 263 IF_ALOG_RATELIMIT_LOCAL(300, &state_b) { 264 PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; 265 } 266 return; 267 } 268 int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC + 269 (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC; 270 if (cost > mConfig.event_time_check_usec) { 271 LOG_TO(SYSTEM, ERROR) 272 << "event loop spent " << cost << " usec, threshold " 273 << mConfig.event_time_check_usec << " usec"; 274 } 275 } 276 } 277