blob: 97b7211e5e878711a1559f161c2e9e3068ade49d [file] [log] [blame]
Adam Lesinski06af1fa2015-05-05 17:35:35 -07001/*
2 * Copyright (C) 2015 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 */
16package com.android.internal.os;
17
18import android.annotation.Nullable;
Jeff Sharkey89182982017-11-01 19:02:56 -060019import android.os.StrictMode;
Adam Lesinski72478f02015-06-17 15:39:43 -070020import android.os.SystemClock;
Adam Lesinski06af1fa2015-05-05 17:35:35 -070021import android.text.TextUtils;
22import android.util.Slog;
23import android.util.SparseLongArray;
Adam Lesinski72478f02015-06-17 15:39:43 -070024import android.util.TimeUtils;
Adam Lesinski06af1fa2015-05-05 17:35:35 -070025
26import java.io.BufferedReader;
27import java.io.FileReader;
Adam Lesinskib83ffee2015-05-12 14:43:47 -070028import java.io.FileWriter;
Adam Lesinski06af1fa2015-05-05 17:35:35 -070029import java.io.IOException;
30
31/**
32 * Reads /proc/uid_cputime/show_uid_stat which has the line format:
33 *
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -070034 * uid: user_time_micro_seconds system_time_micro_seconds power_in_milli-amp-micro_seconds
Adam Lesinski06af1fa2015-05-05 17:35:35 -070035 *
36 * This provides the time a UID's processes spent executing in user-space and kernel-space.
37 * The file contains a monotonically increasing count of time for a single boot. This class
38 * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
39 * delta.
40 */
Mike Ma69d8b3e2018-02-23 14:51:26 -080041public class KernelUidCpuTimeReader extends
42 KernelUidCpuTimeReaderBase<KernelUidCpuTimeReader.Callback> {
43 private static final String TAG = KernelUidCpuTimeReader.class.getSimpleName();
Adam Lesinski06af1fa2015-05-05 17:35:35 -070044 private static final String sProcFile = "/proc/uid_cputime/show_uid_stat";
Adam Lesinskib83ffee2015-05-12 14:43:47 -070045 private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range";
Adam Lesinski06af1fa2015-05-05 17:35:35 -070046
47 /**
48 * Callback interface for processing each line of the proc file.
49 */
Mike Ma69d8b3e2018-02-23 14:51:26 -080050 public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -070051 /**
Mike Ma69d8b3e2018-02-23 14:51:26 -080052 * @param uid UID of the app
53 * @param userTimeUs time spent executing in user space in microseconds
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -070054 * @param systemTimeUs time spent executing in kernel space in microseconds
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -070055 */
Adam Lesinskid4abd1e2017-04-12 11:29:13 -070056 void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs);
Adam Lesinski06af1fa2015-05-05 17:35:35 -070057 }
58
59 private SparseLongArray mLastUserTimeUs = new SparseLongArray();
60 private SparseLongArray mLastSystemTimeUs = new SparseLongArray();
Adam Lesinski7b3c7522015-06-24 11:37:26 -070061 private long mLastTimeReadUs = 0;
Adam Lesinski06af1fa2015-05-05 17:35:35 -070062
63 /**
64 * Reads the proc file, calling into the callback with a delta of time for each UID.
Mike Ma69d8b3e2018-02-23 14:51:26 -080065 *
Adam Lesinski06af1fa2015-05-05 17:35:35 -070066 * @param callback The callback to invoke for each line of the proc file. If null,
67 * the data is consumed and subsequent calls to readDelta will provide
68 * a fresh delta.
69 */
Mike Ma69d8b3e2018-02-23 14:51:26 -080070 @Override
71 protected void readDeltaImpl(@Nullable Callback callback) {
Jeff Sharkey89182982017-11-01 19:02:56 -060072 final int oldMask = StrictMode.allowThreadDiskReadsMask();
Adam Lesinski7b3c7522015-06-24 11:37:26 -070073 long nowUs = SystemClock.elapsedRealtime() * 1000;
Adam Lesinski06af1fa2015-05-05 17:35:35 -070074 try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
75 TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
76 String line;
77 while ((line = reader.readLine()) != null) {
78 splitter.setString(line);
79 final String uidStr = splitter.next();
80 final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10);
81 final long userTimeUs = Long.parseLong(splitter.next(), 10);
82 final long systemTimeUs = Long.parseLong(splitter.next(), 10);
83
Sudheer Shanka318a67d2018-02-10 20:05:22 -080084 boolean notifyCallback = false;
85 long userTimeDeltaUs = userTimeUs;
86 long systemTimeDeltaUs = systemTimeUs;
Adam Lesinskie7f4f022016-06-08 14:19:09 -070087 // Only report if there is a callback and if this is not the first read.
88 if (callback != null && mLastTimeReadUs != 0) {
Adam Lesinski06af1fa2015-05-05 17:35:35 -070089 int index = mLastUserTimeUs.indexOfKey(uid);
Adam Lesinskib83ffee2015-05-12 14:43:47 -070090 if (index >= 0) {
91 userTimeDeltaUs -= mLastUserTimeUs.valueAt(index);
92 systemTimeDeltaUs -= mLastSystemTimeUs.valueAt(index);
93
Adam Lesinski7b3c7522015-06-24 11:37:26 -070094 final long timeDiffUs = nowUs - mLastTimeReadUs;
Adam Lesinskid4abd1e2017-04-12 11:29:13 -070095 if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0) {
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -070096 StringBuilder sb = new StringBuilder("Malformed cpu data for UID=");
97 sb.append(uid).append("!\n");
Adam Lesinski72478f02015-06-17 15:39:43 -070098 sb.append("Time between reads: ");
Adam Lesinski7b3c7522015-06-24 11:37:26 -070099 TimeUtils.formatDuration(timeDiffUs / 1000, sb);
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -0700100 sb.append("\n");
Adam Lesinski72478f02015-06-17 15:39:43 -0700101 sb.append("Previous times: u=");
102 TimeUtils.formatDuration(mLastUserTimeUs.valueAt(index) / 1000, sb);
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -0700103 sb.append(" s=");
Adam Lesinski72478f02015-06-17 15:39:43 -0700104 TimeUtils.formatDuration(mLastSystemTimeUs.valueAt(index) / 1000, sb);
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -0700105
Adam Lesinskid4abd1e2017-04-12 11:29:13 -0700106 sb.append("\nCurrent times: u=");
Adam Lesinski72478f02015-06-17 15:39:43 -0700107 TimeUtils.formatDuration(userTimeUs / 1000, sb);
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -0700108 sb.append(" s=");
Adam Lesinski72478f02015-06-17 15:39:43 -0700109 TimeUtils.formatDuration(systemTimeUs / 1000, sb);
Adam Lesinskid4abd1e2017-04-12 11:29:13 -0700110 sb.append("\nDelta: u=");
Adam Lesinski72478f02015-06-17 15:39:43 -0700111 TimeUtils.formatDuration(userTimeDeltaUs / 1000, sb);
Adam Lesinskia7a4ccc2015-06-26 17:43:04 -0700112 sb.append(" s=");
Adam Lesinski72478f02015-06-17 15:39:43 -0700113 TimeUtils.formatDuration(systemTimeDeltaUs / 1000, sb);
Adam Lesinski19647392016-07-27 16:11:27 -0700114 Slog.e(TAG, sb.toString());
Adam Lesinski72478f02015-06-17 15:39:43 -0700115
116 userTimeDeltaUs = 0;
117 systemTimeDeltaUs = 0;
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700118 }
119 }
120
Sudheer Shanka318a67d2018-02-10 20:05:22 -0800121 notifyCallback = (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0);
Adam Lesinski06af1fa2015-05-05 17:35:35 -0700122 }
123 mLastUserTimeUs.put(uid, userTimeUs);
124 mLastSystemTimeUs.put(uid, systemTimeUs);
Sudheer Shanka318a67d2018-02-10 20:05:22 -0800125 if (notifyCallback) {
126 callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
127 }
Adam Lesinski06af1fa2015-05-05 17:35:35 -0700128 }
129 } catch (IOException e) {
Adam Lesinski80571332015-09-18 14:56:34 -0700130 Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
Jeff Sharkey89182982017-11-01 19:02:56 -0600131 } finally {
132 StrictMode.setThreadPolicyMask(oldMask);
Adam Lesinski06af1fa2015-05-05 17:35:35 -0700133 }
Adam Lesinski7b3c7522015-06-24 11:37:26 -0700134 mLastTimeReadUs = nowUs;
Adam Lesinski06af1fa2015-05-05 17:35:35 -0700135 }
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700136
137 /**
Chenjie Yuec676612018-03-07 09:19:17 -0800138 * Reads the proc file, calling into the callback with raw absolute value of time for each UID.
139 * @param callback The callback to invoke for each line of the proc file.
140 */
141 public void readAbsolute(Callback callback) {
142 final int oldMask = StrictMode.allowThreadDiskReadsMask();
143 try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
144 TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
145 String line;
146 while ((line = reader.readLine()) != null) {
147 splitter.setString(line);
148 final String uidStr = splitter.next();
149 final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10);
150 final long userTimeUs = Long.parseLong(splitter.next(), 10);
151 final long systemTimeUs = Long.parseLong(splitter.next(), 10);
152 callback.onUidCpuTime(uid, userTimeUs, systemTimeUs);
153 }
154 } catch (IOException e) {
155 Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
156 } finally {
157 StrictMode.setThreadPolicyMask(oldMask);
158 }
159 }
160
161 /**
Mike Ma69d8b3e2018-02-23 14:51:26 -0800162 * Removes the UID from the kernel module and from internal accounting data. Only
163 * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
164 * visible system wide.
165 *
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700166 * @param uid The UID to remove.
167 */
168 public void removeUid(int uid) {
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700169 final int index = mLastSystemTimeUs.indexOfKey(uid);
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700170 if (index >= 0) {
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700171 mLastSystemTimeUs.removeAt(index);
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700172 mLastUserTimeUs.removeAt(index);
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700173 }
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700174 removeUidsFromKernelModule(uid, uid);
175 }
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700176
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700177 /**
Mike Ma69d8b3e2018-02-23 14:51:26 -0800178 * Removes UIDs in a given range from the kernel module and internal accounting data. Only
179 * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
180 * visible system wide.
181 *
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700182 * @param startUid the first uid to remove
Mike Ma69d8b3e2018-02-23 14:51:26 -0800183 * @param endUid the last uid to remove
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700184 */
185 public void removeUidsInRange(int startUid, int endUid) {
186 if (endUid < startUid) {
187 return;
188 }
189 mLastSystemTimeUs.put(startUid, 0);
190 mLastUserTimeUs.put(startUid, 0);
191 mLastSystemTimeUs.put(endUid, 0);
192 mLastUserTimeUs.put(endUid, 0);
193 final int startIndex = mLastSystemTimeUs.indexOfKey(startUid);
194 final int endIndex = mLastSystemTimeUs.indexOfKey(endUid);
195 mLastSystemTimeUs.removeAtRange(startIndex, endIndex - startIndex + 1);
196 mLastUserTimeUs.removeAtRange(startIndex, endIndex - startIndex + 1);
197 removeUidsFromKernelModule(startUid, endUid);
198 }
199
200 private void removeUidsFromKernelModule(int startUid, int endUid) {
201 Slog.d(TAG, "Removing uids " + startUid + "-" + endUid);
Jeff Sharkey89182982017-11-01 19:02:56 -0600202 final int oldMask = StrictMode.allowThreadDiskWritesMask();
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700203 try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700204 writer.write(startUid + "-" + endUid);
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700205 writer.flush();
206 } catch (IOException e) {
Suprabh Shuklae6e723d2017-06-14 16:14:43 -0700207 Slog.e(TAG, "failed to remove uids " + startUid + " - " + endUid
208 + " from uid_cputime module", e);
Jeff Sharkey89182982017-11-01 19:02:56 -0600209 } finally {
210 StrictMode.setThreadPolicyMask(oldMask);
Adam Lesinskib83ffee2015-05-12 14:43:47 -0700211 }
212 }
Adam Lesinski06af1fa2015-05-05 17:35:35 -0700213}