• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
publish(void)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 
update(void)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 */
update_mean()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 
update_std()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 
add(struct disk_perf * perf)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 
evict(struct disk_perf * perf)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 
detect(struct disk_perf * perf)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 
update(struct disk_stats * stats)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 
update(void)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 
get_battery_properties_service()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 
is_charger_on(int64_t prop)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 
batteryPropertiesChanged(struct BatteryProperties props)169 void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
170     mUidm.set_charger_state(is_charger_on(props.batteryStatus));
171 }
172 
init_battery_service()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 
binderDied(const wp<IBinder> & who)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 
report_storage_info()203 void storaged_t::report_storage_info() {
204     storage_info->report();
205 }
206 
207 /* storaged_t */
storaged_t(void)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 
event(void)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 
event_checked(void)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